acpmux: a lane reports the end of each turn to the session that started it

Merged
TE
11d ago
+1272-18

A lane now tells the session that started it when each of its turns ends, the way a Claude subagent's parent hears when the subagent stops. The lane doesn't have to remember to acpmux send. The parent receives one short prompt per turn:

[NAME] lane report: turn N ended, STATE.
Session: ID
Last message: the first 400 characters of its last reply
Pull requests: URLs it opened or named, not reported before
Commits named: full SHAs in the reply

STATE is idle, working on its next prompt, waiting on a permission / waiting on a question: ..., or blocked: ... (a failed turn and the queue it paused, a stopped agent).

How it works (hub/lane_reports.rs, on the link from #25327):

  • A report is built when the lane's turn ends, from that turn's own transcript records (paged back to its turn_started) and the lane's state at that moment, and then queued. Delivery and retries send that queued report and never read the lane again, so a later turn can't leak into it. A turn that failed before its agent started reports no reply.
  • One delivery per lane is in flight at a time. If the parent refuses a report, it stays queued and goes at the next turn end. A newer turn's report replaces a queued one and keeps the pull requests only the older one named.
  • A report identical to the last one (state, reply, pull requests) isn't sent again. Each lane sends at most 20 reports per 10 minutes; past that, the newest is held until a later turn ends with the lane back under the cap.
  • A report goes in as a hub-set prompt with provenance {kind: "lane_report", from, fromName, to, turn, state}, as another agent's message (digest.rs; prompt_line.rs shows the lane's name). It counts toward the runaway pair guard (agent_pairs.rs), and a report into a paused pair is held for the person. A report never steers: it waits for the parent's turn to end.

This is part 2 of 3 split from #24365 (Leo: keep PRs under ~800 lines). It comes after #25327, which added the link. Part 3 adds the rule that a parent's turn spent only on reports doesn't report upward. Until it lands, a coordinator that is itself a lane also reports its turns on its lanes' reports. Tree depth, the 20-per-10-minutes cap and the pair guard bound that.

Observed / Not run

Observed at 240a9b5ad7600fbba48f9d8ed8ae2932fed70171 on huge-blue:

  • cargo fmt -p acpmux --check: clean.
  • cargo clippy -p acpmux --all-targets -- -D warnings: clean.
  • cargo test -p acpmux --test lane_reports: 11 passed (each turn reported once, the same report not sent twice, a PR named once, pair-guard hold and resume, the tag doesn't steer the link, a turn whose agent can't start reports blocked with no reply, back-to-back turns and the 20-in-10-minutes cap, a closed parent gets nothing, plus #25327's link tests).
  • cargo test -p acpmux --lib -- lane_reports: 5 passed (a held report's pull request still goes out, replacing a queued report, reading a 1,000-chunk reply from its turn's start, state wording, the closed-parent and mid-link-close cases).

Not run: the full acpmux lib and integration suites, and a live daemon with real harnesses.

Changelog

  • acpmux: a lane reports the end of each of its turns (state, the start of its last reply, the pull requests and commits it names) to the session that started it.

šŸ¤– Generated with Claude Code

Agent session: agent session


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.