fix: prevent same-batch duplicate page proposals in compile_kb (#439)#453
fix: prevent same-batch duplicate page proposals in compile_kb (#439)#453Tet-9 wants to merge 1 commit into
Conversation
…dev#439) taken_names was only seeded from on-disk pages and pending proposals, never updated as drafts were accepted within the phase-1 loop. Two same-titled (or same-slug) drafts from one LLM batch both passed the collision guard, filing duplicate PAGE proposals. Approving the second would silently route through update_page() and overwrite the first. Fold each survivor's title/slug into taken_names immediately upon acceptance, mirroring what phase 2 already does for wikilinks.
📝 WalkthroughWalkthroughThe PR adds dependency auditing, hardens bundle import/export and durable storage, expands retrieval, health checks, session handling, MCP/JSONL APIs, and embedding tests. It also adds Vouch records and removes the desktop application and prior specification artifacts. ChangesCore platform changes
Estimated code review effort: 5 (Critical) | ~120 minutes Sequence Diagram(s)sequenceDiagram
participant Client
participant JSONLServer
participant ContextBuilder
participant IndexDB
Client->>JSONLServer: kb.search or kb.context
JSONLServer->>ContextBuilder: build scoped retrieval request
ContextBuilder->>IndexDB: query embeddings and FTS indexes
IndexDB-->>ContextBuilder: ranked and enriched hits
ContextBuilder-->>JSONLServer: context or search envelope
JSONLServer-->>Client: backend, viewer, hits, and optional explain data
Possibly related PRs
Suggested labels: 🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 12
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
.vouch/captures/1218169c-de25-48f4-bd93-70ff77d2fda2.jsonl (1)
1-94: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick winDo not commit raw capture buffers.
.vouch/captures/is documented as local-only and is deleted after finalization, but this tracked file exposes absolute paths, usernames, repository activity, and credential-store details (notably the command referencing/home/a/.config/mcp-publisher/token.json). Remove it from the commit; if already published, purge it from repository history.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.vouch/captures/1218169c-de25-48f4-bd93-70ff77d2fda2.jsonl around lines 1 - 94, Remove the tracked capture buffer under .vouch/captures from the commit and ensure it is excluded by the repository’s ignore rules. If it exists in published history, purge the file from all repository history and force-push the cleaned history as required; verify no credential-store references or other sensitive capture data remain tracked.
🧹 Nitpick comments (1)
src/vouch/sessions.py (1)
37-38: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winIsolate the volunteer hook from session start.
session_start()has already persisted and audit-logged the session before callingvolunteer_context.on_session_start(), so an exception inhot_memory.register()or_start_watch()abortskb_session_start()beforeregister_mcp_push()runs. Extend the existing best-effort handling to the whole hook so session creation doesn’t fail on volunteer setup.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/vouch/sessions.py` around lines 37 - 38, The volunteer hook currently propagates setup exceptions after the session is persisted, preventing subsequent session initialization. In session_start(), wrap the entire volunteer_context.on_session_start(store, sess) call in the existing best-effort exception handling, including hot_memory.register() and _start_watch() failures, so exceptions are logged or swallowed consistently and the function still returns sess for register_mcp_push() to run.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/security-audit.yml:
- Line 27: Update the actions/checkout@v4 step to set persist-credentials:
false, preventing the GITHUB_TOKEN from being stored in local Git configuration
before installation code runs.
- Around line 25-40: Remove the job-level continue-on-error setting so checkout,
Python setup, and dependency installation failures remain fatal. Add
continue-on-error only to the step named “audit” that runs pip-audit, preserving
non-blocking audit findings without masking setup failures.
In @.vouch/decided/20260707-092531-154cb163.yaml:
- Around line 42-45: Replace the non-actionable decision_reason value “yes” with
a concise, specific explanation of why the proposal was rejected, preserving the
existing status and decision metadata.
In
@.vouch/pages/session-what-are-the-non-development-related-files-and-folde.md:
- Around line 36-38: Replace the host-specific absolute paths in the session
page with repository-relative or otherwise redacted paths, removing usernames,
temporary directories, and private memory or scratchpad filenames. Also update
the corresponding decided record containing the same capture data to apply the
same redaction.
- Line 42: Normalize the captured Markdown in the affected fenced blocks: add a
language identifier to each fence to satisfy MD040, and remove invalid leading
or trailing spaces from the command inline code spans to satisfy MD038. Apply
the same cleanup to both referenced occurrences.
In `@CONTRIBUTING.md`:
- Around line 128-130: The contribution guidelines should distinguish evidence
requirements by change type: require vouch-ui screenshots or screen recording
for web app changes, and terminal captures for CLI-output changes. Update the
wording to use “screen recording” and “web app,” without requiring web-app
evidence for CLI-only changes.
In `@docs/superpowers/specs/2026-07-06-review-ui-multi-kb-design.md`:
- Around line 3-9: The spec metadata includes non-reproducible local filesystem
and unpushed branch details. Update the introductory status text in the
review-ui multi-KB design spec to remove the local path and branch reference,
replacing them with a stable repository or commit link, or a concise
implementation-status statement.
In `@src/vouch/health.py`:
- Around line 576-626: Wire the existing _tick progress helper into
rebuild_index’s stages: call it with "claims", "pages", and "entities" before
their respective indexing loops, and with "embeddings" before
_rebuild_embeddings(store). Preserve the documented phase labels and on_progress
behavior.
- Around line 629-651: Update _rebuild_embeddings to populate the
embedding_index table used by search_semantic() in addition to the legacy
embeddings table written by index_db.index_embedding(). After generating each
vector, invoke the appropriate embedding_index insertion/upsert helper with the
same kind, entity ID, and vector, ensuring rebuilt indexes immediately support
backend=embedding searches.
In `@src/vouch/index_db.py`:
- Around line 134-167: The rebuild and semantic search paths use different
embedding tables, so reindexing leaves embedding search empty. Update the
rebuild logic and its embedding write helper, including index_embedding, to
populate the embedding_index table consumed by search_semantic/search_embedding,
or consolidate both paths onto one shared table and update all related queries
consistently.
In `@src/vouch/jsonl_server.py`:
- Around line 713-726: Update _h_propose_theme to use _agent() as the fallback
when resolving actor, while preserving an explicitly supplied p["agent"] value.
Replace the environment-variable fallback so the HTTP transport’s _actor
ContextVar and X-Vouch-Agent attribution are honored consistently in
themes.propose_theme.
In `@tests/embeddings/test_integration.py`:
- Around line 48-72: Ensure test_semantic_search_finds_lexically_disjoint_claim
registers the mock embedder used by the other embedding tests before calling
index_db.search_semantic, or skip the test with importorskip when the real
embeddings dependency is unavailable. Keep the assertion unchanged once search
is guaranteed to return results.
---
Outside diff comments:
In @.vouch/captures/1218169c-de25-48f4-bd93-70ff77d2fda2.jsonl:
- Around line 1-94: Remove the tracked capture buffer under .vouch/captures from
the commit and ensure it is excluded by the repository’s ignore rules. If it
exists in published history, purge the file from all repository history and
force-push the cleaned history as required; verify no credential-store
references or other sensitive capture data remain tracked.
---
Nitpick comments:
In `@src/vouch/sessions.py`:
- Around line 37-38: The volunteer hook currently propagates setup exceptions
after the session is persisted, preventing subsequent session initialization. In
session_start(), wrap the entire volunteer_context.on_session_start(store, sess)
call in the existing best-effort exception handling, including
hot_memory.register() and _start_watch() failures, so exceptions are logged or
swallowed consistently and the function still returns sess for
register_mcp_push() to run.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: f56e3d1d-9b90-4f73-a0ad-04b6f3bcacb2
⛔ Files ignored due to path filters (6)
desktop/docs/screenshots/browse.pngis excluded by!**/*.pngdesktop/docs/screenshots/dashboard.pngis excluded by!**/*.pngdesktop/docs/screenshots/dual-solve.pngis excluded by!**/*.pngdesktop/docs/screenshots/review.pngis excluded by!**/*.pngdesktop/package-lock.jsonis excluded by!**/package-lock.jsondocs/banner.svgis excluded by!**/*.svg
📒 Files selected for processing (123)
.github/workflows/security-audit.yml.pre-commit-config.yaml.vouch/captures/1218169c-de25-48f4-bd93-70ff77d2fda2.jsonl.vouch/captures/5720220c-b77c-4947-aeec-9d6ef91d70b8.jsonl.vouch/captures/8a6df051-6c56-4d86-b0ed-66f6638ecfdc.jsonl.vouch/captures/ec4b8842-f167-467e-a33c-dc87911c9e0e.jsonl.vouch/claims/vouch-starter-reviewed-knowledge.yaml.vouch/decided/20260707-092531-154cb163.yaml.vouch/decided/20260707-093005-05345f47.yaml.vouch/decided/20260707-093125-4d6972f9.yaml.vouch/pages/edit-in-obsidian.md.vouch/pages/reviewed-knowledge-store.md.vouch/pages/session-what-are-the-non-development-related-files-and-folde.md.vouch/schema_version.vouch/sources/be7aec64b0fc803a33cb3d610f67ae95e636877db20231ef72440a7cbe6b69d2/content.vouch/sources/be7aec64b0fc803a33cb3d610f67ae95e636877db20231ef72440a7cbe6b69d2/meta.yamlCHANGELOG.mdCONTRIBUTING.mdREADME.mddesktop/.gitignoredesktop/CHANGELOG.mddesktop/LICENSEdesktop/README.mddesktop/docs/architecture.mddesktop/docs/reports/2026-06-26.mddesktop/electron-builder.ymldesktop/electron.vite.config.tsdesktop/package.jsondesktop/resources/vouch/.gitkeepdesktop/scripts/dev-with-vouch.tsdesktop/scripts/gen-methods.tsdesktop/src/catalog/backend.jsondesktop/src/catalog/methods.jsondesktop/src/main/http-client.tsdesktop/src/main/index.tsdesktop/src/main/ipc.tsdesktop/src/main/jsonl-client.tsdesktop/src/main/kb-store.tsdesktop/src/main/supervisor.tsdesktop/src/main/tray.tsdesktop/src/main/types.tsdesktop/src/main/vouch-locator.tsdesktop/src/preload/index.tsdesktop/src/renderer/index.htmldesktop/src/renderer/src/App.tsxdesktop/src/renderer/src/app.cssdesktop/src/renderer/src/components/Diff.tsxdesktop/src/renderer/src/components/Drawer.tsxdesktop/src/renderer/src/components/EmptyState.tsxdesktop/src/renderer/src/components/MethodCard.tsxdesktop/src/renderer/src/components/MethodForm.tsxdesktop/src/renderer/src/components/Placeholder.tsxdesktop/src/renderer/src/components/Rail.tsxdesktop/src/renderer/src/components/StatusBar.tsxdesktop/src/renderer/src/components/Topbar.tsxdesktop/src/renderer/src/components/controls/index.tsxdesktop/src/renderer/src/components/results/Cards.tsxdesktop/src/renderer/src/components/results/JsonTree.tsxdesktop/src/renderer/src/components/results/Renderers.tsxdesktop/src/renderer/src/components/results/ResultView.tsxdesktop/src/renderer/src/components/results/atoms.tsxdesktop/src/renderer/src/global.d.tsdesktop/src/renderer/src/lib/VouchContext.tsxdesktop/src/renderer/src/lib/client.tsdesktop/src/renderer/src/lib/format.tsdesktop/src/renderer/src/lib/useOnOpen.tsxdesktop/src/renderer/src/lib/useVouchEvents.tsdesktop/src/renderer/src/main.tsxdesktop/src/renderer/src/views/Dashboard.tsxdesktop/src/renderer/src/views/DualSolve.tsxdesktop/src/renderer/src/views/GenericView.tsxdesktop/src/renderer/src/views/Review.tsxdesktop/src/renderer/src/views/blurbs.tsdesktop/src/renderer/src/views/registry.tsxdesktop/src/shared/ipc.tsdesktop/src/shared/methods.gen.tsdesktop/src/shared/methods.types.tsdesktop/test/catalog.test.tsdesktop/test/controls.test.tsxdesktop/test/gen-methods.test.tsdesktop/test/http-client.test.tsdesktop/test/jsonl-client.test.tsdesktop/test/method-card.test.tsxdesktop/test/method-form.test.tsxdesktop/test/method-gate.test.tsdesktop/test/smoke-jsonl.tsdesktop/test/vouch-locator.test.tsdesktop/tsconfig.jsondesktop/tsconfig.node.jsondesktop/tsconfig.scripts.jsondesktop/tsconfig.web.jsondesktop/vitest.config.tsdocs/superpowers/specs/2026-07-06-review-ui-multi-kb-design.mdmigrations/README.mdspec/2026-05-21/README.mdspec/2026-05-21/SPEC.mdspec/2026-05-21/audit-vocabulary.mdspec/2026-05-21/methods.mdspec/2026-05-21/retrieval.mdspec/2026-05-21/review-gate.mdspec/2026-05-21/transports.mdspec/README.mdspec/audit-vocabulary.mdspec/methods.mdspec/retrieval.mdspec/review-gate.mdspec/transports.mdsrc/vouch/bundle.pysrc/vouch/cli.pysrc/vouch/compile.pysrc/vouch/context.pysrc/vouch/embeddings/base.pysrc/vouch/health.pysrc/vouch/index_db.pysrc/vouch/jsonl_server.pysrc/vouch/server.pysrc/vouch/sessions.pysrc/vouch/storage.pytests/embeddings/conftest.pytests/embeddings/test_integration.pytests/embeddings/test_search.pytests/test_cli.pytests/test_compile.py
💤 Files with no reviewable changes (87)
- spec/methods.md
- desktop/.gitignore
- desktop/electron-builder.yml
- .pre-commit-config.yaml
- desktop/test/gen-methods.test.ts
- desktop/test/http-client.test.ts
- desktop/CHANGELOG.md
- desktop/README.md
- desktop/test/method-gate.test.ts
- desktop/docs/architecture.md
- desktop/src/main/kb-store.ts
- migrations/README.md
- desktop/tsconfig.scripts.json
- desktop/electron.vite.config.ts
- desktop/src/renderer/src/components/Topbar.tsx
- desktop/src/renderer/index.html
- desktop/src/main/supervisor.ts
- desktop/src/renderer/src/components/results/JsonTree.tsx
- desktop/package.json
- spec/2026-05-21/README.md
- spec/README.md
- desktop/src/renderer/src/app.css
- desktop/src/renderer/src/views/Dashboard.tsx
- spec/transports.md
- desktop/LICENSE
- desktop/src/renderer/src/lib/format.ts
- desktop/src/renderer/src/components/Drawer.tsx
- desktop/src/renderer/src/components/Rail.tsx
- desktop/docs/reports/2026-06-26.md
- desktop/scripts/gen-methods.ts
- desktop/test/catalog.test.ts
- desktop/src/renderer/src/views/registry.tsx
- spec/2026-05-21/transports.md
- desktop/src/main/ipc.ts
- desktop/src/renderer/src/components/Placeholder.tsx
- desktop/src/renderer/src/global.d.ts
- desktop/src/renderer/src/views/DualSolve.tsx
- spec/2026-05-21/audit-vocabulary.md
- desktop/src/renderer/src/components/Diff.tsx
- desktop/test/jsonl-client.test.ts
- spec/retrieval.md
- spec/2026-05-21/methods.md
- desktop/src/main/index.ts
- desktop/src/shared/methods.types.ts
- desktop/src/renderer/src/main.tsx
- desktop/vitest.config.ts
- desktop/src/renderer/src/components/MethodForm.tsx
- desktop/test/controls.test.tsx
- spec/review-gate.md
- desktop/tsconfig.node.json
- desktop/tsconfig.json
- spec/audit-vocabulary.md
- desktop/src/renderer/src/components/EmptyState.tsx
- desktop/src/renderer/src/views/blurbs.ts
- desktop/src/catalog/methods.json
- spec/2026-05-21/review-gate.md
- desktop/src/shared/methods.gen.ts
- desktop/src/main/http-client.ts
- desktop/src/renderer/src/components/results/ResultView.tsx
- spec/2026-05-21/SPEC.md
- desktop/src/main/vouch-locator.ts
- desktop/src/main/tray.ts
- desktop/src/main/types.ts
- desktop/src/renderer/src/views/GenericView.tsx
- desktop/src/renderer/src/components/MethodCard.tsx
- desktop/src/renderer/src/components/StatusBar.tsx
- desktop/src/renderer/src/views/Review.tsx
- desktop/src/shared/ipc.ts
- desktop/src/renderer/src/components/results/atoms.tsx
- desktop/src/renderer/src/lib/useOnOpen.tsx
- desktop/scripts/dev-with-vouch.ts
- desktop/src/catalog/backend.json
- desktop/src/renderer/src/App.tsx
- desktop/test/method-card.test.tsx
- desktop/src/main/jsonl-client.ts
- desktop/src/renderer/src/components/controls/index.tsx
- desktop/test/method-form.test.tsx
- desktop/test/smoke-jsonl.ts
- desktop/tsconfig.web.json
- desktop/src/renderer/src/lib/client.ts
- desktop/test/vouch-locator.test.ts
- desktop/src/preload/index.ts
- spec/2026-05-21/retrieval.md
- desktop/src/renderer/src/lib/VouchContext.tsx
- desktop/src/renderer/src/components/results/Cards.tsx
- desktop/src/renderer/src/lib/useVouchEvents.ts
- desktop/src/renderer/src/components/results/Renderers.tsx
There was a problem hiding this comment.
Caution
Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.
Actionable comments posted: 12
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
.vouch/captures/1218169c-de25-48f4-bd93-70ff77d2fda2.jsonl (1)
1-94: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick winDo not commit raw capture buffers.
.vouch/captures/is documented as local-only and is deleted after finalization, but this tracked file exposes absolute paths, usernames, repository activity, and credential-store details (notably the command referencing/home/a/.config/mcp-publisher/token.json). Remove it from the commit; if already published, purge it from repository history.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.vouch/captures/1218169c-de25-48f4-bd93-70ff77d2fda2.jsonl around lines 1 - 94, Remove the tracked capture buffer under .vouch/captures from the commit and ensure it is excluded by the repository’s ignore rules. If it exists in published history, purge the file from all repository history and force-push the cleaned history as required; verify no credential-store references or other sensitive capture data remain tracked.
🧹 Nitpick comments (1)
src/vouch/sessions.py (1)
37-38: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winIsolate the volunteer hook from session start.
session_start()has already persisted and audit-logged the session before callingvolunteer_context.on_session_start(), so an exception inhot_memory.register()or_start_watch()abortskb_session_start()beforeregister_mcp_push()runs. Extend the existing best-effort handling to the whole hook so session creation doesn’t fail on volunteer setup.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/vouch/sessions.py` around lines 37 - 38, The volunteer hook currently propagates setup exceptions after the session is persisted, preventing subsequent session initialization. In session_start(), wrap the entire volunteer_context.on_session_start(store, sess) call in the existing best-effort exception handling, including hot_memory.register() and _start_watch() failures, so exceptions are logged or swallowed consistently and the function still returns sess for register_mcp_push() to run.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/security-audit.yml:
- Line 27: Update the actions/checkout@v4 step to set persist-credentials:
false, preventing the GITHUB_TOKEN from being stored in local Git configuration
before installation code runs.
- Around line 25-40: Remove the job-level continue-on-error setting so checkout,
Python setup, and dependency installation failures remain fatal. Add
continue-on-error only to the step named “audit” that runs pip-audit, preserving
non-blocking audit findings without masking setup failures.
In @.vouch/decided/20260707-092531-154cb163.yaml:
- Around line 42-45: Replace the non-actionable decision_reason value “yes” with
a concise, specific explanation of why the proposal was rejected, preserving the
existing status and decision metadata.
In
@.vouch/pages/session-what-are-the-non-development-related-files-and-folde.md:
- Around line 36-38: Replace the host-specific absolute paths in the session
page with repository-relative or otherwise redacted paths, removing usernames,
temporary directories, and private memory or scratchpad filenames. Also update
the corresponding decided record containing the same capture data to apply the
same redaction.
- Line 42: Normalize the captured Markdown in the affected fenced blocks: add a
language identifier to each fence to satisfy MD040, and remove invalid leading
or trailing spaces from the command inline code spans to satisfy MD038. Apply
the same cleanup to both referenced occurrences.
In `@CONTRIBUTING.md`:
- Around line 128-130: The contribution guidelines should distinguish evidence
requirements by change type: require vouch-ui screenshots or screen recording
for web app changes, and terminal captures for CLI-output changes. Update the
wording to use “screen recording” and “web app,” without requiring web-app
evidence for CLI-only changes.
In `@docs/superpowers/specs/2026-07-06-review-ui-multi-kb-design.md`:
- Around line 3-9: The spec metadata includes non-reproducible local filesystem
and unpushed branch details. Update the introductory status text in the
review-ui multi-KB design spec to remove the local path and branch reference,
replacing them with a stable repository or commit link, or a concise
implementation-status statement.
In `@src/vouch/health.py`:
- Around line 576-626: Wire the existing _tick progress helper into
rebuild_index’s stages: call it with "claims", "pages", and "entities" before
their respective indexing loops, and with "embeddings" before
_rebuild_embeddings(store). Preserve the documented phase labels and on_progress
behavior.
- Around line 629-651: Update _rebuild_embeddings to populate the
embedding_index table used by search_semantic() in addition to the legacy
embeddings table written by index_db.index_embedding(). After generating each
vector, invoke the appropriate embedding_index insertion/upsert helper with the
same kind, entity ID, and vector, ensuring rebuilt indexes immediately support
backend=embedding searches.
In `@src/vouch/index_db.py`:
- Around line 134-167: The rebuild and semantic search paths use different
embedding tables, so reindexing leaves embedding search empty. Update the
rebuild logic and its embedding write helper, including index_embedding, to
populate the embedding_index table consumed by search_semantic/search_embedding,
or consolidate both paths onto one shared table and update all related queries
consistently.
In `@src/vouch/jsonl_server.py`:
- Around line 713-726: Update _h_propose_theme to use _agent() as the fallback
when resolving actor, while preserving an explicitly supplied p["agent"] value.
Replace the environment-variable fallback so the HTTP transport’s _actor
ContextVar and X-Vouch-Agent attribution are honored consistently in
themes.propose_theme.
In `@tests/embeddings/test_integration.py`:
- Around line 48-72: Ensure test_semantic_search_finds_lexically_disjoint_claim
registers the mock embedder used by the other embedding tests before calling
index_db.search_semantic, or skip the test with importorskip when the real
embeddings dependency is unavailable. Keep the assertion unchanged once search
is guaranteed to return results.
---
Outside diff comments:
In @.vouch/captures/1218169c-de25-48f4-bd93-70ff77d2fda2.jsonl:
- Around line 1-94: Remove the tracked capture buffer under .vouch/captures from
the commit and ensure it is excluded by the repository’s ignore rules. If it
exists in published history, purge the file from all repository history and
force-push the cleaned history as required; verify no credential-store
references or other sensitive capture data remain tracked.
---
Nitpick comments:
In `@src/vouch/sessions.py`:
- Around line 37-38: The volunteer hook currently propagates setup exceptions
after the session is persisted, preventing subsequent session initialization. In
session_start(), wrap the entire volunteer_context.on_session_start(store, sess)
call in the existing best-effort exception handling, including
hot_memory.register() and _start_watch() failures, so exceptions are logged or
swallowed consistently and the function still returns sess for
register_mcp_push() to run.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: f56e3d1d-9b90-4f73-a0ad-04b6f3bcacb2
⛔ Files ignored due to path filters (6)
desktop/docs/screenshots/browse.pngis excluded by!**/*.pngdesktop/docs/screenshots/dashboard.pngis excluded by!**/*.pngdesktop/docs/screenshots/dual-solve.pngis excluded by!**/*.pngdesktop/docs/screenshots/review.pngis excluded by!**/*.pngdesktop/package-lock.jsonis excluded by!**/package-lock.jsondocs/banner.svgis excluded by!**/*.svg
📒 Files selected for processing (123)
.github/workflows/security-audit.yml.pre-commit-config.yaml.vouch/captures/1218169c-de25-48f4-bd93-70ff77d2fda2.jsonl.vouch/captures/5720220c-b77c-4947-aeec-9d6ef91d70b8.jsonl.vouch/captures/8a6df051-6c56-4d86-b0ed-66f6638ecfdc.jsonl.vouch/captures/ec4b8842-f167-467e-a33c-dc87911c9e0e.jsonl.vouch/claims/vouch-starter-reviewed-knowledge.yaml.vouch/decided/20260707-092531-154cb163.yaml.vouch/decided/20260707-093005-05345f47.yaml.vouch/decided/20260707-093125-4d6972f9.yaml.vouch/pages/edit-in-obsidian.md.vouch/pages/reviewed-knowledge-store.md.vouch/pages/session-what-are-the-non-development-related-files-and-folde.md.vouch/schema_version.vouch/sources/be7aec64b0fc803a33cb3d610f67ae95e636877db20231ef72440a7cbe6b69d2/content.vouch/sources/be7aec64b0fc803a33cb3d610f67ae95e636877db20231ef72440a7cbe6b69d2/meta.yamlCHANGELOG.mdCONTRIBUTING.mdREADME.mddesktop/.gitignoredesktop/CHANGELOG.mddesktop/LICENSEdesktop/README.mddesktop/docs/architecture.mddesktop/docs/reports/2026-06-26.mddesktop/electron-builder.ymldesktop/electron.vite.config.tsdesktop/package.jsondesktop/resources/vouch/.gitkeepdesktop/scripts/dev-with-vouch.tsdesktop/scripts/gen-methods.tsdesktop/src/catalog/backend.jsondesktop/src/catalog/methods.jsondesktop/src/main/http-client.tsdesktop/src/main/index.tsdesktop/src/main/ipc.tsdesktop/src/main/jsonl-client.tsdesktop/src/main/kb-store.tsdesktop/src/main/supervisor.tsdesktop/src/main/tray.tsdesktop/src/main/types.tsdesktop/src/main/vouch-locator.tsdesktop/src/preload/index.tsdesktop/src/renderer/index.htmldesktop/src/renderer/src/App.tsxdesktop/src/renderer/src/app.cssdesktop/src/renderer/src/components/Diff.tsxdesktop/src/renderer/src/components/Drawer.tsxdesktop/src/renderer/src/components/EmptyState.tsxdesktop/src/renderer/src/components/MethodCard.tsxdesktop/src/renderer/src/components/MethodForm.tsxdesktop/src/renderer/src/components/Placeholder.tsxdesktop/src/renderer/src/components/Rail.tsxdesktop/src/renderer/src/components/StatusBar.tsxdesktop/src/renderer/src/components/Topbar.tsxdesktop/src/renderer/src/components/controls/index.tsxdesktop/src/renderer/src/components/results/Cards.tsxdesktop/src/renderer/src/components/results/JsonTree.tsxdesktop/src/renderer/src/components/results/Renderers.tsxdesktop/src/renderer/src/components/results/ResultView.tsxdesktop/src/renderer/src/components/results/atoms.tsxdesktop/src/renderer/src/global.d.tsdesktop/src/renderer/src/lib/VouchContext.tsxdesktop/src/renderer/src/lib/client.tsdesktop/src/renderer/src/lib/format.tsdesktop/src/renderer/src/lib/useOnOpen.tsxdesktop/src/renderer/src/lib/useVouchEvents.tsdesktop/src/renderer/src/main.tsxdesktop/src/renderer/src/views/Dashboard.tsxdesktop/src/renderer/src/views/DualSolve.tsxdesktop/src/renderer/src/views/GenericView.tsxdesktop/src/renderer/src/views/Review.tsxdesktop/src/renderer/src/views/blurbs.tsdesktop/src/renderer/src/views/registry.tsxdesktop/src/shared/ipc.tsdesktop/src/shared/methods.gen.tsdesktop/src/shared/methods.types.tsdesktop/test/catalog.test.tsdesktop/test/controls.test.tsxdesktop/test/gen-methods.test.tsdesktop/test/http-client.test.tsdesktop/test/jsonl-client.test.tsdesktop/test/method-card.test.tsxdesktop/test/method-form.test.tsxdesktop/test/method-gate.test.tsdesktop/test/smoke-jsonl.tsdesktop/test/vouch-locator.test.tsdesktop/tsconfig.jsondesktop/tsconfig.node.jsondesktop/tsconfig.scripts.jsondesktop/tsconfig.web.jsondesktop/vitest.config.tsdocs/superpowers/specs/2026-07-06-review-ui-multi-kb-design.mdmigrations/README.mdspec/2026-05-21/README.mdspec/2026-05-21/SPEC.mdspec/2026-05-21/audit-vocabulary.mdspec/2026-05-21/methods.mdspec/2026-05-21/retrieval.mdspec/2026-05-21/review-gate.mdspec/2026-05-21/transports.mdspec/README.mdspec/audit-vocabulary.mdspec/methods.mdspec/retrieval.mdspec/review-gate.mdspec/transports.mdsrc/vouch/bundle.pysrc/vouch/cli.pysrc/vouch/compile.pysrc/vouch/context.pysrc/vouch/embeddings/base.pysrc/vouch/health.pysrc/vouch/index_db.pysrc/vouch/jsonl_server.pysrc/vouch/server.pysrc/vouch/sessions.pysrc/vouch/storage.pytests/embeddings/conftest.pytests/embeddings/test_integration.pytests/embeddings/test_search.pytests/test_cli.pytests/test_compile.py
💤 Files with no reviewable changes (87)
- spec/methods.md
- desktop/.gitignore
- desktop/electron-builder.yml
- .pre-commit-config.yaml
- desktop/test/gen-methods.test.ts
- desktop/test/http-client.test.ts
- desktop/CHANGELOG.md
- desktop/README.md
- desktop/test/method-gate.test.ts
- desktop/docs/architecture.md
- desktop/src/main/kb-store.ts
- migrations/README.md
- desktop/tsconfig.scripts.json
- desktop/electron.vite.config.ts
- desktop/src/renderer/src/components/Topbar.tsx
- desktop/src/renderer/index.html
- desktop/src/main/supervisor.ts
- desktop/src/renderer/src/components/results/JsonTree.tsx
- desktop/package.json
- spec/2026-05-21/README.md
- spec/README.md
- desktop/src/renderer/src/app.css
- desktop/src/renderer/src/views/Dashboard.tsx
- spec/transports.md
- desktop/LICENSE
- desktop/src/renderer/src/lib/format.ts
- desktop/src/renderer/src/components/Drawer.tsx
- desktop/src/renderer/src/components/Rail.tsx
- desktop/docs/reports/2026-06-26.md
- desktop/scripts/gen-methods.ts
- desktop/test/catalog.test.ts
- desktop/src/renderer/src/views/registry.tsx
- spec/2026-05-21/transports.md
- desktop/src/main/ipc.ts
- desktop/src/renderer/src/components/Placeholder.tsx
- desktop/src/renderer/src/global.d.ts
- desktop/src/renderer/src/views/DualSolve.tsx
- spec/2026-05-21/audit-vocabulary.md
- desktop/src/renderer/src/components/Diff.tsx
- desktop/test/jsonl-client.test.ts
- spec/retrieval.md
- spec/2026-05-21/methods.md
- desktop/src/main/index.ts
- desktop/src/shared/methods.types.ts
- desktop/src/renderer/src/main.tsx
- desktop/vitest.config.ts
- desktop/src/renderer/src/components/MethodForm.tsx
- desktop/test/controls.test.tsx
- spec/review-gate.md
- desktop/tsconfig.node.json
- desktop/tsconfig.json
- spec/audit-vocabulary.md
- desktop/src/renderer/src/components/EmptyState.tsx
- desktop/src/renderer/src/views/blurbs.ts
- desktop/src/catalog/methods.json
- spec/2026-05-21/review-gate.md
- desktop/src/shared/methods.gen.ts
- desktop/src/main/http-client.ts
- desktop/src/renderer/src/components/results/ResultView.tsx
- spec/2026-05-21/SPEC.md
- desktop/src/main/vouch-locator.ts
- desktop/src/main/tray.ts
- desktop/src/main/types.ts
- desktop/src/renderer/src/views/GenericView.tsx
- desktop/src/renderer/src/components/MethodCard.tsx
- desktop/src/renderer/src/components/StatusBar.tsx
- desktop/src/renderer/src/views/Review.tsx
- desktop/src/shared/ipc.ts
- desktop/src/renderer/src/components/results/atoms.tsx
- desktop/src/renderer/src/lib/useOnOpen.tsx
- desktop/scripts/dev-with-vouch.ts
- desktop/src/catalog/backend.json
- desktop/src/renderer/src/App.tsx
- desktop/test/method-card.test.tsx
- desktop/src/main/jsonl-client.ts
- desktop/src/renderer/src/components/controls/index.tsx
- desktop/test/method-form.test.tsx
- desktop/test/smoke-jsonl.ts
- desktop/tsconfig.web.json
- desktop/src/renderer/src/lib/client.ts
- desktop/test/vouch-locator.test.ts
- desktop/src/preload/index.ts
- spec/2026-05-21/retrieval.md
- desktop/src/renderer/src/lib/VouchContext.tsx
- desktop/src/renderer/src/components/results/Cards.tsx
- desktop/src/renderer/src/lib/useVouchEvents.ts
- desktop/src/renderer/src/components/results/Renderers.tsx
🛑 Comments failed to post (12)
.github/workflows/security-audit.yml (2)
25-40: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
Do not mask audit setup failures.
Job-level
continue-on-erroralso hides checkout, dependency installation, and audit setup failures, allowing the workflow to appear successful without scanning. Keep setup failures fatal and scope the non-blocking behavior to thepip-auditstep only.🧰 Tools
🪛 zizmor (1.26.1)
[warning] 27-27: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false
(artipacked)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.github/workflows/security-audit.yml around lines 25 - 40, Remove the job-level continue-on-error setting so checkout, Python setup, and dependency installation failures remain fatal. Add continue-on-error only to the step named “audit” that runs pip-audit, preserving non-blocking audit findings without masking setup failures.
27-27: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
Disable checkout credential persistence.
actions/checkoutleavesGITHUB_TOKENin local Git configuration by default. Since the workflow later executes installation code, compromised repository or build code could access that token. Setpersist-credentials: false.🧰 Tools
🪛 zizmor (1.26.1)
[warning] 27-27: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false
(artipacked)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.github/workflows/security-audit.yml at line 27, Update the actions/checkout@v4 step to set persist-credentials: false, preventing the GITHUB_TOKEN from being stored in local Git configuration before installation code runs.Source: Linters/SAST tools
.vouch/decided/20260707-092531-154cb163.yaml (1)
42-45: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win
Record an actionable rejection reason.
decision_reason: 'yes'does not explain why this proposal was rejected, making the review decision difficult to audit or act on. Store the actual rejection rationale.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.vouch/decided/20260707-092531-154cb163.yaml around lines 42 - 45, Replace the non-actionable decision_reason value “yes” with a concise, specific explanation of why the proposal was rejected, preserving the existing status and decision metadata..vouch/pages/session-what-are-the-non-development-related-files-and-folde.md (2)
36-38: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
Redact host-specific paths before committing session pages.
This page exposes
/home/a/.claude/...and/tmp/claude-1000/..., leaking the local username, filesystem layout, and names of private memory or scratchpad artifacts. Store repository-relative or redacted paths instead; the same capture data is also present in the corresponding decided record.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.vouch/pages/session-what-are-the-non-development-related-files-and-folde.md around lines 36 - 38, Replace the host-specific absolute paths in the session page with repository-relative or otherwise redacted paths, removing usernames, temporary directories, and private memory or scratchpad filenames. Also update the corresponding decided record containing the same capture data to apply the same redaction.
42-42: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Normalize the captured Markdown.
The fenced block lacks a language identifier, and the command code span contains invalid spacing, triggering MD040 and MD038. Fix the capture formatter or normalize this artifact before committing.
Also applies to: 68-68
🧰 Tools
🪛 markdownlint-cli2 (0.22.1)
[warning] 42-42: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.vouch/pages/session-what-are-the-non-development-related-files-and-folde.md at line 42, Normalize the captured Markdown in the affected fenced blocks: add a language identifier to each fence to satisfy MD040, and remove invalid leading or trailing spaces from the command inline code spans to satisfy MD038. Apply the same cleanup to both referenced occurrences.Source: Linters/SAST tools
CONTRIBUTING.md (1)
128-130: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Separate webapp evidence from CLI-only changes.
This currently requires vouch-ui screenshots or recordings even for CLI-output changes, where no corresponding webapp state may exist. Require vouch-ui evidence for webapp changes and terminal captures for CLI changes; also use “screen recording” and “web app.”
🧰 Tools
🪛 LanguageTool
[grammar] ~128-~128: Ensure spelling is correct
Context: ... commits. - For changes that affect the webapp, CLI output, or user-facing behavior: ...(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)
[grammar] ~129-~129: Ensure spelling is correct
Context: ...ts or screenrecording from the vouch-ui webapp showing the behavior working as inten...(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@CONTRIBUTING.md` around lines 128 - 130, The contribution guidelines should distinguish evidence requirements by change type: require vouch-ui screenshots or screen recording for web app changes, and terminal captures for CLI-output changes. Update the wording to use “screen recording” and “web app,” without requiring web-app evidence for CLI-only changes.Source: Linters/SAST tools
docs/superpowers/specs/2026-07-06-review-ui-multi-kb-design.md (1)
3-9: 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win
Remove local filesystem and unpushed-branch details.
The committed spec includes
~/Dev/plind-junior/...and an unpushed branch reference. This leaks local environment information, is not reproducible for readers, and will become stale; replace it with a stable repository/commit link or a concise implementation-status statement.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/superpowers/specs/2026-07-06-review-ui-multi-kb-design.md` around lines 3 - 9, The spec metadata includes non-reproducible local filesystem and unpushed branch details. Update the introductory status text in the review-ui multi-KB design spec to remove the local path and branch reference, replacing them with a stable repository or commit link, or a concise implementation-status statement.src/vouch/health.py (2)
576-626: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
_tickprogress callback is never invoked.
_tickis defined but never called anywhere inrebuild_index, so the documentedon_progressphase labels ("claims", "pages", "entities", "embeddings") never fire. Either wire_tick(...)into each stage or drop the dead helper and the docstring promise.🔧 Proposed wiring
index_db.reset(store.kb_dir) with index_db.open_db(store.kb_dir) as conn: + _tick("claims") for c in store.list_claims(): index_db.index_claim( conn, id=c.id, text=c.text, type=c.type.value, status=c.status.value, tags=c.tags, ) + _tick("pages") for p in store.list_pages(): index_db.index_page( conn, id=p.id, title=p.title, body=p.body, type=p.type, tags=p.tags, ) + _tick("entities") for e in store.list_entities(): index_db.index_entity( conn, id=e.id, name=e.name, description=e.description, type=e.type.value, aliases=e.aliases, ) + _tick("embeddings") _rebuild_embeddings(store)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.def _tick(phase: str) -> None: if on_progress is not None: on_progress(phase) # Detect a stale embedding-model identity before reset() wipes the meta. try: from . import audit from .embeddings.migration import detect_mismatch m = detect_mismatch(store.kb_dir) if m is not None: audit.log_event( store.kb_dir, event="embedding.model_mismatch", actor="vouch-health", object_ids=[], data=m, ) except ImportError: pass index_db.reset(store.kb_dir) with index_db.open_db(store.kb_dir) as conn: _tick("claims") for c in store.list_claims(): index_db.index_claim( conn, id=c.id, text=c.text, type=c.type.value, status=c.status.value, tags=c.tags, ) _tick("pages") for p in store.list_pages(): index_db.index_page( conn, id=p.id, title=p.title, body=p.body, type=p.type, tags=p.tags, ) _tick("entities") for e in store.list_entities(): index_db.index_entity( conn, id=e.id, name=e.name, description=e.description, type=e.type.value, aliases=e.aliases, ) _tick("embeddings") _rebuild_embeddings(store) return index_db.stats(store.kb_dir)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/vouch/health.py` around lines 576 - 626, Wire the existing _tick progress helper into rebuild_index’s stages: call it with "claims", "pages", and "entities" before their respective indexing loops, and with "embeddings" before _rebuild_embeddings(store). Preserve the documented phase labels and on_progress behavior.
629-651: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash # Which table does semantic search read, and does index_embedding target embeddings vs embedding_index? rg -nP 'def (search_embedding|search_semantic|index_embedding|put_embedding|get_embedding)\b' src/vouch/index_db.py rg -nP 'FROM (embeddings|embedding_index)\b' src/vouch/index_db.py sed -n '110,140p' src/vouch/index_db.pyRepository: vouchdev/vouch
Length of output: 1919
🏁 Script executed:
#!/bin/bash sed -n '400,500p' src/vouch/index_db.py rg -n "embedding_index|search_semantic|search_embedding|rebuild_index|rebuild_embeddings|backend" tests src -g '!**/__pycache__/**'Repository: vouchdev/vouch
Length of output: 24250
🏁 Script executed:
#!/bin/bash sed -n '568,660p' src/vouch/health.py sed -n '1,120p' src/vouch/index_db.py rg -n "\bembeddings\b" src tests -g '!**/__pycache__/**'Repository: vouchdev/vouch
Length of output: 17391
Populate
embedding_indexduring_rebuild_embeddingsrebuild_index()clears the table thatsearch_semantic()reads, but this helper only writes the legacyembeddingstable viaindex_db.index_embedding(). That leavesbackend=embeddingsearches empty after a rebuild until a separate backfill runs.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/vouch/health.py` around lines 629 - 651, Update _rebuild_embeddings to populate the embedding_index table used by search_semantic() in addition to the legacy embeddings table written by index_db.index_embedding(). After generating each vector, invoke the appropriate embedding_index insertion/upsert helper with the same kind, entity ID, and vector, ensuring rebuilt indexes immediately support backend=embedding searches.Source: Linters/SAST tools
src/vouch/index_db.py (1)
134-167: 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash # Who reads the new `embeddings` table vs `embedding_index`? echo "== callers of search_embeddings (new table) ==" rg -nP '\bsearch_embeddings\s*\(' --type=py -g '!**/index_db.py' echo "== callers of search_embedding / embedding_index path ==" rg -nP '\bsearch_embedding\s*\(' --type=py echo "== writers of embedding_index ==" rg -nP '\b(put_embedding|index_embedding)\s*\(' --type=py echo "== what rebuild_index repopulates ==" ast-grep run --pattern 'def rebuild_index($$$) { $$$ }' --lang python src/vouch/health.py || sed -n '560,655p' src/vouch/health.pyRepository: vouchdev/vouch
Length of output: 199
🏁 Script executed:
#!/bin/bash set -euo pipefail echo '== file list ==' git ls-files 'src/vouch/*' echo '== search for embedding-related symbols ==' rg -n --hidden --glob '!**/.git/**' '\b(search_embeddings|search_embedding|index_embedding|put_embedding|embedding_index|embeddings)\b' src/vouch echo '== outline src/vouch/index_db.py ==' ast-grep outline src/vouch/index_db.py --view expanded || true echo '== outline src/vouch/health.py ==' ast-grep outline src/vouch/health.py --view expanded || true echo '== outline src/vouch/storage.py ==' ast-grep outline src/vouch/storage.py --view expanded || trueRepository: vouchdev/vouch
Length of output: 17129
🏁 Script executed:
#!/bin/bash set -euo pipefail echo '== src/vouch/health.py 534-655 ==' sed -n '534,655p' src/vouch/health.py echo '== src/vouch/index_db.py 134-175 ==' sed -n '134,175p' src/vouch/index_db.py echo '== src/vouch/index_db.py 321-500 ==' sed -n '321,500p' src/vouch/index_db.py echo '== src/vouch/storage.py 741-805 ==' sed -n '741,805p' src/vouch/storage.pyRepository: vouchdev/vouch
Length of output: 14981
🏁 Script executed:
#!/bin/bash set -euo pipefail echo '== search_semantic callers ==' rg -n '\bsearch_semantic\s*\(' src/vouch echo '== surrounding fallback logic in likely callers ==' sed -n '150,240p' src/vouch/proposals.py sed -n '160,230p' src/vouch/triage.py sed -n '130,240p' src/vouch/embeddings/similarity.pyRepository: vouchdev/vouch
Length of output: 8134
🏁 Script executed:
#!/bin/bash set -euo pipefail echo '== callers of rebuild_index ==' rg -n '\brebuild_index\s*\(' src/vouch echo '== any direct callers of search_embeddings ==' rg -n '\bsearch_embeddings\s*\(' src/vouch echo '== search/semantic caller contexts around index_db.search_semantic ==' sed -n '120,210p' src/vouch/jsonl_server.py sed -n '150,210p' src/vouch/server.py sed -n '2250,2345p' src/vouch/cli.py sed -n '1,130p' src/vouch/context.pyRepository: vouchdev/vouch
Length of output: 14588
🏁 Script executed:
#!/bin/bash set -euo pipefail echo '== src/vouch/cli.py 2670-2705 ==' sed -n '2670,2705p' src/vouch/cli.py echo '== src/vouch/embeddings/migration.py outline ==' ast-grep outline src/vouch/embeddings/migration.py --view expanded || true echo '== relevant embedding migration functions ==' rg -n '\b(backfill_embeddings|detect_mismatch|migrate|embedding_index)\b' src/vouch/embeddings/migration.py src/vouch/cli.py src/vouch/health.pyRepository: vouchdev/vouch
Length of output: 2877
🏁 Script executed:
#!/bin/bash set -euo pipefail echo '== src/vouch/embeddings/migration.py 1-120 ==' sed -n '1,120p' src/vouch/embeddings/migration.py echo '== src/vouch/index_db.py schema area 1-80 ==' sed -n '1,80p' src/vouch/index_db.pyRepository: vouchdev/vouch
Length of output: 4933
Unify the embedding store used by rebuild and search
index_embeddingwrites toembeddings, butsearch_semantic/search_embeddingstill readembedding_index. A plainvouch reindextherefore rebuilds FTS5 only; embedding-based search stays empty untilbackfill_embeddingsruns. Make the rebuild path populate the same table the semantic path reads, or collapse the two stores.🧰 Tools
🪛 ast-grep (0.44.1)
[info] 137-137: use jsonify instead of json.dumps for JSON output
Context: json.dumps(vec)
Note: [CWE-116] Improper Encoding or Escaping of Output.(use-jsonify)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/vouch/index_db.py` around lines 134 - 167, The rebuild and semantic search paths use different embedding tables, so reindexing leaves embedding search empty. Update the rebuild logic and its embedding write helper, including index_embedding, to populate the embedding_index table consumed by search_semantic/search_embedding, or consolidate both paths onto one shared table and update all related queries consistently.src/vouch/jsonl_server.py (1)
713-726: 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win
_h_propose_themebypasses per-request actor attribution.
actor = p.get("agent") or os.environ.get("VOUCH_AGENT", ...)skips_agent(), so the HTTP transport's_actorContextVar (set from theX-Vouch-Agentheader) is ignored and theme proposals are misattributed in the audit log. Use_agent()as the fallback for consistency with every other handler.🔧 Proposed fix
- actor = p.get("agent") or os.environ.get("VOUCH_AGENT", "unknown-agent") + actor = p.get("agent") or _agent()📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.def _h_propose_theme(p: dict) -> dict: from . import themes store = _store() actor = p.get("agent") or _agent() cluster = themes.ThemeCluster( entities=p["entities"], claim_ids=p["claim_ids"], session_ids=p.get("session_ids", []), score=float(p.get("score", 0.0)), session_count=len(p.get("session_ids", [])), claim_count=len(p["claim_ids"]), ) return themes.propose_theme(store, cluster, proposed_by=actor)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/vouch/jsonl_server.py` around lines 713 - 726, Update _h_propose_theme to use _agent() as the fallback when resolving actor, while preserving an explicitly supplied p["agent"] value. Replace the environment-variable fallback so the HTTP transport’s _actor ContextVar and X-Vouch-Agent attribution are honored consistently in themes.propose_theme.tests/embeddings/test_integration.py (1)
48-72: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash # Check lines 1-47 of test_integration.py for embedder registration setup sed -n '1,47p' tests/embeddings/test_integration.pyRepository: vouchdev/vouch
Length of output: 1470
🏁 Script executed:
#!/bin/bash sed -n '48,120p' tests/embeddings/test_integration.py rg -n "def search_semantic|get_embedder|register.*embedder|_use_mock_embedder|embedder" vouch tests -g '!**/__pycache__/**'Repository: vouchdev/vouch
Length of output: 4273
🏁 Script executed:
#!/bin/bash sed -n '1,220p' tests/embeddings/conftest.py printf '\n--- index_db ---\n' sed -n '1,260p' vouch/index_db.py printf '\n--- embeddings core ---\n' sed -n '1,260p' vouch/embeddings/__init__.py printf '\n--- search tests ---\n' sed -n '1,120p' tests/embeddings/test_search.pyRepository: vouchdev/vouch
Length of output: 5717
🏁 Script executed:
#!/bin/bash fd -a 'index_db.py|base.py|__init__.py' . | sed -n '1,40p' printf '\n--- index_db candidates ---\n' for f in $(fd -a 'index_db.py' .); do echo "### $f"; sed -n '1,260p' "$f"; done printf '\n--- embeddings base/init candidates ---\n' for f in $(fd -a 'base.py' .); do echo "### $f"; sed -n '1,260p' "$f"; done for f in $(fd -a '__init__.py' . | grep '/embeddings/__init__.py'); do echo "### $f"; sed -n '1,260p' "$f"; doneRepository: vouchdev/vouch
Length of output: 12617
🏁 Script executed:
#!/bin/bash python3 - <<'PY' from pathlib import Path p = Path('src/vouch/index_db.py') text = p.read_text() for key in ['def search_semantic', 'get_embedder(', 'except (KeyError, ImportError)', 'return []']: idx = text.find(key) print(f"\n### {key} @ {idx}") if idx != -1: start = text.rfind('\n', 0, idx) end = text.find('\n\n', idx) print(text[idx:end if end != -1 else len(text)]) PY printf '\n--- semantic search references ---\n' rg -n "search_semantic|get_embedder|DEFAULT_MODEL_NAME|register\\(" src tests -g '!**/__pycache__/**'Repository: vouchdev/vouch
Length of output: 11574
Register an embedder or skip this test when embeddings aren’t available.
search_semantic()returns[]if no embedder is registered, sohits[0][1]can fail here unless this module installs a backend or gates the test on the real embedding dependency. Reuse the mock registration pattern from the other embedding tests, or add animportorskipfor the embeddings extra.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/embeddings/test_integration.py` around lines 48 - 72, Ensure test_semantic_search_finds_lexically_disjoint_claim registers the mock embedder used by the other embedding tests before calling index_db.search_semantic, or skip the test with importorskip when the real embeddings dependency is unavailable. Keep the assertion unchanged once search is guaranteed to return results.
Description:
Fixes #439
Problem
compile_kb() seeds taken_names once from on-disk pages and pending proposals, before the phase-1 draft-validation loop runs. It's never updated as drafts are accepted within that same loop. If an LLM batch drafts two pages with the same title — or titles that slugify to the same id (e.g. "Retry Policy" vs "retry policy") — both pass _draft_problem's collision guard and get filed as separate PENDING page proposals with the same underlying id.
Approving the first creates the page. Approving the second silently routes through update_page() (the vault-edit path) and overwrites the first — no error, no diff surfaced to the reviewer.
Fix
Fold each survivor's title and slug into taken_names immediately after it's accepted in the phase-1 loop, mirroring what phase 2 already does for wikilink resolution. A later draft in the same batch with a colliding title/slug now correctly fails the collision guard and is dropped with reason "page for {title!r} already exists or is pending review".
Testing
Added test_same_batch_duplicate_title_drops_second — exact-title collision within one batch
Added test_same_batch_duplicate_slug_drops_second — same-slug, different-casing collision
Both fail without the fix, pass with it
Full suite: make check clean (ruff, mypy), pytest 1160/1161 passing — the one failure (test_git_changes_in_a_real_repo) is a pre-existing local GPG-agent environment issue, confirmed unrelated by reproducing it identically with these changes stashed
CHANGELOG.md updated under [Unreleased]