docs: record Ε-W3 as landed and Phase Ε as complete

This commit is contained in:
2026-08-02 15:57:06 -04:00
parent c0c56ab2a7
commit 24569956cf
2 changed files with 50 additions and 48 deletions
+14 -46
View File
@@ -2404,6 +2404,9 @@ import gate can key on `LedgerStatus` alone without going through `pruneDryRun()
enumeration+scan). **No Ε track touches `core/instrument/`, `shell/instrument/`, or any
capture backend.**
**All three waves have landed — Phase Ε is complete.** W1 through W3 each carry their own
landed note below; see `docs/COMPLETED.md` for every track's full narrative.
---
### Ε-W1 — The contract, the filesystem, and the ledger's new kind
@@ -2568,52 +2571,17 @@ against a package this build is incapable of writing.
**One track.** The whole deliverable is one corpus and the harness over it; splitting it
would mean two tracks writing two halves of one fixture set.
#### Ε-W3-T1 — `package-compat-fixtures`
**Goal.** Turn the version-compatibility policy from an assertion in a doc into a property
proven against **frozen bytes**, so a later format change cannot silently break either
direction.
**Spec:** `docs/product/bank-package.md` §"Version tagging: both directions".
**Surface boundary — owns:** a new checked-in fixture corpus under the package modules' test
tree, the harness that decodes it, and one `docs/` verification script for the DAW half.
**Does not own:** any production module — if a fixture reveals a defect, the fix is filed
against the owning track's module and this track carries the failing test, not the patch.
**Behavior.**
- **Frozen bytes, not regenerated ones.** The corpus holds real `.rsbank` bytes committed to
the repo: a v1 package written by the shipping build, a synthetic
`formatVersion` = N+1 / `minReaderVersion` = current package (the additive-forward case),
and a synthetic `formatVersion` = N+1 / `minReaderVersion` = N+1 package (the refuse case).
A test that regenerates its own fixture proves only that the code agrees with itself —
which is precisely the failure mode a format ladder exists to catch.
- **A truncation corpus.** The valid package truncated at a spread of offsets, each asserted
`Malformed` rather than `TooNew`, so the two recoveries never get crossed.
- **A hostile-name corpus.** Packages whose entry names carry `..`, separators, and absolute
prefixes, each refused.
- **The round-trip anchor.** Export → import → export over the v1 fixture yields
byte-identical payloads.
- **A standalone DAW verification script** in `docs/`, following the
`docs/verify-track-scope-multitrack.md` precedent — the cross-machine transfer is the one
claim no unit test can make.
- **The corpus is append-only.** When a future format version ships, its fixture is added;
no existing fixture is ever regenerated or edited. Stated in the corpus's own README so the
rule survives the person who wrote it.
**Acceptance criteria.**
- All three version fixtures classify as specified, and the additive-forward one imports with
every known field intact and every unknown key skipped.
- Every truncation offset classifies `Malformed`; none classifies `TooNew`, `Readable`, or
crashes.
- Every hostile-name fixture is refused at decode, before any planner runs.
- The round-trip fixture's payloads are byte-identical after export → import → export.
- The DAW script exists and names its steps concretely enough to run without reading this
plan.
**Open questions.** **[propose at review]** how large the committed corpus is allowed to be —
the recommendation is one-sample packages with a few hundred bytes of payload each, since the
properties under test are structural and a large payload proves nothing extra.
**Ε-W3-T1 has landed**`package-compat-fixtures` — see `docs/COMPLETED.md` for the full
narrative. 23 frozen `.rsbank` fixtures now live under `tests/fixtures/package_compat/`
(three version fixtures, nine truncations, eleven hostile-name packages, ~15 KB total),
decoded by a new `package_compat_tests` and driven through export → import → export by a
new `package_round_trip_tests`, plus the DAW script `docs/verify-package-transfer.md` for
the one claim no unit test can make. A repo-root `.gitattributes` (`*.rsbank binary`)
keeps the frozen bytes frozen under `core.autocrlf`. No production module was touched.
**Open question resolved:** the recommendation was followed — the corpus is one-sample
packages with a 300-byte payload each. **Deviation from spec:** RSBK stores no layout
section (it is derived from the manifest), so the planned "mid-layout" truncation lands
at the payload boundary instead, where the manifest parses but the exact-size proof fails.
---