Skip to content

Feat/propose similarity warnings#148

Merged
plind-junior merged 5 commits into
vouchdev:testfrom
jsdevninja:feat/propose-similarity-warnings
Jun 9, 2026
Merged

Feat/propose similarity warnings#148
plind-junior merged 5 commits into
vouchdev:testfrom
jsdevninja:feat/propose-similarity-warnings

Conversation

@jsdevninja

Copy link
Copy Markdown
Contributor

What changed

propose_claim / kb.propose_claim now return optional non-blocking warnings when proposed claim text is semantically similar to an approved claim (similar_approved) or another pending claim proposal (similar_pending). Similarity uses the existing embedding index and on-the-fly embedding of pending payloads; it is gated on the embeddings extra and review.similarity_threshold (default 0.95). The CLI prints warnings to stderr after the proposal id; dry-run includes the same checks. propose_claim returns a ProposeClaimResult with a backward-compatible .id property.

Why

Multi-agent KBs often accumulate near-duplicate proposals that reviewers only catch manually in vouch pending. Post-hoc vouch dedup / kb.dedup_scan help after the fact but do not guide agents or humans at file time. Early warnings reduce duplicate review work without weakening the review gate — proposals still land as pending and nothing auto-merges or rejects.

Closes #147

What might break

  • On-disk layout: No changes.
  • Additive API change: kb.propose_claim responses may include a new warnings array. Clients that ignore unknown fields are unaffected; clients that strict-validate response shape should allow warnings.
  • propose_claim return type: Python callers now get ProposeClaimResult instead of Proposal, but .id and .proposal preserve common usage; no behaviour change when embeddings are not installed.

Not a breaking change for typical KB directories or review workflows.

VEP

Not required — additive optional field on an existing method; no on-disk format or audit-log shape change.

Tests

  • make check passes locally (lint + mypy + pytest)
  • New / changed behaviour has a test (tests/test_propose_similarity.py)
  • CHANGELOG.md updated under ## [Unreleased]

@jsdevninja jsdevninja changed the base branch from main to test June 1, 2026 14:00
@jsdevninja

Copy link
Copy Markdown
Contributor Author
image

@coderabbitai

coderabbitai Bot commented Jun 1, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: ac3be1b6-5aee-420c-b6be-21918df8fd02

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@jsdevninja

Copy link
Copy Markdown
Contributor Author

@plind-junior Would you please review?

@jsdevninja jsdevninja force-pushed the feat/propose-similarity-warnings branch from ac6c367 to 591f901 Compare June 3, 2026 04:14
@plind-junior

Copy link
Copy Markdown
Collaborator

Review

Summary: Implements propose-time similarity warnings for propose_claim as specified in #147. Additive, non-blocking, gated on the embeddings extra, backward-compatible. The feature shape matches the issue request exactly.

What works

  • src/vouch/embeddings/similarity.pyfind_similar_on_propose correctly gates on the embedder being available and returns an empty list on any Exception, so base installs are unaffected.
  • src/vouch/proposals.py — Similarity check runs before _file_proposal writes the proposal to disk, so the current proposal is never a false similar_pending self-match. The exclude_claim_id path correctly handles re-proposals of a claim that already exists as an approved artifact.
  • src/vouch/server.py:399_proposal_response uses hasattr(result, "proposal") to stay compatible with the other propose_* functions that still return a raw Proposal, so propose_page, propose_relation, and propose_entity are unaffected.
  • tests/test_propose_similarity.py — Good coverage: approved hit, pending hit, unrelated-text no-warning, dry-run, JSONL server, and no-embedder fallback.
  • tests/test_storage.py — The guarded_import test covers the ImportError path at the _file_proposal call site cleanly.
  • templates/config.template.yaml — Threshold documented in the canonical config template; similarity_threshold function handles missing config file gracefully via the blanket except Exception.

Suggestions

  • [non-blocking] src/vouch/embeddings/similarity.py:114–163_similar_pending encodes every pending CLAIM proposal on every propose_claim call (one embedder.encode() per pending proposal, synchronously). In a KB with hundreds of stale pending proposals this will stall the propose call noticeably. A comment acknowledging the O(n) cost and suggesting a future cache or cap would help reviewers know this is a deliberate v1 trade-off.

  • [non-blocking] src/vouch/embeddings/similarity.py:60–68similarity_threshold swallows all exceptions from store.config_path.read_text() and yaml.safe_load() silently (except Exception: pass). A _log.debug(...) on the except branch would make it easier to diagnose stale-config or permission issues in the field, consistent with the debug log already present at line 75.

  • [non-blocking] tests/test_propose_similarity.py:55–65test_propose_warns_similar_pending_proposal asserts not first.warnings on the first proposal, which is correct only because MockEmbedder is deterministic and there are no pre-existing pending claims. The assertion is fine, but a brief comment would clarify intent for future readers who might add fixture setup above it.

Verdict

approve — Feature is correctly scoped to v1 (claims only), strictly additive, all existing call sites continue to work, and the test suite covers the key paths including the no-embedder fallback. The non-blocking suggestions are quality-of-life items that do not affect correctness.

@plind-junior plind-junior merged commit 6be281c into vouchdev:test Jun 9, 2026
5 checks passed
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.

feat: propose-time similarity warnings for duplicate claims

2 participants