Skip to content

fix(upgrade): update the CLI even on a healthy machine behind latest (backend#2253) - #590

Merged
aptracebloc merged 3 commits into
developfrom
fix/2253-upgrade-behind-latest
Aug 27, 2026
Merged

fix(upgrade): update the CLI even on a healthy machine behind latest (backend#2253)#590
aptracebloc merged 3 commits into
developfrom
fix/2253-upgrade-behind-latest

Conversation

@aptracebloc

@aptraceblocaptracebloc commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Problem

tracebloc upgrade can 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.5 with latest 0.10.8) is nagged on every command — by update_check.go:59's current < 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:

  • Run the installer via 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, lacking TB_CLI_LATEST, upgrades unconditionally under the flag).
  • Pass the latest release we already resolved for the nudge as TB_CLI_LATEST in the child environment (upgradeEnv), 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 installer's decision (mirrors prepareHostEnv's TB_PREPARE_USER handling).

The nag itself is unchanged and correct — once upgrade brings the CLI to latest, current < LATEST is false and it stops. Windows is unaffected (it runs the CLI-only install.ps1, which always updates the CLI).

The installer half — the cli-behind-latest classification and CLI-only update path that read these signals — is in tracebloc/client (sibling PR, links below).

Tests

  • TestUpgradePlanFor_PerOS extended: the exec args and the manual hint must carry TB_UPGRADE_CLI=1.
  • TestUpgradeInstallerCmdIsExplicitUpgrade: we no longer run the bare installer.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 + full internal/cli suite green; gofmt clean.

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 upgrade doing 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.Script with TB_UPGRADE_CLI=1 baked 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 by upgradeEnv(), which strips any ambient TB_CLI_LATEST and optionally sets it from a fresh GitHub release lookup (latestReleaseVersionFresh, bypassing the 24h nudge cache). If that fetch fails, TB_CLI_LATEST is 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.

…(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>
@aptraceblocaptracebloc self-assigned this Aug 27, 2026
@aptracebloc

Copy link
Copy Markdown
ContributorAuthor

Sibling PR (installer half): tracebloc/client#864 — the cli-behind-latest classification + CLI-only update path that consume the TB_UPGRADE_CLI / TB_CLI_LATEST signals set here. Both must land for tracebloc/backend#2253 to close.

— drafted with Claude Code

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@LukasWodkaLukasWodka left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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.

Comment threadinternal/cli/upgrade.go
…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

Copy link
Copy Markdown
ContributorAuthor

bugbot run

@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.

✅ 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.

@LukasWodkaLukasWodka left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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.

@aptracebloc
aptracebloc merged commit cca290c into developAug 27, 2026
28 checks passed
@aptracebloc
aptracebloc deleted the fix/2253-upgrade-behind-latest branch August 27, 2026 09:11
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.

2 participants

@aptracebloc@LukasWodka