Skip to content

feat(006): template upgrade verb (chassis upgrades as a governed local verb)#5

Merged
bartekus merged 1 commit into
mainfrom
006-template-upgrade-verb
Jul 15, 2026
Merged

feat(006): template upgrade verb (chassis upgrades as a governed local verb)#5
bartekus merged 1 commit into
mainfrom
006-template-upgrade-verb

Conversation

@bartekus

Copy link
Copy Markdown
Contributor

Summary

Implements spec 006: stagecraft template upgrade, the chassis upgrade as a governed verb. Run in a stamped app checkout, it reads template.toml, bumps the chassis package pins in package.json, refreshes the lockfile, runs the reserved codemod hook, runs the verify verb of the contract, 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, template upgrade never 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.
  • Compat gate is the range named by the contract. A target outside the [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.
  • Chassis discovery is scope-derived, not hardcoded. Seeds are the package.json deps that a [requires] key names by unscoped tail (so node drops out and toolchain resolves to @enrahitu/toolchain); the bump set is every exact-pinned dep sharing the scope of a seed, catching companions like @enrahitu/hiqlite-native with no @enrahitu literal in the CLI.
  • Refusals are structured (all exit 1, JSON error.kind): not_stamped, pre_chassis, local_chassis (chassis present but file:-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 carries verify:"fail" and exits 1 (matching stamp status --watch), leaving the branch uncommitted for inspection.
  • Offline by construction. Every git/npm/node side effect sits behind a Runner trait, so cargo test never 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 a Runner fake): scope-derived discovery with companions, the pre_chassis/local_chassis/not_stamped/incompatible_target/dirty_tree refusals, the multi-range gate, format-preserving pin rewrite, the dry-run plan that mutates nothing, latest-resolution when --to is 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.
  • An independent review pass ran on the diff before commit and drove hardening. It caught the verify-fail JSON envelope emitting a novel {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 how stamp status --watch renders a terminal failed job. 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. couple reports 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 new template upgrade subcommand 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.

…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.
@bartekus
bartekus merged commit 732e936 into main Jul 15, 2026
2 checks passed
@bartekus
bartekus deleted the 006-template-upgrade-verb branch July 15, 2026 14:48
Sign up for free to 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.

1 participant