Add session working memory (facts / open_questions / decisions) with audit-gated anti-poisoning#20
Merged
Merged
Conversation
Per-session ledger that tools (`coordinate`) auto-populate from their
synthesis output and that other calls can opt into injecting as
carry-forward context. Anti-poisoning is enforced by gating injection
on audit pass/fail: when `tool_audit` returns passed=false, every
non-stale memory row for that session is marked stale and excluded
from future injection.
Schema:
- New `session_memory(id, session_id, kind, content, source_tool,
source_call_id, confidence, created_at, stale_at, stale_reason)`
table with kind in {fact, open_question, decision}, plus indexes
on session_id and kind. CREATE IF NOT EXISTS — additive to the
existing schema.
Helpers:
- `_session_memory_add` (truncates content to 2000 chars, rejects
unknown kinds, ensures the session row exists first)
- `_session_memory_list` (filters by kinds + include_stale + limit)
- `_session_memory_mark_stale` (by id, by kind, or all-of-session)
- `_session_memory_clear`
- `_session_memory_block` renders a compact `<session_memory>` text
block (decisions / facts / open_questions) capped at 4000 chars
- `_session_memory_inject` prepends the block to the first user msg
Tool:
- `session_memory(action, session_id, ...)` with action in
{list, add, mark_stale, clear}. Error taxonomy:
SESSION_MEMORY_MISSING_SESSION_ID, SESSION_MEMORY_BAD_ACTION,
SESSION_MEMORY_BAD_KIND, SESSION_MEMORY_EMPTY_CONTENT,
SESSION_MEMORY_INVALID.
Auto-write from `coordinate.synthesis_structured`:
- consensus -> kind=decision (carries weighted_confidence)
- key_claims[].claim -> kind=fact (carries per-claim confidence)
- dissent[].claim -> kind=open_question prefixed `DISSENT:`
- open_questions[] -> kind=open_question
Best-effort; never blocks the coordinate response.
Audit gate (anti-poisoning):
- Both single-judge and coalesced `tool_audit` paths: when passed=false,
mark every non-stale memory row for the session stale with
reason=`audit_failed:overall=<score>`. Marker count surfaced as
`session_memory_marked_stale` on the audit response and as a
`session_memory_stale` ndjson event.
Injection (opt-in):
- `confer` and `coordinate` accept `inject_session_memory: true`. When
set with a session_id, the memory block is prepended to the user
message (confer) or topic block (coordinate). Stale rows are excluded.
Tests (scripts/test_session_memory.py):
- CRUD helpers (add / list / mark_stale by id and kind / clear)
- Stale rows excluded from default listings and from the injection block
- `_session_memory_inject` prepends a `<session_memory>` wrapper to first
user message; system message untouched; no-op when no user message
- `tool_session_memory` error taxonomy + happy paths for all four actions
- coordinate auto-writes consensus / key_claims / dissent / open_questions
with content matching the synthesis schema
- inject_session_memory:true on coordinate prepends the block to the
proposer + critic + synthesizer prompts
- Failed `tool_audit` marks ALL session memory stale; subsequent
`_session_memory_block` returns empty
Full suite (32 scripts) passes.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Per-session ledger of `{facts, open_questions, decisions}` that tools auto-populate from synthesis output and that other calls can opt into as carry-forward context. The key safety property: audit-gated anti-poisoning — a failed `tool_audit` automatically marks every session memory row stale, so contradicted facts can't propagate forward.
Error taxonomy: `SESSION_MEMORY_MISSING_SESSION_ID`, `SESSION_MEMORY_BAD_ACTION`, `SESSION_MEMORY_BAD_KIND`, `SESSION_MEMORY_EMPTY_CONTENT`, `SESSION_MEMORY_INVALID`.
Test plan
🤖 Generated with Claude Code