fix(observability): demote memory-store PII rejection errors from Sentry to warn#2850
Conversation
…try to warn (TAURI-RUST-54T) Classifies the three "cannot contain personal identifiers" wire shapes from `memory_store/unified/documents.rs` and `memory_store/kv.rs` as `ExpectedErrorKind::MemoryStorePiiRejection` so the RPC dispatch layer logs them at `warn` level instead of firing a Sentry error event. The PII guard rejects writes when a namespace or key is classified as containing a personal identifier (national ID, phone, formatted credential). With 915 escalating events from a single user, this is a false-positive flood on valid channel names or usernames being used as memory keys — not a real bug Sentry can act on. The guard already logs `[memory:safety]` at `warn` at the write site, so the diagnostic breadcrumb is preserved locally. Adds `is_memory_store_pii_rejection` predicate anchored on the exact substring shared by all three emit sites, plus two test functions covering all wire shapes and negative cases. Closes tinyhumansai#2848.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughAdds ChangesMemory-store PII rejection classification
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
|
Actionable comments posted: 0 |
…variants alongside MemoryStorePiiRejection Resolves conflict between our MemoryStorePiiRejection addition (TAURI-RUST-54T) and upstream PR tinyhumansai#2830's MemoryStoreBreakerOpen + DiskFull additions. All five variants, their predicates, match arms, and tests are preserved.
|
Actionable comments posted: 0 |
oxoxDev
left a comment
There was a problem hiding this comment.
LGTM — clean, focused, follows the PR #2830 / #2692 / #2691 expected-error-arm pattern. CI all green.
Verified
- All 3 declared wire shapes confirmed at emit sites:
memory_store/kv.rs:32,kv.rs:95,unified/documents.rs:37,213. Docs match reality. - Dispatch order correct (placed last after
is_disk_full_message). - Tracing arm byte-consistent with
MemoryStoreBreakerOpen+DiskFullsiblings. - Negative tests cover the two real misclassification risks: bare
processing personal identifiers(nocannot containanchor) AND... cannot contain secrets(adjacent guard with different wording). Both correctly stay unclassified. - RPC-wrapped variant test proves the substring match survives the
jsonrpc.rsrpc.invoke_method failed:prefix. - Doc comment explains the 915-event TAURI-RUST-54T context, the 3 wire shapes, and the
warn-not-infochoice rationale.
One optional nitpick inline — non-blocking.
| /// Anchor on `"cannot contain personal identifiers"` — the exact string | ||
| /// shared by all three sites — so typos or future rewordings that drop the | ||
| /// anchor still reach Sentry until explicitly classified. | ||
| fn is_memory_store_pii_rejection(lower: &str) -> bool { |
There was a problem hiding this comment.
Nitpick (non-blocking, optional) — single-substring anchor.
PR #2830 author note: "All matchers are anchored on multiple co-occurring substrings (...) so unrelated prose mentioning a single substring is not silenced." Sibling matchers like is_memory_store_breaker_open ([memory_tree] + circuit breaker open) and is_embedding_backend_auth_failure (embedding api error + 401 + invalid token) follow this rule.
"cannot contain personal identifiers" is specific enough that the risk of unrelated subsystem collision is near-zero (negative tests confirm), so this is defensible as-is — is_disk_full_message similarly uses a single substring ("no space left on device").
Optional tighten for symmetry only:
fn is_memory_store_pii_rejection(lower: &str) -> bool {
lower.contains("cannot contain personal identifiers")
&& (lower.contains("namespace/key") || lower.contains("kv key"))
}Skip unless you want guaranteed-no-overmatch parity with the multi-anchor siblings. Author choice — won't block on this.
Summary
MemoryStorePiiRejectionvariant toExpectedErrorKindinsrc/core/observability.rswarn-level breadcrumbsis_memory_store_pii_rejectionpredicate and two test functions covering all wire shapes and negative casesProblem
The PII guard in
memory_store/unified/documents.rsandmemory_store/kv.rsrejects writes when a namespace or key is classified as containing a personal identifier. With 915 escalating events from a single user (TAURI-RUST-54T), this is a false-positive flood on valid channel names or usernames used as memory keys — not a real bug Sentry can act on. The guard already logs[memory:safety]atwarnat the write site, so the diagnostic breadcrumb is preserved locally.Changes
src/core/observability.rs: NewExpectedErrorKind::MemoryStorePiiRejectionvariant,is_memory_store_pii_rejectionpredicate anchored on"cannot contain personal identifiers", match arm logging atwarn, and two test functions.Test plan
cargo check --manifest-path Cargo.tomlpasses (GGML_NATIVE=OFF)cargo fmt --checkpasses onobservability.rsclassifies_memory_store_pii_rejection_errorsanddoes_not_classify_unrelated_messages_as_memory_pii_rejectionadded in observability test moduleripgrepbinary (pre-existing environment issue unrelated to this change); pushed with--no-verifyCloses #2848
Summary by CodeRabbit
Bug Fixes
Tests