test(mcp): integration coverage for colliding observation permalinks (index + delete)#926
Conversation
|
Claude finished @groksrc's task in 2m 49s —— View job PR Review: fix(search): duplicate observation permalink collision
Summary: This PR correctly fixes a real bug where two observations sharing a category and a 200-char content prefix produced identical synthetic permalinks, causing the second to be silently dropped from the search index. The core fix (while-loop disambiguation + entity-id cleanup) is sound. Coverage is thorough. A few issues below. Code Quality & Standards
Testing & Documentation
Issues1.
|
| Item | Status |
|---|---|
| MCP tools atomic, composable | ✅ |
| No DB schema changes (no migration needed) | ✅ |
| Knowledge graph consistency maintained | ✅ |
| Local-first architecture preserved | ✅ |
Security & Performance
| Item | Status |
|---|---|
| No hardcoded secrets | ✅ |
| Cleanup path (entity-id delete) is more efficient than N permalink deletes | ✅ |
| Input validation unchanged | ✅ |
Verdict: The core fix is correct and the test coverage is excellent. The main issue worth addressing before merge is the asymmetry in SearchService.handle_delete (item 1) — it means delete_note via MCP will leave incoming-relation ghost rows that sync delete wouldn't. Everything else is minor.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: eaab505f3b
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4ed21a8b01
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3e630b9c4e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
Labeling needs-review: #931 merged a fix for #909 first (digest-suffixed observation permalinks), so the search_service/sync_service changes here would double-handle the collision. The integration test in this PR may still be additive over #931's coverage — worth a maintainer look at salvaging it with authorship preserved (as done for #918 via #943) rather than closing outright. |
Distinct observations sharing a category and a 200-char content prefix used to collide on their truncated synthetic permalink and the second was silently dropped from the search index (#909, fixed by #931 via a content digest suffix). These end-to-end MCP tests pin the behavior independent of the disambiguation mechanism: both observations stay searchable, and delete_note removes every index row — including disambiguated ones, which would otherwise survive as ghost rows since search_index has no FK cascade from entity. Post-delete assertions inspect the index via search_service directly because the MCP search pipeline hides rows whose entity is gone, which would mask an orphan. Refs #909 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: Drew Cain <groksrc@gmail.com>
|
Reworked as suggested: dropped the src changes and unit tests superseded by #931, kept just the additive MCP integration coverage (collision searchability + delete-time ghost-row guard). Branch is now a single signed-off, test-only commit on top of main. The delete/ghost test is the scenario the review round on this PR originally surfaced — #931's digest approach handles it, and this pins it. |
|
Thanks for the rework — this is exactly the right salvage. The stale threads on the dropped approach are resolved; this is queued to land. |
Refs #909
Summary
Reworked per @phernandez's comment: #931 merged the fix for #909 first (digest-suffixed observation permalinks), so this PR now carries only the additive integration coverage — the source changes and unit tests that would double-handle the collision are dropped.
Two end-to-end MCP tests (
test-int/mcp/test_observation_permalink_collision_integration.py) that pin the behavior independent of the disambiguation mechanism:search_notes(the original [BUG] Duplicate observation permalink collision drops the second observation from the search index #909 repro, green since fix(core): disambiguate truncated observation permalinks to prevent index collisions #931).delete_noteleaves no ghost index rows —search_indexhas no FK cascade from entity, so index-time permalink disambiguation must be matched by delete-time cleanup or the extra observation survives as a ghost row pointing at the deleted file. Post-delete assertions inspect the index viasearch_servicedirectly, because the MCP search pipeline hides rows whose entity is gone — which would mask exactly the orphan this test guards against (that hiding behavior may deserve its own look).The delete/ghost scenario is the one our earlier review round demonstrated empirically against an
-{obs.id}-style fix; #931's recomputable digest permalinks handle it correctly, and this test keeps it that way.Test plan
uv run pytest test-int/mcp/test_observation_permalink_collision_integration.py— 2 passed against current mainruff check/ruff format --checkclean🤖 Generated with Claude Code
Reviewed SHA:
5cdc109ef0ddc64da9f013f1f3382cf5e7805ae9Verdict:
approveStatus:
success- BM Bossbot approved this head SHASummary:
Reviewed the full provided diff. The added integration coverage exercises the MCP write/search/delete flow and uses the direct search service only for the post-delete orphan-index assertion, which is an appropriate oracle for this regression. No blocking issues found.
Blocking findings:
Non-blocking findings: