Wire the InvariantReconciliationActor into PlanLifecycleService phase
transitions so that invariant reconciliation runs automatically at each
lifecycle boundary. This ensures plan invariants are verified before
processing can proceed.
Changes:
- Add InvariantService as a new optional dependency on PlanLifecycleService
(injected via the DI container as a Singleton provider)
- Add _run_invariant_reconciliation() method that creates and invokes the
reconciliation actor, emits INVARIANT_RECONCILED events on success, and
raises ReconciliationBlockedError (with INVARIANT_VIOLATED event) on
failure to block the phase transition
- Invoke reconciliation at three phase transition points:
1. start_strategize() - after preflight guardrails, before PROCESSING
2. execute_plan() - after estimation/error patterns, before Execute
3. apply_plan() - after state validation, before Apply transition
- Subscribe to CORRECTION_APPLIED events for post-correction reconciliation
(best-effort, failures logged but not re-raised)
- Per-plan disable: reconciliation is skipped when plan.invariant_actor is
None or "__optional__", following the established estimation actor pattern
- Decision recording: the reconciliation actor already records
invariant_enforced decisions via DecisionService
Tests:
- Behave: 10 scenarios in invariant_reconciliation_autowire.feature
covering auto-invocation, skip-when-disabled, transition blocking,
decision recording, and post-correction reconciliation
- Robot: 5 integration tests in invariant_reconciliation_autowire.robot
- All nox sessions pass (lint, typecheck, unit_tests, integration_tests,
coverage_report at 97%)
ISSUES CLOSED: #829