Repository navigation
C-30/C-46: the exclusion-manifest tripwire now runs in CI — the 2026-08-03 revert was the right observation with the wrong cause - #280
Conversation
…C-46)
On 2026-08-17 this repository told FAO in writing that the 76-cell exclusion list
"is frozen in code and asserted against the producer in our test suite, so it
cannot drift without failing loudly". It could. The assertion —
`test_manifest_matches_datafactory_land_minus_land_gaul` — skipped on every pull
request, because views-datafactory was not fetched in CI. The guarantee was
running on one laptop.
The stated reason it was not fetched did not survive checking. C-46 and
`conftest.SIBLINGS` both recorded that a checkout "converts an honest skip into a
FileNotFoundError — measured 2026-08-03, tried and reverted". The observation was
right; the diagnosis was wrong. `test_gaul_lookup_fidelity` gated on
`data/raw/gaul_admin/` being a DIRECTORY, and that directory IS tracked in
views-datafactory — it holds `supplement_azores.geojson` — while the seven GAUL
parquets beside it are not. So a checkout satisfied the gate, the value
comparison ran, and it died. The sibling was never the obstacle; the gate asked
whether a folder existed when it needed to ask whether the files it reads existed.
Reproduced before changing anything, against a `git worktree --detach` of
views-datafactory@HEAD — exactly what `actions/checkout` produces:
before 1 failed, 37 passed, 1 skipped
FileNotFoundError: .../data/raw/gaul_admin/gaul0_code.parquet
after 35 passed, 4 skipped, 0 failed
What changed:
- `test_gaul_lookup_fidelity._HAS_DATAFACTORY` gates on the seven parquets it
actually reads, not on their directory. The PRIO-GRID check at the bottom of
the same file already had this shape, gating on `priogrid_cell.dbf` itself.
- its skip reason now says the parquets are absent and that they are untracked
upstream, instead of "checkout not found" — which was false in precisely the
case that broke CI.
- `run_pytest.yml` fetches views-datafactory at `ref: main`, and declares
`VIEWS_DATAFACTORY`; `conftest.SIBLINGS` flips to `ci_checkout=True` with the
corrected reason. `test_ci_sibling_coverage` requires those two to agree, and
does.
Two checks move from skipped to running in the gate: C-30's exclusion tripwire,
and C-46's own `TestReleaseGate::test_land_gaul_commit_is_in_a_release_tag` —
the gate that entry says had "never run anywhere but one laptop". The
producer-comparison half still skips, honestly, and still needs the parquets
published somewhere fetchable.
C-30 is NOT re-tiered: what holds it at Tier 1 is the absence of a real global
delivery exercising it end to end, and CI wiring does not supply that.
Suite: 428 passed, 5 skipped, 39 xfailed under a CI-shaped sibling. The 25
failures are the pre-existing local venv drift registered as C-104, unchanged by
this commit. ruff clean.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Findings from /review-diff on the previous commit. All four are the same defect that commit fixed, one level up: a gate asking about something other than what the test reads. `test_gaul_lookup_fidelity` had ONE sibling gate, keyed to the GAUL parquets, and applied it to four tests. Only one of them reads a parquet: test_lookup_values_match_the_producer_parquets 7 parquets (untracked) correct test_lookup_gid_set_equals_the_declared_region land_gaul_pgids.json — TRACKED test_coordinate_formula_matches_every_pg_cell priogrid_cell.dbf; self-skips test_coord_dtypes_are_wire_stable only the committed lookup So two checks that need nothing untracked, and one that needs no sibling at all, were dark in CI because they carried a mark for someone else's dependency. The last is the one worth naming: it asserts `abs(v) < 2**53` for every code column — that the §5.1 int64->float64 wire cast is lossless. That is precisely the property ADR-013 §5.1a records and the 2026-08-17 mail to FAO relies on, and it was skipped in the gate while resting on nothing but a committed fixture. Changes: - `_HAS_DATAFACTORY` -> `_HAS_GAUL_PARQUETS`, `_needs_datafactory` -> `_needs_gaul_parquets`. The old name asserted the conflation the bug was made of: a checkout can be present while these are absent, which is the normal case in CI. - new `_needs_region_pgids`, gating on the tracked pgid list, so the region-set check runs in CI. - the coordinate check loses the mark; its own `dbf.exists()` skip was already the right gate and is now the only one. - the dtype check loses the mark entirely; it is always-on. - the parquet comparison uses `_GAUL_ADMIN` instead of respelling the path, so the gate and the reader cannot drift apart — which is how this started. - module docstring rewritten: three gates, not two, with the rule stated. Measured. CI-shaped sibling (tracked files only): fidelity file goes 21 passed / 4 skipped -> 23 passed / 2 skipped, and both remaining skips name the artifact they want. Full suite CI-shaped: 430 passed / 3 skipped, up from 426 / 6 before this branch. With a full local sibling: 39 passed, nothing lost. ruff clean. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Four findings, all mine, all the same defect the branch set out to fix.
1. HIGH — I broke the no-checkout case. Removing the mark from
`test_coordinate_formula_matches_every_priogrid_cell` exposed that its
`dbf.exists()` skip sits BELOW `dbf = _DATAFACTORY / ...`, and `_DATAFACTORY`
is None when nothing resolves. Measured: `TypeError: unsupported operand
type(s) for /: 'NoneType' and 'str'` — a red suite for any contributor
without a views-datafactory checkout. CI never saw it, because CI now always
has one. Fixed with a declared `_needs_priogrid_dbf` gate, like its
neighbours.
2. MEDIUM — two `xfail(strict=True)` deploy gates began EXECUTING in CI once the
sibling was fetched, and xfailed on missing files rather than on what they
assert. `data/assembled/{grid.npy,provenance.json}` are untracked upstream —
and measured today, `data/assembled/` is empty in the maintainer's own
checkout too, so these gates have never evaluated their assertions ANYWHERE.
A strict xfail that can only fail on FileNotFoundError can never XPASS, so
the flip that is the whole mechanism could not fire. They now skip when the
inputs are absent, which makes the state visible instead of disguising it as
a passing xfail. Registered as C-108; skipping does not make the gate work.
3. LOW/MED — the newly-live C-30 tripwire gated on `land_pgids.json` while
reading `land_gaul_pgids.json` too. Now that it runs in CI against
views-datafactory@main, a rename upstream would have surfaced as a traceback
instead of the drift assertion it exists to produce. Gate names both files.
The stale `(CI has no sibling → skip)` comment is corrected — it was the last
line in the repo still asserting the old state.
4. LOW — `test_the_builder_and_the_tests_resolve_the_same_datafactory` guards
the fallback under `if "VIEWS_DATAFACTORY" not in os.environ`, with a comment
saying that branch matters most in CI. Setting the variable in CI silenced
exactly that branch and left the surviving assertion comparing
$VIEWS_DATAFACTORY with itself. Now asserted unconditionally via
`monkeypatch.delenv`.
Also corrected two overclaims of my own: the workflow comment said the sibling
was fetched "for ONE check" and the register said "two", when four began
executing.
Measured. CI-shaped sibling: 430 passed / 5 skipped / 37 xfailed (two former
xfails are now honest skips). No sibling resolvable: no TypeError, 8 clean
skips. Full local sibling: nothing lost. ruff clean.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Review round —
|
| test | reads | was gated on |
|---|---|---|
test_lookup_values_match_the_producer_parquets |
7 parquets (untracked) | parquets — correct |
test_lookup_gid_set_equals_the_declared_region |
land_gaul_pgids.json — tracked |
parquets |
test_coordinate_formula_matches_every_priogrid_cell |
priogrid_cell.dbf |
parquets |
test_coord_dtypes_are_wire_stable |
only the committed lookup | parquets |
The last is worth naming: it asserts abs(v) < 2**53 for every code column — that the §5.1 int64→float64 wire cast is lossless, the property ADR-013 §5.1a and the 2026-08-17 mail to FAO both rest on — and it was dark in CI while depending on nothing but a committed fixture.
Also fixed: _HAS_DATAFACTORY → _HAS_GAUL_PARQUETS (the old name asserted the very conflation the bug was made of), and the parquet path is no longer respelled between the gate and the reader.
/code-review high — 4 findings, all fixed in 58ac58d
- HIGH, and mine. Removing a mark exposed that
test_coordinate_formula_matches_every_priogrid_cellbuildsdbf = _DATAFACTORY / ...above its.exists()check. With no checkout,_DATAFACTORYisNone→TypeError. CI never sees this, because CI now always has the sibling — it lands purely on contributors. Fixed with a declared_needs_priogrid_dbfgate. - MEDIUM. Two
xfail(strict=True)deploy gates started executing once the sibling was fetched, and xfailed on missing untracked files rather than on what they assert. Measured further:data/assembled/is empty in the maintainer's own checkout too — these gates have never evaluated their assertions anywhere, and a strict xfail that can only fail onFileNotFoundErrorcan never XPASS, so the flip that is the entire mechanism could not fire. Now skip when inputs are absent. Registered as C-108; skipping makes the state honest, it does not make the gate work. - LOW/MED. The newly-live C-30 tripwire gated on
land_pgids.jsonwhile readingland_gaul_pgids.jsontoo — upstream rename would surface as a traceback rather than the drift assertion. Gate names both. - LOW.
test_the_builder_and_the_tests_resolve_the_same_datafactoryguards the fallback underif "VIEWS_DATAFACTORY" not in os.environ, with a comment saying that branch matters most in CI — and this PR set that variable in CI, silencing it. Now unconditional viamonkeypatch.delenv.
Two overclaims of my own, corrected
The workflow comment said the sibling was fetched "for ONE check"; the register said "two". Four began executing.
Verification
| environment | result |
|---|---|
| CI (real) | 455 passed, 5 skipped, 37 xfailed, 0 failed |
| local, CI-shaped sibling | 430 passed, 5 skipped, 37 xfailed |
| local, no sibling resolvable | no TypeError, 8 clean skips |
| local, full sibling | nothing lost |
ruff check . clean. The 25 local failures throughout are the venv drift registered as C-104 — they pass in CI, which is the evidence the diagnosis was right.
Why now
On 2026-08-17 we told FAO, in writing, that the 76-cell exclusion list "is frozen in code and asserted against the producer in our test suite, so it cannot drift without failing loudly."
It could.
test_manifest_matches_datafactory_land_minus_land_gaul— C-30's drift tripwire — skipped on every pull request, because views-datafactory was not fetched in CI. The guarantee we gave a partner was running on one laptop.The blocker was misdiagnosed, and that is the interesting part
C-46 and
conftest.SIBLINGSboth recorded the same reason for not fetching it:The observation was correct. The cause was not.
test_gaul_lookup_fidelitygated ondata/raw/gaul_admin/being a directory — and that directory is tracked in views-datafactory (it holdssupplement_azores.geojson), while the seven GAUL parquets beside it are not. A checkout therefore satisfied the gate, the value comparison ran, and it died on a missing parquet.The sibling was never the obstacle. The gate was asking whether a folder existed when it needed to ask whether the files it reads existed. The PRIO-GRID check at the bottom of the same file already had it right, gating on
priogrid_cell.dbfitself.Reproduced before changing anything
Against
git worktree add --detachof views-datafactory@HEAD — which contains exactly whatactions/checkoutproduces:1 failed, 37 passed, 1 skipped—FileNotFoundError: .../gaul_admin/gaul0_code.parquet35 passed, 4 skipped, 0 failedWhat changed
tests/test_gaul_lookup_fidelity.py—_HAS_DATAFACTORYgates on the seven parquets it reads rather than on their directory; the skip reason now states that the parquets are absent and untracked upstream, instead of "checkout not found", which was false in exactly the case that broke CI..github/workflows/run_pytest.yml— fetches views-datafactory atref: main, declaresVIEWS_DATAFACTORY.tests/conftest.py—ci_checkout=Truewith the corrected reason.test_ci_sibling_coveragerequires the workflow and the declaration to agree; it passes (22 tests).What this buys
Two checks move from skipped to running in the gate:
src/datafactory_query/{land,land_gaul}_pgids.json, both tracked upstream.TestReleaseGate::test_land_gaul_commit_is_in_a_release_tag— the gate that entry says had "never run anywhere but one laptop."The producer-comparison half still skips, honestly. Closing that needs the parquets published somewhere fetchable, which is not an access grant and not this PR.
What this does not do
C-30 is not re-tiered. What holds it at Tier 1 is the absence of a real global delivery exercising the guard end to end. CI wiring does not supply that, and saying otherwise would be the kind of claim this repo keeps a register to prevent.
Risk accepted
A merge to views-datafactory's
maincan now turn this repository red. That is ADR-016's deliberate trade, already accepted for views-appwrite and argued in C-46: it is the drift detector working, and the alternative is the state we were in — noticing drift only when someone happened to run the suite locally.Verification
ruff check .— clean.test_ci_sibling_coverage— 22 passed.