Tooling around appups and relups: a coverage check that catches incomplete appups before they ship, baselines that can be named without knowing systools' path shapes, relup generation folded into assembly, and a build-time task surface named castle.*.
The reasoning for all of it — the decisions, what was measured rather than assumed, and what we deliberately do not do — is in design/upgrade-tooling.md in this repository. It lands with the first PR in this tree. The issues below carry scope and acceptance criteria only; they do not restate the rationale, and where they disagree with it, the document is the one to amend.
Why this is one tracker across two repositories
Castle and Forecastle divide one job between them and this work crosses the boundary in both directions. The task namespace is a Castle-facing decision implemented entirely in Forecastle; the upgrade_from: release option is declared through Castle.customize/1 and honoured by a Forecastle assembly step. Neither repository is the whole of it.
The problem, in one paragraph
:systools.make_relup/4 fails when an appup has no entry for the version being upgraded from. It cannot notice that an entry is incomplete. If two modules changed and the appup mentions one, a relup is generated, the upgrade succeeds, release_handler swaps the code path — and the unmentioned module is still the version that was loaded before, serving calls, because nothing named it and nothing purged it. The failure is invisible to the compiler, to :systools, to --hot and at install time, and it surfaces on the next restart when the code changes underneath a system nobody was upgrading.
Sequencing
1.0.0 — only the rename, which has to be now or never (Castle is 0.3.1, Forecastle 0.1.3).
After — in dependency order: the baseline resolver, then the coverage check, then relup-during-assembly, then the generator, then dependency appups, then --dry-run and the upgrade harness.
Tooling around appups and relups: a coverage check that catches incomplete appups before they ship, baselines that can be named without knowing
systools' path shapes, relup generation folded into assembly, and a build-time task surface namedcastle.*.The reasoning for all of it — the decisions, what was measured rather than assumed, and what we deliberately do not do — is in
design/upgrade-tooling.mdin this repository. It lands with the first PR in this tree. The issues below carry scope and acceptance criteria only; they do not restate the rationale, and where they disagree with it, the document is the one to amend.Why this is one tracker across two repositories
Castle and Forecastle divide one job between them and this work crosses the boundary in both directions. The task namespace is a Castle-facing decision implemented entirely in Forecastle; the
upgrade_from:release option is declared throughCastle.customize/1and honoured by a Forecastle assembly step. Neither repository is the whole of it.The problem, in one paragraph
:systools.make_relup/4fails when an appup has no entry for the version being upgraded from. It cannot notice that an entry is incomplete. If two modules changed and the appup mentions one, a relup is generated, the upgrade succeeds,release_handlerswaps the code path — and the unmentioned module is still the version that was loaded before, serving calls, because nothing named it and nothing purged it. The failure is invisible to the compiler, to:systools, to--hotand at install time, and it surfaces on the next restart when the code changes underneath a system nobody was upgrading.Sequencing
1.0.0 — only the rename, which has to be now or never (Castle is 0.3.1, Forecastle 0.1.3).
After — in dependency order: the baseline resolver, then the coverage check, then relup-during-assembly, then the generator, then dependency appups, then
--dry-runand the upgrade harness.