You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/concepts/interaction-pattern-catalog.md
+141-1Lines changed: 141 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -88,7 +88,7 @@ Map P0/P1 catalog rows to canary archetypes before picking commands:
88
88
| --- | --- | --- | --- | --- | --- |
89
89
| Work Routing | IP-001, IP-002, IP-003, IP-007, IP-008, IP-021, IP-029 | Hot-path route canary; Planning governance canary when cadence or repair is involved |`quota should-run`, `interaction_contract`, `work_lane_contract`, scheduler hint, handoff todo state | one eligible delivery fixture, one blocked/fallback fixture, one quiet or monitor fixture | agent turn routing is unsafe: it may spend, wait, notify, or choose fallback incorrectly |
90
90
| Human Decision | IP-004, IP-014, IP-017, IP-027, IP-030, IP-033 | Scoped decision canary; Product/readiness canary when first-screen human copy changes | user todos, decision scope, operator-gate/reward preview, deferred resume candidates | one concrete user ask, one scoped non-blocking gate, one preview-or-append dry run | humans may be asked the wrong question, or an agent may continue without the needed decision |
91
-
| State And Boundary | IP-005, IP-006, IP-011, IP-016, IP-019, IP-020, IP-022, IP-023, IP-025, IP-026, IP-028, IP-031, IP-032, IP-035, IP-036| Projection and boundary canary; Hot-path route canary when the projection feeds quota/status | active state, todo metadata, task graph, authority source, claim lease, completed-work archive, install ownership, connector runtime policy, operation receipt, public/private scan | fixture state plus structured projection check; boundary scan for touched public files | compact state and executable truth diverge, so dashboards and agents may trust stale or unsafe authority |
91
+
| State And Boundary | IP-005, IP-006, IP-011, IP-016, IP-019, IP-020, IP-022, IP-023, IP-025, IP-026, IP-028, IP-031, IP-032, IP-035, IP-036, IP-037 | Projection and boundary canary; Hot-path route canary when the projection feeds quota/status | active state, todo metadata, task graph, authority source, claim lease, completed-work archive, install ownership, connector runtime policy, operation receipt, retired setting projection, public/private scan | fixture state plus structured projection check; boundary scan for touched public files | compact state and executable truth diverge, so dashboards and agents may trust stale or unsafe authority |
92
92
| Evidence Lifecycle | IP-012, IP-015 | Evidence lifecycle canary; Product/readiness canary when evidence is rendered | external handle observation, benchmark lifecycle reducer, compact result projection | compact public-safe evidence fixture with raw-material exclusion assertions | progress evidence may be missing, double-counted, or represented with unsafe raw material |
93
93
| Planning Governance | IP-010, IP-013, IP-018, IP-024, IP-034 | Planning governance canary; Hot-path route canary when cadence changes affect execution | stalled run history, autonomous replan obligation, repair delta, cadence hint, plan-to-todo writeback | two-turn stalled fixture plus repair/writeback delta assertion | the agent may keep planning in prose while the machine-visible frontier stays unchanged |
| P1 | IP-032 | Completed Work Archive With Durable Decision Retention | Archive selector plus controller | no interruption; preview-then-execute readback | treat archived done work as history, keep durable decisions authoritative, and never move another role's lane |
346
346
| P1 | IP-035 | Install Ownership Is Not An Update Permission | Install lifecycle owner plus user | no silent mutation; report the owning installer and its command | classify the install before mutating it; when LoopX does not own it, hand back the owner-owned command instead of switching install channels |
347
347
| P1 | IP-036 | A Lost Response Is Not An Absent Commit | Effect dispatcher plus caller | no interruption unless recovery needs a user decision; report the receipt read back | name the write with a stable operation id, recover by readback instead of blind retry, and never leave a committed record pointing at material nobody published |
348
+
| P1 | IP-037 | A Retired Setting Is Not An Absent Setting | Configuration reader plus migration owner | no interruption; keep the retired entry visible and read-only where it was once configurable | reject the retired activation before any write, carry its reason in the projection, and treat clearing it as neither enable nor bootstrap of the replacement |
348
349
349
350
### Evidence Lifecycle
350
351
@@ -2620,6 +2621,145 @@ flowchart TD
2620
2621
recovery path reuses it instead of inventing a fourth answer.
2621
2622
-`examples/interaction-pattern-catalog-smoke.py` protects this entry.
2622
2623
2624
+
#### IP-037 A Retired Setting Is Not An Absent Setting
2625
+
2626
+
**Trigger**
2627
+
2628
+
- a Goal, registry entry, or settings document still names a configuration
2629
+
whose implementation has been retired, so a reader must decide whether that
2630
+
setting is off, missing, or still writable;
2631
+
- the caller is about to re-enable it, clear it, or migrate state that mentions
2632
+
it, and the cheapest wrong move is to treat "no longer supported" as "never
2633
+
existed";
2634
+
- the signals that say this already happened are typed, not inferred from
2635
+
prose: a summary carrying `configured: true` with
2636
+
`status: "retired"` and `enabled: false`, a migration row with
2637
+
`attempted: false` and `outcome: "retired"`, a
2638
+
`request_rejected / local_authority_shadow_retired` reply, or a
2639
+
`retired corpus requires lifecycle.retirement_reason` rejection.
2640
+
2641
+
**Expected behavior**
2642
+
2643
+
Retiring a capability removes what it may write, not what it says. Four rules
2644
+
keep "we stopped supporting this" from becoming "this was never configured".
2645
+
2646
+
1.**Keep the retired setting in the projection.** The summary of a Goal that
2647
+
still carries the old key stays present and self-describing rather than
2648
+
dropping the field: `local_authority_shadow_summary` returns
2649
+
`{"enabled": False, ..., "status": "retired" if valid else "invalid",
2650
+
"configured": True, ...}`
2651
+
(`loopx/control_plane/coordination/runtime_shadow.py:53-63`), so a malformed
2652
+
setting reads as `invalid` and a retained one reads as `retired` — neither
2653
+
collapses into "unconfigured". Historical records under the old path remain
2654
+
readable and are labelled instead of being relabelled as promotion evidence:
2655
+
`local_authority_shadow_adapter.py:784` computes `legacy_observation` and
2656
+
`:805` stamps each candidate store as `legacy_observation` or
2657
+
`runtime_shadow`.
2658
+
2.**Reject re-enabling before any write, and reject it by code.** The gate sits
2659
+
ahead of the mutation, not inside it:
2660
+
`validate_coordination_shadow_changes` is documented as "Reject retired
2661
+
activation before any registry mutation"
2662
+
(`loopx/control_plane/coordination/runtime_shadow.py:103-115`) and carries the
2663
+
reason in its message (`:67-78`, text at `:72`). The old runtime RPC keeps
2664
+
its address and answers `local_authority_shadow_retired`
2665
+
(`loopx/control_plane/coordination/local_authority_shadow.ts:57`) rather than
2666
+
disappearing into a transport error, because a rejection that looks like a
2667
+
transient failure invites a retry loop.
2668
+
3.**Clearing is neither enable nor bootstrap.** One setting is retired; the
2669
+
replacement capture path is configured on its own terms.
2670
+
`apply_coordination_shadow_changes` is documented as "Clear retired settings
2671
+
and configure the transaction-bound shadow independently"
2672
+
(`loopx/control_plane/coordination/runtime_shadow.py:117-131`), and
2673
+
`tests/control_plane/test_local_authority_shadow_config.py:58` pins that
2674
+
clearing preserves the runtime configuration and peer registration instead of
2675
+
silently starting the new capture.
2676
+
4.**Migration reports the retirement rather than seeding it.**`migrate-state`
2677
+
keeps the response field callers already parse and answers it with a
0 commit comments