Skip to content

fix(memory): gate person_pending facts out of memory_lookup FTS search (#53)#153

Merged
BrettKinny merged 1 commit into
mainfrom
audit/memory-lookup-kid-gate
Jun 6, 2026
Merged

fix(memory): gate person_pending facts out of memory_lookup FTS search (#53)#153
BrettKinny merged 1 commit into
mainfrom
audit/memory-lookup-kid-gate

Conversation

@BrettKinny
Copy link
Copy Markdown
Owner

Audit finding (HIGH, kid-safety, confirmed 3/3). Off main.

Bug

fetchPersonMemories is namespace-scoped to approved person:<id> and deliberately never returns person_pending:<id> (unreviewed facts about a minor) — but searchMemories ran a bare WHERE memories_fts MATCH ? over all rows, so a pending fact ("kiddo is allergic to peanuts") was returned to a live turn whenever the query phrase-matched it.

Fix

Add AND m.namespace NOT LIKE 'person_pending:%' to the FTS query in brain_db.ts, and mirror it into the test oracle (tests/oracle.py). The original bridge.py search fn the oracle was copied from was removed in #111, so the oracle is now the standalone spec; the kid-safety filter is the one intentional change, applied to both together.

Tests

New hermetic tests/memory_gate.test.ts (wired into npm test): builds a throwaway brain.db with the real FTS5 schema, one approved + one pending row that both phrase-match the query, asserts only the approved row returns. No DOTTY_BRAIN_DB_SNAPSHOT needed (unlike the existing parity test).

⚠️ Deploying needs a dotty-pi image rebuild (TS), like #151.

🤖 Generated with Claude Code

Copilot AI review requested due to automatic review settings June 5, 2026 11:12
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR addresses a high-severity kid-safety issue in dotty-pi-ext where the free-text memory lookup (FTS) could surface unreviewed person_pending:<id> facts (e.g., about minors) into live turns. It adds an explicit namespace gate to the FTS query and locks the behavior in with a hermetic regression test.

Changes:

  • Exclude person_pending:% rows from the FTS-backed searchMemories query in brain_db.ts.
  • Mirror the same exclusion into the Python oracle (tests/oracle.py) so parity/spec remains aligned.
  • Add a new hermetic regression test (tests/memory_gate.test.ts) and wire it into npm test.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.

File Description
dotty-pi-ext/src/lib/brain_db.ts Adds an explicit NOT LIKE 'person_pending:%' gate to FTS search results to prevent leaking unreviewed per-person facts.
dotty-pi-ext/tests/oracle.py Updates the oracle/spec query to include the same kid-safety namespace exclusion as the TS implementation.
dotty-pi-ext/tests/memory_gate.test.ts Adds a hermetic regression test that builds a real FTS5 schema and asserts pending facts are excluded from FTS search.
dotty-pi-ext/package.json Wires the new test:memgate script into the main npm test chain.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

#53)

Audit finding (HIGH, kid-safety, confirmed 3/3). fetchPersonMemories is
namespace-scoped to approved `person:<id>` and deliberately never returns
`person_pending:<id>` (unreviewed facts about a minor) — but searchMemories ran
a bare `WHERE memories_fts MATCH ?` over ALL rows, so a pending fact ("kiddo is
allergic to peanuts") was returned to a live turn whenever the query phrase-
matched it.

Add `AND m.namespace NOT LIKE 'person_pending:%'` to the FTS query in
brain_db.ts, and mirror it into the test oracle (tests/oracle.py) — the original
bridge.py search fn it was copied from was removed in #111, so this is now the
standalone spec; the filter is the one intentional change, applied to both.

Tests: new hermetic tests/memory_gate.test.ts (wired into `npm test`) — builds a
throwaway brain.db with the real FTS5 schema, one approved + one pending row both
matching the query, asserts only the approved row returns. No snapshot needed.

Deploying needs a dotty-pi image rebuild (TS), like the pi-ext auth PR.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@BrettKinny BrettKinny force-pushed the audit/memory-lookup-kid-gate branch from 35a1c1d to 127d7e2 Compare June 6, 2026 11:17
@BrettKinny BrettKinny merged commit 631a5e5 into main Jun 6, 2026
9 checks passed
@BrettKinny BrettKinny deleted the audit/memory-lookup-kid-gate branch June 6, 2026 11:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants