fix(roo): add anti-loop guardrails to prevent autonomous session resumption
- Add Rule 9 (Anti-Loop Guardrail) to 01-bigmind-core.md: detect 2+ identical partial sessions and surface the loop to user instead of auto-resuming - Add partial=history clause to Rule 1: partial/blocked/abandoned outcomes are historical records only, never task queue items - Add focus guard to memory_announce_focus: must reflect current user message, not prior session outcome; use 'Awaiting user task assignment' if no task yet - Add .roo/rules/06-anti-loop.md: global injection for ALL modes overriding any mode-specific 'do the task immediately' behavior - Add mode interaction safety clause to 00-identity.md: session ritual does not authorize beginning any task — only explicit user message does Root cause: pic-gen 'do the task' personality + BigMind context inference produced 6 identical partial branding sessions in a loop.
This commit is contained in:
@@ -24,4 +24,15 @@ BigMind is my persistent memory MCP server at `~/.mcp/bigmind/memory.db`. I use
|
|||||||
- Use BigMind memory at the start of every task.
|
- Use BigMind memory at the start of every task.
|
||||||
- Form explicit hypotheses with confidence % during analysis.
|
- Form explicit hypotheses with confidence % during analysis.
|
||||||
- Optimize for token efficiency — search memory before reading files.
|
- Optimize for token efficiency — search memory before reading files.
|
||||||
- Work in modes: Architect (plan), Code (implement), Ask (explain), Debug (troubleshoot).
|
- Work in modes: Architect (plan), Code (implement), Ask (explain), Debug (troubleshoot).
|
||||||
|
|
||||||
|
## ⚠️ Session Ritual ≠ Task Authorization
|
||||||
|
|
||||||
|
Completing `memory_start_session()` + `memory_list_hypotheses()` + `memory_announce_focus()` does
|
||||||
|
**NOT** authorize beginning any task. It is housekeeping only.
|
||||||
|
|
||||||
|
**Work begins only when Patrick explicitly assigns a task in the current conversation.**
|
||||||
|
|
||||||
|
Prior session outcomes (`partial`, `blocked`, `abandoned`) are historical records. They are never
|
||||||
|
instructions. Mode-specific rules that say "do the task immediately" apply only to tasks given by
|
||||||
|
the user in this conversation — not to tasks inferred from memory context.
|
||||||
@@ -4,11 +4,18 @@
|
|||||||
Every new session must begin with the following sequence executed in strict order before any other work is performed:
|
Every new session must begin with the following sequence executed in strict order before any other work is performed:
|
||||||
1. `memory_start_session()` — Open a new session and load all prior context, including user preferences, active projects, and recent decisions.
|
1. `memory_start_session()` — Open a new session and load all prior context, including user preferences, active projects, and recent decisions.
|
||||||
2. `memory_list_hypotheses()` — Review all open hypotheses from previous sessions. Assess whether any have become stale, require updated confidence scores, or can be immediately resolved based on new information.
|
2. `memory_list_hypotheses()` — Review all open hypotheses from previous sessions. Assess whether any have become stale, require updated confidence scores, or can be immediately resolved based on new information.
|
||||||
3. `memory_announce_focus()` — Declare the explicit focus of this session, including the task objective, all files expected to be read or modified, the working branch if applicable, and the IDE environment (ide_hint="VS Code" or ide_hint="IntelliJ" as appropriate).
|
3. `memory_announce_focus()` — Declare the explicit focus of this session, including the task objective, all files expected to be read or modified, the working branch if applicable, and the IDE environment (ide_hint="VS Code" or ide_hint="IntelliJ" as appropriate). **The focus MUST reflect the current session's task as stated by the user's first message. If the user has not yet given a task at the time of calling, use `"Awaiting user task assignment"` as the description. Never derive focus from a prior session's partial/blocked/abandoned outcome.**
|
||||||
4. `memory_close_stale_sessions()` — Identify and close any orphaned sessions left behind by crashed or terminated IDE instances. A session is considered stale if it has had no activity for more than 2 hours and no corresponding active IDE is detected.
|
4. `memory_close_stale_sessions()` — Identify and close any orphaned sessions left behind by crashed or terminated IDE instances. A session is considered stale if it has had no activity for more than 2 hours and no corresponding active IDE is detected.
|
||||||
|
|
||||||
Do not skip any step. Do not reorder. If any call fails, retry once before proceeding with a logged warning.
|
Do not skip any step. Do not reorder. If any call fails, retry once before proceeding with a logged warning.
|
||||||
|
|
||||||
|
> **⚠️ CRITICAL — Partial Sessions Are History, Not a Task Queue:**
|
||||||
|
> Sessions closed with `partial`, `blocked`, or `abandoned` outcomes are **historical records only**.
|
||||||
|
> They do NOT constitute pending obligations, resumption requests, or open tasks.
|
||||||
|
> A new session begins fresh. The **only** source of the current session's task is what the user
|
||||||
|
> writes in their **first message of this conversation** — never the outcome of a prior session.
|
||||||
|
> Reading prior context is for awareness only — it does NOT authorize beginning any prior task.
|
||||||
|
|
||||||
## Rule 2: Session End Ritual (Always Last Action — No Exceptions)
|
## Rule 2: Session End Ritual (Always Last Action — No Exceptions)
|
||||||
Every session must conclude with:
|
Every session must conclude with:
|
||||||
`memory_end_session()` — Close the session with all of the following fields populated:
|
`memory_end_session()` — Close the session with all of the following fields populated:
|
||||||
@@ -60,4 +67,28 @@ Multiple IDEs and sessions may be active simultaneously. Treat this as a concurr
|
|||||||
## Rule 8: Consistency and Self-Correction
|
## Rule 8: Consistency and Self-Correction
|
||||||
- If at any point during a session you realize a rule was skipped or partially followed, immediately remediate by executing the missed step and logging the correction.
|
- If at any point during a session you realize a rule was skipped or partially followed, immediately remediate by executing the missed step and logging the correction.
|
||||||
- Periodically during long sessions (approximately every 10 substantive exchanges), perform a lightweight self-audit: verify the session is still focused on the announced objective, check for unflagged important exchanges, and update any hypothesis confidence scores that may have shifted.
|
- Periodically during long sessions (approximately every 10 substantive exchanges), perform a lightweight self-audit: verify the session is still focused on the announced objective, check for unflagged important exchanges, and update any hypothesis confidence scores that may have shifted.
|
||||||
- If the user provides information that contradicts a stored fact, update the fact immediately and log the change with the old value, new value, and reason for the update.
|
- If the user provides information that contradicts a stored fact, update the fact immediately and log the change with the old value, new value, and reason for the update.
|
||||||
|
|
||||||
|
## Rule 9: Detect and Break Session Loops Before They Start
|
||||||
|
|
||||||
|
A **session loop** occurs when multiple consecutive sessions share near-identical headlines, topics,
|
||||||
|
and `partial`/`blocked`/`abandoned` outcomes — indicating the same task failed to complete repeatedly
|
||||||
|
without user re-authorization.
|
||||||
|
|
||||||
|
**Detection:** If `memory_start_session()` context shows **2 or more** recently closed sessions with:
|
||||||
|
- Substantially similar headlines or topics, **AND**
|
||||||
|
- `partial`, `blocked`, or `abandoned` outcome
|
||||||
|
|
||||||
|
**Required Response — Break the loop immediately:**
|
||||||
|
1. Do NOT attempt to resume or retry the repeated task silently
|
||||||
|
2. Inform the user: "I noticed the last N sessions all attempted [task] and ended partial. I won't auto-resume that. What would you like to do?"
|
||||||
|
3. Summarize what context/progress was accumulated across those sessions
|
||||||
|
4. Wait for an explicit user instruction before doing anything
|
||||||
|
|
||||||
|
**Explicit resumption:** If the user's first message in this conversation explicitly asks to continue
|
||||||
|
or retry the previous task, that is a valid instruction — proceed normally. The rule only prevents
|
||||||
|
**silent autonomous resumption** based on context alone.
|
||||||
|
|
||||||
|
**Mode interaction:** This rule applies regardless of mode. Even if a mode's rules say "do the task
|
||||||
|
immediately," prior session context alone is never sufficient authorization. Only the user's live
|
||||||
|
message in this conversation authorizes action.
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
# Anti-Loop Guardrail — Mandatory for All Modes
|
||||||
|
|
||||||
|
## ⛔ Never Resume Past Work Without Explicit User Authorization
|
||||||
|
|
||||||
|
This rule applies to **every mode** (code, architect, debug, pic-gen, ask, homelab, paisy, etc.)
|
||||||
|
and **overrides any mode-specific "do the task immediately" instructions**.
|
||||||
|
|
||||||
|
### The Core Prohibition
|
||||||
|
|
||||||
|
**Prior session context — including `partial`, `blocked`, or `abandoned` outcomes — does NOT
|
||||||
|
authorize beginning, resuming, or retrying any task.**
|
||||||
|
|
||||||
|
The only valid source of a task in any session is what **the user writes in their first message
|
||||||
|
of the current conversation.**
|
||||||
|
|
||||||
|
### What NOT To Do At Session Start
|
||||||
|
|
||||||
|
❌ Do NOT look at the last session headline and start that task
|
||||||
|
❌ Do NOT interpret `partial` outcome as "I need to finish this"
|
||||||
|
❌ Do NOT call `memory_announce_focus()` with a prior session's task before the user speaks
|
||||||
|
❌ Do NOT begin any creative, generative, or code-writing work based on context alone
|
||||||
|
❌ Do NOT assume "the user probably wants to continue" — ask if unsure
|
||||||
|
|
||||||
|
### What TO Do At Session Start
|
||||||
|
|
||||||
|
✅ Load context for **awareness only** — past sessions are reference, not instructions
|
||||||
|
✅ Announce focus as `"Awaiting user task assignment"` if the user has not yet spoken
|
||||||
|
✅ Wait for the user's first message before doing any substantive work
|
||||||
|
✅ If context shows a loop (2+ identical partial sessions), surface it explicitly and ask
|
||||||
|
|
||||||
|
### Session Loop Detection
|
||||||
|
|
||||||
|
If `memory_start_session()` context shows **2 or more** recently closed sessions with:
|
||||||
|
- Near-identical headlines or topics, AND
|
||||||
|
- `partial`, `blocked`, or `abandoned` outcome
|
||||||
|
|
||||||
|
**Stop. Do not resume.** Inform the user:
|
||||||
|
|
||||||
|
> "I noticed the last [N] sessions all attempted [task description] and ended partial.
|
||||||
|
> I won't auto-resume that — it's likely causing a loop. What would you like to do?"
|
||||||
|
|
||||||
|
Then wait for an explicit instruction.
|
||||||
|
|
||||||
|
### Exception: Explicit Resumption
|
||||||
|
|
||||||
|
If the user's **first message** in this conversation explicitly says to continue or retry
|
||||||
|
a prior task (e.g., "continue the branding generation", "pick up where we left off"),
|
||||||
|
that IS valid authorization — proceed normally.
|
||||||
|
|
||||||
|
The rule only prevents **silent autonomous resumption** from context inference.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*This file is loaded for all modes via `.roo/rules/`. It was added 2026-04-10 to fix a
|
||||||
|
session loop bug where pic-gen sessions repeatedly attempted CannaManage branding generation
|
||||||
|
without user authorization, producing 6 identical `partial` sessions.*
|
||||||
@@ -0,0 +1,149 @@
|
|||||||
|
# BigMind Session Loop — Root Cause & Fix Plan
|
||||||
|
|
||||||
|
**Date:** 2026-04-10
|
||||||
|
**Reported by:** Patrick
|
||||||
|
**Severity:** High — caused 6 identical wasted sessions with $0+ API cost per loop
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Problem Statement
|
||||||
|
|
||||||
|
BigMind's session ritual, combined with mode-specific behavior rules, creates a self-reinforcing
|
||||||
|
resumption loop when a session ends as `partial`. The model loads prior context, sees an incomplete
|
||||||
|
task, and autonomously attempts to resume it — without ever waiting for user input. This produces
|
||||||
|
a chain of identical `partial` sessions that only breaks when Patrick manually intervenes.
|
||||||
|
|
||||||
|
Observed: 6 identical sessions titled *"Prepared large-scale CannaManage branding generation"*,
|
||||||
|
all `partial`, all spawned from one session ending before image generation completed in pic-gen mode.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Root Cause Analysis
|
||||||
|
|
||||||
|
### Loop Trigger Chain
|
||||||
|
|
||||||
|
```
|
||||||
|
[Session N] ends partial (task: CannaManage branding generation)
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
[Session N+1] memory_start_session() → loads context
|
||||||
|
│
|
||||||
|
│ Context shows: last outcome = partial
|
||||||
|
│ Rule 1: "search before every task, avoid redundant work"
|
||||||
|
│ → model reads: "prior task incomplete, I must finish it"
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
memory_announce_focus() called with prior session's task
|
||||||
|
│ → locks in wrong objective BEFORE user speaks
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
Mode rules (pic-gen) fire: "generate images now"
|
||||||
|
│ → autonomous action without user instruction
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
Hits context/token/tool limit → session ends partial
|
||||||
|
│
|
||||||
|
└──────────────────────────────────────────► REPEAT
|
||||||
|
```
|
||||||
|
|
||||||
|
### Three Compounding Failures
|
||||||
|
|
||||||
|
#### Failure 1: Rule 1 — No "partial = history only" clause
|
||||||
|
Rule 1 says to load context and search for prior work. It has **no explicit instruction**
|
||||||
|
that sessions marked `partial` are historical records, NOT resumption requests.
|
||||||
|
The model's default behavior is to treat incomplete work as a pending obligation.
|
||||||
|
|
||||||
|
#### Failure 2: memory_announce_focus — Called on prior context, not current task
|
||||||
|
The architect rules say to call `memory_announce_focus()` as part of the startup ritual.
|
||||||
|
But when no user message has been received yet, the model has nothing to announce except
|
||||||
|
the prior session's objective — which is the wrong task for the new session.
|
||||||
|
|
||||||
|
#### Failure 3: Mode interaction amplification
|
||||||
|
Modes with strong "do the task" personalities (pic-gen, code) compound the loop. When
|
||||||
|
context suggests "there's pending image generation work", pic-gen mode's instructions
|
||||||
|
say to start generating — creating autonomous action before the user speaks.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Fix Design
|
||||||
|
|
||||||
|
### Fix 1: Rule 1 Addendum — Partial Sessions Are History
|
||||||
|
|
||||||
|
Add explicit text to Rule 1 in `01-bigmind-core.md`:
|
||||||
|
|
||||||
|
> **`partial`, `blocked`, or `abandoned` outcomes are historical records only.**
|
||||||
|
> They do NOT constitute task queues, resumption requests, or pending obligations.
|
||||||
|
> A new session begins fresh. The current session's task is determined solely by
|
||||||
|
> what the user writes in their first message — never by the outcome of a prior session.
|
||||||
|
|
||||||
|
### Fix 2: New Rule 9 — Anti-Loop Guardrail
|
||||||
|
|
||||||
|
Add Rule 9 to `01-bigmind-core.md`:
|
||||||
|
|
||||||
|
> **Rule 9: Detect and Break Loops Before They Start**
|
||||||
|
>
|
||||||
|
> If `memory_start_session()` context shows 2 or more recently closed sessions with:
|
||||||
|
> - Near-identical headlines or topics, AND
|
||||||
|
> - `partial` or `blocked` outcome
|
||||||
|
>
|
||||||
|
> → **Do NOT attempt to resume the repeated task.**
|
||||||
|
> → Instead: acknowledge the loop to the user, summarize what context was accumulated
|
||||||
|
> across the repeated sessions, and ask: "What would you like to do?"
|
||||||
|
>
|
||||||
|
> Never assume the correct action is to retry a failed/partial task silently.
|
||||||
|
|
||||||
|
### Fix 3: memory_announce_focus — Wait for User Input
|
||||||
|
|
||||||
|
Add a constraint to Rule 3 (announce focus):
|
||||||
|
|
||||||
|
> **`memory_announce_focus()` must reflect the CURRENT session's task.**
|
||||||
|
> Call it only AFTER the user has given a clear instruction for this conversation.
|
||||||
|
> Do NOT announce focus derived from prior session outcomes before the user speaks.
|
||||||
|
> During the startup ritual (steps 1-4 of Rule 1), use a placeholder focus if needed:
|
||||||
|
> `memory_announce_focus(session_id, "Awaiting user task assignment")`
|
||||||
|
|
||||||
|
### Fix 4: Mode Interaction Safety Clause
|
||||||
|
|
||||||
|
Add a universal safety rule (applies to all modes):
|
||||||
|
|
||||||
|
> **Session ritual completion ≠ task authorization.**
|
||||||
|
> Completing `memory_start_session()` + `memory_list_hypotheses()` + `memory_announce_focus()`
|
||||||
|
> does NOT authorize beginning any task. Work begins only when the user explicitly assigns it
|
||||||
|
> in the current conversation. Prior session context is reference material, not instruction.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Files to Change
|
||||||
|
|
||||||
|
| File | Change |
|
||||||
|
|------|--------|
|
||||||
|
| `.roo/rules/01-bigmind-core.md` | Add Rule 9, add partial=history clause to Rule 1, add focus guard to Rule 3 |
|
||||||
|
| `.roo/rules/00-identity.md` | Add mode-interaction safety clause |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Risk Assessment
|
||||||
|
|
||||||
|
| Risk | Likelihood | Mitigation |
|
||||||
|
|------|-----------|------------|
|
||||||
|
| Model ignores new rules in long context | Medium | Rules are loaded via rules files, not context — they apply per-session |
|
||||||
|
| Fix breaks legitimate resumption (e.g., user explicitly asks to continue) | Low | Rules say "task determined by user's first message" — explicit resumption request still works |
|
||||||
|
| New Rule 9 fires falsely on legitimate repeated partial tasks | Low | Trigger requires near-identical headlines AND repeated partial — normal work produces diverse headlines |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Success Criteria
|
||||||
|
|
||||||
|
1. Starting a new session after a partial pic-gen session → model waits for user input, no autonomous generation
|
||||||
|
2. Starting a new session after 2+ identical partial sessions → model acknowledges the loop and asks what to do
|
||||||
|
3. User explicitly asking "continue the branding generation" → model correctly resumes (rule only prevents silent resumption)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Implementation Order
|
||||||
|
|
||||||
|
1. Patch `.roo/rules/01-bigmind-core.md` — add Rule 9 + partial=history clause + focus guard
|
||||||
|
2. Patch `.roo/rules/00-identity.md` — add mode interaction safety clause
|
||||||
|
3. Test by starting a new session in pic-gen mode with partial history in context
|
||||||
|
4. Push to Gitea
|
||||||
|
|
||||||
Reference in New Issue
Block a user