docs/adr/0218-native-seats-drive-their-attached-conversation.md

ADR 0218: Native seats drive their attached conversation

Status: accepted for engineering (James, 2026-10-04). Extends room turn admission, room inspection, room-owned harvests, and conversation body leases.

Context

Clankie's conversation is independent of the harness that executes it. Native operator seats already select a conversation, receive channel events, and project their own transcripts. Worker output currently enters the default conversation even when another conversation hired the worker. Room conversations are inspectable but cannot yet be selected by a native operator seat.

Decision

Amendment — an owner links a private Discord channel to main (2026-10-18)

James explicitly selected his main conversation for his private #clank channel. The old path ran a room Pi agent that messaged the main lead, watched its pane, read its transcript and paraphrased a result. That relay added model turns and made one Clankie describe another as "the lead".

discord.mainConversationChannelIds records this explicit choice through the existing revisioned settings API, CLI and shared settings UI. A linked text request enters the default main conversation's existing queue and runner. A live native head receives a reply-bearing discord-main escalation; otherwise the normal service runner continues the same main context. Neither route starts a room child or relay agent. The existing handoff record retains the room origin, result and mainConversationId; its transcript contains only the room request and correlated answer, never the main conversation's private log.

Only the configured owner account, bot transport, owners: me server policy, proven private audience and original machine grant qualify. Room skills and voice do not take this path. Admission, result return and saved-result replay recheck authority and the link. Ordinary main output is not broadcast. Native receipt correlation and the existing conversation admission fence apply; only a definite pre-acceptance native refusal may select the main service runner. Accepted or uncertain native deliveries never fall back to another executor. The escalation envelope preserves compatibility with existing native bridges; its host-stamped source distinguishes direct owner input from worker output.

Conversation attachment

A native operator seat may select any existing service conversation, including the default conversation and canonical Discord text or voice rooms. A room remains the same room conversation; selecting the default never selects all Discord rooms. Conversation discovery exposes stable IDs and readable names. Inspection, ordinary owner sends, reset, and attachment retain their separate admission rules.

The service selects one execution destination for each admitted input. A live attached native seat receives worker output, escalations, wakes, watches and room messages through its existing conversation channel. Its reply uses the existing reply correlation. When no seat is live, the service runner executes the conversation. Extend the existing native source metadata, conversation admission and seat outbox; do not create a second conversation or mailbox system. Existing Pi goal continuations retain their service loop; this change routes the listed external inputs and asynchronous notifications.

Execution admission and attachment handover share a conversation fence. A service execution that has already reserved admission keeps that input; attachment cannot start a second execution of it. A native delivery that was taken, accepted, or became uncertain is never replayed into the service runner. Only a definite refusal before native acceptance permits fallback, after rechecking the current destination. Detach cannot redirect an in-flight accepted input. Unaccepted queued input follows the current destination. Existing durable delivery IDs, fingerprints and receipts survive retries; transport uncertainty remains visible instead of becoming a duplicate answer.

Attachment grants no tools or room authority. Discord turns and asynchronous room notifications refresh the original actor and route grants as today. Native replies return through the admitted room turn's existing body mouth and lease checks. Selecting a room grants neither cross-room replies nor the right to invoke a generic operator runner on that room. Other rooms and conversations retain their own execution destination and grants. A room's cached MCP tool bank remains social and has no generic operator body identity. The current MCP session contract has no exact per-event actor binding; it cannot safely import a later actor's machine grants into that cached bank.

A worker's lead is the host-stamped conversation that hired it. The existing persisted hire ownership proof binds it to the exact fleet, pane, seat and native occupant. A successful host-admitted message_seat from another conversation adopts the worker under that conversation. Workers never choose this route in message_clankie. Authenticated worker messages use their existing receipts and the existing framing that agent output is untrusted context, not an instruction from the owner. When the recorded conversation is gone, worker messages fall back to global-default; a live room with revoked authority is refused rather than redirected. This missing-conversation fallback applies to worker messages, and does not change scoped watch or body-lease fallback rules in ADR 0215.

Extension — Reports from unadopted workers, 2026-10-04

In VUH-1615, James selected the host-observed Herdr parent/launcher edge for workers without persisted hire or message adoption. Explicit adoption always wins. The host refreshes the census, matches the reporting occupant, and resolves only its exact fleet-qualified parent pane and native occupant. Names, tabs and report content select no lead. An eligible parent receives the report in its attached conversation or through the existing native seat channel. Native-only parents retain acceptance in their existing seat conversation; they never invoke the generic service runner.

Parent selection creates no ownership registry and grants no tools. Attachment uses the existing authenticated native-session association, with ambiguous associations refused. A room still requires its original admitted Discord owner proof and current grants; missing proof or revoked authority cannot escape into the default conversation or a native-only route. Bridge process observations are diagnostics, not delivery receipts or tool authority.

Immediately before durable inbound acceptance, the host refreshes ancestry and both occupants and rechecks explicit adoption. Changed proof refuses that attempt. Acceptance retains the selected destination and routing reason in the existing inbound receipt and accepted turn. Later adoption or detach cannot redirect that ID. Native dispatch uses the existing per-seat fence with a stable report receipt key and rechecks the original recipient. Uncertain delivery is never replayed into a different conversation or channel. Every supplied native recipient binding applies to fleet mailbox takes and acknowledgments, regardless of message source. The existing receipt retains that binding across restart; a replacement occupant cannot take or acknowledge the original parent's queued report. Conversation-wide driver handover keeps its separate existing admission contract.

With no eligible parent, global-default receives an explicitly tagged unadopted report identifying the missing-parent, unavailable-parent or unlinked-parent reason. The roster exposes the same routing diagnostic, and doctor names the observed parent and children when the parent lacks a bridge. A removed explicitly adopted conversation retains the existing default fallback with an owner_removed reason; it does not enable implicit parent adoption.

Extension — Linear work ownership, 2026-10-04

Superseded later that day by ADR 0214's VUH-1678 decision: The later VUH-1743 amendment selects configured project lead chats, with global-default as the project fallback; the lead delegates from there. This extension's issue-owner routing and inbox handoff are historical; native seat conversation admission elsewhere in this ADR remains unchanged.

James selected issue-owned routing in VUH-1611. A successful Linear issue or comment write from an admitted conversation, an issue-scoped native hire, or an explicit owner claim records that conversation in the existing linear-work.json. Identifier-only comment writes can acquire canonical parent identity through an exact signed match to the existing write receipt. Its host-stamped owner and original write time survive restart; a delayed echo cannot undo a newer claim. An explicit unbind retains its timestamp in the same file, so an older receipt cannot silently reclaim released work. Incomplete receipts establish no automatic ownership. The organization and canonical issue UUID are the key. An admitted later claim adopts the work, as an admitted message adopts a worker. Room ownership retains the original Discord actor and route proof; later delivery refreshes those grants. Model arguments and worker output cannot invent that proof.

Signed linear-attribution.json history supplies canonical issue identity for actor-less notifications. Ambiguous identity stays unowned. Ownership neither changes attribution nor bypasses the follow switch and ADR 0214's wake rules. Workspace hooks remain passive history. Owned notifications wake their existing conversation through the same admission fence and native channel as other inputs. Unowned notifications and notifications whose conversation has been removed wake linear-inbox, never an implicit global-default. A present room with revoked authority remains undelivered rather than gaining another conversation's tools.

The inbox reads durable work ownership, memory, work items and the fleet roster; it does not import another conversation's transcript. An explicit inbox handoff uses the retained event's current issue owner and preserves its original wake eligibility. A stable derived handoff ID and a new journal cursor admit it once, even when the owner has already processed newer provider events. Completed admissions stay marked in the inbox metadata, so deleting an owner does not replay its completed notifications. Passive or filtered history cannot become a wake merely because ownership changes. Existing per-conversation cursors and interrupted-run recovery retain the accepted destination across restart.

This extension supersedes the inert-binding amendments in ADR 0168 and the fixed global-default destination in ADR 0214. The inbox remains the shared durable event journal; no parallel notification mailbox or ownership service is added.

Replies to status updates and native authors

A reply to a project or initiative status update belongs to the authoring seat or conversation. Successful save_status_update writes retain the canonical update UUID and the host's original author proof in the existing write receipt. Signed comment history matches that exact parent and carries the receipt into linear-attribution.json. Notification URL aliases are resolved only against those signed full IDs; names, short prefixes alone, and provider-supplied routing fields cannot establish an author. Missing or conflicting proof leaves the event in the inbox. Existing attribution and follow rules still decide whether it wakes.

A native author can live on a local or remote fleet without owning a local conversation. Its proof retains the fleet-qualified pane, seat, native occupant and admission binding. Capture uses the existing authenticated process observation, never a pane named by the model or a fleet bearer alone. Later delivery refreshes that exact recipient and any original room grants, then uses the existing native delivery fence and fleet link. A replacement occupant cannot inherit the reply. Uncertain delivery retains its original ID and is reconciled rather than replayed. The shared inbox journal stores the admission and outcome; it does not introduce a second mailbox or copy an author's conversation transcript. The host commits the admission proof before appending an eligible event. A crash cannot leave a native event recoverable as an ordinary inbox model turn. Pending native admissions remain retained independently of the inbox's read/wake cursor. Explicit stable native delivery receipts keep confirmed outcomes for seven days in the existing delivery fence, covering a crash between native acceptance and the journal's completion marker. Stable Linear receipt keys and peer-message IDs share the same per-seat delivery reservation. After asynchronous recipient and attachment checks, reservation rechecks unresolved deliveries without yielding. A second key cannot bypass an in-flight or uncertain receipt, or reconcile another key's identical content. The existing peer delivery options carry both the native author guard and stable receipt key; their final adapter and fleet dispatch checks remain authoritative. An unresolved native admission older than that receipt window fails loudly and remains unread for reconciliation; expired proof never permits automatic replay.

The live acceptance case is James's 2026-10-04 19:09Z approval on KH2 Multiplayer status update d9b90f52-0b0e-463d-a1e9-9457d250592c, comment 0707b479: “I APPROVE all!!”. Its author was the native Claude lead at kh2/w3:pK on the PC fleet. After landing, reconcile any existing manual relay before checking this exact reply. Older writes for which the host retained no author receipt cannot acquire guessed ownership from the current roster.

Reattachments and retained worker results (VUH-1657, VUH-1615)

A local private Codex seat may reattach with --remote without emitting Herdr's session hook. Admission joins its foreground socket/thread to the retained controller record, exact server PID lifetime and socket ownership. Census, native steering and private-seat admission use the same proof. Unknown or ambiguous occupants remain unbound. A native startup timeout during a large same-thread resume does not terminate a proven launched view's dedicated server; read-only restore observation continues without a second writer or brief.

Explicit re-adoption belongs to the original owning conversation. It refreshes native proof and rebinds only an already owned same thread. A resumed hire does the same under admitted hiring authority. A changed occupant cannot inherit control through ordinary messaging or watching. Same-thread report provenance may retain output before re-adoption, but grants neither control nor dispatch.

The host retains observed launcher edges by fleet and native child/parent thread, independently of Herdr's resettable pane metadata. Recovery needs one exact live child and parent; an observed ancestry change invalidates the old edge. Legacy launches with no retained provenance keep the visible no_parent fallback.

Worker reports use the existing conversation acceptance journal as their durable inbox. Their original payload, target and delivery ID survive trimming, reset, service replacement and disappearing panes. The host persists an attempting mark before invoking a receiver. Definitely queued/pre-handoff refusals can recover under refreshed recipient authority; interrupted attempts and legacy records remain uncertain and readable. Recovery cannot change recipients or replay an uncertain native effect. Native receipts describe transport only. Reading offers complete bounded payloads; only a recipient's explicit acknowledgment of offered IDs clears unread state. Roster and console expose pending/uncertain results and unread delivered results even after the worker leaves.

Reviewed history acknowledgment (VUH-1690)

Ordinary acknowledgment retains the offered-ID requirement. The CLI accepts an unchanged returned JSON page with its conversation binding and validates exact delivery IDs before dispatch, so malformed arguments fail locally rather than as an opaque HTTP 400.

An explicitly authenticated operator can retire up to 1,000 selected retained history IDs through acknowledge_worker_report_history (reports ack-history). Captain and paired-device principals cannot invoke it. Every selected receipt must belong to the named conversation; a missing or foreign ID rejects the whole write. The existing metadata transaction persists the read state and notifies the same roster projection. It never resends content or marks newly arriving reports read. Migration itself stays conservative: historical transport success cannot prove that the lead read a report.

Focused HTTP integration checks exercise the production CLI, authenticated route, operator service and persisted journal: 20/100 returned IDs, unchanged JSON-page binding, owner-only 165-record cleanup, surviving fresh unread output, roster removal and restart persistence. The historical live 400 is not reproduced by these current-source checks; its original runtime inputs remain a separate diagnostic gap.

Consequences and verification

Conversation identity and worker ownership survive harness changes. The native seat can lead the workers it hired without an unrelated default conversation harvesting their reports. A room remains independently inspectable and retains its current transport and authority boundaries.

Focused regressions cover hire, adoption, missing-owner fallback and remote identity; live attachment, detachment and execution reservation races; taken or uncertain delivery without replay; room reply authority and independent room routing; and discovery and native launch selection. A live post-landing worker report to the hiring Claude conversation remains separate evidence from these deterministic checks.

Stalled service preparation and execution (VUH-1613)

A service reservation cannot hold attachment and later turns indefinitely. A five-minute inactivity watchdog covers cold preparation from the reservation through Pi execution. Host-observed preparation progress and Pi events renew it. The watchdog is suspended while one or more Pi tools execute; each tool retains its own timeout and cancellation behavior. A full five-minute idle window resumes after the last tool ends. Before execution starts, or with no active tool and no preparation or streamed progress, inactivity still times out after five minutes. Healthy work has no total duration cap. Queued runs do not consume this timeout while waiting. Question authority and hook checks before driver selection, and native attachment preparation before dispatch, are bounded too.

On a stall, a stored run fails with conversation_turn_stalled. The service log identifies the conversation, run ID and stalled phase. The host aborts and evicts that exact cached startup/session and releases its admission, allowing the attached seat to receive later queued inputs. Late completion cannot prompt or publish. The failed input keeps its original acceptance and receipt; it is never replayed into another destination. Earlier effects may have an unknown outcome, so check the original evidence before submitting a new request.

Native delivery retains its existing acknowledgment and reply deadlines, including the ten-minute escalation reply wait. The service inactivity watchdog does not impose a five-minute native reply cutoff or permit replay of taken, accepted or uncertain native delivery.

The log is the conversation, 2026-10-06

Accepted for engineering by James on 2026-10-06, after the 2026-10-06 operator backlog: a closed Claude seat held 65 worker reports for about four hours, then delivered them as 65 separate turns. The service was running the whole time.

The rule above holds for every harness. When no seat is live, the service runner executes worker reports, self-wakes and watch notifications, whether Claude, Codex or any later harness last held the seat. The 2026-10-05 refusal (309b693d, "keep internal native-owned deliveries out of Pi") is withdrawn; its exponential wake backoff remains. That refusal worked around a Pi session that had grown to about 316k tokens and stalled in compaction. The fix below removes that cause instead. Native-only parent routes still never invoke the generic service runner. Signed Linear activity keeps its own VUH-1743 contract: it waits for the attached receiver and is offered again on its next poll. Taken, accepted or uncertain native deliveries still never fall back.

The conversation event log is the single source of truth. The service lane and every harness are bounded views of it, and nothing writes into a harness's own session file. Harness transcripts already sync into the log. One bounded projection (projectConversation: messages and finished tool actions, newest first within about 24k characters, read oldest first, with an omission marker) carries the log back out at each change of driver:

  • Log → service lane. When a harness has driven the conversation since the service lane last ran (the native transcript revision has moved), the service starts a fresh Pi session seeded with the projection. It does not resume its private session file, which stays on disk. Pi's next turns continue that fresh session until a harness drives again.
  • Log → fresh harness session. The operator seat's SessionStart hook asks for clankie prompt --sections …,conversation, for both the Claude and the Codex plugin. Reading it records the projected cursor as the harness cursor.
  • Log → reconnecting harness. A service turn in a conversation that a harness has driven opens a handoff span at the harness cursor. Its internal input enters the log as an external message. When the seat polls again, inside the existing driver fence, it first receives exactly one service-handoff turn. That turn holds the service's actual turns since the harness cursor, verbatim within the same budget, and points to the worker-report inbox for anything omitted. The original inputs are never delivered again as separate turns.

The existing fence decides in-flight work. A service run admitted before the seat polled finishes on the service lane and lands inside the handoff. Input queued behind it selects its driver after the poll binds, so it goes to the seat, after the handoff. A SessionStart projection that already covers an open span satisfies it, so the harness is not seeded twice.

The handoff is sealed and persisted as attempting before transport. Acknowledgment advances the harness cursor. A definite pre-take refusal reopens the span. An unproven take advances the cursor without resending and records a visible external note in the conversation. A restart turns attempting into unresolved: an exact acknowledged receipt settles it as delivered, and anything else is uncertain and never resent. Service turns that begin after sealing carry into the next span.

Regression coverage is apps/clankie/test/native-seat-service-fallback.integration.test.ts. The owner-turn regression in apps/clankie/test/owner-app-seat-turn.integration.test.ts also overlaps native admission with service routing and checks one operator MCP tracker dispatch and one durable issue. Removing the admission wait makes that regression fail. It uses real admission, driver fence, journals, inbound receipts, seat outbox and handoff state, with a scripted model. It covers the following:

  • a worker report runs once on the service lane, seeded from a bounded log;
  • a taken but unacknowledged native report never moves to the service lane, including across a restart;
  • a reconnect receives one handoff that contains the in-flight run, and queued input follows it to the seat;
  • a second rebind gets no handoff;
  • a restart between take and settlement does not duplicate the handoff;
  • the SessionStart projection suppresses a second handoff;
  • failed service wakes keep their backoff.

No live harness, provider or production state was exercised.

Owner-directed room turns, 2026-10-06

James asked that the operator seat, whichever harness holds it, be able to speak in a Discord room itself, "it just works". Until now the seat could only answer rooms that had escalated to it (attachment grants no room authority, above). The seat's generic Discord write tool refused outright.

Decision. The owner's seat forks a turn into a room with the room_turn tool. It is in the operator lane's bank only, so only the owner-authenticated seat holds it. Workers, peers, rooms and room-attached seat banks never get it.

  • Authority stays the room's. The fork runs as that room's own turn, with the owner as its Discord actor. It takes the room's current grants, body lease and mouth, and it posts through the existing send_reply/post_message captain actions and their per-call receipts. The seat holds no Discord credential and chooses no channel ID; the room conversation names it.
  • Its own authority basis, not a borrowed receipt. An ordinary room turn proves its route with the Discord delivery receipt of the message it answers. A fork has no such message: replyTo is only a reply reference, often another member's message. While the fork is in flight, the captain holds a grant for it, and only room_turn creates one. The fork's origin names the grant (deliveryId: room-fork-<id>, owner as actor). The app's route check accepts that exact grant plus a connected bot presence that can reply. The presence-action route accepts a captain-action write keyed to that grant for the same channel. Grants end when the fork settles. No receipt is ever written for someone else's message. A refusal before dispatch, such as no live body, is never recorded, so the same requestId can retry.
  • Tools follow the room, not the owner. The fork gets machine tools only when the room itself holds a guild or channel machine grant. The owner's personal machine access never turns a shared room's turn into a shell.
  • Context: brief in, bounded result out, no transcript inheritance. The fork starts a one-shot session from the room's own history, projected with the same projectConversation and budget used by the service handoff. That history is the room log plus its heard/said lane log, which is where per-message handoff children leave the live conversation. Added to it is the brief the seat writes. Nothing else from the owner's conversation reaches a shared room. The private operator transcript never does, except as the seat's own words in the brief.
  • One result, two logs. The seat gets one bounded result: posted, silent, failed or uncertain; channel, reply target, message ID, the posted words up to 1,600 characters, and the attached file name. The room log records the room turn. The seat's conversation records a room_turn tool event with the same result, so projections and handoffs see it.
  • A file rides the reply. file names a workspace file. The delivered-file host publishes it under the room's key and it posts with the reply (ADR 0088, 2026-10-06), so it needs replyTo. A file the fork delivers itself rides the same way. Amended 2026-10-21 (VUH-2581): a file also rides a message that answers nobody, and the fork can name a channel by ID before any room conversation exists. Tools and context now follow the room's audience (ADR 0251).
  • Retries never rerun. A request ID, by default a hash of the request, maps to one settled result in room-forks.json. A retry returns it. A run interrupted by restart reports uncertain and is never rerun.

Remote project heads (ADR 0259)

A project lead is a named workspace chat with a native head, rather than a worker pane leading other workers informally. Its hires and reports belong to that chat. ADR 0259 extends the local attachment with a standalone Windows Claude bridge over the fleet link and a seat/chat/machine-bound delegation. Existing worker context moves by a written handoff when the launch path cannot resume it; adoption and retirement require separate coordination, never an implicit restart of active workers.

A usage-limited seat is not a driver (VUH-2273)

A bound seat that refuses turns on a session or weekly usage limit is treated as unbound for new input until the limit resets. Claude Code writes the refusal into the seat transcript as a synthetic reply with apiError: "usage_limit_reached", its window and its reset time (older entries have only the wording). clankie seat-sync carries that as usageLimit on the message, and the seat outbox parks the seat. Wakes, rounds and reports then run on the service lane, input queued but not yet taken moves there too, and the conversation gets one service notice. A real reply from the seat releases it early. Once the reset passes, the next poll delivers the usual service handoff. A refusal without a reset time parks the seat for an hour from when it happened. A remote project head has no local fallback, so its runs fail with the existing refusal instead of reaching the limited seat.

A local lead seat then moves, in its own pane, through the same launcher as a fresh restart (ADR 0271). It goes to the signed-in account with the most headroom: another Claude account first, then Codex, never the limited one. A hard limit leaves only the unsent-draft guard. After the reset, the seat moves back to its original launch with the usual quiet-owner and idle guards; a refused return is tried again on the next check. With no account that has room, a refused move or an unknown original launch, the service lane keeps running the conversation. An unconfirmed move or return is reported and never retried. Each move posts a notice, and the lead chat roster shows the current move (seatMove).

A busy head hears its owner first (VUH-2874, 2026-10-26)

On 2026-10-26 the owner's linked-channel messages waited behind one long native head turn (one for about 38 minutes), and each later got its own late answer. Meanwhile the service lane ran lead turns beside the live head and messaged its workers. The traced causes:

  • an internal input (a worker question resolved elsewhere) had no seat event kind, so it always ran on the service lane;
  • a head poll waits behind in-flight service runs before it parks. A service run longer than the bridge's 35 s poll deadline read as the head leaving, so more input routed to the service lane;
  • linked-channel escalations were held until the native turn ended, then released one per turn;
  • the room handoff coordinator admits two handoffs per room, so a third owner message waited for an earlier answer.

This amends "Seat live?" in the selection above for the head (global-default):

  • Lane hold. A head holds its lane for 45 s (HEAD_LANE_HOLD_MS) from its seat's last ask: a parked poll, a completed poll, or a poll still proving its source or waiting behind admission (held for as long as it waits). This supersedes the 30 s head grace as the selection boundary. The grace still ends a completed poll's binding, but input that arrives inside the hold is stored at the seat for its next poll, not run by the service lane. 45 s covers one bridge poll timeout (35 s) and its retry (5 s). Worker and room outboxes have no hold.
  • Recorded takeover. Input still waiting when the hold lapses settles unbound as a takeover, and the service lane runs it, including input that had been stored at the seat. The first takeover of each silence records a service notice in the conversation ("Clankie's service lane took over this conversation …") with the seat's last ask and how long it was silent. A service run already executing when the head returns still finishes first and reaches the head in the usual handoff.
  • A held Queue is never taken over (VUH-2885, 2026-10-27). A Queue stored behind the seat's own running turn is that seat's to run, never the service lane's (VUH-2045). When its bridge leaves, it keeps the 30 s grace boundary: once the grace lapses it settles unbound and is reported "Not sent". It does not wait out the lane hold and is never taken over. The first VUH-2874 landing let it wait out the hold and then run on the service lane, so the app showed a detached Queue as "Queued · Sent".
  • Internal input is a wake. An internal input on a head conversation reaches a live seat as a wake, like a hook.
  • Owner first. A poll takes owner turns and escalations ahead of wakes, watches, Auto rounds and reports, whatever order they were queued in.
  • Owner messages steer. A linked-channel escalation steers a busy native turn instead of waiting for it to end. On the service lane it is still a queued turn.
  • Same-batch coalescing. Escalations from the same linked channel that are waiting together when a poll takes them reach the seat as one attributed event under the newest one's id, oldest first, with the later messages framed as context. One reply to that event answers the whole batch: the answer posts once, on the newest message, and each older member settles absorbed with that reply's replyDeliveryId. Each message keeps its own receipt. A reply covers only the messages its event carried. An escalation the seat received in an earlier event keeps its own reply, so answering a newer message first never closes an older one.
  • Early room-slot release. A linked main-conversation handoff releases its room slot once it reaches the main conversation and only waits for the answer. The two-per-room cap therefore no longer limits linked owner messages; it still bounds room handoffs that do their work in the room.

Regression coverage is apps/clankie/test/owner-delivery-busy-head.integration.test.ts. It uses the real captain, room admission, conversation runner, outbox and channel pump, with a scripted model in which any service-lane turn shows up as a prompt. It covers the owner heard mid-turn, the batch answered once, an earlier separately delivered message keeping its own answer, an owner message taken ahead of a watch queued before it, a resolved worker question reaching a bound head as a wake, an explicit takeover after the hold, and a held Queue settling unsent at the grace when its bridge leaves. No live harness or production state was exercised.