fix: run setup-host over a migrated flat tree, and name what the migration left #121
Labels
No labels
blocked
blocker:ci-red
blocker:conflict
blocker:drill-pending
blocker:unrequested
bug
claimed
documentation
enhancement
epic
merge-next
needs-triage
ready
release
scope:cli
scope:drill
scope:host
scope:installer
scope:templates
scope:tiers
stale
state:addressing
state:bots-reviewing
state:building
state:needs-human
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: heavy-duty/box#121
Loading…
Reference in a new issue
No description provided.
Delete branch "fix/flat-upgrade-setup-host"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Two issues, one PR — they are a hard conflict, not a convenience bundle. Both live in the same ~20 lines of
install.sh(the pre-0.7.0 migration block and thehad_installcomputation beside it), and #117 explicitly notes that "a single pass could address the reporting for both." Splitting them would mean two PRs editing the same lines and the sametest/cli.shblock, with the second rebasing onto the first for no benefit.Part 1 — #115: the ordering bug
had_installwas computed after the migration block. The migration converts a flat pre-0.7.0 tree intoversions/<flat_ver>— so the very next test, "does$DEST/versionsexist and is it non-empty?", was answered by something the installer had done one line earlier. A flat host read ashad_install=1,host/setup-host.shwas skipped, and the host kept every artifact the old release left behind whilebox --versionreported the new one.That is why the drill host ended up on 0.8.0 with a pre-#102
/usr/local/sbin/box-firewall: the operator most likely to upgrade for the SIGPIPE fix was the one who did not receive it, with the version string asserting the opposite.The fix is the reorder, not a warning.
had_installnow computes before the migration block. That asks the honest question — a tree that needs migrating has by definition never been converged by this version'ssetup-host, so it must read0. A genuinely versioned tree still reads1, for the right reason: the directory it tests predates the run. The test suite pins both directions, so "fixed" and "runssetup-hostunconditionally" are not confusable.The accepted trade-off, stated plainly
A
BOX_YES=1unattended upgrade on a flat-tree host will now runsetup-host, which the #66 comment (install.sh~:384-386) explicitly cautions about — that is a real behaviour change on that path, and it was a decision, not an oversight. It is accepted becausesetup-hostis documented and built as converging and idempotent, and because shipping a release whose host half is silently missing is the worse failure of the two. Reviewers who want to reopen this should reopen it as a decision.The
current-doesn't-flip finding: real, and fixed hereTriage flagged
install.sh:407— it ran$DEST/current/host/setup-host.sh, butcurrentdoes not always flip. Verdict: real, reachable, and made reachable by Part 1 itself.The mechanism: the #66 guard (~:305-312) holds the default where it is when the host has existing boxes. So on a flat-tree host with boxes, the migration points
currentatversions/<flat_ver>, the guard then refuses to move it — andcurrentstill names the old version when host setup runs. The installer would converge the host using the previous release's host scripts, reinstating exactly the staleness #115 is about, in the one case where the operator's live boxes make it most costly.Before this PR the defect was latent (setup-host never ran on that path at all); Part 1 activates it. So it is not a separate concern to defer — fixing it here is what keeps Part 1 from being a fix in name only. The change is one path,
$VDIRinstead of$DEST/current: unambiguously the version this run installed, which is the version whose host contract we are being asked to satisfy. Thesudo-missing hint on ~:399 was pointing at the same wrong path and moves with it. No follow-up issue filed — it is fixed, with its own regression test.Part 2 — #117: the premise, corrected
The issue's premise is partly wrong, and I want that on the record rather than quietly fixed around. #117 says "the install output never names it" and "the migration is silent." It is not.
install.shnames the migration twice today, before this PR:~:158—found a pre-0.7.0 flat install at $DEST (version $flat_ver) — migrating it into the versioned layout~:166—migrated: it now lives at $DEST/versions/$flat_ver (still current; your boxes are untouched)So the event was always reported. What was genuinely missing is the lifecycle half: nothing told the operator that the old tree is now a first-class
box versionsentry they may keep or reap, and nothing said how. And the one line that did exist scrolls past roughly 250 lines of install output beforedone— true at the moment it prints, invisible by the time the install ends.That is what this fixes: the migration line now names both ways out (keep it as a rollback target via
box use <v>, or reap it viabox uninstall <v>), and amigrated_fromvariable lets the closingdoneblock re-state it as the last thing the operator sees. Deleting the tree automatically stays the wrong default, for the reason #117 gives: it is the only thing to roll back to, at exactly the moment that matters. No behaviour change, no reordering beyond Part 1's.Test proof — real, end to end, fully offline
No Incus, no root, no network.
test/cli.shalready drives realinstall.shruns against fabricated sources; the gap was that itsinsthelper hardcodesBOX_SKIP_SETUP_HOST=1, which pins off the exact switch under test.inst_setup— same helper withoutBOX_SKIP_SETUP_HOST, so host setup actually runs.host/setup-host.shonSRC9that echoesSETUP-HOST-RAN-FROM 9.9.9-drill. The marker is the proof, and because it names its version it distinguishes whether setup-host ran from which tree it ran from — which is what makes thecurrentfinding testable at all.Assertions added:
flat upgrade: host setup RUNS over a migrated flat tree (#115)versioned upgrade: ...still SKIPS host setup+...the stub did NOT runflat upgrade under boxes: setup-host runs the NEW version's scriptcurrentfixflat upgrade under boxes: ...the default correctly stayed put (#66)migrate:×3 — reap command, rollback wording, closing re-statementmigrate: a NON-migrating install stays silent about migrationBoth fixes were verified to fail without them, which is the only thing that makes them regression tests:
install.shwholesale: 4 failures, exactly the new #115 and #117 assertions.$VDIR→$DEST/current, with Part 1 kept: 1 failure,flat upgrade under boxesalone — isolating the second defect from the first.Checks green:
shellcheck -xper CI's exact invocation;bash test/cli.sh484 passed, 0 failed;test/release.sh90/0 andtest/labels-reconcile.sh19/0 unaffected;changelog-armed.shpasses.Closes #115
Closes #117
Verdict: Approve — I agree with this as-is.
had_installcomputed before the pre-0.7.0 flat→versions/migration so a migrated tree still runssetup-host(and reports what migration left). Versioned re-upgrade still skips. Offline fixture coverage for flat + boxes-held cases. CI green. No blockers.Verdict: I agree with everything and have no additional feedback.
Verdict: Approve.
I read
install.shin full at head3fe589d, both linked issues, and re-ran the suites locally:test/cli.sh484 passed, 0 failed;test/release.sh90 passed, 0 failed;shellcheck -x install.shclean. I also independently verified the regression claim by revertinginstall.shto the parent commit (15b67d9) and re-runningtest/cli.sh: 5 failures, all of them the new #115/#117 assertions — so the tests genuinely pin the fix, they are not vacuous. (Footnote: the PR body says a wholesale revert produces 4 failures; I measured 5 —flat upgrade under boxes: setup-host runs the NEW version's scriptalso fails on wholesale revert, since setup-host never runs at all on that path. Harmless narrative discrepancy, mentioning it only for the record.)Why the core fix is right
install.sh:160-163now computeshad_installbefore the migration block atinstall.sh:179-197. This is the correct question, and I verified all three tree states behave:bin/box, noversions/):had_install=0, setup offered — unchanged from before, same code path the flat case exercises.versions/does not exist at the time of the test, sohad_install=0and setup-host runs after the migration — the #115 fix, pinned byflat upgrade: host setup RUNS over a migrated flat tree (#115)(test/cli.sh:1839-1840).versions/predates the run,had_install=1, setup skipped with thebox setup-hostpointer atinstall.sh:422— pinned in both directions by theversioned upgradepair (test/cli.sh:1848-1851), which is what keeps "fixed" distinguishable from "runs setup-host unconditionally."The
$VDIRfix (install.sh:429,install.sh:437) is the part I scrutinized hardest, because Part 1 is what makes it reachable: on a flat host with live boxes, the #66 guard atinstall.sh:326-333holdscurrentat the migrated old version, so$DEST/current/host/setup-host.shwould have converged the host with the previous release's scripts — or, as the test comment attest/cli.sh:1856-1859correctly notes, found no script at all, since the flat fixture carries nohost/dir.$VDIRis unambiguously the tree this run installed. Theflat upgrade under boxespair (test/cli.sh:1862-1865) proves both the new-version marker and that the #66 default stayed put. The sudo-missing hint atinstall.sh:429moving to the same path is correct and easy to miss — good catch including it.The #117 half
Detection is precise:
migrated_from(install.sh:178,196) is set only inside the migration branch, whose guard[ -e "$DEST/bin/box" ] && [ ! -d "$DEST/versions" ](install.sh:179) cannot fire on a fresh host (nobin/box) or a versioned one (versions/exists) — no false positives, and theNON-migrating install stays silentassertion (test/cli.sh:1814-1815) pins that. The messages name the actual leftover path (versions/$flat_ver) and both ways out (box use/box uninstall), at the migration (install.sh:193-195) and again afterdone(install.sh:460-463). Nothing destructive happens to the leftover — name-and-continue, with auto-delete explicitly rejected for the rollback-target reason #117 itself gives. That is the right default.Migration idempotency holds: once migrated,
versions/exists and the guard cannot re-fire; a re-run converges as a normal versioned install. (The narrow crash window inside the two-rename migration itself predates this PR and is unchanged by it.)The stated trade-off
Accepting that a
BOX_YES=1unattended upgrade on a flat host now runssetup-hostis the right call, argued honestly in the PR body:setup-hostis built to converge, and a release whose host half silently never lands (#115's exact failure — 0.8.0 reported while the pre-#102box-firewallkeeps taking the no-UFW branch) is strictly worse. The decision is on the record in the comment atinstall.sh:146-159and the CHANGELOG entry, where a future reviewer can reopen it.Non-blocking observations
new_ver == flat_ver, e.g. re-piping the 0.6.0 installer over a flat 0.6.0): the migration runs,$VDIRis the migrated old tree,had_install=0, and setup-host would execute from a tree that may have nohost/setup-host.sh. The failure mode is the gracefulwarnatinstall.sh:440-441, so nothing breaks — just noting the edge exists. Not worth code.inst_setupassertion (no prior tree at all) would complete the matrix, but the fresh path is byte-identical to the flat path's gate and unchanged by this PR — genuinely optional.Nice work — the test proof discipline here (marker names the version, reverts verified to fail, the conditional-silence assertion) is exactly what makes a fix in this file trustworthy.
— automated review by
claude-bot-andresmgsl· heavy-duty-review-botRound passed — three approvals, no blockers. Thanks all.
Both of @claude-bot-andresmgsl's observations are ones I agree with and am deliberately not acting on:
new_ver == flat_ver) — the edge is real: migration runs,$VDIRis the migrated old tree,had_install=0, and setup-host executes from a tree that may carry nohost/setup-host.sh. It lands on the gracefulwarnatinstall.sh:440-441, so the failure mode is a message rather than a break. Agreed it is not worth code.inst_setupassertion — the fresh path is byte-identical to the flat path's gate and unchanged by this PR, so it would pin something this PR does not move.Neither is filed, on the principle that an issue nobody will act on is worse than a review comment that stays findable on the PR.
Worth restating for whoever reads this at merge time, since it is the load-bearing part: the
$VDIRfix is not incidental to Part 1 — Part 1 activates it. Before this PR,install.sh:407running from$DEST/currentwas harmless because setup-host never ran on that path at all. Making it run is exactly what turns the #66 guard (which holdscurrentat the migrated old version when boxes exist) into a live defect: the host would converge with the previous release's scripts, reinstating #115's staleness in its most expensive case. Shipping Part 1 without the$VDIRchange would have been a fix in name only. The isolating revert — Part 1 kept,$VDIRreverted → exactly one failure,flat upgrade under boxes— is what proves that empirically rather than by argument.Handing to the maintainer: requesting @danmt for the human round.
Rebased onto
mainafter #126 merged.CHANGELOG.mdonly —install.shandtest/cli.shrebased clean, so the$VDIRfix and its fixtures are byte-identical to what you approved at3fe589d.The conflict needed a human and the resolver said so. Both sides carried
### Fixed— main's (now holding #116's and #122's entries, merged as #118 and #126) and this PR's three. It refused withsides share section(s) {Fixed}; resolved by hand into one### Fixedheading holding all six bullets,### Changeduntouched above.Verification, including the structural check that content guards cannot see:
That last line is #126's guard, now live on
main, running against this branch — first real use since it landed.On the two non-blocking observations (@claude-bot-andresmgsl) — both left alone deliberately, not overlooked:
warnatinstall.sh:440-441, so nothing breaks. Adding code for a path that already degrades correctly would be more surface than the edge is worth.inst_setupassertion. Agreed it would complete the matrix, and agreed it is out of scope here — the fresh path is byte-identical to the flat path's gate and unchanged by this PR. Worth its own small PR rather than smuggling coverage of an untouched path into a fix.Re-requesting all three — the push moved head, so approvals bound to
3fe589dare stale regardless of content.Verdict: Approve — I agree with this as-is.
Tip
b1968dais the same fix rebased onto main after #126. Prior approve was at3fe589d.What holds
had_installbefore the pre-0.7.0 migration — a flat host no longer looks already versioned and skipssetup-host.$DEST/current(which can still name the old version when boxes hold the default).box useor reap viabox uninstall.## Unreleased### Fixedwith main's entries; heading set matches main (single## 0.8.0).Accepted trade-off (unattended flat upgrade runs
setup-host) still stated; CI green. No remaining blockers.✅ Approved — I agree with all of this, no concerns.
Re-approving after the rebase to head
b1968da. My3fe589dapproval covered the substance; this round I verified the rebase itself rather than re-arguing it:3fe589dagainst the patch atb1968da— forinstall.shandtest/cli.shthey are identical except for hunk offsets and blob hashes (the head-to-head file diff shows only main's own staging→staging-box renames, which is exactly what a clean rebase picks up). The$VDIRfix and its fixtures are the same bytes I approved.### Fixedunder## Unreleased(line 62) now holds main's entries plus this PR's three bullets,### Changeduntouched above, and the##heading set is identical to main's — so the #126 monotonicity guard has nothing to object to, and indeed passes.b1968da:test/cli.sh484 passed / 0 failed,test/release.sh120/0,shellcheck -x install.shclean,changelog-armed.shandchangelog-monotonic.shboth pass — matching the numbers in the rebase comment.My two non-blocking observations from last round (same-version flat reinstall; fresh-host
inst_setupassertion) were addressed by explicit, reasoned non-action, which I accept — nothing new to raise.— automated review by
claude-bot-andresmgsl· heavy-duty-review-botVerdict: I agree with everything and have no additional feedback.\n\nRe-evaluated the complete current diff at
b1968dabafter the rebase. The installer ordering and $VDIR setup-host path remain correct, the migration guidance is conditional and actionable, the regression coverage exercises both run and skip paths, and all current checks pass.