The first real data-model field of the schema-major-1 bump, and the point
where the dispatch seam flips from the Phase-B identity to a genuine
migration. Zero golden churn: CanvasLayoutDefaults::default() equals the
engraver's existing A4/8mm default, so no resolved geometry moves.
- Data model (core/graph.rs): Canvas gains `layout_defaults:
CanvasLayoutDefaults`, with new core geometry primitives CanvasSize /
CanvasMargins (staff-space CanonicalF64, A4/8mm Default -- core has no
geometry types of its own and must not depend on layout-ir). Exported from
the crate root; ~7 Canvas construction sites updated with
`..Default::default()`.
- Codec (core/codec.rs): struct_codec! for the three new types; Canvas v1
encodes `regions` then `layout_defaults`.
- The frozen migrate-on-read (decode_v0_score): a byte-level splice. v0 Score
bytes are the v1 layout minus Canvas.layout_defaults; Canvas is Score field 2
and its v0 layout was just `regions`. Read the v0 prefix (metadata,
canvas.regions) to find the split, insert the default CanvasLayoutDefaults
encoding, then decode the resulting v1 bytes. Total and default-filling (no
score context), frozen by value. A `pos()` accessor was added to Reader for
the splice.
- Test (v0_score_migrates_by_default_filling_layout_defaults): derives REAL v0
bytes by stripping the field from a v1 encoding, then migrates them back and
checks the original score is reconstructed with the default refilled. A wrong
splice offset corrupts the bytes and fails the decode, so it guards the
frozen v0 assumptions.
Deferred: routing the migrate through a bundle acceleration_snapshots slot (a
Phase-B Finding-3 item). The migrate logic is proven by the core unit test and
the bundle read path by the canonical-base roundtrip; combining them hits
cross-crate friction (constructing v0 bytes needs core-internal Reader, which
testkit can't reach and core-below-bundle can't stage) for marginal coverage.
The forward scenario (v1 reader migrating a v0 bundle's major-0 acceleration
snapshot) needs no new bundle code -- the v0 snapshot passes the exact gate.
863 workspace tests pass; clippy -D warnings, fmt --check, rustdoc -D warnings
all clean; no render/snapshot goldens changed.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NEs4aYiu8MXjdYdMxw8PTd