feat(schema): make 0.3.0 the current scaffold.toml schema - #255
Conversation
Bump SCAFFOLD_TOML_SCHEMA_VERSION to "0.3.0" and turn the migrator into a
chain so one `init` takes any older file all the way to the current schema.
0.3.0 changes no sections and no fields — it is a version stamp alone. It is
still a migration because the parser exact-matches the current schema: a 0.2.0
file must be routed through `init` rather than silently accepted.
Bumping the constant on its own would have been wrong. `migrate_to_v0_2_0`
short-circuited on `== SCAFFOLD_TOML_SCHEMA_VERSION`, so a valid 0.2.0 file
would have stopped short-circuiting and had the pre-0.2.0 rewrites (lssa
drop/rename, url strip, [basecamp] reshape, [basecamp.modules.*] move) run
against it — silently rewriting content it is entitled to keep, such as a
hand-kept [repos.lssa] for a fork.
- migrate.rs: new `migrate` dispatcher reads [scaffold].version once, returns
an empty report untouched when already current, runs the pre-0.2.0
structural rewrites only for files below the 0.2 series, then runs the
0.3.0 stamp. `migrate_to_v0_2_0` keeps its rewrites, loses the stamp and
the short-circuit, and is private so it cannot be called unguarded. The
stamp is owned by the last step, so a pre-0.2.0 file reports one bump
("0.1.0" -> "0.3.0") instead of one per generation crossed.
- config.rs: `detect_old_schema_markers` flags the whole 0.2 series as stale,
so a 0.2.0 file — which trips none of the shape markers — gets the targeted
"run `init`" line instead of the generic version-mismatch bail. The gate is
a series match in both places, so detection and migration agree on 0.2.1.
- Non-init commands keep hard-failing stale schemas, JSON paths included; the
parser still accepts exactly one version.
- Fixtures that meant "current schema" move to 0.3.0; legacy 0.1.x inputs stay
as they are.
Tests: 0.3.0 file untouched with a stray [repos.lssa] preserved; 0.2.0 file
stamped with the rewrites proven not to run (stray section survives, no spel
backfill); whole 0.2 series gated the same; pre-0.2.0 file fully migrated in
one call; missing [scaffold] section stamped; non-init commands rejecting
0.2.0; init dry-run/backup behavior on the 0.2.0 path; fresh init emitting
0.3.0. Full suite green (558 unit + 187 CLI + 3 API + 5 doc).
The crate version is untouched and unrelated to the schema version.
There was a problem hiding this comment.
Pull request overview
This PR updates the scaffold.toml schema “current version” from 0.2.0 → 0.3.0 and adjusts migration + stale-schema detection so projects with a 0.2.x stamp are routed through init (without accidentally re-running pre-0.2 structural rewrites that could clobber user-kept data such as a stray [repos.lssa]).
Changes:
- Bump
SCAFFOLD_TOML_SCHEMA_VERSIONto0.3.0and update docs/fixtures accordingly. - Convert migration into a chained dispatcher (
migrate) that skips pre-0.2 rewrites for 0.2.x files and stamps the file to 0.3.0. - Expand stale-schema detection/tests so 0.2.x versions get the targeted “run init” rejection path (including JSON-output commands).
Reviewed changes
Copilot reviewed 17 out of 17 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| tests/common/test_node.rs | Updates test scaffold fixture stamp to 0.3.0. |
| tests/cli.rs | Updates minimal fixture stamp, adds coverage for 0.2.0→0.3.0 gating + init behavior. |
| src/testnode/state.rs | Updates test config version to 0.3.0. |
| src/testnode/pins.rs | Updates test config version to 0.3.0. |
| src/project.rs | Updates test config version to 0.3.0. |
| src/migrate.rs | Introduces chained migrator with explicit 0.2.x skip behavior and 0.3.0 stamp step. |
| src/constants.rs | Bumps SCAFFOLD_TOML_SCHEMA_VERSION to 0.3.0 and updates comment. |
| src/config.rs | Expands stale-schema marker detection to include 0.2.x and updates tests/docs. |
| src/commands/run.rs | Updates test config version to 0.3.0. |
| src/commands/run_state.rs | Updates test config version to 0.3.0. |
| src/commands/init.rs | Switches init to call migrate and updates init tests/messages for 0.3.0. |
| src/commands/idl.rs | Updates test config version to 0.3.0. |
| src/commands/basecamp.rs | Updates scaffold fixture stamps in basecamp tests to 0.3.0. |
| src/api/testnode.rs | Updates scaffold fixture stamp to 0.3.0. |
| src/api/mod.rs | Updates fixture writer + comments to schema 0.3.0. |
| README.md | Updates user-facing init semantics/documentation for 0.3.0 and 0.2.x stamping. |
| ADR.md | Documents the 0.3.0 migration model and the role of the 0.2.x gate. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| // A file already at 0.2.x carries none of the pre-0.2.0 shapes, so the | ||
| // structural rewrites are skipped and only the version stamp runs. | ||
| if !is_v0_2_x(&from_version) { | ||
| report.merge(migrate_to_v0_2_0(doc)?); | ||
| } |
Review + targeted dogfooding (E3 / migration paths)The migrator-as-a-chain refactor is the right shape, and the reasoning in the PR body is correct: flipping the constant alone really would have run the pre-0.2.0 rewrites against valid 0.2.0 files. Splitting the version stamp into Test coverage is good: the 0.2-series gate, the stray I verified the happy paths behave as described — a fresh One finding: a file newer than the current schema is silently downgraded and structurally rewritten
Reproduced against this branch with a $ lgs init
scaffold.toml in /tmp/futuresch migrated to schema v0.3.0.
- dropped stale [repos.lssa] (kept [repos.lez])
- appended [repos.spel] with default pin
- migrated [basecamp].pin / .source -> [repos.basecamp]
- bumped [scaffold].version: "0.4.0" -> "0.3.0"Three things go wrong at once: the hand-kept This is pre-existing, not a regression — I checked master and it does the same thing ( Worth noting the detection side already behaves correctly here — Minor
Nothing else blocking from my side — the core change is well-reasoned and well-tested.
Generated by Claude Code |
weboko
left a comment
There was a problem hiding this comment.
Review: make 0.3.0 the current schema — verified ✅
The migration design is clean: migrate() chains one step per generation (pre-0.2.0 structural rewrites → 0.2.0→0.3.0 version stamp), a 0.2.x file skips the structural rewrites and only gets re-stamped, and an already-current file is untouched. The from_version gating (is_v0_2_x) and the single "one bump line, not one per generation" report are the right shape.
Verified on my side:
cargo test --lib migrate→ 13/13 pass, including the new cases (migrates_v0_2_0_by_stamping_the_version_without_rerunning_v0_2_0_rewrites,migrates_the_whole_0_2_series…,migrates_pre_v0_2_0_to_current_schema_in_one_call). Full lib suite: 574 pass.- Real end-to-end with a built binary: a
version = "0.2.0"project is rejected bydoctorwith "Runlogos-scaffold initto migrate to v0.3.0; existing settings are preserved";initmigrates it to 0.3.0, writesscaffold.toml.bak, and reports the single bump;doctorthen reads it fine. A freshinitstamps 0.3.0. - The crate-version-vs-schema-version decoupling is sound and well-documented in the constant's doc comment.
The stale-version detection correctly extends to 0.2/0.2.x while leaving other mismatches to parse_config's more specific error. No blocking issues.
Generated by Claude Code
Re-review: 0.3.0 as the current schema — verified end-to-end, one documentation gapEnvironment: Nix 2.35.2, Rust 1.94.1, r0vm 3.0.5 + risc0 guest toolchains, real LEZ sequencer + wallet from I re-ran the migration against a real 0.2.0 project — one generated by the Chained migration, one One bump line spanning both generations, exactly as designed. The 0.2.0 → 0.3.0 stamp-only path: Stale-schema gate: a 0.2.0 file against the new binary gets the targeted line, not the generic mismatch error: Backup safety: Migrated project still works: I migrated the real provisioned project in place and then ran the full path against a live sequencer — The design reads well too. The chain-with-a-dispatcher shape is right, The one thing I'd want before this lands: DOGFOODING.md has no migration scenarioThe Verification section cites E3 for the So the behaviours you actually verified for this PR — the stale-schema gate across 9 commands + the two The runbook's own maintenance note is the argument:
I'd add an Minor, non-blocking
Verdict: the code is correct and I could not break it. I'd approve once the DOGFOODING scenario is added — for a change whose entire blast radius is a migration every user must run, the runbook not describing that migration is the thing I'd fix before merging, not after. Generated by Claude Code |
User Story
Every project on the Logos stack carries a
scaffold.tomlstamped0.2.0. Movingthe schema to
0.3.0meansinithas to take them there, and the naive version ofthat change is actively destructive:
migrate_to_v0_2_0short-circuited on== SCAFFOLD_TOML_SCHEMA_VERSION, so flipping the constant alone would stop a valid0.2.0 file from short-circuiting and run the pre-0.2.0 rewrites (lssa drop/rename,
urlstrip,[basecamp]reshape) against it — silently rewriting content the useris entitled to keep, such as a hand-kept
[repos.lssa]for a fork. Detection had themirror-image gap:
version_staleonly matched0.1.x/0.1/0.0, so a 0.2.0 filewould skip the marker and fall through to the generic "this build expects…" error
instead of the targeted "run
init" line.Surfaced by E3 (
init/ re-init) and by D1/D7 rerun on a migrated project.Change Summary
Bumps
SCAFFOLD_TOML_SCHEMA_VERSIONto0.3.0and turns the migrator into a chain:a
migratedispatcher reads[scaffold].versiononce, runs the pre-0.2.0 structuralrewrites only for files below the 0.2 series, then applies the 0.3.0 stamp. 0.3.0
changes no sections and no fields — it is a version stamp alone — but it is still a
migration, because the parser exact-matches the current schema and a 0.2.0 file must
be routed through
initrather than silently accepted. Oneinittakes a 0.1.x fileall the way to 0.3.0, reporting a single bump (
"0.1.0" -> "0.3.0").Verification
DOGFOODING rerun: E1, E3, D1 (
setup/build/deploy), D6, D7 — the last fourrun against a project migrated 0.2.0 → 0.3.0, not a fresh one.
setupexit 0;doctor20 PASS / 4 WARN / 0 FAIL (warns: nonix, localnetnot started)
runexit 0 — 5 programs deployed, 0 failed, real sequencer, blocks 5→861cf6f66…);wallet account getshowsnonce: 1deploy --json/doctor --jsonall hard-fail atinitwithstdout_bytes=0;scaffold.tomlunmutated. Afterinit, none stillcite the schema.
init --dry-runwrites nothing;.bakcollision refuses,--no-backupproceeds.Tests: 558 unit + 187 CLI + 3 API + 5 doc, all green;
cargo fmt --checkclean.New coverage: 0.3.0 file untouched with a stray
[repos.lssa]preserved; 0.2.0 filestamped with the rewrites proven not to run; the whole 0.2 series gated identically;
pre-0.2.0 migrated in one call; missing
[scaffold]stamped; non-initcommandsrejecting 0.2.0; fresh
init/newemitting0.3.0.Checklist
README.md,ADR.md) if user-facing behavior changed