Wrong subject, right source
The failure this does NOT yet prevent. This page documents a known open gap, not a feature. Read it before you put CiteNexus in front of anyone who will act on an answer without reading the cited passage in full.
Here is the failure, from the live law benchmark:
Q “How much notice must a landlord give to terminate a fixed five-year commercial lease with a specified term in California?” A “at least 60 days prior to the proposed date of termination” — citing
01-ca-civ-1946_1-statute, tiercontrolling-statute.
That answer is wrong, and every guard in the library passed it, correctly:
| guard | verdict | and it was right |
|---|---|---|
| faithfulness gate | supported | those words are verbatim in that passage |
| authority floor | admitted | nothing outranks a controlling statute |
| conflict detection | no conflict | no other source contradicts it |
§ 1946.1 is the right authority. It is simply about a different kind of tenancy — a periodic tenancy with no specified term, not a fixed five-year commercial lease. Grounding proves provenance. Authority adds standing. Neither is applicability.
Why authority cannot be stretched to cover it
Section titled “Why authority cannot be stretched to cover it”An authority floor is an ordering over sources, and it withholds what falls below a bar. The wrong-subject source here sits at the top of the ordering — it is the most authoritative document in the corpus. No floor can exclude the top of its own ordering. Raising the bar higher excludes everything else and still admits this.
That is the structural reason, and it is not a tuning problem. Two content-derived alternatives were measured on this corpus and both failed:
- a query-term relevance floor — fixed 2 cases, broke 3;
- a content-token coverage threshold — the two known-bad pairings score
0.31and0.83against a good range of0.29–0.80. One sits inside the good range, the other above every good pairing. The signal is not weak, it is anti-correlated.
The general form: the wrong-scope passage is genuinely the most topically relevant passage in the corpus. It is supposed to score high. So no monotone function of topical relevance — rerank score, fusion score, coverage, distinct document count — separates it, by construction.
The root cause: applicability severance
Section titled “The root cause: applicability severance”The scope information is not missing from the corpus. It is severed from the rule it governs by chunking.
Extraction emits one paragraph per block and each block is chunked independently, so one statutory subdivision becomes one Evidence Unit:
01-ca-civ-1946_1-statute::2::0 "(a) … a hiring of residential real property or commercial real property by a qualified commercial tenant FOR A TERM NOT SPECIFIED BY THE PARTIES …" <- the precondition
01-ca-civ-1946_1-statute::3::0 "… shall give notice at least 60 days prior to the proposed date of termination." <- the operative ruleRetrieval selected ::3::0. The gate saw ::3::0. The generator saw ::3::0.
Nothing in the pipeline ever saw the sentence saying this rule does not apply to
a lease with a specified term.
That is not a Python defect — it is what chunk-local verification does in every implementation. The same corpus produces the same wrong-scope answer in all three, which is the clearest way to show the gap is structural and that no port closes it:
The failure above is from the live law benchmark; the shape reduces to two
Evidence Units, one holding the precondition and one holding the rule. ask()
selects the rule, the gate passes it verbatim, and the precondition is never in
front of anything.
rag.ingest(text="(a) A hiring of residential real property for a term not " "specified by the parties is deemed renewed as stated in " "Section 1945.", document_id="ca-civ-1946_1::2")rag.ingest(text="The owner shall give notice at least 60 days prior to the " "proposed date of termination.", document_id="ca-civ-1946_1::3")
response = rag.ask("How much notice must a landlord give to terminate a " "fixed five-year commercial lease?")print(response.evidence.decision) # answered — every guard passedprint(response.sources[0].document) # ca-civ-1946_1::3package main
import ( "fmt"
"github.com/muthuishere/citenexus/golang/answer")
func main() { // One statutory subdivision per Evidence Unit — the precondition and the // operative rule are in different units. corpus := []answer.Doc{ {DocumentID: "ca-civ-1946_1::2", Text: "(a) A hiring of residential real property for a term not specified by the parties is deemed renewed as stated in Section 1945."}, {DocumentID: "ca-civ-1946_1::3", Text: "The owner shall give notice at least 60 days prior to the proposed date of termination."}, }
res := answer.Ask(corpus, "How much notice must a landlord give to terminate a fixed five-year commercial lease?", answer.DefaultTopK)
fmt.Println(res.Evidence.Decision) // answered — every guard passed fmt.Println(res.Answer) // ...and the answer is out of scope fmt.Println(res.Sources[0].Document) // ca-civ-1946_1::3}answeredThe owner shall give notice at least 60 days prior to the proposed date of termination.ca-civ-1946_1::3Go has no authority tiers either (Evidence.AuthorityTier is always empty
here — selection lives in the Python facade), so mitigation 2 below is not
available in this port. Mitigation 1 — keeping the precondition and the rule in
the same Doc — is, and it is the one that actually works.
import { ask } from "@muthuishere/citenexus"
// One statutory subdivision per Evidence Unit — the precondition and the// operative rule are in different units.const corpus = [ { document_id: "ca-civ-1946_1::2", text: "(a) A hiring of residential real property for a term not specified by the parties is deemed renewed as stated in Section 1945." }, { document_id: "ca-civ-1946_1::3", text: "The owner shall give notice at least 60 days prior to the proposed date of termination." },]
const res = ask(corpus, "How much notice must a landlord give to terminate a fixed five-year commercial lease?")
console.log(res.evidence.decision) // answered — every guard passedconsole.log(res.answer) // ...and the answer is out of scopeconsole.log(res.sources[0].document) // ca-civ-1946_1::3answeredThe owner shall give notice at least 60 days prior to the proposed date of termination.ca-civ-1946_1::3JavaScript has no authority tiers (evidence.authority_tier is always "" —
selection is in the Python facade), so mitigation 2 below does not apply here.
Mitigation 1 — keeping the precondition and the rule in the same document — does,
and it is the one that actually works.
Measured over that corpus: 8 of 11 operative notice-period Evidence Units are citable in isolation from the precondition that governs them — a 73% applicability-severance rate. Five of the six documents state their term-scope in plain prose; one states it in its own title. The information is there, and every downstream guard is chunk-local by design.
What you can do about it today
Section titled “What you can do about it today”Nothing here closes the class. Each raises the cost of a wrong-scope answer.
-
Keep the whole applicability clause in one chunk. This is the highest-value move and it is free. If your documents have preconditions (“for a term not specified…”, “applies to entities with more than 50 employees”, “for patients over 12”), ingest them so the precondition and the operative rule land in the same Evidence Unit — larger blocks, or a section-aware pre-split rather than a paragraph-level one. A precondition the generator can see is a precondition it can be held to.
-
Encode scope you already know as authority metadata. Where the scope distinction is stable per document, it is a tier, and the authority floor already handles it. Splitting a corpus into
residential-*andcommercial-*tiers, and flooring per question class, is a deterministic, refusal-only filter you can ship now:rag.ingest(path, document_id=path.stem,authority={"authority_tier": "ca-residential-periodic"})No authority layer in this port.
Evidence.AuthorityTierandEvidence.AuthorityFloorAppliedare carried for wire parity and always empty / false — authority selection runs in Python’sask()facade. To floor by scope here, split the corpus yourself and pass only the tier the question belongs to.No authority layer in this port.
evidence.authority_tierandevidence.authority_floor_appliedare always""/false— selection runs in Python’s facade. Floor by scope by passingaskonly the subset of documents the question’s class is entitled to.This is exactly the ADR-0004 seam — a curator’s assertion turned into a deterministic input. It does not generalise to scope facts that vary within a document.
-
Read the citation, not just the answer. Every answer carries its verbatim passage, document and location precisely so a reviewer can check applicability themselves. In this failure the answer looks impeccable and the passage, read in context, does not support the question. That check is currently the human’s.
-
Score your own golden set for scope, not just for grounding.
groundedness_ratewas 100% on the run that produced the bad answer above. A metric that cannot fall when the answer is about the wrong subject will not warn you. Add abstain-expected rows for out-of-scope questions and track them separately — see Evaluate a corpus.
What is being built, and what it will honestly buy
Section titled “What is being built, and what it will honestly buy”ADR-0012 treats applicability the way ADR-0004 treated standing — asserted about a source, applied strictly after grounding, never derived from a relevance score, able only to withhold:
- Scope-context propagation (deterministic, default-on) — carry a document’s applicability clause onto every Evidence Unit derived from it, shown to the generator, excluded from the verbatim citation. Measured feasible with zero recall cost. It refuses nothing on its own; it makes the precondition visible to a check, a judge, or a human, where today it is invisible to all three.
- Declared scope facets + a refusal-only floor (deterministic, opt-in) — measured on the law corpus: 1/1 target case caught, 0/8 regressions… and 0/6 under paraphrase. Six rewordings of the same commercial-lease question that avoid the declared vocabulary all fail open. A closed vocabulary is per language, and clients do not phrase questions the way curators write lexicons.
- A model scope verdict as a recorded input to a deterministic rule — the only thing with a chance against those paraphrases, and it must never be sold as deterministic.
Related
Section titled “Related”- Authority — source standing — the floor that closed wrong jurisdiction, and why it cannot close wrong subject.
- Conflicting sources — the other class where a perfectly grounded answer is the wrong output.
- Worked example: law — the corpus and run these numbers come from.