Cut: State.tasks, Event::TaskStarted, the tool_use_id keying of task lines and the notification replay, and TaskNotified's tasks.remove gate. running is a copy of the CLI's last background_tasks_changed, replaced whole; a notification owes a turn when the task was backgrounded and the session did not stop it with TaskStop (or KillShell, KillBash: the stream shows the alias as the model named it); Polled and Inbox carry other_first, so a served conversation's newer brief no longer outruns an older brief of another. Fixtures bg-fgto, bg-kill and bg-monitor pin the three falsified cases; the probe's fake API gains a generic tool step and a timed scenario.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A foreground task moved to the background at its timeout, a task stopped with TaskStop, and a persistent Monitor; scrubbed to /probe/work, the key is the fake one.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
decide owns idleness (no turn open, nothing outstanding, no backgrounded task running, no notification owed its turn) and the switch of
conversation; read_usage reads the task lines for liveness only; the CLI's replay of a task notification is no echo of ours. SelfInbox
serves one Conversation and attributes a result by the span, not by the order of the stream. Deleted: briefless_open, briefless_answers,
turn_conversation, turn_allows, may_tell, one_conversation_told, note_task, tasks, notified, the Persona pointer line and its plumbing.
ScheduleWakeup and CronCreate are denied to the Self session. Tests replay the real-order captures with briefs spliced in.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The harness runs the CLI against the fake Messages API with a fake key and a throwaway config dir: bg and agent plan steps, a
Monitor step, --disallowedTools through DENY. Captured: an Agent call with run_in_background gives task_started
(is_backgrounded true, the call's tool_use_id) and a task_notification with the same id; a background Bash ending while no turn is open
makes the CLI begin its own turn (init, a request, no echo); ScheduleWakeup and CronCreate are absent from the init tools when denied;
a Monitor is a backgrounded task with the same two lines, so it needs no denial. Host paths scrubbed to /probe/work.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A notification with no tool_use_id registers nothing (the open-turn gate still holds it by its request). Tests: the notified conversation's brief joins its turn, a notification of another conversation stays pending through a brief turn, two conversations' notifications open a turn no brief may join, an idle non-request line opens no turn, a resolved claim is read by its own key, a claimed cut spec stays on the start line.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A request with no line of ours echoed is a turn that took in no brief, notification or not; until its result only the conversation it continues, or the notification's task's, is written. Nothing told yet means no other conversation exists.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A reply that answers no brief, or briefs of two conversations, was read by nothing and re-paged on every Persona read. It is now a route in the public conversation marked as a pointer: the line carries the reply id and a fixed note, never its text, and the Persona reads the reply by id. Heard, it is resolved like any reply.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The stream's task_started and task_notification events carry the tool_use_id of the call that started the task. The actuator records, per task, the briefs the starting turn was answering; a briefless result after a notification answers those (any notification it cannot place answers none). While a notification's turn is open, only the conversation it is attributed to may be written. A restart reads a resolved claim's conversation by key and opens the gate for it alone. The flush result is the note to the successor, in the journal: it is no reply. The start message states the rules.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A reply to no brief is told in no session and stays in force (ruling briefless-result-routing). A restart drops a claim that is not of the start set conversation.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The start set is one conversation's; poll and tell gate briefs by the conversation of those unanswered;
a result that took in no brief continues the turn before; the start message says so.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
DM invariant across three sessions, a reply alone opening its DM once per start, the oldest waiting thing deciding,
pre-deploy briefs going public, a two-conversation reply told nowhere, the yield, one origin per turn, the open-brief mark.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
reply_routes derives each in-force reply's conversation from the origins of the briefs it answers (nothing stores it);
next_session lets the oldest waiting thing decide, carry's batch no longer owns rooms, conversation or origin;
an empty batch takes the session's origin; the brief records the turn's origin; a session with nothing of its own yields to another conversation's reply.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
PipelineFollowUp gains origin (absent is not written, so the golden sample is unchanged);
MemoryOrigin's doc says it is a brief's too; the header facts carry it; schemas regenerated.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A heard reply whose resolution did not take (admit failed, or the keyed read errs) went back through untell and was told again. The answered
replies now wait in answered_replies, retried at each result and at close (settle_replies), one by one so no refusal holds another hostage;
untell serves only the lines she did not answer. Tests pin the retry, the close retry, the reply resolved elsewhere on a refused line, and the
unreadable in-force read on that path (told again, kept as retell).
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
hear_replies attempts each resolution and untell asks the mind which replies are still in force, so an Ok/Err reading of the
admission is no second opinion. The out-of-force test holds replies past the first line so a read by kind alone would retell the
resolved one.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
untell checks a reply is still in force before it waits again, and hear_replies resolves each reply on its own, so one refused
resolution neither retells a reply nobody can answer nor holds the rest of its batch. Tests: out-of-force retell, a reply reaching an
idle session with no chat pending, and a reply waiting across a read while a line is not echoed (a stalled child).
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Documents decode one by one through serde_path_to_error, so the refusal says
documents[i].path and what is wrong, in the schema's words: a field name, the
allowed variants, the expected type. Serde's own text quotes the input, so it
is not passed through.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The strict decode that refuses unknown keys by path moves from the huginn
binary to eureka_state::door; the CLI re-exports it and the MCP admit takes
documents as a Value (schema still Vec<PipelineDocument>) and decodes through
it, answering InvalidInput before any call. A research note with extra keys is
refused by path and nothing is stored.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>