From 4df42b7758c7062ad455636b38aec6644d3d0c42 Mon Sep 17 00:00:00 2001 From: Lukas Wuttke Date: Sat, 11 Jul 2026 17:56:24 +0200 Subject: [PATCH 1/2] docs: add the CLI navigation map (single source of truth) Four Mermaid flowcharts (top-level, the two gate chains, data ingest, resources) + exit-code legend + cross-links + known gaps. Diffable, renders on GitHub, kept current via PRs. Flags: two independent gate chains; stateless home today (status redesign proposed); delete exits 0 on partial offboard; resources unshipped. Co-Authored-By: Claude Opus 4.8 --- docs/cli-navigation.md | 190 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 docs/cli-navigation.md diff --git a/docs/cli-navigation.md b/docs/cli-navigation.md new file mode 100644 index 00000000..2d6b8f57 --- /dev/null +++ b/docs/cli-navigation.md @@ -0,0 +1,190 @@ +# tracebloc CLI — navigation map + +**The single source of truth for how a user moves through the CLI.** Every command, decision point, and place a user can end up. Diagrams are [Mermaid](https://mermaid.js.org) — they render natively on GitHub and in the docs, and this file is version-controlled, so **edit this file + open a PR to change the map** (that PR is where we discuss flow changes). + +> **Basis:** `develop` @ `06f9d41`. Two things are marked distinctly: +> - **`resources`** is on a feature branch (PRs #237 / #241), not yet on `develop` → drawn **dashed / "not shipped"**. +> - The **status-aware home screen** (greeting + sign-in + environment) is a *proposed* redesign (see `home-screen-spec.md`); today's home screen is **stateless** (same for everyone). Proposed bits are dashed. + +**How to read it:** `{diamond}` = decision · `[box]` = step · `([rounded])` = where you end up · green = exit 0 · red = non-zero exit · grey dashed = hidden (installer/back-compat) · orange dashed = proposed / not-yet-shipped. + +--- + +## 1. Top-level map — what's reachable from `tracebloc` / `tb` + +```mermaid +flowchart TD + H0["tracebloc / tb — home screen"] + + H0 --> ACCT["Account (needs sign-in)"] + H0 --> ENVC["Your secure environment & data (needs a reachable client)"] + H0 --> OFF(["delete — offboard this machine"]) + + ACCT --> login["login"] + ACCT --> logout["logout"] + ACCT --> authst["auth status"] + ACCT --> clis["client status"] + ACCT -.-> clcreate["client create"]:::hidden + ACCT -.-> cllist["client list"]:::hidden + + ENVC --> di["data ingest"] + ENVC --> dl["data list"] + ENVC --> dd["data delete"] + ENVC --> dv["data validate (local only, no cluster)"] + ENVC --> ci["cluster info"] + ENVC --> doc["doctor (a.k.a. cluster doctor today)"] + ENVC -.-> res["resources — show / set"]:::proposed + + classDef hidden fill:#eee,stroke:#999,stroke-dasharray:3 3,color:#666; + classDef proposed fill:#fff5e6,stroke:#e0a24a,stroke-dasharray:5 5; +``` + +`tb` is a convenience alias for `tracebloc` (installer-placed symlink; identical behavior). Aliases kept one deprecation cycle: `data`↔`dataset`, `data ingest`↔`push`, `data delete`↔`rm`. Hidden nodes are fully functional but off the everyday surface (installer / back-compat). + +--- + +## 2. The two gate chains — the key structural fact + +Commands split into **two independent families** that authenticate differently. Account commands need you signed in (a user token). Data / environment commands are **auth-free w.r.t. your login** — they reach the cluster via kubeconfig RBAC and mint an in-cluster token. Only `client create` and `delete` cross both. + +```mermaid +flowchart TD + subgraph A["Chain A — Account (your user token)"] + a0["login · logout · auth status · client * · delete"] --> a1{"signed in?"} + a1 -->|no| aL(["exit 1 → run: login"]):::fail + a1 -->|yes| a2{"token valid? (WhoAmI)"} + a2 -->|"401 / 403"| aL + a2 -->|"426"| aU(["exit 1 → upgrade the CLI"]):::fail + a2 -->|ok| aOK(["proceed"]):::ok + end + + subgraph B["Chain B — Data & environment (kubeconfig + in-cluster token; NO sign-in)"] + b0["data ingest / list / delete · cluster info · resources"] --> b1{"kubeconfig reachable?"} + b1 -->|no| bK(["exit 3 → fix kubeconfig · doctor"]):::fail + b1 -->|yes| b2{"client / release found?"} + b2 -->|no| bR(["exit 4 → run the installer, or --namespace"]):::fail + b2 -->|yes| b3{"shared storage bound? (ingest / delete)"} + b3 -->|no| bR + b3 -->|yes| b4{"in-cluster token mintable?"} + b4 -->|no| bT(["exit 5 → grant RBAC"]):::fail + b4 -->|yes| bOK(["proceed"]):::ok + end + + classDef fail fill:#fdecec,stroke:#d9534f; + classDef ok fill:#eafaea,stroke:#5cb85c; +``` + +--- + +## 3. `data ingest` — the core flow + +The wizard fills only what flags left empty; off a TTY (or `--no-input` / `--output-json`) every gap becomes a hard error instead of a prompt. + +```mermaid +flowchart TD + di["data ingest <path>"] --> wiz{"interactive TTY
and not --no-input?"} + wiz -->|yes| W["guided wizard — fills only what's missing:
train/test → name → path → task → label → extras → review → confirm"] + wiz -->|no| FLAGS["flag-only path"] + W -->|"cancel / Ctrl-C"| cwiz(["exit 0 — nothing ingested"]):::ok + W --> LOCAL + FLAGS --> LOCAL + + LOCAL{"local checks — path exists · name valid · task supported ·
flags relevant · layout walk · schema · content preflight"} + LOCAL -->|"bad input"| e2(["exit 2"]):::fail + LOCAL -->|"unreadable / parse"| e3(["exit 3"]):::fail + LOCAL -->|ok| CONN["Connecting to your workspace… (Chain B: kubeconfig→3, no client/storage→4)"] + + CONN --> DRY{"--dry-run?"} + DRY -->|yes| e0dry(["exit 0 — checks out, nothing created"]):::ok + DRY -->|no| DEST{"destination already exists?"} + DEST -->|"new"| STAGE + DEST -->|"exists · interactive"| REPL{"replace it?"} + REPL -->|no| e0a(["exit 0 — left as-is"]):::ok + REPL -->|yes| TD + DEST -->|"exists · non-interactive · no --overwrite"| e6(["exit 6 — already exists"]):::fail + DEST -->|"--overwrite"| TD["teardown existing (fail → exit 7)"] + TD --> STAGE + + STAGE["Step 2/3 — copy into your workspace (stage pod; fail → exit 7)"] --> SUB["Step 3/3 — submit → watch → summary"] + SUB --> OUT{"outcome"} + OUT -->|"token 401/403"| e5(["exit 5"]):::fail + OUT -->|"submit rejected 4xx/5xx"| e8(["exit 8"]):::fail + OUT -->|"Failed / Unknown / watch lost / completed-with-failures"| e9(["exit 9"]):::fail + OUT -->|"--detach / Ctrl-C mid-watch"| e0d(["exit 0 — detached (kubectl logs -f)"]):::ok + OUT -->|"Succeeded, clean"| e0s(["exit 0 — done"]):::ok + + classDef fail fill:#fdecec,stroke:#d9534f; + classDef ok fill:#eafaea,stroke:#5cb85c; +``` + +> Note: exit codes are **not** monotonic in execution order — staging (exit 7) runs *before* the token mint (exit 5). The diagram shows the true order. + +--- + +## 4. `resources` — show & set *(feature branch #237/#241, not yet on `develop`)* + +```mermaid +flowchart TD + R0["resources (bare = show)"] --> Rg{"Chain B gates
kubeconfig→3 · no client→4"} + Rg -->|ok| RS(["show machine capacity + per-run ceiling — exit 0"]):::ok + + RSET["resources set [max]"] --> RVsh{"request valid?
(not max+flags; not empty)"} + RVsh -->|no| re2a(["exit 2"]):::fail + RVsh -->|ok| Rmode{"max · flags · or wizard?"} + Rmode -->|"wizard (TTY)"| RW["current vs machine →
'Use as much as possible' (default) / choose / leave"] + Rmode -->|flags| RF["override only the passed dimensions"] + Rmode -->|max| RM["whole machine − overhead"] + RW --> FIT + RF --> FIT + RM --> FIT + + FIT{"fits the machine? (+ floors)"} + FIT -->|no| re2b(["exit 2 — too big / too small
(macOS: raise Docker Desktop)"]):::fail + FIT -->|"no change"| re0n(["exit 0 — nothing to change"]):::ok + FIT -->|ok| CONF{"confirm? (--yes skips)"} + CONF -->|"declined / non-TTY, no --yes"| re0c(["exit 0 declined / exit 1 non-TTY"]):::fail + CONF -->|yes| PIN{"chart version pinned?"} + PIN -->|no| re1(["exit 1 — refuse unpinned upgrade"]):::fail + PIN -->|yes| APPLY(["helm upgrade — applies to your next run — exit 0"]):::ok + + classDef fail fill:#fdecec,stroke:#d9534f; + classDef ok fill:#eafaea,stroke:#5cb85c; +``` + +--- + +## Exit codes + +| code | meaning | +|---|---| +| 0 | success (incl. dry-run, detached, "nothing to change", declined-safely) | +| 1 | generic / account-auth (not signed in, token rejected, upgrade required) | +| 2 | bad input / schema violation / doesn't fit | +| 3 | kubeconfig unreachable, or a local file/parse error | +| 4 | cluster reached but no tracebloc client / storage | +| 5 | in-cluster token could not be minted (RBAC) | +| 6 | destination dataset already exists | +| 7 | staging / teardown failed | +| 8 | jobs-manager rejected the submit | +| 9 | ingestion Job failed / partial-failure / watch error | +| 130 | Ctrl-C | + +## Cross-links — where a dead-end points + +- **not signed in / token 401·403** → `login` +- **426 upgrade-required** → upgrade the CLI +- **kubeconfig (exit 3)** → fix `--kubeconfig`/`--context`, then `doctor` +- **no client / environment (exit 4)** → run the installer (or `--namespace`); triage with `doctor` +- **no token (exit 5)** → grant RBAC; diagnose with `cluster info` / `doctor` +- **destination exists (exit 6)** → `--overwrite`, a different `--name`, or `data delete` first +- **staging partial (exit 7)** → `data delete` then re-ingest +- **ingest failed (exit 9)** → the panel / `kubectl get job` / `kubectl logs -f` +- **no active client** (client status / delete) → `client create` / re-run installer + +## Known gaps / decisions (raise in review) + +1. **Home screen is stateless today.** The status-aware redesign (greeting + sign-in + environment + compute) in `home-screen-spec.md` is *proposed* — it's the target, not current behavior. +2. **`delete` (offboard) exits 0 even on a *partial/degraded* teardown** — it warns but never returns non-zero, so a script can't detect an incomplete offboard. A dedicated non-zero "partial offboard" code would close this. +3. **`resources` is unshipped on `develop`** (feature branch). Merges via #237 (show) → #241 (set). +4. **`cluster doctor` → `tb doctor`** rename is decided (home-screen spec); the map already shows `doctor`. `cluster info`'s home (stay under `cluster`, or also promote) is open. +5. Terminology in the live copy (client / cluster / ``) is pre-cleanup; the map uses the agreed target words (secure environment, etc.). The rename wave aligns the code later. From 2bea5914aef68c7f5673e0d32f659b44243346be Mon Sep 17 00:00:00 2001 From: Arturo Peroni Date: Mon, 13 Jul 2026 11:38:32 +0200 Subject: [PATCH 2/2] =?UTF-8?q?docs:=20nav-map=20=E2=80=94=20resources=20s?= =?UTF-8?q?how=20shipped=20(#237);=20rebase=20on=20develop?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #237 put `resources show` on develop, so un-dash SHOW (keep `set`/#241 dashed), bump the basis commit to develop @27c5392, and reconcile the §4 heading + known-gaps note. The exit-6/--overwrite flow already matches current develop (data.go:236), so it's left as-is. Co-Authored-By: Claude Opus 4.8 (1M context) --- docs/cli-navigation.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/cli-navigation.md b/docs/cli-navigation.md index 2d6b8f57..d668f9d5 100644 --- a/docs/cli-navigation.md +++ b/docs/cli-navigation.md @@ -2,8 +2,8 @@ **The single source of truth for how a user moves through the CLI.** Every command, decision point, and place a user can end up. Diagrams are [Mermaid](https://mermaid.js.org) — they render natively on GitHub and in the docs, and this file is version-controlled, so **edit this file + open a PR to change the map** (that PR is where we discuss flow changes). -> **Basis:** `develop` @ `06f9d41`. Two things are marked distinctly: -> - **`resources`** is on a feature branch (PRs #237 / #241), not yet on `develop` → drawn **dashed / "not shipped"**. +> **Basis:** `develop` @ `27c5392`. Two things are marked distinctly: +> - **`resources show`** has shipped to `develop` (#237) → drawn solid; **`resources set`** (#241) is still on a feature branch → drawn **dashed / "not shipped"**. > - The **status-aware home screen** (greeting + sign-in + environment) is a *proposed* redesign (see `home-screen-spec.md`); today's home screen is **stateless** (same for everyone). Proposed bits are dashed. **How to read it:** `{diamond}` = decision · `[box]` = step · `([rounded])` = where you end up · green = exit 0 · red = non-zero exit · grey dashed = hidden (installer/back-compat) · orange dashed = proposed / not-yet-shipped. @@ -33,7 +33,8 @@ flowchart TD ENVC --> dv["data validate (local only, no cluster)"] ENVC --> ci["cluster info"] ENVC --> doc["doctor (a.k.a. cluster doctor today)"] - ENVC -.-> res["resources — show / set"]:::proposed + ENVC --> res["resources show"] + ENVC -.-> resset["resources set"]:::proposed classDef hidden fill:#eee,stroke:#999,stroke-dasharray:3 3,color:#666; classDef proposed fill:#fff5e6,stroke:#e0a24a,stroke-dasharray:5 5; @@ -121,7 +122,7 @@ flowchart TD --- -## 4. `resources` — show & set *(feature branch #237/#241, not yet on `develop`)* +## 4. `resources` — show & set *(`show` shipped #237, on `develop`; `set` on feature branch #241, not yet on `develop`)* ```mermaid flowchart TD @@ -185,6 +186,6 @@ flowchart TD 1. **Home screen is stateless today.** The status-aware redesign (greeting + sign-in + environment + compute) in `home-screen-spec.md` is *proposed* — it's the target, not current behavior. 2. **`delete` (offboard) exits 0 even on a *partial/degraded* teardown** — it warns but never returns non-zero, so a script can't detect an incomplete offboard. A dedicated non-zero "partial offboard" code would close this. -3. **`resources` is unshipped on `develop`** (feature branch). Merges via #237 (show) → #241 (set). +3. **`resources set` is unshipped on `develop`.** `show` shipped via #237 (now on `develop`); `set` lands via #241 (still on a feature branch). 4. **`cluster doctor` → `tb doctor`** rename is decided (home-screen spec); the map already shows `doctor`. `cluster info`'s home (stay under `cluster`, or also promote) is open. 5. Terminology in the live copy (client / cluster / `
`) is pre-cleanup; the map uses the agreed target words (secure environment, etc.). The rename wave aligns the code later.