From c2fe2f583d5807f96ab9c78d9f2023fbed61533e Mon Sep 17 00:00:00 2001 From: BigDataDZ <76271875+BigDataDZ@users.noreply.github.com> Date: Sun, 13 Sep 2026 15:53:25 +0800 Subject: [PATCH] docs(catalog): align pattern details order with the catalog table The catalog keeps two ordered views of the same patterns: the per-family catalog table and the Pattern Details block. Two families disagreed, so the details order did not mirror the table it summarizes. Work Routing lists IP-029 Handoff Todo Gate State in its table and in the pattern-to-canary matrix, and the IP-026 cross-references describe it as a routing gate, but the details block placed it under Human Decision. Move the IP-029 detail entry into the Work Routing block, between IP-003 and IP-021. State And Boundary lists IP-026 Agent-Scoped No-Candidate Gap as a P0 row directly after IP-006, but the details block placed it after IP-022, inside the P1 group, so a P0 boundary pattern read as if it were P1. Move the IP-026 detail entry to sit after IP-006 and before IP-011. Both entries are relocated verbatim. No IP wording, priority, or family membership changes, and the file keeps its line multiset (190 insertions against 190 deletions). Signed-off-by: BigDataDZ <76271875+BigDataDZ@users.noreply.github.com> --- docs/concepts/interaction-pattern-catalog.md | 380 +++++++++---------- 1 file changed, 190 insertions(+), 190 deletions(-) diff --git a/docs/concepts/interaction-pattern-catalog.md b/docs/concepts/interaction-pattern-catalog.md index 69224b4b12..33b556fdc5 100644 --- a/docs/concepts/interaction-pattern-catalog.md +++ b/docs/concepts/interaction-pattern-catalog.md @@ -613,6 +613,86 @@ IP-003 scope metadata being ignored by the user-todo blocking summary. delivery. - `docs/archive/incidents/agent-scoped-user-gate-overreach-incident-20260624.md` +#### IP-029 Handoff Todo Gate State + +**Trigger** + +- a todo carries `blocks_agent=` and represents review, handoff, + unblock, or owner work for that agent; +- the todo status changes among open/blocked, done, deferred, or superseded; +- the todo may name a follow-up via `unblocks_todo_id`, + `resume_when=todo_done:`, or `superseded_by`; and +- `quota should-run --agent-id ` needs to decide whether the agent + should wait, replan, or run a concrete successor. + +**Expected behavior** + +`blocks_agent` todos are not only backlog rows. They are inter-agent gate +states. Status should project `agent_todos.handoff_gates[]` from the complete +todo list, not only from open lanes, using `todo_handoff_gate_v0`. + +| gate_state | Todo condition | Quota effect | +| --- | --- | --- | +| `blocking` | non-terminal handoff todo for the scoped agent | return `agent_scope_wait`; name the owning reviewer/agent rather than waking the blocked agent for delivery | +| `cleared_without_successor` | done handoff with no stable successor or supersede link | return `successor_replan_required`; reopen, supersede, or record no-follow-up rationale | +| `cleared_with_successor` | done handoff linked to a successor via `unblocks_todo_id`, `resume_when`, or `superseded_by` | route to the concrete successor through normal todo selection | +| `cleared_no_followup` | done handoff carries `no_followup=true` with a compact rationale | keep as terminal history; do not wake the blocked agent for successor replan | +| `superseded` | handoff todo carries `superseded_by` | keep as history; do not wake the blocked agent from the stale gate | +| `deferred` | handoff todo is parked behind an unsatisfied resume condition | keep diagnostic visibility; IP-027 owns the ready-deferred resume path | + +Quota ordering matters. Current-agent ordinary advancement still wins normal +delivery. If no ordinary current-agent successor is ready, a current-agent +`blocking` handoff wins over stale done handoffs. A +`cleared_without_successor` handoff wins over generic IP-026 no-candidate wait +because it means the handoff state changed but no replayable successor exists. +Only after those checks may IP-026 classify `scope_exhausted` or +`agent_scope_wait`. + +**Visual Model** + +```mermaid +flowchart TD + T["blocks_agent todo"] --> S{"todo lifecycle"} + S -->|"open / blocked"| B["handoff gate: blocking"] + B --> W["agent_scope_wait for blocked agent"] + S -->|"done + successor"| C["handoff gate: cleared_with_successor"] + C --> N["run concrete successor normally"] + S -->|"done + no successor"| R["handoff gate: cleared_without_successor"] + R --> L["successor_replan_required"] + L --> F["reopen / supersede / no-follow-up rationale"] + S -->|"open + stale closeout"| X["route continuation replan required"] + X --> L + S -->|"superseded_by"| H["handoff gate: superseded"] + H --> I["historical only"] + S -->|"deferred"| D["handoff gate: deferred"] + D --> P["IP-027 resume rules"] +``` + +**Bad smell** + +A done review/handoff todo disappears because only open lanes feed quota, so +the blocked agent falls into a vague `agent_scope_wait`. The opposite bad smell +is also harmful: a stale done handoff outranks a live open review blocker, so +the agent replans while a real reviewer-owned gate is still open. Both are +state-machine bugs, not prompt wording bugs. + +A third bad smell is an open handoff gate whose action is already a stale +handoff closeout. That gate is no longer a live reviewer decision. It should +project `route_continuation_replan_required` so quota wakes successor replan to +reopen, supersede, or close the stale route with a no-follow-up rationale. + +**Validation** + +- `loopx/control_plane/todos/handoff_gate.py` owns the + `todo_handoff_gate_v0` projection. +- `examples/control_plane/quota-cleared-blocker-successor-gate-smoke.py` covers + `blocking`, `cleared_without_successor`, `cleared_with_successor`, and + `superseded` gate states. +- `docs/quota-allocation.md` +- `docs/status-data-contract.md` +- `skills/loopx-self-repair/references/repair-patterns.md` records + `handoff_gate_state_projection_gap` for incident triage. + #### IP-021 Per-Todo Capability Gate **Trigger** @@ -992,86 +1072,6 @@ step, so stale or future work outranks live open tasks. - `skills/loopx-self-repair/references/repair-patterns.md` records `deferred_gate_resume_misclassified` for incident triage. -#### IP-029 Handoff Todo Gate State - -**Trigger** - -- a todo carries `blocks_agent=` and represents review, handoff, - unblock, or owner work for that agent; -- the todo status changes among open/blocked, done, deferred, or superseded; -- the todo may name a follow-up via `unblocks_todo_id`, - `resume_when=todo_done:`, or `superseded_by`; and -- `quota should-run --agent-id ` needs to decide whether the agent - should wait, replan, or run a concrete successor. - -**Expected behavior** - -`blocks_agent` todos are not only backlog rows. They are inter-agent gate -states. Status should project `agent_todos.handoff_gates[]` from the complete -todo list, not only from open lanes, using `todo_handoff_gate_v0`. - -| gate_state | Todo condition | Quota effect | -| --- | --- | --- | -| `blocking` | non-terminal handoff todo for the scoped agent | return `agent_scope_wait`; name the owning reviewer/agent rather than waking the blocked agent for delivery | -| `cleared_without_successor` | done handoff with no stable successor or supersede link | return `successor_replan_required`; reopen, supersede, or record no-follow-up rationale | -| `cleared_with_successor` | done handoff linked to a successor via `unblocks_todo_id`, `resume_when`, or `superseded_by` | route to the concrete successor through normal todo selection | -| `cleared_no_followup` | done handoff carries `no_followup=true` with a compact rationale | keep as terminal history; do not wake the blocked agent for successor replan | -| `superseded` | handoff todo carries `superseded_by` | keep as history; do not wake the blocked agent from the stale gate | -| `deferred` | handoff todo is parked behind an unsatisfied resume condition | keep diagnostic visibility; IP-027 owns the ready-deferred resume path | - -Quota ordering matters. Current-agent ordinary advancement still wins normal -delivery. If no ordinary current-agent successor is ready, a current-agent -`blocking` handoff wins over stale done handoffs. A -`cleared_without_successor` handoff wins over generic IP-026 no-candidate wait -because it means the handoff state changed but no replayable successor exists. -Only after those checks may IP-026 classify `scope_exhausted` or -`agent_scope_wait`. - -**Visual Model** - -```mermaid -flowchart TD - T["blocks_agent todo"] --> S{"todo lifecycle"} - S -->|"open / blocked"| B["handoff gate: blocking"] - B --> W["agent_scope_wait for blocked agent"] - S -->|"done + successor"| C["handoff gate: cleared_with_successor"] - C --> N["run concrete successor normally"] - S -->|"done + no successor"| R["handoff gate: cleared_without_successor"] - R --> L["successor_replan_required"] - L --> F["reopen / supersede / no-follow-up rationale"] - S -->|"open + stale closeout"| X["route continuation replan required"] - X --> L - S -->|"superseded_by"| H["handoff gate: superseded"] - H --> I["historical only"] - S -->|"deferred"| D["handoff gate: deferred"] - D --> P["IP-027 resume rules"] -``` - -**Bad smell** - -A done review/handoff todo disappears because only open lanes feed quota, so -the blocked agent falls into a vague `agent_scope_wait`. The opposite bad smell -is also harmful: a stale done handoff outranks a live open review blocker, so -the agent replans while a real reviewer-owned gate is still open. Both are -state-machine bugs, not prompt wording bugs. - -A third bad smell is an open handoff gate whose action is already a stale -handoff closeout. That gate is no longer a live reviewer decision. It should -project `route_continuation_replan_required` so quota wakes successor replan to -reopen, supersede, or close the stale route with a no-follow-up rationale. - -**Validation** - -- `loopx/control_plane/todos/handoff_gate.py` owns the - `todo_handoff_gate_v0` projection. -- `examples/control_plane/quota-cleared-blocker-successor-gate-smoke.py` covers - `blocking`, `cleared_without_successor`, `cleared_with_successor`, and - `superseded` gate states. -- `docs/quota-allocation.md` -- `docs/status-data-contract.md` -- `skills/loopx-self-repair/references/repair-patterns.md` records - `handoff_gate_state_projection_gap` for incident triage. - #### IP-014 Decision Write Preview And Append **Trigger** @@ -1333,6 +1333,116 @@ the checkpointed decision. - `examples/project/configure-goal-smoke.py`; - `docs/state-interaction-model.md` checkpointed decision sections. +#### IP-026 Agent-Scoped No-Candidate Gap + +**Trigger** + +- `quota should-run --agent-id ` returns `should_run=true` or + `interaction_contract.agent_channel.must_attempt=true`; +- the same payload has no `agent_lane_next_action`; +- `current_agent_claimed_advancement_items` is empty; +- no runnable candidate is projected for that agent; +- no current-agent or unclaimed deferred resume candidate is ready; and +- the recommended action points at another agent's lane, an out-of-scope lane, + or a goal-level route the current agent cannot safely advance. + +**Expected behavior** + +Agent-scoped quota must distinguish "the goal has runnable work" from "this +agent has runnable work." When the current agent has no in-scope candidate, +quota should not force a delivery turn. This pattern applies only after the +guard has also checked IP-027 and found no ready current-agent or unclaimed +deferred resume candidate, and after IP-029 has found no current-agent handoff +gate state that should wait or replan. If a deferred resume candidate is ready, +IP-027 owns the `successor_replan_required` path; if a handoff review todo has +changed state, IP-029 owns the handoff wait or successor-replan path. IP-026 +must not swallow either case as "nothing runnable." + +When the scoped frontier is truly empty, quota should project one of these +machine states: + +- `scope_exhausted`: no current-agent or unclaimed candidate matches the + registered agent profile and boundary; +- `agent_scope_wait`: an explicit blocking review/handoff dependency is owned + by another peer and must clear before the current peer can continue; +- `reassignment_required`: useful work exists, but ownership must be changed + before this agent may treat it as its lane. + +The interaction contract should then set: + +```text +agent_channel.must_attempt=false +agent_channel.delivery_allowed=false +agent_channel.quiet_noop_allowed=true +``` + +The user channel remains quiet unless a concrete user todo exists. The +recommended action should name the scoped condition, not borrow the global +goal-level route. A peer should be allowed to no-op without spend, or +claim a newly exposed in-scope todo before delivery becomes allowed again. + +This pattern is the runtime counterpart of IP-022. IP-022 makes claimed, +deferred, handoff, and agent-lane work visible; IP-026 says what to do when the +scoped open frontier is empty, IP-027 has not found a ready deferred gate +resume, and IP-029 has not found a handoff todo gate state for the scoped +agent. +If the only apparent blocker is a user todo with `blocks_agent` pointing at a +different agent, IP-003 owns the case before IP-026: filter that other-agent +gate out of the current agent's blocking user summary, then decide whether the +current agent still has runnable work. If it does, delivery may continue; if it +does not, IP-026 can classify the remaining empty frontier. + +**Visual Model** + +```mermaid +flowchart TD + Q["quota should-run --agent-id side"] --> F{"current-agent frontier?"} + F -->|"current-agent candidate"| D["bounded delivery allowed"] + F -->|"unclaimed in-scope candidate"| C["agent may claim before delivery"] + F -->|"no open candidate"| R{"IP-027 ready deferred resume?"} + R -->|"yes"| P["defer to IP-027"] + R -->|"no"| G{"IP-029 handoff gate state?"} + G -->|"blocking or cleared_without_successor"| K["defer to IP-029"] + G -->|"none"| X["scope_exhausted / agent_scope_wait"] + F -->|"only other-agent or out-of-scope work"| X + X --> N["quiet no-op, no spend"] + X --> H["owning agent may advance, merge, or reassign"] + H --> Q +``` + +**Bad smell** + +A peer heartbeat receives `should_run=true`, +`delivery_allowed=true`, and `quiet_noop_allowed=false` even though +`agent_lane_next_action=None`, `current_agent_claimed_advancement_items=[]`, +and the only recommendation is another agent's benchmark or runtime lane. The +agent either churns through repeated empty heartbeats or risks working outside +its registered scope. A related failure is treating a ready deferred successor +as part of this no-candidate pattern instead of routing it through IP-027's +gate-resume lifecycle, or treating a handoff todo lifecycle change as generic +agent wait instead of routing it through IP-029. The opposite bad smell is also +harmful: deferred or handoff items are mixed into the open todo list, so stale +or future work outranks live open tasks. + +**Validation** + +- future quota/status regression with two registered peers where all runnable + work is claimed by the other peer and the current `--agent-id` call returns + `reassignment_required` unless an explicit blocking review dependency exists; +- `examples/control_plane/work-lane-contract-smoke.py` should cover that an empty + current-agent frontier cannot produce `delivery_allowed=true`; +- `docs/project-agent-todo-contract.md` +- `docs/quota-allocation.md` +- `docs/status-data-contract.md` +- `examples/control_plane/quota-agent-scoped-user-gate-smoke.py` for the nearby case where + a user gate is real but scoped to a different agent and therefore must not + create current-agent scope exhaustion. +- `examples/control_plane/quota-cleared-blocker-successor-gate-smoke.py` for the nearby + case where a `blocks_agent` handoff todo directly controls the scoped gate. +- `skills/loopx-self-repair/references/repair-patterns.md` records + `agent_scoped_no_candidate_gap` and `handoff_gate_state_projection_gap` for + incident triage. + #### IP-011 Authority Material Intake **Trigger** @@ -1781,116 +1891,6 @@ monitor through status/quota/todo projection. - PR #262 / commit `292a2c8`: additive status/quota visibility lanes with a 16-item agent-facing cap. -#### IP-026 Agent-Scoped No-Candidate Gap - -**Trigger** - -- `quota should-run --agent-id ` returns `should_run=true` or - `interaction_contract.agent_channel.must_attempt=true`; -- the same payload has no `agent_lane_next_action`; -- `current_agent_claimed_advancement_items` is empty; -- no runnable candidate is projected for that agent; -- no current-agent or unclaimed deferred resume candidate is ready; and -- the recommended action points at another agent's lane, an out-of-scope lane, - or a goal-level route the current agent cannot safely advance. - -**Expected behavior** - -Agent-scoped quota must distinguish "the goal has runnable work" from "this -agent has runnable work." When the current agent has no in-scope candidate, -quota should not force a delivery turn. This pattern applies only after the -guard has also checked IP-027 and found no ready current-agent or unclaimed -deferred resume candidate, and after IP-029 has found no current-agent handoff -gate state that should wait or replan. If a deferred resume candidate is ready, -IP-027 owns the `successor_replan_required` path; if a handoff review todo has -changed state, IP-029 owns the handoff wait or successor-replan path. IP-026 -must not swallow either case as "nothing runnable." - -When the scoped frontier is truly empty, quota should project one of these -machine states: - -- `scope_exhausted`: no current-agent or unclaimed candidate matches the - registered agent profile and boundary; -- `agent_scope_wait`: an explicit blocking review/handoff dependency is owned - by another peer and must clear before the current peer can continue; -- `reassignment_required`: useful work exists, but ownership must be changed - before this agent may treat it as its lane. - -The interaction contract should then set: - -```text -agent_channel.must_attempt=false -agent_channel.delivery_allowed=false -agent_channel.quiet_noop_allowed=true -``` - -The user channel remains quiet unless a concrete user todo exists. The -recommended action should name the scoped condition, not borrow the global -goal-level route. A peer should be allowed to no-op without spend, or -claim a newly exposed in-scope todo before delivery becomes allowed again. - -This pattern is the runtime counterpart of IP-022. IP-022 makes claimed, -deferred, handoff, and agent-lane work visible; IP-026 says what to do when the -scoped open frontier is empty, IP-027 has not found a ready deferred gate -resume, and IP-029 has not found a handoff todo gate state for the scoped -agent. -If the only apparent blocker is a user todo with `blocks_agent` pointing at a -different agent, IP-003 owns the case before IP-026: filter that other-agent -gate out of the current agent's blocking user summary, then decide whether the -current agent still has runnable work. If it does, delivery may continue; if it -does not, IP-026 can classify the remaining empty frontier. - -**Visual Model** - -```mermaid -flowchart TD - Q["quota should-run --agent-id side"] --> F{"current-agent frontier?"} - F -->|"current-agent candidate"| D["bounded delivery allowed"] - F -->|"unclaimed in-scope candidate"| C["agent may claim before delivery"] - F -->|"no open candidate"| R{"IP-027 ready deferred resume?"} - R -->|"yes"| P["defer to IP-027"] - R -->|"no"| G{"IP-029 handoff gate state?"} - G -->|"blocking or cleared_without_successor"| K["defer to IP-029"] - G -->|"none"| X["scope_exhausted / agent_scope_wait"] - F -->|"only other-agent or out-of-scope work"| X - X --> N["quiet no-op, no spend"] - X --> H["owning agent may advance, merge, or reassign"] - H --> Q -``` - -**Bad smell** - -A peer heartbeat receives `should_run=true`, -`delivery_allowed=true`, and `quiet_noop_allowed=false` even though -`agent_lane_next_action=None`, `current_agent_claimed_advancement_items=[]`, -and the only recommendation is another agent's benchmark or runtime lane. The -agent either churns through repeated empty heartbeats or risks working outside -its registered scope. A related failure is treating a ready deferred successor -as part of this no-candidate pattern instead of routing it through IP-027's -gate-resume lifecycle, or treating a handoff todo lifecycle change as generic -agent wait instead of routing it through IP-029. The opposite bad smell is also -harmful: deferred or handoff items are mixed into the open todo list, so stale -or future work outranks live open tasks. - -**Validation** - -- future quota/status regression with two registered peers where all runnable - work is claimed by the other peer and the current `--agent-id` call returns - `reassignment_required` unless an explicit blocking review dependency exists; -- `examples/control_plane/work-lane-contract-smoke.py` should cover that an empty - current-agent frontier cannot produce `delivery_allowed=true`; -- `docs/project-agent-todo-contract.md` -- `docs/quota-allocation.md` -- `docs/status-data-contract.md` -- `examples/control_plane/quota-agent-scoped-user-gate-smoke.py` for the nearby case where - a user gate is real but scoped to a different agent and therefore must not - create current-agent scope exhaustion. -- `examples/control_plane/quota-cleared-blocker-successor-gate-smoke.py` for the nearby - case where a `blocks_agent` handoff todo directly controls the scoped gate. -- `skills/loopx-self-repair/references/repair-patterns.md` records - `agent_scoped_no_candidate_gap` and `handoff_gate_state_projection_gap` for - incident triage. - #### IP-023 Status Neutral Run Window **Trigger**