# Lessons learned from notify-pull experiment

## What worked

- Notifications without bodies reduced context pollution.
- Explicit IDs prevented reply-to-latest ambiguity.
- Shared owner arbitration prevented duplicate watchers.
- Presence TTL exposed stale liveness instead of pretending owner PID meant online.
- Natural E2E revealed behavior deterministic tests missed.

## What failed or remained ambiguous

- `processed`, `active`, and `completed` were added incrementally without one state machine.
- Reading an active message changed mailbox location and could clear active state.
- Reload/takeover semantics were not defined before heartbeat work.
- Model context could preserve stale status text after live state changed.
- Shared historical mail had no resume/quarantine/abandon policy.
- Regex/tmux E2E assertions confused plausible text with causal message identity.
- Provider failures, bridge failures, and stale mailbox behavior were initially conflated.
- Documentation retained obsolete drain/polling descriptions after implementation changed.

## Rules for future harnesses

1. Define protocol identity before runtime identity.
2. Define state transitions before adding fields.
3. Treat presence as advisory lease evidence, never truth or authorization.
4. Make reload equivalent to controlled runtime incarnation change.
5. Make operation retries idempotent before exposing them to models.
6. Use exact envelope/state evidence for acceptance tests.
7. Keep natural model tests diagnostic, not sole correctness gate.
8. Preserve old mail intentionally only with explicit stale-work policy.
9. Record every unresolved gap as a named residual risk.
10. Keep architecture docs current enough that contributors cannot follow retired behavior.

## Scope boundary

This experiment validates notify-pull over AMQ filesystem mailboxes. It does not yet validate OpenCode/Codex host APIs, hard provider-turn cancellation, authentication, or power-loss durability.
