eval(attribution): #887 measure the context-size regime the probe never entered - #897
Merged
Merged
Conversation
…er entered `evals/query_attribution` measured `es-long` at 30/30, and then both wild Spanish long answers dropped the `USED:` line. Its documents are constructed concepts, median 170 chars, max 1,656; the wild retrieval set held two `Source` documents of 55,403 and 57,116 chars. #871 closed the ANSWER-length regime and left the CONTEXT-length one open. A third axis now crosses the other two: `context` in (small, large). The large rung swaps the three `sources/*` bodies -- and only those -- for full-length transcripts of the same meetings, so the knowledge and the question set are held constant. Every row carries the MEASURED `prompt_eval_count`, captured off the response the production client already receives. Measured on qwen3:8b, two pooled 3-run sweeps, n=30 per cell, 240 answers, 0 failures, 0 no-matches: cell small large es-short 1.00 1.00 es-long 0.93 0.97 en-short 0.80 0.87 en-long 0.80 1.00 rung 0.883 0.958 prompt tokens (median) 777 -> 2348 context sent (median) 3,184 -> 9,704 chars The context-size hypothesis is REFUTED and the direction is the opposite of the report's: three times the prompt with most of the retrieval set clipped away, and no cell loses ground. Post-#882 the size regime is not where this defect lives; the non-reported answers stay question-shaped, as #871 found. What did break in the wild is the UNBOUNDED prompt, and `--unbounded` reproduces it: 26,671 chars sent, `prompt_eval_count` pinned at 2,050, compliance 0.21 (es, n=28) and 0.22 (en, n=9), and the conservative fallback citing 4.68 of 5 blocks the model never read. llama.cpp keeps head tokens plus the last half of the window, so the system prompt -- the first message, where the `USED:` instruction lives -- is exactly what is discarded. That answers the question #887 left open. Also in this change: - `_write_corpus` now renders frontmatter with the shipped `okf.dump_frontmatter`. The f-string it replaces interpolated the title unquoted, so the four `Decisión: ...` documents were invalid YAML, counted `skipped` by reindex, and absent from every run including the stored 2026-08-25 ones. The probe measured ten documents while documenting fourteen. `--self-test` now asks the shipped reader whether every materialized document parses. Three other harnesses still carry it: #895. - `--context-window` / `--max-generation-tokens` pins, and a `chars/ptok` column that makes silent truncation visible: 4.13 when the prompt is read, 13.01 when two thirds are discarded. - `--self-test` pins the excerpt's convergence (shape identical from 8x to 64x document size) and the authored rung's drift from it, so ~8 KB transcripts can speak for the wild 55 KB case with a stated margin. A bounded arm at num_ctx 4096 returned 60 of 60 no-matches with every block omitted, which is not a result about attribution: `OllamaClient` never exposes `max_generation_tokens`, so `prompt_budget.reply_reserve` always falls back to 8192 and the budget floors to zero below the default ceiling. Filed as #896; its emission is kept as evidence. Review receipt review-d897719acc9056c9, APPROVED, no correction consumed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
evals/query_attributionmeasuredes-longat 30/30, and then both wildSpanish long answers dropped the
USED:line. Its documents are constructedconcepts, median 170 chars, max 1,656; the wild retrieval set held two
Sourcedocuments of 55,403 and 57,116 chars. #871 closed the ANSWER-length regime and
left the CONTEXT-length one open — the same methodological miss, one level up.
This adds the missing axis, measures it, and refutes the issue's hypothesis.
Related issue
Closes #887
Type of change
test— measurement harness only; no shipped code changesWhat was measured
qwen3:8b, two pooled 3-run sweeps, n=30 per cell, 240 answers, 0 failures and0 no-matches. Arm
baseline(production untouched), identical pins in both.smalllargees-shortes-longen-shorten-longsmalllargeThree times the prompt, most of the retrieval set clipped away, 8–9 elision
markers — and no cell loses ground. Post-#882 the size regime is not where this
defect lives. The non-reported answers stay question-shaped, exactly as #871
found.
What actually broke in the wild
#887 named the missing evidence precisely: "proving that needs to know where
the cut falls relative to the attribution instruction."
--unboundedsends it.nomatchprompt_eval_countpinned at 2,050 whilesent_charsclimbs to 26,671 is thetruncation itself. llama.cpp keeps head tokens plus the last half of the
window; the system prompt is the FIRST message and is where the
USED:instruction lives, so under overflow the model is never told to emit the line.
nomatchis 0, so this is not a groundedness collapse — the model answered atlength and the conservative fallback then cited 4.68 of 5 blocks it never
read, which is #882's false-provenance defect reproduced.
Two qualifications are in the README: the unbounded rate is an over-estimate
(two capped generations were dropped, and a capped reply cannot reach its
closing line), and the arms are not at matched pins because of #896 below.
Changes
evals/query_attribution/attribution_large_sources.pyevals/query_attribution/attribution_corpus.pyCONTEXTSaxis,DOCS_BY_CONTEXT_LANGUAGE,DECISIVE_ANCHORS.evals/query_attribution/run_query_attribution_probe.pyprompt_eval_countper row;--context,--context-window,--max-generation-tokens,--unbounded;chars/ptoktruncation column; frontmatter fix; extended--self-test.evals/query_attribution/README.mdevals/query_attribution/results/*Two defects found while doing this
#895 (P2) —
_write_corpushand-rolled its frontmatter and interpolated thetitle unquoted, so the four
Decisión: ...documents were invalid YAML,counted
skippedbyreindex, and absent from every run including thestored 2026-08-25 ones. The probe measured ten documents while documenting
fourteen. Production was never affected (
okf.dump_frontmatterquotescorrectly); the harness had a second renderer beside the shipped one. Fixed
here;
query_citation,query_entailmentandquery_sufficiencystill carryit. This is why Part 1's numbers and Part 2's are not comparable.
#896 (P1) — a bounded arm at
num_ctx 4096returned 60 of 60 no-matcheswith every block omitted.
OllamaClientnever exposesmax_generation_tokens, soprompt_budget.reply_reservealways falls back to8192; any workspace that lowers the ceiling gets budget zero and
queryanswers NO_MATCH on a full bundle. Its emission is kept as evidence.
How was this tested
uv run pytest -q— 5761 passed, 1 skippeduv run ruff check ./ruff format --check ./uv run mypy .— cleanuv run python evals/run_self_tests.py— 36 of 36--self-testnow pins, for free and against the productionbound: the small rung is sent whole; the large rung is excerpted with every
decisive anchor surviving; the excerpt's shape converges from 8x to 64x
document size; the authored rung's drift from that converged prompt stays
under
_CONVERGENCE_MARGIN; and every materialized document parses.demotion positions; the indexability check names all four dropped documents
when the old writer is restored; the convergence check refuted two earlier,
stronger wordings of its own claim before settling on the true one.
Notes for reviewers
Two things I would push back on if I were reviewing:
larger without its content changing.
largemeans "a full-lengthSourcedocument of the same meeting" — what the wild retrieval set held — not "the
same text, longer". Knowledge and question set are held constant; the prose
around them is not, and no design could hold it constant. Stated in the
README.
chunk_linespacks greedily from the start, so only window 0 is a guaranteedsurvivor; a pre-flight showed two of three closing-recap anchors excerpted
away. Without a surviving statement of the decisions the large cells collapse
into refusals and the probe measures groundedness under the name of
attribution.
Review receipt
review-d897719acc9056c9, APPROVED, no correction consumed.Both reviewer findings were WARNING and are adjudicated in the captured
evidence: the table-separator one is refuted (both rows carry six columns;
it also named the wrong lines), and the
_chars_per_tokenone is accurate butits implied remedy would introduce a
ZeroDivisionError— the truthy filterguards
prompt_tokens == 0.