Skip to content

test(memory): avoid PII-like tool rule names#2680

Open
YOMXXX wants to merge 2 commits into
tinyhumansai:mainfrom
YOMXXX:chore/pii-resistant-tool-test-names
Open

test(memory): avoid PII-like tool rule names#2680
YOMXXX wants to merge 2 commits into
tinyhumansai:mainfrom
YOMXXX:chore/pii-resistant-tool-test-names

Conversation

@YOMXXX
Copy link
Copy Markdown
Contributor

@YOMXXX YOMXXX commented May 26, 2026

Summary

  • Replace the UUID-based `unique_tool_name` helper in `tool_memory.rs` tests with a deterministic atomic counter, so generated tool names no longer look like a UUID to the PII detection rules introduced in `b9925e0b`.

Problem

`src/openhuman/memory/ops/tool_memory.rs` tests generate per-test tool identifiers like `toolmem<12-hex-chars>`. The new PII detection module (`src/openhuman/memory_store/safety/pii.rs`, landed via `b9925e0b`) flags these as UUID-like and rejects the tool rule before storage, which makes every test in this module flake on a clean main.

Solution

Swap `uuid::Uuid::new_v4()` for a process-local `AtomicUsize` counter:

```rust
fn unique_tool_name() -> String {
static NEXT_TOOL_ID: AtomicUsize = AtomicUsize::new(1);
let id = NEXT_TOOL_ID.fetch_add(1, Ordering::Relaxed);
format!("toolmem_test_{id}")
}
```

  • Names look like `toolmem_test_1`, `toolmem_test_2`, ... — visibly not a UUID, not a hex blob, not anything PII detection would match.
  • Still unique within a single `cargo test` invocation (the only collision surface the original UUID was guarding against).
  • Cheaper than `Uuid::new_v4` and avoids a fallible random dep at the test path.

Submission Checklist

  • Tests added or updated (happy path + at least one failure / edge case) per Testing Strategy — N/A: this only updates a test helper. The existing test suite exercises the new helper.
  • Diff coverage ≥ 80% — N/A: test-only change. No production code touched.
  • Coverage matrix updated — N/A: no behaviour-visible feature row affected.
  • All affected feature IDs from the matrix are listed in the PR description under `## Related` — N/A.
  • No new external network dependencies introduced (mock backend used per Testing Strategy)
  • Manual smoke checklist updated if this touches release-cut surfaces (`docs/RELEASE-MANUAL-SMOKE.md`) — N/A: test-only.
  • Linked issue closed via `Closes #NNN` in the `## Related` section — N/A: no tracking issue.

Impact

  • Platform: cross-platform test-only change.
  • Behaviour: none in shipped builds. The change is confined to `#[cfg(test)]` in `tool_memory.rs`.
  • Performance / migration / compatibility: none.

Related


AI Authored PR Metadata (required for Codex/Linear PRs)

Linear Issue

  • Key: N/A
  • URL: N/A

Commit & Branch

  • Branch: `chore/pii-resistant-tool-test-names`
  • Commit SHA: `$(git rev-parse HEAD)`

Validation Run

  • `pnpm --filter openhuman-app format:check` — N/A: no frontend files changed.
  • `pnpm typecheck` — N/A: no TypeScript files changed.
  • Focused tests: `GGML_NATIVE=OFF cargo check --manifest-path Cargo.toml --lib` clean.
  • Rust fmt/check (if changed): `cargo fmt --check` clean.
  • Tauri fmt/check (if changed): N/A — no `app/src-tauri` change.

Validation Blocked

  • `command:` N/A
  • `error:` N/A
  • `impact:` N/A

Behaviour Changes

  • Intended behaviour change: `tool_memory.rs` tests use a deterministic atomic counter rather than a UUID for per-test tool names, so they no longer collide with the PII detection introduced by `b9925e0b`.
  • User-visible effect: none.

Parity Contract

  • Legacy behaviour preserved: per-test uniqueness still holds (every call returns a fresh value within a single `cargo test` invocation). The surrounding test bodies are unchanged.
  • Guard/fallback/dispatch parity checks: no production code paths touched.

Duplicate / Superseded PR Handling

  • Duplicate PR(s): N/A
  • Canonical PR: this PR
  • Resolution (closed/superseded/updated): N/A

Summary by CodeRabbit

  • Tests
    • Improved test helpers for tool memory operations: unique test identifiers now use a stable process-wide counter, producing simpler, deterministic names.
    • This reduces reliance on random UUIDs and improves test stability and reproducibility.

Review Change Stack

@YOMXXX YOMXXX requested a review from a team May 26, 2026 10:13
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 26, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 17744046-6b43-4e21-bc72-672b1b182107

📥 Commits

Reviewing files that changed from the base of the PR and between a6ac808 and 2a74c24.

📒 Files selected for processing (1)
  • src/openhuman/memory/ops/tool_memory.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/openhuman/memory/ops/tool_memory.rs

📝 Walkthrough

Walkthrough

Refactors test helpers in the tool memory module: adds AtomicUsize/Ordering imports and changes unique_tool_name() to generate sequential names toolmem_test_{id} using a static atomic counter. No production or RPC code changed.

Changes

Test Helper Deterministic Naming

Layer / File(s) Summary
Atomic counter-based unique tool naming
src/openhuman/memory/ops/tool_memory.rs
Adds AtomicUsize and Ordering imports and refactors unique_tool_name() to use a static AtomicUsize counter with fetch_add(..., Ordering::Relaxed) to produce toolmem_test_{id} names instead of a UUID-derived suffix.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~5 minutes

Suggested labels

rust-core, memory

Suggested reviewers

  • senamakel

Poem

🐰 A tiny counter wakes at dawn,
numbers march and hop along,
toolmem_test_0 then 1 and 2,
tests get names that always cue,
a rabbit smiles — deterministic too.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly addresses the main change: replacing UUID-based tool names with deterministic counter-based names to avoid PII detection in tests.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot added rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure. memory Memory store, memory tree, recall, summarization, and embeddings in src/openhuman/memory/. labels May 26, 2026
Copy link
Copy Markdown
Contributor

@graycyrus graycyrus left a comment

Choose a reason for hiding this comment

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

Clean fix. Atomic counter is the right call here — deterministic, no false PII triggers, cheaper than UUID, and uniqueness within a single cargo test invocation is all that's needed.

YOMXXX added 2 commits May 27, 2026 08:51
The previous run failed on
`envelope_memory_handlers_report_counts_and_statuses` in
`src/openhuman/memory/ops/documents.rs` with
`memory_init: "disk I/O error"`, and the same run logged
`Cache write errors 1` from sccache — both classic runner-side
disk pressure symptoms. The test exercises SQLite via the shared
memory client and has no dependency on this PR's `unique_tool_name`
helper change in `tool_memory.rs`, so an empty commit to retrigger
the CI run.
@YOMXXX YOMXXX force-pushed the chore/pii-resistant-tool-test-names branch from a6ac808 to 2a74c24 Compare May 27, 2026 00:51
format!("toolmem{short}")
static NEXT_TOOL_ID: AtomicUsize = AtomicUsize::new(1);
let id = NEXT_TOOL_ID.fetch_add(1, Ordering::Relaxed);
format!("toolmem_test_{id}")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Question (non-blocking): confirm the rejection path this fix targets.

The PR says the old toolmem<12-hex> names "look like a UUID to the PII detection rules" and get rejected before storage. There's no UUID detector in safety/pii.rs — the only boundary rejection on a tool name is has_likely_pii(namespace), where namespace = tool-{tool_name} (memory_tools/types.rs:144, enforced in memory_store/kv.rs:89 and unified/documents.rs:206).

has_likely_pii only fires when collect_strict_redactions matches, and every strict pattern is word-boundary-anchored (\b…). For tool-toolmem<hex>, the toolmem segment is 7 contiguous letters with no internal word boundary, so no strict pattern (RFC, PAN-IN, NINO, DNI, SSN, IBAN, NANP…) can anchor inside the hex run — I couldn't reproduce a namespace-level rejection of the old names.

If the real trigger was content-level redact_pii intermittently redacting a rare all-digit hex run inside the serialized tool_name (bare CPF/CC checksums apply there, unlike strict has_likely_pii), that would break prompt.rendered.contains(&primary_tool) rather than reject the write — so the "rejected before storage" framing would be slightly off.

Either way this is non-blocking: toolmem_test_<n> is unambiguously free of digit-run / hex / formatted-ID patterns and is strictly safer. Just want to confirm the actual mechanism so we know it covers the Windows path too.

Copy link
Copy Markdown
Contributor

@sanil-23 sanil-23 left a comment

Choose a reason for hiding this comment

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

PR #2680 — test(memory): avoid PII-like tool rule names

Walkthrough

This PR swaps the unique_tool_name() test helper in tool_memory.rs from a UUID-based name (toolmem<12-hex>) to a process-local AtomicUsize counter (toolmem_test_<n>). The stated goal is to keep generated tool names from resembling identifiers the memory PII-detection layer (memory_store/safety/pii.rs, from b9925e0b) might reject. The change is correct, minimal, and strictly more deterministic than the previous random-UUID approach: the counter is process-global, shared across the test runner's threads, and the backing store is a fresh leaked TempDir per process (ensure_shared_memory_client), so resetting the counter to 1 each run carries no cross-run collision risk. Ordering::Relaxed is the right choice for a pure monotonic unique-ID counter. No production code is touched. Overall: safe to merge.

Changes

File Summary
src/openhuman/memory/ops/tool_memory.rs Replace UUID-based unique_tool_name() test helper with a static AtomicUsize counter producing toolmem_test_<n> names; add std::sync::atomic import inside #[cfg(test)] mod tests.

Actionable comments (1)

❓ Question (non-blocking)

src/openhuman/memory/ops/tool_memory.rs:187-191 — confirm the actual rejection path the fix targets (posted inline)

The description says the old names "look like a UUID to the PII detection rules" and get rejected before storage. There's no UUID detector in safety/pii.rs; the only boundary rejection on a tool name is has_likely_pii(namespace) (tool-{tool_name}), and every strict pattern there is word-boundary-anchored — the 7-letter toolmem prefix prevents any of them from anchoring inside the hex run, so I couldn't reproduce a namespace-level rejection of the old names. If the trigger was instead content-level redact_pii redacting a rare all-digit hex run inside the serialized tool_name, the "rejected before storage" framing is slightly off. Non-blocking — the new deterministic names are strictly safer regardless. See the inline comment for the full trace.

Nitpicks (1)

  • PR description metadata — the Commit SHA: $(git rev-parse HEAD) line in the body is a literal, unexpanded shell substitution. Cosmetic; not a code issue.

Verified / looks good

  • static NEXT_TOOL_ID: AtomicUsize is function-local but process-global; fetch_add returns a distinct value per call and is correct across the test runner's threads → uniqueness holds within a cargo test invocation (the only collision surface).
  • Store isolation: ensure_shared_memory_client (memory/ops/test_support.rs) binds a fresh tempfile::TempDir per process, so the counter restarting at 1 each run cannot collide with leftovers from a previous run.
  • Ordering::Relaxed is sufficient — no cross-variable ordering is needed for a unique-ID counter.
  • Import placement follows rustfmt grouping (std group, blank line, then super/crate).
  • Scope is confined to #[cfg(test)]; zero shipped-build behavior change. CI test / Rust Core Tests + Quality (which runs this module) is green.

CI note (not PR-caused)

Two checks are red but neither is attributable to this diff:

  • Markdown Link Check — fails on a dead link in docs/OPERATIONS.md, a file this PR does not touch (pre-existing).
  • test / Rust Core Tests (Windows — secrets ACL) — the job exceeded the 20-min execution cap; the "Run Windows-specific secrets tests" step itself completed (✓). A slow-runner timeout, not a test failure.

LGTM — approving. The one question above is non-blocking.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

memory Memory store, memory tree, recall, summarization, and embeddings in src/openhuman/memory/. rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants