Release develop → main#397
Open
shujaatTracebloc wants to merge 14 commits into
Open
Conversation
…389) * fix(delete): verify the host-data wipe before printing ✔ removeHostDataDir did os.RemoveAll and returned nil without confirming the tree was actually gone; the caller then printed "✔ Removed local tracebloc data and config". A nil RemoveAll is not proof of absence (racing writer, mount, masked partial failure), so offboard could claim a clean slate it didn't achieve — the RFC-0003 offboard-hygiene gap. Now removeHostDataDir stats the dir after RemoveAll and treats "still present" (or an unexpected stat error) as a failure, so the caller prints the warn + manual-rm hint instead of ✔. Adds an osStat seam + a test proving delete does NOT claim success on an unverified wipe. Closes #388. Refs tracebloc/client#367, backend#1151, #366. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test(delete): regenerate copy-catalog golden for the two verify strings The wipe-verify error messages are user-visible (surfaced via the "Couldn't remove local data (%v)" warn), so zz-all-strings.golden picks them up. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* feat(cli): auto-update — check-and-nudge + `tracebloc upgrade` (F1) Customers run the installer once and then never again, so they silently sit on an old CLI. Three layers, all safe (no silent binary swap): - Update-check nudge: after any command, a quiet one-liner if a newer release exists. Throttled to once/day via a cache in ~/.tracebloc, network capped at 2s, best-effort. Silent on dev builds, off a terminal, in CI, or with TRACEBLOC_NO_UPDATE_CHECK. Nudges from cache; refreshes when stale. - `tracebloc upgrade`: the apply step. Re-runs the official installer (curl … | bash) so it reuses the existing cosign verification and upgrades the CLI + the secure environment together (no version skew) — no new download/ verify surface in the CLI. - The existing 426 "CLI too old" error now points at `tracebloc upgrade`. Tests cover the semver compare (incl. v-prefix + pre-release), cache round-trip, the GitHub fetch (httptest), fresh-vs-stale cache behavior, and the skip gates. Catalog: adds 11-upgrade.golden. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(cli): resolve Bugbot findings on auto-update (F1) Three medium-severity issues from Cursor Bugbot: 1. Offline throttle broken (update_check.go): on a failed fetch, latestReleaseVersion fell back to the stale cache but never re-stamped CheckedAt, so the cache stayed expired and every command re-hit the network and ate the 2s timeout while offline. Now re-stamps CheckedAt so the once-per-interval throttle actually holds. 2. Nudge fired after a successful `tracebloc upgrade` (main.go): the nudge used the running process's compile-time version, which is stale by design once upgrade swaps the binary — so it claimed a newer release existed right after the user installed it. main now captures the executed command via ExecuteContextC and skips the nudge for `upgrade`. 3. `upgrade` broken on Windows (upgrade.go): it hardcoded `bash i.sh`, but Windows is a shipped platform (install.ps1, windows/* build matrix) with no bash — while the new 426 message tells users to run `upgrade`. Now branches on GOOS to run install.ps1 via PowerShell on Windows. Adds regression tests: offline-fetch throttle refresh, per-OS upgrade command, and the upgrade nudge-skip detector. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(cli): resolve Bugbot HIGH findings on upgrade command Round-2 Bugbot review of the auto-update work surfaced 3 real HIGH issues, all verified against scripts/install.ps1: 1. Upgrade hid curl failures: `curl … | bash` ran under `bash -c` without pipefail, so a failed curl left the trailing `bash` exiting 0 on empty stdin and `upgrade` reported success having installed nothing. Now runs with `bash -o pipefail -c`. 2/3. Windows self-upgrade can't work: install.ps1 is CLI-only (no environment upgrade) and Move-Items the binary into place, which Windows blocks for a running .exe. Proper Windows self-update is a separate feature, so instead of pretending, `upgrade` on Windows now prints the documented manual command to run in a fresh shell (no tracebloc process holding the binary). Help/home/copy no longer promise CLI+environment parity on Windows. Refactors the per-OS branch into upgradePlanFor(goos) (exec on Unix, guide on Windows) so it's testable on any host. Regenerates copy-catalog goldens. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: shujaat hasan <shujaathasan@shujaats-MacBook-Pro.local>
The staging progress bar was built with RenderBlankState(true), so
schollz painted a 0% bar at construction time — before Stage prints its
setup lines ("Opened a secure channel…", "Preparing the copy…") and
before the up-to-5-minute pod-ready wait. Two problems:
1. The 0% bar sat frozen through the pod-ready wait, reading as
"stuck".
2. Those setup lines (plain \n writes) collided with the bar's \r
redraw on the same terminal line, producing garbled output like
"Copying x 0% |…| (0 B/53 kB) [0s:0s]Opened a secure channel…".
Flip to RenderBlankState(false): the bar first paints on the first
Add() inside StreamLayout, after every setup line has printed on its own
clean line. Better UX too — no misleading frozen bar during the
pod-ready wait. No copy strings change; catalog golden unaffected.
Backlog item: D3.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* feat(install): prefer ~/bin when already on PATH, for same-terminal use (RFC 0001 B2) When /usr/local/bin is not writable, the installer fell straight to ~/.local/bin, which is often not on the current shell PATH — so tracebloc was not resolvable until a new terminal or an rc reload. Now, before that fallback, prefer ~/bin when it already exists on $PATH and is writable: the binary is usable in this shell and every new one with no rc edit at all. Restricted to the conventional ~/bin (never a language-specific dir like ~/.cargo/bin that merely happens to be on PATH); the ~/.local/bin fallback + rc persistence are unchanged. POSIX sh; shellcheck --severity=warning + dash -n clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(install): ~/bin already on PATH => no rc edit, no "new terminal" nudge (Bugbot #392) When the installer prefers ~/bin because it is ALREADY on $PATH, the binary is usable immediately and in the user's shells (they configured ~/bin), so the persist step must not rewrite their rc or tell them to open a new terminal — that undercut the B2 goal. Flag that selection (PREFIX_PRESELECTED_ON_PATH) and skip persist for it, same clean no-message outcome as an on-PATH /usr/local/bin. The ~/.local/bin fallback (created mid-session, needs the rc line for non-login shells, #304) is unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(install): ~/bin still persists to rc (session-only PATH), but message says "ready now" (Bugbot #392 r2) My earlier skip-persist for ~/bin broke a SESSION-ONLY $PATH entry (direnv, a one-off export): those are not in the rc, so new terminals lost tracebloc with no guidance. Revert to always persisting a $HOME prefix (idempotent — a no-op when the rc already has it), so new terminals are covered. To still honour B2 (do not nag "open a new terminal" for a dir usable NOW), the message branches on whether $PREFIX is on the current $PATH: "ready to use now" (+ note the rc was updated for new terminals) instead of "open a new terminal". Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(install): guard HOME=/ for ~/bin, and say ready-now on rc-write failure too (Bugbot #392 r3) 1) "${HOME%/}/bin" collapses to /bin when HOME is "/" or empty, so a root process could drop the CLI into /bin — require a real, non-root $HOME before preferring ~/bin. 2) The on_path "ready now" acknowledgement was applied to the added/present messages but not the rc-write-failure branch; a ~/bin (usable now) whose rc could not be written still nagged "open a new terminal". Add it there too. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * install.sh: tolerate trailing-slash PATH entries when detecting ~/bin The PATH membership checks matched only ":$dir:" and missed a trailing-slash entry like "$HOME/bin/". A user with "~/bin/" on PATH would be wrongly classified as not-on-PATH: the installer would skip the usable ~/bin prefix and fall back to ~/.local/bin, and would nag "open a new terminal" for a dir that is in fact already on PATH (Bugbot #392). Add a "|*":$dir/:"*" alternative to all three checks (home_bin detection, persist decision, on_path message). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* feat(cli): tracebloc prepare-host — one-time admin step wrapper (RFC 0001 #1178) Adds `tracebloc prepare-host`: a thin, discoverable wrapper that re-runs the official installer's verified prepare-host step (curl … | bash -s -- prepare-host), exactly like `tracebloc upgrade` delegates to the installer rather than re-implementing privileged host prep in the CLI. Registered in root; copy catalog gains 11-prepare-host.golden + the strings flow into zz-all-strings. build/vet/ staticcheck/deadcode clean; catalog no-drift; gofmt clean. Pairs with the client installer prepare-host step (tracebloc/client#377). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(cli): set -o pipefail in prepare-host so a curl failure is not swallowed (Bugbot #394) Without pipefail, `curl … | bash -s -- prepare-host` under `bash -c` exits 0 when curl fails (bash reads empty stdin), so the command reported success while prepare-host never ran. Prepend `set -o pipefail;` so curl's non-zero propagates and c.Run() surfaces the failure. Regression guard added. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * prepare-host: run installer pipeline in its own process group Cancelling the context (Ctrl-C / parent shutdown) previously killed only the top-level `bash -c`, leaving the `curl` and the `bash -s` prepare-host child -- which performs privileged host prep -- running detached after the CLI had already reported failure and exited (Bugbot #394). Extract prepareHostCmd(ctx): set SysProcAttr.Setpgid so the pipeline gets its own process group, and a Cancel that group-signals (kill -PGID SIGINT) so the whole pipeline stops when the user aborts. Add a test asserting Setpgid + Cancel are wired. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * prepare-host: run installer from a temp file, not a pipe (keep stdin on TTY) `curl | bash -s -- prepare-host` makes the inner bash read its *program* from the pipe, so the installer's stdin is no longer the terminal — any interactive prompt in prepare-host (e.g. which non-admin user gets runtime access) gets EOF (Bugbot #394, second finding). Switching to `bash <(curl …)` would fix stdin but reopen the FIRST #394 finding: process-substitution exit codes bypass pipefail, so a failed curl would silently run nothing. Instead download to a temp file under `set -e` (so a failed `curl -o` aborts) and run the file (stdin stays on the TTY). Best of both: fail-closed on download error AND interactive-capable. The manual-run hint shown on failure uses `bash <(curl …)` — the repo's recommended idiom — since a human re-running it keeps their own TTY. Add tests: fail-closed on download error (set -e + curl -o), and never pipe the script into bash. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * prepare-host: fix Windows build — move POSIX process-group logic behind build tags The process-group cancel added for Bugbot #394 used syscall.SysProcAttr.Setpgid and syscall.Kill(-pid, …), which are POSIX-only — the Windows build failed to compile (unknown field Setpgid; undefined syscall.Kill). Extract configureProcessGroup into build-tagged files: - prepare_host_unix.go (//go:build !windows): sets Setpgid + the group-killing Cancel (unchanged behavior on linux/darwin). - prepare_host_windows.go (//go:build windows): no-op — POSIX process groups don't exist there, and exec.CommandContext still kills the top-level process; prepare-host is a Linux host op regardless. Move the Setpgid assertion test into prepare_host_unix_test.go (also !windows-tagged) so `go test`/`go vet` compile on Windows too. Verified: `GOOS=windows go build/vet ./...` now pass for amd64 + arm64, and the native build/test/staticcheck stay green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * prepare-host: run in the foreground group, quiet interrupt on cancel (Bugbot #394) The process-group approach was wrong for an interactive command and Bugbot flagged five follow-ups: - Setpgid put the installer in its own (background) process group while stdin was the TTY, so any prepare-host prompt got SIGTTIN and hung (High). - the SIGINT-only Cancel with no WaitDelay could hang Wait forever if a privileged child ignored the signal, re-opening the orphaned-work risk. - a user Ctrl-C was wrapped as "prepare-host didn't complete — retry" instead of a quiet interrupt. Drop Setpgid and the custom Cancel entirely: keep the installer in the CLI's foreground process group so prompts work and a terminal Ctrl-C signals the whole pipeline (bash + curl + child) at once. Add WaitDelay=5s so a programmatic cancel can't hang Wait. Treat ctx cancel as exitInterrupted (130), matching the other cancellable paths. This also removes all syscall usage, so the Windows build no longer needs the build-tagged split (files deleted). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * prepare-host: reuse installCmd for the hint + robust interrupt detection (Bugbot #394) - prepareHostManualHint duplicated the bootstrap idiom owned by installCmd (doctor.go), so a URL/idiom change could leave the prepare-host fallback stale. Build it from installCmd + " prepare-host" (same value, one source). - Interrupt detection only checked ctx.Err() after c.Run(); on a terminal Ctrl-C the child dies (bash exits 130) and Run can return before NotifyContext flips ctx.Err(), so an abort was mis-reported as a failed install. Add prepareHostInterrupted(ctx, err): interrupt if ctx cancelled OR the run exited 130 (128+SIGINT). Unit-tested (cancelled ctx, exit 130, exit 1). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * prepare-host: accept a researcher username to grant docker-group access (Divya #377) prepare-host was cobra.NoArgs with no flag and no mention of TB_PREPARE_USER, so an admin had no discoverable way to name the researcher — the installer's docker-group grant (which reads TB_PREPARE_USER) was always skipped and the feature couldn't deliver Tier-0 access end-to-end. Add an optional positional arg: `tracebloc prepare-host <researcher-username>` (MaximumNArgs(1)). The username is validated (Linux-username shape) and passed to the installer via the TB_PREPARE_USER environment variable (not the command string, so it can't be shell-interpreted; the installer quotes it for usermod). Help text explains the arg and stresses it's the researcher, not the admin. Without it, prepare-host installs prereqs only and prints how to grant access. The client installer already grants ONLY TB_PREPARE_USER (never $SUDO_USER), so this closes the loop. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(cli): guard prepare-host on Windows (Bugbot #394) prepare-host shells out to bash/curl/mktemp and readies a Linux server / HPC login node (container runtime, docker group) — a Unix-only concept. On Windows it appeared in --help then failed with a cryptic missing-bash error and a Unix-only retry hint. It now stops early with a clear explanation (a no-op-with-message), mirroring upgrade's Windows handling. Adds a regression test for the OS guard. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: shujaat hasan <shujaathasan@shujaats-MacBook-Pro.local>
…atus --seal) (#395) * feat(status): surface the environment's seal-check verdict (client status --seal) `tracebloc client status --seal` runs the chart's conformance checks (its helm-test hooks — the RFC-0003 §8.2 seal check) against this machine's secure environment and prints an honest verdict with per-check detail: sealed every conformance check passed (exit 0) unsealed a check failed — a protection is not enforced (exit 2) unknown the chart ships no checks; nothing was verified (exit 2) Chart contract (works against today's probes, picks up the growing backend#1184 suite as it lands): test hooks labelled `tracebloc.io/seal-check: "true"` form the suite; with no labelled hook every helm test runs, with a visible fallback note; the optional `tracebloc.io/seal-name` / `tracebloc.io/seal-hint` annotations refine a check's display name and its failure hint. Checks run one `helm test --filter name=<hook>` at a time so a first failure can't hide the rest of the suite's state, and helm stays pinned to the resolved kubeconfig/context — never the ambient one. Honest-output rules (the #389 spirit): only a fully-passed suite exits 0; "unknown" is never worded as sealed; a cancelled run (Ctrl-C) and a failed hook enumeration yield no verdict at all. Also: moves the status command into client_status.go (client.go sat at its 1050-line file-budget ceiling) and adds Printer.Spinner strings to the copy-catalog harvest (they print as static lines on non-TTY runs and were previously missed by the backstop). Closes #393 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs(troubleshooting): add client status --seal to the exit-code table The table is the cross-command scripting contract; the new seal mode produces 2 (unsealed / unknown via exitChecksFailed) and shares the 3 / 4 cluster-resolution codes with the data and resources commands. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(seal): align to the chart's shipped label contract; carry aux hooks in every filter Two alignments against the chart-side suite (client docs/SEAL-CHECK.md, backend#1184) that landed in parallel: - The per-check identifier is the tracebloc.io/seal-check-name LABEL (values: egress-enforcement, backend-reachability, storage-assertions), not a seal-name annotation — read it from labels. The hint stays an optional CLI-side annotation (labels cannot carry sentences); absent, the kubectl-logs fallback stands. - The storage-assertions Job depends on a ServiceAccount/RBAC that are themselves test hooks at negative hook-weight, and helm's --filter excludes every unlisted test hook — plumbing included. Filtering to the check alone would strand the Job without its SA and report a false Unsealed. Every per-check run now lists the check PLUS the release's non-runnable test hooks (applied instantly; helm only waits on Jobs/Pods), while other checks stay excluded so the verdict remains per-check. Non-runnable hooks never count as checks: a chart whose only test hooks are plumbing is still honestly "unknown". Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(seal): pin helm to the resolved kube-context; quiet exit on Ctrl-C during enumeration (Bugbot) - helm.TestTarget.KubeContext now carries target.Resolved.Context, not the raw --context flag: with the flag omitted the raw value is empty and helm falls back to its own ambient resolution ($HELM_KUBECONTEXT included), which can diverge from the context client-go discovery just used. Same pinning `resources set` applies. - A context cancellation during `helm get hooks` now exits 130 quietly (like the per-check loop and `status --wait`) instead of reporting a hard enumeration failure. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: shujaat hasan <shujaathasan@shujaats-MacBook-Pro.local>
* docs(rfc): add RFC-0003 — dataset storage & offboard hygiene (draft) Commits the drafted RFC-0003 into cli/docs/rfcs/ alongside 0001/0002. Concept-only design doc covering two user-visible problems that share one root cause: offboard should leave a true clean slate, and ingested datasets are stored as world-readable host files bind-mounted into the cluster (engineered to survive cluster deletion), which sits awkwardly against "your data stays within the secure environment". Storage options + open decisions (section 7) pending Lukas + Asad. Companion to backend#1151. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * docs(rfc): RFC-0003 v2 — record decisions, define the secure-environment boundary - §7 decision menu -> §10 decision log (D1-D14): Option C node-local, leftover-guard, no data-copier, 777 dies with C, encryption phase 2 - New §1-2: secure-environment definition (3-in/1-out channel list) + threat model with honest ceilings (owner-root, data-derived weights) - New §6: model IP protection — watermarking + audit now, envelope encryption + crypto-shredding for at-rest weights (keys in memory, not weight files), TEE as phase 2, HE/MPC rejected - New §7: in-cluster walls — dataset-scoped mounts, per-experiment DB grants, spawned-pod hardening completion - New §8: egress-lockdown flip dependency, seal check, per-substrate guarantee matrix, verify k3d enforcement - §3/§13 evidence corrected + refreshed (777 scoping, cluster reuse, stale line numbers) - Open items: O1 default-flip, O2 retention, O3 key custody, O4 watermark Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs(rfc): v2.1 — correct weight-lifecycle facts against code; record D15 - §3.1/§6.4: verified against tracebloc-client + client-runtime + averaging-service — weights do NOT rest durably in the environment (per-cycle backend download -> pod-scoped scratch -> upload back); durable store is the platform-side averaging share - D8 re-aimed: edge = lifecycle hygiene only; envelope encryption + crypto-shredding applies to the platform-side store (backend/averaging ticket, outside the environment boundary) - O1 decided -> D15: node-local becomes the default for local installs after one green training run on node-local - O3 dissolved by architecture; O2 re-scoped to platform-side retention - Evidence appendix: added weight-lifecycle code anchors Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs(rfc): v2.2 — status DECIDED; cross-link execution tickets in §10/§12 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs(rfc): v2.3 — per-dataset immutable tables + grant-scoped view isolation; split composition to data-spaces RFC Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs(rfc): C1 pins single-node via AGENTS=0 AND SERVERS=1, not just AGENTS=0 §5 C1 and the appendix said node-local forces AGENTS=0; the prototype (client#368) had to force SERVERS=1 too — k3s server nodes are schedulable, so SERVERS>1 still yields multiple nodes a Job could land on away from the local-path volume. Match the doc to the shipped code. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * docs(rfc): fix stale code citations in RFC-0003 - Repo rename: the training-client code is now in `tracebloc-engine`, not `tracebloc-client` (§7bis, O6, appendix). Verified the cited paths exist there: core/utils/database.py:243 (get_sql_query_and_params), core/utils/general.py:21-33 (get_experiment_path), core/weights/base.py. - D19 line drift: the ingestor reuse/append branch spans 275-357, not 309-357 — the old range started after the "return existing table if already created" reuse check (line 275) that D19 actually removes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: Asad Iqbal <asad.dsoft@gmail.com> Co-authored-by: shujaat hasan <shujaathasan@shujaats-MacBook-Pro.local>
- upgrade: reuse prepareHostInstallerCmd / installerURL (download-then-exec) instead of curl|bash, so stdin stays on the TTY and the URL has one source - upgrade: treat cancelled context / bash exit 130 as a quiet interrupt (exit 130), matching prepare-host Co-authored-by: shujaat hasan <shujaathasan@shujaats-MacBook-Pro.local> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
… (#403) On a machine that shrank under the configured ceiling (WSL2 field case: node ~6.7 GiB under a lingering chart-default 8Gi RESOURCE_LIMITS), the 'Choose an amount' prompts offered the current ceiling as the default — outside their own validator range — so pressing Enter on '(8)' answered 'must be between 2 and 3'. Defaults are now clamped into [floor, max], and the header annotates an over-ceiling budget instead of printing a bare '8 of 6.7 GiB'. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
#404) * fix: resolve Bugbot findings on promotion PR #397 (TLS floor + delete cache) - installer: pin the TLS 1.2 floor (--tlsv1.2) on the shared installerRunScript download, matching scripts/install.sh, so `tracebloc upgrade` and `prepare-host` can never negotiate a weaker protocol - update-check: skip the post-command nudge after `tracebloc delete` (reuse SkipUpdateNudge) AND make writeUpdateCache refuse to recreate a missing ~/.tracebloc, so a clean offboard is never resurrected by the throttle cache Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix: drive update-nudge skip by annotation, not command name (Bugbot #404) isDeleteCommand matched any leaf named "delete", so the nudge was wrongly skipped after `data delete` too (which neither offboards nor wipes ~/.tracebloc). Replace the name-based upgrade/delete predicates with a self-declared cobra annotation (skipUpdateNudgeAnnotation) set on the top-level upgrade and delete commands, so `data delete` is unaffected. Add a table-guard test. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: shujaat hasan <shujaathasan@shujaats-MacBook-Pro.local> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…400) (#405) * fix(doctor): per-OS compute remedies + resources-set-max drift nudge (#400) The 'raise the machine's allocation in Docker Desktop -> Resources' remedy was emitted unconditionally -- that slider does not exist on Windows's default WSL2 backend (field case: the user followed it into Docker Desktop and found nothing to raise), and bare Linux has no Docker Desktop at all. - computeRemedy(GOOS): windows names both levers (.wslconfig + wsl --shutdown / Hyper-V slider), darwin keeps the slider, linux drops the Docker Desktop reference; every variant ends with 'tracebloc resources set max' (the backend#1236 drift fix). Applied to both the node-capacity fail and the stuck-pending remedy. - checkNodeFit OK path gains the grow-side drift nudge: when the budget uses no more than half of what the largest node could give one run, the detail points at resources set max. - copy-catalog golden regenerated for the new strings. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * remedies: the memory slider lives at Settings -> Resources -> Advanced Verified against Docker's settings docs (review question by Lukas on the client twin, tracebloc/client#392): 'Memory limit ... Mac, Linux, Windows Hyper-V' sits under Resources > Advanced. Golden regenerated. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * drift nudge: CPU-major node selection, matching resources set max (Bugbot) The nudge tracked the largest node memory-first while resources. LargestReadyNode (what 'set max' applies) is CPU-major -- on heterogeneous clusters the advertised ceiling could name numbers set max would not apply. Same total order now; heterogeneous regression test added. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…-node sum (#399) (#406) The default k3d topology is server-0 + agent-0 -- two kubernetes nodes on the SAME physical machine -- so summing allocatable across Ready nodes double-counted it: 'equipped with 24 CPU · 13.4 GiB' on a 12-CPU node exposing 6.7 GiB (field case). A pod schedules onto ONE node anyway. - resources.MachineCapacity now delegates to LargestReadyNode; every surface (headline, wizard, doctor checkNodeFit) quotes the same machine. - home.go's sumCapacity becomes the same largest-node selection (CPU-major, mirroring nodeLarger's total order); GPU count comes from the chosen node. - addInto removed (orphaned by the delegation); regression tests on all three pinned paths. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
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.
Reviewed by Cursor Bugbot for commit 327987b. Configure here.
…397) (#408) The seal check's cancel detection looked only at ctx.Err(). On a terminal Ctrl-C the helm child can exit 130 before NotifyContext flips the context, so the check read as a real failure and rendered a false Unsealed (exit 2) instead of a quiet interrupt (130) — breaking seal's "never claim a verdict you didn't verify" rule. Reuse installerRunInterrupted (shared with upgrade/prepare-host) at both seal cancel sites (mid-suite and enumeration) so the exit-130 race is caught. Adds a regression test. Co-authored-by: shujaat hasan <shujaathasan@shujaats-MacBook-Pro.local> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
… missing (#401) (#407) * fix(home): adopt a LOCAL cluster's release when the client pointer is missing (#401) Home's env verdict hung entirely on ActiveClientNamespace -- written only by 'client create', which the Windows installer never runs -- so a healthy installed environment read as 'No secure environment on this machine yet' while doctor said Ready (field case). The ownership gate stays intact: the fallback adopts a discovered release ONLY when the kubeconfig server is local (loopback / k3d wildcard / host.docker.internal) -- a cluster that IS this machine, so no shared-cluster stranger can be greeted (section 7.5 preserved); namespace-only discovery, no cluster scan; every error degrades to the honest no-release. Also: tb alias detection accepts the Windows tb.cmd shim (install.ps1 cannot symlink without admin), so remedies echo 'tb' on Windows too. Both moved to home_local_fallback.go (home.go file budget). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * tb.cmd ownership: full-path match, not basename (Bugbot) A shim mentioning 'tracebloc' anywhere -- a comment, or an invocation of a DIFFERENT tracebloc install -- claimed ownership. Ours = the shim contains THIS exe's full path (case-insensitive; install.ps1 writes an absolute target, the same bar aliasStatus applies to symlinks). Tests for both false-claim shapes added. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This was referenced Jul 26, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Promotion: develop → main
This release promotes 7 commits from
developtomain(prod). Nostagingbranch exists, so develop promotes straight to prod.Commits being promoted
client status --seal) (feat(status): surface the environment's seal-check verdict (client status --seal) #395)tracebloc prepare-hostwrapper (#1178, cli) (feat(cli): tracebloc prepare-host wrapper (#1178, cli) #394)~/binwhen already on PATH (B2, RFC 0001) (feat(install): prefer ~/bin when already on PATH (B2, RFC 0001) #392)tracebloc upgrade(F1) (feat(cli): auto-update — nudge + tracebloc upgrade (F1) #390)Highlights
client status --sealverdict andtracebloc prepare-host/tracebloc upgradecommands~/binwhen already on PATH; auto-update nudge addedNote
Medium Risk
Touches offboarding data removal, privileged installer execution, and cluster helm tests used for security claims; changes are well-tested but affect production CLI behavior and messaging.
Overview
This promotion bundles CLI product work (F1 auto-update, RFC-0003 seal/offboard hygiene) with UX fixes on home, doctor, and resources.
New capabilities:
tracebloc client status --sealruns the chart’s conformance helm tests and reports sealed / unsealed / unknown with documented exit codes;tracebloc upgradeandtracebloc prepare-hostdelegate to the cosign-verified installer (download-then-run, TLS-pinned). After each command, main may print a once-a-day “newer release” nudge (skipped forupgrade/deleteand when offboard wiped config). The HTTP 426 message now points attracebloc upgrade.Trust & hygiene:
tracebloc deletestats the host data dir afterRemoveAllbefore claiming a clean wipe. Update-check cache writes do not recreate~/.traceblocafter delete.Diagnostics & UX: Home adopts a local cluster when the active-client pointer is empty (#401, Windows
tb.cmd); machine capacity uses the largest Ready node instead of summing k3d nodes (#399).doctorcompute remedies are OS-specific (#400). The resources wizard clamps defaults and flags budgets above what the machine can offer (#398).Docs: Adds RFC-0003 (secure environment, storage, offboard, seal matrix) and updates troubleshooting exit codes for
--seal. Golden copy catalogs cover seal verdicts, upgrade, and prepare-host.Reviewed by Cursor Bugbot for commit 12bbe7e. Bugbot is set up for automated code reviews on this repo. Configure here.