Skip to content

feat(memory): add is_user_autosave_key detector for per-turn user message keys#5631

Merged
singlerider merged 2 commits intozeroclaw-labs:masterfrom
vernonstinebaker:fix/memory-user-autosave-key-detection
Apr 20, 2026
Merged

feat(memory): add is_user_autosave_key detector for per-turn user message keys#5631
singlerider merged 2 commits intozeroclaw-labs:masterfrom
vernonstinebaker:fix/memory-user-autosave-key-detection

Conversation

@vernonstinebaker
Copy link
Copy Markdown
Contributor

@vernonstinebaker vernonstinebaker commented Apr 11, 2026

Summary

  • Base branch target (master for all contributions): master
  • Problem: Per-turn user message auto-saves (user_msg, user_msg_<uuid>) embed prior conversation context verbatim. Re-injecting these into memory recall causes exponential bloat as each recalled entry carries forward all prior generations.
  • Why it matters: Without a detection function, downstream context paths cannot distinguish raw per-turn user messages from genuine semantic memories.
  • What changed: Added is_user_autosave_key() to crates/zeroclaw-memory/src/lib.rs matching user_msg and user_msg_<uuid> patterns (case-insensitive), with full unit test coverage. Added a module-level reserved key prefix doc table documenting the user_msg* and assistant_resp* reserved namespaces and their detection functions.
  • What did not change (scope boundary): No behavior change. No context paths are modified. Both additions are pure — the detection function has no callers yet, and the doc table is Rust doc comments only.

Label Snapshot (required)

  • Risk label (risk: low): risk: low — pure additive function and doc comments, no behavior change
  • Size label (size: XS): size: XS — ~34 lines added across two commits
  • Scope labels: memory, tests
  • Module labels: memory: autosave
  • Contributor tier label: auto-managed

Change Metadata

  • Change type: feature
  • Primary scope: memory

Dependencies

Linked Issue

  • Related: Pre-requisite for follow-up PR wiring is_user_autosave_key into all context-building paths

Validation Evidence (required)

cargo fmt --all -- --check   # pass
cargo clippy --all-targets -- -D warnings  # pass
cargo test  # 821 passed; 0 failed; 7 ignored
  • Evidence provided: all unit tests pass including new user_autosave_key_detection_matches_per_turn_patterns

Security Impact (required)

  • New permissions/capabilities? No
  • New external network calls? No
  • Secrets/tokens handling changed? No
  • File system access scope changed? No

Privacy and Data Hygiene (required)

  • Data-hygiene status: pass
  • Redaction/anonymization notes: test data uses impersonal keys (user_msg, user_msg_1234, USER_MSG_abcd)
  • Neutral wording confirmation: all test language is system-focused

Compatibility / Migration

  • Backward compatible? Yes
  • Config/env changes? No
  • Migration needed? No

i18n Follow-Through (required when docs or user-facing wording changes)

  • i18n follow-through triggered? No — the doc table added is Rust API documentation (doc comments), not user-facing strings or prose docs; no locale files affected

Human Verification (required)

  • Verified scenarios: function correctly matches user_msg, user_msg_<uuid> (any case), rejects user_message, assistant_resp_*, telegram_*
  • Edge cases checked: case-insensitive matching, whitespace trimming, prefix boundary (user_messageuser_msg)
  • What was not verified: N/A — pure function with exhaustive unit tests

Side Effects / Blast Radius (required)

  • Affected subsystems/workflows: none — function is not called yet
  • Potential unintended effects: none
  • Guardrails/monitoring for early detection: N/A

Agent Collaboration Notes (recommended)

  • Agent tools used: codebase exploration, test execution
  • Workflow/plan summary: identified need for user autosave key detection, implemented matching existing is_assistant_autosave_key pattern; added reserved-prefix doc table to document the contract centrally
  • Verification focus: test coverage parity with is_assistant_autosave_key
  • Confirmation: naming + architecture boundaries followed (AGENTS.md + CONTRIBUTING.md): Yes

Rollback Plan (required)

  • Fast rollback command/path: git revert <sha> — two commits, no side effects
  • Feature flags or config toggles (if any): none
  • Observable failure symptoms: N/A — no runtime behavior change

Risks and Mitigations

None.

@theonlyhennygod
Copy link
Copy Markdown
Collaborator

Agent Review — Ready to Merge

Comprehension summary: This PR adds a pure detection function is_user_autosave_key() to src/memory/mod.rs that matches raw per-turn user message keys (user_msg and user_msg_<uuid>, case-insensitive). This is a prerequisite for the follow-up PR #5632, which wires this function into all memory context-building paths to prevent exponential bloat from re-injecting raw user messages. Blast radius: zero — the function is defined but not called in any production path yet.

Thank you, @vernonstinebaker. Clean additive change with complete test coverage.

What was reviewed and verified:

  • Code correctness: The function follows the exact same pattern as the existing is_assistant_autosave_key(). Case-insensitive matching via to_ascii_lowercase() and trim() is appropriate. The user_msg_ prefix boundary check correctly rejects user_message (different word boundary).
  • Regression analysis: Zero regression risk — the function is not called anywhere. Pure addition.
  • Test coverage: Comprehensive unit test covering: exact match (user_msg), UUID variant (user_msg_1234), case insensitivity (USER_MSG_abcd), negative boundary (user_message), negative cross-pattern (assistant_resp_1234).
  • Privacy/data hygiene: Pass — test keys use impersonal system-scoped identifiers.
  • Architecture alignment: Follows established memory module patterns exactly.

Security/performance assessment:

  • Security: No security impact.
  • Performance: No runtime impact — function not called yet.

CI Status: The Quality Gate's CI Required Gate failure is from the known wasmtime Security Audit issue. The CI workflow's CI Required Gate passes. All lint, test, and build checks pass.

Dependency note: This PR depends on #5633 (CI: suppress wasmtime RUSTSEC-2026-04-09 audit batch). PR #5632 depends on this PR.

This PR is ready for maintainer merge.


Field Content
PR #5631 — feat(memory): add is_user_autosave_key detector for per-turn user message keys
Author @vernonstinebaker
Summary Adds pure detection function for user autosave keys, preparing for context filtering
Action Ready to merge
Reason Clean additive function, zero runtime impact, complete test coverage, no findings
Security/performance No impact
Changes requested None
Architectural notes Mirrors is_assistant_autosave_key() pattern exactly
Tests All pass; new test covers positive and negative cases
Notes Prerequisite for #5632; should be merged first in the stack

@theonlyhennygod theonlyhennygod added the agent-approved PR approved by automated review agent label Apr 12, 2026
@theonlyhennygod
Copy link
Copy Markdown
Collaborator

This PR has merge conflicts with master. Could you rebase to resolve them? Once conflicts are cleared, this is agent-approved and ready to merge.

@github-actions github-actions bot removed the memory Auto scope: src/memory/** changed. label Apr 13, 2026
@vernonstinebaker
Copy link
Copy Markdown
Contributor Author

Agent Session Report — Conflict Resolution

Field Detail
PR #5631 — feat(memory): add is_user_autosave_key detector for per-turn user message keys
Author @vernonstinebaker
Action Conflict resolved — branch updated against upstream/master

Summary

What: Adds is_user_autosave_key() to the memory module, matching user_msg and user_msg_<uuid> keys (case-insensitive). Mirrors the existing is_assistant_autosave_key pattern.

Why: Per-turn user message auto-saves re-inject prior context verbatim on recall, causing exponential bloat. This pure detection function prepares for context-path filtering in a follow-up PR. No runtime behavior change.

Blast radius: None on merge. The function is additive and uncalled until the follow-up PR.

Conflict Root Cause

Upstream merged a large crate-extraction refactor between this PR's base and now. src/memory/mod.rs was reduced to a thin re-export shim — all functions (including is_assistant_autosave_key) moved to crates/zeroclaw-memory/src/lib.rs. This created a CONFLICTING merge state because the PR added is_user_autosave_key to the old location.

Resolution

  1. src/memory/mod.rs → accepted upstream version (minimal shim with pub mod traits).
  2. crates/zeroclaw-memory/src/lib.rs → added is_user_autosave_key() immediately after is_assistant_autosave_key() at line 102, and added user_autosave_key_detection_matches_per_turn_patterns test after its sibling test — preserving the original PR's intent exactly, just in the correct crate location.

Validation

cargo fmt --all -- --check    ✓ clean
cargo clippy --all-targets -- -D warnings    ✓ clean (281 checks)
cargo test --package zeroclaw-memory    ✓ 281 passed, 0 failed

Security / Performance

No security impact. No performance impact. Pure additive function with no callers yet.

Notes for maintainer

@singlerider
Copy link
Copy Markdown
Collaborator

Agent Review — DRY Acknowledgment

All findings from this PR were fully covered by the prior review (@theonlyhennygod). Summary of state:

  • CI: all checks pass (Lint, Test, Security Audit, CI Required Gate, all builds — green across both workflow runs)
  • Conflict resolved correctly: function and test placed in crates/zeroclaw-memory/src/lib.rs after rebase, mirroring is_assistant_autosave_key() exactly
  • Diff is minimal (18 lines added, 0 deleted) and correct
  • No new findings to report

This PR is agent-approved and awaiting maintainer merge.

@singlerider singlerider added risk: low Auto risk: docs/chore-only paths. size: XS Auto size: <=80 non-doc changed lines. labels Apr 17, 2026
vernonstinebaker added a commit to vernonstinebaker/zeroclaw that referenced this pull request Apr 19, 2026
Per-turn user messages (user_msg, user_msg_<uuid>) are auto-saved for
consolidation but must not be re-injected into memory recall context.
Each recalled entry embeds prior context verbatim, causing exponential
bloat across turns.

Wire is_user_autosave_key (from zeroclaw-labs#5631) into all three context paths:
- crates/zeroclaw-runtime/src/agent/loop_.rs build_context()
- crates/zeroclaw-runtime/src/agent/memory_loader.rs DefaultMemoryLoader
- crates/zeroclaw-channels/src/orchestrator/mod.rs should_skip_memory_context_entry()

Fix pre-existing test that used a user_msg_real key as the pass-through
case (now correctly filtered). Add dedicated tests for each path.

Stacked on zeroclaw-labs#5631.
vernonstinebaker added a commit to vernonstinebaker/zeroclaw that referenced this pull request Apr 19, 2026
Per-turn user messages (user_msg, user_msg_<uuid>) are auto-saved for
consolidation but must not be re-injected into memory recall context.
Each recalled entry embeds prior context verbatim, causing exponential
bloat across turns.

Wire is_user_autosave_key (from zeroclaw-labs#5631) into all three context paths:
- crates/zeroclaw-runtime/src/agent/loop_.rs build_context()
- crates/zeroclaw-runtime/src/agent/memory_loader.rs DefaultMemoryLoader
- crates/zeroclaw-channels/src/orchestrator/mod.rs should_skip_memory_context_entry()

Fix pre-existing test that used a user_msg_real key as the pass-through
case (now correctly filtered). Add dedicated tests for each path.

Stacked on zeroclaw-labs#5631.
…sage keys

Raw per-turn user messages are auto-saved under the 'user_msg' / 'user_msg_*'
key prefix. Re-injecting these into context assembly causes exponential bloat:
each recalled entry contains prior generations' full context verbatim, growing
unboundedly across sessions. Add is_user_autosave_key() as the read-path
counterpart to the existing is_assistant_autosave_key(), so all three
context-building callers can consistently skip them.

Adjacent to is_assistant_autosave_key in zeroclaw-memory/src/lib.rs.
Includes a unit test covering the canonical patterns.
Add a module-level doc table listing both reserved auto-save key prefixes
(assistant_resp_* and user_msg_*) alongside their detection functions and
the context-building paths that honour them. Provides a single reference
point for contributors adding new auto-save prefixes or writing memory tests.
@vernonstinebaker vernonstinebaker force-pushed the fix/memory-user-autosave-key-detection branch from fe137fa to 049aeb5 Compare April 19, 2026 13:38
Copy link
Copy Markdown
Collaborator

@WareWolf-MoonWall WareWolf-MoonWall left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR Review — #5631 feat(memory): add is_user_autosave_key detector for per-turn user message keys

Reviewing on the current HEAD. I read the full diff, the PR description, and the prior
review thread. No formal reviews exist; no inline threads; no active blocks. First review.


What this change does

Adds a single pub fn is_user_autosave_key(key: &str) -> bool to
crates/zeroclaw-memory/src/lib.rs, placed directly adjacent to the existing
is_assistant_autosave_key(). Adds a module-level reserved key prefix doc table
documenting both assistant_resp* and user_msg* namespaces. Adds a unit test covering
the canonical patterns. No callers are wired in this PR — this is the foundation commit
for #5632.


✅ Commendation

The implementation matches is_assistant_autosave_key() exactly in structure — same
normalization (trim + to_ascii_lowercase), same exact-match + prefix-match pattern,
same placement. When two functions enforce the same contract for symmetric key families,
structural symmetry is correctness evidence: a reader can verify the logic by diff
against the established sibling, and the test mirrors the existing
assistant_autosave_key_detection_matches_legacy_patterns test case-for-case. That
parity is intentional and right.

The cross-prefix negative assertion — assert!(!is_user_autosave_key("assistant_resp_1234"))
is worth naming explicitly as good work. It closes a subtle gap: a reviewer scanning the
test can immediately confirm the function does not accidentally match the other reserved
family. Same pattern exists in the assistant test with assert!(!is_assistant_autosave_key("user_msg_1234")). Both directions covered. ✅

The risk label is correct. crates/zeroclaw-memory/src/lib.rs is not in any of the
explicitly listed high-risk paths in AGENTS.md (crates/zeroclaw-runtime/src/**,
crates/zeroclaw-gateway/src/**, crates/zeroclaw-tools/src/**,
.github/workflows/**). A pure additive function with no callers carries no runtime
blast radius. risk: low / size: XS is an accurate snapshot. ✅


🔵 Advisory — module-level doc preamble claims behavior that lands in #5632, not here

The doc table preamble reads:

Any memory stored under these keys will be excluded from context assembly by all
three context-building paths (build_context, DefaultMemoryLoader, and
should_skip_memory_context_entry).

The PR description correctly states "the detection function has no callers yet." At the
point #5631 merges, that claim is accurate for assistant_resp* (already wired) but not
yet accurate for user_msg* — the wiring lands in #5632. Someone reading rustdoc
between the two merges would see a promise that user_msg* keys are filtered from
context, but the three callers won't enforce it yet.

The simplest fix is to frame the preamble as the reserved-namespace contract rather than
a behavioral claim — e.g., "these prefixes are reserved for the auto-save system and
must not be used for semantic memories" — and let the detection function docstrings
explain when and where they are enforced. The behavioral claim could also carry a forward
reference: "enforced by downstream callers; see #5632 / is_user_autosave_key."

This does not need to block merge. The PR description is honest about the no-callers
state, the function itself is correct, and the window between the two merges is short. I'm
raising it so the doc stays accurate at each merge point, per FND-006 §4.2 (Public API
Surface as a Promise).


Gates

All pass per stated validation evidence: cargo fmt --all -- --check,
cargo clippy --all-targets -- -D warnings, cargo test (821 passed, 0 failed, 7
ignored). CI checks shown as passing on the PR. ✅


Merge note

#5631 must land before #5632. After this merges, the #5632 branch rebases cleanly and
its diff reduces to only the three context-path wiring files plus their tests.


Verdict

Approved. No active blocks. The function is correct, the tests cover the right
cases, the placement and structure are consistent with the existing pattern, and the risk
label accurately reflects a pure additive change. The doc preamble observation above is
advisory only — worth addressing in a follow-up doc commit or as part of the #5632 merge
if convenient, but not a reason to hold this PR.

@github-project-automation github-project-automation bot moved this from Backlog to Ready to Merge in ZeroClaw Project Board Apr 19, 2026
@WareWolf-MoonWall WareWolf-MoonWall added this to the v0.7.4 milestone Apr 20, 2026
@WareWolf-MoonWall
Copy link
Copy Markdown
Collaborator

Hey @vernonstinebaker — pulling this into the v0.7.4 milestone as part of our contributor triage sweep. Your PR is approved and in the merge queue (must land before #5632). Thank you for the contribution! 🙌

Copy link
Copy Markdown
Collaborator

@singlerider singlerider left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed. Clean additive implementation — symmetric mirror of is_assistant_autosave_key, well-tested, no issues.

@singlerider singlerider merged commit fe3cec4 into zeroclaw-labs:master Apr 20, 2026
13 checks passed
@github-project-automation github-project-automation bot moved this from Ready to Merge to Shipped in ZeroClaw Project Board Apr 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agent-approved PR approved by automated review agent risk: low Auto risk: docs/chore-only paths. size: XS Auto size: <=80 non-doc changed lines.

Projects

Status: Shipped

Development

Successfully merging this pull request may close these issues.

4 participants