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
|
plan
|
Any
|
the compiled plan; its effect grants and stage effects stamp the run's monotone memory marker (CORE-194). |
None
|
Source code in src/symfonic/kernel/run_observation.py
bind ¶
Make this run current for the generator step about to execute (CORE-194).
The runner is a generator its consumer may step from a fresh task, or alternately with another run. Bound per step and released before the step yields, the run's own code always sees its own lineage, and the consumer keeps none of it between steps.
Source code in src/symfonic/kernel/run_observation.py
close ¶
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
stepped
async
¶
Relay source, binding its run around each step and its teardown.
holder receives the run's :class:RunObservation once the source
opens it; until then the source's first step binds the run itself.
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).