Skip to content

feat(agents): seats tell their Captain how they ended - #150

Merged
bryantderosier merged 9 commits into
crews/05-fleet-page-and-expanderfrom
crews/06-seats-settle-and-notify
Sep 21, 2026
Merged

bryantderosier merged 9 commits into
crews/05-fleet-page-and-expanderfrom
crews/06-seats-settle-and-notify

Conversation

@bryantderosier

@bryantderosier bryantderosier commented Sep 15, 2026 •

Copy link
Copy Markdown
Collaborator

Crew seats report completed and failed runs to their Captain, including the state of a declared handoff.

When a member's run completes or fails and it owes no open reply, the platform posts one platform-composed notice into the Captain's thread (it settles nothing; upstream's settle rules apply to a seat as to any thread): the seat, how the run ended, and whether its declared handoff was written, missing, or never declared, with the handoff inline when short. A notice posts on first finish and again only when those facts change, and a notice arriving while the Captain's turn is running folds into the seat notice already queued behind it, so the Captain reads a digest in one turn rather than one turn per seat. Interrupted and cancelled runs are not finishes. Each notice names the seat's Crew, since one Captain may run several, and renders in the Captain's thread as a card: one row per seat with how the run ended and where its handoff stands, the handoff opening in the artifacts panel and readable inline when short.

Notice delivery is best effort: a failed passive notice is reconsidered on a later seat finish or server restart; an otherwise idle server does not promise an immediate retry. Sign-in and permission failures also create a durable human-inbox request, deduplicated by run and shared with the launch reporter. A written artifact is evidence of delivery, not a judgment that the handoff is correct or accepted.

t3_thread_wait leaves the J5 surface. Platform notices queue behind a running turn, so a turn that blocks on another thread can never receive the notice it is waiting for; a Captain on my dev server did exactly that and starved itself of ten queued notices. FORK.md case 2 now says the verb is deliberately absent.

Built with Claude Fable 5.1 in Claude Code.

Evidence

Finish notices as the Captain sees them: one seat alone and three folded into one card, each with its status, handoff type, artifact path, and the handoff behind a disclosure.

Seat finished cards

🤖 Generated with Claude Code

Review follow-ups implemented and verified with Codex in the Codex app.

Closes #206.

@github-actions github-actions Bot added the vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. label Sep 15, 2026
@bryantderosier
bryantderosier added this pull request to stack #153 September 15, 2026 21:36
@github-actions github-actions Bot added the size:L 100-499 effective changed lines (test files excluded in mixed PRs). label Sep 15, 2026
@bryantderosier
bryantderosier force-pushed the crews/06-seats-settle-and-notify branch from cbc86d4 to 730d270 Compare September 15, 2026 21:44
@bryantderosier bryantderosier self-assigned this Sep 15, 2026
@bryantderosier
bryantderosier force-pushed the crews/06-seats-settle-and-notify branch 2 times, most recently from faf4b42 to 233e3e4 Compare September 16, 2026 11:32
@bryantderosier
bryantderosier force-pushed the crews/06-seats-settle-and-notify branch from 233e3e4 to 902b6d1 Compare September 16, 2026 18:05
@bryantderosier
bryantderosier force-pushed the crews/06-seats-settle-and-notify branch from 902b6d1 to 51753ad Compare September 16, 2026 18:18
@github-actions github-actions Bot added size:XL 500-999 effective changed lines (test files excluded in mixed PRs). and removed size:L 100-499 effective changed lines (test files excluded in mixed PRs). labels Sep 16, 2026
@bryantderosier
bryantderosier force-pushed the crews/06-seats-settle-and-notify branch from 51753ad to f71657d Compare September 17, 2026 01:59

@Jacksondr5 Jacksondr5 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Settlement semantics check out: only completed and failed count as finishes, interrupted and cancelled are excluded and tested, owed replies are read from open Exchanges, and a notice arriving mid-turn folds into the queued one. The hook is a J5-owned subscriber on the stored-event stream, the same shape as the lifecycle and silence services, so no upstream seam.

On t3_thread_wait: the removal is clean. Upstream's toolkit is untouched, the J5 surface drops it in a J5-owned file, absence is asserted three ways (the FORK case 4 proof file, the surface test, the registration test), and no remaining instruction or doc text tells agents to wait. On delegate_task's wait mode: a child that messages its parent ends its own turn, so the wait returns and the parent reads the message next turn; latency, not starvation. Worth one sentence in agent-tools.md so nobody re-derives it.

Four notes on the settler, inline, none blocking on their own; the seat-name keying matters more now that one Captain runs several Crews.

Reviewed by Claude Fable 5.1 in Claude Code, with an independent pass by GPT-6-Astra in Codex.

Comment thread apps/server/src/j5/a2a/CrewSeatFinishNotifier.ts
Comment thread apps/server/src/j5/a2a/CrewMemberSettler.ts Outdated
Comment thread apps/server/src/j5/a2a/CrewSeatFinishNotifier.ts
Comment thread apps/server/src/j5/a2a/CrewMemberSettler.ts Outdated
@bryantderosier
bryantderosier force-pushed the crews/06-seats-settle-and-notify branch from f71657d to 17dbccc Compare September 17, 2026 03:24
@bryantderosier

Copy link
Copy Markdown
Collaborator Author

Four for four in 17dbccc90: notices keyed by participant, a handoff digest in the facts, the opening seat tag escaped, and the notice committing before the seat settles. The delegate_task wait sentence is in agent-tools.md.

@bryantderosier
bryantderosier force-pushed the crews/06-seats-settle-and-notify branch from 17dbccc to ee98bea Compare September 17, 2026 12:27
@bryantderosier

Copy link
Copy Markdown
Collaborator Author

You were right about settle. Upstream settles by hand, on a merged PR, or after idle days, and we were settling a seat the moment it finished, so a Crew read "2 settled" seconds after launch. In ee98beae4 the platform settles nothing: the notice to the Captain stays exactly as it was, the thread.settle dispatch is gone, and the machinery is renamed to what it does (CrewSeatFinishNotifier, <j5_seat_finished>). The state summary still counts a seat you settle yourself.

@bryantderosier
bryantderosier force-pushed the crews/06-seats-settle-and-notify branch from 67bf081 to 84317da Compare September 18, 2026 14:22

@Jacksondr5 Jacksondr5 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Round five. All five claims verified: the finish notice leads with the outcome and carries the run's recorded error; the notifier stays quiet about a launch failure the report covers, before watch, after the report posts, and after restart, proven with the real notifier; baseline and queued digest require system provenance; the silence detector suppresses only Captain-bound seat errors; later failures reuse the deduplicated alert by run receipt.

One shared defect, filed on #148 where the formatter lives: provider error text is interpolated raw into the line-oriented notice (runFailures.ts), so a multi-line provider message can inject field lines the web parser trusts, and ordinary multi-line diagnostics lose everything after the first line. The finish notice here uses the same formatter, so the writer-side encode fixes both.

Reviewed by Claude Fable 5.1 in Claude Code, with an independent pass by GPT-6-Astra in Codex.

@bryantderosier
bryantderosier force-pushed the crews/06-seats-settle-and-notify branch from 84317da to 16b812c Compare September 21, 2026 11:56
@bryantderosier

Copy link
Copy Markdown
Collaborator Author

The shared provider-diagnostic finding is fixed in this head and #148. Finish notices encode diagnostics before interpolation, then decode after field extraction. Regression tests preserve multiline diagnostics and prevent injected participant/thread fields from changing the card destination.

@bryantderosier
bryantderosier force-pushed the crews/06-seats-settle-and-notify branch from 16b812c to e07ee5e Compare September 21, 2026 12:16

@Jacksondr5 Jacksondr5 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Round six. The finish notice now encodes provider diagnostics before interpolation and decodes after field extraction, with the multiline, injected-field, and closing-tag tests in place. Verified by two independent passes.

One gap shared with #148 and filed there on the writer: the escape set covers ampersand, angle brackets, CR, and LF but not U+2028 and U+2029, and the multiline regex that extracts fields treats those as line boundaries. Both reviewers reproduced a spoofed participant and thread from a diagnostic containing the line separator, and on this side the dedupe baseline keys by the parsed participant, so a real seat's earlier notice is not found. One character class at the writer, two code points at the decoder.

Reviewed by Claude Fable 5.1 in Claude Code, with an independent pass by GPT-6-Astra in Codex.

@bryantderosier
bryantderosier force-pushed the crews/06-seats-settle-and-notify branch from e07ee5e to 95dfed1 Compare September 21, 2026 14:16
@bryantderosier

Copy link
Copy Markdown
Collaborator Author

The shared escape gap is fixed at the writer in #148 (2e2ba0894) and in the decoder both parsers use; the finish notifier test now carries a U+2028 in the diagnostic and asserts the encoded field. This head is 95dfed148.

bryantderosier and others added 9 commits September 21, 2026 11:07
When a Crew member's run completes or fails and it owes no open reply, the platform settles its
thread and posts one platform-composed notice into the Captain's thread: the seat, how the run
ended, and whether its declared handoff was written, missing, or never declared, with the handoff
inline when short. A notice posts on first finish and again only when those facts change, and a
notice arriving while the Captain's turn is running folds into the seat notice already queued
behind it, so the Captain reads a digest in one turn. Interrupted and cancelled runs are not
finishes. t3_thread_wait leaves the J5 surface: a turn that blocks on another thread cannot receive
the notices that queue behind it, and a Captain that waited on a seat starved itself of its own
Crew's news. The Fleet page and the sidebar expander summarize seat state from the same facts.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A seat's <j5_seat_settled> notice reached the Captain's thread as raw tagged text, one block per
seat when several folded into one message. It now renders through the same J5 user-row seam as
the gate decisions: one card per message, one row per seat with its measured run end and where its
handoff stands, the handoff opening in the artifacts panel and readable inline when the notice
carried it. The notice names the seat's Crew so a Captain of several Crews can tell them apart.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…their own tag, and commit before settling

One Captain's several Crews reuse seat names, so the "unchanged" baseline is now the seat's
participant, not its name. A written handoff always carries its size and digest in the
notice facts, so a re-briefed seat that rewrites a body too long to inline still reads as
changed and the Captain hears of it. The opening seat tag is escaped in quoted handoff
bodies like the closing body tag, so a Critic quoting a notice cannot become a phantom seat
on the card or break the dedupe compare. The notice commits before the seat settles: a
failed notice leaves the seat unsettled and logged so the next pass retries it.

The tools doc says in one sentence why delegate_task's wait mode is safe where
t3_thread_wait was not.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ed by the platform

Jackson's review of the stack, round two: upstream settles a thread by hand, on a merged PR, or after idle days, and a seat marked settled seconds after launch read as wrong. The settler becomes the seat finish notifier: the notice to the Captain stays as it was, the thread.settle dispatch is gone, and the notice tag, service, session, and web parser are renamed to what the action is.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…s the run's error, said once

A seat that died on its first turn was reported as a finish: block and card named "finished", the
failure one line among handoff lines about a missing artifact, and no reason. The reason existed
only in the silence detector's "errored" notice, which fires only when the Captain had an open ask
to that seat, arrives later, and describes a messaging failure (Jackson's dogfood, 2026-09-17).

The notice now opens with the run's status and, for a failed run, the recorded error; the card is
titled by what ended how and shows the status first. A failed first turn that the launch report is
about to carry is that report's to tell and is not also a finish; the notifier's stream feeds the
reporter and runs its sweep first. A failed run is reported whatever the seat still owes, and the
silence detector no longer posts an errored notice about a seat to the Captain that commands it, so
one death is one telling.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@bryantderosier
bryantderosier force-pushed the crews/06-seats-settle-and-notify branch from 95dfed1 to 4a4074d Compare September 21, 2026 15:07
@bryantderosier
bryantderosier merged commit 0da348f into j5/main Sep 21, 2026
19 of 20 checks passed
@bryantderosier
bryantderosier deleted the crews/06-seats-settle-and-notify branch September 21, 2026 15:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL 500-999 effective changed lines (test files excluded in mixed PRs). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Crew seats tell their Captain how they ended

2 participants