Skip to content

develop -> main - #164

Merged
saadqbal merged 17 commits into
mainfrom
develop
Jul 8, 2026
Merged

develop -> main#164
saadqbal merged 17 commits into
mainfrom
develop

Conversation

@saadqbal

@saadqbalsaadqbal commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

Note

Medium Risk
tracebloc delete is irreversible local teardown plus credential revoke; behavior is heavily tested and backend rows are preserved, but mis-runs or partial teardown still need careful operator review.

Overview
Machine offboarding (RFC-0001 §7.10) adds top-level tracebloc delete: typed-name confirm (or --yes), POST /edge-device/<id>/revoke/ via new RevokeClient, then best-effort local teardown through internal/nodeboot (helm uninstall, k3d delete, scoped ghcr.io/tracebloc/* image prune, optional ~/.tracebloc wipe, CLI/tb removal). Backend client history stays; closing output distinguishes clean vs degraded teardown.

Single-machine client UX drops client use, hides client list (installer-only), and updates hints away from multi-client selection. askAnAdmin takes action-specific copy for provision vs offboard.

CLI ergonomics (#75): parent commands use runGroup so mistyped subcommands exit non-zero with suggestions (hidden commands excluded).

Cluster / ingest: ingestor SA comes from the ingestion-authz ConfigMap ( --ingestor-sa removed ). Token mint records server ExpiresAt for cluster info. Successful ingests run CleanStaging to drop .tracebloc-staging/<table> on the PVC. data delete copy now says catalog metadata is retained, not auto-removed.

Docs: RFC 0001 Rev 9 (offboarding, revoke vs DELETE); new RFC 0002 draft for inverted data ingest UX. Category registry adds sentence_pair_classification and embeddings; parity goldens cover schema-aware tabular label checks.

Reviewed by Cursor Bugbot for commit 073d19a. Bugbot is set up for automated code reviews on this repo. Configure here.

saadqbaland others added 6 commits July 7, 2026 16:50
main's promote-merge commits (#148, #155) aren't in develop's ancestry, so the
next develop→main promote would conflict on release drift again. Trees are
already identical (v0.6.0 == develop), so this changes no files — it only brings
main's history into develop so future promotes fast-forward cleanly.
…op-2026-07-07
chore: back-merge main → develop (reset promote ancestry after v0.6.0)
test(preflight): pin #152's schema-type-aware label diversity in the parity harness
…+ single-machine CLI scope (#157)
Decided by Lukas 2026-07-07. Two coupled decisions:
- The CLI is scoped to THIS machine (one client per machine — the §7.2
anchor); the account's fleet lives in the web-UI. So `client use` is
removed and `client list` is internal-only (hidden; still callable for
the installer pre-flight). Amends the §6.2 surface; folds in the cli#136
client-surface prototype.
- Offboarding is a top-level `tracebloc delete` (not `client delete
--uninstall`): a SOFT offboard that revokes the machine credential,
tears down the local install, wipes local data, and RETAINS all backend
artifacts (client record, dataset catalog, use cases, trained models) as
history. A hard row-destroy is REJECTED — it would cascade the client's
training telemetry (weight refs, confusion matrices, carbon).
New §7.10 (design of record) + Rev 9 callouts on §6.2/§7.4; R12 flipped to
addressed; C.6 corrected to name the built machine-revoke endpoint
(POST /edge-device/<id>/revoke, backend#886) and note DELETE is unrouted.
Supersedes the cli#136 proto's client delete/DELETE offboarding draft.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…beddings (#162) (#163)
The Schema drift check (scripts/sync-schema.sh --check) was red on every
open PR: internal/schema/ingest.v1.json had drifted from upstream
tracebloc/data-ingestors@master, which added two task categories
(sentence_pair_classification, embeddings), a content_hash data_id
strategy, and description updates.
- Re-vendor the current upstream schema (sync-schema.sh).
- Add both new categories to categoryRegistry as FamilyText (they stage
raw .txt from texts/, per data-ingestors conventions.py TEXT_CATEGORIES).
- Mark both CLISupported: false with an UnsupportedNote, mirroring
causal_language_modeling/seq2seq/token_classification, until the
`tracebloc ingest` discover/build staging path for them is confirmed.
(Flip to true if the push path already supports them.)
- Update the pinned lists in category_registry_test.go.
Fixes the registry⇄schema parity test (TestRegistryCoversSchemaCategories)
that a bare schema sync would otherwise break. go build/vet/test green.
Closes#162
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…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>
Comment threadinternal/cli/delete.go
Comment threadinternal/cli/delete.go
…inter under --keep-data (#165)
Two Cursor Bugbot findings on the develop->main PR (#164):
- High: `tracebloc delete` registered --kubeconfig/--context but runDelete
never read them, so `helm uninstall` ran against the ambient
current-context — offboarding could uninstall the wrong release when the
operator's context isn't the tracebloc cluster. UninstallChart now takes
kubeconfig + kubeContext and appends --kubeconfig/--kube-context (only
when set, preserving default-context behavior); runDelete threads the
flags through. (k3d cluster delete targets the cluster by name, so it's
context-independent.)
- Medium: under --keep-data, offboard revoked the credential but left the
active-client pointer in ~/.tracebloc, so a later sign-in/reinstall still
saw the host as enrolled as the (now-revoked) client. Clear
ActiveClientID/Name/Namespace even under --keep-data (token + on-host data
stay; re-running `client create` re-adopts by cluster_id), per §7.5.
Tests: flags reach helm (unit + delete-level); --keep-data clears the
pointer while sparing the data dir. go build/vet/test green (11 pkgs).
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Comment threadinternal/cli/delete.go
saadqbaland others added 2 commits July 7, 2026 18:41
…p stale client-list hints (#168)
Thorough review pass on the develop->main PR (#164), addressing the new
Bugbot finding plus adjacent gaps a review flagged:
- Stale client pointer after a failed wipe (Bugbot): after revoke, if
`rm -rf ~/.tracebloc` failed the default path left the active-client
pointer intact (the --keep-data path cleared it). Now the pointer is
cleared in memory once after revoke and persisted in BOTH paths, incl.
the wipe-failure branch — the host never looks enrolled under a dead
credential.
- Misleading success line: the closing "Offboarded … no longer connected"
printed unconditionally even when uninstall/teardown/wipe left real state
behind (all best-effort warns). Track a `degraded` flag over the
state-leaving steps and print an honest closing that tells the user to
finish the flagged steps by hand. (Image reclaim is pure disk cleanup —
excluded; exit stays 0 since the credential revoke, the core, succeeded.)
- Online guard: a stored id not in the signed-in account (found=false) now
emits a hint instead of silently passing the guard.
- Stale copy: `client status` errors pointed at the now-hidden
`client list`; retargeted to `client create` / the installer, matching
the phrasing used elsewhere. Fixed a `create/use` comment (use removed).
Tests added: wipe-failure clears the pointer; a failed teardown produces
the degraded closing. go build/vet/test green (11 pkgs). Rolls up under
the §7.10 offboarding work (Bugbot follow-up).
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
#166) (#167)
The CLI streams a full copy of the dataset into
SharedRoot/.tracebloc-staging/<table>, and the in-cluster ingestor
COPIES (shutil.copy, never moves) those files into the final table dir.
So after a successful `tracebloc data ingest` BOTH copies lived on the
shared PVC — the staged source was only ever removed by `data delete`
or an `--overwrite` re-ingest. Every successful push of a file-bearing
dataset silently doubled PVC usage, eventually surfacing as
"no space left on device" on a later ingest with no signal as to why.
Add push.CleanStaging: a best-effort rm -rf of ONLY StagedPrefix(table)
via the same ephemeral stage-identity pod Teardown already uses (it runs
as the uid that wrote the staging files, so the rm works by ownership on
hostPath and CSI alike). It never touches the final table dir or the
MySQL table. runDataIngest calls it after a CLEAN success only
(classifyPushOutcome == "succeeded"), so it never fires on --detach (the
Job is still reading the source), completed_with_failures, or any
failure. A failed reclaim logs a warning and does not fail the ingest.
Robustness (from pre-PR adversarial review, all low-severity):
- the reclaim's wait+exec is bounded by StagingCleanupTimeout (45s) so a
stuck/unschedulable cleanup pod can't tack the full pod-ready timeout
onto a command the user already saw succeed;
- the cleanup pod is created under a detached context so a parent-ctx
cancel in the create window can't orphan a server-committed pod;
- with --output-json the result object is emitted BEFORE the reclaim, so
scripted consumers get their result at ingest-completion latency.
Longer term the cleaner fix is server-side (ingestor move-not-copy /
remove SRC after a verified load) — will file a data-ingestors follow-up.
Closes#166. Refs #67.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment threadinternal/cli/delete.go Outdated
Comment threadinternal/cli/delete.go
…save
fix(cli): delete guard fails fast on 426; keep-data save failure marks offboard degraded
Comment threadinternal/cli/delete.go
LukasWodkaand others added 3 commits July 7, 2026 17:28
…171)
`removeSelf` deleted any sibling file named `tb` (guard was only `tb !=
exe`), with no check that it was tracebloc's own symlink. If a user had an
unrelated `tb` on the same PATH dir tracebloc installed into (another
tool's binary, or a symlink elsewhere), `tracebloc delete` removed it —
wrong-target deletion of a file tracebloc never created.
Make delete symmetric with install. The installer refuses to clobber a
pre-existing `tb` (install.sh: creates it only when absent or when
`readlink tb == PREFIX/tracebloc`). Delete now mirrors that: new
aliasStatus() removes `tb` only when it is a symlink resolving to this
binary; a regular file or a symlink pointing elsewhere is left in place
with a note ("isn't tracebloc's `tb` alias"). Relative targets resolve
against the link dir, and an EvalSymlinks fallback covers the case where
the binary itself is a symlink (Intel Homebrew).
Found in the FR review of the offboarding surface; not a Bugbot finding.
Tests: TestDelete_OwnTBAlias_Removed (real tb->binary symlink is removed),
TestDelete_ForeignTBAlias_Left (a foreign regular-file `tb` is NOT removed
and is reported), and the full-sequence test now lays down a real symlink.
The foreign-tb test is verified to fail without the guard. Suite + vet green.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
)
The `tracebloc data ingest` run worked but spoke Kubernetes and went
silent at the worst moment. Three UX fixes surfaced by the ingest-flow
audit:
1. Silent hang after submit. WatchJob's waitForJobPod polls up to 5 min
(PodReadyTimeout) for the ingestor Pod to schedule + pull its image,
printing nothing — the CLI looked hung right after the key step. Now
a live spinner ("Waiting for the ingestion to start…", with a Ctrl-C
hint) covers that wait, then a clean "Ingestion started — live
progress:" precedes the log stream. WatchJob takes a nil-safe
*ui.Printer for this; nil (tests) stays silent as before.
2. Undisclosed 1-hour watch cap. JobWatchTimeout is 1h; on expiry the
CLI silently "detached". Step 4 now discloses the follow window up
front — and only when NOT --detach (the hints used to promise
streaming even under --detach, which was itself dishonest).
3. Kubernetes jargon on the happy path. Reworded the run narrative to
plain language: upload-channel wording instead of "stage Pod",
"Submitted — tracebloc is validating your data…", "Connecting to your
workspace to submit the run…", and plain detach/timeout messages. The
raw `kubectl logs` reconnect stays (there is no CLI re-attach verb
yet) but as a labelled optional follow, not jargon in a sentence.
From the pre-PR adversarial review: the green "✔ Ingestion started" now
only shows for a live/completed pod — a Pod already Failed (immediate
crash, or a prior backoffLimit retry) gets a neutral "streaming logs:"
line instead of a success checkmark before its crash output
(waitForJobPod now returns the selected pod's phase). The
pod-wait-timeout detach message no longer claims "you don't need to do
anything" (false for the PSA-rejection / unschedulable subcases the same
path covers).
No control-flow or exit-code changes — output copy + one nil-safe
progress-reporter param. Tests updated for the reworded strings + the
new waitForJobPod phase return.
Closes#172. Part of the data ingest UX sweep (epic #67).
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…nomy (#174)
* docs(rfc-0002): tracebloc data ingest — flow, terminology & task taxonomy
Draft RFC capturing the ingest-UX redesign discussed with Lukas:
- Invert the flow: ask for the DATA first, sniff the family from the
layout, then offer only the compatible tasks — instead of the current
task-first 16-item wall shown before anything is known about the data.
- Accept a flexible input path (a bare .csv for tabular/time, a directory
otherwise) — today every family requires a directory, even tabular.
- Never "upload/push/stage" in user copy — the data stays on the user's
own infrastructure; "ingest" umbrella, "copy into your storage" for the
move. Rename --category -> --task (required), --intent -> --split.
- Reduce ceremony: one environment, so drop "Connect to your workspace"
and the cluster/PVC fields; Kubernetes behind --verbose.
- The 15 ML tasks with data-scientist-facing names + one-liners (HF /
scikit-learn / Papers With Code research); the label column is
task-specific (skipped for the self-supervised text tasks).
- The taxonomy contract: the task list is duplicated in 5 places across 3
repos with one enforced edge; make the schema enum the single source of
truth + cross-repo drift checks.
- Phased delivery incl. wiring the 5 CLI-pending text tasks so the CLI
matches the platform.
Grounded in a code-level audit of CLI develop + the ingestor + the
backend. Supersedes the copy in #173 where they conflict.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs(rfc-0002): Rev 2 — split→name→path order, file-or-folder echo, label column task-specific
Per discussion with Lukas: settle the Phase-1 prompt order (train/test →
name → path → task), make the file-or-folder mental model explicit (point
at your data in whatever shape it has; the "Found ..." echo removes the
confusion), and move the label column fully into the task-specific
questions.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs(rfc-0002): Rev 3 — label design (kill #340 silent-null) + full 15-task input matrix
Rewrite the label section: three shapes (class/target/absent), precise
per-family wording (never the ambiguous "label to predict"), and
pick-from-real-headers + exact-match-or-hard-fail validation that closes
the data-ingestors#340 case-mismatch silent-NULL-label bug. Add the full
task-specific input matrix for all 15 tasks. New reconciliation open
questions (drop vestigial --label-column for sidecar-labeled vision,
forecasting timestamp gap, target_size placement, schema-for-regression).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs(rfc-0002): Rev 4 — settle the 4 reconciliation decisions
Per Lukas: drop --label-column for sidecar-labeled vision (object
detection/keypoint/segmentation); forecasting gets a first-class
timestamp prompt + preflight; normalize --target-size to file_options;
surface inferred schema for confirmation on the regression family.
Task display names remain under review (decoupled from the wire task_id).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment threadinternal/cli/delete.go Outdated
Comment threadinternal/cli/delete.go
…of exiting 0 (#75) (#175)
`tracebloc data ingst` (and cluster/auth/client typos) printed the group's
help and exited 0, silently swallowing the mistake. A parent command with
subcommands but no Run/RunE is "not runnable", and cobra short-circuits a
non-runnable command to flag.ErrHelp BEFORE it validates args — so the
unknown token never reached arg validation. (The issue's suggested
`cobra.NoArgs` does NOT fix this: it's an arg validator, never reached on a
non-runnable command.)
Give the four group commands (data, cluster, auth, client) a RunE=runGroup:
a bare `tracebloc <group>` still prints help and exits 0, but a mistyped
subcommand is now a hard error (exit 1) with a nearest-match suggestion,
matching the "unknown command" wording the root already emits via its
default legacyArgs. SuggestionsMinimumDistance=2 drives the hint;
SuggestionsFor skips hidden commands, so the Rev-9 hidden `client list` is
never suggested. The root command is unchanged — as the parent-less command
it already errored on unknown tokens.
Tests: internal/cli/group_test.go — unknown-subcommand-errors (across all
four groups + the `dataset` alias), nearest-match suggestion, hidden-list
not suggested, bare-group-still-helps. The error cases are verified to fail
without the fix (unfixed groups print help + exit 0). Full internal suite +
vet + gofmt green.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment threadinternal/submit/watch.go
LukasWodkaand others added 3 commits July 8, 2026 12:02
… drop --ingestor-sa (#7) (#176)
The ingestor ServiceAccount name was hardcoded to "ingestor" in
DiscoverParentRelease, with a manual --ingestor-sa flag on both
`cluster info` and `data ingest` as the only escape for customers who
set a non-default `ingestionAuthz.serviceAccountName`. A renamed SA
made the CLI mint a token jobs-manager then rejected — and `data delete`
had no flag at all, so it broke with no workaround.
Discover it instead from the chart's `<release>-ingestion-authz`
ConfigMap (key `ingestion-authz.yaml`) — the very policy jobs-manager
enforces, so it's the authoritative source. New best-effort
cluster.discoverIngestorSAName reads `allowed[]`, keeps entries whose
`namespace` matches the namespace we mint in (the rendered policy
always populates namespace), and requires exactly one distinct
`service_account`; a missing ConfigMap (older chart), RBAC denial,
empty, or ambiguous policy all keep the "ingestor" default. It never
errors — discovery is advisory.
With discovery authoritative, --ingestor-sa is removed from `cluster
info` and `data ingest` (its acceptance criteria); everything
downstream (stage/teardown pods, the jobs-manager token mint, and now
`data delete`) reads the discovered release.IngestorSAName.
Verified the contract against tracebloc/client
templates/ingestion-authz-configmap.yaml: name `<release>-ingestion-authz`,
key `ingestion-authz.yaml`, `allowed[].service_account` + per-entry
`namespace` — NOT the top-level `serviceAccountName` the issue sketched.
Tests: discover_test.go — DiscoversRenamedSAFromConfigMap,
AmbiguousSAKeepsDefault, CrossNamespaceSAIgnored (pins the namespace
gate); the existing happy-path (no ConfigMap) proves the fallback. Full
internal suite + vet + gofmt green.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…e requested one (#4) (#177)
`cluster info` printed the REQUESTED token lifetime ("expires in ~10m0s
(server may cap shorter)"), computed from ExpirationSeconds — even when
kube-apiserver's --service-account-max-token-expiration capped the grant
shorter. The customer saw a lifetime the token doesn't actually have.
The TokenRequest response already carries the authoritative expiry
(TokenRequestStatus.ExpirationTimestamp, capped by policy) — no JWT
parsing needed, contrary to the issue title. Capture it as
IngestorToken.ExpiresAt; `cluster info` shows the real remaining
lifetime when set, falls back to the requested value when the server
didn't return a timestamp, and still reads "never" for the long-lived
static-secret fallback (ExpiresAt stays zero there).
Tests: token_test.go — CapturesServerExpiry (server caps 3600→300, asserts
ExpiresAt reflects the cap), StaticSecretHasNoExpiresAt (zero → "never").
Full internal suite + vet + gofmt green.
Low priority per the issue (tokens are short-lived, so the misleading
window is small) — but a cheap correctness win now that the API value is
right there.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…atch phase)
Four low/medium follow-ups from the Bugbot review of PR #164; the other
five Bugbot items were already fixed by #165/#168/#171.
- delete: fail fast on a 401/403 from the pre-offboard online check
(revoked/expired credential) with a `tracebloc login` hint, instead of
warning and marching the user through the confirm only to fail at revoke.
- delete: clear + persist the active-client pointer IMMEDIATELY after the
revoke succeeds (before the best-effort teardown), so a failed or
interrupted teardown can't leave the host looking enrolled under a dead
credential.
- delete: mark the offboard degraded when removeSelf can't remove the CLI
binary / own `tb` alias, so the closing line stops claiming a clean
offboard while the CLI is still on disk.
- data ingest: a pod already in Succeeded prints "Ingestion complete —
showing its logs:" (replayed) instead of the "live progress:" line.
Tests added for each; full internal/... suite + go vet + gofmt green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@cursorcursorBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 073d19a. Configure here.

Comment threadinternal/cluster/discover.go
@saadqbal
saadqbal merged commit 30cb8f3 into mainJul 8, 2026
30 of 32 checks passed
Sign up for freeto 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.

3 participants

@saadqbal@aptracebloc@LukasWodka