A zero nobody has ruled on is not a measurement - #94
Merged
Merged
Conversation
Five DINS fields measured as numbers publish a recorded zero, and until now the registry had no way to say whether anybody had read the inspection form for them. A reviewed decision and an unexamined field both carried Basis.NONE and published marker_basis: "none" -- which docs/MARKERS.md section 7 said in its own last sentence: "the gate that reads this file has no way to tell a reviewed decision from an unexamined one." FieldSpec.zero_reading is a second axis, not more Basis members: Basis answers where a declared vocabulary came from, this answers what a zero is, and a field can be in any combination of the two. Four words -- measurement, undecidable, marker, unreviewed -- with unreviewed the default, because a field added tomorrow has not been reviewed. The readings are the ones section 7 already recorded, transcribed into the registry rather than invented. Every artifact and both pages now publish two numbers derived from the rows they describe: fields measured as numbers, and how many carry a reading, with the rest named. A field publishing a recorded zero while declaring unreviewed fails the build. artifact_schema_version 1 -> 2. Closes #83.
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.
Closes #83.
The defect
Five DINS fields are
FieldSpec(..., numeric=True)with no declared vocabulary, so each carriesBasis.NONEand publishesmarker_basis: "none". So does a field nobody has ever opened.docs/MARKERS.mdsection 7 named it in its own last sentence — "the gate that reads this file has no way to tell a reviewed decision from an unexamined one" — and the registry, the artifacts and both pages had no word for the difference.NOOFCARSONPROPERTYNOOUTBUILDINGSDAMAGEDNOOUTBUILDINGSNOTDAMAGEDNUMBEROFUNITPERSTRUCTUREASSESSEDIMPROVEDVALUEWhat this does
FieldSpec.zero_readingis a second axis, not moreBasismembers.Basisanswers where a declared vocabulary came from;ZeroReadinganswers what a zero is, and a field can be in any combination of the two. Four words, because a reader acts differently on each:0measurement0is a findingundecidablemarker0stands in for a value that was not recorded, so the zeros are counted as recorded-as-unknown and the field publishes none0to read; it is already counted as an absenceunreviewed0would be published as a value and might be an absenceThe readings are section 7's own, transcribed rather than invented. Three counts are
measurement, the two contested fields areundecidable— the third answer #83 asks for by name — andYEARBUILTismarker. Section 7 now states the word beside each row andtests/test_schema.pyholds document and registry to each other by an exact token, in both directions.UNREVIEWEDis the default, because a field added tomorrow has not been reviewed.Two numbers everywhere, derived at render time from the rows beside them.
recorded_zero_reviewin each artifact; the sentence above each field table ondins.htmlandperimeters.html; each field's own reading on its own row.Coverage, before and after
LATITUDE,LONGITUDEnamed as the rest; both publish no zero)GIS_ACRESpublishes no zeroSchema and consumers
artifact_schema_version1 → 2.recorded_zero_reviewis a new required top-level key andrecorded_zero_readinga new optional per-field one; a consumer validating against version 1 — whose schema closes withadditionalProperties: false— would reject the new artifact. The rule for a bump is stated insrc/perimeter/artifacts.pyand in the CHANGELOG so neither can be edited alone.site/is regenerated from the pinned 2026-08-07 retrieval, andmake site-checkreports it byte-identical to a fresh build fromdata/raw/(1182and81203leaves compared, none differing).Negative controls
Three sabotages, each with the occurrence count and
git hash-objectrecorded before and after, each restored to a byte-identical tree.ZeroReadingdefaults toMEASUREMENT, so an unexamined field's zeros publish as reviewedNOOFCARSONPROPERTY's ruling, so it publishes 55,831 zeros declaring nobody ruled on themtests/test_schema.pygreen8 of 8Two of the three controls found a gate that could not fail, and both are fixed in this PR.
The second passed because every gate on the zero question reads the committed artifact, and the only thing that rebuilds it —
make site-check— needsdata/raw/and cannot run in CI. So a ruling withdrawn inschema.pywould have shipped green.spine()intests/test_published_site_is_current.pyalready holdsmarker_basisbetween a fixture build and the committed copy; it now holdsrecorded_zero_readingbeside it. Re-run after the fix: fired,dins-coverage.jsonshape mismatch.The third passed because every gate on
recorded_zero_reviewrecomputes it from the same payload the block was written into — a summary checked against itself.zero_reviewnow has two tests that read its own answer over a field set whose two numbers are known to differ, one of them specifically that a field with no zeros today still counts as a question. Re-run after the fix: fired, 2 tests red.Verified
pytest1160 passed, 25 skipped (browser/jsdom gates skip withoutmake node-sync);ruff check,ruff format --check,mypy --strict srcall clean, each exit code captured off the bare command rather than through a pipe.make site-checkbyte-identical.Prepared with AI assistance; reviewed before submission.