Authority — grounding is not standing
A Florida statute can be quoted perfectly verbatim and still be the wrong law for a Texas question — and the faithfulness gate passes it, because the words really are in the passage. Grounding proves the words came from the source. It says nothing about whether that source governs.
That is not a bug in the gate; it is the limit of what a gate can prove. Closing it needs a second, separate signal: the standing of the source.
Authority is metadata, never content
Section titled “Authority is metadata, never content”A California statute’s body text never says “California.” Jurisdiction,
precedential weight and publisher standing are properties asserted by whoever
curated the corpus — they are not recoverable from the prose. So the seam is
Mapping[str, str] -> AuthorityTier: a profile is handed metadata and never a
passage, and therefore cannot read content.
Two content-derived alternatives were measured and rejected before this shape was chosen: a query-term relevance floor (fixed 2 failures, broke 3) and a token-coverage threshold (the bad answers scored inside the good range). See ADR-0004.
Policy and profiles
Section titled “Policy and profiles”AuthorityPolicy binds a profile to an optional minimum tier — the floor:
from citenexus.domain.authority import AuthorityPolicy
policy = AuthorityPolicy.unranked() # default.v1, no floor — today's behaviour
policy = AuthorityPolicy.ordered( # ordered.v1, floored ( "out-of-jurisdiction", "secondary-blog", "general-statute", "statute", "binding-appellate", "controlling-statute", ), # LEAST-authoritative first minimum_tier="general-statute",)| Profile | profile_version |
Behaviour |
|---|---|---|
DefaultAuthorityProfile |
default.v1 |
Every source gets UNRANKED (rank 0). All ranks equal ⇒ the stable sort is the identity ⇒ fusion order survives ⇒ existing Results are unchanged. |
OrderedTierProfile |
ordered.v1 |
Rank = index in the caller-supplied order tuple, read from the metadata key authority_tier (override with key=). A name absent from order — including missing metadata — ranks UNKNOWN_RANK (-1), below every named tier. |
An AuthorityTier is rank: int plus a reporting-only name: str. name is
deliberately excluded from comparison: two profiles that disagree on naming
must still produce one total order, and comparing names would make authority
depend on spelling.
The same thing declaratively, via AuthorityConfig:
from citenexus import CiteNexusfrom citenexus.config.schema import AuthorityConfig, CiteNexusConfig, StorageConfig
config = CiteNexusConfig( storage=StorageConfig(bucket="./citenexus-data"), authority=AuthorityConfig( profile="ordered.v1", tier_order=("out-of-jurisdiction", "secondary-blog", "general-statute", "statute", "binding-appellate", "controlling-statute"), minimum_tier="general-statute", # metadata_key="authority_tier", # the default ),)rag = CiteNexus.from_config(config)Attaching authority at ingest
Section titled “Attaching authority at ingest”ingest() takes authority= — opaque caller-supplied key/value metadata, the
same posture as acl, except that it is persisted on the Evidence Unit rows
(as the additive authority_meta column) because selection happens at read time.
crawl() takes the same keyword, and a URL passed to ingest() carries it
through the fetch.
-
Curate the standing of each document. A CSV next to the corpus is enough — this is the curator’s assertion, not something the library derives:
document_id,authority_tier,authority_rank,label01-ca-civ-1946_1-statute,controlling-statute,1,CA Civil Code 1946.1 — controlling statute05-nolo-month-to-month-blog,secondary-blog,5,Nolo self-help summary (non-binding)06-florida-83_57-statute,out-of-jurisdiction,9,Fla. Stat. 83.57 — wrong state -
Hand it to
ingest()as metadata.import csvfrom pathlib import Pathwith Path("authority.csv").open(newline="", encoding="utf-8") as fh:authority = {row["document_id"]: row for row in csv.DictReader(fh)}for path in Path("corpus").glob("*.txt"):row = authority.get(path.stem, {})rag.ingest(path,document_id=path.stem,authority={"authority_tier": row.get("authority_tier", ""),"authority_rank": row.get("authority_rank", ""),},) -
Ask in strict mode. The floor is enforced between grounding and generation; nothing else about
ask()changes.response = rag.ask("What is the notice period to end a month-to-month tenancy in Texas?")
Omit authority= and the document is unranked — exactly the pre-feature
behaviour.
Where it applies: after grounding, never inside it
Section titled “Where it applies: after grounding, never inside it”retrieve → fuse → rerank → grounded candidates (faithfulness, unchanged) → select_by_authority(grounded, policy, mode) (the ONE authority function) → generate → per-claim faithfulness gate (unchanged)select_by_authority() can only ever reorder or remove candidates that
grounding already admitted. It cannot promote anything grounding rejected, so the
only reachable behaviour change is more abstention — it is structurally
incapable of admitting an ungrounded claim. No authority module imports the
faithfulness predicate, and the predicate never sees a tier.
TrustMode coupling
Section titled “TrustMode coupling”TrustMode |
What authority does |
|---|---|
strict |
Enforces the floor. Every candidate below minimum is dropped outright — no fallback to a lower tier — then the survivors are stably sorted by tier descending. If nothing survives, the answer is a refusal with the reason "no evidence at or above the required authority tier". |
normal |
Tie-break only. A stable sort by descending tier; nothing is dropped. |
exploratory |
Ignored entirely. The candidates are returned untouched. |
The refusal reason is deliberately distinct from “no sufficiently relevant evidence found”: conflating “I found nothing” with “what I found has no standing” is exactly how an out-of-jurisdiction citation stayed invisible behind 100% groundedness.
The signals
Section titled “The signals”Two additive fields on EvidenceSignals — modelled on unsupported_scripts,
which established that a standing/capability signal is not an evidence
judgement:
sig = response.evidencesig.authority_tier # str — the WEAKEST cited tier name ("" when unranked)sig.authority_floor_applied # bool — the floor WITHHELD grounded evidence on this callauthority_floor_applied is not “a floor was configured” — a signal that is true
on every strict call tells you nothing. It means “I had evidence and declined to
cite it for lack of standing.” It is also how you tell this refusal apart from
the five others: see Why did it abstain?.
Both fields are additive: no existing field on EvidenceSignals changed meaning
or type, and both are empty on every Result from an unranked corpus.
Measured on the law benchmark
Section titled “Measured on the law benchmark”From the live run in
examples/law-authority/
(real Jina embeddings + reranker, real Gemini generation, nothing mocked):
The baseline column is v0.10.0 pre-floor — the same code as the right-hand column with the floor switched off, not the older v0.9.0 run that the law benchmark also reports:
| metric | v0.10.0 pre-floor | v0.10.0 post-floor |
|---|---|---|
| out-of-jurisdiction citations | 4 | 0 |
abstain_when_no_evidence |
33% | 100% |
groundedness_rate / citation_rate |
100% | 100% |
The Texas question — previously answered “not less than 30 days’ notice” from a
Florida statute with all_claims_verified: True — is now a refusal. That is
the trade the floor buys: strictly stronger abstention, never a weaker one.
What the floor does not fix
Section titled “What the floor does not fix”Also out of scope today: model-derived authority classification and authority-aware conflict resolution.