Document RetrievalField engagement

Retrieval quality cannot be judged until each stage is scored separately, against a gold set built from the source rather than from the pipeline's own output.

Architecture and delivery lead.
The approach, in four words
gold from source, not outputscore each stageunits are semanticsplant the faults
extraction
index
fusion
generation
schema-valid, wrong units
a branch contributing nothing
absorbs an empty list silently
inherits all of it
Where a thin answer actually comes from. Scored as one fused output, all four are the same symptom. Scored per stage, each is a different piece of work.
What was at stake

Hybrid search and model-based extraction over documents full of tables, written in a language the standard text-search stack has no support for. The visible request was better search quality. The failure that mattered sat at the joint between extraction and the index, where a value can be perfectly well formed and still wrong, and every stage after it inherits the error without complaint.

How this works

Hybrid retrieval runs two searches and blends the results, so one of them can stop working without anyone noticing.

Document search systems now commonly combine two kinds of search. Vector search turns text into numerical embeddings and finds passages whose meaning is close to the query, even when the words differ. Lexical search matches the actual words, which matters for names, codes, product identifiers and figures, the things embeddings tend to blur. A hybrid system runs both and merges their ranked lists. A common way to merge them is rank fusion, where each document earns credit from its position in each list and the credits are added together.

Lexical search depends on a text-search configuration for the language: how to split text into words, how to reduce words to a common form, which words to ignore. For widely used languages these come built in. For a language without one, text is processed by a generic fallback that does not split or normalise it in a useful way, and queries can match nothing at all. Rank fusion then receives one full list and one empty list. An empty list adds no credit to anything, so the fused ranking is the vector ranking, unchanged. The system still reports itself as hybrid, and no step raises an error.

Tables add a second trap at extraction time. A model reads a table and emits structured rows, and a schema checks that each field has the right type: an amount is a number, a date is a date. Schema checks are about form. They cannot tell that a column header said the figures are in ten-thousands, so a bare number in a cell passes validation while being wrong by that whole factor. The defence comes from the documents themselves. Financial and official tables usually state totals, and a total is an independent check on every row that feeds it.

Language with text-search support
Vector branch returns candidates
matches on meaning
Lexical branch returns candidates
matches names, codes and figures
Fusion blends both lists
each branch covers the other's blind spots
Language without a configuration
Vector branch returns candidates
unchanged
Lexical branch returns nothing
no tokens match, no error raised
Fusion returns the vector ranking
labelled hybrid, behaving dense-only
Nothing in the output reveals which column you are in
Shown in a lab reproduction of the commonly published recipe, not a client measurement.
FigureThe same hybrid pipeline, on a language with built-in text-search support and on one without. On the right, the lexical branch quietly returns nothing and fusion passes the vector ranking straight through. The output looks the same shape either way.
The constraint

Two of the obvious moves make things worse. A gold set built from extracted rows grades the pipeline against its own output, so it agrees with itself wherever it is wrong. It has to be built from the source tables. A score taken only on the fused result cannot say which branch contributed nothing, so each stage has to be scored on its own. Both silent failures here are of that kind: a lexical branch that returns no rows at all, and an extracted amount that passes every schema check while being wrong by four orders of magnitude.

Where it usually breaks

Multi-stage pipelines fail in the stage nobody scored separately.

Retrieval pipelines are usually evaluated where the user meets them, on the final answer. That is a sensible place to judge quality and a poor place to find causes. A weak answer can come from extraction that got a value wrong, from a branch that contributed nothing, or from ranking that put the right passage too low. From the final output these look the same: a thin answer.

The second pattern is a reference built from the system's own work. Labelling extracted rows is far quicker than going back to the source tables, so gold sets are often built that way. Every extraction error is then copied into the answer key, and the evaluation reports agreement exactly where the pipeline is wrong.

01

The branch that returns nothing

One side of a hybrid search contributes no candidates, and fusion hides it. The system runs as single-branch while every dashboard says hybrid.

02

The well-formed wrong value

An extracted figure has the right type and passes the schema, but its unit was left in the header. It is out by a large factor, with no error.

03

The self-referential gold set

The answer key was built from extracted rows, so it shares every extraction error and scores them as correct.

04

Tuning a knob that multiplies zero

Fusion weights are adjusted at length while one of the inputs they weight is empty. Nothing improves, and the conclusion drawn is that retrieval is hard.

05

The harness nobody tested

The evaluation has never been shown a known fault, so nobody knows whether it would notice one.

Lexical branch returns nothing
fusion passes the vector ranking through
Unit left in the header
schema-valid, out by a factor of ten thousand
Gold set built from output
the answer key shares the errors
The failure point
A thin answer
the only symptom the user sees
Each stage looks healthy when judged by the final output.
Each is visible the moment it is scored on its own.
Attribute before improving. The same thin answer has three different fixes.
FigureThree unrelated causes behind the same weak answer. A dead lexical branch, a unit error in extraction and a gold set copied from output each make results thinner, and none of them shows up in a score taken only on the final ranking.
The fork

The reflex, and the fix.

Road not taken

Tune the fused ranking

Pull

It is where quality is judged, and the fusion weights are the obvious knob.

Why not

If one branch contributes nothing, no weighting of it changes the result. The tuning is spent on a parameter that is multiplying zero.

Road taken

Score each stage against a gold set from source

Accepted

Building a gold set from the source tables and planting faults on purpose, before any tuning.

Bought

Each stage attributable on its own, so a dead branch or a unit error becomes a measurement instead of a theory.

Decision

Attribute before improving, because three different causes produce the same thin answer.

How it was built
01Gold from source
›
02Extraction
›
03Unit check
›
04Index and fuse
›
05Score per stage
01

A gold set built from the source tables

The reference answers come from the original tables, never from extracted rows. A gold set built from the pipeline's own output scores the pipeline against itself and agrees with it wherever it is wrong.

02

The lexical branch verified separately

The standard recipe pairs a vector index with a full-text index. For a language the text-search stack has no configuration for, the lexical side returns nothing, and rank fusion absorbs that silently. The result is the dense ordering, presented as hybrid, with no error raised anywhere. This was shown in a lab reproduction of the commonly published recipe.

03

Units extracted, never assumed

A table headed as being in ten-thousands reports bare numbers in its cells. A strict schema accepts the bare number, and the value is then wrong by a factor of ten thousand with no validation error anywhere. The unit is part of the value and is extracted as such.

04

Arithmetic cross-checks against stated totals

Documents of record are internally redundant, because people check them too. Summing the line items and comparing them with the stated total catches unit errors, missed rows and duplicated rows in one comparison.

05

Planted faults

Known faults are injected into the gold set, so the harness is shown to detect the classes of error it claims to detect. A harness that has never caught a planted fault has not been tested.

Inside the key decisions

What each choice cost, and what it bought.

ABuilding the gold set from the source tables

Going back to the original tables is slower than labelling extracted rows, and it surfaces disagreements that then have to be resolved by reading the source carefully. It is the only reference that can catch an extraction error, because it was made without the extractor. A gold set built from output would have scored the unit error as correct.

BScoring each stage on its own

Extraction was scored against the source, and each retrieval branch was measured for what it actually contributed before anything was fused. That adds several evaluations where one would usually be run. It is what turned an empty lexical branch from a suspicion into a measurement, and it stopped effort going into fusion weights that could not have helped.

CTreating the unit as part of the value

Units and scale were extracted explicitly from headers and notes, and every extracted table was checked arithmetically against its stated total where one existed. That adds work to extraction and leaves documents with no stated total flagged for attention. It catches the class of error a schema is structurally blind to, along with missed and duplicated rows, in a single comparison.

DPlanting faults before trusting the harness

Known errors, of the classes the harness claims to detect, were placed into the gold set deliberately. If the harness failed to flag them it would have been fixed before it was used to judge anything. That is extra work spent on the measuring instrument. Without it, a clean report could mean a clean pipeline or a blind harness, and there is no way to tell which.

  1. Gold set from source tables
    made without the extractor
  2. Plant known faults
    prove the harness can see them
  3. Score extraction alone
    against source, units included
  4. Measure each branch's contribution
    does lexical return anything at all
  5. Cross-check against stated totals
    units, missing rows, duplicates
  6. Only then tune fusion
    on inputs known to be live
Tuning was the first thing proposed and the last thing done.
FigureThe order of work. The measuring instrument is built and proven before it is used, each stage is scored on its own, and tuning the fused ranking comes last, once there is evidence that both branches are contributing.
How it was measured

A single headline number hides where a system fails. This work was scored on the dimensions that actually decide whether it holds in production, measured on real, held-out cases rather than the demo path.

Extraction correctness against sourceCandidate contribution per retrieval branchUnit and scale correctnessDetection rate on planted faults
The gate
Do the extracted line items add up to the document's stated total?
Accept the extraction
units, row count and duplicates are consistent
Flag for review
a unit error, a missed row or a duplicate
A document with no stated total is flagged too. There is nothing to check it against.
FigureThe arithmetic check applied to every extracted table that states a total. Documents of record are internally redundant because people check them too, and one comparison catches unit errors, missed rows and duplicated rows together.
figures

Reproduction results are lab measurements with their method and versions stated. They are not client outcomes.

What it produces
Without this discipline

A hybrid system running dense-only without anyone knowing, tuned on its fusion weights, serving values that are schema-valid and four orders of magnitude out.

This system

A gold set from source, each stage scored on its own, the lexical branch confirmed to contribute, units extracted explicitly and cross-checked against stated totals, and planted faults proving the harness sees what it claims to.

gold from source, not outputscore each stageunits are semanticsplant the faults
The operating envelope

What it owns, and what it hands to a person.

Handled with confidence
Per-stage attribution
Unit and scale validation against stated totals
Branch contribution measurement
Flagged for review
A document with no stated total to cross-check
A language with no text-search configuration
Out of scope by design
Correctness of a source table that is itself wrong
The honest limit

The reproductions behind this were lab measurements, run locally on a stated database and extension version against the commonly published recipe. They are not client outcomes. The behaviour follows from how text-search configurations and rank fusion each work, with no defect in either, so it should hold broadly. It was measured on one configuration.

What it generalizes to

Any multi-stage pipeline whose stages are judged by one combined output. Build the reference from the source, measure what each stage contributes, and plant faults so the harness proves it can see them.

What to take from this

A gold set built from a pipeline's own output agrees with that pipeline wherever it is wrong. Build the reference from the source.

In hybrid search, verify that each branch returns candidates on its own. Rank fusion absorbs an empty branch silently, and the system keeps calling itself hybrid.

Lexical search depends on a text-search configuration for the language. Without one, it can return nothing at all and raise no error.

A schema checks the form of a value, never its meaning. Extract units and scale explicitly, and use stated totals to check the arithmetic.

Plant known faults in your evaluation before trusting it. A harness that has never caught anything has not been tested.

How we engage

You have a system like this one.
Tell us where it stands.

Whether it is failing, not yet built, or about to meet a scale it has never seen, we can tell you what we see.

Start a conversation
mostafa@opulion.dev · Response within 24 hours · By inquiry