What
A refresh of the pinned retrievals replaces site/data/perimeters-coverage.json and site/data/dins-coverage.json wholesale, and today the only thing that says what moved is git diff over a large JSON document. python -m perimeter.diff OLD.json NEW.json walks every leaf of both artifacts, reports each changed value with its path, old value and new value, reports keys added, and refuses to pass when a published key disappeared unless --allow-removals names that as deliberate. Output is console and --json; exit 0 no change, 1 changes reported, 2 removals not allowed or unreadable input. make site-check prints the diff when the served artifact and a fresh build disagree.
Why it matters
The README promises figures "move only when those retrievals are deliberately refreshed", and a deliberate refresh should be able to say what it moved. The sibling wildfire-service-territory-overlap built exactly this (artifact_diff.py) and used it to show a 4,370-value comparison with nothing removed; perimeter is its upstream and should hold itself to the same discipline. The command is offline, deterministic, and reads only the two files given. A field moving from a number to null (a domain the layer stopped publishing, per ADR-0010) is reported as a change to absence, not as a removal.
Scope
src/perimeter/diff.py and a make diff OLD=... NEW=... target; --allow-removals, --json, --ignore is_fixture for comparing a fixture build to itself.
- Leaf comparison with integer-exact equality;
tenths_pct fields compared as integers, never as floats.
- A comparison artifact (
{path, old, new} rows sorted by path) that PROVENANCE.md can cite for a refresh.
- Tests over artifacts that must fail it (a removed key, a changed count, a type change, an empty file), per ADR-0004.
Out of scope
- Diffing the pages; they are rendered from the artifacts.
- Automatic refreshes.
Done when
- Diffing an artifact against itself exits 0 and prints "no change".
- Removing
duplicate_signals from the new artifact exits 2 without --allow-removals and 1 with it, naming the key.
- A
records count change is reported with both values, and the JSON output is byte-identical on repeat.
make site-check on a deliberately altered site/data/ prints the leaf-level diff.
Pointers
src/perimeter/artifacts.py, cli.py, Makefile (site-check), PROVENANCE.md
wildfire-service-territory-overlap: src/wildfire_service_territory_overlap/artifact_diff.py, tests/test_artifact_diff.py
Proposed with AI assistance.
What
A refresh of the pinned retrievals replaces
site/data/perimeters-coverage.jsonandsite/data/dins-coverage.jsonwholesale, and today the only thing that says what moved isgit diffover a large JSON document.python -m perimeter.diff OLD.json NEW.jsonwalks every leaf of both artifacts, reports each changed value with its path, old value and new value, reports keys added, and refuses to pass when a published key disappeared unless--allow-removalsnames that as deliberate. Output is console and--json; exit0no change,1changes reported,2removals not allowed or unreadable input.make site-checkprints the diff when the served artifact and a fresh build disagree.Why it matters
The README promises figures "move only when those retrievals are deliberately refreshed", and a deliberate refresh should be able to say what it moved. The sibling
wildfire-service-territory-overlapbuilt exactly this (artifact_diff.py) and used it to show a 4,370-value comparison with nothing removed; perimeter is its upstream and should hold itself to the same discipline. The command is offline, deterministic, and reads only the two files given. A field moving from a number tonull(a domain the layer stopped publishing, per ADR-0010) is reported as a change to absence, not as a removal.Scope
src/perimeter/diff.pyand amake diff OLD=... NEW=...target;--allow-removals,--json,--ignore is_fixturefor comparing a fixture build to itself.tenths_pctfields compared as integers, never as floats.{path, old, new}rows sorted by path) thatPROVENANCE.mdcan cite for a refresh.Out of scope
Done when
duplicate_signalsfrom the new artifact exits 2 without--allow-removalsand 1 with it, naming the key.recordscount change is reported with both values, and the JSON output is byte-identical on repeat.make site-checkon a deliberately alteredsite/data/prints the leaf-level diff.Pointers
src/perimeter/artifacts.py,cli.py,Makefile(site-check),PROVENANCE.mdwildfire-service-territory-overlap:src/wildfire_service_territory_overlap/artifact_diff.py,tests/test_artifact_diff.pyProposed with AI assistance.