feat(ci): declare sibling visibility, and un-dark seven cross-repo checks - #229
Merged
Merged
Conversation
…ecks
A few tests here verify claims this repo makes about OTHER repos — chiefly that the
coordinate-registry edition we pinned is still the one that exists. They need the sibling
on disk, so they skipped in CI and ran only on a laptop.
Which siblings CI could fetch was decided in a COMMENT, and the comment said
views-appwrite was private. It went public on 2026-08-08 (views-appwrite@9d80b75, a
deliberate recorded act) and the comment did not, so seven checks stayed dark for two days
for no reason — including both registry-drift detectors, which had fired twice in one day
the week before. The first draft of ADR-016 proposed issuing a credential to reach them,
written one day after the fact justifying it stopped being true.
So the fact now lives in a declaration that carries the date it was checked:
Sibling(env=..., public=..., public_checked=..., ci_checkout=..., note=...)
`public` is a fact about the world; `ci_checkout` is our decision. Conflating them is what
went wrong. frozen + kw_only deliberately: two adjacent booleans are a one-token slip
between "public, not checked out" and the combination G3 forbids, and a plain dict would
let a missing key read as None and silently exempt a sibling from every rule.
CI now checks out views-appwrite and views-crafdapi, both with `ref: main` — without it
actions/checkout takes the sibling's own default branch, which for views-appwrite is
`development`, while two checks read the working tree and a third demands reachability
from main. Latent today; contradictory the first time a bump lands on development first.
tests/test_ci_sibling_coverage.py: eight rules, each a pure function of
(workflow, siblings) so each runs against a synthetic broken world as well as the real
file. G3 (public => no token) and G5 (no continue-on-error) look like fussiness and are
not: `public` is verified by CI DOING the tokenless checkout, and either key silently
turns it into an unchecked claim. A meta-test refuses a rule added to _RULES with no
mutant proving it bites.
Also fixed, found en route: broken_sibling_overrides treated a variable set to the EMPTY
STRING as unset — which is exactly what a YAML interpolation resolving to nothing
produces. Seven checks would skip on a green build. Path("") .exists() is True, so the
obvious fix makes it worse; the strip is load-bearing.
pyyaml declared and re-locked in the same commit. It already arrived transitively, which
is precisely how this repo lost pytest; a stale lock makes poetry install refuse and takes
the whole suite with it.
test_no_coordinate_value_is_copied_into_this_repo changes character rather than merely
un-skipping: the scan refusing registry VALUES in this public repo's markdown now runs on
every PR rather than only on a maintainer's machine. Its comment said the opposite.
ADR-016 rewritten around the public/private rule; the token guide deleted, since we are
not issuing a token. The credential for views-faoapi — the one private sibling, worth one
test — is deferred with a named trigger, pending a request to FAO to make it public.
C-46's explicit recommendation ("do NOT add sibling checkouts to the per-PR workflow")
is overridden and disposed of in the same change: its stated objection was coupling to a
default branch, which `ref: main` addresses; the residual cost, that an upstream merge to
main can block merges here, is accepted and stated rather than glossed.
Deciders swept across ADRs 000-015: the PRIO MD&D Team no longer exists.
Suite 404 passed / 40 xfailed; ruff clean; lock fresh.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
CI caught this on the first run, which is the point of the change it is part of: the guard could not fail locally, because locally there is only one clock. The dates were stamped from a maintainer's machine in CEST at 01:25 on 2026-08-10. The runner is UTC, where it was 23:25 on 2026-08-09. So a date recorded truthfully today read as tomorrow two hours away, and G8 called it a lie. "Today" is not something a bare ISO date determines — it depends on where the reader is — so comparing one against `date.today()` asks two different questions. A full day of tolerance covers every real offset, and a date more than a day ahead is still exactly what the rule is for: a fact nobody checked. Written down rather than fixed quietly, because the repair a hurried reader reaches for here is deleting the rule (ADR-014 §3). Added test_g8_tolerates_a_timezone_but_not_a_ fiction, pinning both sides of the boundary at 0/+1/+2/+400 days — a tolerance with no test becomes whatever made the last failure go away. Suite green under TZ=UTC too. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Read off the merge run rather than derived. 398 passed / 9 skipped / 38 xfailed; the 9 are 8 views-datafactory (needs published data, not a credential) and 1 views-faoapi. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.
Adds ADR-016. Partially mitigates C-81; resolves the CI residual on C-46 and C-57.
The failure this fixes had already happened
A few tests here verify claims this repo makes about other repos — chiefly that the coordinate-registry edition we pinned is still the one that exists. They need the sibling on disk, so they skipped in CI and ran only on a laptop.
Which siblings CI could fetch was decided in a comment, and the comment said views-appwrite was private. It went public on 2026-08-08 (
views-appwrite@9d80b75, a deliberate recorded act) and the comment did not — so seven checks stayed dark for two days for no reason, including both registry-drift detectors, which had fired twice in one day the week before.The first draft of ADR-016 proposed issuing a credential to reach those seven. It was written one day after the fact justifying it stopped being true. That is not a footnote to this change; it is the argument for it.
The fix: a declaration that carries its own date
publicis a fact about the world.ci_checkoutis our decision. Conflating them into one sentence of prose is exactly what went wrong.frozen=True, kw_only=Truedeliberately: two adjacent booleans are a one-token slip between "public, not checked out" and the combination rule G3 forbids, and a plain dict would let a missingci_checkoutread asNone— silently exempting that sibling from every rule, which is the failure mode this repo has registered more than any other.ref: mainis not a detailWithout it
actions/checkouttakes the sibling's own default branch — which for views-appwrite isdevelopment. Two checks read the working tree while a third demands reachability frommain. Latent today (both branches carry the same edition); contradictory the first time a bump lands ondevelopmentfirst. Retrofitted to the existing crafdapi step too, and made a rule rather than a habit.The guards
tests/test_ci_sibling_coverage.py— eight rules, each a pure function of(workflow, siblings), so each runs against a synthetic broken world as well as the real file. A rule demonstrable only by editing CI is one nobody ever watches fail.codeql.ymlis not invisiblecontinue-on-error_siblings/ref: mainpublic_checkedparses, and is not in the futureG3 and G5 look like fussiness and are not. No test here touches the network — that is a hard convention.
publicis verified by CI doing the tokenless checkout: the defaultGITHUB_TOKENis scoped to this repo, so fetching a repo declared public fails if it is actually private. Onetoken:added to dodge a rate limit, or onecontinue-on-error:added while debugging, and that verification silently stops existing.A meta-test refuses a rule added to
_RULESwith no mutant proving it bites — and it is itself mutation-proven.Found en route: an empty variable was a silent skip
broken_sibling_overridesfiltered onif value, soVIEWS_APPWRITE=""read as unset — which is exactly what a YAML interpolation resolving to nothing produces. Seven checks would skip on a green build, in the one place it matters.Path("").exists()isTrue, so dropping the truthiness test alone makes it worse; the.strip()is load-bearing.One test changes character rather than merely un-skipping
test_no_coordinate_value_is_copied_into_this_repo— the scan refusing registry values in this public repo's markdown — now runs on every PR rather than only on a maintainer's machine. README.md carried four such values once already. Its own comment said the opposite and has been corrected.What is deferred, and what is overridden
Deferred: the credential for views-faoapi, the one genuinely private sibling. It buys one test — admittedly the one whose failure produces no error anywhere — and a better answer is pending: asking FAO to consent to making that repo public. An audit of its full history found no credentials and no partner staff emails; it is already MIT. ADR-016 §8 carries the trigger for falling back to the credential.
Overridden, and disposed of in the same change (ADR-014 §5): C-46 recommended "do not add sibling checkouts to the per-PR workflow". Its stated objection was coupling to another repo's default branch — which
ref: mainaddresses. The residual cost is real and stated rather than glossed: a merge to a sibling'smaincan turn this repo red and block merges until someone re-pins. That is the drift detector working, and the trade is deliberate.Also
pyyamldeclared and re-locked in the same commit — it already arrived transitively, which is precisely how this repo lost pytest, and a stale lock makespoetry installrefuse and takes the whole suite with it. The lock diff is two lines.Decidersswept across ADRs 000–015: the PRIO MD&D Team no longer exists, and a decider field naming a body nobody can ask is worse than useless.Verification
Expected CI skips after this lands: 9 (8 views-datafactory, which no credential can fix — its tests need raw data absent from its git repo — plus 1 views-faoapi). I will read the real number off the CI run and correct the record if it differs, rather than deriving it.
🤖 Generated with Claude Code