test(registry): match on the rows we read, not the edition label — and #238 D3+D4 - #239
Merged
Merged
Conversation
Three things, the last found by falsifying the ADRs against the architecture rules rather than against themselves. THE PICTURE. Neither ADR contained one, and neither had a table saying which repository does what — you had to assemble that from prose that said "this repository" throughout. The maintainer read both and was lost three times; that was data about the documents. ADR-017 §5 gains a three-party diagram and a role table. The diagram's point is the arrow that is not there: both sides point at the registry, neither points at the other. The table's "needs access to" column is what shows why no credential is required. ADR-016 §4 gains the role table. Its diagram was drafted, rendered badly, and was DELETED rather than fixed — it duplicated the table beside it, and the table is better. For that document the table was the picture. RENDERING, kept out of the source. Fenced blocks split across pages in PDF. Fixed with a pandoc Lua filter that makes each block an unbreakable minipage, living beside the PDFs rather than as raw LaTeX in the markdown — the markdown is the artifact, the PDF a view. The ADR-017 diagram was also rebuilt with its columns computed rather than eyeballed, so the arrows sit over the boxes they rise from. WHERE DECLARATIONS BELONG — new C-88, and the one substantive finding. tests/conftest.py is pytest's fixture file and now holds four unrelated groups: the package taxonomy, the sibling repositories, the consumer mapping, and two git helpers. None is a fixture. ADR-016 §4 asserted "the list of siblings is code, not a comment" and named that file without ever asking whether it was the right home — which is exactly the question the repository's own architecture rules are about. The cost is already paid, not hypothetical: scripts/build_gaul_lookup.py needs the same sibling-location fact and cannot import it, because a script importing from tests/ is the dependency direction backwards. So it declares "VIEWS_DATAFACTORY" a second time. That duplication is defended on WET grounds and the defence is sound — but it was not a free choice, and a structural constraint and a design decision reached the same answer with only one of them examined. §4 now says where the declaration lives, what that costs, and the trigger for moving it. Not fixed here: moving it touches a dozen imports for no immediate gain, and the second incident is what tells you the right shape. Probes that found nothing: hedging language (three hits, all legitimate prose); OCP — adding a sibling is data plus a workflow block, no rule changes; ISP — the record is down to three fields and its two audiences are coherent. Register 87/14/73 -> 88/15/73. Pre-existing on development and NOT from this branch: three failures — two stale registry pins and the consumer-name check, which broke when views-faoapi tidied the file it reads. That is #238's work and is awaiting the maintainer's discussion. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…d not have known Falsified the TESTS against "readable by someone unfamiliar with the decision" — a different lens from the previous passes, which checked the documents against themselves. Four findings, all real, two of them contradictions with things written days earlier. THE NUMBERING GAP WAS FIXED IN THE ADR AND LEFT IN THE CODE. test_ci_sibling_coverage runs G1, G2, G4, G5, G6, G7. ADR-016 now explains why two numbers are missing; the test file did not, and the test file is what someone opens when a build goes red. It says so now: G3 and G8 were removed as circular, survivors keep their names, the gap is deliberate. INVERTED FAILURE SEMANTICS, UNSIGNPOSTED — the sharpest of the four. Half this file fails when the workflow is wrong; the other half fails when the RULE is wrong, because those tests feed a deliberately broken world to a rule and demand it complain. Nothing said so. A maintainer seeing "[G6] did not object to: outside _siblings/" would go and stare at run_pytest.yml, which is fine. The module docstring now names the inversion, the assertion says "Fix the rule, not run_pytest.yml", and test_each_rule_bites_on_a_broken_world has its docstring back — it lost one in the refactor that moved _MUTANTS out. Mutation-proven: breaking G6 produces that message. "TWO FIELDS" OVER A THREE-FIELD RECORD. Sibling's docstring counted ci_checkout and note and forgot env, the field two other modules actually use. CONFTEST'S FIRST LINE SAID IT HOLDS ONE THING; C-88 SAYS FOUR. Registered that yesterday and left the docstring claiming "Shared test fixtures — currently just one". It now opens by listing the four groups, defines "sibling" where a newcomer first meets the word, and points at C-88 rather than defending the arrangement. Its second line also opened with four private identifiers (S6 / #187 / C-46 / C-57) — the same thing the maintainer objected to in the ADRs, in the file a newcomer opens first. Not registered, consistently with the previous three passes: each is a defect fixed in the same change, and the only candidate trigger — "whenever a test is edited" — is perpetual, which the register's own quality gate rejects. Say so if you want them tracked anyway. Pre-existing and NOT from this change: three failures on development — two stale registry pins and the consumer-name check, which broke when views-faoapi tidied the file it reads. That is #238, awaiting discussion. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The registry check compared version strings, so it fired on every upstream edition —
five in four days, four of them recording console observations that carried no
obligation here (C-86). Two of those failures were red on development.
The diagnosis is ADR-014 §3: when a guard fires on something legitimate, ask whether the
MATCHING is wrong before narrowing the scope. It matched on meta.version, a label meaning
"anything at all changed". What this package depends on is a set of rows.
Two earlier proposals of mine were wrong, and the reasons are in the ADR erratum. The
second — read everything at the pinned commit — would have frozen both sides of every
comparison, so upstream could rename every coordinate and the suite would stay green.
ADR-016 §7b already adjudicated that fork, in a document I wrote days ago.
Three checks replace one:
the pinned commit declares the pinned version. Both sides frozen, so upstream can never
redden it. This closes a hole that was live: "Do not bump one alone — the pair is the
claim" existed only inside an error-message string, and nothing compared the two.
fcf32c9 does declare 1.4.4 — true by luck.
every top-level table upstream is classified here. _declared_classes parses three and
was silently ignoring four. `[contract.*]` arrived in v1.5.0 carrying a live obligation
and the ONLY thing that noticed was the noisy version check. Directional on purpose: a
new table fails, a vanished IGNORED table does not.
no row we declare differs between the pinned edition and the current one. Catches
ROTATION, which no other check here can see — a rotated bucket id keeps its name and
its class, so names-and-classes passes while every delivery goes elsewhere. The no-copy
rule forbids keeping expected values in our source, so the pinned edition is the only
lawful baseline for that comparison.
The reader is deliberately NOT built on conftest.git_output, which turns any failure into
"" — and tomllib.loads("") is {}, so an unreadable pin would produce an empty baseline
compared against an empty projection, passing forever. That is the shape ADR-014 §2 is
about, and building it into a drift detector's own fix would be the joke writing itself.
It distinguishes a non-zero exit from an empty file and refuses a parse lacking anchors.
Module-local, not conftest: C-88's trigger is a fifth declaration there and this has one
consumer.
Seven mutations proven, three of them now permanent tests that need no sibling: a bogus
sha must raise rather than return {}; a new table must fire while a vanished IGNORED one
must not; a rotation must fire where names-and-classes cannot.
ADR-016 gains an erratum. §7a's "not adopted here — needs the upstream side first" was
wrong: fixing the matching removes the false alarms without upstream doing anything.
§7b's two categories become three — a differential tripwire reads a pinned baseline AND
current, and only that shape can see a rotation.
C-86 amended with the measured rate change and explicitly NOT closed: the coupling, the
checkout and the zero bypass actors are untouched. Its trigger is still a console action.
Suite 401 passed / 1 skipped / 40 xfailed. The one remaining failure is the faoapi
source-read, which is Change 2 (#238 D4).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…t the consumer D3. The consumer-name check now reads the public coordinate registry instead of the consumer's source, for BOTH partners. No credential, and the private partner is reachable for the first time — that is ADR-017 §5 in one assertion. The check it replaces broke on 2026-08-11, and how it broke is the argument: views-faoapi tidied managers/api.py into a named constant, so our regex went looking for an APIPathManager(...) construction that had moved. Their code got better and our check went red. ADR-017 §7 — we were never entitled to depend on another repository's file layout. D4 is PER PARTNER, and I got this wrong once before catching it. My first pass deleted the source-read for both, which violates ADR-017 §5's own sequencing constraint: a partner's source-read goes only when THAT partner's consumer-side check exists. Otherwise the registry row is a string a human typed and a green build proves only that two values this platform authored agree. views-faoapi#379 merged 2026-08-11 -> the FAO source-read is gone views-crafdapi#53 open -> the crafd source-read stays The survivor is scoped by a declared, deliberately SHRINKING map (_CONSUMER_SELF_CHECK_PENDING) naming the issue that retires each entry, and its docstring says plainly that the test is meant to be deleted. The crafd sibling fetch lives or dies with it, which conftest's note already records. BOTH PARTNERS, correcting #238. That issue says CRAF'd's label "is not a decided value" and defers it. views-appwrite declared both rows in v1.5.0 and the CRAF'd row corrects this itself: "Both sides already use this value in code today — this row DECLARES a standing fact, it does not decide a new one", citing both sides' source. ADR-017 Appendix B updated. ADR-017 Appendix B also carried a contradiction, fixed before scoping rather than discovered mid-PR: step 2 said "in the same change, stop fetching views-crafdapi", while §5 forbids retiring that partner's check until #53 lands — and that fetch's sole consumer IS that check. The two could not both be followed. The no-copy scan is now scoped BY THE PARTITION rather than an inline tuple, so `contract` cannot be swept in by a one-word edit. It must not be: ADR-017 §5 REQUIRES those values in our source, so banning them would forbid what the contract obliges. Not an exception to "never copy a coordinate" — a different class, declared upstream, whose values no reader ever emits into a process environment. Proven: reclassifying contract as CONSUMED reddens on our own product.py, so the widening cannot be quiet. Suite 409 passed / 1 skipped / 40 xfailed — green for the first time in this arc. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Requested by the views-appwrite seat on #238. Their three facts all check out: b703cab declares 1.5.2, it is reachable from their main, and it is the tag appwrite-seam-v1.5.2. ONE CORRECTION TO THEIR PREMISE. The issue is titled "we are breaking your build" and names test_the_pinned_contract_edition_still_matches_the_registry. That test no longer exists — the preceding commit deleted it, because comparing version STRINGS is what made three observation-only editions look like three obligations. So nothing was broken and no push was going to break. Worth telling them, since they filed it as an outage they had caused. Their advice survives the correction, and is the better half of the message: "actually read the diff rather than just moving the number." Done, both ways. By hand — git diff appwrite-seam-v1.4.4..v1.5.2 on the registry is, in full: + [contract.UNFAO_CONSUMER_DOCUMENT_NAME] value = "un_fao" + [contract.UNCRAFD_CONSUMER_DOCUMENT_NAME] value = "un_crafd" - [unmodelled.session_auth_email_password] ... and prose Every element is already handled by the checks that replaced the string comparison: the two contract rows are classified MIRRORED and asserted in test_product; the unmodelled removal is the IGNORED direction that is deliberately silent; and nothing in connection, target or secret moved. Mechanically — test_nothing_this_repo_reads_has_changed_since_the_pin was green across the whole 1.4.4 -> 1.5.2 window before this commit. That is the re-verification the ratchet asks for, done by a check rather than by a promise, and it is what makes moving the baseline safe rather than merely tidy. Note what re-pinning costs: the differential now spans nothing until upstream moves again. That is correct — a baseline that has been verified moves forward — but it means the evidence for this window lives in this message rather than in a test from here on. Docstring version and the pinned blob URL moved with the constants; the pin-pair check confirms b703cab declares 1.5.2 rather than taking it on trust. Suite 409 passed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ed-and-dead The design had been reviewed before implementation and the ADRs falsified four times. The ~470 lines of test code had been reviewed by nobody. Fifteen findings; most were mutation-proven by the reviewer against my own code. THE ONE THAT WAS ALREADY LIVE. SEAM_CONTRACT_COMMIT = "b703cab" is an annotated TAG OBJECT, not a commit. git cat-file -t says `tag`; it peels to c7b597e. So the pinned blob URL both PUBLIC partner modules publish returned HTTP 404 — verified over the network — three lines above the sentence "A pinned URL does not rot." Every test passed because git peels tags silently in show, merge-base and cat-file alike. Pinned c7b597e. SECURITY. The drift check's failure message interpolated projection tuples, which carry coordinate VALUES, into a PUBLIC repository's world-readable CI log — on the one event the check exists to fire on. Values are now digested (sha256 prefix); names and fields are reported in the clear. BOTH "PERMANENT PROOFS" WERE TAUTOLOGIES. They re-typed the production expressions instead of calling them. Proven: replacing the real predicates with `return []` left the table proof green; making the drift comparison ignore `value` — literally the thing the rotation proof exists to disprove — left that one green too. So the guards this PR sells as mutation-proven had no detector at all. Predicates extracted; both proofs now call production code; both re-proven by breaking the real thing. _TABLE_ROLE WAS DECORATIVE. Two of its three consumers kept hardcoded copies of the section tuple, so classifying a table CONSUMED satisfied the guard demanding it and added zero coverage — C-74's shape arriving through a guard's own remediation advice. One _rows() reader now drives all three. Role strings are a closed vocabulary, because a typo silently narrowed the security scan from twelve values to two. THE DELETED CHECK'S REAL JOB WAS NOT FULLY REPLACED. A new upstream row in a table we read was invisible, and nothing forced a re-pin: restoring the pin to 1.4.4 against the current registry passed everything. Added: coordinates ARRIVING in a table we read now fail with "decide whether this package must adopt them" — the half worth keeping, since `[contract.*]` arrived exactly that way. "MAIN" WAS THE WORKING TREE. The differential compared against whatever branch the sibling clone sat on — #196's shape, grading this repo against unreviewed content. Reads origin/main now, which is what the ADR already claimed. Also: an unvalidated ref meant a blanked or branch-valued pin compared the registry to itself and passed forever; three exception types escaped a reader whose whole job is failing legibly; the reader's proof exercised one branch for the wrong reason (five branches now, against a purpose-built scratch repo); an emptied _CONSUMER_SELF_CHECK_ PENDING silently SKIPPED rather than prompting deletion. Nine prose claims corrected, including three repetitions of an [unmodelled] worked example that was simply wrong — it was never in the partition, so it would have been a red build, not the silent pass it was cited as. And an ADR table asserting machine enforcement that does not exist, in the document whose thesis is that unbacked claims go wrong unnoticed. Suite 410 passed / 1 skipped / 40 xfailed; ruff clean. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…e more Step 4 of the loop, aimed at the remediation commit itself, because fixing fifteen things at once is when the next one gets introduced. It did. THE BYPASS REOPENED THE HOLE IT WAS ADDED BESIDE. The frozen-commit guard existed because a pin set to "" reads the git index and a pin set to "main" reads a moving tip — either makes the differential compare the registry to itself and pass forever. Then I exempted "main"/"origin/main" from that guard so _registry_current could call _registry_at, which meant a pin literally set to "main" was accepted. Verified before and after. _registry_current now resolves the branch to a SHA first, so the guard has no exceptions. I FIXED THE WORKING-TREE PROBLEM IN ONE PLACE OUT OF FOUR. The differential moved onto origin/main; the names-and-classes check, the table partition and the no-copy scan were all still reading whatever branch the sibling clone happened to sit on — which is #196's shape, the case that cost this platform a withdrawn PR. All four read origin/main now, and _load_registry, which read the working tree, is deleted rather than left as a loaded gun. Four registry readers become three. A REAL DIAGNOSIS WAS SWALLOWED. _registry_current caught _RegistryReadError per ref and then raised its own, so an anchorless or corrupt registry ON MAIN was reported as "neither origin/main nor main resolves" — a message pointing at the wrong problem. Read errors now propagate; only genuine ref-resolution failure produces that text. AND THE PROSE WAS ONE FIX AHEAD OF THE CODE. ADR-016 §7b's erratum said differential tripwires read the sibling's main. That was true of one check and false of three at the moment I wrote it. Corrected, and the correction records its own overclaim, because a sentence written to describe a fix that outran the fix is the same defect §3 diagnoses. Also caught in passing: my first attempt at deleting the dead reader cut from its `def` to the next `def`, swallowing the _TABLE_ROLE block. The suite caught it; the file was restored and the removal redone against the function's own bounds. Suite 410 passed / 1 skipped / 40 xfailed; ruff clean. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…e shared reader
Loop iteration 2. Five findings plus one of mine, and the first is the serious one.
THE NO-COPY SCAN WAS BLIND IN THE STYLE OF THE DOCUMENT IT WAS WRITTEN FOR. Proven by
injection: real registry values written into README.md as `NAME=value # comment` passed
the guard, because `(.+?)\s*$` swallowed the comment into the captured value and
.strip('"\'') could not recover it. README's own Configuration block is written in exactly
that form. On a PUBLIC repository that is the guard's whole purpose defeated by its own
house style. Now: quoted values matched whole (a `#` inside quotes is legitimate),
unquoted values truncated at a comment. The `len > 6` floor is gone too — it excluded two
five-character coordinates and, measured, removing it keeps the suite green, so it was
narrowing a security check for nothing.
THE FOUNDING INCIDENT REAPPEARED IN THE FOUNDING FILE. run_pytest.yml still said a
tokenless checkout "is what verifies the `public` field — no test does". `public` was
deleted on 2026-08-10 because nothing could verify it, and ADR-016 §4 — added by THIS
branch — says so explicitly. A comment in that file asserting an unverifiable fact about
another repository is ADR-016 §3's founding incident, recurring in the file it happened in.
C-87 WATCHED THE WRONG ISSUE. Its trigger, body and cross-refs still named
views-crafdapi#39 while everything else moved to #53. Closing #39 would have fired it
spuriously; #53 landing would not have cleared it.
Mine, found while checking their claims: test_product.py was still reading the sibling's
WORKING TREE. I moved four checks onto origin/main last iteration and left the fifth — the
same partial-fix pattern review-diff had just caught. That is the second copy of the same
rule disagreeing with itself, which is this repo's stated trigger for extracting, so the
reader now lives in tests/seam_registry.py: one module, named for what it does, out of
conftest (C-88), with every refusal branch and the reason each exists.
Also: the mutant assertion hardcoded "views-appwrite" under a docstring framing it
generically — correct only by coincidence of today's fixtures; and two register blocks
were appended straight after a `Cross-refs:` line, rendering as run-on paragraphs below
the line every other entry treats as terminal.
AND THE PARTITION EARNED ITS KEEP ON LIVE DATA. Mid-fix it went red: views-appwrite had
added an `[edition]` table at v1.6.0 — which is views-appwrite#76 delivered, each edition
marked `obliges_consumers = true|false`. Exactly the mechanism ADR-016 §7a described and
I filed for. The guard caught its arrival unprompted, on its first real encounter, and the
row-level drift check stayed correctly silent because nothing we read moved. Classified
IGNORED for now; adopting it is recorded as the follow-up, not folded into a remediation.
Suite 410 passed / 1 skipped / 40 xfailed; ruff clean.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… and #76 landed Five findings from /review-diff on iteration 2. Two are worth reading. THE NO-COPY SCAN WAS BLIND IN THE HOUSE STYLE AGAIN, IN A DIFFERENT WAY. Iteration 2 fixed `NAME=value # comment`. The pattern still anchored the coordinate name at `^\s*`, so it saw only an assignment that STARTS A LINE. Proven by injecting three real registry values into README.md — a markdown bullet, a table cell, and an assignment quoted mid-sentence — all three invisible, all three now caught. Thirteen forms proven caught, four legitimate mentions proven silent. The shared cause of both blindnesses is not a regex bug: the pattern described one way of writing markdown, the way this repository happens to write it today. A guard against publishing a coordinate value from a PUBLIC repository has to survive the next contributor writing a bullet instead of a fenced block. C-57 amended with both, and with the residual that stays deliberate — a value merely NAMED in a sentence is not a copy, and an earlier draft that matched those fired on a dozen documents (ADR-014 §3). VIEWS-APPWRITE#76 HAS LANDED AND TWO RECORDS SAID IT WAS "FILED". Registry v1.6.0 ships `[edition."x.y.z"].obliges_consumers` — C-86's stated first-preference resolution. C-86 still called it filed; ADR-016 §7b still called it "still worth doing"; the code comment added in the previous commit already called it delivered. Three artifacts in one branch, two of them behind. Both records amended, and the re-pin deferral that lived only in a pull-request description now has a written trigger and an owner — both halves of that trigger have already fired (ADR-014 §4). THE MUTANT OFFENDER INFERRED WHAT IT SHOULD DECLARE. `next(iter(siblings), None) or "views-appwrite"` reads as principled and is wrong for G2, whose premise is an EMPTY declaration: there is nothing to derive from, so it fell back to the hardcoded name while its own message claimed it had not. Each mutant now declares the offender its rule must name (ADR-003), proven load-bearing by feeding one a wrong name. Also: `_ABSENT`'s doc-comment survived `_ABSENT` — the block moved to seam_registry.py and left its `#:` lines attached to `_TABLE_ROLE`, so the partition was documented as a sentinel for a valueless row. And the no-copy scan was the last of seven readers still hand-rolling its skip instead of calling `require_sibling`, whose whole justification is that the hand-rolled message tells a contributor too little to run the test. Suite 410 passed / 1 skipped / 40 xfailed; ruff clean. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This was referenced Aug 12, 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.
Closes #238. Amends C-86 (does not close it). Four commits — the two ADR/readability ones were already reviewed with you and never merged, so they ride along.
developmentis green again. It has been red on three failures; all three are gone.The diagnosis changed twice, and both corrections matter
I first proposed replacing the version comparison with a value comparison. That deletes the catch-all the guard's own docstring calls its purpose.
I then proposed reading everything at the pinned commit, on SDP grounds. An expert review killed it: both sides of every comparison would be frozen, so upstream could rename every coordinate and the suite would stay green — "a test reading a copy compares a thing to itself". ADR-016 §7b already adjudicates that fork, in a document I wrote days ago. SDP is about which module imports which, not which git ref a monitor reads.
The real diagnosis is ADR-014 §3: when a guard fires on something legitimate, ask whether the matching is wrong before narrowing the scope. It matched on
meta.version— a label meaning "anything at all changed". What we depend on is a set of rows.Change 1 — three checks replace one
pinned version string == current version stringTwo holes this closes that neither of us had seen:
The pin was internally unchecked. "Do not bump one alone — the pair is the claim" existed only inside an error-message string. Nothing compared the version to the commit. Verified:
fcf32c9does declare1.4.4— true by luck. Bumping either alone passed everything._declared_classesparses three tables and was silently ignoring four.[contract.*]arrived in v1.5.0 carrying a live obligation for us, and the only mechanism here that noticed was the noisy version check. On 2026-08-10 it fired correctly — which is why this replaces it rather than deleting it.Rotation is now detectable at all. A rotated bucket id keeps its name and its class, so names-and-classes passes while every delivery goes elsewhere. The no-copy rule forbids keeping expected values in our source, so the pinned edition is the only lawful baseline for that comparison. That is the pin earning its keep.
The reader is deliberately not built on
conftest.git_output. That helper turns any failure into"", andtomllib.loads("")is{}— an unreadable pin would give an empty baseline compared against an empty projection, passing forever. That is the shape ADR-014 §2 exists for; building it into a drift detector's own fix would be the joke writing itself.Measured: across v1.4.4 → v1.5.2 (three editions, one week) the new checks are green, because none of those editions touched a row we read. Under the old check every one was a red build blocking a release.
Change 2 — #238 (D3 + D4)
D3 — the consumer-name check reads the registry, for both partners. No credential, and the private partner is reachable for the first time.
The check it replaces broke on 2026-08-11, and how is the argument: views-faoapi tidied
managers/api.pyinto a named constant, so our regex went looking for a construction that had moved. Their code got better and our check went red. ADR-017 §7 — we were never entitled to depend on another repository's file layout.D4 is per partner, and I got it wrong once before catching it. My first pass deleted the source-read for both, violating ADR-017 §5's own sequencing constraint. Corrected:
The survivor is scoped by a declared, deliberately shrinking map naming the issue that retires each entry, and its docstring says plainly that the test is meant to be deleted.
Both partners, correcting #238. That issue says CRAF'd's label "is not a decided value". views-appwrite declared both rows in v1.5.0 and the CRAF'd row corrects it itself: "Both sides already use this value in code today — this row DECLARES a standing fact."
An ADR-017 contradiction, fixed before scoping rather than mid-PR. Appendix B step 2 said "in the same change, stop fetching views-crafdapi", while §5 forbids retiring that partner's check until #53 lands — and that fetch's sole consumer is that check.
The no-copy scan is now scoped by the partition, not an inline tuple, so
contractcannot be swept in by a one-word edit. It must not be: ADR-017 §5 requires those values in our source. Proven — reclassifyingcontractas CONSUMED reddens on our ownproduct.py, so widening cannot be quiet.Mutation proofs
Seven run, three made permanent (they need no sibling, so they run everywhere):
{}contractas CONSUMEDWhat is deliberately not built
No advisory tier.
pytest.skipwould encode "I looked and found something" as "I did not look" — false in the one place this repo reads for vacuity, and it would worsen the skip count C-81 tracks. A scheduled issue-opening job is the only honest form, and ADR-014 §4's named trigger for it has not fired. Residual with a trigger: re-pin when a check fires, or when views-appwrite#76 lands.No re-pin to 1.5.2. Once the differential exists, re-pinning is hygiene with no safety consequence.
No tag pin. The tag convention has already broken once (
platform-001-v1.2.0→appwrite-seam-v1.3.0), tags are movable, and the sha is already the pin of record.C-86 is amended, not closed. The coupling, the checkout and the zero bypass actors are untouched; only the false-alarm rate moved. Its trigger is still a console action.
Verification
🤖 Generated with Claude Code