Skip to content

feat(memory): implement TrajectoryRiskAccumulator and ImplicitConflictDetector#4386

Merged
bug-ops merged 3 commits into
mainfrom
shadow-memory-safety
May 18, 2026
Merged

feat(memory): implement TrajectoryRiskAccumulator and ImplicitConflictDetector#4386
bug-ops merged 3 commits into
mainfrom
shadow-memory-safety

Conversation

@bug-ops
Copy link
Copy Markdown
Owner

@bug-ops bug-ops commented May 18, 2026

Summary

  • TrajectoryRiskAccumulator (zeph-memory, feat(memory): implement TrajectoryRiskAccumulator — shadow memory safety guardrail #4372): per-session shadow memory stream that ingests per-turn audit signals with exponential temporal decay and gates tool execution when cumulative trajectory risk exceeds a configurable threshold. Addresses multi-turn attack vectors (tool-chain chaining, persistent indirect prompt injection) that per-turn ContentSanitizer controls cannot detect. Based on MAGE (arXiv:2605.03228).
  • ImplicitConflictDetector (zeph-memory, feat(memory): implement ImplicitConflictDetector — write-time stale memory resolution #4373): write-time predicate similarity detection for APEX-MEM using Levenshtein distance, staging conflict candidates in implicit_conflict_candidates (migration 090), and annotating SYNAPSE ActivatedFact results with is_implicit_conflict/conflict_candidate_id. Addresses the STALE benchmark gap (55.2% frontier model accuracy on implicit conflicts).

Both features are opt-in with enabled = false default — zero overhead when disabled.

Changes

  • crates/zeph-memory/src/shadow/mod.rs — new: TrajectoryRiskAccumulator with noop mode, decay, ring buffer, is_blocked()/should_escalate(), 8 unit tests
  • crates/zeph-memory/src/graph/implicit_conflict.rs — new: ImplicitConflictDetector, normalized_levenshtein, detect_candidates, stage_candidates, annotate_conflicts, 12 unit tests including DB tests
  • crates/zeph-db/migrations/sqlite/090_implicit_conflict_candidates.sql — new staging table
  • crates/zeph-sanitizer/src/audit.rs — new: AuditSignalType, Severity enums
  • crates/zeph-config/src/memory.rsTrajectoryRiskAccumulatorConfig + [memory.shadow_memory]; ImplicitConflictConfig + [memory.graph.implicit_conflict]; non-negative weight validators
  • crates/zeph-memory/src/graph/activation.rsActivatedFact extended with is_implicit_conflict: bool, conflict_candidate_id: Option<i64>
  • crates/zeph-memory/src/graph/store/mod.rsinsert_or_supersede_with_conflict_detection wrapper
  • crates/zeph-tools/src/executor.rsToolError::TrajectoryRiskExceeded { score, top_signals }

Test plan

  • cargo +nightly fmt --check — clean
  • cargo clippy --workspace --features desktop,ide,server,chat,pdf,scheduler -- -D warnings — clean
  • cargo nextest run --workspace --features desktop,ide,server,chat,pdf,scheduler --lib --bins10149 passed
  • cargo test --doc --workspace --features desktop,ide,server,chat,pdf,scheduler — 19 passed
  • RUSTFLAGS="-D warnings" cargo check --workspace --all-targets --features desktop,ide,server,chat,pdf,scheduler --locked — clean
  • Security audit: zero unsafe blocks, SQL injection safe, shadow isolation structural (no sqlx/qdrant in shadow module), noop bypass impossible
  • Config non-negative weight validation (rejects NaN, inf, negative)
  • halflife_turns = 0 clamped to 1 with tracing::warn!
  • SQLite 999-bind-param guard in annotate_conflicts (chunks of 499)

Closes #4372
Closes #4373

@github-actions github-actions Bot added enhancement New feature or request size/XL Extra large PR (500+ lines) documentation Improvements or additions to documentation memory zeph-memory crate (SQLite) rust Rust code changes core zeph-core crate dependencies Dependency updates labels May 18, 2026
@bug-ops bug-ops force-pushed the shadow-memory-safety branch from 808947d to 8a62f5b Compare May 18, 2026 16:44
@github-actions github-actions Bot removed core zeph-core crate dependencies Dependency updates labels May 18, 2026
@bug-ops bug-ops enabled auto-merge (squash) May 18, 2026 16:45
bug-ops added 3 commits May 18, 2026 18:59
…tDetector

Implements two security and memory quality improvements:

TrajectoryRiskAccumulator (#4372): per-session shadow memory that
accumulates safety signals (PolicyViolation, PromptInjectionPattern,
ToolChainAnomaly, ConfidenceDrop) with exponential temporal decay and
gates tool execution when trajectory risk exceeds the configured
threshold. Based on MAGE (arXiv:2605.03228) — reduces tool-chain attack
success from 100% to ≤10% with default config. Controlled via
[memory.shadow_memory] with enabled=false default.

ImplicitConflictDetector (#4373): write-time predicate similarity
detection for APEX-MEM that stages implicit conflict candidates using
Levenshtein distance, extends SYNAPSE ActivatedFact with
is_implicit_conflict/conflict_candidate_id fields, and annotates recall
results when pending candidates exist. Addresses the STALE benchmark gap
(55.2% frontier model accuracy on implicit conflicts). Controlled via
[memory.graph.implicit_conflict] with enabled=false default.

Both features are additive and opt-in: disabled by default with
zero-overhead noop paths. No changes to existing memory pipeline behavior
when both are disabled.

Closes #4372
Closes #4373
@bug-ops bug-ops force-pushed the shadow-memory-safety branch from db6813d to daf8c84 Compare May 18, 2026 16:59
@bug-ops bug-ops merged commit b743e9e into main May 18, 2026
32 checks passed
@bug-ops bug-ops deleted the shadow-memory-safety branch May 18, 2026 17:07
bug-ops added a commit that referenced this pull request May 18, 2026
- Rename migration 090 → 091 to avoid conflict with 090_implicit_conflict_candidates
  added in #4386 (TrajectoryRiskAccumulator)
- Rename ConsolidationDaemonConfig (five-signal) → FiveSignalConsolidationConfig
  to avoid collision with existing spec 004-17 ConsolidationDaemonConfig
- Keep shadow_memory field added by #4386 alongside five_signal in MemoryConfig
bug-ops added a commit that referenced this pull request May 18, 2026
- Rename migration 090 → 091 to avoid conflict with 090_implicit_conflict_candidates
  added in #4386 (TrajectoryRiskAccumulator)
- Rename ConsolidationDaemonConfig (five-signal) → FiveSignalConsolidationConfig
  to avoid collision with existing spec 004-17 ConsolidationDaemonConfig
- Keep shadow_memory field added by #4386 alongside five_signal in MemoryConfig
bug-ops added a commit that referenced this pull request May 18, 2026
- Rename migration 090 → 091 to avoid conflict with 090_implicit_conflict_candidates
  added in #4386 (TrajectoryRiskAccumulator)
- Rename ConsolidationDaemonConfig (five-signal) → FiveSignalConsolidationConfig
  to avoid collision with existing spec 004-17 ConsolidationDaemonConfig
- Keep shadow_memory field added by #4386 alongside five_signal in MemoryConfig
bug-ops added a commit that referenced this pull request May 18, 2026
…dation daemon (#4392)

* release: prepare v0.21.2

- Bump workspace version 0.21.1 → 0.21.2
- Consolidate duplicate CHANGELOG.md section headers in [0.21.2]
- Update splash snapshot for new version string
- Update test badge count (9824)
- Update specs to reflect changes since v0.21.1

* feat(memory): extend SYNAPSE to five-signal retrieval + async consolidation daemon

Extends SYNAPSE recall in zeph-memory from two signals (recency + semantic
relevance) to five by adding access frequency, causal distance, and novelty.
Adds an optional async consolidation daemon via zeph-scheduler that promotes
high-utility episodic facts to Qdrant and deprioritizes cold ones.

New signals (all off by default — w_frequency=w_causal=w_novelty=0.0):
- access_frequency: log(1+count) normalized, tracked in fact_access_log SQLite
  table; session-scoped via per-process UUID
- causal_distance: BFS on MAGMA causal edges from current goal entity, bounded
  by causal_bfs_max_depth (default 10), cached per turn
- novelty: exp(-λ × days_since_agent_init), pure arithmetic, zero I/O

Weight normalization to 1.0 happens once at startup with WARN if config values
diverge. The is_baseline() short-circuit preserves zero overhead for the
two-signal default. Feature-gated consolidation daemon registered via
zeph-scheduler under the `scheduler` feature.

Migration 090 adds: fact_access_log table, messages.memory_tier,
messages.qdrant_promoted columns.

Research basis: MemTier (arXiv:2605.03675) — +33pp on LongMemEval-S;
14pp tool-execution degradation over 72h with flat retrieval.

Closes #4374
Closes #3703

* fix(memory): resolve merge conflicts with main after rebase onto v0.21.2

- Rename migration 090 → 091 to avoid conflict with 090_implicit_conflict_candidates
  added in #4386 (TrajectoryRiskAccumulator)
- Rename ConsolidationDaemonConfig (five-signal) → FiveSignalConsolidationConfig
  to avoid collision with existing spec 004-17 ConsolidationDaemonConfig
- Keep shadow_memory field added by #4386 alongside five_signal in MemoryConfig
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation enhancement New feature or request memory zeph-memory crate (SQLite) rust Rust code changes size/XL Extra large PR (500+ lines)

Projects

None yet

1 participant