Skip to content

server: a ticketed learning mutation answers at once, and its result is pushed on GET /learn/events - #112

Merged
joelteply merged 1 commit into
codex/s4-per-mind-integrationfrom
cormac/ledger-tickets
Nov 11, 2026
Merged

joelteply merged 1 commit into
codex/s4-per-mind-integrationfrom
cormac/ledger-tickets

Conversation

@joelteply

Copy link
Copy Markdown

Card 7fc7e2ce (continuum), part 2: a learning mutation the core must otherwise wait out behind the work it controls becomes a ticket whose result is pushed. Stacked on #109 (ledger reads off the loop).

Design agreed in #continuum-dev: Fable e626bb70 (one event stream, delivery is the drop, no per-ticket wait route: a blocking poll), Codex 988bf0cf (custody: emission is not consumption, a missed result is a reconcilable unknown for the core, never silent success).

Change

  • server_response (the one owner of task results): a ticketed-id set, a delivery queue and a subscriber count under its existing mutex_results / condition_results. send() routes a ticketed result to the queue only while a subscriber is connected, stored before notify_all; otherwise it is dropped. The last unsubscribe drops anything undelivered.
  • GET /learn/events: one SSE stream per subscriber; first event {engine, subscribed: true}, then {ticket, error, result} per terminal result, SSE keepalives when idle (--sse-ping-interval); the request's connection ends it.
  • "ticket": true on /learn/grants/revoke, /learn/residency/release, /learn/residency/revoke (via grant_route) and /lora-adapters/unload: posts the loop task and answers {ticket} at once. Untagged requests are unchanged.

Tested (IntelMac, CPU build, stories fixture)

  • New tests/learn-tickets.py: a ticketed revoke and a ticketed unload answer only {ticket}, and their terminal results arrive on the stream under the same ticket; a revoke made with no subscriber is never replayed to a later one. Mutation (keep results for a later subscriber) fails it.
  • learn-ledger-off-loop, learn-past-example, learn-cancel-custody pass.

Core side (next, continuum)

The core subscribes once per engine incarnation, holds a handle per ticket, holds an early result until its handle registers, and on disconnect or a missed result reconciles against the physical grant/adapter/residency under the same incarnation (Codex's constraints, recorded on the card).

…is pushed on GET /learn/events

Card 7fc7e2ce part 2 (design agreed with Fable e626bb70 and Codex 988bf0cf). A grant revoke, a
residency release or an adapter unload sent with "ticket": true posts its loop task and answers
{ticket} at once. server_response::send, the one place results land, routes a ticketed result to
the learning event stream's subscriber (stored before the notify, under the lock the stream waits
with) and drops it when nobody subscribes: delivery is the drop, and a reconnecting core reads
the physical state instead of a replay. GET /learn/events is one SSE stream per subscriber
(keepalives when idle; its connection ends it). Untagged mutations are unchanged.

tests/learn-tickets.py: a ticketed revoke and unload answer only their ticket and their terminal
results arrive on the stream; a result made with no subscriber is never replayed (mutation: keep
it for a later subscriber -> fails).
@joelteply
joelteply changed the base branch from cormac/ledger-off-loop to codex/s4-per-mind-integration November 11, 2026 18:09
@joelteply
joelteply merged commit f76ef34 into codex/s4-per-mind-integration Nov 11, 2026
14 of 17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant