Skip to content

feat(search): offline BM25 lexical provider + pm eval relevance harness (pm-75k9, pm-u8n5) - #314

Merged
unbraind merged 2 commits into
mainfrom
feat/search-offline-bm25-and-relevance-eval
Jun 20, 2026
Merged

unbraind merged 2 commits into
mainfrom
feat/search-offline-bm25-and-relevance-eval

Conversation

@unbraind

Copy link
Copy Markdown
Owner

Summary

Two coherent post-v0.1 search capabilities under epic pm-ydp6 (Search & semantic retrieval), bundled because the eval harness is the natural validation vehicle for the new provider. Both ship at 100% coverage with full sandbox verification.

Offline BM25 provider (pm-75k9)

  • New pure module src/core/search/bm25.ts — Okapi BM25 (IDF + k1 term-frequency saturation + b length-normalization) scoring the in-memory corpus with no embedding service or vector store, for air-gapped / CI / zero-setup retrieval.
  • Activated via search.provider=bm25 (always) or auto (offline fallback only when no embedding/extension provider is available). Plain keyword mode is unchanged.
  • Wired into runSearch: --semantic returns pure BM25 hits (matched_fields:["bm25"]); --hybrid blends BM25 with the keyword scorer via combineHybridHits (now carries a dense-component label so hits read honestly). The exact full-ID / short-ID ranking guarantee is preserved in both modes.
  • Validated, persisted tuning knobs search.bm25.{k1,b}, settable via pm config set search_bm25_k1/b.

Search relevance eval harness (pm-u8n5)

  • New pure module src/core/search/eval.ts — nDCG@k / MRR@k / precision@k / recall@k over a binary-relevance golden set + parseEvalQuerySet validator.
  • New core command pm eval — runs each golden query through the live search path, reports per-query + macro-aggregate metrics; --fail-under turns it into a CI gate (prints the report, exits non-zero on aggregate-nDCG regression).
  • Golden set at <pmRoot>/search/eval-queries.json (git-tracked; a .gitignore negation keeps the search cache dir ignored while tracking the curated file). A 4-query golden set for this repo is included (aggregate nDCG ≈ 0.74).

Docs & governance

  • docs/COMMANDS.md + docs/CONFIGURATION.md document the BM25 provider, search.provider bm25/auto, the bm25 tuning knobs, and pm eval.
  • Registered as a core command (enum-contracts, EVAL_FLAG_CONTRACTS, help-content, regenerated contracts fixture). ADR pm-f2al records the design.

Verification

  • 100/100/100/100 coverage (4766 tests). static + docs-skills + docs-links + typecheck + contracts:check all green.
  • Manual sandbox test: keyword baseline unchanged; BM25 semantic/hybrid ranking; auto-fallback warning; config knobs persist + reject out-of-range; pm eval gate pass & fail (non-zero exit).

Closes pm-75k9, pm-u8n5. Records ADR pm-f2al.

🤖 Generated with Claude Code

Deliver two coherent post-v0.1 search capabilities under epic pm-ydp6
(Search & semantic retrieval), both validated end-to-end and at 100%
coverage.

Offline BM25 provider (pm-75k9)
- New pure module src/core/search/bm25.ts: Okapi BM25 (IDF + k1
  term-frequency saturation + b length-normalization) scoring the
  in-memory corpus with NO embedding service or vector store.
- Activated via search.provider=bm25 (always) or auto (offline fallback
  only when no embedding/extension provider is available); plain keyword
  mode is unchanged. Wired into runSearch for --semantic (pure BM25,
  matched_fields:[bm25]) and --hybrid (blended with the keyword scorer
  via combineHybridHits, which gained a dense-component label). The
  exact full-ID/short-ID guarantee is preserved in both modes.
- Validated/persisted tuning knobs search.bm25.{k1,b}, settable via
  pm config set search_bm25_k1/b.

Search relevance eval harness (pm-u8n5)
- New pure module src/core/search/eval.ts: nDCG@k, MRR@k, precision@k,
  recall@k over a binary-relevance golden set + parseEvalQuerySet
  validator.
- New core command `pm eval` (src/cli/commands/eval.ts): runs each
  golden query through the live search path, reports per-query +
  macro-aggregate metrics, and --fail-under turns it into a CI gate
  (prints the report, exits non-zero on aggregate-nDCG regression).
- Registered as a core command (enum-contracts, EVAL_FLAG_CONTRACTS,
  help-content, regenerated contracts fixture). Golden set lives at
  <pmRoot>/search/eval-queries.json (gitignore negation keeps the
  search cache dir ignored while tracking the curated file).

Docs: COMMANDS.md + CONFIGURATION.md cover the BM25 provider, the
search.provider bm25/auto values, the bm25 tuning knobs, and pm eval.
ADR pm-f2al records the design. All gates green: 100/100/100/100
coverage, static + docs-skills + typecheck + contracts.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WiNZNrE3rjftCC1udbBLGt
@gemini-code-assist

Copy link
Copy Markdown

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@sourcery-ai sourcery-ai 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.

Sorry @unbraind, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@unbraind

Copy link
Copy Markdown
Owner Author

@coderabbitai full review

@unbraind

Copy link
Copy Markdown
Owner Author

/gemini review

@unbraind

Copy link
Copy Markdown
Owner Author

@codex review

@gemini-code-assist

Copy link
Copy Markdown

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@coderabbitai

coderabbitai Bot commented Jun 20, 2026 •

Copy link
Copy Markdown
✅ Action performed

Full review finished.

@coderabbitai

coderabbitai Bot commented Jun 20, 2026 •

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@unbraind, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 40 minutes and 48 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: feddf7e1-e643-410c-b13b-19368e9573aa

📥 Commits

Reviewing files that changed from the base of the PR and between 384ee0e and c9930f0.

📒 Files selected for processing (32)
  • .agents/pm/decisions/pm-f2al.toon
  • .agents/pm/features/pm-75k9.toon
  • .agents/pm/features/pm-u8n5.toon
  • .agents/pm/history/pm-75k9.jsonl
  • .agents/pm/history/pm-f2al.jsonl
  • .agents/pm/history/pm-u8n5.jsonl
  • .agents/pm/search/eval-queries.json
  • .gitignore
  • CHANGELOG.md
  • docs/COMMANDS.md
  • docs/CONFIGURATION.md
  • src/cli/commands/contracts.ts
  • src/cli/commands/eval.ts
  • src/cli/commands/index.ts
  • src/cli/commands/search.ts
  • src/cli/help-content.ts
  • src/cli/register-list-query.ts
  • src/core/config/nested-settings.ts
  • src/core/search/bm25.ts
  • src/core/search/eval.ts
  • src/core/store/settings-validator.ts
  • src/sdk/cli-contracts.ts
  • src/sdk/cli-contracts/enum-contracts.ts
  • src/types.ts
  • tests/fixtures/contracts/full.json
  • tests/unit/cli/register-list-query.spec.ts
  • tests/unit/commands/config-key-aliases-search.spec.ts
  • tests/unit/commands/eval-command.spec.ts
  • tests/unit/commands/search-bm25.spec.ts
  • tests/unit/commands/search-command.spec.ts
  • tests/unit/core/search/bm25.spec.ts
  • tests/unit/core/search/eval-metrics.spec.ts
📝 Walkthrough

Walkthrough

Adds two new features: (1) an in-process offline Okapi BM25 lexical ranker that activates for semantic/hybrid modes when search.provider=bm25 or as an auto fallback when no embedding provider is configured, and (2) a pm eval CLI command that runs nDCG/MRR/precision/recall metrics over a git-tracked golden query set with a --fail-under CI gate.

Changes

Offline BM25 provider and pm eval relevance harness

Layer / File(s) Summary
BM25 types, settings schema, and config descriptors
src/core/search/bm25.ts, src/types.ts, src/core/store/settings-validator.ts, src/core/config/nested-settings.ts
Defines Bm25Params, Bm25Document, Bm25Index contracts; extends PmSettings.search with optional bm25?: { k1?, b? }; adds bm25 persistence to settings-validator; registers search_bm25_k1 and search_bm25_b in the nested-settings descriptor list with range constraints.
Okapi BM25 engine
src/core/search/bm25.ts
Implements tokenizeBm25, buildBm25Index, Lucene-variant IDF, scoreBm25Query with k1 saturation and b length normalization, flattenSearchCorpusText for corpus text extraction, and resolveBm25Params for settings clamping.
BM25 wiring into runSearch
src/cli/commands/search.ts
Adds resolveBuiltInBm25Mode and computeBuiltInBm25Hits; parameterizes combineHybridHits with a configurable semanticFieldLabel; integrates BM25 mode detection and hit computation into runSearch outside the semantic try/catch, emitting a warning in auto-fallback mode; exposes helpers via _testOnlySearchCommand.
Eval metrics core and golden-query model
src/core/search/eval.ts, .agents/pm/search/eval-queries.json
Defines EvalQuery/EvalQuerySet/EvalQuerySetError; implements dcgAtK, ndcgAtK, reciprocalRankAtK, precisionAtK, recallAtK, evaluateRanking, and aggregateEvalMetrics; adds parseEvalQuerySet for golden-query validation; adds the initial golden query set with four entries.
pm eval CLI command, registration, and contracts
src/cli/commands/eval.ts, src/cli/register-list-query.ts, src/sdk/cli-contracts.ts, src/sdk/cli-contracts/enum-contracts.ts, src/cli/commands/contracts.ts, src/cli/commands/index.ts, src/cli/help-content.ts
Implements runEval with options parsing, loadEvalQuerySet, per-query search execution, metric aggregation, and passed gate evaluation; registers the eval subcommand with --mode, --k, --fail-under, --queries, --format; adds EVAL_FLAG_CONTRACTS, extends PM_CORE_COMMAND_NAMES and CORE_COMMAND_FLAG_CONTRACT_ENTRIES; adds help content and re-exports runEval.
Unit tests
tests/unit/core/search/bm25.spec.ts, tests/unit/commands/search-bm25.spec.ts, tests/unit/commands/search-command.spec.ts, tests/unit/core/search/eval-metrics.spec.ts, tests/unit/commands/eval-command.spec.ts, tests/unit/cli/register-list-query.spec.ts, tests/unit/commands/config-key-aliases-search.spec.ts, tests/fixtures/contracts/full.json
Adds BM25 tokenization/index/scoring/flattening/clamping tests; resolveBuiltInBm25Mode and computeBuiltInBm25Hits unit tests; runSearch BM25 integration and auto-fallback warning test; runEval end-to-end, gate, loading, and failure-path tests; eval metric function and parseEvalQuerySet tests; CLI eval registration flag-forwarding and gate-rejection tests; updated alias count and contracts fixture.
Docs, gitignore, changelog, and PM tracking
.gitignore, CHANGELOG.md, docs/COMMANDS.md, docs/CONFIGURATION.md, .agents/pm/...
Updates .gitignore to unignore eval-queries.json while keeping search cache ignored; adds CHANGELOG entries; documents offline BM25 activation and tuning knobs; closes feature records pm-75k9 and pm-u8n5; adds ADR pm-f2al with history entries.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant CLI as register-list-query (eval)
  participant runEval
  participant loadEvalQuerySet
  participant runSearch
  participant evaluateRanking
  participant aggregateEvalMetrics

  User->>CLI: pm eval --mode hybrid --k 10 --fail-under 0.5
  CLI->>runEval: EvalOptions
  runEval->>loadEvalQuerySet: resolve queries path, readFile
  loadEvalQuerySet-->>runEval: EvalQuerySet
  loop per EvalQuery
    runEval->>runSearch: query text, mode, limit=k
    runSearch-->>runEval: ranked SearchResult ids
    runEval->>evaluateRanking: rankedIds, relevantIds, k
    evaluateRanking-->>runEval: QueryEvalMetrics
  end
  runEval->>aggregateEvalMetrics: QueryEvalMetrics[]
  aggregateEvalMetrics-->>runEval: AggregateEvalMetrics
  runEval-->>CLI: EvalResult { passed, fail_under, queries }
  alt passed = false
    CLI-->>User: throw PmCliError (EXIT_CODE.GENERIC_FAILURE)
  else passed = true
    CLI-->>User: print EvalResult JSON
  end
Loading
flowchart TD
  runSearch --> resolveBuiltInBm25Mode
  resolveBuiltInBm25Mode -- provider=bm25 --> explicit
  resolveBuiltInBm25Mode -- provider=auto no embedding --> auto_fallback
  resolveBuiltInBm25Mode -- other --> null_path
  explicit --> computeBuiltInBm25Hits
  auto_fallback --> emitOfflineWarning
  emitOfflineWarning --> computeBuiltInBm25Hits
  computeBuiltInBm25Hits --> flattenSearchCorpusText
  computeBuiltInBm25Hits --> buildBm25Index
  computeBuiltInBm25Hits --> scoreBm25Query
  computeBuiltInBm25Hits -- hybrid mode --> combineHybridHits
  combineHybridHits --> forceExactIdHitsToTop
  null_path --> semanticProviderBlock
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • unbraind/pm-cli#40: Modifies the same runSearch semantic/hybrid execution control flow and fallback-warning mechanics in src/cli/commands/search.ts that this PR extends with the BM25/auto offline path.
  • unbraind/pm-cli#81: Introduces the NESTED_SETTING_DESCRIPTORS/nested-settings alias infrastructure that this PR extends with the search_bm25_k1 and search_bm25_b descriptor entries.
  • unbraind/pm-cli#282: Introduces the forceExactIdHitsToTop exact-ID ranking guarantee that this PR's BM25 hybrid path explicitly routes through to preserve ID-match ordering.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 70.59% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(search): offline BM25 lexical provider + pm eval relevance harness (pm-75k9, pm-u8n5)' accurately and concisely summarizes the two main features added: an offline BM25 provider and an evaluation harness.
Description check ✅ Passed The description is well-structured and directly related to the changeset, covering the BM25 provider implementation, eval harness design, configuration, and verification results with comprehensive detail.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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.

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

@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: 5

🧹 Nitpick comments (1)
tests/unit/core/search/eval-metrics.spec.ts (1)

132-143: ⚡ Quick win

Add a regression test for mixed-type relevant_ids.

Current parser tests cover missing/empty arrays but not [string, non-string], which is a contract-sensitive validation edge case.

Suggested test case
   it("rejects a missing relevant_ids array", () => {
     expect(() => parseEvalQuerySet([{ query: "x" }])).toThrow(/"relevant_ids" array/);
   });
 
+  it("rejects non-string relevant_ids entries", () => {
+    expect(() => parseEvalQuerySet([{ query: "x", relevant_ids: ["pm-1", 7] }])).toThrow(/array of strings/);
+  });
+
   it("rejects an empty relevant_ids list (after trimming)", () => {
     expect(() => parseEvalQuerySet([{ query: "x", relevant_ids: ["", "  "] }])).toThrow(/at least one relevant id/);
   });
🤖 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/unit/core/search/eval-metrics.spec.ts` around lines 132 - 143, Add a
new test case in the parseEvalQuerySet test suite to validate that mixed-type
relevant_ids arrays are rejected. Create an it statement that calls
parseEvalQuerySet with a query object containing relevant_ids with both string
and non-string values (for example, strings mixed with numbers or objects), and
expect it to throw an appropriate error. This test should be placed alongside
the existing validation tests for missing arrays, empty lists, and invalid modes
to ensure the parser properly validates the type consistency of relevant_ids
elements.
🤖 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 `@CHANGELOG.md`:
- Line 8: In the CHANGELOG.md file, the offline/fallback embedding provider
entry currently mentions "TF-IDF or BM25" but only BM25 was actually implemented
and shipped. Remove the "TF-IDF or" portion from the changelog entry so it
accurately reflects that only the BM25 implementation was delivered, keeping the
rest of the description about the offline/fallback embedding provider feature
intact.

In `@src/cli/commands/eval.ts`:
- Around line 190-215: The issue is that metrics are being rounded before
aggregation, which can cause false pass/fail decisions around the failUnder
threshold. Store unrounded metrics from the evaluateRanking call (ndcg, mrr,
precision, recall) in the reports array without applying roundMetric() at the
point of insertion into the reports object. Then pass these unrounded metrics to
aggregateEvalMetrics() instead of the rounded ones. Only apply roundMetric() to
the final aggregateNdcg result after aggregateEvalMetrics() returns, just before
comparing it against the failUnder threshold in the passed variable assignment.
This ensures aggregate calculations work with full precision values rather than
pre-rounded ones.

In `@src/core/search/bm25.ts`:
- Around line 197-202: The resolveClampedParam function currently returns the
fallback value when a candidate is a finite number but outside the valid range,
which silently ignores user-configured values. Instead of rejecting out-of-range
finite values, clamp them to the min-max boundaries using Math.max(min,
Math.min(max, candidate)) to preserve user intent. Only return the fallback
value when the candidate is not a finite number, ensuring that values like
search.bm25.k1=5000 are clamped to the maximum allowed value rather than being
reset to defaults.

In `@src/core/search/eval.ts`:
- Around line 221-233: The current validation in the relevant_ids processing
silently filters out non-string values instead of rejecting malformed data.
After checking that entry.relevant_ids is an array, add explicit validation to
ensure all entries are strings, and throw an EvalQuerySetError with the query
index if any non-string values are found. Then apply the existing trim and
empty-string filtering only to the validated string array. This prevents
malformed golden data from passing validation undetected.

In `@src/sdk/cli-contracts.ts`:
- Around line 1393-1399: The EVAL_FLAG_CONTRACTS constant is defined but not
integrated into the command-name resolver logic, causing eval command contract
queries to default to an empty flag set. Locate the resolver logic (likely a
switch statement handling command names) and add a case "eval" branch that
returns EVAL_FLAG_CONTRACTS to make these flag contracts reachable for eval
command processing.

---

Nitpick comments:
In `@tests/unit/core/search/eval-metrics.spec.ts`:
- Around line 132-143: Add a new test case in the parseEvalQuerySet test suite
to validate that mixed-type relevant_ids arrays are rejected. Create an it
statement that calls parseEvalQuerySet with a query object containing
relevant_ids with both string and non-string values (for example, strings mixed
with numbers or objects), and expect it to throw an appropriate error. This test
should be placed alongside the existing validation tests for missing arrays,
empty lists, and invalid modes to ensure the parser properly validates the type
consistency of relevant_ids elements.
🪄 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: Repository UI (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 3ba64422-645f-4852-ae31-f550e2d6f64d

📥 Commits

Reviewing files that changed from the base of the PR and between 384ee0e and 9e69b21.

📒 Files selected for processing (32)
  • .agents/pm/decisions/pm-f2al.toon
  • .agents/pm/features/pm-75k9.toon
  • .agents/pm/features/pm-u8n5.toon
  • .agents/pm/history/pm-75k9.jsonl
  • .agents/pm/history/pm-f2al.jsonl
  • .agents/pm/history/pm-u8n5.jsonl
  • .agents/pm/search/eval-queries.json
  • .gitignore
  • CHANGELOG.md
  • docs/COMMANDS.md
  • docs/CONFIGURATION.md
  • src/cli/commands/contracts.ts
  • src/cli/commands/eval.ts
  • src/cli/commands/index.ts
  • src/cli/commands/search.ts
  • src/cli/help-content.ts
  • src/cli/register-list-query.ts
  • src/core/config/nested-settings.ts
  • src/core/search/bm25.ts
  • src/core/search/eval.ts
  • src/core/store/settings-validator.ts
  • src/sdk/cli-contracts.ts
  • src/sdk/cli-contracts/enum-contracts.ts
  • src/types.ts
  • tests/fixtures/contracts/full.json
  • tests/unit/cli/register-list-query.spec.ts
  • tests/unit/commands/config-key-aliases-search.spec.ts
  • tests/unit/commands/eval-command.spec.ts
  • tests/unit/commands/search-bm25.spec.ts
  • tests/unit/commands/search-command.spec.ts
  • tests/unit/core/search/bm25.spec.ts
  • tests/unit/core/search/eval-metrics.spec.ts

Comment thread CHANGELOG.md Resolved
Comment thread src/cli/commands/eval.ts Resolved
Comment thread src/core/search/bm25.ts Resolved
Comment thread src/core/search/eval.ts Resolved
Comment thread src/sdk/cli-contracts.ts Resolved
- eval gate: aggregate and gate on UNROUNDED metrics; round only for
  display so --fail-under decisions can't flip on display precision.
- eval: reject non-string relevant_ids entries (fail loudly) instead of
  silently dropping malformed golden data.
- bm25: clamp finite out-of-range k1/b to their bounds (preserve intent,
  e.g. k1=5000 -> 1000) rather than resetting to default; non-finite /
  non-number still falls back to the default.
- cli-contracts: add `case "eval"` to the command-name flag resolver so
  EVAL_FLAG_CONTRACTS is reachable (pm contracts --command eval).
- changelog: regenerate from the corrected pm-75k9 title (BM25-only,
  dropping the overstated "TF-IDF or BM25" wording).

All gates green: 100/100/100/100 coverage (4768 tests), static +
docs-skills + typecheck + contracts.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WiNZNrE3rjftCC1udbBLGt
@unbraind

Copy link
Copy Markdown
Owner Author

Addressed all 5 review findings in c9930f0 (unrounded gate, strict relevant_ids, BM25 clamp, eval flag resolver, changelog wording). @coderabbitai full review

@unbraind

Copy link
Copy Markdown
Owner Author

/gemini review

@gemini-code-assist

Copy link
Copy Markdown

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@coderabbitai

coderabbitai Bot commented Jun 20, 2026 •

Copy link
Copy Markdown

@unbraind Thanks for addressing all 5 findings! I'll kick off a fresh full review of the updated changes in c9930f0 now.

✅ Action performed

Full review finished.

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.

1 participant