3 Commits
Author SHA1 Message Date
Teknium 5feaa50b9f fix(gateway): a note into an old conversation leaves the row the chat's /new ended closed
Re-review N2a of #144840. A reminder or background result written into a conversation its chat moved
past as a note (no viewer, no turn) reopened the row the chat's /new had ended. The local path already
skips the reopen for notes; the detached branch now does the same, and a result that runs as a turn
(a viewer is open) reopens it as any first turn does.
2026-10-27 17:04:02 -07:00
unsupportedpastels 2352d1d22c fix(gateway): write a local chat's cron result as a note, not a turn
A cron result admitted into a local chat ran as an automation turn over
the Bot Chat framing: a second model call over text that is already
finished. The admission now goes to the existing note executor
(session_completion_notes): a 'cron' producer is always noted, viewer or
not, so at the FIFO head the gateway writes the delivered text into the
chat's history (append_completion_note, keyed by the admission) and
settles it with no model call. The FIFO row is kept rather than a direct
write, which a live turn's lease would refuse. Failure notices are noted
the same way, marked diagnostic. The no-owner/unknown-chat/refusal/
timeout errors are unchanged.

Refs #143547
2026-10-25 19:18:26 -04:00
unsupportedpastels d04e580956 fix(gateway): exit and /new end a session's delegations; unviewed completions become notes
Main's classic CLI interrupted its async delegations at exit, and main's TUI
ended a session's own delegations when it closed it. Under the gateway the
client is only a viewer, so the delegations kept running after it left, and
their completions (and background-process notices) started turns nobody
watched.

- The last viewer's `session.detach {end_reason}` (classic CLI exit and
  /new, Ink /new, resume switch and exit) now interrupts that session's own
  async delegations in the gateway at once, mid-turn too, matched by the
  session's route and its logical and physical ids. It also refuses new
  ones for those selectors until a viewer attaches again: the refusal is
  set before the interrupt and checked under the delegation registry's lock
  at registration, so a unit the still-running turn dispatches later, or
  mid fan-out, is refused. The viewer check runs again right before the
  interrupt, with no await between, so a viewer that attached meanwhile
  keeps them. Other sessions are untouched. A plain detach (Desktop
  closing, a dropped connection) or a close while another viewer is still
  attached cancels nothing. Background processes are left running, as
  main's CLI exit left them.
- A local session's async-delegation result, background-process completion
  or watch-pattern notice is admitted like any producer input. A batch is
  still coalesced into one admission under its primary identity, with the
  sibling identities in its descriptor: a retry of any of them finds that
  admission, results already admitted are left out of a new batch, and its
  one outcome (note or turn) covers the whole batch. When that admission
  reaches the head of the FIFO with no viewer attached (the authority's own
  subscriber records), execute_admission writes it into the session as a
  note, the row the next turn reads, and settles the admission without a
  model call. With a viewer attached it runs as the turn it always was.
  Queue order, restart survival and exactly-once come from the admission
  contract: a busy session keeps the completion queued, and the note's
  check and insert share one writer transaction in the state layer
  (SessionDB.append_completion_note, keyed by the admission id; the API
  delegation-delivery row uses the same check-and-insert). Writing a note
  re-baselines the cached agent's message count, so the next turn reuses
  the agent.
- A completion whose local route still names the session the user closed,
  directly or through the compression continuation it was pinned before,
  is noted on that closed session; it never reaches its replacement. Any
  end of that session other than compression counts as a close, whichever
  reason the client sent (exit, /new, /resume, /branch).

Messaging, cron, Kanban, /loop and heartbeat wakes are unchanged. No schema
change.

Refs #134889 (LC-7)
Refs #139523
2026-10-16 17:42:48 -04:00