feat(session): add anti-drift session notes#7
Conversation
ff69c1e to
cfac4be
Compare
There was a problem hiding this comment.
Pull request overview
This PR advances the “search-first unified memory” architecture by introducing normalized memory result contracts, durable session notes (no TTL) with freshness-aware ranking, and a new <memory version="2"> injection envelope that avoids injecting exact <entry> records. It also adds dream summary storage/job scaffolding and extends shutdown/teardown coverage to prove graceful waiting behavior.
Changes:
- Introduces normalized memory result models and a unified
session_search()orchestration path that can merge entries/notes/summaries. - Adds durable session notes (no TTL), note read metadata (
last_read_at), freshness-based ranking, and MCP note read/write tools. - Updates continuity injection to
<memory version="2">(nested<persistent_memory>and optional compaction-only<session_notes>), plus adds shutdown warning/proof scaffolding.
Reviewed changes
Copilot reviewed 47 out of 48 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| src/types/index.ts | Adds NormalizedMemoryResult contract for unified memory search/injection. |
| src/testing/detached-dream-proof.ts | Adds proof-only plugin to validate graceful shutdown waiting behavior. |
| src/testing/detached-dream-proof.test.ts | Tests detached dream proof plugin behavior/artifact writing. |
| src/session.ts | Updates injection envelope to <memory version="2">, strips <entry> blocks, adds compaction-only note injection. |
| src/session.test.ts | Adds tests for compaction notes injection and v2 envelope invariants. |
| src/services/session-snapshot.test.ts | Updates expectations to <memory version="2">. |
| src/services/session-notes.ts | Introduces durable session notes service with freshness-aware search and same-project delete-by-id semantics. |
| src/services/session-mcp-types.ts | Extends MCP schemas: normalized search results (ref/refs) and note tool request/response types. |
| src/services/session-mcp-runtime.ts | Wires session_search through unified memory search, adds note tools + descriptions, increases response budget. |
| src/services/runtime-teardown.ts | Adds createRuntimeTeardownTask helper and refines Deno vs Node signal listener wiring. |
| src/services/runtime-teardown.test.ts | Adds “live runtime” shutdown-wait proofs for SIGINT and beforeExit flows. |
| src/services/redis-snapshot.ts | Adds helper to emit snapshot summaries as NormalizedMemoryResult. |
| src/services/redis-client.test.ts | Makes waitFor async-friendly to reduce flakiness. |
| src/services/opencode-warning.ts | Adds notifyDreamShutdownDelay() warning helper. |
| src/services/memory-search.ts | Adds unified memory search service (entries + notes + summaries) with query vs reflection mode behavior. |
| src/services/memory-search.test.ts | Tests ordering and query/reflection mode behavior for unified memory search. |
| src/services/memory-results.ts | Adds ordering utilities for normalized memory results. |
| src/services/hot-tier-slice.test.ts | Updates continuity assertions for <memory version="2"> envelope. |
| src/services/exact-history.ts | Adds adapter interface/scaffold for exact-history searching. |
| src/services/dream-store.ts | Adds Redis-backed dream summary storage + retrieval around a reference time. |
| src/services/dream-runner.ts | Adds dream runner that buckets inputs and advances watermark. |
| src/services/dream-runner.test.ts | Tests dream store + runner watermark/summary behavior. |
| src/services/dream-jobs.ts | Adds pending dream job storage/preparation. |
| src/services/dream-jobs.test.ts | Tests dream job write/read/clear and prepare semantics. |
| src/services/detached-dream-worker.ts | Adds detached worker spawn scaffold (currently returns false). |
| src/index.ts | Wires notes service into runtime/session manager; adds session_search biasing and dream shutdown warning teardown task. |
| src/index.test.ts | Extends entrypoint tests for notes service wiring, biasing, dream shutdown warning behavior, and tool arg exposure. |
| src/handlers/tool-before.ts | Uses deny guidance as the thrown error message when present. |
| src/handlers/tool-before.test.ts | Updates tests to assert new thrown-denial guidance behavior. |
| src/handlers/messages.ts | Updates scrubbing logic for the new <memory> envelope and logging text. |
| src/handlers/messages.test.ts | Updates tests for <memory version="2"> injection and scrubbing behavior. |
| src/handlers/compacting.ts | Passes { forCompaction: true } to inject compaction-only session notes and updates log messages. |
| src/handlers/compacting.test.ts | Updates compaction tests for v2 envelope and compaction options. |
| src/handlers/chat.ts | Updates log messages to “memory” naming. |
| src/handlers/chat.test.ts | Updates chat handler tests for new prepareInjection signature. |
| opencode.json | Removes local dev plugin config from repo root. |
| docs/superpowers/specs/2026-05-10-session-notes-freshness-without-ttl-design.md | Adds design doc for durable notes and freshness ranking. |
| docs/superpowers/specs/2026-04-21-search-first-unified-memory-design.md | Adds design doc for search-first unified memory architecture. |
| docs/superpowers/specs/2026-04-11-session-notes-anti-drift-design.md | Adds spec doc for cross-session notes recall model. |
| docs/superpowers/plans/2026-05-10-session-notes-freshness-without-ttl.md | Adds implementation plan for durable notes + freshness ranking. |
| docs/superpowers/plans/2026-03-20-context-mode-mcp-first-implementation.md | Updates bounded-response budget documentation to 32 KB. |
| docs/SmokeTests.md | Updates smoke-test coverage and procedures for notes/tools and dream shutdown proof. |
| deno.lock | Adds @std/async dependency lock entry. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const sessionTool = isSessionMcpTool(tool); | ||
| const canonicalSessionId = await resolveCanonicalSessionId( | ||
| deps.sessionCanonicalizer, | ||
| sessionID, | ||
| ); |
| `<persistent_memory${ | ||
| persistent.nodeRefs.length > 0 | ||
| ? ` node_refs="${escapeXml(persistent.nodeRefs.join(","))}"` | ||
| : "" | ||
| }>${stripExactEntryBlocks(persistent.body)}</persistent_memory>`, |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 59 out of 60 changed files in this pull request and generated 2 comments.
Comments suppressed due to low confidence (1)
src/session.ts:596
- PR description/design docs describe the new injection envelope as a normalized hint surface (summaries + optional notes, with exact entries excluded). However, buildPreparedInjectionEnvelope still emits the legacy event-projection sections (<last_request>, <active_tasks>, <key_decisions>, <files_in_play>, etc.). Either the PR description/docs need to be adjusted to reflect this interim shape, or the envelope builder should be updated to only render normalized note/summary-derived tags.
| const MEMORY_VERSION_ATTR_PATTERN = /<memory\b[^>]*\bversion=(['"])2\1/i; | ||
| const LEGACY_MEMORY_UUID_ATTR_PATTERN = | ||
| /<memory\b[^>]*\bdata-uuids=(['"])(?:[^'"]*)\1/i; | ||
| const EMPTY_MEMORY_BLOCK_PATTERN = /^<memory\b[^>]*>\s*<\/memory>$/i; |
| const watermark = await dreamStore.getWatermark(rootSessionId); | ||
| if (watermark === null || watermark < targetWatermark) { | ||
| dependencies.notifyDreamShutdownDelay(); |
Summary
session_search()is the canonical recall API and injected XML is only a bounded hint surface.Design
Authority Model
opencode db/ SQLite is the exact chronological source of truth for user turns, assistant turns, and tool calls.Canonical Recall Path
session_search()becomes the default memory read API.queryplus optionalwhen, searches normalized exact/history, notes, and summaries, and returns exact-style results before summaries.when.type: "entry" | "note" | "summary",ref,snippet,score,created_at, and optional metadata.Injection Contract
<memory version="2">wrapper.<persistent_memory>is nested inside<memory>instead of being a separate top-level block.session_search().<session_memory>expectations were updated in tests to the normalized<memory>envelope.Durable Session Notes
last_read_aton successfulsession_notes_read(id)calls.session_searchnote hits exposecreated_atandupdated_at, but notlast_read_at.Dream Summary Layer
Graphiti Role
session_search().Retention Model
Implementation Notes
session_searchschemas and runtime wiring for normalizedref/refsresponses and optionalwhen.<memory version="2">wrapper.Test Plan
deno test -Adeno task checkdeno task lintdeno task fmt --checkLatest full-suite verification before commit:
66 passed (692 steps), 0 failed.