Uh oh!
There was an error while loading. Please reload this page.
fix(upgrade): update the CLI even on a healthy machine behind latest (backend#2253) - #590
Conversation
…(backend#2253)
`tracebloc upgrade` re-runs the installer, whose stop-and-check gate short-
circuits an already-set-up machine to "already set up — no need to run the
installer again" and touches nothing. So a CLI behind the latest release but
still above the mandatory-reinstall floor (e.g. 0.10.5 with latest 0.10.8) was
nagged on every command while the very command the nag names could never carry
it out — two unrelated definitions of "up to date".
Carry an explicit-upgrade signal into the installer: run it via
installer.Script("", "TB_UPGRADE_CLI=1") (exec AND the printed manual hint, so a
copy-pasted retry still upgrades), and pass the latest release we already
resolved for the update nudge as TB_CLI_LATEST in the child environment so the
installer updates the CLI only when actually behind — not on every upgrade.
Ambient TB_CLI_LATEST is stripped first so a stray shell value can't drive the
decision (mirrors prepareHostEnv's TB_PREPARE_USER handling).
The installer half (the cli-behind-latest classification + CLI-only update) is
in tracebloc/client.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>aptracebloc
commented
Aug 27, 2026
Sibling PR (installer half): tracebloc/client#864 — the — drafted with Claude Code |
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
LukasWodka
left a comment
There was a problem hiding this comment.
Reviewing this together with its other half, tracebloc/client#864 — I verified the cross-repo contract there and it holds on both names and semantics: the note is on #864. In particular assess.sh implements your upgrade.go:79 contract exactly — an absent TB_CLI_LATEST fails safe toward updating rather than short-circuiting.
Two mechanical gates here before it can go green: closing-ref (the title names backend#2253 but the body links nothing — needs Closes tracebloc/backend#2253, full form) and version-bump-gate / version-check. Substantive review once CI is green.
Uh oh!
There was an error while loading. Please reload this page.
…end#2253) Bugbot (High): upgradeEnv fed the installer TB_CLI_LATEST from latestReleaseVersion(), which prefers a cache up to 24h old. On an explicit `tracebloc upgrade` a stale cache can equal the running version, so the installer concludes the CLI is already current and skips the update the user asked for — worst right after a 426, when a new release lands while the cache still matches what's installed. Add latestReleaseVersionFresh(): fetch the release directly (bypassing the throttle), refresh the cache on success, and return "" on ANY error so the caller omits TB_CLI_LATEST and the installer updates unconditionally under TB_UPGRADE_CLI — the correct fail-safe for an explicit upgrade. upgradeEnv now uses it. New TestUpgradeEnvIgnoresStaleCache pins the fix. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
aptracebloc
commented
Aug 27, 2026
bugbot run |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 95825ab. Configure here.
LukasWodka
left a comment
There was a problem hiding this comment.
Approving 95825abc — 25 passing, 3 path-skipped, nothing pending or failing, no open threads, mergeable=MERGEABLE.
The cross-repo contract holds, which I checked against client#864 rather than reading both descriptions and assuming: names match, and the semantics do too — your upgrade.go:79 promise that a missing TB_CLI_LATEST still upgrades unconditionally is exactly what assess.sh:244-247 implements, failing safe toward updating.
Four things here I'd single out, because each is a decision rather than a default:
The flag is baked into the command string and the manual hint from one source.upgradeInstallerCmd = installer.Script("", upgradeCLIEnvAssign) feeding both args and manual means a user who copy-pastes the printed retry gets the same behaviour as the automatic run. Two strings that must agree, derived from one — the #394/#397 lesson applied rather than restated.
TB_UPGRADE_CLI in the string, TB_CLI_LATEST in the environment, and the comment says why: one is a compile-time constant, the other a runtime value that must not end up in a string someone pastes into a shell later. That distinction is easy to miss and the consequences are asymmetric.
latestReleaseVersionFresh() rather than the 24h-cached lookup. A stale cache equal to the running version would make the installer skip a real update on an explicit tracebloc upgrade — the exact class of bug this PR fixes, one layer down. Good catch by Bugbot and a clean fix.
Ambient TB_CLI_LATEST is stripped first. I checked the implementation rather than the comment: the loop continues on every match (not just the first), and the = in the prefix means a TB_CLI_LATEST_SOMETHING var isn't caught by accident. So a stray value in someone's shell can't drive the installer's decision.
Every one of those has a test, and they pass locally:
TestUpgradeInstallerCmdIsExplicitUpgrade
TestUpgradeEnvStripsAmbientLatest
TestUpgradeEnvCarriesResolvedLatest
TestUpgradeEnvIgnoresStaleCache
ok github.com/tracebloc/cli/internal/cli 2.046s
Four claims, four tests, no gap between what the description asserts and what CI proves.
On merge order: this half is safe to land first. If #590 merges before client#864, tracebloc upgrade passes TB_UPGRADE_CLI=1 to an installer that doesn't yet read it — an ignored env var, so the behaviour is exactly today's no-op rather than a regression. The fix simply doesn't take effect until the installer half lands. No sequencing hazard either way.
Value: the command the update nudge tells people to run can finally carry it out, instead of cheerfully doing nothing and leaving the nag in place.
Uh oh!
There was an error while loading. Please reload this page.
Problem
tracebloc upgradecan never clear the update nag (backend#2253). It re-runs the installer, whose stop-and-check gate short-circuits an already-set-up machine to "already set up — no need to run the installer again" and touches nothing. So a CLI behind the latest release but still above the installer's mandatory-reinstall floor (e.g.0.10.5with latest0.10.8) is nagged on every command — byupdate_check.go:59'scurrent < LATEST— while the very command the nag names cannot carry it out.Fix (issue's preferred option 1)
Carry an explicit-upgrade signal into the installer so it updates the CLI even on an otherwise-healthy box:
installer.Script("", "TB_UPGRADE_CLI=1")— the flag is a compile-time constant baked into both the executed command and the printed manual hint, so a copy-pasted retry still upgrades (and, lackingTB_CLI_LATEST, upgrades unconditionally under the flag).TB_CLI_LATESTin the child environment (upgradeEnv), so the installer updates the CLI only when actually behind — not on every upgrade. AmbientTB_CLI_LATESTis stripped first so a stray shell value can't drive the installer's decision (mirrorsprepareHostEnv'sTB_PREPARE_USERhandling).The nag itself is unchanged and correct — once
upgradebrings the CLI to latest,current < LATESTis false and it stops. Windows is unaffected (it runs the CLI-onlyinstall.ps1, which always updates the CLI).The installer half — the
cli-behind-latestclassification and CLI-only update path that read these signals — is in tracebloc/client (sibling PR, links below).Tests
TestUpgradePlanFor_PerOSextended: the exec args and the manual hint must carryTB_UPGRADE_CLI=1.TestUpgradeInstallerCmdIsExplicitUpgrade: we no longer run the bareinstaller.Cmd(whose healthy fast-path updated nothing) — the failing-today guard.TestUpgradeEnvCarriesResolvedLatest/TestUpgradeEnvStripsAmbientLatest: the resolved latest is handed to the installer; ambient values are stripped. Both hermetic (config dir pinned, no network).go vet+ fullinternal/clisuite green;gofmtclean.Closes tracebloc/backend#2253
— drafted with Claude Code
Note
Medium Risk
Changes the explicit upgrade → installer contract (env vars and bootstrap command); incorrect behavior could skip real updates or mis-inform the installer, though fail-safes favor unconditional CLI update when version fetch fails.
Overview
Fixes
tracebloc upgradedoing nothing on an already-set-up host when the CLI is behind the latest release but above the installer’s mandatory-reinstall floor — the same case the update nudge keeps pointing at.On Linux/macOS, upgrade now runs the shared installer bootstrap via
installer.ScriptwithTB_UPGRADE_CLI=1baked into both the executed command and the printed retry hint, so the installer performs a CLI-only update instead of the healthy fast-path no-op. The child environment is built byupgradeEnv(), which strips any ambientTB_CLI_LATESTand optionally sets it from a fresh GitHub release lookup (latestReleaseVersionFresh, bypassing the 24h nudge cache). If that fetch fails,TB_CLI_LATESTis omitted so the explicit-upgrade flag still forces an update.Adds regression tests for the explicit-upgrade command string, env stripping, resolved latest, and stale-cache behavior. Version bump to 0.10.15.
Reviewed by Cursor Bugbot for commit 95825ab. Bugbot is set up for automated code reviews on this repo. Configure here.