feat(006): template upgrade verb (chassis upgrades as a governed local verb)#5
Merged
Merged
Conversation
…l verb)
`stagecraft template upgrade`, run in a stamped app checkout, bumps the
chassis package pins in package.json to a target template version, refreshes
the lockfile, runs the reserved codemod hook, runs the contract's verify verb,
and commits on a template-upgrade/<from>-<to> branch. The enrahitu spec 018
gate (chassis packages published at v0.1.0) is cleared, so this verb is no
longer parked.
The one local governed verb: unlike the spec 004 verbs it never calls the
control plane; it orchestrates a repo-local operation with all structure
knowledge staying in the template and its packages. It still renders the
shared {ok,data|error} envelope. The compat gate is the contract's own
[requires] range (the target must satisfy every named range); chassis
discovery is scope-derived so no @enrahitu literal leaks into the CLI. Every
git/npm/node effect sits behind a Runner trait, so cargo test runs offline.
Refusals (exit 1, JSON error.kind): not_stamped, pre_chassis, local_chassis,
bad_target, incompatible_target, dirty_tree. A verify failure is a completed
run whose {ok:true,data} result carries verify:"fail" and exits 1 (matching
stamp status --watch), leaving the branch for inspection.
An independent review pass drove hardening before commit: the verify-fail
envelope now keeps the two-shape contract ({ok:true,data} + exit 1) instead of
a novel third shape; the no-op check compares every pin so a companion behind
the primary is still bumped; the dirty-tree preflight runs before target
resolution; and the compat gate checks every seed range. Each is locked with a
test.
Spec 006 stays implementation: in-progress; the live check needs a real
stamped app with published pins, which does not exist yet (enrahitu's scaffold
is still v0). A dated §5 Status note records the v1 decisions and what remains.
Adds the semver crate.
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.
Summary
Implements spec 006:
stagecraft template upgrade, the chassis upgrade as a governed verb. Run in a stamped app checkout, it readstemplate.toml, bumps the chassis package pins inpackage.json, refreshes the lockfile, runs the reserved codemod hook, runs the verify verb of the contract, and commits on atemplate-upgrade/<from>-<to>branch. The enrahitu spec 018 gate (chassis packages published at v0.1.0) is cleared, so this verb is no longer parked.template upgradenever calls the control plane. It orchestrates a repo-local operation; all structure knowledge stays in the template and its packages. This is the boundary that keeps the CLI from becoming a build daemon (spec 006 summary). It still renders the shared{ok,data|error}envelope, so both faces stay uniform and a later fleet-wide sweep can consume the result.[requires]chassis range is the "major upgrade requires the migration path" refusal (incompatible_target); the version policy lives in the template, not the CLI. When a contract names more than one range, the target must satisfy all of them.package.jsondeps that a[requires]key names by unscoped tail (sonodedrops out andtoolchainresolves to@enrahitu/toolchain); the bump set is every exact-pinned dep sharing the scope of a seed, catching companions like@enrahitu/hiqlite-nativewith no@enrahituliteral in the CLI.error.kind):not_stamped,pre_chassis,local_chassis(chassis present butfile:-linked, i.e. a template-dev tree),bad_target,incompatible_target,dirty_tree. A verify failure is a completed run whose{ok:true,data}result carriesverify:"fail"and exits 1 (matchingstamp status --watch), leaving the branch uncommitted for inspection.Runnertrait, socargo testnever gates on the outside world (the spec 003 section 1 discipline).Spec 006 stays
implementation: in-progress(same shape as 003/004/005): the section 3 live check needs a real stamped app carrying published-version chassis pins plus a newer template release to upgrade across, and the enrahitu scaffold verb (spec 014) is still v0 and edits no dependencies, so no such app exists yet. A dated section 5 Status note records the v1 decisions and exactly what remains (the live upgrade transcript, no code change).Testing
cargo fmt --check,cargo clippy --all-targets -- -D warnings: clean.cargo test: 117 pass (101 unit + 16 integration). New coverage (all offline, every git/npm/node effect behind aRunnerfake): scope-derived discovery with companions, thepre_chassis/local_chassis/not_stamped/incompatible_target/dirty_treerefusals, the multi-range gate, format-preserving pin rewrite, the dry-run plan that mutates nothing, latest-resolution when--tois omitted, the no-op that still bumps a companion left behind the primary, the happy path (branch to lock to verify to commit), the verify-failure path that leaves the branch uncommitted, and the result envelope staying{ok:true,data:{verify:"fail"}}with a Rendered exit 1. Three end-to-end binary checks drive the offline paths (not-stamped, pre-018, dry-run) with the process working directory set to a fixture.{ok:false,data}third shape; fixed to keep the two-shape contract of the codebase as{ok:true,data:{verify:"fail"}}plus a Rendered exit 1, matching howstamp status --watchrenders a terminalfailedjob. Also fixed, each locked with a test: the no-op check now compares every chassis pin (a companion left behind the primary is still bumped), the dirty-tree preflight now runs before target resolution (fail fast, no wasted registry read), and the compat gate checks every named[requires]range. Two review notes were accepted and documented in spec section 5 rather than coded (the scope-sweep lockstep assumption; Cargo-flavored semver reading bare ranges as caret, so contract ranges must carry an explicit operator).spec-spine lint --fail-on-warn(0/0/0),index check(fresh): green.couplereports the expected spec-002 drift (below).Spec-Drift-Waiver: this PR implements spec 006 (the template upgrade verb) but necessarily edits files under the spec 002 crate scaffold: Cargo.toml, Cargo.lock, src/cli.rs, src/commands.rs, src/verbs/template.rs. The
[package.metadata.spec-spine]key of the crate couples the whole crate to spec 002, so every feature spec code lands in 002 territory (including its own new module file); the new logic lives in the spec-006-owned stagecraft_cli::verbs::template module, and the scaffold edits are the command-tree wiring (a newtemplate upgradesubcommand and its dispatch) that spec 002 placed the tree specifically to receive. No 002 design is contradicted, so this is a coupling waiver, not a coherence override.