Uh oh!
There was an error while loading. Please reload this page.
feat(cli#128): selected-vs-connected — bind data commands to the active client (§7.3) - #130
Conversation
…i#127) data ingest / list / delete each repeated the same Load -> NewClientset -> DiscoverParentRelease (-> DiscoverSharedPVC) sequence and its exit-code contract (3 for kubeconfig/clientset, 4 for a missing release/PVC). Collapse it into one helper in clustertarget.go. Behavior-preserving; `cluster doctor` is deliberately not a caller (it has a different 2/3-escalation exit contract). This is the resolveClusterTarget task from cli#127, landed here as the base for the cli#128 §7.3 binding. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
RFC-0001 §7.3: "selected" (a local pointer) was not "connected" (a reachable cluster). `client use` set only a pointer, and the data commands ignored it — they targeted whatever the current kubeconfig context pointed at, risking a silent wrong-target on a multi-cluster / remote host. - Cache the active client's namespace + display name in the env profile at `client use` / `create` time (new setActiveClient), so the data commands can bind without a backend round-trip (they run cluster-local, maybe offline). - data ingest/list/delete default -n to the active client's namespace when the user gave neither --namespace nor --context (bindActiveClientNamespace). No active client → unchanged current-context behavior (backward compatible). - A "no release in namespace" miss on a bound namespace is rewritten to the §7.3 "active client runs on another machine" guidance (typed noParentReleaseError), while a PVC-missing failure passes through. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
`client list` marked only the active (selected) client and showed no connection state, so a stale pointer to a client whose cluster is gone was invisible. Add a state column (online/offline/pending) sourced from the backend EdgeDevice.status code — the "connected somewhere" signal per RFC-0001 C.4 — alongside the existing "(active — this machine)" marker, and a hint separating selected (local pointer) from connected (backend heartbeat). Plain words, not flag/emoji glyphs, to avoid the CI/Windows-console mojibake called out as a §12 watch-item. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
LukasWodka
commented
Jul 6, 2026
👋 Heads-up — Code review queue is at 31 / 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.) |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Want fixes drafted automatically? Bugbot Autofix can create code changes for findings. A team admin can enable Autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 758af8d. Configure here.
Uh oh!
There was an error while loading. Please reload this page.
…re" (Bugbot) The §7.3 binding wrapped every DiscoverParentRelease failure in noParentReleaseError, so `explain` rewrote API/RBAC list errors and ambiguous multiple-release matches as "the active client runs on another machine" — hiding the real diagnostic. Add a cluster.ErrNoParentRelease sentinel on the true not-found case and gate the wrapping (and thus the rewrite) on errors.Is; other discovery failures keep their own message and exit 4. Tests assert the sentinel matches not-found and not the multiple-release case. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
aptracebloc
left a comment
There was a problem hiding this comment.
Approving. Clean implementation of RFC-0001 §7.3 — the refactor is a solid DRY win and the binding is careful. A couple of non-blocking notes below.
Summary
resolveClusterTargetcentralizes theLoad → NewClientset → DiscoverParentRelease (→ PVC)block + the 3/4 exit contract out of the three data commands (cluster doctorcorrectly excluded — different 2/3 contract).- §7.3 binding:
client use/createcache the active client's namespace+name; data commands default-nto it only when neither--namespacenor--contextwas given. A "no release here" miss on a bound namespace is rewritten to the "runs on another machine" guidance. client listshowsstate=(backend heartbeat) +(active — this machine)+ a selected-vs-connected hint.
What stands out
- Precise error plumbing: the new
cluster.ErrNoParentReleasesentinel +errors.Is/errors.Asmean only the genuine "namespace has no release" binding-miss gets rewritten — RBAC / ambiguous-multi-release / PVC-missing errors pass through untouched. Not a blanket rewrite. - Backward-compatible + non-presumptuous: no active client / no cache / explicit
--namespace|--context→ unchanged current-context behavior; explicit flags always win; new config fields areomitempty(v1/v2 configs unaffected). - Offline-correct: namespace cached at use/create rather than a per-run backend lookup — and namespace is effectively immutable per client, so staleness isn't a concern.
- Good coverage of the binding (default / explicit-override no-op / no-active no-op), the
explainrewrite-vs-passthrough, the sentinel, and the state-label mapping.
Non-blocking notes
- Deliberate default-targeting change: once a user has run
client use/create, a baredata …now targets the cached namespace, not the kubeconfig's current namespace. That's the §7.3 intent and it's mitigated (explicit flags override, clear message) — just flagging it changes behavior for already-migrated users. - Binding is namespace-string-based, not identity-based — it defaults the namespace but not the cluster/context, so a wrong cluster is detected via the discovery miss + "runs elsewhere" message rather than prevented. Narrow gap: a different cluster hosting a release under the same namespace name wouldn't be caught (silent right-namespace-wrong-cluster). Almost certainly fine given slug-derived namespaces — worth a one-line confirmation, not a change.
— drafted with Claude (Opus 4.8), sent by @aptracebloc
Uh oh!
There was an error while loading. Please reload this page.

Closes#128. Implements RFC-0001 §7.3 ("'selected' is not 'connected'") —
client useset only a local pointer while the data commands ignored it and targeted whatever the current kubeconfig pointed at, risking a silent wrong-target on multi-cluster / remote hosts.Three logical commits (each builds + tests on its own):
resolveClusterTarget, collapsing the duplicatedLoad → NewClientset → DiscoverParentRelease (→ DiscoverSharedPVC)block + its exit-code contract (3 kubeconfig/clientset, 4 missing release/PVC) out ofdata ingest/list/delete. This is theresolveClusterTargettask from CLI quick wins: cluster-connect + kubeconfig-flag helpers, rename sweep, pinned lint + deadcode gate #127, landed here as the base (the rest of CLI quick wins: cluster-connect + kubeconfig-flag helpers, rename sweep, pinned lint + deadcode gate #127 stays a separate quick-wins PR, different epic).cluster doctordeliberately excluded (different 2/3 exit contract).client use/create(setActiveClient), so data commands bind without a backend round-trip (they run cluster-local, maybe offline).data ingest/list/deletedefault-nto it when the user gave neither--namespacenor--context; no active client → unchanged current-context behavior (backward compatible). A "no release here" miss on a bound namespace is rewritten to the §7.3 "active client runs on another machine" guidance (typednoParentReleaseError); a PVC-missing failure passes through.client liststate column (§7.3) — add online/offline/pending from the backendEdgeDevice.statuscode (the "connected somewhere" signal, C.4) beside the(active — this machine)marker, plus a hint separating selected (local pointer) from connected (backend heartbeat). Plain words, not emoji glyphs (§12 mojibake watch-item).Design decisions
active_client_namespace+active_client_nameto the config Profile (bothomitempty→ v1/v2 configs unaffected).status), not per-row local cluster probing (that's the slow path flagged in §12); local reachability stays a per-active-client concern.Not in scope
client use(issue marks it optional; would add a cluster dial to an intentionally cluster-free command) — left as a follow-up.Verification
go build ./...,go vet ./...,gofmt, and the fullgo test ./...suite are green; new tests inclustertarget_test.gocover the state-label mapping, binding (defaults / explicit-override no-op / no-active-client no-op),explain(rewrite vs pass-through), and thesetActiveClientcache.🤖 Generated with Claude Code
Note
Medium Risk
Data commands may target a different namespace when an active client is set, which changes default cluster targeting for multi-cluster setups; behavior is backward compatible without a cached namespace.
Overview
Implements RFC-0001 §7.3 so
data ingest,data list, anddata deleteno longer ignore the machine's active client and silently target whatever the kubeconfig's current context implies.Active client binding:
client create/client usenow callsetActiveClient, which persistsactive_client_namespaceandactive_client_nameon the env profile (alongsideactive_client_id). When neither--namespacenor--contextis set, data commands default the target namespace from that cache—no backend call—while explicit flags still win. No cached active client keeps the old current-context behavior.Cluster resolution: Shared
resolveClusterTargetreplaces duplicated kubeconfig → clientset → parent release (→ PVC) logic and preserves exit codes 3/4.DiscoverParentReleaseexposesErrNoParentReleaseso a true "no release in namespace" can be distinguished from RBAC or ambiguous multi-release errors; bound-namespace misses get a "active client runs on another machine" message viaactiveClientBinding.explain(PVC failures are not rewritten).client list: Rows show backendstate=(online/offline/pendingas plain text),(active — this machine)on the selected id, and a short hint separating local selected from backend connected heartbeat.Reviewed by Cursor Bugbot for commit e798dc8. Bugbot is set up for automated code reviews on this repo. Configure here.