Repository navigation
Pipeline Roles Finalizer
The merger, reimagined as the finalizer (proposed: finalizer-role). The sections marked "today" describe the merger as built; the proposed sections replace them.
Draft from integration c1797bd (2026-10-16). It describes today's code; adjust it as the split settles. Index: Pipeline roles.
The finalizer takes an issue that is reviewed and approved, merges the base into its branch, retests it, and then either sends findings back to the implementor or merges and closes the PR (Axlog, 2026-10-16: "The merger should be reimagined as the "finalizer". It does the merge, retests, and kicks back findings to the implementor or merges and closes the PR").
- It runs no model session and repairs nothing. A conflict or a failed retest becomes a finding for the implementor.
- It takes over the implementor's
syncstage: bringing the branch up to date with the base now happens here, once, right before the merge. After implementation, this rebase is the only sync. The implementor syncs only at the start of its entries, before any edit (sync-at-edges). - The security review runs again on the merged head, as the last check before landing (
final-security-review), unless that head's tree is the one the security review last passed (security-skip-unchanged). The finalizer hands off to the reviewer for it and lands only the head it passed. A base that moves after that review sends the issue back to the merge. Deferred (roles-6-10-scope): for now there is no final security review, and the finalizer only syncs, merges and reruns the tests. - It publishes the issue's wiki commits, closes the issue and any finished parent, and frees closed issues' local resources, as the merger does today.
- It is the only role that holds merge credentials. It also pushes the rebased branch. Neither token reaches a model, because it runs no session.
Today (the merger): it lands a change that every check and review has passed, and finishes the issue. It squash-merges the verified head in merge order, publishes the issue's wiki commits, closes the issue and any finished parent, and frees closed issues' local resources.
-
Stages:
merge(stages/merge.ts,merge-wiki.ts),publish(stages/publish.ts), and the sweep's closing steps for parents (stages/parents.ts) and cleanup (stages/cleanup.ts). -
Ops:
-
merge(src/ops/merge.ts,merge-order.ts); -
finish-wiki,close-parent(src/ops/finish.ts); -
wiki-sync,finish-wiki-sync,publish(src/ops/publish.ts,src/wiki-publish.ts); -
wiki-checkbefore the merge; -
cleanup(src/ops/cleanup.ts).
-
-
Sessions: none of its own. The wiki conflict resolver (agent
issue-pipeline-writer) runs insidemergeandpublishtoday. It replies withCIFIX_SCHEMA, given in Implementor. Proposed (merge-only-when-ready): it moves to the spec writer, and the merger runs no session. -
Job role:
mergerfor merge and publish. ItstokenEnvtoken goes to ops, never to a model. Proposed (finalizer-role):mergerforfinalizeandpublish, with push access toagent/*branches added for the rebase, since no session runs.
Built first (roles-6-10-scope): the finalizer runs today's merge stage, and publish stays as it is. In order, it applies today's merge gate, waits in merge order (step 3 of finalize below), and rebases a branch that is behind (step 4). A clean rebase is pushed and retested in the same job (step 5), and the issue merges once the retest passes, as today's testsOnly path does. A rebase conflict saves the issue at sync, and a failed retest at checks, so the implementor handles them as today. It then handles the wiki as merge does today, merges, and finishes as step 4 of land describes. Deferred: finalize and land as stages, the conflict and retest findings, the final security review, the ready check and the returns for missing verdicts.
The finalizer has three entries: finalize, land and publish. Each is a linear script, not a state machine (role-state-machines), on the shared runner. Wiki access: write, in the job's docs/, at the issue's wiki branch, used only by wiki-sync and publish, which are ops, and by the wiki conflict resolver. Code access: read, in repo/: merge and publish run as merger, so pipeline_commit refuses a repo/ path there (#338). No session commits, and the finalizer runs no session: the final security review is the reviewer's, between finalize and land.
Stage finalize replaces today's sync and merge. The reviewer's first security pass saves the issue at finalize.
The security review runs again as the last check, on the merged head (Axlog, 2026-10-16: "The security review should happen again as the final step after the merge. If a conflict occurs after the security review, the process returns to the merge."). So the order is: merge the base in, retest, final security review, land.
finalize (merge the base in and retest)
- Claim the issue, and check out the PR's head and the issue's wiki branch.
- Ready check (script, below): the issue is reviewed and approved at the PR's head. A missing verdict posts a note and returns the issue to the stage that gives it (Returns for missing verdicts, below).
-
Wait: merge order, or a stacked prerequisite that is still open. A
queuedreply saves and waits. -
Merge the base in: rebase the branch onto the base (
sync-base), or onto the base once a stacked prerequisite has merged. A branch that already contains the base's head skips the rebase.- Clean: push with
--force-with-leaseto the head the ready check saw. - Conflict: abort the rebase, and send a
conflictfinding to the implementor (below).
- Clean: push with
-
Retest the new head: setup, the test command (twice, as
verifyruns it: as the branch has it, and with the spec writer's tests as atspecTestsSha), lint, typecheck and the lockfile check, then CI at the head (ci-status). A head that is alreadyverifiedShawith CI green skips this.- Pass: record
verifiedShaat the new head. - Failure: a
retestfinding, with the failing output, to the implementor. - CI pending: end
held, and the next start carries on from the pushed head.
- Pass: record
-
Wiki: with wiki commits,
wiki-syncandwiki-check. A conflict or failed check returns the issue to the spec writer, the wiki's writer (see Open questions). -
Hand off: save the issue at
final-security, withmergedSha(the retested head) andmergedBaseSha(the base head it contains). The reviewer's final security review runs next.
final-security (the reviewer's; see Reviewer): the security reviewer reviews the merged head, unless its tree equals securityTree, the tree the security review last passed (security-skip-unchanged); a skip records finalPassedSha and saves at land with no session. A pass records finalPassedSha, securitySha and securityTree, and saves at land. Findings go to the implementor at fix, as security findings do today, and the issue comes back through checks, accept, security and finalize.
land
- Claim, and read the PR's head and the base's head from GitHub. No checkout is needed.
-
Still current? The PR's head must be
finalPassedSha, and the base's head must still bemergedBaseSha(or contained in the branch).- Base moved, or the merge reports
behindorconflict: the process returns to the merge. Save atfinalize, which rebases, retests and sends the issue through the final security review again. At mostmaxSyncstimes per issue, then stop. - PR head moved: a missing verdict; return to
finalize, whose ready check routes it.
- Base moved, or the merge reports
-
Merge: mark the draft PR ready, then squash-merge with
--match-head-commitatfinalPassedSha. GitHub closes the PR. -
Finish:
publishthe wiki commits (or save atpublishif that failed), close the issue when the base isn't the default branch,close-parent, runcommands.teardown, remove the worktree and branches, labelagent:merged, and release.
publish
-
wiki-sync. A conflict returns the issue to the spec writer, which rebases the wiki branch and saves the issue back atpublish. -
publish, then finish as in step 4 ofland.
First and final security review (decided: security-skip-unchanged, Axlog, 2026-10-17): both reviews stay, and each runs only when the code changed since the security review last passed: when the head's tree differs from securityTree. The first review sends findings back before acceptance and the merge-order wait. The final review then runs on the merged head only when merging the base in changed the tree. When the branch already contained the base, the merged head's tree is the one the first review passed, and the final review is skipped.
Merge order and the final review: the merge-order wait comes before the rebase, so only the issue at the head of the queue spends a final security review. A merge into the base by someone else can still move it. That returns the issue to finalize, as above.
Locate (proposed: every-role-resumes)
Every start runs the steps in order. The ready check and the up-to-date check skip what is done: a branch that already contains the base's head isn't rebased again, and a head equal to verifiedSha with CI green isn't retested. Each step that changes GitHub checks first whether it is done (Shared): merge whether the PR is merged, publish whether the wiki's base holds the issue's wiki commits, closing the issue whether it is closed, branch deletion whether the branch exists. Merge order holds across a restart, since --merge-queue is in the job's arguments. An interrupted rebase or wiki-sync starts over from the pushed heads, and an interrupted retest runs again.
No work (proposed: no-work-skips-stages)
-
finalize(todaymerge): a PR already merged by hand gets the bookkeeping and no merge, as today. A wiki-only change goes throughfinish-wiki, as today. An issue already closed with no PR left to merge is released, with nothing done. -
publish: no wiki commits ahead of the wiki's base means there is nothing to publish. The issue is finished without a push.
cleanup of other closed issues stays with whatever runs each sweep (today the sweep's entry; see the orchestrator's open questions).
The finalizer reads these, but trusts none of them just because the issue is at finalize: the ready check tests each against the PR's current head.
- Proposed: from the reviewer, at
finalize: a security review with no finding, andpassedSha. - From the reviewer, at
merge:passedShaafter a security review with no finding. - From the implementor, at
merge: a clean rebase of a passed head that re-ran its tests (testsOnly). -
verifiedSha,verifySummary,flows,stackedOn, and no open blocking finding. - From the orchestrator, optionally: its ranked merge queue (
--merge-queue).
-
Merged: the PR squash-merged into the base at
verifiedSha, a signed merger comment, the code branch deleted, the wiki commits published, the issue closed (when the base isn't the default branch) and labelledagent:merged, its claims closed, the state atdone. -
Wiki only:
finish-wikipublishes the wiki commits and closes the issue as merged, with no PR merge. -
Waiting: stays at
mergewhen queued behind another issue or a stacked prerequisite. -
Back to the implementor:
syncwhen the branch is behind or conflicts, keepingpassedShaso a clean rebase re-runs only the tests. -
Findings (proposed): a
conflictorretestfinding saved for the implementor, the issue atfix, a signed note on the PR, andfinalizeReturnscounted. -
Returns for missing verdicts (proposed): a signed note on the PR and the issue saved at the stage that gives the verdict, with
finalizeNotein its state andfinalizeReturnscounted. -
At
publish: code merged but the wiki commits not yet published. -
Stops:
merge-refused,wiki-check,conflict,budget, a security category orerror. Proposed: onlymerge-refused(what no earlier stage can fix),finalize-returns(new, past the limit),maxSyncsreached,budgetanderror; the rest become findings or returns.
Deferred (roles-6-10-scope).
The finalizer works only on an issue that is reviewed and approved (Axlog, 2026-10-16: "The merge should operate on approved and reviewed."). A script checks, before any other step, reading GitHub, git and the issue's state and never a model. At the PR's current head:
-
there is a PR, open, for
agent/issue-N(none needed on the wiki-only path); -
reviewed: the head's diff was reviewed (
reviewedSha, through the fix rounds), or the head's changes have the patch id the review passed (reviewedPatchId,review-keeps-on-clean-rebase), and no blocking finding is open; -
approved: acceptance passed at the head (
acceptedSha) or at changes with the same patch id (acceptedPatchId), and the security review passed at it (passedSha; it keeps its own rule,security-skip-unchanged).
Being up to date with the base, the tests and CI aren't part of the check: the finalizer brings the branch up to date and retests it itself.
- The finalizer rebases onto the base (today's
sync-base, moved from the implementor). For a stacked issue it waits while the prerequisite is open, and rebases onto the base once it has merged. - Proposed (
sync-at-edges): this rebase, after the merge-order wait, is the only sync after implementation. No sync runs after a review clears, and none while an implementor entry runs. The implementor's other syncs come at the start of its entries, before any edit. Only returns tofinalizecount towardmaxSyncs. The implementor's start syncs don't. - A clean rebase keeps the verdicts. The diff from the base is the reviewed and approved diff, so only the retest runs, as today's
testsOnlyrule does. Built today (review-keeps-on-clean-rebase, #394): the review and acceptance stand on the changes' patch id, so a restart after a clean rebase keeps the review and an acceptance at changes with the patch id it passed runs no session, while the security review still runs when the tree changed. A rebase that conflicts is aborted; the finalizer never resolves it. - The retest is today's
verify, minus the fails-before-fix check, plus CI at the new head. A pass recordsverifiedShaat the head the finalizer will merge. - A head that already contains the base's head and equals
verifiedShawith CI green skips both.
A conflict or a failed retest is a finding, saved with the issue's findings and sent to the implementor at fix:
-
conflict: the base's head, the conflicting files and commits. Thefixentry's start sync does the rebase, and the implementor's conflict resolver resolves it there, before any other edit (sync-at-edges). -
retest: what failed (a test, lint, typecheck, the lockfile, a CI check), with its output clipped. The implementor's CI fixer handles it.
The finalizer posts a signed note on the PR naming the findings, marked <!-- issue-pipeline:<issue>:finalize-note:<n> -->, and counts the return in finalizeReturns (a checkpoint). Code the implementor changes then goes through its checks, the check-fix review, accept and security again, as a resolved conflict or a check fix does today, and comes back to finalize.
Deferred (roles-6-10-scope).
When the ready check finds something missing, the finalizer posts the same kind of note, saves finalizeNote: { missing, detail, sha, stage } (which the receiving role's task includes), counts the return in finalizeReturns, and saves the issue at the stage that supplies it, for the first missing item in this order:
| Missing | Back to | Role |
|---|---|---|
| no open PR (none was ever opened) |
spec, whose open-pr step opens it |
spec writer |
| a PR a person closed | none: stops with merge-refused, since closing is a person's call |
|
| an open blocking finding | fix |
implementor |
| head's diff not reviewed | review |
reviewer |
| acceptance not passed at the head | accept |
reviewer |
| security review not passed at the head | security |
reviewer |
wiki commits conflict with the wiki's base, or fail wiki-check
|
spec (a wiki-sync entry, see Spec writer) |
spec writer |
- Each receiving role's own locate and no-work checks carry the issue forward again, back to
finalize. - Past
maxFinalizeReturns(proposed: 3 per issue, findings and missing verdicts together), the finalizer stops withagent:stopped-finalize-returns, the notes listing every return. - A refusal no earlier stage can fix stops with
merge-refusedand a note on how to fix it: branch protection that requires an approval the pipeline can't give, or a PR a person closed. - Waiting in merge order or on a stacked prerequisite isn't a return.
- A network failure defers to the next sweep, as today.
- An open blocking finding stops the merge before any launch. An open security finding stops with its category as the code; any other with no code. Proposed: a return to
fix. - The merge request carries the state and the checks' summary. The summary notes a verdict given before a clean rebase.
-
mergerefuses, changing nothing:- a closed PR, with its state;
- a PR whose head moved from
verifiedSha, with the new head (proposed: the finalizer retests the head instead); - a conflicting PR, as
conflict; - a PR GitHub calls
BEHIND, a refusal "Base branch was modified", or a verified head that lacks the base's latest commit (checked locally), asbehind.
- A PR merged by hand gets the merge bookkeeping and no merge.
- A draft PR is marked ready before the merge. Proposed (
spec-writer-opens-pr): every PR is still a draft here, since no earlier role marks it ready, so this step always runs.mergeAdminmerges with--admin. A refusal for want of an approval says so and how to fix it. - No approving review is ever needed: GitHub doesn't count a PR author's approval, and the pipeline's account is the author. Branch protection on the base should require CI but not an approval, or let the account bypass it (
mergeAdmin). - The behind check runs locally as well as on GitHub, because without branch protection GitHub would merge a stale branch.
The finalizer keeps this order. Weighing re-check cost, such as merging the issue with the dearest checks first, is deferred (roles-6-10-scope).
- With
mergeOrder: trueand no queue, the older PR merges first: another openagent:workingissue at accept, security or merge with an older PR makesmergereplyqueued. Issues at sync or checks, stopped issues, newer PRs, unreviewed issues and expired leases don't hold the line (#358). - The order is total, so two issues never wait on each other. It exists so a slow issue's verify stops losing merge races to quick issues, each loss costing one of its
maxSyncs. - The order is opt-in (
mergeOrder: true), so a sweep running an older copy of the workflow is unaffected. - With the orchestrator's
--merge-queue(issues ranked by how many waiting issues they unblock),mergewaits only for an issue ahead of it in that queue that is open, not stopped and at accept, security or merge; one at sync or checks doesn't hold it (#358). - A stacked issue isn't ranked while its prerequisite is open, so it neither heads the queue nor holds another merge.
- A stacked issue replies
queuedwhile its prerequisite is open, naming it inwaitingForandstackedOn, with its PR inwaitingForPr(0 when it has none), with or without a queue. Once the prerequisite merged, it repliesbehinduntilsync-baseunstacks it. The wait usesstack.ts's one merged rule (prereqMerged, throughstackedQueuedinsrc/ops/merge-order.ts), and doesn't depend onmergeOrder. - A queued merge notes the wait once and stays at
mergefor the next sweep, costing only ops calls.
-
mergesquashes with--match-head-commitset toverifiedSha, posts a signed merger comment, and finishes the issue. - A rebased head that changed goes through verification and acceptance again, but not the first review. A clean rebase of a head that passed every check, acceptance and the security review (a lost merge race) re-runs only the tests (setup, the test command and the lockfile check, skipping
fails-before-fix) and then merges. A resolved conflict or a check fix changes code, so every check runs again. -
behindsends the issue back tosyncin the same sweep, once, keeping its passed head. A secondbehindin one sweep, and aconflict, wait atsyncfor the next sweep. All of this counts towardmaxSyncs. Proposed (finalizer-role): the finalizer rebases and retests itself, and only a conflict goes to the implementor, as a finding. - A network failure defers to the next sweep. Any other failed merge step, or a refused merge, stops the issue.
- A repo's wiki is on when its config has
wiki: trueor{ dir, branch, url }. A repo whose wiki doesn't exist yet is skipped; GitHub creates the wiki repo only when its first page is made in the browser. - With a wiki,
mergefirst rebases the issue's wiki commits onto the wiki's latest version (wiki-sync) and checks them (wiki-check). A failed check stops the issue withagent:stopped-wiki-checkbefore the merge. Without a wiki, it merges at once. - Proposed (
merge-only-when-ready): a wiki conflict or a failedwiki-checkreturns the issue tospec, and the finalizer runs no session. Today: a failed check stops the issue, and a wiki conflict goes to the conflict resolver in the wiki checkout. A resolved conflict goes on to the check without counting a sync. A rejected resolution stays atmergefor the next sweep. A conflict after the last resolution (maxConflictFixes) stops asconflict. - A merge whose wiki commits were not published moves to
publish.publishrebases them again, pushes, and finishes the issue. A conflict goes to the resolver and publishes again; a second conflict in one sweep waits for the next. A failed publish stops; one on the network defers. Nothing is saved as a patch. - A wiki-only change (
flows) finishes throughfinish-wiki: it deletes the code branch, publishes the wiki commits, closes the issue with a comment listing them, and labels itagent:merged.
- PRs merge into the configured
baseBranch, which may differ from the default branch. project-buddy's isintegration, nevermain: production runsmain, which onlyscripts/deploy.shmoves. Merging is never a release, and the merger never touchesmain. - GitHub closes an issue from "Closes #N" only when the PR merges into the default branch. So after a merge into another base, ops closes the issue itself with a comment naming the PR. An issue already closed isn't closed again.
- Not enforced today: the second step of an expand-then-contract migration must not merge into
integrationuntil the first step is live in production. -
close-parentcloses a split parent once every sub-issue is closed and at least one merged (closed as completed, or labelledagent:merged), and names the open ones otherwise. It closes the parent first, then relabels it, then comments, so a failed close leaves no comment. The orchestrator runs the same code each tick (#378). - After a merge or split, the issue's worktree and branches are deleted, and the config's optional
commands.teardownruns in the issue's run dir to free what setup made elsewhere. - Each sweep's
cleanupremoves a closed, unclaimed issue's worktree, branches and teardown resources once nothing local is unsaved, holding<clone>.lockfor one issue at a time. It keeps an open or stopped issue, a live claim, uncommitted changes, commits not on GitHub, unpublished wiki commits, and the sweep's own issue. A failed cleanup is reported in the summary, never thrown.
- Every requirement above has a test at one of the interfaces below, and
mise //apps/issue-pipeline:checkpasses. - The role's stages and ops live in modules the other roles don't import, apart from the shared parts the index lists.
- No model session runs with the merger's token.
--print-boundaryfor merge and publish shows rolemerger, networkapi.github.com, and no model session getsGH_TOKEN. - A merge can only land
verifiedSha, and only with no open blocking finding. - Proposed: a merge lands only a reviewed and approved diff, rebased onto the base's head and retested there. A conflict or failed retest always ends as a finding for the implementor, and a missing verdict as a return to its stage, never as repair work by the finalizer.
- Proposed:
finalizeandpublishlaunch no model session. - Every merged issue ends closed, labelled
agent:merged, with its branch deleted and its wiki commits published or waiting atpublish. - The wiki's
merge-by-script,merge-orderandwiki-docssections describe the role as built.
-
Step machine:
nextfromstages/merge.tsandstages/publish.ts, withworkflow-finish-test-kit.mjs(stateWith,contextWith,VERIFIED,replied). -
Built sweep:
runWorkflowwith an issue claimed atmergeorpublish, scriptingmerge,wiki-sync,wiki-check,publish,finish-wiki,close-parentandcleanupreplies, andargs.mergeQueue. Assert withopsRequests,requestForandreleasedState. -
Ops CLI:
-
merge:runOpsagainstops-test-kit.mjs(world,finishReplies,finishWrites,advanceBase) and the fakegh, asserting the exact gh writes and comments. - wiki ops:
runOpsagainstwiki-test-kit.mjsrepos, checking the wiki remote's branches. -
cleanup:runOpsagainstops-test-kit.mjs(world) worktrees.
-
-
Stage job:
runJobwith--stage mergeand--print-boundary, asserting the merger boundary and that no pi session gets the merger's token. -
Orchestrator: the merge queue's ranking in
src/orchestrator/queue.tswithorchestrator-fixtures.mjs.
| Requirement | Interface | Case | Today |
|---|---|---|---|
| Ready (new) | runner, fake gh, local git |
an issue reviewed, accepted and security-passed at its head goes on to rebase, retest and merge; nothing else is required of it up front | none yet |
| Up to date and retested (new) | runner, local git, fake gh
|
a branch behind the base is rebased, pushed and retested before the merge; one already current with green CI at verifiedSha is merged with no rebase or retest |
none yet |
| Conflict to the implementor (new) | runner, local git | a conflicting rebase is aborted, a conflict finding saved, the issue at fix, one marked note |
none yet |
| Retest failure to the implementor (new) | runner, fake verify and CI |
a failing test, lint, typecheck, lockfile or CI check becomes a retest finding with its output, and the issue goes to fix
|
none yet |
| Hands off to the final security review (new) | runner, local git | a clean rebase and retest save at final-security with mergedSha and mergedBaseSha
|
none yet |
| Land when current (new) | runner, fake gh
|
at land, a PR at finalPassedSha with the base still at mergedBaseSha merges at that head |
none yet |
| Lost merge race returns to the merge (new) | runner, fake gh
|
at land, a moved base or a behind or conflict refusal saves at finalize; the rebase, retest and final security review run again; past maxSyncs it stops |
none yet |
| Each missing verdict returns (new) | runner, fake gh, local git |
one row per table row: the item missing sends the issue to its stage with one marked note and finalizeNote saved; several missing return for the first in order |
none yet |
| Return limit (new) | runner | the return past maxFinalizeReturns, findings and missing verdicts counted together, stops with finalize-returns
|
none yet |
| Not fixable (new) | runner, fake gh
|
a person-closed PR and an approval requirement stop with merge-refused and a how-to note |
none yet |
| No session (new) | stage job |
finalize, land and publish launch no model session, a wiki conflict included |
none yet |
| Gate on findings | step machine, built sweep | an open finding stops before any launch; a security one names its category |
workflow-stages-merge-next.test.mjs, workflow-stages-finish-codes.test.mjs
|
| Merge request | step machine | carries state, summary and merge queue |
workflow-stages-merge-next.test.mjs, workflow-merge-queue.test.mjs
|
| Refusals | ops CLI | closed, moved head, conflict, behind (three ways), approval hint | merge-op.test.mjs |
| Merged by hand | ops CLI | bookkeeping only | merge-op.test.mjs |
| Squash and finish | ops CLI | squash at the verified head, verdict recorded, issue finished |
merge-op.test.mjs, finish-ops.test.mjs
|
| Merge order | ops CLI | older PR at accept, security or merge holds; at sync or checks, stopped, newer, unreviewed and expired don't |
merge-op.test.mjs, merge-order-op.test.mjs
|
| Merge queue | ops CLI | queue ahead at accept, security or merge holds; at sync or checks, closed, stopped, unready don't | merge-queue-op.test.mjs |
| Stacked wait | ops CLI | waits for an open prerequisite; behind once it merged | merge-stacked-op.test.mjs |
| Outcomes | step machine, built sweep | queued stays; behind resyncs once; second behind and conflict wait; network defers |
workflow-stages-merge-next.test.mjs, workflow-stages-merge-resync.test.mjs
|
| Wiki at merge | step machine | rebase, check, merge; failed check stops; conflict to resolver; limits |
workflow-stages-merge-wiki-next.test.mjs, wiki-publish-ops.test.mjs
|
| Publish | step machine, built sweep, ops CLI | clean publish closes; conflicts; budget; network; no patch |
workflow-stages-publish-next.test.mjs, workflow-stages-publish.test.mjs, finish-merged.test.mjs
|
| Wiki only | step machine, ops CLI |
finish-wiki publishes, closes and labels |
workflow-stages-flows-next.test.mjs, finish-wiki-op.test.mjs
|
| Close parent | ops CLI, step machine | closes when all sub-issues closed; names open ones |
finish-ops.test.mjs, workflow-stages-finish-next.test.mjs
|
| Cleanup | ops CLI | removes only what is safe | cleanup-ops.test.mjs |
| Merger boundary | stage job | merger role, network, no model token |
job-roles.test.mjs, job-boundary.test.mjs
|
| Role isolation (new) | lint or unit | the role's modules import nothing from the other roles' modules | none yet |
| Kill anywhere (new) |
locate, runner, fake gh
|
killed before and after each step and started again, the finalizer ends as an uninterrupted run: rebased and pushed once per base head, merged once, published once, closed once | none yet |
-
Wiki conflict resolver: proposed (
merge-only-when-ready): a wiki conflict returns to the spec writer, the wiki's writer, so the finalizer has no model session. Or should it be a finding for the implementor like a code conflict, which would mean giving the implementor wiki write access? Open: whether the spec writer's wiki-sync entry is worth its own state, or the spec stage simply runs again from locate. - Final security review scope: the branch's diff against the new base, or that plus the base's changes since the first pass that touch the same files?
-
Rebase or merge commit: "does the merge" is proposed as a rebase onto the base, as
sync-basedoes today, then a squash merge. Merging the base into the branch would avoid force-pushes but adds merge commits that the squash discards anyway. - Migration order: should the finalizer refuse to merge the second step of an expand-then-contract migration until the first is live? Today it's only a rule people follow.
- Whether closing parents and cleanup belong here or in the shared sweep code.
- "Approved": proposed to mean the pipeline's verdicts (acceptance and security) at the head. Should it also, or instead, mean a person's approving review on GitHub?
-
maxFinalizeReturns: 3 per issue, or per head? And does aretestreturn count toward the implementor'sciFixRoundstoo?
The requirements above take in the wiki decisions this role follows, as of wiki f1b2944 (2026-10-16): merge-by-script, merge-order, stacked-branches, base-branch-may-differ-from-default, wiki-docs, wiki-flows, worktrees-and-branches, integration-branch (Decisions-Accounts). Once the specs are approved, prune-wiki-decisions deletes or trims the wiki sections the specs make redundant. From this split, not on the wiki yet: merge-only-when-ready, finalizer-role, final-security-review. From this split, on the wiki: sync-at-edges.