ADR-NNN: Contested is a claim about specific other work, so it must name it
Context
ADR-015 added a second axis so the record could distinguish we are not
convinced from the field is not convinced. It works: ten practices are
assessed, and SOTA-136 reads Proposed, contested where it used to read
Proposed and nothing else.
Follow that word, though. A reader who clicks In dispute from the
practices index lands on docs/practices/consensus/contested.md, whose
columns are # | Title | Summary | Status. It names two practices and tells
you nothing about the dispute. The field that holds the reason,
consensus_note:, appears in no generated view at all — grep -rl consensus_note docs/ returns nothing — and the codes inside it sit bare:
consensus_note: >-
Two independent groups attacked the doubly-stochastic constraint within
a month of each other, by different arguments and with opposite
remedies ([LIT-151](../literature.d/LIT-151.md), [LIT-181](../literature.d/LIT-181.md)), while it ships at 1.6T in DeepSeek-V4.
Those two facts are one fact. Luria’s list of frontmatter keys whose codes get
linked is a constant, and the comment above it says why: “a key is prose
exactly when the generator renders its value as markdown somewhere… a project
cannot make a field prose by declaring it so, because the rendering is what
makes it true.” consensus_note: is not rendered, so it is correctly not
prose, so its codes are correctly left bare. Nothing is broken upstream. The
record simply put its answer somewhere nothing reads.
What actually directs the reader today is body prose, and only that. SOTA-136’s body links LIT-151 and LIT-181 and says what each one proves; SOTA-130’s links LIT-167. That is good writing and it is entirely voluntary — nothing requires it, nothing checks it, and no run would notice a contested practice whose body named nobody.
The two relations that come close mean something else.
compared_against: on SOTA-136 names SOTA-133, which is an alternative design
sitting at Active, emerging — a rival, not an objector. And LIT-140, the
source SOTA-136 rests on, carries extended_by: [LIT-151, LIT-181]: those
are the contesting papers, and this is the one place the dispute is
machine-readable. But the relation is spelled “extends”, so a paper refuting
the doubly-stochastic constraint and a paper building on it are stored
identically, and the path runs two hops through source: onto the other
scheme. For SOTA-130 it does not exist at all: LIT-130 carries no relation
naming LIT-167, which is reachable only from prose in two unrelated notes.
Decision
A practice assessed as contested names what contests it.
[luria.schemes.SOTA.references]
contested_by = { scheme = "LIT", required = false, many = true,
required_when = { consensus = ["contested"] } }
The load-bearing observation is narrower than “annotate the consensus axis”:
contested is the only value on the axis that entails a specific other
document. unassessed names nobody by definition. converged and
universal are readings of a population, not citations. unreplicated
asserts the absence of the second document. Only contested — “credible
groups publicly disagree, now” — is a claim about work that exists and
could be pointed at. So the requirement attaches to the one word that already
implied it, rather than to the axis.
That makes this the same rule as source:, deliberately. source: is the
evidence for; contested_by: is the evidence against; and a recommendation
asserting a dispute it cannot cite is the same failure as a recommendation
with no paper behind it (ADR-010). It points at LIT for the same reason:
what contests a recommendation is a paper, and both cases here are papers.
No converse. Luria’s converse is a mutual pair of fields within one scheme, and this crosses SOTA→LIT, so one is not expressible. That is the right shape anyway — “the practices this paper undercuts” is a fact about this record’s editorial reading, not about the paper.
The note keeps the argument; the field carries the citation.
consensus_note: says how they disagree — “by different arguments and with
opposite remedies” is not recoverable from a list of codes — and stays prose.
The field says who, and is checked.
Fired on real cases before being trusted. Three deliberate breakages, all caught:
- the field removed from both contested practices →
no
contested_by:in frontmatter … becauseconsensus: contested - a code naming nothing → resolves to no LIT document
- a code from the wrong scheme → is not a LIT code — a SOTA document’s
contested_bynames a LIT document
The second and third are what many = true plus a declared scheme buy over
requires = ["contested_by"], which would accept any truthy value.
Alternatives considered
-
Leave it in body prose. The status quo, and it currently works — for two documents, maintained by one person, with the context loaded. It costs nothing right up until a contested practice is filed without its opposition named, and there is no run that would say so. This record adopted a lint to stop precisely this class of silence: a practice with no source, an attic pointing at papers not in the corpus. Same class.
-
Make
consensus_note:a prose key, so its codes link. The tempting one, and upstream is right to refuse it.PROSE_KEYSis a constant so that a project cannot declare a field prose; the honest fix in that direction is to render the note, which is a Luria change and a different decision. It also would not do this job: prose is not checkable, so a note naming the wrong code, or none, would still pass. -
Widen
compared_against:to cover it. Rejected — rivalry is not dispute. SOTA-133 is a real alternative to SOTA-136 that nobody is arguing about, and collapsing “here is another way” into “here is someone saying you are wrong” discards the distinction ADR-015 was written to draw. It is the same error as answering that decision with more statuses. -
Derive it from the literature graph — walk
source:thenextended_by:. Rejected for the reason ADR-014 and ADR-015 both give: it is a count wearing a relation’s clothes. LIT-140’sextended_by:would hold a refutation and a continuation with nothing to tell them apart, and for SOTA-130 the edge does not exist. -
Put
contests:onLITinstead, pointing at practices. Rejected on ADR-015’s own ground: the axis belongs where the claim lives. No paper is written against a recommendation in this record; the judgement that it undercuts one is ours, and belongs on our document.
Consequences
Two practices gained the field and 142 did not, which is the conditional
requirement working: most of the corpus is unassessed, and nothing is asked
of it.
Assessing a practice as contested now costs a citation. That is the intended price, and it is the cheapest available check on the risk ADR-015 names as its own worst: “a consensus value ages with nothing to trigger a re-read.” A named opposition is at least something a re-reader can go and look at.
docs/record.md gained the rule in the generated field list — contested_by
— required when consensus is contested — so the obligation is documented
where the other field rules already are, without anyone writing it twice.
Checked is not the same as rendered, and only the first half is done here.
docs/practices/consensus/contested.md still lists # | Title | Summary | Status, so a reader following “In dispute” still learns who only by opening
the document. What changed is that the fact is now structural, verified, and
impossible to leave out — which is also what makes the other half tractable,
since the data a value page would need is now guaranteed present rather than
optional prose. Rendering it is Luria’s, and is filed there as dmarx/luria#193.