symfonic.kernel.run_observation¶
run_observation ¶
What a runner opens around one turn so the turn can be observed.
Two things belong to the run rather than to any step of it: the identity every
observer correlates on, and the stage traces the run publishes as its
capabilities execute. They were two modules of about twenty lines each, and the
runner had to remember to open one, thread run_id and the trace sink
through five call sites, and close the other in a finally.
One object owns both now. The runner opens it, hands it the traces each phase produced, and closes it -- and the correlation identifier is never passed again, because the thing publishing already knows which run it is.
Metadata only, and that is a contract not a convenience. A stage trace carries the stage's name, phase, capability and outcome. It never carries the subject a stage acted on or the payload it produced: this stream reaches durable storage and an operator's screen, and a memory's text on either would be a leak that no consumer could opt out of.
Emitter ¶
RunObservation ¶
The identity a run carries, and the traces it publishes.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
context
|
Any
|
the invocation context, which owns |
required |
request
|
Any
|
the turn request, which may name a root and a parent when this run is a delegated child. |
required |
callbacks
|
Any
|
unused now that stage events ride the ordinary channel; kept so the signature still says what a run is given. |
required |
emitter
|
Any
|
the run's event factory. Stage events take their index
from it, so they sit in the same dense sequence as the model
and tool events and a reader can reconstruct the turn in
order. They were emitted at |
None
|
Source code in src/symfonic/kernel/run_observation.py
close ¶
Release the identity. Idempotent, because teardown has two paths.
stage_events ¶
One phase's stage records, as events on the run's own sequence.
Returned rather than published, because the caller is an async generator and these have to be yielded: the public stream and the durable execution log must be two readers of one event, and an event delivered only to callbacks is a second channel that can disagree with the first about what a turn did.
Indices come from the run's emitter, so a stage sits in order among
the model and tool events and a reader can place a retrieval against
the round it fed. They were emitted at index=-1 before this, which
is not a position: two of them could not be told apart.
Source code in src/symfonic/kernel/run_observation.py
terminal_on_exit
async
¶
Record — and where owed, deliver — the cancelled terminal (CXL-2).
Cancellation is not an error, so it never emits an error event. If
the stream already went terminal the emitter refuses a second one
(EVT-1), and there is nothing left to say.
reason is the run's own teardown word — disconnected when the
consumer walked away, cancelled when this task was cancelled — and
it rides on the terminal so an observer can tell the two apart. Both
are kind="cancelled": they end the stream the same way, and they
mean different things about who stopped it (TA8.29).