Skip to content

symfonic.capabilities.governance.values

values

The vocabulary every governance stage speaks (T3.4.4).

Four enums and three readings. Nothing here knows what a stage is; the types exist so a phase, a failure mode, and a disposition are values a reviewer can enumerate rather than strings a stage invents.

Disposition

Bases: StrEnum

What a working stage decided about this turn.

ALLOW nothing to say. ANNOTATE the subject was amended; the amendment travels onward. STEER an objection the model (or the caller) must act on; the turn continues, because a governance stage that halts on every objection cannot express "fix this and carry on". REFUSE terminal. No later stage runs.

Enforcement

Bases: StrEnum

The three-position knob every legacy governance flag already had.

OFF is a zero-cost guarantee, not a quiet allow: the pipeline does not run, so no classifier is called and no meter is read.

FailureMode

Bases: StrEnum

What the pipeline does when a stage fails, as opposed to objects.

An objection is the stage working. A raise is the stage broken. The two are separate axes and conflating them is how a crashed scrubber turns into a clean bill of health.

Finding dataclass

Finding(kind: str, detail: str = '', confidence: float = 1.0, stage: str = '', rule: str = '')

One piece of evidence a stage produced.

confidence is the number thresholds are read against. A stage that cannot estimate one states 1.0 and says so in detail rather than inventing a hedge.

with_stage

with_stage(stage: str) -> Finding

Stamp the stage, keeping everything else.

replace rather than a field-by-field rebuild: the rebuild dropped whichever field was added last, silently, and a finding that reaches an operator with its rule erased is worse than one that never travelled.

Source code in src/symfonic/capabilities/governance/values.py
def with_stage(self, stage: str) -> Finding:
    """Stamp the stage, keeping everything else.

    ``replace`` rather than a field-by-field rebuild: the rebuild dropped
    whichever field was added last, silently, and a finding that reaches
    an operator with its rule erased is worse than one that never
    travelled.
    """
    return replace(self, stage=stage)

GovernancePhase

Bases: StrEnum

When a stage runs, relative to the model and to the effects.

The phase is not decoration: it is what makes the canonical order checkable. A stage that claims INGRESS cannot be sequenced after one that claims EGRESS, because "before the model reads the turn" and "after the model has drafted" are not orderings a composition may reverse locally.

IntentReading dataclass

IntentReading(label: str, confidence: float = 0.0)

The classifier's answer about the user's turn.

Published once by the intent stage and read by later stages; the canonical order exists so that "later" is a fact rather than a hope.

Reflection dataclass

Reflection(revise: bool, reason: str = '', confidence: float | None = None)

The critic's answer about the draft.

ToolCall dataclass

ToolCall(name: str, args: Mapping[str, Any] = dict(), result: str = '')

A reading of one call: enough to govern it, not enough to run it.

with_result

with_result(result: str) -> ToolCall

Replace the result, keeping the call it belongs to.

The twin of :meth:with_args, and it exists because that method preserves result โ€” deliberately, since amending a call's inputs should not silently rewrite what it returned. Scrubbing the output is a separate decision and therefore a separate method.

Source code in src/symfonic/capabilities/governance/values.py
def with_result(self, result: str) -> ToolCall:
    """Replace the result, keeping the call it belongs to.

    The twin of :meth:`with_args`, and it exists because that method
    *preserves* ``result`` โ€” deliberately, since amending a call's inputs
    should not silently rewrite what it returned. Scrubbing the output is a
    separate decision and therefore a separate method.
    """
    return ToolCall(name=self.name, args=dict(self.args), result=result)