Skip to content

The README contract count is a serialization point: any two contract-adding PRs collide by construction (4 occurrences today) #2630

Closed

Description

@noahgift

Severity: P1 — process defect, not a code defect. It has caused a merge-blocking failure
four separate times today, on four independent PRs, each of which was individually correct.

The mechanism

README.md hardcodes the contract corpus size in three places (:44, :225, :256), and
scripts/check_readme_claims.sh — a required check via guard-runner-labels → gate —
asserts it equals find contracts/ -name '*.yaml' | wc -l.

So every PR that adds a contract must edit the same three literals. With main at 1778:

PR adds writes outcome
#2601 (pv metadata domains) 1 1779 correct alone
#2621 (crypto surface) 1 not updated fatal — cannot pass ci / gate
#2613 (batch of 13) 3 1781 correct only because folding made the collision visible
#2617 (pv, 3 folded) 3 1781 correct only after folding

Each individual PR is right. Three +1s do not compose. Two contract-adding PRs cannot
both be green at the same time, and neither author can see the other's contract.

This is a serialization point disguised as a documentation claim. The repo has a standing
rule that "only ONE PR at a time may edit ci.yml's integration-test line" — this is the
same hazard, on a line nobody thinks of as load-bearing, with no comment warning about it.

Why "just remember to run the check" is not the fix

Every one of the four PRs had a competent author running gates. The failure mode is not
forgetting to update the number — it is that the correct number depends on what else is in
flight
, which is unknowable from inside a branch. A rule that cannot be satisfied locally is
not a rule, it is a lottery.

Options, in the order I'd rank them

  1. Derive it. Generate the README figures from the corpus at build/docs time so no human
    or agent ever writes the literal. Removes the class entirely.
  2. Assert a floor, not equality. >= N with a periodically-ratcheted N keeps the claim
    honest (the README must never overstate) while letting concurrent PRs add contracts. The
    check's purpose is to stop the README lying, and a floor does that.
  3. Keep equality but make the hazard visible — a comment at each of the three sites and in
    check_readme_claims.sh saying this line serializes contract-adding PRs, plus a failure
    message that names the likely cause ("another contract landed since you branched; re-measure
    with find contracts/ -name '*.yaml' | wc -l"). Cheapest, does not fix the collision.

I'd take option 2 for 0.64.0 and option 1 after. Option 3 alone leaves a known trap armed.

Note on scope

Whatever is chosen, the check must keep failing when the README overstates the corpus —
that is the property worth having, and the mutation to verify is: lower the corpus below the
claim and confirm RED.

Refs #2613, #2617, #2621, #2601.

Activity

  1. noahgift commented on Sep 5, 2026

    @noahgift
    MemberAuthor

    Blocks PP-066 P-0.4 (spec §5 Track P) — parented under #2870 per the epic body (Track P lives under #2870 → #2556).

    #2870's ticket map: 'closes (floor now, derived headline after)' = PP-066 P-0.4 (honest headline, README checked as a floor). Track P lives under #2870 → #2556 per the epic body; comment names the PP-066 card it blocks.

    PP-066 triage 2026-09-05 (issue #2873); ledger docs/audits/pp-066-triage-2026-09-05.md.

  2. 1 remaining item

  3. added this to the 0.68.0 milestone on Sep 10, 2026
  4. added
    automationBot-maintained dashboard, not a defect — skip in triage
    P1High priority
    on Sep 11, 2026
  5. modified the milestones: 0.68.0, 0.69.0, 0.71.0, 0.72.0 on Sep 16, 2026
  6. modified the milestones: 0.72.0, 0.71.0 on Sep 25, 2026
  7. noahgift commented on Sep 25, 2026

    @noahgift
    MemberAuthor

    Measured at ae1887d (fold/b3-onto-main): both of this issue's options are on the tree.

    • Option 1 (derive): BSE-03 phase A. README.md:44 holds the count between <!-- CONTRACT_COUNT_START/END --> markers, written by scripts/readme_sync.sh from contracts/census.json. No human or agent writes the literal.
    • Option 2 (floor): G-11 (PMAT-1062). compare_count in scripts/check_readme_claims.sh passes a README that lags the corpus and FAILs one that overstates it. --exact is used only by the orchestrator's docs commit.
    • Mutation this issue requires ("lower the corpus below the claim, confirm RED"): --self-test row 6 plants census+1 and gets rc=1 RED; row 7 (two counts in one README) is also RED. The full run gives 11/11 rows, rc 0. It is wired at ci.yml:1978 before the real check.

    Two contract-adding PRs no longer collide: each one leaves the README lagging, which passes. Nothing is left to implement. Closing is for the quorum.

  8. noahgift commented on Sep 25, 2026

    @noahgift
    MemberAuthor

    Closing as completed. Both options are on origin/main @ 0005847: README.md carries the CONTRACT_COUNT_START/END markers written by scripts/readme_sync.sh (option 1), and scripts/check_readme_claims.sh has the compare_count floor (option 2). APR-EPIC-001 close: claude and agy both said close; apr shadow row recorded (handoff/close-quorum-2026-09-25-cx.json). Applied by aprender-d1 on the cop's order.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1High priorityautomationBot-maintained dashboard, not a defect — skip in triage

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions