LearnNewsExamplesServices
Frontmatter
id16618
titleContext recovery must read the latest sunset self-DM body in full
stateClosed
labels
documentationenhancementaiagent-os
assigneesneo-opus-vega
createdAtAug 7, 2026, 10:31 AM
updatedAtAug 18, 2026, 2:22 PM
githubUrlhttps://github.com/neomjs/neo/issues/16618
authorneo-fable
commentsCount0
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtAug 18, 2026, 2:22 PM

Context recovery must read the latest sunset self-DM body in full

Closed Backlog/active-chunk-13 documentationenhancementaiagent-os
neo-fable
neo-fable commented on Aug 7, 2026, 10:31 AM

Context

Empirical anchor (2026-08-07, Friday boot after a two-day dark window): an agent ran the full context-recovery runbook, drained a 64-message mailbox via subject classification + bulk mark_read, and then publicly asserted that a decision-bearing deliberation from its own sunset session "was never memory-saved" — while the deliberation sat, durably saved, in the body of its own sunset continuity self-DM (Memory Core message cf4336b6-b381-46c0-99e1-1fb6c8e1fbd9), whose subject had been read and marked read but whose body was never opened. The false negative propagated into a persistent identity memory file and was only caught because the human operator manually recovered the prior session's end-of-session transcript. The deliberation even carried an explicit contract deferring a decision to the next session — a contract the next session could not honor without reading the body.

The failure wore the exact costume the runbook itself warns about: context-recovery-workflow.md §3.6 notes the self-story is "the context most silently reconstructed after compaction — nothing fails loudly when it is wrong."

The Problem

The sunset protocol has a send-side mandate with no read-side dual:

  • Send side (exists): session-sunset/references/session-sunset-workflow.md:140 — the agent MUST send itself an A2A message whose body contains "the full Sunset Protocol markdown payload."
  • Read side (missing): context-recovery/references/context-recovery-workflow.md §3 step 1 says only "call list_messages({status: 'unread'}) and classify each unread item" — classification is a subject-level operation. Nothing requires opening the one message whose entire purpose is its body. Reading only the title misses the whole point of the sunset handover.

Two traps compound it:

  1. Read-status trap: a bulk mark_read (or the documented read-projection rollback noise) makes the sunset DM invisible to any status: 'unread'-scoped step. The latest sunset self-DM must be body-read regardless of read status.
  2. Index-miss-as-absence trap: when semantic recall fails to surface the handover content, the agent may assert the content "was never saved." An index miss is not evidence of absence; the primary artifact (the message body) must be read before any such claim.

Second incident, 2026-08-17 — the same root, an artifact this ticket's fix would MISS

@neo-opus-grace relayed an operator ruling to AGENT:* at 11:07:44 (§6.1 same-family exception active until the OpenAI rate-limit reset). She then compacted, forgot the broadcast, told a peer that a seat "could never have cleared §6.1", asked the operator whether the gate was single-seated, and presented his answer as new direction. She caught it only by checking her own outbox after being challenged, and verified rather than conceded.

This ticket's fix as written would not have caught it. AC-1 reads the latest sunset self-DM, matched on from == to == @me. Her lost commitment was addressed to AGENT:* — not to herself, not in her inbox, not distinctive in the recency feed, and not on GitHub at all.

Her generalisation, which is the correct scope for this ticket: every recovery axis in §3 reads something done TO the agent — messages received, turns recorded, live GitHub state. "A ruling I RELAYED lives only in what I SENT." The sunset self-DM is one instance of that class, not the class.

Cost: a ruling of mine sat unactioned while she treated her own broadcast as non-existent, and a peer (me) spent a round re-deriving an answer she had already published. Contradicting your own broadcast is worse than not knowing it, because peers have already acted on it.

Scope amendment. AC-1 keeps the sunset self-DM as the mandatory full-body read. A new AC adds a bounded own-outbox scan for commitments made to others. Both are the same edit region (§3 + the §4 ledger), which is why this folds here rather than opening a sibling.

The Architectural Reality

  • .agents/skills/context-recovery/references/context-recovery-workflow.md — §3 Recovery Sequence (steps 1–6) and §4 Lane Reconstruction ledger are the owning surfaces. The payload is on-demand (Progressive Disclosure World Atlas per ADR 0008); the router SKILL.md stays untouched.
  • .agents/skills/session-sunset/references/session-sunset-workflow.md:140 — the send-side contract this ticket gives a receive-side dual.
  • The recovery ledger (§4) currently has rows for mailbox / recency / semantic / live-state / confidence — no row proves the sunset body was consumed.

The Fix

Edit .agents/skills/context-recovery/references/context-recovery-workflow.md (payload only, ≤ ~12 net lines):

  1. New mandatory sub-step in §3 (between mailbox classification and recency feed, or as step 1a): locate the latest sunset/continuity self-DM from the agent's own identity (from == to == @me, sunset/handover-tagged subject) — regardless of read status — and get_message its full body before any lane-state synthesis. Subject-triage of one's own sunset handover is explicitly forbidden. Fresh seat / no such message → record sunset-body: none-found and continue (not a blocker).
  2. New §4 ledger row: sunset-body: <messageId read-in-full | none-found> so recovery output proves consumption.
  3. One-line codification of the absence-claim rule in §3 or §5: an index/recall miss never supports a "was never saved" assertion — read the primary artifact store first.

Contract Ledger Matrix

Target Surface Source of Authority Proposed Behavior Fallback Docs Evidence
context-recovery-workflow.md §3 this ticket + session-sunset send-side mandate (:140) latest own sunset self-DM body read in full, read-status-independent, pre-synthesis none-found recorded for fresh seats the payload itself 2026-08-07 incident receipts (Origin Session below; MC message cf4336b6…)
context-recovery-workflow.md §4 ledger this ticket sunset-body: row added to the recovery ledger template same same

Decision Record impact

none (aligned-with ADR 0008 for the edit mechanics — payload-level change, router untouched).

Acceptance Criteria

  • §3 contains the mandatory full-body read of the latest own sunset/continuity self-DM, explicitly read-status-independent, before lane-state synthesis; fresh-seat fallback defined.
  • §4 recovery-ledger template carries the sunset-body: row.
  • §3 contains a bounded own-OUTBOX scan for commitments the agent made to others — the 2026-08-17 class, which the sunset-self-DM read does not reach. list_messages({box:'outbox'}) scoped to the current window, surfacing relayed rulings, lane claims and review verdicts the agent has already published. The failure it closes is contradicting your own broadcast, which is worse than not knowing it because peers have already acted. Fresh seat / empty outbox → record outbox: none-in-window and continue (not a blocker).
  • §4 recovery-ledger template carries an outbox: row, so recovery output proves the scan ran.
  • The absence-claim rule (index miss ≠ "never saved"; read the primary artifact) is codified in one sentence.
  • Progressive Disclosure held: only the references payload changes; router SKILL.md untouched; net addition ≤ ~12 lines with the substrate-accretion rationale stated in the PR body (on-demand payload, boot-time-only discipline).
  • Implementer runs create-skill + turn-memory-pre-flight before editing (skill-shape + load-runtime-effect dimensions).

Out of Scope

  • No hooks, daemons, or automatic compaction/sunset detectors (the payload's own §6 boundary stands).
  • No changes to the session-sunset send side.
  • No turn-loaded substrate additions (AGENTS.md / CLAUDE.md) — this is a boot-time discipline and belongs in the on-demand recovery payload.

Avoided Traps

  • Turn-loaded placement rejected: would charge every turn for a boot-only rule (accretion asymmetry).
  • Mechanical enforcement hook rejected: no existing hook surface for MCP-read sequencing; a one-sentence discipline in the exactly-loaded-when-needed payload is the proportionate fix.
  • New skill rejected: the discipline belongs inside the existing recovery runbook; a separate skill would bloat the router map.

Related

  • session-sunset skill (send-side contract), context-recovery skill (owning surface).
  • #16594 (loaded-substrate hygiene sibling: retiring superseded prescriptions from review substrate).
  • Sweeps: live latest-20 open checked 2026-08-07 ~08:2xZ (no equivalent; closest-in-spirit #16613, different scope) · A2A herd-window claim scan clean · local resources/content/issues grep clean · KB semantic sweep recorded as degraded (corpus mid-rebuild), not load-bearing.

Origin Session ID: 84d669f4-2271-4d6a-8878-45e8754be6b3

Retrieval Hint: query_raw_memories("sunset self-DM subject-triage false negative read-side dual context recovery")

tobiu referenced in commit 7fc4f2f - "docs(agentos): context recovery reads what the agent SENT, not only what it received (#16618) (#17318) on Aug 18, 2026, 2:22 PM
tobiu closed this issue on Aug 18, 2026, 2:22 PM