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: