fix: guard graph push volatile bank files - #29
Conversation
chrlesur
left a comment
There was a problem hiding this comment.
Review
Verdict: request changes — the direction and the core implementation are right, and this is careful work. But this PR is the server-side guardrail announced for Wave B, and two of the four acted Wave B acceptance criteria are not covered yet. Both are small, high-leverage additions.
What holds up well (checks performed)
- Default skip + opt-in: volatile files are excluded by default;
include_volatile=Trueis enforcedmanage/adminat the MCP tool level (admin console and CLI both go through the tool), and awritetoken is rejected — tested. - Two-level audit logging (tool intent + bridge data-plane with the file list): both are useful, I would keep both.
- Normalized basename matching (
NFC, backslash, nested paths): covers the corrupted-name and subfolder cases — tested (1.MEMORY_BANK/activeContext.md). - No breaking change:
pushedstays numeric;pushed_files/skipped_volatile/warningare additive. - Orphan cleanup deliberately scoped to the full bank (not the filtered set), with the explanatory comment — this correctly neutralizes the destructive-cleanup risk for volatiles still present in the bank.
- Empty batch short-circuited (
call_tools_batchnot called when there is nothing to do) — tested. - Full suite on the PR branch: 419 passed + 1 xfailed (baseline 413 + 6 new adversarial tests).
import jsonalready present ingraph_bridge.py. Mergeable CLEAN on post-v2.5.4main.
Blocking 1 — Wave B criterion "legacy volatiles detected"
Volatiles already ingested in Graph Memory stay completely invisible: nothing in the response signals them, and they will silently rot there (the exact staleness problem the doctrine wants to avoid). No destructive cleanup asked — that stays out of scope, rightly. The minimal ask (~5-10 lines + 1 test):
- when volatile filenames are found among
existing_docs, expose them in the response asexisting_volatile_in_graph(list) withcleanup_performed: falseand an explicit warning telling the operator how to remediate (e.g. delete via Graph Memory tooling, or a one-offinclude_volatilepush after cleanup).
Blocking 2 — Wave B criterion "memory_id separation documented"
The most dangerous failure mode of this tool remains undocumented: if a memory_id is shared between graph_push and canonical-document ingestion (RFCs, runbooks ingested agent-side), the orphan cleanup deletes those canonical docs — any document absent from the bank is treated as an orphan. Pre-existing behavior, not introduced here — but this PR is precisely the guardrail revision the docs have been pointing to. A few lines in the tool docstring + the README Graph section are enough ("never share a memory_id between bank pushes and canonical ingestion"); a code-level guard can come with Wave C.
Recommended (non-blocking)
- Document two edge behaviors: (a) a volatile file removed from the bank does get cleaned from the graph by the orphan pass (opportunistic cleanup); (b) the guard protects the configured names, not the concept — a
progress-2026.mdis pushable by default. GRAPH_PUSH_VOLATILE_FILES=""silently disables the guard entirely — worth one sentence in the config comment/docs.
Versioning note (for the maintainers)
New tool parameter + new response fields + a default-behavior change: per the versioning doctrine this PR consumes the reserved 2.6.0 minor, and the behavior change (volatiles no longer pushed by default) must be called out in the CHANGELOG.
Adversarial pass on the guard itself (complements the review above)Ran a hostile-input pass directly against Blocking — case-sensitive bypass Recommended — all-volatile bank still runs orphan cleanup Recommended — Already noted (recommended): Net: direction is right, but as the Wave-B server guardrail this needs the case fix (blocking) plus the two criteria from the review before it lands. Still a 2.6.0-class change. |
Bump VERSION, __version__ and version assert to 2.6.0; add CHANGELOG entry for the health-probe proxy fix (Cloud-Temple#31); document PROXY_URL in ARCHITECTURE.md (now covers S3, LLMaaS consolidation and health probes); refresh version badges in both READMEs. Minor bump: server-side behavior change on the outbound network path. Consumes the 2.6.0 slot; the graph_push volatile guardrail (Wave B, PR Cloud-Temple#29) moves to the next minor once its blocking review items land.
Summary
Tests
Note: uv run pytest tests/ -q could not start because existing uv.lock fails to parse at line 431 (live-memory package missing version).