symfonic.platform.governance¶
governance ¶
The governance door: one call a composition root makes.
The rung mapping and the reading of a turn live in
:mod:symfonic.platform.governance_rungs; this file is the entry point and
nothing else, so the thing an adopter imports is the thing they read first.
GovernanceStages ¶
A composable wrapper around a built governance pipeline.
The object a composition root passes to Agent(capabilities=[...]).
It holds the capability rather than subclassing it: governance answers
"what does this turn get, and why", and this answers "which rungs does that
run on" -- two questions, and merging them is what would put kernel imports
back inside the contained package.
Source code in src/symfonic/platform/governance.py
capability
property
¶
The governed pipeline, for a caller that wants the trace directly.
contribute ¶
Declare the rungs this pipeline runs on, and the handlers for them.
Classification and reflection may call a model and declare that effect when composed. Refusal and deterministic checks need no additional effect grant.
Source code in src/symfonic/platform/governance.py
governance ¶
Build the safety layer and bind it to the rungs that run it.
One call, in the shape memory_capabilities(store, scope) established:
sensible defaults, every port injectable, nothing required.
Agent(provider, capabilities=[governance(reflector=my_reflector)])
Every keyword is forwarded to GovernanceCapability.compose, which
leaves a stage out rather than in-but-inert when its port is missing.
Credential-shaped tool results and errors stop the turn before the next
model call. POST_TOOL cannot deliver a sanitized replacement: this is a
refusal boundary, not redaction of the transcript or already emitted events.
Default patterns may also match benign text; deployments can narrow them
explicitly through patterns.
decisions is the exception, and it is held here rather than forwarded:
what governance decided about a rung is a fact about the kernel mapping,
not about the safety pipeline, which does not know a rung exists. Passing
a sink -- any object with record(decision), such as DecisionLog --
turns those decisions into a readable record::
log = DecisionLog()
Agent(provider, capabilities=[governance(guards=[...], decisions=log)])
Omitted, nothing is recorded: a deployment that never asked for a decision log does not accumulate one for the life of the process.