Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
271802a
CRW-906: record a hand-opened correction of an accepted, still-curren…
Oct 7, 2026
3252c35
CRW-906: name the correction route where the ruling refusal and the r…
Oct 7, 2026
d2b442d
CRW-906: pin that the correction reason does not loosen the stale rou…
Oct 7, 2026
19899c3
CRW-906: refuse to merge an accepted result whose correction generati…
Oct 7, 2026
5921d1a
CRW-906: hold the accepted head back in the lane's own check and land…
Oct 7, 2026
41d4298
Merge remote-tracking branch 'origin/dev' into codex/crw-906-accepted…
Oct 7, 2026
a547bf1
CRW-906: let the shipped relationship contract carry the correction r…
Oct 7, 2026
d4ca75c
Merge remote-tracking branch 'origin/dev' into codex/crw-906-accepted…
Oct 7, 2026
6b66b30
CRW-906: close the two ways the correction gate could still be passed…
Oct 7, 2026
30087f6
CRW-906: resolve a refreshed head in the lane gate, and read an exclu…
thisisjun786 Oct 7, 2026
e1a9072
CRW-906: resolve the in-flight turn by every identity, ask every matc…
thisisjun786 Oct 7, 2026
141c105
CRW-906: keep a named relationship from hiding a shared head, and cat…
thisisjun786 Oct 7, 2026
bbb6cc8
CRW-906: match the forge identity, ask a member's own gate, and refus…
thisisjun786 Oct 7, 2026
f1c1141
CRW-906: hold a correction's accepted head in every merge path, and f…
thisisjun786 Oct 7, 2026
5ee9066
CRW-906: name the lane-gate test by the gate it exercises
thisisjun786 Oct 7, 2026
6f79654
CRW-906: compare a held head as a commit, not as its spelling
thisisjun786 Oct 7, 2026
ad05476
CRW-906: keep a replaced head and a live bundle's head refused across…
thisisjun786 Oct 7, 2026
7f7b39c
CRW-906: keep a refresh-held head and a legacy bundle's head refused …
thisisjun786 Oct 7, 2026
38e3504
CRW-906: check another node's correction for a member that left the lane
thisisjun786 Oct 7, 2026
596938c
CRW-906: say when a correction can be withdrawn, and what a base refr…
thisisjun786 Oct 7, 2026
d99417d
CRW-906: match a held head by the whitespace SameCommit trims
thisisjun786 Oct 7, 2026
e93776f
CRW-906: compare commit identities through one definition in Go and SQL
thisisjun786 Oct 7, 2026
a1a7ff7
CRW-906: refuse a correction over the head of a landed bundle's exclu…
thisisjun786 Oct 8, 2026
af1903e
CRW-906: compare only TEXT heads in SQL and check refresh rows as Sta…
thisisjun786 Oct 8, 2026
fc9dc3b
CRW-906: give the commitid test package the store test isolation import
thisisjun786 Oct 8, 2026
0192891
CRW-906: match a turn by its local path or forge identity, and docume…
thisisjun786 Oct 8, 2026
b3056f5
CRW-906: compare a turn's repository by the lane's reading, and keep …
thisisjun786 Oct 8, 2026
22a666d
CRW-906: resolve a repository the way the lane's stat does before rea…
thisisjun786 Oct 8, 2026
a0cd9b2
CRW-906: record the S27b and S27i rows' correction route in their cas…
thisisjun786 Oct 8, 2026
314a02b
CRW-906: match a repository by the common git directory git reports f…
thisisjun786 Oct 8, 2026
7771746
Merge branch 'dev' into codex/crw-906-accepted-result-correction
thisisjun786 Oct 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion contract/schema/SOURCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ with this note until todo 44 removed its source; the copies here are the ones th
| acknowledgement.json | 193c2a1dbdb6197f852aaa38c6b8b4e55ba804ffc66e7b2a73925365b133eb7c |
| completion-receipt.json | fd6498fdca80c7e8f4d97e37ceec12935bf1afce10211826fdc232593b9fb0d5 |
| delivery-attempt.json | ad856f98872952ffc2235acc12ccc5942bbd6e5cae0df1771f063dc74526d24b |
| relationship.json | c8ebaf4559fa1ac6df26d98c4214938caf78bd8c61659bce026da6a3595a4b90 |
| relationship.json | 6a994cad6400a07d3e2faaf2161a16818ac7784be651cdcb2d6c9b9439988cbd |
| verification-verdict.json | 0b3f8f4b061cff2992fc60a7c1f45dec6f803116894735751c40df3a8d356af9 |

Contract bundle revision c37d332e2daba95c9ef47adf00a82bc9c6a539ab62538f0ad857561e470d2989.
Expand All @@ -32,3 +32,14 @@ on a `ready_for_review` receipt. Old receipts without it still validate. The 18
were re-judged against the revised bytes with jsonschema 4.19.2 Draft7Validator and kept their
verdicts; 18 additional recorded cases cover the item stated, absent, on an execution-only receipt and
malformed. This changes the stored JSON contract, not the SQLite schema.

The relationship copy now allows one more `generations[].reason`: `accepted_result_correction`,
the reason a coordinator gives `generation-open` when it corrects a result that was accepted and is
still current (the relay's verdict writer refuses a second ruling on an accepted head, so the
generation is opened by hand and its reason is what notes the route). The enum previously allowed
only `initial_assignment` and `needs_changes_revision`, so a relationship opened by that route
serialized a reason the shipped contract refused. Old relationships without it still validate; a
generation with no reason (a returning tenure) still validates as null. The 6 existing relationship
cases were re-judged against the revised bytes with jsonschema 4.19.2 Draft7Validator and kept their
verdicts; 6 additional recorded cases cover each reason the registry accepts, the empty reason, and
an unknown and a mistyped one. This changes the stored JSON contract, not the SQLite schema.
1 change: 1 addition & 0 deletions contract/schema/relationship.json
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@
"enum": [
"initial_assignment",
"needs_changes_revision",
"accepted_result_correction",
null
]
}
Expand Down
2 changes: 1 addition & 1 deletion docs/crw-run/dispatch-cases/recorded/0560-S27b.md
Original file line number Diff line number Diff line change
@@ -1 +1 @@
| S27b | The child waits for the one run of each reviewer within the waiting budget before it emits: a Devin status `Analyzing your changes` is waited for up to the budget and `Full review skipped: trial expired and no credits remaining` is not; Codex is waited for while its eyes reaction is on the pull request or any row of its summary comment is not `Completed`, and each of its code review and security review must be `Completed` or skipped by the bot's notice (a thumbs-up counts for both when no row contradicts it), so a Security Review row `Completed` alone is not finished; past the budget a run still going is recorded as pending, not complete, and the wait is released only where the candidate's required independent review and its finding dispositions already exist; when neither reviewer shows any signal 30 minutes after the pull request became ready or was opened, the handoff says `review unavailable (no signal)` and the child goes on, and when only one is silent the same 30 minutes apply to it and the handoff says so; a thread that arrives after the receipt is a late finding: unless the parent has dispositioned it for that head (`--late-dispositions`) it returns the candidate before the acceptance, and after the acceptance no correction can reach the child and the candidate is held ([Late review threads](merge-readiness.md#late-review-threads)) | [The one run of each reviewer, awaited before the receipt](merge-readiness.md#the-one-run-of-each-reviewer-awaited-before-the-receipt) and [Recheck, integrate, and record](merge-readiness.md#recheck-integrate-and-record) and [a late thread the parent dispositions itself](merge-readiness.md#a-late-thread-the-parent-dispositions-itself) | Merge gate | changed with CRW-808; the unlimited wait became the waiting budget with a pending record |
| S27b | The child waits for the one run of each reviewer within the waiting budget before it emits: a Devin status `Analyzing your changes` is waited for up to the budget and `Full review skipped: trial expired and no credits remaining` is not; Codex is waited for while its eyes reaction is on the pull request or any row of its summary comment is not `Completed`, and each of its code review and security review must be `Completed` or skipped by the bot's notice (a thumbs-up counts for both when no row contradicts it), so a Security Review row `Completed` alone is not finished; past the budget a run still going is recorded as pending, not complete, and the wait is released only where the candidate's required independent review and its finding dispositions already exist; when neither reviewer shows any signal 30 minutes after the pull request became ready or was opened, the handoff says `review unavailable (no signal)` and the child goes on, and when only one is silent the same 30 minutes apply to it and the handoff says so; a thread that arrives after the receipt is a late finding: unless the parent has dispositioned it for that head (`--late-dispositions`) it returns the candidate before the acceptance, and after the acceptance the correction goes through the hand-opened generation [Late review threads](merge-readiness.md#late-review-threads) describes, while a node that landed is held ([Late review threads](merge-readiness.md#late-review-threads)) | [The one run of each reviewer, awaited before the receipt](merge-readiness.md#the-one-run-of-each-reviewer-awaited-before-the-receipt) and [Recheck, integrate, and record](merge-readiness.md#recheck-integrate-and-record) and [a late thread the parent dispositions itself](merge-readiness.md#a-late-thread-the-parent-dispositions-itself) | Merge gate | changed with CRW-808; the unlimited wait became the waiting budget with a pending record |
2 changes: 1 addition & 1 deletion docs/crw-run/dispatch-cases/recorded/0630-S27i.md
Original file line number Diff line number Diff line change
@@ -1 +1 @@
| S27i | A red, P0, P1 or security late thread, a P2 or P3 whose effect is in a blocking class, or a late thread the coordinator cannot grade without reconstructing the child's reasoning, is the child's ordinary correction with the restoration block before the acceptance: the child fixes the finding or answers it with code evidence, pushes and reruns checks only if it changed something, and emits again, and the candidate does not merge meanwhile; after the acceptance of a current result no correction can reach the child, so such a thread, and a minor one the installed relay cannot record, is reported on the coordination record and the candidate is held, with no generation opened by hand around `dag-correct`; the review threads on N, and each reviewer's summary comment, are read once more before `dag-accept` so that a late thread surfaces while a route exists; after the merge a late thread is new work (a minor one for the backlog, a red, P0, P1 or security one a correction issue) | [Late review threads](merge-readiness.md#late-review-threads) and [Refresh the base yourself when only the base moved](merge-readiness.md#refresh-the-base-yourself-when-only-the-base-moved) | Merge gate | added 2026-10-03; basis below |
| S27i | A red, P0, P1 or security late thread, a P2 or P3 whose effect is in a blocking class, or a late thread the coordinator cannot grade without reconstructing the child's reasoning, is the child's ordinary correction with the restoration block before the acceptance: the child fixes the finding or answers it with code evidence, pushes and reruns checks only if it changed something, and emits again, and the candidate does not merge meanwhile; after the acceptance of a current result the correction goes through the generation opened by hand under a reason that states it, so such a thread returns to the child that way; a thread that route cannot reach, a node that landed and a minor one the installed relay cannot record included, is reported on the coordination record and the candidate is held; the review threads on N, and each reviewer's summary comment, are read once more before `dag-accept` so that a late thread surfaces while a route exists; after the merge a late thread is new work (a minor one for the backlog, a red, P0, P1 or security one a correction issue) | [Late review threads](merge-readiness.md#late-review-threads) and [Refresh the base yourself when only the base moved](merge-readiness.md#refresh-the-base-yourself-when-only-the-base-moved) | Merge gate | added 2026-10-03; basis below |
4 changes: 2 additions & 2 deletions docs/relay/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -841,7 +841,7 @@ When a step refuses, the refusal names what to do:
| recorded `verified`, asked `unverified` or `aborted` | `disposition_conflict` | rule `needs_changes`, or stop the assignment by changing the relationship's status |
| recorded `needs_changes` | `disposition_conflict` | the ruling opened a generation and is not withdrawn: rule the head of that generation when the child reports there |
| recorded `unverified` or `aborted` | `disposition_conflict` | the ruling is final for the event: open a fresh execution generation (`generation-open`, then `generation-bind`) and rule what the child reports there |
| a plan accepted the verified event | `disposition_conflict` | read the node's stale reading: when its action is `correct`, `dag-correct --prepare` prints the instruction and the dispatch request id, the generation is opened by hand and `dag-correct` binds it; `revalidate` and `hold` have their own steps; when the accepted result is current, a base that moved after the acceptance is recorded by `dag-base-refresh` (a generation opened by hand that only merges the base, ruled `verified`; the relay proves from git that its head is the accepted head plus merges of the base), and for any other current result this build records no correction route, so report it and open no generation that `dag-correct` will refuse |
| a plan accepted the verified event | `disposition_conflict` | read the node's stale reading: when its action is `correct`, `dag-correct --prepare` prints the instruction and the dispatch request id, the generation is opened by hand and `dag-correct` binds it; `revalidate` and `hold` have their own steps; when the accepted result is current and a defect was found in it before it landed, the same steps correct it, with the generation opened under a reason that states the correction (`accepted_result_correction`, or the `needs_changes_revision` default), after which `dag-accept --supersedes` takes the corrected result ([the scheduler](dag-scheduler.md#correcting-a-result-that-was-accepted-and-is-still-current)); when only the base moved, `dag-base-refresh` records it (a generation opened by hand that only merges the base, ruled `verified`; the relay proves from git that its head is the accepted head plus merges of the base) |
| the work is marked merged, or a turn landed it | `disposition_conflict` | a merged result is corrected by new work, not by a second ruling |
| a merge turn is merging or of unknown effect | `disposition_conflict` | resolve the turn (`merge-turn-resolve` reads the branch), then rule again |
| the event is not the head | `stale_generation` or `superseded_revision` | rule the head the assignment shows |
Expand Down Expand Up @@ -886,7 +886,7 @@ The rule is fixed by the kind. `answer` and `stop` change nothing the child's at

No refusal reason is added, and a refusal writes nothing. The command line is checked first: an unknown `--decision` or a missing required option ends with the parser's own exit 2 and a message on stderr before the writer runs, an unreadable `--note @path` is a host problem (exit 3, as for `verdict --criteria`), and `malformed_receipt` is what the writer answers to a direct call or to a blank note, turn or digest. `decision-show` reads the decisions of a relationship back, oldest first, each with the state of its delivery.

Limits that are part of the contract. The relay records the decision and its delivery; it does not read the child's thread, so `dispatched` says the message was accepted, not that the child acted. A decision that opened g+1 is recorded against a DAG plan node by `dag-correct` ([the third way to open a generation](dag-scheduler.md#three-ways-to-open-the-generation)), which refuses until the decision was dispatched into the turn the generation is bound to; until it is recorded, `dag-accept` finds no execution for g+1 and refuses `stale_generation`. A message sent to the child outside this route leaves a record only when the registered parent admits its turn ([Direct parent interventions](#direct-parent-interventions)). The crw-run skill's need-input procedure follows this route. After an answer or a stop, the relationship still reads as blocked (`dispositions-show`) until the child reports again. `registry`'s `generation-open --reason` still accepts only its own two reasons: `decision_reply` is written by this command alone. An installed relay older than this change has no `decision-reply` and answers the command as an unknown subcommand.
Limits that are part of the contract. The relay records the decision and its delivery; it does not read the child's thread, so `dispatched` says the message was accepted, not that the child acted. A decision that opened g+1 is recorded against a DAG plan node by `dag-correct` ([the third way to open a generation](dag-scheduler.md#three-ways-to-open-the-generation)), which refuses until the decision was dispatched into the turn the generation is bound to; until it is recorded, `dag-accept` finds no execution for g+1 and refuses `stale_generation`. A message sent to the child outside this route leaves a record only when the registered parent admits its turn ([Direct parent interventions](#direct-parent-interventions)). The crw-run skill's need-input procedure follows this route. After an answer or a stop, the relationship still reads as blocked (`dispositions-show`) until the child reports again. `registry`'s `generation-open --reason` still accepts only the reasons that command writes: `decision_reply` is written by this command alone. An installed relay older than this change has no `decision-reply` and answers the command as an unknown subcommand.


## The coordination summary
Expand Down
Loading
Loading