symfonic.kernel.post_model¶
post_model ¶
The post-model seam: capability stages that read a completed round.
23 slice 1. Until this module the ladder was a vocabulary with one rung wired¶
— run_phase was called from prompt_assembly and nowhere else, so a
capability declaring a stage in any other phase compiled into a plan, took its
place in the order, received its effect grants, and was never invoked.
Three things this deliberately does not do, each because the plan for #23 says so and each with a reason in the code rather than in the plan:
- it does not bind.
run_prompt_assemblyopens the turn;RequestContext.bind_generationis write-once and raises on a second call. By the time apost-modelstage runs the turn is already open, so this module dispatches and nothing else — no bind, no assembly, norequire_no_failed_stage. - it applies nothing.
apply=Noneis the documented case indispatch's own docstring, not a placeholder: no contract exists yet for what apost-modelcontribution mutates. Deciding that is the governance-attachment work, and inventing it here would be the fabricationT3.5.2refused onrun. - it grants explicitly.
grants=defaults toNoneinrun_phase, andNoneskips the effect check (dispatch._ungranted). A new call site that forgets it reopens STG-8 silently — the PR #92 class, which is why the plan enumerates it and why a test names it.
PostModelContext
dataclass
¶
PostModelContext(plan: Any, request: Any, stage: Any, resolved: Any, turn: Any, transcript: Any = None)
What a post-model stage is handed.
Carries the whole ModelTurn rather than a pre-interpreted "draft".
A seam that extracted the answer text would be choosing, for every future
capability, which part of a round matters — and the two capabilities this
phase is for disagree already: fabrication reads text, budget reads
text and pinned content. The turn is the fact; the reading is the stage's.
No RequestContext, for the reason StageContext states: a stage
returns rather than mutates, so handing it the mutable run context would be
handing it the thing it must not touch.
run_post_model
async
¶
run_post_model(plan: Any, request: Any, turn: Any, *, resolved: Any = None, transcript: Any = None, handlers: Mapping[str, StageHandler] | None = None) -> tuple[StageTrace, ...]
Dispatch the post-model stages for one completed model round.
Handlers come from plan.bindings.stage_handlers — G6, where the plan
already keeps its live callables — overlaid with handlers, which exists
for tests and for a composition root that has not moved yet. Additive, so a
plan's own handler cannot be silently replaced.
Returns the traces. The runner discards them today for the same reason it
discards prompt-assembly's: RequestContext has no runtime-diagnostic
slot. Returning them rather than swallowing them is what lets that change
without touching this module.