| name | runner-synchronous-lifecycle |
| description | When the runner is about to return -- hold the invocation open until the full PR lifecycle is done (push, mark ready, CI watch, merge). Returning early orphans the work. |
Runner synchronous discipline
Your (the runner's) invocation must hold open until the full
lifecycle is done. Returning to the dispatcher signals "task
complete: PR is merged (or an exception was hit -- see exception
cases in runner.md)." Returning earlier orphans the work.
The anti-pattern this prevents
Original failure mode observed on the work machine (roba #104):
- Runner fires roba with
run_in_background=true
- Runner reports a summary and returns
- Dispatcher gets a "completed" notification for the runner
- roba is still running locally; the commit never gets pushed; CI
never starts; the dispatcher thinks the task is done when it
isn't.
Discipline that prevents it
-
The dispatch is fired synchronously (no run_in_background).
Your session blocks until the dispatch exits.
For Bash-based dispatch, set a generous timeout (harness max is
600000 ms / 10 min; pick what fits the task size).
-
CI watch CAN use run_in_background=true because the watch is
part of your runner's lifecycle and YOU wait for the notification
yourself before returning. The
dispatch-wait-react skill is
the operational guide for that wait.
-
Push, mark ready, merge are all within your session. Don't
hand them off to "the dispatcher will pick this up." The
dispatcher's expectation is that when your invocation returns,
the lifecycle is done.
What return-to-dispatcher means
When you DO return to the dispatcher:
- Success case (default): report PR number, merge commit hash,
any caller-actionable notes (live-test follow-up, surfaced gaps
in the issue spec, etc.). The PR is merged.
- Exception case: report PR number, why the exception applies
(no CI configured,
needs-review or no-auto-merge label on the PR,
review:manual constraint, critical/delicate label), and "PR #N ready;
awaiting manual merge."
- Failure case: report what failed, where (dispatch run? CI?
push conflict?), the failing job's URL if applicable, and your
read on whether this is refireable vs needs human decision.
The dispatcher's contract: "the runner returned" → "the lifecycle
is complete." If you return earlier than that, you've broken the
contract and the dispatcher will trust the wrong state.
Label-based exception cases
Two PR labels signal the runner to skip auto-merge and return "awaiting manual
merge" instead:
needs-review -- set by the dispatcher or issue author to require human
sign-off before merging.
no-auto-merge -- set by the runner (copied from the issue) or manually,
to signal that automated merging should be skipped regardless of CI status.
Check for these before calling gh pr merge:
LABELS=$(gh pr view $PR --json labels --jq '[.labels[].name] | join(",")' 2>/dev/null || echo "")
if echo "$LABELS" | grep -qE "needs-review|no-auto-merge"; then
echo "PR #$PR ready; awaiting manual merge (label: needs-review or no-auto-merge)"
fi
Related