Skip to content

PROTOTYPE: client owns teardown; installer stays create front door; withdraw use, hide list#136

Closed
saadqbal wants to merge 2 commits into
developfrom
proto/cli-owns-cluster
Closed

PROTOTYPE: client owns teardown; installer stays create front door; withdraw use, hide list#136
saadqbal wants to merge 2 commits into
developfrom
proto/cli-owns-cluster

Conversation

@saadqbal

@saadqbal saadqbal commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator

Prototype — not for merge as-is. Explores simplifying the client command surface (one machine = one client). After exploring "the CLI bootstraps the cluster," we settled on: the one-line installer stays the front door for create (it already bootstraps the cluster and calls client create to provision — reimplementing k3s/k3d/GPU/proxy in Go isn't worth it, and create → installer would recurse). Still needs an RFC-0001 amendment + tickets to become the design of record.

Final shape of the prototype

  • client create — unchanged behavior (provision-only). The installer bootstraps the cluster, then calls it. (Reverted the earlier spike where create ran k3d/helm itself.)
  • client delete (new) — the inverse teardown: deprovisions the backend client (DELETE /edge-device/<id>/), uninstalls the Helm release, deletes the local k3d cluster, clears the local pointer. Confirms; --yes to skip; 403 → ask-an-admin. No recursion (nothing calls delete).
  • client use — removed (nothing to select when a machine owns one client).
  • client listhidden, not removed: off --help/home screen, but still callable so the installer's one-client-per-machine pre-flight (client#303, provision.sh:_account_owns_namespace) keeps working. No provision.sh change; #303 stays intact.
  • New internal/nodeboot — trimmed to the teardown side: TeardownCluster + UninstallChart (+ ClusterExists), shell-out via injectable Runner. Plus api.Client.DeleteClient.

Caveats (deliberate for a prototype)

Tests

nodeboot: ClusterExists, TeardownCluster (delete-when-present / noop-when-absent), UninstallChart (not-found = noop). cli: client delete (deprovision + uninstall + teardown + clear pointer), no-active-client guard, hidden list still runs. Full go build/vet/gofmt/go test ./... green; client --help shows only create/delete.

To formalize

RFC-0001 amendment (installer = create front door; use gone; list internal-only; delete owns teardown) + tickets, and decide the fate of §7.1/§7.3 + PR #133.

🤖 Generated with Claude Code

@LukasWodka

Copy link
Copy Markdown
Contributor

👋 Heads-up — Code review queue is at 35 / 30

Above the WIP limit. The team convention is to review existing PRs before opening new work.

Open PRs currently in Code review (oldest first):

Pull from review before opening new work. (This is a nudge from the kanban WIP check, not a block.)

@saadqbal saadqbal changed the title PROTOTYPE: client create/delete own the cluster; withdraw list/use PROTOTYPE: client owns teardown; installer stays create front door; withdraw use, hide list Jul 6, 2026
saadqbal added a commit that referenced this pull request Jul 6, 2026
…el (from #133)

Salvage the two pieces of #133 that survive the "use removed / list hidden"
direction (the rest of #133 was `client use` UX, now moot):

- `cluster info` defaults its namespace to the active client's (§7.3) when the
  user gave neither --namespace nor --context, and routes its no-release error
  through binding.explain — so it diagnoses the selected client's cluster (set
  by `client create`), matching the data commands.
- Gate explain on the cluster.ErrNoParentRelease sentinel instead of the
  internal noParentReleaseError wrapper (removed) — simpler, and makes explain
  callable from both the data commands and cluster info.

#133 is superseded by this direction (PR #136) and closed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@saadqbal

saadqbal commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator Author

Reconciliation done (per the "use removed / list hidden" direction):

Gate to flip this from draft → ready: accept the §15 amendment (#139), then close out #140/#141.

…lete + nodeboot

develop's #142 landed the §7.3 namespace-discovery + cluster-info binding (the
pieces this branch had folded from #133), so those are dropped as redundant.
What remains unique to this prototype (RFC-0001 §15, cli#136) is re-applied
cleanly on top of #142:

- `client use` removed; `client list` hidden (installer #303 pre-flight only);
  `client delete` added — deprovision + helm uninstall + local cluster delete.
- internal/nodeboot (TeardownCluster + UninstallChart) + api.DeleteClient.
- RFC-0001 §15 amendment (PROPOSED).

Rebuilt via reset-to-develop + re-apply to avoid a semantic mis-merge (the
auto-merge had silently reverted the surface to develop's create/list/use).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@saadqbal saadqbal force-pushed the proto/cli-owns-cluster branch from f49ebbe to 9a54abe Compare July 7, 2026 07:30
…ster

# Conflicts:
#	docs/rfcs/0001-cli-auth-and-client-provisioning.md
#	internal/cli/client.go
#	internal/cli/client_test.go
@saadqbal

saadqbal commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator Author

Closing this prototype as superseded — rather than merging the prototype itself, its pieces shipped (or are shipping) as focused PRs against the current develop:

That's why it went CONFLICTING — develop moved on underneath it. The branch stays for reference; happy to reopen a scoped PR if we want the prototype's client-owns-teardown angle on its own later.

@saadqbal saadqbal closed this Jul 7, 2026
saadqbal added a commit that referenced this pull request Jul 7, 2026
…ace (§7.10) (#160)

* feat(nodeboot): node teardown seam for offboarding (RFC-0001 §7.10)

Add internal/nodeboot — the inverse of the installer's node bootstrap that
`tracebloc delete` will drive. Based on the cli#136 prototype's k3d/helm
teardown, with an injectable Runner exec seam:

  - ClusterExists(name) / TeardownCluster(name) — `k3d cluster delete` when the
    cluster exists (also prunes its kubeconfig entry); a missing cluster is an
    idempotent no-op.
  - UninstallChart(namespace) — `helm uninstall`, swallowing not-found.
  - PruneImages() — NEW beyond #136: reclaim tracebloc images, SCOPED to
    `ghcr.io/tracebloc/*` (docker images -q | docker rmi), deduped, best-effort.
    NEVER a blanket `docker system prune`.

All four are unit-tested against a fake Runner — no real k3d/helm/docker runs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(cli): top-level `tracebloc delete` offboarding (RFC-0001 §7.10)

Add `tracebloc delete` — a top-level command (NOT `client delete --uninstall`):
on the single-machine CLI the host owns one client, so "delete the client" is
"remove tracebloc," and a top-level verb avoids colliding with `data delete`.

A SOFT offboard with a removed / retained / left three-way summary shown before
a TYPED-CLIENT-NAME confirm (skipped only with --yes). Flow, in order:

  - guard: refuse if the client is online / has a running job unless --force
    (reuses the #146 lookupClientStatus / clientStatusOnline);
  - api.RevokeClient(id) → POST /edge-device/<id>/revoke (NEW; 2xx = revoked) —
    kills the credential while PRESERVING the row (never a hard destroy that
    would cascade the retained training history);
  - nodeboot.UninstallChart → TeardownCluster → PruneImages (best-effort warns);
  - rm -rf HOST_DATA_DIR (~/.tracebloc) unless --keep-data;
  - remove the running CLI binary + its sibling `tb` symlink LAST (best-effort;
    on failure prints the exact rm, or `brew uninstall tracebloc` if brew-managed).

Never removes Docker/Homebrew/kubectl/k3d/helm/NVIDIA, never reboots, never
`docker system prune`. Flags: --yes / --keep-data / --force + the standard
--kubeconfig/--context/--namespace; uses the existing exitError contract.

Tests (fake nodeboot Runner + httptest backend + temp HOST_DATA_DIR + temp
config dir; no real ~/.tracebloc, k3d/helm/docker): (a) no --yes non-interactive
refuses with no side effects; (b) --yes runs the full sequence — revoke POSTed to
/edge-device/<id>/revoke, nodeboot fakes called in order, ~/.tracebloc removed;
(c) --keep-data spares ~/.tracebloc; (d) running job refuses unless --force;
(e) the RETAINED + LEFT copy is present in output.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor(cli): withdraw `client use`, hide `client list` (RFC-0001 §7.10)

The single-machine CLI owns exactly one client, so there is nothing to select:

  - Remove `client use` (newClientUseCmd + runClientUse + its AddCommand entry +
    TestClientUse). The active-client pointer is now set only by `client create`.
  - Hide `client list` (Hidden: true) — kept callable for the installer's
    one-client-per-machine pre-flight, off the user-facing surface.
  - Rewrite the `client` parent help and the root home-screen: drop the
    `client list` line, add `tracebloc delete`, point offboarding at it.
  - Retarget the residual "run `client use`" guidance (create save-failure fallback,
    client status, doctor, clustertarget "runs elsewhere" + multi-namespace refusal)
    to `client create` / --namespace, and adjust the test that asserted the old string.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(cli): correct data-delete catalog copy — kept, not removed (RFC-0001 §7.10)

The catalog metadata for a deleted dataset is NEVER removed — it is kept as a
record on tracebloc and marked unavailable (soft-flagged). The old
"removed automatically" copy in `data delete` help + its success line, and the
push.TeardownPlan doc comment, wrongly implied the backend deletes it. Reword
all three to "kept as a record on tracebloc, marked unavailable."

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(cli): redirect the save-failure hint off the removed `client use`

Review finding (medium): the client-create config-save fallback still pointed
at `tracebloc client use %d`, which T3 removes. Point it at `client create`
(idempotent — it re-adopts this cluster's client).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(cli): address delete-offboard review findings (§7.10)

Review follow-ups on the tracebloc delete offboarding PR:

- api: RevokeClient POSTs to /edge-device/<id>/revoke/ WITH a trailing
  slash — the DRF DefaultRouter registers the `revoke` @action as
  /edge-device/<pk>/revoke/, and a slashless body-bearing POST hits
  Django's APPEND_SLASH (which errors instead of redirecting), aborting
  the whole offboard at step 1.
- cli: a 403 on revoke now speaks in offboard terms ("offboarding
  requires CLIENT_WRITE") instead of the provisioning copy the shared
  askAnAdmin hardcoded; askAnAdmin takes action/capability params.
- cli: an empty namespace warns + points at --namespace instead of
  silently skipping the Helm uninstall while the summary claims success.
- nodeboot: UninstallChart matches helm's specific "release: not found",
  not a bare "not found" that could swallow a cluster-unreachable error.
- cli: --force help no longer advertises a running-job check the guard
  doesn't implement.
- cli: looksBrewManaged resolves symlinks so the Intel /usr/local/bin →
  Cellar install gets the `brew uninstall` hint.
- config: correct stale `client use` comment.

Tests added for each behavioral fix; go build/vet/test green (11 pkgs).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Asad Iqbal <asad.dsoft@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants