Skip to content

feat(search): passage-select + snippet-first for the answer path#327

Merged
us merged 1 commit into
mainfrom
feat/single-shot-passage-select
Jul 19, 2026
Merged

feat(search): passage-select + snippet-first for the answer path#327
us merged 1 commit into
mainfrom
feat/single-shot-passage-select

Conversation

@us

@us us commented Jul 19, 2026

Copy link
Copy Markdown
Owner

Two gated levers for /v1/search LLM answer synthesis. Both default off, so
merging changes nothing in prod until the flags are flipped; off = byte-identical
to the prior answer path (A/B keep/revert).

Changes

  • answer_bm25_select (new flag, default off): when a scraped source exceeds
    the per-source byte budget, keep its query-relevant passages (sentence-chunked +
    BM25-ranked, reusing the existing chunker/ranker) instead of a blind
    head-truncation that drops answers buried deep in a page. Two-pass with a
    partial-fill tail so it never feeds the model less than a head-truncation would
    (monotone on recall); non-adjacent passages are joined with a [...] gap marker.
  • snippet_fallback (repurposed → snippet-first): prepend the SERP snippet to
    every answer source and block-guard the scraped body, so a fetched-but-blocked
    page (a "Wikimedia Error" / bot-wall shell) falls back to the clean snippet
    instead of grounding on error text. The legacy path (flag off) is byte-identical,
    so the multi-round scout still fires on such sources.
  • Citation parsing splits on the last ===CITATIONS=== marker (rsplit) so a
    source that quotes the marker cannot truncate the answer or divert the parse.

Safety / rollout

  • Both features gated, default off — no behavior change on merge.
  • cargo fmt + cargo clippy --workspace -D warnings + cargo test --workspace
    all green; new unit tests cover passage-selection (deep-answer, budget-fill,
    oversized-blob, passthrough) and the block-shell detector.
  • Opencore images build on release only, so this is not live on prod until the
    next release-please release; activating the levers is a separate config flip.

Add two gated levers to the /v1/search LLM answer synthesis, both default
off so prod behavior is unchanged until flipped (A/B keep/revert; off =
byte-identical to the prior path).

- answer_bm25_select: when a scraped source exceeds the per-source byte
  budget, keep its query-relevant passages (sentence-chunked, BM25-ranked,
  reusing the existing chunker/ranker) instead of a blind head-truncation
  that drops answers sitting deep in the page. Two-pass with a partial-fill
  tail so it never feeds the model less than a head-truncation would
  (monotone on recall); non-adjacent passages are joined with a gap marker.
- snippet_fallback is now snippet-first: prepend the SERP snippet to every
  answer source and block-guard the scraped body, so a fetched-but-blocked
  page (a "Wikimedia Error"/bot-wall shell) falls back to the clean snippet
  instead of grounding the answer on error text. The legacy path (flag off)
  is byte-identical, so the multi-round scout still fires on such sources.

Also parse citations from the LAST ===CITATIONS=== marker (rsplit) so a
source that quotes the marker cannot truncate the answer or divert parsing.
@us
us merged commit 88f2e93 into main Jul 19, 2026
11 checks passed
@github-actions github-actions Bot locked and limited conversation to collaborators Jul 19, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant