Skip to content

feat(experts): kb.experts — rank entities by evidence density on a topic (closes #315)#347

Open
e11734937-beep wants to merge 8 commits into
vouchdev:testfrom
e11734937-beep:feat/vouch-experts
Open

feat(experts): kb.experts — rank entities by evidence density on a topic (closes #315)#347
e11734937-beep wants to merge 8 commits into
vouchdev:testfrom
e11734937-beep:feat/vouch-experts

Conversation

@e11734937-beep

@e11734937-beep e11734937-beep commented Jul 3, 2026

Copy link
Copy Markdown

Summary

Closes #315. Adds kb.experts — a read-only query that answers "who/what does the kb know about X." Given a free-text topic, it ranks the entities carrying the most matched evidence, so an agent can pull the right write-ups or ask the right follow-up.

Pure read: it aggregates approved, live claims and returns a ranking — no propose_*, no approve, no writes, no network, no LLM. The review gate is untouched by construction.

Surface

  • cli: vouch experts "<topic>" [--limit N] [--min-claims N] [--weight count|recency|citation] [--json]
  • method: kb.experts(topic, limit=10, min_claims=1, weight="count"), wired at all four registration sites — server.py (kb_experts MCP tool), jsonl_server.py (_h_experts + HANDLERS), capabilities.py (METHODS), cli.py (vouch experts). test_capabilities stays green.
  • matching: FTS hits on the topic (index_db.search) plus the substring pass on entity name/aliases (salience._substring_entity_ids); aggregate the entities referenced by the matched claims.
  • weights: count (matched-claim count), recency (half-life decay on last_confirmed_at/updated_at), citation (distinct evidence ids × confidence). An unknown weight falls back to count (never raises).
  • result: [{entity_id, name, type, claim_count, citation_count, score, top_claim_ids}], ordered by descending score with a stable tie-break on entity_id.

Scope & correctness

Ranking/status logic lives in a new dedicated src/vouch/experts.py (not recall.py, not storage.py which stays pure I/O). Claims with status superseded/archived/redacted are excluded so a non-live claim never inflates a score (issue #78). Runs entirely against the local .vouch/ kb; zero network, zero LLM.

Tests

tests/test_experts.py covers each weight mode, the status-exclusion filter, min_claims/limit, unknown-weight fallback, empty-kb / no-match, and the deterministic tie-break. tests/test_capabilities.py stays green with kb.experts present at all sites.

Verification

  • python -m ruff check src tests — clean
  • python -m mypy src — clean (0 errors, 80 files)
  • python -m pytest — full suite green (7 new tests; no regressions)

Summary by CodeRabbit

  • New Features
    • Added expert-ranking support across the app, including a new command, server tool, and request method (kb.experts).
    • Outputs ranked “experts” for a given topic, with configurable limit, min-claims, and scoring weight.
    • Supports both human-readable output and JSON output.
  • Tests
    • Added a dedicated test suite covering ranking, filtering, empty/no-match behavior, fallback weight handling, deterministic tie-breaking, and JSONL endpoint responses.

@github-actions github-actions Bot added cli command line interface mcp mcp, jsonl, and http surfaces tests tests and fixtures size: M 200-499 changed non-doc lines labels Jul 3, 2026
@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a read-only kb.experts ranking path that scores entities for a topic, exposes it through MCP, JSONL, and CLI entry points, and updates capabilities plus tests for ranking, filtering, and request handling.

Changes

kb.experts ranking feature

Layer / File(s) Summary
Core ranking logic
src/vouch/experts.py
Implements rank_experts with count, recency, and citation weighting; excludes superseded, archived, and redacted claims; and returns deterministically ordered expert rows.
Expose kb.experts across interfaces
src/vouch/server.py, src/vouch/jsonl_server.py, src/vouch/cli.py, src/vouch/capabilities.py
Adds the MCP kb_experts tool, JSONL kb.experts handler and dispatch entry, the vouch experts CLI command, and "kb.experts" in capabilities.
Tests for rank_experts and kb.experts
tests/test_experts.py
Adds coverage for weighting modes, min_claims/limit, status exclusion, fallback behavior, empty/no-match cases, tie-breaking, and JSONL request responses.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CLI as vouch experts
  participant MCP as kb_experts
  participant JSONL as kb.experts handler
  participant Experts as rank_experts
  participant Store as KBStore

  CLI->>Experts: rank_experts(store, topic, limit, min_claims, weight)
  MCP->>Experts: rank_experts(store, topic, limit, min_claims, weight)
  JSONL->>Experts: rank_experts(store, topic, limit, min_claims, weight)
  Experts->>Store: query matching claims and entities
  Store-->>Experts: matched claims and entities
  Experts-->>CLI: ranked expert rows
  Experts-->>MCP: ranked expert rows
  Experts-->>JSONL: ranked expert rows
Loading

Related issues: #315

Suggested labels: enhancement, feature

Suggested reviewers: vouchdev-maintainers

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The implementation matches #315: read-only kb.experts is exposed via MCP, JSONL, CLI, and capabilities, with the required ranking, filters, and tests.
Out of Scope Changes check ✅ Passed The diff stays within the requested experts-query feature and its registration/tests, with no unrelated changes indicated in the summary.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the new kb.experts feature and its purpose of ranking entities by evidence density on a topic.
✨ 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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/vouch/experts.py (1)

17-17: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Reaching into a private helper across module boundaries.

_substring_entity_ids is underscore-prefixed, signaling it's internal to salience. Importing it directly from experts.py couples the two modules to an unstable private API. Consider exposing a public wrapper (e.g. substring_entity_ids) in salience.py if this matching logic is meant to be reused.

🤖 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/experts.py` at line 17, The import in experts.py is reaching into
the private helper _substring_entity_ids from salience.py, which couples modules
to an internal API. Expose a public wrapper or renamed public function in
salience.py, such as substring_entity_ids, and update experts.py to import and
use that public symbol instead of the underscore-prefixed helper. Keep the
matching logic in salience.py and route any cross-module reuse through the
public entry point.
🤖 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 `@tests/test_experts.py`:
- Around line 1-126: `tests/test_experts.py` only exercises `rank_experts`
directly; add coverage for the `kb.experts` JSONL request/response envelope so
both success and failure cases are validated. Introduce tests around the
`kb.experts` entrypoint that assert a request yields `{id, ok, result}` on
success and `{id, ok: false, error}` on failure, using the existing
`rank_experts`/`KBStore` setup to keep the assertions aligned with the current
ranking behavior.

---

Nitpick comments:
In `@src/vouch/experts.py`:
- Line 17: The import in experts.py is reaching into the private helper
_substring_entity_ids from salience.py, which couples modules to an internal
API. Expose a public wrapper or renamed public function in salience.py, such as
substring_entity_ids, and update experts.py to import and use that public symbol
instead of the underscore-prefixed helper. Keep the matching logic in
salience.py and route any cross-module reuse through the public entry point.
🪄 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: d8578c4d-65a1-4ccc-8e2e-e2065cfcd901

📥 Commits

Reviewing files that changed from the base of the PR and between 5f58c69 and 3abe49e.

📒 Files selected for processing (6)
  • src/vouch/capabilities.py
  • src/vouch/cli.py
  • src/vouch/experts.py
  • src/vouch/jsonl_server.py
  • src/vouch/server.py
  • tests/test_experts.py

Comment thread tests/test_experts.py
plind-junior and others added 8 commits July 5, 2026 20:44
release 1.2.0: fresh-install fixes + compile/company-brain feature set
release 1.2.1: container images + version self-report
docs: promote readme restructure to main
docs: promote contributing refresh to main
docs: promote vouch webapp guidance to main
docs: promote pages-usage guidance to main
Closes vouchdev#315.

Add a read-only kb.experts query: given a free-text topic, rank the entities
carrying the most matched evidence (count / recency / citation weightings)
identically across mcp / jsonl / cli. Aggregates approved, live claims only —
excludes superseded/archived/redacted so a non-live claim never inflates a
score; no proposals, writes, network, or llm. Ranking lives in a new
src/vouch/experts.py, wired at the four registration sites.
The suite exercised rank_experts() directly but not the kb.experts JSONL
entrypoint. Add two envelope tests mirroring tests/test_jsonl_server.py:
a well-formed request returns {id, ok, result} with the ranking under
result["experts"], and a request missing the required `topic` param returns
the {id, ok: false, error} failure envelope (code "missing_param").

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@e11734937-beep

Copy link
Copy Markdown
Author

Rebased onto latest main and resolved the cli.py conflict (kept the base scaffolding block and appended the experts command) — the branch is mergeable again and the experts test suite passes (9/9). Ready for review whenever you have a moment, @plind-junior.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
tests/test_experts.py (1)

49-127: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

No test coverage for weight="recency".

Tests cover count, citation, and fallback-to-count for unknown weights, but recency (decay-weighted by updated_at/last_confirmed_at per PR objectives) has no dedicated test. Consider adding a case that seeds claims with distinct timestamps and asserts recency ordering differs from plain count ordering.

🤖 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/test_experts.py` around lines 49 - 127, Add a dedicated test for
rank_experts with weight="recency" to cover the decay-based ranking behavior
that is currently missing. In tests/test_experts.py, extend the existing
rank_experts-related coverage by seeding claims with distinct updated_at and/or
last_confirmed_at values so you can assert newer evidence ranks ahead of older
evidence even when claim counts are the same or differ. Make the test clearly
reference rank_experts, the recency weight branch, and the seeded timestamps so
it validates the intended ordering rather than the count-based fallback.
🤖 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.

Nitpick comments:
In `@tests/test_experts.py`:
- Around line 49-127: Add a dedicated test for rank_experts with
weight="recency" to cover the decay-based ranking behavior that is currently
missing. In tests/test_experts.py, extend the existing rank_experts-related
coverage by seeding claims with distinct updated_at and/or last_confirmed_at
values so you can assert newer evidence ranks ahead of older evidence even when
claim counts are the same or differ. Make the test clearly reference
rank_experts, the recency weight branch, and the seeded timestamps so it
validates the intended ordering rather than the count-based fallback.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: f06a26ca-bd45-4fe2-8d45-89d619b210c0

📥 Commits

Reviewing files that changed from the base of the PR and between 3abe49e and e967470.

📒 Files selected for processing (6)
  • src/vouch/capabilities.py
  • src/vouch/cli.py
  • src/vouch/experts.py
  • src/vouch/jsonl_server.py
  • src/vouch/server.py
  • tests/test_experts.py
🚧 Files skipped from review as they are similar to previous changes (5)
  • src/vouch/experts.py
  • src/vouch/server.py
  • src/vouch/cli.py
  • src/vouch/jsonl_server.py
  • src/vouch/capabilities.py

@plind-junior plind-junior changed the base branch from main to test July 6, 2026 08:39
@plind-junior

Copy link
Copy Markdown
Member

@e11734937-beep – For future reference, please ensure that PRs are raised against the test branch.

And congratulations on your first contribution to Vouch – great to have you on board! 💪

@e11734937-beep

Copy link
Copy Markdown
Author

Hello @plind-junior 👋
I'm happy to be contributing to vouch for the first time. I opened two PRs since July 3rd, both are passing all their checks, and each is set to close its linked issue on merge. I hope you can take a look when you have time.

#346vouch new <kind> (closes #330):
Generates a correctly-typed page/entity proposal from its registered shape. Passed CodeRabbit and the label checks.

#347 — kb.experts (closes #315):
A read-only query that ranks entities by evidence density for a topic ("who/what does the kb know about X"). Passed tests on Python 3.11 and 3.12.

There's absolutely no rush but I'm just flagging them in case they slipped the queue. I'm happy to rebase or adjust anything to comply with the project's conventions. Thank you for keeping vouch going! 🙏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cli command line interface mcp mcp, jsonl, and http surfaces size: M 200-499 changed non-doc lines tests tests and fixtures

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: kb.experts — rank entities by evidence density on a topic

2 participants