Remediate Ε-W3-T1 package-compat-fixtures review findings

Freeze *.rsbank as binary via .gitattributes; add a truncated additive_forward fixture proving the exact-size proof beats TooNew; enumerate the fixture dir to catch orphaned files; make fixture-size checks fatal instead of just logged; pin fixture version asserts as literals, not build-relative.
This commit is contained in:
2026-08-02 15:39:04 -04:00
parent 9521b5339f
commit 3fd3214ff8
8 changed files with 173 additions and 61 deletions
+28 -11
View File
@@ -12,20 +12,29 @@ The reason is the whole point of the corpus. These bytes exist to catch a format
that quietly breaks a compatibility direction. A fixture regenerated by the build that
broke it agrees with that build by construction and catches nothing — which is exactly
the failure mode a version ladder exists to prevent. The same argument forbids a test
that builds its own fixture at run time.
that builds its own fixture at run time. The repo-root `.gitattributes` (`*.rsbank
binary`) keeps this mechanical: without it, git's NUL-sniffing heuristic could
text-classify a future short/ASCII fixture and CRLF-mangle a line ending on a Windows
checkout, silently breaking the frozen-bytes premise.
If a fixture stops decoding, the answer is never to re-cut the fixture. Either the format
change was structural (bump `minReaderVersion`, add a new fixture, and leave the old one
asserting the refusal) or it is a regression.
A fixture's BYTES are frozen forever; a fixture's ASSERTION is not. `additive_forward.rsbank`
and `refuse_structural.rsbank` carry version pairs one step past THIS build's ladder (2/1
and 2/2). When a future build's own `kPackageFormatVersion` reaches 2, `refuse_structural.rsbank`
classifies `Readable` under the new ladder — its bytes never claimed to need more than
format 2 — so that build re-aims the assertion (and adds a new synthetic pair one step
past the NEW ladder); it never re-cuts the fixture. If a truncation or hostile-name
fixture ever changes classification, that is a regression, never a ladder consequence.
## Provenance
`v1_shipping.rsbank` was produced by running this repo's own export verb (`exportBank`)
at version **1.4.0** over a one-sample bank, and copying the emitted file here verbatim.
Every other fixture is derived from those bytes: the truncations are prefixes of them,
and the synthetic packages reuse their manifest region under different version integers
or a hand-written hostile manifest (the encoder refuses to write one, which is why those
could not come from the verb).
Every other fixture is derived from those bytes: eight of the nine truncations are
prefixes of `v1_shipping.rsbank` (the ninth, `trunc_additive_forward.rsbank`, is a prefix
of `additive_forward.rsbank` itself — a prefix of a prefix, still frozen bytes, never
regenerated), and the synthetic packages reuse their manifest region under different
version integers or a hand-written hostile manifest (the encoder refuses to write one,
which is why those could not come from the verb).
Payloads are one 300-byte 16-bit mono WAV. The properties under test are structural —
version integers, framing arithmetic, name validation — so a larger payload proves
@@ -46,9 +55,10 @@ build, exactly as this one was, and recording the build's version here.
### Truncation — one file per distinct decode failure site
Each is a prefix of `v1_shipping.rsbank` (907-byte prefix + 300-byte payload = 1207
bytes). All classify `Malformed`; none may classify `TooNew`, since "install a newer
build" does not fix a partial download.
The first eight are prefixes of `v1_shipping.rsbank` (907-byte prefix + 300-byte payload
= 1207 bytes), so `formatVersion` never exceeds this build's on that path. All classify
`Malformed`; none may classify `TooNew`, since "install a newer build" does not fix a
partial download.
| File | Bytes | Site the cut lands in |
|---|---|---|
@@ -61,6 +71,13 @@ build" does not fix a partial download.
| `trunc_payload_middle.rsbank` | 1057 | Inside the first payload. |
| `trunc_one_short.rsbank` | 1206 | One byte short of the total. |
`trunc_additive_forward.rsbank` is the ninth: a 983-byte prefix of `additive_forward.rsbank`
(25-byte frozen header/manifest-length region + 958-byte manifest = 983), cut exactly at
ITS payload boundary. `formatVersion` here is 2 — one past this build's — so this is the
one truncation that proves the exact-size-proof failure stays `Malformed` even when
`formatVersion > kPackageFormatVersion`, rather than relabeling to `TooNew` (the parse
branch is the only one that relabels — see `src/core/package/CLAUDE.md`).
### Hostile names — refused at decode, before any planner
The two naming fields carry different rules (`src/core/package/CLAUDE.md`), so each
Binary file not shown.