# Stale Active Mailbox Hijacked Natural Conversation

## Incident summary

Naturalistic E2E attempted one fresh rock-paper-scissors game between `bpat` and `bi-boss`, then introduced one urgent task from `e2e-referee`.

The run appeared to show `bi-boss` failing to reply to the new game invitation. Full mailbox inspection proved that no fresh invitation was sent. `bpat` continued an old unresolved RPS conversation from shared mailbox history and sent an answer to that old message. `bi-boss` then handled the urgent task normally.

This was not an AMQ transport delivery failure and not a `bi-boss` response failure.

## Environment

- **Mailbox root:** `/Users/mak/.amq-bridge/mail`
- **Agents:** `bpat`, `bi-boss`, `e2e-referee`
- **Model:** `openai-codex/gpt-5.4-mini`
- **Thinking:** `medium`
- **Extension:** AMQ Bridge only
- **Scenario:** one-shot natural prompts; old mailbox history intentionally retained
- **Run artifact:** `e2e-natural-peer-20260803-000642-83343`

## User-visible symptom

Natural harness timed out waiting for a rock-paper-scissors response from `bi-boss`:

```text
MESSAGE_TIMEOUT label=rps-response pattern=rock|paper|scissors
```

Initial interpretation: `bi-boss` ignored the invitation.

Correct interpretation: `bpat` never sent a new invitation. It answered an old invitation already present in its mailbox.

## Timeline

Times below use AMQ message timestamps. Harness wall-clock directory name uses local time and differs by timezone.

### Existing stale state

`bpat` shared state contained:

```text
activeId = 2026-08-02T15-34-05.808Z_pid73325_7966ccc4
owner = null after cleanup
processedIds included activeId
completedIds did not include activeId
```

The active message remained physically present at:

```text
bpat/inbox/new/2026-08-02T15-34-05.808Z_pid73325_7966ccc4.md
```

Its content was an old `bi-boss → bpat` RPS invitation:

```text
subject: RPS Game Invitation
kind: question
body: I'd like to invite you to a game of Rock Paper Scissors...
```

### Natural run

1. Harness launched three fresh Pi sessions against shared mailbox root.
2. Harness prompted `bpat` once:
   > Invite bi-boss to one casual game of rock, paper, scissors. Play exactly one round, announce who won, and stop after that game.
3. Harness keyword matcher found a message containing RPS terms and labeled it a fresh invitation.
4. Actual message was:

   ```text
   from: bpat
   to: bi-boss
   subject: Re: One round of rock, paper, scissors?
   kind: answer
   refs: old message IDs
   body: Scissors — I win. Thanks for the round.
   ```

5. This was an answer to old RPS context, not a new invitation.
6. Harness prompted `e2e-referee` once to send one urgent task to `bi-boss`.
7. Urgent message was delivered correctly:

   ```text
   priority: urgent
   kind: todo
   to: bi-boss
   ```

8. `bi-boss` replied to `e2e-referee`:

   ```text
   Task marker ... completed.
   ```

9. No new RPS invitation/response pair occurred, so harness timed out.
10. Harness cleanup stopped test watchers; live status later showed peers offline.

## Evidence

### Stale active message

```text
/Users/mak/.amq-bridge/mail/agents/bpat/inbox/new/2026-08-02T15-34-05.808Z_pid73325_7966ccc4.md
```

### Stale answer emitted by bpat

```text
/Users/mak/.amq-bridge/mail/agents/bi-boss/inbox/cur/2026-08-02T18-37-20.360Z_pid85689_949ce33c.md
```

The same message existed in `bpat/outbox/sent`, proving sender and direction.

### Urgent task handled by bi-boss

```text
/Users/mak/.amq-bridge/mail/agents/bi-boss/outbox/sent/2026-08-02T18-37-38.975Z_pid86741_39cfa5b2.md
```

This proves `bi-boss` watcher/model path was functioning and urgent delivery succeeded.

## Root cause

Shared mailbox reuse preserved an old unresolved actionable request. `bpat` retained an `activeId` pointing to that request. The old message was marked in `processedIds` but not in `completedIds`, so it represented “already injected, not completed” work.

The next natural prompt did not establish exclusive conversation ownership. The model continued the old active conversation instead of initiating the requested new game.

## Contributing factors

### 1. Shared mailbox intentionally retained unresolved work

The test correctly reused real history, but no preflight distinguished:

- old pending work that should resume;
- old work that should be quarantined;
- new work requested by current user prompt.

### 2. `activeId` had no freshness/intent boundary

`activeId` identified old work but did not carry enough lifecycle context to tell the new natural scenario that this was stale relative to the current interaction.

### 3. Processed and completed state differ

`processedIds` prevents duplicate injection. It does not mean a message was answered or resolved. `completedIds` now exists, but old unresolved messages remain legitimately pending unless explicitly completed or quarantined.

### 4. Harness false positive

The natural harness used broad keyword matching:

```text
rock|paper|scissors
```

It classified any RPS-shaped message as a new invitation. It did not verify:

- expected direction;
- fresh subject/body semantics;
- absence of `Re:`/old refs;
- relation to current prompt.

### 5. Model followed available active context

`bpat` behavior was plausible given mailbox context. It answered old RPS work rather than inventing a new protocol violation.

## Fault ownership

| Component | Assessment |
|---|---|
| AMQ transport | No fault. Mail delivered and persisted correctly. |
| `bi-boss` | No fault. It handled the urgent request correctly. |
| `bpat` model | Followed stale available work; behavior exposed state ambiguity. |
| Bridge lifecycle | Primary architectural gap: stale active work was not surfaced/quarantined at new-session boundary. |
| Natural harness | Secondary fault: broad keyword matching misclassified stale answer as fresh invite. |
| Test setup | Deliberately retained unresolved old mail without a stale-work policy. |

## Why urgent task succeeded

Urgent task was a new message with explicit `priority=urgent`, sent after the stale RPS answer. `bi-boss` received and answered it. This separates peer availability and transport correctness from stale conversation selection.

## Impact

- New natural conversation did not start as intended.
- No message loss occurred.
- No cross-peer delivery occurred.
- Old mailbox conversation was resumed unexpectedly.
- Harness produced an incorrect initial diagnosis until message refs/state were inspected.
- Test cleanup left peers offline afterward by design.

## Already implemented protections

- `processedIds` injection dedupe.
- `completedIds` completion tracking.
- Queue advancement excludes completed messages.
- Receive planning excludes completed messages.
- Explicit message IDs for read/reply/resolve.
- Strict authentic E2E evidence and quiet-window checks.
- Presence heartbeat and owner lifecycle cleanup.

These protections prevent completed-message loops but do not decide what to do with old unresolved work.

## Required corrective actions

### P0 — Surface stale pending work

At attach/start, expose active pending message age, sender, subject, and ID. Do not silently present it as current conversation context.

Example status warning:

```text
Pending stale work: bpat message <id>, age 2h, subject "RPS Game Invitation".
Resume, resolve, or quarantine before starting new conversation.
```

### P0 — Add explicit stale-work policy

Choose one explicit user/model-visible policy:

- resume old pending work;
- quarantine old pending work from current turn;
- mark old work abandoned without pretending it was resolved.

Never silently discard mail.

### P1 — Strengthen natural E2E identity assertions

Natural harness must identify current-run messages by:

- sender and recipient;
- creation time after run start;
- current run marker where available;
- semantic invitation/response shape;
- refs not pointing solely to pre-run messages.

Keyword presence alone is insufficient.

### P1 — Add stale-state regression scenario

Seed:

- old actionable message in `inbox/new`;
- stale `activeId`;
- processed but incomplete state.

Start fresh session and assert stale work is surfaced according to policy, not silently substituted for new prompt.

### P2 — Improve model context contract

Context should distinguish:

```text
Current new notification
Existing pending work
Historical messages
```

Model should not infer conversation freshness from `activeId` alone.

## Validation status

- Natural run with stale shared history: failure reproduced.
- Exact stale message and refs confirmed.
- Urgent third-agent task delivered and answered.
- No transport failure found.
- Corrective implementation: pending.

## Final conclusion

`bi-boss` did not fail to answer a fresh invitation because no fresh invitation existed. Shared unresolved mailbox state caused `bpat` to continue an old RPS thread. The bridge preserved and exposed that state without a stale-work boundary, while the harness misclassified the old answer.

The correct fix is not “force bi-boss to reply.” It is explicit stale pending-work handling at session/attach boundaries, plus natural E2E assertions that validate message identity and causal freshness.
