Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,11 @@ build):

- Total coverage must be at least **80%**.
- Coverage of the lines your change touches must be at least **85%** — new
code is held above the total floor so the total only ratchets upward.
code is held above the total floor so the total only ratchets upward. A line
sitting inside one block that ran and one that did not is *not* covered, on
both sides of the gate: that is what Codecov calls a partial, and counting it
as covered locally is how `make patch-coverage` used to report a few points
above `codecov/patch` on the same diff.
- Cyclomatic complexity ≤ **10** and cognitive complexity ≤ **15** per
function. The frontend carries the same two numbers as eslint `complexity`
and `sonarjs/cognitive-complexity`, so one budget governs both languages.
Expand Down
31 changes: 26 additions & 5 deletions DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ Targets: macOS, Linux, Windows.
| Terminal | **xterm.js + real PTY** (WebGL renderer) | The proven embedded-terminal stack (VS Code's). Cross-platform today, MIT, and fast enough for full-screen `claude` and `vim` (§8). |
| Editor | **CodeMirror 6** | Lighter than Monaco, better touch/perf profile, MIT. "Light yaml editing" does not need Monaco's weight. |
| Git | **Shell out to system `git`**, parse porcelain output | Inherits SSH agent, credential helpers, signing config, and every edge case for free. Rejected: go-git (auth and worktree edge-case parity is a permanent tax). |
| Kube mutations | **Shell out to `kubectl`** (`diff`, `apply`, `delete`) | Inherits kubeconfig, exec auth plugins (OIDC / EKS / GKE / AKS), server-side apply semantics. |
| Kube mutations | **Shell out to `kubectl`** (`diff`, `apply`, `delete`) | Inherits kubeconfig, exec auth plugins (OIDC / EKS / GKE / AKS), and the same apply semantics the user's colleagues and CI already get. |
| Kube reads | **client-go, read-only** | Live status and drift views without polling through kubectl. Watch/list only; the client-go path never mutates. |
| Helm | **Both modes**: render→apply and real releases | `helm template` output feeds the same diff/apply pipeline as plain YAML; a separate release mode wraps `upgrade --install` / `history` / `rollback` for charts genuinely managed as releases. Shell out to `helm`. |
| Manifest formats | Plain YAML directories + Helm charts | Kustomize deferred. |
Expand Down Expand Up @@ -246,9 +246,18 @@ Single window. Top-level tabs are projects; each project tab contains:
the chosen context names and stays free text — listing namespaces is a
permission many users of a shared cluster do not have, and a dropdown would be
empty for exactly them. Below that sits live health (from the watch service +
kstatus) for every object declared in the project, and a drift indicator when
live objects differ from the checked-in manifests (server-side dry-run
kstatus) for the objects **the open manifest declares** — one line per object,
a second line only where there is something to read — and a drift indicator
when live objects differ from the checked-in manifests (server-side dry-run
comparison, computed on demand — not continuous).

The health list is scoped to the file rather than to the project, which is a
change from this document's first draft. A project-wide list is one nobody
reads: this pane is 280px wide and already carries three sections above it, so
in any real repository the row that matters is off the bottom. The watch
itself is still project-wide — the backend keeps one session per bound cluster
and namespace — so moving between files is a filter in the panel rather than a
reconnection.
- **Making a folder override**: on the folder, in the tree. Its context menu
carries a Kubernetes entry that opens a dialog to set or remove the folder's
context and namespace, and a folder carrying one of its own is marked in the
Expand Down Expand Up @@ -281,8 +290,20 @@ or a Helm render:
"No changes" is a first-class result, not an empty screen.
3. **Confirm** — the confirm dialog restates target context + namespace.
Protected projects require typing the context name.
4. **Apply** — `kubectl apply` (server-side apply configurable per project),
streamed output, followed by the cluster panel reflecting new live status.
4. **Apply** — `kubectl apply`, streamed output, followed by the cluster panel
reflecting new live status.

Applies are **client-side**, and there is no setting for it (#69). Server-side
apply was offered per project and removed: it records per-field ownership, so a
server-side apply from m6t is refused on every object whose fields are owned by
`kubectl-client-side-apply` — which is every object anyone has ever applied
normally. That is a one-time migration only if nothing else writes to the
cluster again, and m6t is a workbench used alongside colleagues and CI who keep
running plain `kubectl apply`; each of those hands ownership back, and the next
apply conflicts again. Forcing past a conflict on every apply is server-side
apply with the only property it buys switched off. m6t applies the way the rest
of the team applies. It comes back if there is ever a reason for a whole team to
move at once, which is a v1.x question and not a checkbox.

Delete follows the same shape (`--dry-run=server`, listing what will be
removed, protected-confirm, `kubectl delete`).
Expand Down
8 changes: 8 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,14 @@ WAILS_VERSION := v2.13.0
# PATCH_COVERAGE_MIN holds NEW code above it so the total can only ratchet up.
# Both figures are mirrored in ci.yml, codecov.yml and CONTRIBUTING.md, and
# TestGateFiguresAgree fails when any copy disagrees.
#
# PATCH_COVERAGE_MIN is enforced twice — here and by codecov/patch — so the
# figure agreeing is only half of the agreement. The other half is what a line
# is worth: an overlapping block makes a line partially covered, Codecov counts
# that against the ratio, and `go tool cover` has no such category. Both sides
# now take the pessimistic view; the rule and the reason live in
# scripts/coverage-lines.awk, and TestCoverageLinesAgreesWithCodecov fails if
# the two arithmetics part company again (#29).
COVERAGE_MIN := 80
PATCH_COVERAGE_MIN := 85

Expand Down
7 changes: 7 additions & 0 deletions codecov.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
# Codecov targets. These figures are the same ones the Makefile enforces
# locally (COVERAGE_MIN / PATCH_COVERAGE_MIN) and CI enforces in the test job;
# TestGateFiguresAgree fails the build when any copy drifts.
#
# The patch target below is computed as hits / (hits + misses + partials), so a
# line covered by one block that ran and one that did not counts against it.
# scripts/coverage-lines.awk applies the same rule locally rather than the
# any-block-ran view `go tool cover` implies, which is what makes the local
# gate's figure the same number as this one instead of a few points above it
# (#29).
coverage:
status:
project:
Expand Down
Loading