The inconsistency
After #188, the two extraction components measure "saved tokens" against different baselines:
| Component |
Measures |
Site |
extract_llm_sweep |
content − the message as spliced |
extract_sweep.go, phase 3 |
extract_llm |
content − the projection |
extract_llm.go, out[k].saved |
In marker_mode: full — the default — the text actually written is replacement + "\n" + marker + recovery hint. So the projection-based figure omits the marker and the hint, and overstates by that much per candidate. Measured on the sweep's stocked fixture before it was corrected: 86,458 claimed against 86,201 actually sent, i.e. ~23 tokens per candidate.
Both feed metrics.RecordExtractionSaving / RecordExtractionValue, and both surface in /stats under by_component, so the two arms of a comparison are no longer measuring the same thing.
Why the gap matters more than its size
It is systematic, not noise: a fixed per-candidate overhead in one component and not the other, so it scales with the number of removals rather than averaging out. A configuration that removes more looks disproportionately better under the projection-based figure.
That matters specifically because extract_llm's savings figure is what iteration 024's re-run will be judged on. Anyone reading the two arms side by side needs to know one is wire-measured and the other is not.
The sweep is the correct one
content − MessageText(req.Input[i]) after the splice is the number an operator can check against their bill: it is what the request actually shrank by. extract_llm should move to the same basis.
Why it was not fixed in #188
Deliberate, and the reasoning is worth keeping: #188's subject is reserve durability, and moving a published savings figure inside it would make the iteration-024 comparison unreadable for a reason unrelated to what that PR changed. A savings number should move in a change whose subject is the savings number — otherwise the re-run cannot separate "the mechanism got better" from "we started counting differently". The sweep's figure moved there only because a comment added in the same commit asserted it was the wire figure, which made it wrong rather than merely inconsistent.
Suggested fix
Mirror the sweep: compute saved in phase 3 from the spliced message rather than carrying the projection-only delta out of runCall. out[k].saved already exists for that purpose, so it is a one-line change plus its test.
Note the same question applies to the replay paths, which credit content − cached.Projected at the repeat rate — also projection-only.
Sequencing
Worth landing after the iteration-024 re-run, or as an explicit note beside its results, so the re-run's numbers stay comparable to the ones already published. Otherwise a savings change lands in the middle of the comparison it would invalidate.
The inconsistency
After #188, the two extraction components measure "saved tokens" against different baselines:
extract_llm_sweepcontent − the message as splicedextract_sweep.go, phase 3extract_llmcontent − the projectionextract_llm.go,out[k].savedIn
marker_mode: full— the default — the text actually written isreplacement + "\n" + marker + recovery hint. So the projection-based figure omits the marker and the hint, and overstates by that much per candidate. Measured on the sweep's stocked fixture before it was corrected: 86,458 claimed against 86,201 actually sent, i.e. ~23 tokens per candidate.Both feed
metrics.RecordExtractionSaving/RecordExtractionValue, and both surface in/statsunderby_component, so the two arms of a comparison are no longer measuring the same thing.Why the gap matters more than its size
It is systematic, not noise: a fixed per-candidate overhead in one component and not the other, so it scales with the number of removals rather than averaging out. A configuration that removes more looks disproportionately better under the projection-based figure.
That matters specifically because
extract_llm's savings figure is what iteration 024's re-run will be judged on. Anyone reading the two arms side by side needs to know one is wire-measured and the other is not.The sweep is the correct one
content − MessageText(req.Input[i])after the splice is the number an operator can check against their bill: it is what the request actually shrank by.extract_llmshould move to the same basis.Why it was not fixed in #188
Deliberate, and the reasoning is worth keeping: #188's subject is reserve durability, and moving a published savings figure inside it would make the iteration-024 comparison unreadable for a reason unrelated to what that PR changed. A savings number should move in a change whose subject is the savings number — otherwise the re-run cannot separate "the mechanism got better" from "we started counting differently". The sweep's figure moved there only because a comment added in the same commit asserted it was the wire figure, which made it wrong rather than merely inconsistent.
Suggested fix
Mirror the sweep: compute
savedin phase 3 from the spliced message rather than carrying the projection-only delta out ofrunCall.out[k].savedalready exists for that purpose, so it is a one-line change plus its test.Note the same question applies to the replay paths, which credit
content − cached.Projectedat the repeat rate — also projection-only.Sequencing
Worth landing after the iteration-024 re-run, or as an explicit note beside its results, so the re-run's numbers stay comparable to the ones already published. Otherwise a savings change lands in the middle of the comparison it would invalidate.