diff --git a/docs/specification.md b/docs/specification.md index dbe7bd381..4d34da4c7 100644 --- a/docs/specification.md +++ b/docs/specification.md @@ -19798,8 +19798,8 @@ The system collects, reconciles, and checks invariants: or self.get_global_invariant_actor() ) - # 3. Reconcile: apply precedence (plan > project > global), resolve conflicts - effective = reconciler.reconcile(raw, precedence=['plan', 'project', 'global']) + # 3. Reconcile: apply precedence (plan > action > project > global), resolve conflicts + effective = reconciler.reconcile(raw, precedence=['plan', 'action', 'project', 'global']) return effective def collect_all_invariants(self, plan): @@ -19820,6 +19820,22 @@ The system collects, reconciles, and checks invariants: return Success() +#### Reconciliation Failure Behavior + +When invariant reconciliation fails at a phase transition, the transition is **blocked** — the plan cannot proceed to the next phase until the invariants are corrected. The system raises a `ReconciliationBlockedError` and emits an `INVARIANT_VIOLATED` event on the event bus. + +Reconciliation runs at the start of three phase transitions: + +| Phase Transition | Method | Behavior on Failure | +|---|---|---| +| Strategize start | `start_strategize()` | Raises `ReconciliationBlockedError`; plan stays in `PENDING` state | +| Execute start | `execute_plan()` | Raises `ReconciliationBlockedError`; plan stays in `STRATEGIZED` state | +| Apply start | `apply_plan()` | Raises `ReconciliationBlockedError`; plan stays in `EXECUTED` state | + +After a correction is applied (`agents plan correct`), reconciliation automatically re-runs via a `CORRECTION_APPLIED` event subscription (best-effort; does not block correction completion). + +The built-in reconciliation actor is registered as `builtin/invariant-reconciliation`. + #### Layer 4: Predictive Error Prevention The system learns from past failures: