{"path":"research/citations-in-the-passes.md","content":"# Citations in the passes: where the source's own characters could carry a link\n\n**Date:** 2026-10-23. **Standing:** one measurement, an inventory and proposals; nothing built in a\npass, nothing ruled.\n\n**His words.** On the comparison of going direct to Anthropic or through OpenRouter\n(`whose-tokens-pay-for-mapping.md` § 3h), where Citations was named as the one direct-only feature\nworth testing: *\"Excellent! Yeah try it.\"* Then, on its line *\"Citations returns the exact characters\nin the source behind each sentence, which is the claim-to-source link that extraction needs\"*:\n*\"Consider all places and all microtasks where we can use this to our advantage. Make sure caching\nworks excellently in all machine passes/calls. Excellent test coverage for all of that also.\"*\n\n## 0. In short\n\n- **What Citations is.** A document sent with `citations: {enabled: true}` comes back with each\n  sentence of the answer tied to the passage of the document it rests on: the passage's exact text\n  and its character offsets, produced by the API, not written by the model. Anthropic only; not\n  documented through OpenRouter.\n- **The test.** One call to Claude Haiku 5.5 listing the claims of the § 10 reference article\n  (`pass-quality-and-the-choice-of-model.md` § 10) with Citations on: 41 and 46 claims in two runs,\n  45 and 46 of the 46 hand-read passages reached, no near-duplicates, 5 and 7 claims leaning on their\n  context, 0.33 to 0.38 cents and about 20 seconds. The whole router extraction on the same model\n  reached 44 and 45 of 46 with 31 to 36 near-duplicates, for about 8.5 cents\n  (`scripts/try_citations.py`; runs in `data/model-comparison/`, gitignored).\n- **What the count does not say.** The one call lists claims; it finds no arguments, premises or\n  links, so its cost is not comparable with a whole extraction. A plain-text document is cut into\n  sentences, so every cited passage is a whole sentence, which makes \"reached\" easier than for the\n  hand reading's shorter quotes. Nine conditional claims read against their passages kept their\n  conditions, including the *\"Otherwise …\"* sentence that GPT-6 Luna turned into an assertion\n  (§ 10a of the comparison note); that is a reading of nine, not a measure.\n- **Two limits that shape every use.** Citations cannot be combined with structured output (a 400),\n  so a cited answer is prose the code parses, and the structured fields come from a second call or\n  the same call's text. The two runs wrote their claims in two shapes (a paraphrase with the source\n  sentence repeated after it, then a framing such as *\"The author claims that\"* followed by the\n  source's words), so the answer's shape must be pinned before any pass relies on it.\n- **The strongest use** is the one it was named for: the link from a claim to the characters it came\n  from, made by the API. Several other microtasks rest on that same link (§ 2).\n\n## 1. What a cited answer gives that a quoted one does not\n\nToday every pass that points into the source asks the model to copy a passage into a field\n(`source_span`, `thesis_quote`, `premise_quotes`), and code then looks for the copy in the text\n(`scripts/measure_quote_fidelity.py`). The copy can be wrong in ways code catches (not found: GLM\n5.3 quoted 57 % word for word, Gemini 3 Flash 97 %) and in ways it does not (found, but the wrong\nsentence for the claim). A cited answer removes the first class entirely: the passage is the\ndocument's own characters, with offsets, by construction. It does not remove the second, since the\nmodel still chooses which passage to cite.\n\nTwo consequences for the graph. A claim's span becomes an exact range in its source, so the map can\nunderline it and the drift check between a claim and its span (`signposts-for-the-whole-project.md`\n§ 3a, *The machine does not steer*) compares against characters, not against a model's copy. And the\nholder test (*Holders recognise their own claims*, same register) can show a holder the exact\nsentence each of their claims rests on.\n\n## 2. Every microtask that points into a text, and what Citations would change\n\nRead from the passes as built on 2026-10-23 (`deliberus/extraction/`, `deliberus/`), ordered by how\nmuch of the pass's job is the pointing.\n\n| Microtask | What it points at today | With Citations | Shape it needs |\n|---|---|---|---|\n| **Claim reading** (decompose, then decontextualise, `focused.py`) | `source_span` copied per atom | the span is the cited passage; the copy and its check go | one cited call per argument or per source, then the classifying fields |\n| **Finding the arguments** (`scout.py`) | `thesis_quote`, `premise_quotes`, `text_start`/`text_end` copied | each argument's thesis and premises cited; its extent from the first and last cited offsets | cited call, then the form |\n| **Reported speech** (`reported_speech.py`) | which claims are someone else's, with who | the cited passage shows the reporting verb and the speaker together | cited call per claim or per source |\n| **Attribution** (`attribution.py`) | who speaks in a source | the passage naming the speaker is cited, so a wrong attribution shows its evidence | cited call |\n| **Content dates** (`temporal_extraction.py`) | the dates a source's content refers to | each date with the sentence it was read from | cited call |\n| **Contested concepts** (`contested_concepts.py`) | terms used in more than one sense | each sense with the passages using it, which is what a reader needs to see the two senses | cited call over the source |\n| **Self-evaluation** (`self_eval.py`) | which claims misread the source | each flag with the passage the claim misreads | cited call over the source and the claims |\n| **Unstated premises** (`implicit_premises.py`) | nothing: a premise is unstated | the stated sentences the gap lies between, cited, so a reader sees what the premise bridges | cited call; the premise itself stays uncited |\n| **Critical questions** (`cq_generation.py`) | slot values filled from the claims | values cited from the source where it answers them, marked unanswered where it does not | cited call over the source |\n| **Pair judgements across sources** (keeper, relevance judge) | two claims' texts | with both sources as documents, the verdict cites the passage of each source it rests on, so a person reviewing it reads two sentences, not two sources | two documents per call; dearer per pair, so for the pairs a person reviews |\n\nThe last row is where Citations would lower the draw on his attention most directly: a verdict that\ncarries the two passages it rests on is checked in seconds. In the flywheel terms of\n`flywheels-in-building-deliberus.md` § 3, it makes his review cheaper, which raises the pace the\nstanding passes may run at.\n\n## 3. What it costs and where it can run\n\n- **Price.** Input as usual; the document counts once. On the test, one cited listing of a\n  1,935-word source cost 0.33 to 0.38 cents on Claude Haiku 5.5 with effort low.\n- **Caching.** A document block is part of the prompt's opening and caches like any other turn.\n  Measured the same night, on Anthropic the answer form is part of the cached opening\n  (`whose-tokens-pay-for-mapping.md` § 3h), so structured passes cannot share one cached source;\n  a cited call sends no form, so cited passes on one source should share it (inferred, untested).\n- **Batch.** A cited call needs no tool loop, so it fits the half-price batch.\n- **Where.** Anthropic only, so it needs the engine's direct line (built 2026-10-23,\n  `deliberus/extraction/anthropic_direct.py`); through OpenRouter it is not documented.\n\n## 4. Proposals, in order (Claude's, unruled)\n\n1. **Pin the shape of a cited claim list first**: one claim per line, the claim in the author's\n   words, attribution in its own field rather than a *\"The author claims that\"* frame, then measure\n   the same two counts on two more sources of other kinds (a news report, a policy paper), against\n   hand readings. One pass at a time, as his order says.\n2. **Then try Citations where pointing is the whole job**: claim reading's spans and the scout's\n   quotes, as a cited first call followed by today's classifying call, and compare with the router\n   run on the same sources (quotes found, reached, duplicates, faults read by hand).\n3. **For the pairs he reviews**, a cited variant of the pair judgement, so each verdict he reads\n   shows its two passages.\n4. Not proposed: switching extraction wholesale. The comparison note's finding stands, that a cheap\n   model copying every sentence is not yet a better map (§ 10a).\n\n## Sources\n\nThe Claude API reference bundled with Claude Code 2.1.308 (cached 2026-10-06): Citations,\nstructured output and its JSON Schema limits, prompt caching. The runs:\n`scripts/try_citations.py`, `scripts/score_extraction_run.py`, `data/model-comparison/` (gitignored:\nthe claims render other people's words). Cross-references: `whose-tokens-pay-for-mapping.md` § 3h ·\n`pass-quality-and-the-choice-of-model.md` § 10 · `flywheels-in-building-deliberus.md` § 3 ·\n`signposts-for-the-whole-project.md` § 3.\n"}