Add pane message delivery intent

Task 5521 · Done · Coder · created · updated

Epic: Merge lane — CP-scheduled verification queue, plan-gated. Planner Task 5517; the full PRD is BA Task 5515 and the full architecture is Architect Task 5516. Read both with `task_read`. Principle (verbatim): "a runner never runs the full suite and never sees a failure it did not cause". ## Requirement (work item 5, the delivery clause, verbatim) "red → sequential bisect (merge the green first half, test the second half on the new base), post the failing tests on the culprit PR and deliver them to its runner's pane". The BA decided (D8, verbatim): "Failure delivery reuses the existing node → pane answer/message delivery. If the culprit runner's session is not live, the failure stays on the PR comment and the queue row (`failed`), and the task follows the existing broken-session path. The lane does not dispatch a new runner." This child builds the PANE-TEXT MECHANISM only. The lane core child (C3a) calls it when a row fails. ## Approach (architecture §4.6 and A4, settled) - Today only `deliver_answer` exists (`fleet_verdicts.py:71-74`). It is fenced to `awaiting_response` and sends `Escape` first (`apps/jaahd/answer_delivery.py:383-452`). Escape would abort a runner's in-flight `pr view` poll. - CP side: - Add `fleet_verdicts.build_deliver_message_intent(task_id: int, session_id: str, text: str) -> dict`, with verb `"deliver_message"` added to `SLOT_INTENT_VERBS`. - Factor the live-runner lookup that `routes/tasks.py::_deliver_answer_to_live_runner` uses into ONE helper that both callers use. The lookup is: the worktree whose `task_id` is the task, `state='task'`, and its recorded launch session id. - The helper returns nothing when the runner session is not live, so the caller mints nothing. - Expose a function the lane core calls, e.g. `deliver_message_to_live_runner(session, task_id, text) -> bool`. Keep that name and signature; C3a consumes it. - jaahd side: add an executor `_enact_deliver_message`. - It uses the same session fence and cwd check as `_enact_deliver_answer`. - It pastes and submits **without `Escape`**. Claude Code queues a message typed during a running tool. - It is NOT fenced to `awaiting_response`, because a polling runner is `active`. - Text frame (used by C3a; document it on the builder): `Merge lane: PR #<n> failed on <tree> — <tests…>\n<excerpt>\nFix it, push, and report the new head with task_pr_queue.` ## Acceptance (planner-numbered; this child carries no PRD AC of its own — it enables AC5.4's delivery clause) - M1 A `deliver_message` intent pastes and submits its text into the fenced pane and NEVER sends `Escape`. - M2 A wrong or stale session id, or a cwd mismatch, is refused by the fence. Nothing is typed into a pane that does not belong to that task's live session. - M3 When the task has no live runner session, the CP helper mints nothing and returns False. - M4 `deliver_answer` behaviour is unchanged (it still sends Escape and is still fenced to `awaiting_response`). Its existing tests pass unmodified. - M5 There is ONE live-runner lookup helper. `routes/tasks.py`'s deliver_answer path and the new message path both call it, and there is no second copy. Credentials & reach: none. Every oracle is a worktree-local unit test in `apps/api` and `apps/jaahd` (verified; no external reach). Out of scope: - Epic (verbatim): "GitHub merge queue / merge_group; any CP-side forge calls; changing the manual develop → master promotion; cgroup tuning of GHA runners; squash merges." - BA-derived (verbatim): "No change to the runner flow, guard, prompt, pool or CI when the flag is OFF (R0)." - Do NOT: - build queue rows or any lane logic; - dispatch a new runner for a dead session (D8); - change `deliver_answer`'s semantics. Done means: - M1 — a jaahd executor test with a fake tmux/pane driver asserts the key sequence contains the pasted text plus submit, and no `Escape`. - M2 — executor tests assert a mismatched session id and a mismatched cwd each refuse, with nothing sent. - M3 — a CP test with a task that has no live worktree session: the helper returns False and no intent row or payload is minted. - M4 — the existing `deliver_answer` tests (CP and jaahd) pass unchanged; `git diff` shows no edits to their assertions. - M5 — a grep shows the lookup query in exactly one function, referenced by both callers. Required checks: gate, review-lane

Outcome

Added deliver_message pane intent (no Escape, session+cwd fenced) and live_runner.deliver_message_to_live_runner with one shared live-runner lookup. Full gate green; PR #4810 merged, Jaah Deploy succeeded. Also regenerated stale jaah-api reference.

Pull request

Artifacts

Activity

  • Draft
  • Ready
  • Runner started
  • Runner ended (done)