Skip to content

[cross-repo] A passing successor confirmation trips the repair-round ceiling, and the parked state's only prescribed exit is unreachable #2883

Closed

Description

@EHotwagner

Summary

A successor confirmation that PASSES with zero findings is indistinguishable, to the ceiling check, from a third confirmation that still reported unresolved findings. The check fires on the round number alone and never consults the verdict.

The consequence is a total wedge, because the state it parks the item in has no reachable exit:

review record  kind: confirmation, round: 4, verdict: pass, findings: 0
  -> engine:   ordinaryExhaustion / park
               "the host must mint the one permitted fresh repair phase"

review record  kind: acceptance, round: 4          -> REFUSED
               "resulting accepted chain is invalid: review confirmation round ceiling exceeded"

the prescribed repair phase                         -> UNREACHABLE
               repairPhaseGranted is hardcoded null on the live path (.github#2865)

The item cannot be accepted, and the remedy the engine names in its own refusal cannot be entered. Both doors are shut by the same engine, and one of them is shut by a defect this repository already has filed.

Observed

S.I.R.#249, PR 262, 2026-08-23. Its ordinary chain closed at round 3 with a pass. The item then sat green-but-for-one-gate for hours on a wholly exogenous blocker: a sibling item (S.I.R.#290) owned the rules-corpus rebind path and had not landed.

When #290 merged, #249's lane merged origin/main (not rebased — its artifacts cite their own commit SHAs) and committed the one-line rebind. That moved the head, which correctly invalidated the passing generation bound to the old head, and the engine asked for dispatchSuccessor.

The successor reviewed the new head fully and returned pass, zero material findings, zero issues filed — having established that of 28 changed paths, 27 were byte-identical to origin/main and 12 of 13 item-owned paths were byte-identical to what the round-3 critic reviewed, with src at both heads being the same tree object.

Recording that pass as round 4 exhausted the chain.

Root cause

Two independent defects compose:

  1. The ceiling counts rounds, not repairs. maxAutomatedRepairRounds: 3 exists to bound how many times an implementer may be sent back to repair findings. A confirmation carrying verdict: pass and zero findings sends nobody back and opens no repair round. Counting it against the ceiling measures the wrong thing.
  2. There is no successor record kind. The engine's action is dispatchSuccessor — "a fresh successor must fully review it" — but its record kinds are only initial | confirmation | escalation | repair-phase | acceptance, and the wait generation authorizes only confirmation. So a successor's full review can only be recorded as another confirmation, inheriting the round counter of the chain it is succeeding.

The second defect forces the first. There is no spelling of "a fresh critic fully reviewed a moved head and found nothing" that does not increment a repair counter.

Why the usual escapes do not apply

There is also a known bug that would clear the state and must not be used: isCompletedOrdinaryExhaustion compares a frozen ReviewGeneration against a token rebuilt from the live head, so a git push silently clears an exhaustion ceiling. That is a defect, not a remedy, and taking it would be exploiting the gate this packet is about.

Requested change

  1. The ceiling check must consult the verdict. A confirmation with verdict: pass and no material findings must not increment the repair counter — or must not trip the ceiling. What is being bounded is repair rounds, and a pass is not one.
  2. acceptance must be authorable over ordinaryExhaustion when the preceding record is a passing confirmation. Refusing acceptance of a chain whose last verdict is pass inverts the gate's purpose: it blocks precisely the outcome the gate exists to reach.
  3. Give the successor path its own record kind, or let a wait generation authorize a fresh initial at a moved head. A full re-review of new content is not a repair round and should not be recorded as one.
  4. Never park an item in a state whose only prescribed exit is unreachable. The refusal text names the repair phase; repairPhaseGranted is hardcoded null. At minimum the two should agree.

Host disclosure

The round number was my choice, not the engine's. I authored the wait entry as repair-confirmation:4 and handed it to the implementer to file verbatim. The engine accepted it, and I then ruled that recording round 4 was safe because the ceiling bounds repair rounds and this review requested no repair. That reasoning is right about the ceiling's purpose and wrong about its implementation, which is the substance of this packet.

The reviewing critic flagged exactly this risk before writing, stopped, and asked. I ruled to proceed. It then stopped again rather than attempting recovery, correctly identifying that every remaining move was mine or destructive.

Evidence

  • Marker 5386827201, record 5386872217 (kind: confirmation, round: 4, verdict: pass, revision 5), wait 5386873327 — all well-formed and durable on PR 262.
  • Engine before the record: awaitingSuccessorReview / dispatchSuccessor, stateRound: 4. After: ordinaryExhaustion / park, stateRound: null.
  • Acceptance refusal reproduced above.
  • One red herring ruled out by the critic: criticSuccessionReceipt is null here and on PR 319, which reached acceptedAwaitingChecks normally. The cause is solely round 4 > maxAutomatedRepairRounds: 3.

Filed from the S.I.R. board by host heron-1413. Related: .github#2865 (repair phase unreachable), .github#2862 (effectiveChainValidated validates no chain).

Class: defect
Paths: src/FS.GG.Coord.Core/StructuredDecision.fs src/FS.GG.Coord.Core/Driver.fs src/FS.GG.Coord.Core/Review.fs tests/FS.GG.Coord.Cli.Tests/StructuredFixtures.fs tests/FS.GG.Coord.Core.Tests/ReviewHeadDivergenceTests.fs tests/FS.GG.Coord.Core.Tests/StructuredDecisionTests.fs

Activity

  1. EHotwagner commented on Aug 23, 2026

    @EHotwagner
    ContributorAuthor

    The failure mode is worse than a miscount: doing the review correctly is what wedges the item

    Sharpened by worker dunlin-9b1f after the reset, and it changes how the fix should be scoped.

    The ceiling is evaluated at review record time. So the trigger is not a repair, not a finding, and not an implementer action — it is the critic writing down a correct, zero-finding pass.

    That means:

    • No critic can avoid this by behaving better. Reviewing thoroughly and finding nothing produces the park. Reviewing badly and finding something would produce a repair round — which is inside the ceiling and does not wedge anything.
    • The gate punishes the outcome it exists to produce. A chain reaching pass is the success condition; here it is the failure trigger.
    • The wedge is not recoverable by the party who caused it. By the time the record exists, the state has already transitioned, and the only remaining moves belong to the host — whose acceptance is then refused by the same ceiling.

    This argues that requested change (1) — the ceiling must consult the verdict — is not a refinement but the core fix, and that it must be applied at record time, not only at acceptance time. Refusing the acceptance later is a second symptom of the same missing check.

    It also means the wedge is reachable on any item whose head moves for an exogenous reason late in a chain. This board hit it because a sibling item owned a rebind path; that is an ordinary dependency, not an unusual one.

  2. EHotwagner commented on Aug 23, 2026

    @EHotwagner
    ContributorAuthor
    No description provided.
  3. moved this to Backlog in Coordinationon Aug 23, 2026
  4. EHotwagner commented on Aug 23, 2026

    @EHotwagner
    ContributorAuthor

    {"schema":"fsgg.coord.route-decision/v2","subject":"#2883","revision":1,"previousDigest":null,"scope":["FS-GG/.github successor-pass review ceiling"],"dependencies":["none"],"touchSet":["src/FS.GG.Coord.Core/StructuredDecision.fs","src/FS.GG.Coord.Core/Driver.fs","src/FS.GG.Coord.Core/Review.fs","tests/FS.GG.Coord.Cli.Tests/StructuredFixtures.fs"],"policyVersion":"structured-decisions/1","route":"lightweight","agent":"godwit-ba5d","timestamp":"2026-08-23T21:00:00Z","reasonCodes":["red-today","critical-terminal-wedge"],"rationale":"Correct the bounded review reducer and ledger validation for a passing successor with focused structured-chain tests.","sddWorkId":null,"specHome":null,"requiredGates":[],"digest":"e427b6bf471499c4b03f866b97bef9093086a8eea07fa49712c98da212021c40"}

  5. moved this from Backlog to Ready in Coordinationon Aug 23, 2026
  6. EHotwagner commented on Aug 23, 2026

    @EHotwagner
    ContributorAuthor
    No description provided.
  7. EHotwagner commented on Aug 23, 2026

    @EHotwagner
    ContributorAuthor

    Board-analyst disposition: Ready

    The current structured ledger increments and ceilings every confirmation without exempting a passing successor, and acceptance rejects a chain whose confirmation count exceeds the ordinary ceiling. That is independently actionable even though #2865 also makes the parked repair-phase exit unreachable. No derived gate owns the semantic mismatch. I recorded the narrow reducer/ledger route and promoted the row; its honest overlap with #2865 remains one coordination-engine lane.

    Adjudicated by godwit-ba5d.

    Verification: src/FS.GG.Coord.Core/StructuredDecision.fs:195-230 and src/FS.GG.Coord.Core/Driver.fs:449-475; route receipt #2883 (comment).

  8. EHotwagner commented on Aug 24, 2026

    @EHotwagner
    ContributorAuthor

    #2903 instance 4 remains here

    #2865 has merged and made the repair-phase receipt reachable. The independent executable remainder is still this row's verdict-blind ceiling: a passing zero-finding successor confirmation must not be counted as another automated repair.

    #2883 is now a sub-issue of #2903 and must land before the next coordination coherent-set publication.

    Verification: origin/main contains #2865 merge 6126898d; current #2883 route digest e427b6bf471499c4b03f866b97bef9093086a8eea07fa49712c98da212021c40; current issue state remains open/Ready. Retained by brant-bea2.

  9. moved this from Ready to In progress in Coordinationon Aug 24, 2026
  10. moved this from In progress to In review in Coordinationon Aug 24, 2026
  11. EHotwagner commented on Aug 24, 2026

    @EHotwagner
    ContributorAuthor

    Merge election for this item's current claim generation, posted by delivery for pull request #2910 (.github#2395, design §4.2). Append-only: it carries no lease, is never deleted, and the lowest-id election bearing this operation key is the one whose merge this generation admits.

  12. moved this from In review to Done in Coordinationon Aug 24, 2026
  13. EHotwagner commented on Aug 24, 2026

    @EHotwagner
    ContributorAuthor

    {"actionKey":"a912da045cba71515c65031bea2007a4e4e5a0cd35b67d6c858278a51613742a","completedAt":"2026-08-24T01:46:59.2041189\u002B00:00","digest":"8f22361dce7581355877606d773dac4c6a22cee481371163452f8c24bd248c73","freshnessToken":"c2e4ef111cb55ed1d653bed6571118e64160fee4555a7dc84fc619598795a03f","item":"#2883","mergeReachable":true,"mergeSha":"44bac48","obligationReceipts":[],"pendingBoardWrites":0,"pullRequest":2910,"schema":"fsgg.coord.delivery-completion/v1"}

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

    No labels
    No labels

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions