Repository navigation
fix: memory store and odek memory CLI contract (2026-10-13 audit) - #319
Merged
Merged
Conversation
…r task message A sub-agent's incoming user message is the task its parent model wrote, possibly carrying text the parent ingested from tools. Per-turn atom extraction stores every atom as user_approved and recalls it into every later session, so delegation laundered model-authored text into the principal's trust class. agent.Config.Subagent now switches extraction off (recall stays on); odek subagent sets it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…tinuing it The session-end summariser received the raw history — one observed case was 730 KB, 93% tool output, ending on the assistant's own message — and the model answered by continuing the chat. The transcript is now bounded (32 KiB, head and tail kept, tool results replaced by a size note), the prompt treats it as data and allows NONE, replies that read as a conversation turn or a record of nothing are not stored, and stored summaries are cut at a sentence end under a 2 KiB cap instead of mid-word at 1 KiB. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
go-vector writes vectors and the embedder vocabulary with os.Create, so episodes_vectors.gob and episodes_embedder.gob were 0644 beside the 0600 summaries they reconstruct. The extended index already chmods its files; the episode index now does the same. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… atoms record their session TTL-expired goals and questions were only hidden at recall and kept accumulating (787 goals, 433 questions observed); Prune deletes them, sweeps orphan chunk files and expired quarantine entries, with a dry run. Triage finds live atoms by pattern and moves them to quarantine for review — the recovery path for sub-agent briefs stored as user_approved. PersistedIndex reports the on-disk vector index without rebuilding it. Per-turn atoms now carry the shared session id and project (the Telegram surface never set them). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Promoting an unknown id leaked a filesystem error with the full path, and promoting a trusted episode reported success. Promote now reads the index first: not found, already approved, or not pending review (the same answers discard gives); auto-approved episodes stay promotable so a human approval outlives the auto_approve_episodes setting. FactStats exposes a target's entries, usage and cap for operator surfaces. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…bulk promote/discard, facts, honest extended stats/compact, prune and triage - help/--help/-h print usage; discard is documented; stray arguments are errors instead of being ignored - list --all shows every episode with its trust state; promote and discard take several ids and report each - facts [user|env] / add / replace / remove edit the fact files from the CLI with the memory tool's filters - extended stats reports the persisted vector index instead of the never-built in-process one and drops the process-local recall counters; compact waits for the rebuild and reports it - extended prune [--dry-run] and triage [--quarantine] <regexp> - docs: CLI.md rows corrected (episodes, not facts), MEMORY.md layout matches the flat on-disk store, EXTENDED_MEMORY.md command table Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…lock, CLI bounds and guard - looksLikeEpisode: word-bounded decline check (Native…/Navigated… pass), you/your/I'll judged on the first sentence outside quotes, later first-person sentences and curly apostrophes still caught; combined extraction prompt carries the same NONE / no-address rules; the no-sentence fallback stays within the cap - Prune: orphan sweep re-reads atoms.json under the store locks and skips chunks younger than 10 minutes (another process may be mid-Add); one failing atom no longer aborts the pass; quarantine counts use one clock - Triage: a failed store removal undoes the quarantine copy - facts: 2048-byte field bound and the configured guard sidecar, as the memory tool; help and typos no longer open the extended store; triage accepts -- before a pattern starting with --; list --help Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
odek | ebb3d8b | Commit Preview URL Branch Preview URL |
Oct 13 2026, 02:34 AM |
…s not stored Seen e2e: the model hedged with a prose record of absence instead of NONE; the trivial-reply check now matches inflected forms. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ded config, inert maintenance open, atoms.json flock, summary-shape precision - odek memory extended opens the store with memory.ExtendedConfigFor (the agent's resolution: TTLs, embedding backend); prune therefore applies the configured ephemeral_ttl_days and compact rebuilds in the same embedding space as recall - extended.NewForMaintenance: no quarantine eviction on open or on listing, so stats/quarantine/prune --dry-run change nothing; Prune evicts explicitly - AtomStore takes a cross-process flock on atoms.json for every read-modify-write (prune/triage beside a running daemon) - looksLikeEpisode: declines must be the whole reply, records of absence need 'there is nothing …' or a short reply, openers need a conversational continuation, second-person checks are explicit forms; quoted and code spans never count - list output sanitises session ids; odek subagent's Subagent flag is pinned by a test; continue summarises the reloaded session (the turn that just ran was left out) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…be created Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…s rejected, records of absence judged on the last sentence Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
3 of 5 tasks
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
Audit of the memory store and the
odek memoryCLI contract (2026-10-13). Nine findings fixed, one commit each, RED test first.user_approvedatoms.odek subagentran per-turn atom extraction on its incoming message — the task written by the parent model — so model-authored text (337 of 4,106 atoms in the audited store) got the principal's trust label and was recalled into every later session.agent.Config.Subagentdisables user-message extraction (recall stays on);odek subagentsets it.NONE, conversational/declined replies not stored, sentence-boundary trim under 2 KiB.episodes_vectors.gob/episodes_embedder.gobwere 0644 beside 0600 files.Prune(dry-run),Triage(regexp → quarantine, the recovery path for finding 1),PersistedIndex; session/project stamped on atoms; Telegram wired.promoteon an unknown id leaked the filesystem path;promoteon a trusted episode reported success.helpwas "unknown subcommand",discardundocumented, stray args ignored,extended statsalways said0 (dirty),extended compactdid nothing (background work died with the process), no way to see all episodes or edit facts. Docs described afacts/+episodes/layout that does not exist and called episodes "facts".memory_cmd.go: help, strict args,list --all, bulk promote/discard,facts [user|env] / add / replace / remove, honeststats, waitingcompact,prune,triage. CLI.md, MEMORY.md, EXTENDED_MEMORY.md, CHEATSHEET.md, AGENTS.md corrected.you/yourfalse positives, orphan-sweep race against a concurrentAdd, triage rollback, facts field bound + guard sidecar,--end-of-flags.Not changed (by design / follow-up): delegation sessions stay pending review (
delegate_taskstaints the episode — security rule); the two "user impersonation" quarantine entries were produced by a rule that no longer exists (the texts scan clean today) and can be promoted; Telegram chats never produce episodes (chat-scoped sessions never end) — separate design question.Coverage
internal/memoryinternal/memory/extendedcmd/odekinternal/agentgo test -raceoninternal/memory,internal/agent, the new extended and CLI tests: clean.golangci-linton touched packages: 0 issues.E2E with the head binary (scratch copy of
~/.odek)odek subagent --goal "I plan to deliver a read-only adversarial review…"→ live atoms unchanged (2563 → 2563); three parent turns afterwards added 3 atoms.odek memory/odek memory extendedsubcommand exercised: strict args,list --all, bulk promote/discard,facts,stats(persisted index),compact(waits, 0.2 s for 2.5k atoms),prune(1,540 expired atoms, 6 orphan chunks),triage --quarantine(3 sub-agent briefs).Test plan
TestRED_*in each package)go test -count=1oninternal/memory,internal/memory/extended,internal/agent,cmd/odek-raceon changed packages🤖 Generated with Claude Code