You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Decision 8: census.json becomes derived (CI computes, guard refuses PR diffs); lint-baseline counts become a base-vs-head never-down check #3569
So roughly a quarter of all merged PRs rewrite one of these files, and in lint-baseline.json the churn is almost entirely counts. armed_shapes is the only key observed that is a decision — which is the one the ruling keeps committed.
Step 2 — what lands
contracts/census.json becomes derived.
PRs stop committing it; CI computes it and gates on its invariants, not its bytes.
A guard refuses any PR whose diff touches it.
The train is its single writer, at T-0.
contracts/lint-baseline.json keeps only decisions.
The monotone counts leave the file and become a base-versus-head never-down check — computed, compared, never stored.
Keys like armed_shapes stay committed, because arming a shape is a decision a human makes and a reviewer must see in a diff.
Interim, until the above lands
A path guard labels any PR touching either file touches-shared-contracts, and those PRs merge in a queue group of one, behind slice M. Label created.
Acceptance
A PR that edits contracts/census.json is refused by the guard, with the reason naming the file. Falsifier: plant such a diff and require RED.
With census.json absent from a PR, CI computes it and its invariant check passes; corrupt one invariant and the check goes RED.
The never-down check fails when a count regresses base→head, and passes when it rises or holds. Both directions proven, or it is decoration.
armed_shapes still appears in a normal diff and still requires review to change.
Note the ruling corrects
The ontology slot is not blocked today. The fleet pv pin bump (#3567), the pmat ticket for ONT-11, and the capability ledger touch neither file. Earlier notes on #3080 and #3269 said slot 3 was blocked pending this decision — that is now wrong, and the slot starts with those three while this PR is written.
Measured 2026-09-20 on #3581: there are three derivatives, not two, and they are strictly serialized — each invisible until the one before it clears
One added contract file obliges three generated artifacts:
contracts/census.json — FAIL contracts/census.json .n_files=1799 but HEAD carries 1800
contracts.nt
README's generated CONTRACT_COUNT block — FALSIFY-README-002: the CONTRACT_COUNT block states 1799, the merge tree carries 1800
The third was masked by the first. It could not be seen until the census was regenerated, because the census check fails earlier and the run stops there. So the real cost is not one confusing message — it is three CI rounds for one file, each revealing the next obligation only after the previous fix lands, on a pool where a full round is tens of minutes and this was a T-0 gate PR.
That changes the fix. "Name both derivatives in the failure message" is not enough: the number is three, and a message that names the one derivative it happened to check still leaves the author to discover the rest serially. The gate must evaluate all three and report every one that is stale in a single run, so one regeneration pass closes the whole set. Detecting them independently is what makes the count knowable; reporting them together is what makes it one round instead of three.
Note also the downstream noise this produced: check_readme_claims.sh row 4 (rc=0 wanted 1, lags by one under --exact) read as a second, unrelated defect and is not one — it is the documented aprender#3516 consequence of the same stale census (the planted cc-1 claim lands exactly on the stale count, so the verdict correctly says PASS and the row reads red). Confirmed 7/7 with the census regenerated. One root cause presented as three failures across two guards.
Credit: measured by the slice-M lane while clearing #3581.
Amendment: it is not three derivatives. It is three, plus a guard that fires on the remedy — and that fourth round hits a contributor who did everything right, in the right order.
README CONTRACT_COUNT — masked by the census red in round 1
3
guard-tree
§11.1 ont-delta — caused by round 2's mandatory fix
Rounds 1→2 are the masking already recorded here. Round 3 is a different defect and my earlier fix for this issue does not address it.
make readme-sync is not optional — guard-cargo's FALSIFY-README-002 refuses the PR without it. But README.md is one of §11.1's five named prose sinks, so running the mandatory remedy reclassifies the PR as a sweep and demands an ont-delta: line in the body that was not required a moment earlier. Doing the required thing creates the next violation.
So "name every stale derivative in one run" — the fix I wrote on this issue an hour ago — is necessary and still insufficient. A contributor who regenerates all three derivatives in one pass, correctly, on the first try, still eats round 3, because the fourth failure is not a derivative at all. It is a classification side effect of the repair.
The generalisable rule
A mandatory remedy must announce the obligations it creates.make readme-sync should say, at the moment it edits README.md, that it has just made this PR a §11.1 sweep and that the body now needs an ont-delta: line. The information exists at exactly the point of the edit and is currently discovered one CI round later, from a guard that names §11.1 and not readme-sync.
That is cheaper than the alternative (teaching §11.1 to exempt generated README edits), and it is more honest: the PR is touching a prose sink, so the classification is correct. What is wrong is that nothing connects the cause to the consequence.
Added to done_when
Any target that edits a §11.1 prose sink as a required step prints the obligation it has just created, naming the guard that will otherwise fire and the body line that satisfies it.
Falsifier: run the target on a clean tree and assert the notice appears; remove the notice and assert the case table goes RED. A notice nobody asserts is the class this repo keeps re-finding.
Also recorded: a round 4 that did not happen because it was checked
The slice-M lane edited the contract's references: line (.py → .awk) after generating contracts.nt. If reference strings fed the graph, it would have been stale again and shard 1/3 would have failed on the next round. Re-extracted and compared: contracts.nt and census.json are both byte-identical to a fresh run. They do not feed it. Verified rather than assumed, which is the only reason it is a footnote instead of round 4.
Credit: measured by the slice-M lane on #3581 (2246d0940 → d51343bee), both polarities verified against the real guard — PASS with the ont-delta: line, FAILED: §11.1 … without.
evidence for close: #4655 @ 989cb01 (on main), checked by reading main: scripts/check_census_derived.sh refuses any non-train diff to contracts/census.json naming the file, and checks a freshly computed census's invariants (--census FILE), with a --self-test case table whose RED rows must go RED; contracts/lint-baseline.json now opens "counters are MEASURED comparand->head by scripts/check_ont_ratchet.sh (#3569); this file holds decisions only", and keeps armed_gates / armed_shapes as reviewed decisions. Both directions of the never-down check are rows in scripts/check_ont_ratchet.sh --self-test (e.g. "contracts_anchored RISES: GREEN" / "contracts_anchored FALLS: RED", "contracts_shaped RISES: GREEN" / "FALLS: RED").
evidence for close: 989cb01 (#4655), ancestor of main 6bd89b0. Checked at main: scripts/check_census_derived.sh refuses a PR diff to census.json and names the file, and it runs on every PR through guard_tree.sh; scripts/contracts_gate.sh (step_census) checks a freshly computed census; scripts/check_ont_ratchet.sh --self-test has rise→GREEN and fall→RED rows for never-down; lint-baseline.json now holds decisions only (armed_shapes, armed_gates).
Activity
noahgift commentedon Sep 20, 2026
Measured 2026-09-20 on #3581: there are three derivatives, not two, and they are strictly serialized — each invisible until the one before it clears
One added contract file obliges three generated artifacts:
contracts/census.json—FAIL contracts/census.json .n_files=1799 but HEAD carries 1800contracts.ntCONTRACT_COUNTblock —FALSIFY-README-002: the CONTRACT_COUNT block states 1799, the merge tree carries 1800The third was masked by the first. It could not be seen until the census was regenerated, because the census check fails earlier and the run stops there. So the real cost is not one confusing message — it is three CI rounds for one file, each revealing the next obligation only after the previous fix lands, on a pool where a full round is tens of minutes and this was a T-0 gate PR.
That changes the fix. "Name both derivatives in the failure message" is not enough: the number is three, and a message that names the one derivative it happened to check still leaves the author to discover the rest serially. The gate must evaluate all three and report every one that is stale in a single run, so one regeneration pass closes the whole set. Detecting them independently is what makes the count knowable; reporting them together is what makes it one round instead of three.
Note also the downstream noise this produced:
check_readme_claims.shrow 4 (rc=0 wanted 1, lags by one under --exact) read as a second, unrelated defect and is not one — it is the documented aprender#3516 consequence of the same stale census (the plantedcc-1claim lands exactly on the stale count, so the verdict correctly says PASS and the row reads red). Confirmed 7/7 with the census regenerated. One root cause presented as three failures across two guards.Credit: measured by the slice-M lane while clearing #3581.
Refs #3581, #3516, #3420, #3494.
noahgift commentedon Sep 20, 2026
Amendment: it is not three derivatives. It is three, plus a guard that fires on the remedy — and that fourth round hits a contributor who did everything right, in the right order.
Measured on #3581 across four CI rounds:
guard-cargo+ shard 1/3census.json,contracts.ntstaleguard-cargoCONTRACT_COUNT— masked by the census red in round 1guard-treeont-delta— caused by round 2's mandatory fixRounds 1→2 are the masking already recorded here. Round 3 is a different defect and my earlier fix for this issue does not address it.
make readme-syncis not optional —guard-cargo's FALSIFY-README-002 refuses the PR without it. ButREADME.mdis one of §11.1's five named prose sinks, so running the mandatory remedy reclassifies the PR as a sweep and demands anont-delta:line in the body that was not required a moment earlier. Doing the required thing creates the next violation.So "name every stale derivative in one run" — the fix I wrote on this issue an hour ago — is necessary and still insufficient. A contributor who regenerates all three derivatives in one pass, correctly, on the first try, still eats round 3, because the fourth failure is not a derivative at all. It is a classification side effect of the repair.
The generalisable rule
A mandatory remedy must announce the obligations it creates.
make readme-syncshould say, at the moment it editsREADME.md, that it has just made this PR a §11.1 sweep and that the body now needs anont-delta:line. The information exists at exactly the point of the edit and is currently discovered one CI round later, from a guard that names §11.1 and notreadme-sync.That is cheaper than the alternative (teaching §11.1 to exempt generated README edits), and it is more honest: the PR is touching a prose sink, so the classification is correct. What is wrong is that nothing connects the cause to the consequence.
Added to done_when
Also recorded: a round 4 that did not happen because it was checked
The slice-M lane edited the contract's
references:line (.py→.awk) after generatingcontracts.nt. If reference strings fed the graph, it would have been stale again and shard 1/3 would have failed on the next round. Re-extracted and compared:contracts.ntandcensus.jsonare both byte-identical to a fresh run. They do not feed it. Verified rather than assumed, which is the only reason it is a footnote instead of round 4.Credit: measured by the slice-M lane on #3581 (
2246d0940→d51343bee), both polarities verified against the real guard —PASSwith theont-delta:line,FAILED: §11.1 …without.Refs #3581, #3516.
PMAT-3459: the contract's formals carry Σ symbols; census, graph and …
PMAT-3459: regenerate census, graph and README from the merged tree
PMAT-3401 (adoption): the row states invariants, not the counts of a …
noahgift commentedon Sep 23, 2026
milestone → 0.71.0 per docs/roadmaps/milestone-triage-2026-09-23.md (#4024), operator approval 2026-09-23 (relayed by aprender-cf). Reason: debt ratchet pillars B/C (#3997: pv at the deepest level, ontology merge), slice 2
20 remaining items
BLD-002/R0: regenerate the contract derivatives the new contract moves
BLD-002/R2: regenerate the contract derivatives the new contract moves
pvbin="$(command -v pv)") — on a fleet-clobbered runner (pv 0.65.2, no census) it reads 'no consumer' and REDs an honest anchored rise; check_apr_bin_pinned.sh is blind to the form #3679pvbin="$(command -v pv)") — on a fleet-clobbered runner (pv 0.65.2, no census) it reads 'no consumer' and REDs an honest anchored rise; check_apr_bin_pinned.sh is blind to the form #3679noahgift commentedon Oct 12, 2026
evidence for close: #4655 @ 989cb01 (on main), checked by reading main:
scripts/check_census_derived.shrefuses any non-train diff tocontracts/census.jsonnaming the file, and checks a freshly computed census's invariants (--census FILE), with a--self-testcase table whose RED rows must go RED;contracts/lint-baseline.jsonnow opens "counters are MEASURED comparand->head by scripts/check_ont_ratchet.sh (#3569); this file holds decisions only", and keepsarmed_gates/armed_shapesas reviewed decisions. Both directions of the never-down check are rows inscripts/check_ont_ratchet.sh --self-test(e.g. "contracts_anchored RISES: GREEN" / "contracts_anchored FALLS: RED", "contracts_shaped RISES: GREEN" / "FALLS: RED").noahgift commentedon Oct 12, 2026
evidence for close: 989cb01 (#4655), ancestor of main 6bd89b0. Checked at main: scripts/check_census_derived.sh refuses a PR diff to census.json and names the file, and it runs on every PR through guard_tree.sh; scripts/contracts_gate.sh (step_census) checks a freshly computed census; scripts/check_ont_ratchet.sh --self-test has rise→GREEN and fall→RED rows for never-down; lint-baseline.json now holds decisions only (armed_shapes, armed_gates).
noahgift commentedon Oct 12, 2026
Cop batch close (FLOW-004 drain, ≤43/d): fix verified on main — merged #4655 ; ancestor of origin/main: 989cb01 . Evidence: #3569 (comment)