Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
b095a41
fix(routing): a start that continues a logical turn keeps the turn's …
Oct 13, 2026
12db349
fix(routing): a wake a tool boundary already weighed doesn't re-pin a…
Oct 13, 2026
f4cf796
fix(routing): weigh arrivals between a turn's streams as the messages…
Oct 13, 2026
2374a60
fix(routing): answer the second internal review of the turn-routing c…
Oct 13, 2026
4a6ffe6
fix(routing): answer the review of the second fix round
Oct 13, 2026
0cff233
Merge remote-tracking branch 'origin/main' into nigel/314-continuing-…
Oct 13, 2026
26eeafe
fix(routing): look up the sending turn only for a send tool
Oct 13, 2026
9d20ac9
Merge remote-tracking branch 'origin/main' (0d2dd88f) into nigel/314-…
Oct 14, 2026
3340391
fix(routing): a start dropped before its stream sends anything ends t…
Oct 14, 2026
139aca6
test(routing): pin a resume's reopened turn and a failed start's ephe…
Oct 14, 2026
984f2fa
fix(routing): an arrival re-pins only while its message remains; a la…
Oct 14, 2026
7b02c83
fix(routing): a store that can't be read at a start fails it, rather …
Oct 14, 2026
eab8755
test(routing): bring a capacity hold to its deadline before a test re…
Oct 14, 2026
a679e96
fix(routing): answer sw-af314d; tune-out diversions and modes without…
Oct 14, 2026
b534aaf
Merge main cd036e0d into nigel/314-continuing-starts-keep-routing
Oct 14, 2026
88ffb8a
docs(routing): a dropped start reaches its routing after stop() only …
Oct 14, 2026
4b29570
refactor(routing): a channel_open's move needs only its open turn, wh…
Oct 14, 2026
f8f2ec1
docs(routing): a silent turn's routing state can become the open turn…
Oct 14, 2026
f07c6ea
fix(routing): every resident's open turn weighs what lands in the sha…
Oct 14, 2026
0dfdbd5
fix(routing): answer sw-af314e; a boundary that re-pins clears older …
Oct 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions changelog.d/continuing-starts-keep-routing.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
- A start that continues a logical turn now keeps what the turn has decided
about where its speech is published. Those starts are a framework retry
after a stream error, the re-inference that consumes unstreamed tool
results, and the compile a provider-capacity hold defers a turn to (#314).
Before, each began with fresh routing:
- in hybrid mode, the hold after `>>>skip_reply` was dropped, so the new
stream's unprefixed prose was published to the turn's locus;
- the sticky destination was dropped in both modes, so unprefixed prose
went to the locus in hybrid mode, and in explicit mode bounced with a
notice and a wake, while the new stream streamed nothing;
- the turn's locus was resolved again: a retry lost a mid-turn addressed
re-pin, a re-inference took the locus of whichever wake started it, and
a held turn's later compile let a newer ambient message move it.

A hybrid stream's live outgoing deltas still start at the turn's locus,
as before.
- A message that no tool boundary weighed now moves the turn's locus at the
turn's next start, by the rule a mid-turn message follows: a
conversational message that addressed the agent, or that follows up in a
channel the turn sent into, with the same
`[routing] The conversation moved to …` notice. That covers a message that
arrives during a capacity hold or before a re-inference, and one drained
at a budget restart's over-budget boundary, which before never moved the
locus. Ambient traffic in a channel the turn hasn't sent into, reactions
and system markers don't move it. Neither does a message the agent won't
see: one that tune-out diverts, or one removed before that start, such as
an unread coalesced message its server retracted. The newest qualifying
message that remains decides. Residents read one message slot, and a
tool boundary weighs only the messages drained for its own agent, so each
resident's open turn also takes, by the same rule, a message stored for
another resident whenever it lands, including one that resident's
boundary drained. A message tagged as addressed addresses the account the
residents share, so it can move any resident's turn.
- A silent turn's tool boundary no longer re-pins its locus or adds a
`[routing]` notice to its stream.
- For a trunk agent, the channel context passed to `beforeInference` hooks
(`channels.defaultOutgoing`) names the turn's locus once the turn has one.
After a re-pin, a later start of the turn reports the locus it moved to,
where its unprefixed speech is published unless a hybrid `>>>` destination
takes it, not the channel that triggered the turn. A conversation fork
still reports its home channel.
- A start that fails before its stream exists now lands the messages
deferred during it, as a stream's end does. Before, they waited for the
agent's next start and landed after any message stored in between. A
start that throws outside its stream's failure handling ends its logical
turn, so the agent's next start opens its own, and an ephemeral run
(`runEphemeralToCompletion`) whose start throws that way fails at once
with the start's error. Before, the run waited for its watchdog: 30 s by
default before its inference started, or 15 minutes once it had.
- A send's engaged channel is recorded on the turn that called the tool,
even when the open that follows the send comes after that turn has ended.
A `channel_open` moves the locus of the turn that called it while that
turn is open. Its result tells the agent of the move, so one that comes
after the turn ended moves nothing: the result is dropped unread.
8 changes: 6 additions & 2 deletions docs/explicit-prose-routing.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,12 @@ A prose segment's FIRST line may carry a routing prefix:
```

- Body may start on the same line (`>>#ops deploy done`) or the next.
- **Sticky within the turn:** the first resolved target applies to later
unprefixed segments of the SAME turn. Cross-turn, nothing is implicit.
- **Sticky within the turn:** the latest resolved target applies to later
unprefixed segments of the SAME turn, including those a later stream of it
writes, such as a framework retry's, a budget restart's or the compile a
provider-capacity hold defers the turn to. A round kept private (one that
calls `skip_reply`, or has a same-round private think) sets no target.
Cross-turn, nothing is implicit.
- **Continuation modifier:** ` !` immediately after the target
(`>>#ops !` / `>>skip_reply !`) requests an immediate re-wake after this turn
ends, instead of the default pause-until-next-event. Gives prose the same
Expand Down
8 changes: 8 additions & 0 deletions docs/hybrid-prose-routing.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,14 @@ At logical turn end, a `[delivered]` receipt names canonical destinations (or a
bounce explains failure), so authored intent cannot impersonate delivery.
Unprefixed prose after a successful envelope follows that explicit destination
for the remainder of the turn; a fresh turn begins at its ordinary locus.
After `>>>skip_reply`, or a `>>>` envelope that is malformed, doesn't resolve
or isn't delivered, unprefixed prose isn't published until a later `>>>`
names a destination that resolves; if that envelope's body then isn't
delivered, the hold returns. The sticky destination and this hold last for
the whole logical turn, across its later streams, such as a framework
retry's, a budget restart's or the compile a provider-capacity hold defers
the turn to. They govern publication: a stream's live outgoing deltas still
start at the turn's locus.

This is publication routing only. It creates no privacy meaning for `<think>`
or other prose tags, and grants no channel authority beyond the existing
Expand Down
Loading
Loading