Contract review
The failure this prevents: a reviewer asks “can they subcontract without consent?”, the model produces a fluent paragraph, and no clause in the agreement actually says it. The answer looks identical to a correct one.
-
Ingest the agreement set. PDFs keep their page number, so every later citation lands on a page a human can open and check.
for path in ["msa.pdf", "sow-2026.pdf", "dpa.pdf"]:rag.ingest(path) -
Ask in the reviewer’s own words.
response = rag.ask("May the supplier subcontract without our written consent?") -
Read the decision before the prose. The answer text is the last thing you should trust; the decision and the citation are the first.
from citenexus.answer.result import Decisionif response.evidence.decision is Decision.answered:src = response.sources[0]print(response.answer) # verbatim from the contractprint(src.document, "p.", src.page)else:print("no clause supports this:", response.answer)
The Supplier shall not subcontract any part of the Services without the priorwritten consent of the Customer.msa.pdf p. 14package main
import ( "fmt"
"github.com/muthuishere/citenexus/golang/answer")
func main() { clauses := []answer.Doc{ {DocumentID: "msa", Text: "The Supplier shall not subcontract any part of the Services without the prior written consent of the Customer."}, {DocumentID: "dpa", Text: "The Processor shall notify the Controller without undue delay after becoming aware of a personal data breach."}, }
res := answer.Ask(clauses, "May the supplier subcontract without our written consent?", answer.DefaultTopK) if res.Evidence.Decision == "answered" { fmt.Println(res.Answer) fmt.Println(res.Sources[0].Document, "page:", res.Sources[0].Page) // page is nil }
// No clause covers this, so the flow refuses and cites nothing. miss := answer.Ask(clauses, "What is the liability cap for consequential damages?", answer.DefaultTopK) fmt.Println(miss.Evidence.Decision, "|", miss.Answer, "| sources:", len(miss.Sources))}The Supplier shall not subcontract any part of the Services without the prior written consent of the Customer.msa page: <nil>refused | I can't answer that from the available evidence. | sources: 0The difference: there is no PDF ingest, so there is no page number. Go has no
extractor and no storage — you supply the clause text, and Sources[0].Page is
always nil. The outcome that matters is identical: the verbatim clause with its
document, or the pinned refusal with zero sources.
import { ask } from "@muthuishere/citenexus"
const clauses = [ { document_id: "msa", text: "The Supplier shall not subcontract any part of the Services without the prior written consent of the Customer." }, { document_id: "dpa", text: "The Processor shall notify the Controller without undue delay after becoming aware of a personal data breach." },]
const res = ask(clauses, "May the supplier subcontract without our written consent?")if (res.evidence.decision === "answered") { console.log(res.answer) console.log(res.sources[0].document, "page:", res.sources[0].page) // page is null}
// No clause covers this, so the flow refuses and cites nothing.const miss = ask(clauses, "What is the liability cap for consequential damages?")console.log(miss.evidence.decision, "|", miss.answer, "| sources:", miss.sources.length)The Supplier shall not subcontract any part of the Services without the prior written consent of the Customer.msa page: nullrefused | I can't answer that from the available evidence. | sources: 0The difference: no PDF ingest, therefore no page number — sources[0].page is
always null. You supply the clause text; the cite-or-abstain outcome is the
same one Python returns.
Why the quote is not a paraphrase
Section titled “Why the quote is not a paraphrase”The quoted sentence in every tab above is verbatim from the source, not a paraphrase. That is deliberate: a paraphrased quote is no longer evidence, and a reviewer who cannot diff the quote against the page cannot defend the answer.
Reading the signals
Section titled “Reading the signals”The signal names are the same in all three — EvidenceSignals is one of the
conformance-pinned shapes, so a reviewer reads the same four fields whichever
port produced the Result.
sig = response.evidencesig.decision # answered | refused | partialsig.distinct_documents # how many DIFFERENT documents support thissig.unsupported_claims_removed # sentences dropped for lacking supportsig.all_claims_verified # False means the answer was trimmedsig := res.Evidencefmt.Println(sig.Decision) // answered | refused | partialfmt.Println(sig.DistinctDocuments) // how many DIFFERENT documents support thisfmt.Println(sig.UnsupportedClaimsRemoved) // claims dropped for lacking supportfmt.Println(sig.AllClaimsVerified) // false means the answer was trimmedanswered10trueconst sig = res.evidenceconsole.log(sig.decision) // answered | refused | partialconsole.log(sig.distinct_documents) // how many DIFFERENT documents support thisconsole.log(sig.unsupported_claims_removed) // claims dropped for lacking supportconsole.log(sig.all_claims_verified) // false means the answer was trimmedanswered10trueunsupported_claims_removed is the one reviewers care about most. An answer is
verified per atomic claim: if the model produces two sentences and only one
is supported by the cited clause, you get the supported sentence and a count of
what was dropped — not a fluent paragraph that is 50% invented.
Scoping to one matter
Section titled “Scoping to one matter”Isolation between matters comes from the partition, and from nothing else. A
CiteNexus instance is bound to one PartitionPath at construction; its vector
index, manifests and evidence all live under that leaf, so a question asked on
one matter’s client cannot reach another matter’s paper.
from citenexus import CiteNexusfrom citenexus.domain.partition import PartitionPath
matter = CiteNexus( "s3://firm-corpus", partition=PartitionPath.of(("matter", "4471")), signals=["embedding", "text"],)matter.ingest("msa.pdf")Go has no partition, no storage layer and no acl field — there is nothing
to isolate, because the port never holds your corpus. The []answer.Doc slice
you pass to Ask is the scope: build it from the one matter the caller is
entitled to, and the isolation is your slice.
JavaScript has no partition, no storage layer and no acl field — same
reason as Go: the corpus is the array you pass in. Scoping a question to one
matter means passing only that matter’s documents.
One client per matter. Route the request to the instance whose partition the caller is entitled to, and the entitlement check stays in your application — where it can see your identity system.
See Access & partitions for the full contract, including what the library deliberately does not enforce for you.
When the wrong paper is cited
Section titled “When the wrong paper is cited”A clause quoted verbatim from a superseded draft, or from the counterparty’s template instead of the executed MSA, passes the gate — the words really are there. Rank the versions at ingest and let strict mode refuse below the floor: see Authority — grounding is not standing.
Where this goes wrong
Section titled “Where this goes wrong”- A clause split across a page break. Chunking respects structure, but a
clause whose operative sentence straddles pages can be cited to the page
holding the sentence, not the clause heading. Check
src.pageagainst the clause number in the quote. - Definitions. “Services” may be defined 40 pages earlier. The answer cites where the obligation is stated, not where its terms are defined — ask the definition as its own question.