test(schemas): freeze a document per schema version and assert it still reads - #174
Merged
Merged
Conversation
Up to standards ✅🟢 Issues
|
| Metric | Results |
|---|---|
| Complexity | 38 |
| Duplication | 0 |
NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.
This was referenced Aug 22, 2026
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.
Implements item 3 of #94 — the compatibility test — and it found a live bug on
its first run.
The gate
One minimal sector-data document frozen per
(sector, version)the registryserves: 28 today. Three properties:
until one is frozen, which is what makes this a tripwire rather than a suite.
fixtures: one that was never legal would pass (3) while proving nothing.
Passport::from_stored. The tripwire.Fixtures are written once by
just freeze-schema-fixturesand neverregenerated — one regenerated from the current schema would agree with the
current schema by construction and could not catch anything.
Why (3) tests
from_storedand notSectorDataMy first version deserialised the bare
SectorDataand reported 14 of 28versions broken. That was wrong, and worth recording because the number looked
alarming: old documents are meant to arrive through a lens.
from_storedisthe path a node actually reads by — direct read, then upcast from the recorded
schemaVersionthrough the lens registry. A sector whose rename shipped a lensis not broken, and asserting otherwise would have been a gate that fails for a
contract nobody has.
Through the real path, exactly one sector was genuinely broken.
The bug it found
A textile passport stored under schema v1.0.0 could not be read at all. The
lens chain had no
1.0.0 → 1.1.0step, soupcast_str_towardrefused withNoPath— while the catalog went on declaring v1.0.0 supported.The step needs no transformation. v1.0.0 and v1.1.0 declare identical
requiredlists, v1.1.0 removes no property, and its sixteen additions are alloptional. But a chain cannot cross a gap: a document two versions behind could
not reach current through a step that required no change. An identity lens closes
it, and
1.0.0 → 1.1.0 → 1.2.0now carries the document through thecountryOfManufacturingrename that was always waiting for it.Textile is the sector whose rename caused the incident this issue was filed over.
Battery pre-2.5.0 is listed as a deliberate refusal
v2.5.0 made
batteryTyperequired because Annex VI Part A point 2 makes thebattery category mandatory public content, and the v2.4.0 → v2.5.0 lens refuses
rather than inventing a category for a record predating the mandate. There is no
correct value to supply, so refusing is the honest outcome.
Listed exactly, and asserted in both directions: a new orphan fails as a
regression, and a listed version that starts reading fails as a stale exemption.
The list cannot quietly become wrong in either direction.
Two tests were pinned to the textile gap
Both
toward_still_refuses_a_gap_no_lens_touches_at_allandfrom_stored_refuses_a_gap_no_lens_bridgesused textile 1.0.0 as their exampleof an unbridged version. Neither is about textile — they assert that an
unbridgeable gap is a typed refusal rather than a panic or a silent identity.
Pointing a mechanism test at a real gap means legitimately closing that gap fails
a test that was never about it, which is exactly what happened here. Both now
build their own gap: a synthetic registry, and a
schemaVersionthis build hasnever served.
The gate was verified to fail
Per the standing rule that an untested gate is not a gate. Adding a required
field to
TyreData:Reverted immediately; the diff carries no trace of it.
On the generator
minimal_documentbuilds fromrequiredonly, and is deliberately not a generalJSON Schema instance generator. Pattern-constrained strings come from a small
explicit table (two entries: a check-digit-valid GTIN-14 and an ISO 3166-1
alpha-2 code) that a reviewer can verify by eye; an unknown pattern produces a
value that fails validation, and the freezer then refuses to write the file
and names the version for hand authoring. A fixture that happens to pass while
meaning nothing is worse than one that is missing loudly.
Still open on #94
Items 1 (a written additive-only contract) and 2 (exposing a transform entry
point from this crate) are untouched. Item 2 is partly there already —
LensRegistryexists andfrom_storeduses it — but there is noSectorData::upgrade-shaped public entry point for a consumer that is notreading a whole
Passport.Verification
just checkgreen: 1121 tests, clippy, doctests, ten plugin suites,cargo docwith
-D warnings,cargo audit.