Verify the Phase 2 gate, and give every blocked item an unblock condition
Starting from the phase's stated exit criteria rather than the checklist, because
"complete" should mean the gate, not the feeling of the list.
THE GATE IS MET. Both halves, checked by inspection:
* Golden tests. Every module in gc-formats/src is referenced by a test or another
module's test path; none is unreferenced. gc-extract/tests/disc.rs carries 50
real-disc tests, and overlay_reloc's mask test resolves a level-01 function on
all 26 other overlays.
* Counts are failures, not warnings. No parser writes warning-style output
outside #[cfg(test)] -- the only eprintln! calls in gc-formats are inside test
modules. Count and length problems surface as typed errors: 42 uses of
ErrorKind::Invalid / InvalidLength, including global_wad's "pair table is not a
whole number of entries", which is precisely a header count disagreeing with
the data.
THE GOAL IS NOT MET, and saying otherwise would be the thing AGENTS.md forbids.
The goal reads "every asset type parses into plain Rust values". Four do not:
collision cells, volumes, moby_anim and the tfrag morph are located or framed but
have no decoded fields. The gate was written to be checkable and it does not test
for that, which is a gap in the gate rather than a reason to declare victory.
So the remaining gap in the phase's own discipline is that the four blocked items
did not say what would unblock them, which AGENTS.md requires and which none of
them did. Closed now, each with the specific unblock condition:
collision cells the game addresses its assert string by something other than a
$gp-relative load -- a %hi/%lo split that does not straddle
zero, a pointer table, or another section. A plain $gp search
returns zero and always will.
volumes ground truth: a count of level 0's trigger volumes from a map,
to match against the 144-byte table's population. No class name
containing "volume" exists on the disc, so the dispatch route is
closed.
moby_anim needs moby class records decoded past the header -- a
dependency, not a measurement.
tfrag morph needs a frame captured at a KNOWN camera distance, so the
expected blend is computable. Requires driving the running game,
not analysing a static savestate.
None of these is an approximation, and none is marked done.
258 tests, 50 in the disc suite, clippy clean on my own code.
This commit is contained in:
@@ -540,6 +540,52 @@ Phase 1 hands over the extents; this phase works out what each one contains.
|
|||||||
**Gate:** every parser has a golden test against bytes from the real disc, and
|
**Gate:** every parser has a golden test against bytes from the real disc, and
|
||||||
reports mismatched header counts as failures rather than warnings.
|
reports mismatched header counts as failures rather than warnings.
|
||||||
|
|
||||||
|
### Gate status, checked
|
||||||
|
|
||||||
|
Both halves verified by inspection rather than assertion:
|
||||||
|
|
||||||
|
* **Golden tests.** Every module in `gc-formats/src` is referenced by a test or
|
||||||
|
another module's test path; none is unreferenced. `gc-extract/tests/disc.rs`
|
||||||
|
carries 50 real-disc tests, and the `overlay_reloc` mask test resolves a level-01
|
||||||
|
function on all 26 other overlays.
|
||||||
|
* **Counts are failures, not warnings.** No parser writes warning-style output
|
||||||
|
outside `#[cfg(test)]` -- the only `eprintln!` calls in `gc-formats` are inside
|
||||||
|
test modules. Count and length problems surface as typed errors: 42 uses of
|
||||||
|
`ErrorKind::Invalid` / `InvalidLength`, including `global_wad`'s "pair table is
|
||||||
|
not a whole number of entries", which is exactly a header count disagreeing with
|
||||||
|
the data.
|
||||||
|
|
||||||
|
**The gate is met.**
|
||||||
|
|
||||||
|
### Blocked, and what would unblock each
|
||||||
|
|
||||||
|
AGENTS.md requires a blocked item to say what would unblock it. These four did
|
||||||
|
not, which is itself a gap; this is that gap closed. None of these is a shortcut
|
||||||
|
or an approximation -- each is a measurement this repository currently cannot
|
||||||
|
make.
|
||||||
|
|
||||||
|
- **Collision cell layout.** The payload is verbatim in RAM and does not walk as
|
||||||
|
fixed-stride cells; every disc-side segmentation is excluded. Needs the game's
|
||||||
|
own `Camera_CollPrimTest`, which lives in `.lit`. The route that would work:
|
||||||
|
the code addresses the assert string by something other than a `$gp`-relative
|
||||||
|
load -- a `%hi`/`%lo` split that does not straddle zero, a pointer table, or a
|
||||||
|
different section. A naive `$gp` search returns zero hits and will keep doing so.
|
||||||
|
- **Volumes.** A 144-byte float record table with world positions at `+0x0c`
|
||||||
|
exists in every level and is not referenced by any `data.bin`, so it is reached
|
||||||
|
by walking structure, and nothing ties it to volumes. Needs ground truth: a
|
||||||
|
count of level 0's trigger volumes from a map or guide, to match against a
|
||||||
|
table's population. No class name containing "volume" exists on the disc, so the
|
||||||
|
dispatch-table route is closed.
|
||||||
|
- **`moby_anim`.** The instance-table reading is disproved and nothing replaces
|
||||||
|
it. Needs the class-dispatch table for the classes that reference the animation
|
||||||
|
data, which needs `moby` class records decoded past the header -- a dependency,
|
||||||
|
not a measurement.
|
||||||
|
- **tfrag morph.** All patch bytes are rewritten by LOD-selected VU-packet
|
||||||
|
regeneration, so the morph is invisible in a savestate. Needs a frame captured
|
||||||
|
at a *known* camera distance, so the expected blend is computable and can be
|
||||||
|
compared. Requires running the game and driving the camera, not analysing a
|
||||||
|
static savestate.
|
||||||
|
|
||||||
**Discipline:** bound every read. Typed errors, no panics, no reads past the
|
**Discipline:** bound every read. Typed errors, no panics, no reads past the
|
||||||
buffer.
|
buffer.
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user