Skip to content

Correction Loop

The correction loop creates approval-gated remediation proposals after a halt or warning. It does not release replacement text automatically. A proposal must first pass cross-verifier consensus with an allow decision, then receive an explicit operator approval ID before release() returns candidate text. For a durable reviewer inbox and append-only decision trail, enqueue proposals into HumanReviewQueue.

Physical-domain and irreversible actions are rejected at proposal time. Those cases must stay in the no-go or human-review path because automatic remediation can hide actuator, security, or irreversible operational risk.

Usage

from director_ai.core import CorrectionLoop
from director_ai.core.guard_control import RiskEnvelope, VerifierSignal
from director_ai.core.scoring.consensus import CrossVerifierConsensus

loop = CorrectionLoop(
    consensus=CrossVerifierConsensus(),
    risk_envelope=RiskEnvelope(
        action_category="text",
        reversibility="reversible",
        domain="regulated",
        calibrated_threshold=0.65,
        no_go_threshold=0.9,
    ),
    policy_id="policy.correction.regulated",
)

proposal = loop.propose(
    candidate_text="Corrected response text.",
    signals=[
        VerifierSignal(
            verifier="nli",
            modality="text",
            score=0.08,
            verdict="supported",
            confidence_low=0.03,
            confidence_high=0.14,
            evidence_refs=("kb://fact-1",),
        )
    ],
    evidence_refs=("trace://halt-7",),
)

approved = loop.approve(proposal, approval_id="review-20260513-001")
released_text = loop.release(approved)

Use propose_from_halt() when the correction should be built from structured halt evidence. The loop constructs a HaltCorrectionContext from evidence chunks and trace attribution, passes that context to a continuation builder, then applies the same cross-verifier consensus and approval gate.

from director_ai.core import GroundedCorrectionDraft


def build_candidate(context):
    return GroundedCorrectionDraft(
        candidate_text="Corrected response text with source citation.",
        verifier_signals=(nli_signal,),
        evidence_refs=context.source_refs,
    )


proposal = loop.propose_from_halt(
    halt_evidence=halt_evidence,
    continuation_builder=build_candidate,
    structured_recovery=session.structured_recovery,
)

Audit Boundary

CorrectionProposal.to_dict() excludes candidate_text by default so shared audit records do not leak generated payloads. Use include_candidate=True only inside a tenant-controlled forensic store. Structured recovery audit records include metadata, errors, validity, and halt offset; they do not include raw partial output or recovered payload text.

Full API

director_ai.core.runtime.correction.CorrectionLoop

CorrectionLoop(*, consensus: CrossVerifierConsensus, risk_envelope: RiskEnvelope, policy_id: str)

Build and release correction proposals under verifier consensus control.

propose

propose(*, candidate_text: str, signals: Sequence[VerifierSignal], evidence_refs: Sequence[str] = (), structured_recovery: StructuredRecoveryResult | None = None) -> CorrectionProposal

Return an unreleased correction proposal guarded by verifier consensus.

propose_from_halt

propose_from_halt(*, halt_evidence: HaltEvidence, continuation_builder: Callable[[HaltCorrectionContext], GroundedCorrectionDraft], structured_recovery: StructuredRecoveryResult | None = None) -> CorrectionProposal

Build an unreleased grounded correction proposal from halt evidence.

approve

approve(proposal: CorrectionProposal, *, approval_id: str) -> CorrectionProposal

Approve a proposal that consensus already allowed.

release

release(proposal: CorrectionProposal) -> str

Return candidate text only after consensus allow and explicit approval.

director_ai.core.runtime.correction.CorrectionProposal dataclass

CorrectionProposal(proposal_id: str, candidate_text: str, evidence_refs: Sequence[str], guard_decision: GuardDecision, structured_recovery: StructuredRecoveryResult | None = None, approved: bool = False, approval_id: str = '')

Correction candidate with verifier evidence and an explicit release gate.

to_dict

to_dict(*, include_candidate: bool = False) -> dict[str, Any]

Serialise a tenant-safe audit payload.

Generated candidate text is excluded by default because audit streams often cross tenant and operator boundaries.

to_safety_event

to_safety_event(*, hook_id: str, hook_scope: str, request_id: str = '', tenant_id: str = '', latency_ms: float | None = None) -> SafetyEvent

Convert the proposal decision to the shared safety-event schema.

director_ai.core.runtime.correction.HaltCorrectionContext dataclass

HaltCorrectionContext(halt_reason: str, last_score: float, evidence_texts: Sequence[str], source_refs: Sequence[str], trace_refs: Sequence[str] = (), suggested_action: str = '')

Tenant-local evidence context passed to a correction continuation builder.

director_ai.core.runtime.correction.GroundedCorrectionDraft dataclass

GroundedCorrectionDraft(candidate_text: str, verifier_signals: Sequence[VerifierSignal], evidence_refs: Sequence[str])

Candidate continuation and verifier evidence produced from halt evidence.