A model and the bytes it reads to, both committed - #336
Merged
Conversation
Every gate beside this crate asks whether a reader answered -- `Ok` or a named refusal, no panic, no read past the end. That is the right question for a corpus of hostile inputs and it is nearly blind to a reader that answers confidently and wrongly. A document whose second primitive is dropped, whose node transform is not applied, or whose texture coordinates are shifted by one vertex answers perfectly well. So one model is committed beside the exact bytes it reads to, and the comparison is byte for byte. The model is generated rather than borrowed, and built to reach every layer at once: two primitives in one mesh, so the appending path runs and the second primitive's indices are shifted by the first's vertex count; a node with a translation, so positions arrive somewhere other than where the accessor put them; indices, so the indexed path runs; per-corner normals and texture coordinates, so the optional streams are present. It also carries a material, a texture and an image, which change no geometry at all -- they are there so the golden proves they stay out of the canonical form. Exact comparison is legitimate here and the provenance file says why: the canonical form is little-endian f32 and u32 copied out of the document, with no arithmetic on a coordinate beyond the transform the document itself states. Nothing rounds, nothing reorders, and no platform spells an f32 differently in memory. That claim is what the comparison pins, and the day it stops being true is the day this gate earns its keep. Coordinates are compared by their bits for the same reason. A tolerance would absorb exactly the change this file exists to notice. Refreshing it is one command rather than a ritual. A rendered golden needs a pinned adapter and candidates adopted by hand, because no two adapters rasterize alike; any machine that runs the generator reproduces these two files, so a diff after running it is a real change to what this crate reads.
The refresh command could make a broken reader green. Nothing held the committed bytes to anything independent: the byte comparison held them to what the reader produces now, and the generator writes the source and the blob together, so both sides moved in step. A reader that started attributing texture coordinates to the wrong corners failed, was fixed by one documented command, and landed as a binary diff nobody can read. This tree's own rule for its rendered goldens is that a golden can never enter the tree through a passing run -- they write a candidate and fail by design so a person looks. That ritual exists partly because no two adapters rasterize alike, and partly so somebody sees what changed. Only the first reason is absent here. So the blob is decoded and every position, normal and texture coordinate is asserted against values derived from the document by hand, with the arithmetic written out to be checked rather than trusted. The fixture could not see three things, and each was its own fault. Its normals repeated within a primitive, so any permutation of them was a no-op -- and the rest of the crate is blind the same way, using identical normals in two other files. Its corner count and its stream bitfield were both six, and those sit adjacent in the header, so swapping the two fields left the bytes identical. Its indices were the identity permutation, so the indexed and unindexed paths produced the same output. It is now a triangle and a quad: nine corners, a distinct normal at every one, and indices that reorder and repeat. Every value distinct wherever a reader could confuse two -- a fixture whose values repeat cannot see a permutation of them. A node with only a translation left the inverse transpose at the identity, so the arithmetic that carries normals was not exercised at all. The node now scales as well, by exact powers of two. The document states `min` and `max` on its position accessors because the format requires them there. This reader ignores both, and a fixture no independent validator would accept is worth less than one that would. The sidecar carries a digest of the blob, as the other goldens' sidecars do, and a test holds one to the other -- without it the sidecar describes whatever the file used to be. The generator writes it, having previously claimed to. And a `.gitattributes` rule keeps the committed source out of line-ending translation, which was rewriting it on checkout. The model itself moves to a shared file so the gate can hold the committed document to the code that describes it, and the generator uses the base64 encoder the other generators share rather than a sixth copy. Also corrects several claims that were true of this fixture and stated as facts about the reader: the path does multiply and add, the bytes travel between machines because the format converts endianness explicitly rather than because memory layout is universal, and the sibling suites already assert values -- one of them catches a defect this golden does not.
This suite exercised the inverse transpose on face normals under a scale and a rotation, and touched corner normals only under a translation -- where leaving them alone is the correct answer. So a reader that transformed the face normals and copied the corner normals through unchanged passed every test in the crate. Three distinct corner normals through a non-uniform scale now, each asserted: the inverse transpose halves x where the matrix doubles it, which is the whole difference between transforming a normal and transforming a direction. The shared fixture beside it carried three copies of one normal, so any permutation of them was a no-op. Three different ones, for the same reason the assertions above exist: a fixture whose values repeat cannot see a reader that reorders them.
…th artifacts Three comparisons in this file compared whole values with `assert_eq!`, which prints both sides. One byte's disagreement in a megabyte artifact buys nine megabytes of log that says nothing the offset does not -- and the file's own comment beside the fourth comparison already forbade it. This crate's tests run in every removability cell that keeps it, so that log is paid over and over rather than once. One helper, used by all of them: it names the first byte that differs, or the two lengths when every shared byte agrees. Also corrects two sentences that were true of the fixture before it grew a scale, and are the stated reason the comparison can be exact. The node states a translation and a scale, both exact powers of two -- the file contradicted itself about this, since the note beside its coordinate comparison already said so. And every accessor the document reads a coordinate through is componentType 5126, but not every accessor: the two index accessors are 5123, and an index selects rather than computes.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Every gate beside this crate asks whether a reader answered —
Okor a named refusal, no panic, no read past the end. That is the right question for a corpus of hostile inputs, and it is nearly blind to a reader that answers confidently and wrongly. A document whose second primitive is dropped, whose node transform is not applied, or whose texture coordinates are shifted by one vertex answers perfectly well.So one model is committed beside the exact bytes it reads to, and the comparison is byte for byte.
The model is generated rather than borrowed, and built to reach every layer at once: two primitives in one mesh, so the appending path runs and the second primitive's indices are shifted by the first's vertex count; a node with a translation, so positions arrive somewhere other than where the accessor put them; indices, so the indexed path runs rather than the implicit one; per-corner normals and texture coordinates, so the optional streams are present and the blob's
presentbitfield is not zero. It also carries a material, a texture and an image, which change no geometry at all — they are there so the golden proves they stay out of the canonical form.Exact comparison is legitimate here, and the provenance file says why: the canonical form is little-endian
f32andu32copied out of the document, with no arithmetic on a coordinate beyond the transform the document itself states. Nothing rounds, nothing reorders, and no platform spells anf32differently in memory. That claim is what the comparison pins, and the day it stops being true — a reader that normalises, or averages, or reorders — is the day this gate earns its keep by failing.Coordinates are compared by their bits for the same reason. A tolerance would absorb exactly the change this file exists to notice.
Refreshing it is one command rather than a ritual. A rendered golden needs a pinned adapter and candidates adopted by hand, because no two adapters rasterize alike. Any machine that runs
cargo run -p renew-mesh --example make_import_goldenreproduces these two files, so a diff after running it is a real change to what this crate reads.Probed before it was called done, since a golden nobody has watched fail is a file rather than a gate: a bit flipped in the committed blob is caught by byte offset; the node transform removed from the source is caught twice, by the byte comparison and by the check that the golden is not vacuous; the second primitive dropped is caught twice, including by length. The tree returns to green after each.
Local gates:
cargo fmt --all --checkclean,cargo clippy --workspace --all-targets -D warningszero errors and zero warnings,cargo test --workspace265 suites with zero failures.