Problem
On an existing-fleet box, a live tracebloc client whose backend cluster_id is still null (installed before the anchor shipped) is re-provisioned by tracebloc client create: it reads the cluster's kube-system UID, the backend finds no client bound to that cluster_id, and mints a fresh client + stamps the anchor on the new one — stranding the live client. This is the RFC-0001 §7.2 / R7 case the create flow explicitly defers (internal/cli/client.go:272–276: "…the CLI backfills it via PATCH … not done here").
This is the root cause behind the installer band-aid in tracebloc/client#303 (PR #305): that pre-flight refuses the second mint, but the proper fix is to adopt the live client and backfill its anchor.
Backend is ready (no changes needed)
backend#883/#893 (merged to master, commit ee247ee4) already ships: EdgeDevice.cluster_id (partial-unique), account-scoped get-or-create (200 adopt / 201 mint), cross-account 409, and PATCH /edge-device/{id}/ adopt-backfill (write-once, clash→409, idempotent). Gate release on confirming dev/prod actually run a build with #893.
CLI work
- api: add
PatchClientClusterID(ctx, id, clusterID) → PATCH /edge-device/{id}/ body {"cluster_id":…}; map the write-once/clash 409 to a typed error.
- cluster discovery: add a best-effort reader for the live in-cluster
CLIENT_ID — Secret <release>-secrets key CLIENT_ID, found cluster-wide by the chart labels app.kubernetes.io/name=client,app.kubernetes.io/managed-by=Helm.
- client create: before minting, if a live client id X is discovered AND the kube-system UID is readable → look X up in
ListClients (confirm account ownership + numeric id + namespace): owned → PATCH-backfill cluster_id onto X (skip if set) and adopt it (write the ADOPTED credential; no mint); not in the account → refuse (mirror the cross-account 409). No live client → unchanged.
- installer (tracebloc/client): retire the #305 ownership pre-flight once create adopts-and-backfills; keep the Helm-step one-client guard as a backstop.
Acceptance
- Existing-fleet box (live client, null cluster_id, same account) re-run → the live client's cluster_id is backfilled and it is adopted; NO new client on the dashboard.
- Live client owned by a different account → refuse, no mint.
- Fresh machine (no live client) → mint as today.
- Anchored re-run (cluster_id already set) → adopts via the existing 200 path.
Problem
On an existing-fleet box, a live tracebloc client whose backend
cluster_idis still null (installed before the anchor shipped) is re-provisioned bytracebloc client create: it reads the cluster's kube-system UID, the backend finds no client bound to thatcluster_id, and mints a fresh client + stamps the anchor on the new one — stranding the live client. This is the RFC-0001 §7.2 / R7 case the create flow explicitly defers (internal/cli/client.go:272–276: "…the CLI backfills it via PATCH … not done here").This is the root cause behind the installer band-aid in tracebloc/client#303 (PR #305): that pre-flight refuses the second mint, but the proper fix is to adopt the live client and backfill its anchor.
Backend is ready (no changes needed)
backend#883/#893 (merged to master, commit ee247ee4) already ships:
EdgeDevice.cluster_id(partial-unique), account-scoped get-or-create (200 adopt / 201 mint), cross-account409, andPATCH /edge-device/{id}/adopt-backfill (write-once, clash→409, idempotent). Gate release on confirming dev/prod actually run a build with #893.CLI work
PatchClientClusterID(ctx, id, clusterID)→PATCH /edge-device/{id}/body{"cluster_id":…}; map the write-once/clash 409 to a typed error.CLIENT_ID— Secret<release>-secretskeyCLIENT_ID, found cluster-wide by the chart labelsapp.kubernetes.io/name=client,app.kubernetes.io/managed-by=Helm.ListClients(confirm account ownership + numeric id + namespace): owned → PATCH-backfillcluster_idonto X (skip if set) and adopt it (write the ADOPTED credential; no mint); not in the account → refuse (mirror the cross-account 409). No live client → unchanged.Acceptance