Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ All notable changes to vouch are documented here. Format follows

## [Unreleased]

### Fixed
- Fix `vouch search` CLI: assign backend label per code path so substring fallback results are no longer mislabelled as `fts5`; update stale docstring to reflect multi-backend search surface (#52).

### Fixed
- Bundle import rejects tar members whose path escapes `kb_dir`
(CVE-2007-4559, #9). Previously a crafted `.tar.gz` with a member
Expand Down
2 changes: 1 addition & 1 deletion src/vouch/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,7 @@ def crystallize(session_id: str, no_page: bool) -> None:
@click.argument("query")
@click.option("--limit", default=10, show_default=True, type=int)
def search(query: str, limit: int) -> None:
"""FTS5 search over claims, pages, and entities."""
"""Search claims, pages, and entities (embedding → fts5 → substring)."""
from . import index_db
store = _load_store()
try:
Expand Down
41 changes: 41 additions & 0 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,44 @@ def test_propose_entity_empty_name_shows_clean_error(store: KBStore) -> None:
def test_show_missing_proposal_shows_clean_error(store: KBStore) -> None:
result = CliRunner().invoke(cli, ["show", "no-such-proposal"])
_assert_clean_error(result, "proposal no-such-proposal")


def test_search_fts5_backend_label(
store: KBStore, monkeypatch: pytest.MonkeyPatch
) -> None:
"""vouch search prints (fts5) when FTS5 returns hits."""
from vouch import index_db
from vouch.proposals import approve as do_approve
from vouch.proposals import propose_claim
src = store.put_source(b"e")
pr = propose_claim(store, text="findable token", evidence=[src.id], proposed_by="agent")
do_approve(store, pr.id, approved_by="reviewer")
# Index only the FTS5 tables directly — no embedding stack needed
with index_db.open_db(store.kb_dir) as conn:
index_db.index_claim(
conn, id="c-findable", text="findable token",
type="observation", status="actionable", tags=[],
)
runner = CliRunner()
result = runner.invoke(cli, ["search", "findable"])
assert result.exit_code == 0, result.output
assert "(fts5)" in result.output


def test_search_substring_backend_label(
store: KBStore, monkeypatch: pytest.MonkeyPatch
) -> None:
"""vouch search prints (substring) when FTS5 raises and fallback runs."""
from vouch.proposals import approve as do_approve
from vouch.proposals import propose_claim
src = store.put_source(b"e")
pr = propose_claim(store, text="findable token", evidence=[src.id], proposed_by="agent")
do_approve(store, pr.id, approved_by="reviewer")
# Remove state.db so FTS5 raises and substring fallback runs
state_db = store.kb_dir / "state.db"
if state_db.exists():
state_db.unlink()
runner = CliRunner()
result = runner.invoke(cli, ["search", "findable"])
assert result.exit_code == 0, result.output
assert "(substring)" in result.output