Skip to content

Auto-merge requires the agent's setReadyForMerge signal (#1363) - #1392

Merged
suleimansh merged 1 commit into
mainfrom
worktree-issue-1363-merge-gate
Jul 30, 2026
Merged

Auto-merge requires the agent's setReadyForMerge signal (#1363)#1392
suleimansh merged 1 commit into
mainfrom
worktree-issue-1363-merge-gate

Conversation

@suleimansh

Copy link
Copy Markdown
Member

TLDR: an armed merge now runs only when the agent called setReadyForMerge() and its own session TODO file has no open entries. Push and PR are untouched; a withheld merge opens the PR as a draft and says why. The system prompt now makes the signal a required terminal action. Implements the rule settled on #1390 (fix #1363).

The two halves (they must ship together)

  1. The gatemaybeAutoHandoff withholds the merge unless (a) journal.sawReadyForMerge() (same signal the on-before-mergeable step already requires) and (b) TODO_<SESSION_NAME>.agent.md has no open entries. Never TODO_AGENTS.md: the global queue is decoupled from sessions, or auto-merge would never fire while any backlog exists.
  2. The prompt — the closing "consider whether … then call setReadyForMerge()" is now a required yes/no terminal action. Without this half, gating on the signal silently stops auto-merge on simple runs — live matrix row 3 (Which session endings run the auto handoff (push / PR / merge)? The verified matrix — and whether Stop-at-a-gate skipping it is the design we want #1363, run 00-21-32-410Z) merged 3s after the PR opened with the signal never emitted.

Built to be deleted

(b) is the temporary safety belt from #1390 — the agent's word should ultimately be enough. Deleting it = removing sessionTodoOpen from withheldMerge() and sessionTodoPending() in todo-loop.ts; both say so in their comments.

Visibility

A withheld merge is not a skipped handoff: the branch pushes, the PR opens (as a draft, since draft: !intent.merge), and the handoff event carries merge: { outcome: 'withheld', reason }. The transcript now renders every merge outcome — before this, a merged/withheld/failed merge was invisible in a dashboard transcript.

Tests

  • withheldMerge decision table (run-handoff.test.ts)
  • sessionTodoPending reads only the session file, ignores TODO_AGENTS.md, refuses path-escaping names (todo-loop.test.ts)
  • transcript lines for all four merge outcomes (events.test.ts)
  • Suites: the-framework 1637/0 (1 pre-existing skip), dashboard 655/655 (one PreviewBar flake on first run, clean on rerun)

Not yet done: a live matrix row (needs the main checkout's daemon — will dogfood after merge like rows 1–3).

@brillout this touches prompts/system_prompt.md — the new wording is the smallest change I could make that turns the suggestion into a required decision; rephrase freely.

🤖 Generated with Claude Code

Merge is now authorized, not just configured (rule settled on #1390):
an armed merge runs only when (a) the agent declared the session done
via setReadyForMerge() — mirroring the on-before-mergeable check — and
(b) the session's own TODO_<SESSION_NAME>.agent.md has no open entries
(a temporary safety belt, built to be deleted). The global
TODO_AGENTS.md queue never withholds: it is decoupled from sessions.

A withheld merge is not a skipped handoff — push and PR go ahead, the
PR opens as a draft, and the handoff event + transcript line say why
the merge did not run.

The system prompt's closing instruction becomes a required terminal
action, so agents reliably signal — without this, gating on the signal
would silently stop auto-merge on simple runs (live matrix row 3: the
daemon merged 3s after the PR opened, the signal never emitted).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
After you're done, consider whether <SESSION_NAME> is finished and there isn't any work left to do — if that's the case then call setReadyForMerge()
After you're done, decide: is <SESSION_NAME> finished, with no work left to do?
- Yes: call setReadyForMerge() — required, the work is never merged without it
- No: don't call it; say what's left instead

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good

@suleimansh
suleimansh marked this pull request as ready for review July 30, 2026 20:57
@suleimansh
suleimansh merged commit dd865d8 into main Jul 30, 2026
1 of 2 checks passed
@suleimansh
suleimansh deleted the worktree-issue-1363-merge-gate branch July 30, 2026 20:58
suleimansh added a commit that referenced this pull request Jul 30, 2026
Both PRs edited maybeAutoHandoff's neighborhood: the merge keeps the
#1363 merge gate and adds this branch's `fixes` ride-along beside it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
suleimansh added a commit that referenced this pull request Jul 31, 2026
…p the obsolete uncommitted-changes step

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
suleimansh added a commit that referenced this pull request Jul 31, 2026
* sync system_prompt.md from #326: issue edit left every PR's drift check red

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Apply suggestion from @brillout

Co-authored-by: Rom <git@brillout.com>

* re-sync from the corrected #326: keep the #1392 required wording, drop the obsolete uncommitted-changes step

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Rom <git@brillout.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Which session endings run the auto handoff (push / PR / merge)? The verified matrix — and whether Stop-at-a-gate skipping it is the design we want

2 participants