Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
acc2b06
CRW-965: accept a pull-request-less implementation node by its commit
Oct 7, 2026
1f147d3
CRW-965: record the two appended zone tables in the shipped snapshot
Oct 7, 2026
d6148de
CRW-965: integrate ready candidates on the local integration branch
thisisjun786 Oct 7, 2026
a5e3939
CRW-965: add dag-integrate and the fast-forward push with tests
thisisjun786 Oct 7, 2026
faf93d6
CRW-965: wire dag-accept --commit, the local-integration test and the…
thisisjun786 Oct 7, 2026
f3faec2
CRW-965: re-record the crw plugin version for the merge-readiness change
thisisjun786 Oct 7, 2026
2c6c74d
CRW-965: drop an unused git helper in the integration package
thisisjun786 Oct 7, 2026
960901b
CRW-965: rebuild the integration batch on real merged worktrees
thisisjun786 Oct 7, 2026
b752c8f
CRW-965: complete pending marks from their frozen rows and let an unm…
thisisjun786 Oct 7, 2026
2bb077e
CRW-965: recheck the coordinator fence before the branch moves and sc…
thisisjun786 Oct 7, 2026
739f09e
CRW-965: accept a commit-accepted artifact edge and freeze criteria p…
thisisjun786 Oct 7, 2026
14a04f0
CRW-965: document the reuse boundary, the criteria reading and the ve…
thisisjun786 Oct 7, 2026
4f73dd3
CRW-965: keep a batch from merging a branch-held head twice and refus…
thisisjun786 Oct 7, 2026
63fe9df
CRW-965: mark a contained candidate from its frozen row, never merge …
thisisjun786 Oct 7, 2026
ff281f5
CRW-965: report already-contained and unverified candidates from dag-…
thisisjun786 Oct 7, 2026
f850f15
CRW-965: defer a survivor that conflicts after a removal and judge co…
thisisjun786 Oct 8, 2026
5c46667
CRW-965: fix the pre-merge findings on verification, exclusion, recei…
thisisjun786 Oct 8, 2026
3a48791
CRW-965: read a linked worktree's git directory with the GIT_ variabl…
thisisjun786 Oct 8, 2026
8c7587d
CRW-965: scope batches to their checkout, keep retried marks single, …
thisisjun786 Oct 8, 2026
e000c10
CRW-965: judge tool values against their pins, complete commit nodes …
thisisjun786 Oct 8, 2026
c00163a
CRW-965: replay a commit acceptance on a fresh record of the same hea…
thisisjun786 Oct 8, 2026
81b2a05
CRW-965: re-verify a covering head whose keys no longer hold before m…
thisisjun786 Oct 8, 2026
638fa96
CRW-965: move the branch and its record in one fenced transaction, re…
thisisjun786 Oct 8, 2026
a2ee21d
CRW-965: document the reuse boundary, the verification keys, the comp…
thisisjun786 Oct 8, 2026
82fb006
CRW-965: report reconciled and abandoned batches from dag-integrate
thisisjun786 Oct 8, 2026
7fad547
CRW-965: check the batch's currency, platform, moves and push against…
thisisjun786 Oct 8, 2026
e2d24ac
CRW-965: freeze the integration commands' answers and document the co…
thisisjun786 Oct 8, 2026
9f03e72
CRW-965: compare the criteria set in the frozen currency guard
thisisjun786 Oct 8, 2026
1eaee9a
CRW-965: count a commit-accepted node only on refs its own batch moved
thisisjun786 Oct 8, 2026
afe9102
CRW-965: take the verified-move check from the move itself
thisisjun786 Oct 8, 2026
491d770
CRW-965: verify a contained candidate again when its criteria set cha…
thisisjun786 Oct 8, 2026
bbaea60
CRW-965: describe the covering verification in the scheduler doc
thisisjun786 Oct 8, 2026
565b2ae
CRW-965: merge origin/dev into the commit-acceptance branch
thisisjun786 Oct 8, 2026
837c1d8
CRW-965: select a node named twice in a batch once
thisisjun786 Oct 8, 2026
f779c03
CRW-965: refuse a NULL key in the commit path's appended tables
thisisjun786 Oct 8, 2026
7c77e55
CRW-965: reword the NULL key test comment
thisisjun786 Oct 8, 2026
4604777
CRW-965: complete a contained node on the branch that contains it
thisisjun786 Oct 8, 2026
befa17f
CRW-965: keep an escaped character as the argument it starts
thisisjun786 Oct 8, 2026
b1183bd
CRW-965: link testsupport from the integrate package's tests
thisisjun786 Oct 8, 2026
cad90aa
Merge branch 'dev' into codex/crw-965-commit-acceptance-integration
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
1 change: 1 addition & 0 deletions cmd/crw/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import (
"github.com/thisisjun786/codex-relay-workflow/internal/relay/childcleanup"
_ "github.com/thisisjun786/codex-relay-workflow/internal/relay/dag"
_ "github.com/thisisjun786/codex-relay-workflow/internal/relay/dagsched"
_ "github.com/thisisjun786/codex-relay-workflow/internal/relay/integrate"
_ "github.com/thisisjun786/codex-relay-workflow/internal/relay/managed"
_ "github.com/thisisjun786/codex-relay-workflow/internal/relay/mergeturn"
_ "github.com/thisisjun786/codex-relay-workflow/internal/relay/routing"
Expand Down
1 change: 1 addition & 0 deletions contract/schema/relay-exit-codes.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
"CRITERIA_SET_CHANGED": "criteria_set_changed",
"UNKNOWN_CRITERION": "unknown_criterion",
"FINDINGS_REQUIRED": "findings_required",
"HEAD_NOT_RECEIPT_HEAD": "head_not_receipt_head",
"DUPLICATE_ASSIGNMENT": "duplicate_assignment",
"READBACK_MISMATCH": "readback_mismatch",
"SYNC_NOT_CLAIMABLE": "sync_not_claimable",
Expand Down
51 changes: 51 additions & 0 deletions docs/relay/dag-scheduler.md

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions internal/contract/exit_codes_generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions internal/contracttest/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
_ "github.com/thisisjun786/codex-relay-workflow/internal/relay/cli"
_ "github.com/thisisjun786/codex-relay-workflow/internal/relay/dag"
_ "github.com/thisisjun786/codex-relay-workflow/internal/relay/dagsched"
_ "github.com/thisisjun786/codex-relay-workflow/internal/relay/integrate"
_ "github.com/thisisjun786/codex-relay-workflow/internal/relay/managed"
_ "github.com/thisisjun786/codex-relay-workflow/internal/relay/mergeturn"
_ "github.com/thisisjun786/codex-relay-workflow/internal/relay/routing"
Expand Down
11 changes: 11 additions & 0 deletions internal/contracttest/dag_integrate_cli_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package contracttest

import "testing"

// The commit-acceptance and integration commands (CRW-965) are proved against the built crw, every case of
// testdata/fixtures/dag-integrate-cli-cases.json replayed through `crw relay`: each prints the stdout bytes and exit code its
// golden holds. The cases cover each new command's usage and absent-store refusal, the refusal family a host without a
// store answers before any git or verification runs.
func TestDagIntegrateCommands_the_built_crw_prints_its_frozen_answers(t *testing.T) {
replayCLICases(t, "dag-integrate-cli-cases.json", false, []string{"dag-integrate", "dag-integrate-push", "dag-integration-observe", "dag-accept"})
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
{
"integrate-missing-plan": [
{
"argv": [
"dag-integrate",
"--actor",
"parent",
"--checkout",
"/nonexistent/checkout",
"--integration-ref",
"dev-int",
"--base",
"dev",
"--verify",
"true"
]
}
],
"integrate-absent-store": [
{
"argv": [
"dag-integrate",
"--plan",
"p",
"--actor",
"parent",
"--checkout",
"/nonexistent/checkout",
"--integration-ref",
"dev-int",
"--base",
"dev",
"--verify",
"true"
]
}
],
"push-missing-checkout": [
{
"argv": [
"dag-integrate-push",
"--checkout",
"/nonexistent/checkout",
"--integration-ref",
"dev-int",
"--remote",
"origin",
"--remote-ref",
"dev"
]
}
],
"push-missing-remote": [
{
"argv": [
"dag-integrate-push",
"--checkout",
"/nonexistent/checkout",
"--integration-ref",
"dev-int",
"--remote-ref",
"dev"
]
}
],
"observe-absent-store": [
{
"argv": [
"dag-integration-observe",
"--plan",
"p",
"--node",
"a",
"--actor",
"parent"
]
}
],
"accept-commit-absent-store": [
{
"argv": [
"dag-accept",
"--plan",
"p",
"--node",
"a",
"--actor",
"parent",
"--commit",
"0123456789abcdef0123456789abcdef01234567",
"--base",
"0123456789abcdef0123456789abcdef01234567",
"--verification",
"/nonexistent/record.json"
]
}
]
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
18 changes: 18 additions & 0 deletions internal/relay/argparse/specs.json
Original file line number Diff line number Diff line change
Expand Up @@ -907,6 +907,10 @@
{"flag":"--repository","help":"an implementation node's pull request repository (owner/name)"},
{"flag":"--pull-request","type":"int","help":"an implementation node's pull request number"},
{"flag":"--supersedes","help":"the active acceptance of another output this one replaces"},
{"flag":"--commit","help":"an implementation node accepted without a pull request: the commit that is the receipt head of its generation (full lower-case hex). Needs --base, --checkout and --verification; not with --repository or --pull-request"},
{"flag":"--base","help":"with --commit: the commit the head must descend from"},
{"flag":"--checkout","help":"with --commit: an absolute path to the local checkout that holds both commits"},
{"flag":"--verification","help":"with --commit: the verification-record/1 document (JSON or @file) that names this commit tree with a PASS it may reuse"},
{"flag":"--rule-version","required":true,"help":"the rules the result was verified under, {skills_digest, model, effort} as JSON or @file"},
{"flag":"--expect-epoch","type":"int","help":"the coordinator epoch this session holds (dag-coordinator-claim answers it); a write from another epoch is refused stale_coordinator_epoch. 0 names none, which only a plan nobody claimed takes"}]},
{"name":"dag-integration-observe","summary":"records whether an accepted implementation node's head is contained in the branches it has to land on, read by the relay itself (git merge-base --is-ancestor for a local checkout, the compare API for a forge repository). Integration needs every required target to contain the head and the parent's merged mark on the same revision; the node's slot is returned when it does. A landing also runs the conflict sweep it owes (conflict_sweep in the answer), once per landing","options":[
Expand All @@ -915,6 +919,20 @@
{"flag":"--actor","required":true},
{"flag":"--target","kind":"append","help":"repository@ref to observe (repeatable); the targets of the node's outgoing edges by default. A terminal node needs it"},
{"flag":"--expect-epoch","type":"int","help":"the coordinator epoch this session holds (dag-coordinator-claim answers it); a write from another epoch is refused stale_coordinator_epoch. 0 names none, which only a plan nobody claimed takes"}]},
{"name":"dag-integrate","summary":"merges the plan's ready accepted implementation candidates (or the named --node ones) one after another onto a local integration branch with merge commits, runs one verification (--verify, split into arguments, never a shell) on the merged tree, and moves the branch only to a tree whose verification record is a PASS. A candidate whose merge conflicts or whose verification breaks is left out and returned in split. The branch moves by a compare-and-swap on its old head, so a head that moved under the command is refused. On success the parent's merged mark is recorded for each merged candidate; integration is then observed by dag-integration-observe --target on the integration branch","options":[
{"flag":"--plan","required":true},
{"flag":"--actor","required":true,"help":"the parent running the batch"},
{"flag":"--checkout","required":true,"help":"an absolute path to the local checkout that holds the candidates' commits and the integration branch"},
{"flag":"--integration-ref","required":true,"help":"the local branch the batch merges onto"},
{"flag":"--base","required":true,"help":"the branch the candidates descend from, read in the same checkout"},
{"flag":"--verify","required":true,"help":"the one verification run on the merged tree, a command split into arguments (no shell); it runs in the merged worktree with CRW_VERIFY_RECORD (a fresh path to write a verification-record/1 to), CRW_VERIFY_BASE and CRW_VERIFY_HEAD in its environment; a non-zero exit is a failure"},
{"flag":"--node","kind":"append","help":"a candidate to consider (repeatable); none means every ready accepted candidate of the plan"},
{"flag":"--expect-epoch","type":"int","help":"the coordinator epoch this session holds (dag-coordinator-claim answers it); a write from another epoch is refused stale_coordinator_epoch. 0 names none, which only a plan nobody claimed takes"}]},
{"name":"dag-integrate-push","summary":"moves the remote branch to the integration branch's commit by a fast-forward only: nothing is pushed when the remote already holds that commit (up_to_date), when the remote holds a commit the integration branch does not contain (refused merge_base_mismatch), or never by force. When the remote cannot be reached the push is deferred (outcome deferred, exit 0) and the integration recorded by dag-integrate stands; run this command again later to make the push","options":[
{"flag":"--checkout","required":true,"help":"an absolute path to the local checkout that holds the integration branch"},
{"flag":"--integration-ref","required":true,"help":"the local integration branch whose commit is pushed"},
{"flag":"--remote","required":true,"help":"the remote name, for example origin"},
{"flag":"--remote-ref","required":true,"help":"the remote branch to fast-forward, for example dev"}]},
{"name":"dag-base-refresh","summary":"records that an accepted implementation node's acceptance also stands on a later generation of its relationship that only refreshed the base: the relay reads the pull request head from the forge and the base tip from the target, and proves in a local checkout that the head is the accepted head plus merges of the base branch (each merge a two-parent commit whose tree is the tree git merges from its parents; a merge git cannot do cleanly is accepted only when the commit differs from git's tree in the files git could not merge, and files not proved by the node's declared mechanical rule must be named exactly with --resolved). The acceptance is not replaced; integration is then judged on the refreshed head and the merged mark of that generation. A stale node, a landed node and a head that holds anything but base merges are refused","options":[
{"flag":"--plan","required":true},
{"flag":"--node","required":true},
Expand Down
Loading
Loading