Skip to content

epic(kb): retrieval quality is unmeasurable — real benchmarks, span metrics, chunker comparison, evidence-based tuning #13251

Open
0 of 7 issues completed

Description

@mrveiss

Why

We can change retrieval quality but we cannot measure it. Every chunking and retrieval constant in
the KB path was chosen by hand and has never been scored against a retrieval-quality metric, and the
one benchmark harness we have scores a synthetic corpus using a fake embedding function. The result
is that no one can answer "did that change make retrieval better?" with evidence.

This umbrella closes that loop: real measurement first, then comparison, then the tuning the
measurement unlocks. The ordering is deliberate — the tuning issues are worthless without the
measurement issues, and running them early would produce confident numbers we cannot trust.

Task tree

Phase 1 — make the measurement real (blocking; nothing downstream is meaningful without these)

Phase 2 — compare what we already run

Phase 3 — tune, on evidence

What we already do well (audited — no work proposed)

Each of these was checked against the code before anything was filed, and each is stronger than the
comparable technique in the reviewed external work:

Deliberately NOT proposed (do not re-raise without new information)

Closure gate

This umbrella closes when Phase 1 and Phase 2 are merged and at least one Phase 3 sweep has produced
a result — including a null result. "We measured and the current defaults are already best" is a
legitimate outcome and closes #13246; "we never measured" is not.

Activity

  1. mrveiss commented on Aug 1, 2026

    @mrveiss
    OwnerAuthor

    This gap is already blocking shipped work. #10621 (enable chat tiered routing by default) is gated on "benchmark chat quality with tiered routing ON vs OFF via autobot-backend/knowledge/rag_benchmarks.py" — a validation that cannot currently be performed, because that harness scores a 20-doc synthetic corpus with a 128-term count vector instead of the real embedding model (see #13243). A cost-saving routing change has therefore sat gated off rather than being validated. #13243 unblocks it.

  2. mrveiss commented on Aug 3, 2026

    @mrveiss
    OwnerAuthor

    A comparative platform audit (umbrella #13413) filed #13415 as the SQL-path half of this epic: services/nl_database_service.py converts natural language to SQL and executes it, and has no test file and no eval (rg -l 'nl_database' returns the service, the router, two schema files, the router registry and generated FE types — nothing else).

    Proposed to extend the existing eval/ harness rather than build a second one: golden reference queries graded on execution accuracy (result sets, position-matched columns, names stripped), 4-way verdicts, and a floor test so the corpus cannot be narrowed to raise the score.

  3. mrveiss commented on Aug 4, 2026

    @mrveiss
    OwnerAuthor

    Cross-link from a code-intelligence audit (umbrella #13467).

    #13472 (cohesion-based community re-split + hub exclusion in community_clusterer) changes which mesh nodes get promoted to retrieval anchors. It is explicitly blocked on this epic: until retrieval is measurable, landing it would swap one unmeasured heuristic for another with no way to show the swap was an improvement.

    No overlap in scope — this epic builds the measurement, #13472 is a consumer of it.

  4. mrveiss commented on Aug 4, 2026

    @mrveiss
    OwnerAuthor

    Sequence map: this umbrella is track U#13251 in #13483, which places all 282 open issues into ordered tracks.

    Derived order for this track's 7 open children:

    1. #13243 [--] fix(kb): RAG benchmark harness scores a synthetic corpus with a fake embed
      2. #13244 [--] feat(kb): add span-level retrieval metrics (recall/precision/precision-cei
      3. #13245 [--] feat(kb): chunking-strategy comparison runner — five production chunkers, 
      4. #13246 [--] feat(kb): sweep and validate chunk size + overlap defaults — 800-1000 toke
      5. #13247 [--] feat(kb): add global-segmentation semantic chunker — percentile-threshold 
      6. #13248 [--] feat(kb): generate a domain-specific retrieval eval set from AutoBot's own
      7. #13249 [--] feat(kb): bounded retrieval-config sweep runner with a significance gate a
    

    How much to trust this: track membership is reliable. The order is derived from stated blockers (only 9 exist backlog-wide), then priority label, then issue number — it is a starting default, not a proven critical path. Where a child carries its own ## Implementation order, that wins.

    64% of open issues have no priority label, which is why some rows sort last for no good reason — see #13485.

  5. mrveiss commented on Aug 8, 2026

    @mrveiss
    OwnerAuthor

    Cross-link: umbrella #13685 independently reconfirms this blocker from the context-assembly side.

    An audit of the tiered L0–L4 context stack found two of five layers structurally unable to render (#13686, #13687) and the whole stack flag-off with no recorded A/B result (#13689). Five of the items under that umbrella want a tuning decision, and none can be evaluated while knowledge/rag_benchmarks.py guards a fake embedding over 20 synthetic docs.

    Concretely, this issue gates the one design idea worth importing from an external layered-memory implementation: event-driven distillation with idle-flush and min/max interval bands instead of fixed crontabs. Adding seven interacting scheduler constants before a recall-quality metric exists would be adding tuning surface we cannot evaluate — the same mistake the external implementation's own docs concede they made.

    #13689 is deliberately not blocked on this: it judges what the stack demonstrably puts in the prompt, plus token cost and latency, all observable today. What this issue blocks is tuning the layers, not deciding whether they fire.

  6. 17 remaining items

  7. mrveiss commented on Oct 3, 2026

    @mrveiss
    OwnerAuthor

    Correction: the scheduling inversion I reported above was not real. Seven of the eight edges were spurious and have been removed.

    My earlier comment reported seven dependents scheduled before their blocker and asked whether to move this epic forward or the dependents back. That framing rested on the edges, and the edges were wrong. Nothing was scheduled against a blocker three milestones out, because seven of those eight issues were never blocked by this one.

    Exactly one dependent is genuine: #13472, which states the dependency in its own voice with reasoning — "#13251 builds the measurement, this consumes it." Its edge is untouched. And even it is decision-permissive: "Land after #13251, or at minimum with a recorded before/after anchor-set diff on this issue."

    The other seven all trace to one copied line. Six of the eight contain this status-table row verbatim:

    GATED   #13472  cohesion re-split                blocked by #13251
    

    That line says #13472 is blocked. It does not say the containing issue is. It appears in #13470, #13473, #13475, #13476, #13477 and #13467 — boilerplate replicated across a sibling set, with a native edge drawn from each occurrence because 13251 matched in the body.

    #13483 is the clearest case: its two mentions are "#13251 (retrieval measurement) gates #13472" and a list entry #13472 <-blocked by #13251. The sequencing tracker was subject to a gate it was accurately documenting.

    #13473 settles it beyond argument. Its body reads "Safe to start immediately. Independent of the code-graph track and of #13251" — while carrying a live edge to #13251. The edge contradicted the text it was derived from.

    What was actually released

    Three in-milestone, not the five a first count suggested — two of the seven had other open blockers the #13251 edge was masking:

    issue milestone open blockers now
    #13470 v0.10.0 none — startable
    #13473 v0.10.0 none — startable
    #13476 v0.10.0 none — startable
    #13467 v0.9.6 none
    #13477 Backlog none
    #13475 v0.10.0 #13476 — still blocked, and #13476 just became startable, so the pair clears in sequence
    #13483 v0.10.0 #13421, #13422

    Removing a spurious edge does not make an issue startable — it makes the remaining edges visible. That distinction cost two issues off the count.

    Mechanism, so it is not repeated

    13251 appearing in a body was treated as this body depends on 13251, with no check on what the sentence asserted. A prose reference to a sibling's gate became an edge on the containing issue.

    Each removal carries its evidence on the issue itself. #13472's edge is left in place. The needs-decision label can come off as far as the reschedule-versus-repoint question goes: neither is needed, because the dependency was real for one issue that already has its own escape hatch.

  8. removed
    needs-decisionBlocked on an owner decision; options and a recommendation are on the issue
    on Oct 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions