ADR 0028 shipped types 4-7 and said honestly that they were unproven: the
uncovered lines of `shading.rs` were exactly `parse_mesh`, "the position
`image.rs` was in before ADR 0016 found the JPEG decoder was a stub".
Writing the fixtures found three real bugs.
- Type 5 has no per-vertex flag; `/VerticesPerRow` delimits it. Reading 8
phantom bits shifted every vertex after the first, decoding plausible
coordinates that were entirely wrong.
- Types 6 and 7 are patches: 12 or 16 control points carrying no colour,
then four corner colours. The old loop read a colour per point, consumed
three times too many components, ran off the stream, and the
None-on-truncation path swallowed it as "the mesh ended".
- A flag-0 triangle is three vertices whose second and third flags are
ignored (§8.7.4.5.5). Acting on them cleared the strip every time and
produced no triangles at all. Caught in new code, before it shipped.
And one omission: `color_at_point` returned None for a mesh, so a mesh that
parsed perfectly still painted nothing — indistinguishable from one that
failed. `MeshTriangle::color_at` now interpolates the corner colours by
barycentric coordinates, None outside, because black is a colour a mesh can
legitimately produce.
Shared-edge patches (flags 1-3) inherit the previous patch's edge rather
than being read as fresh patches, which desynchronised the rest of the
stream.
Five corpus fixtures, generated from named coordinates and colours so every
expected value in the tests is one the generator wrote deliberately. Eight
tests, five mutations, all killed. Coons flattening is still an
approximation and still reports `is_approximate`.
ADR 0029.