cadrumo.adapters.outbound.llm.evidence_draft_text module¶
Semantic invoice-field extraction from a document’s TEXT representation.
Reading a rendered document is two questions, not one. The vision reader once answered them together, handing rasterised pages to a model and taking back typed fields in a single call – so when the result was wrong there was no way to tell a transcription error from a reasoning error, and a perfect transcription obtained by any other means had nowhere to go.
This module is the second stage that made splitting them possible: text in,
grounded InvoiceDraft out. Both acquisition lanes
now feed it – the deterministic text-layer extractor and
LocalVisionDocumentTranscriber, which transcribes and interprets
nothing. Splitting it out means the
transcription stage can be swapped, measured or replaced independently of the
understanding stage, and it makes any already-transcribed text – a PDF text
layer, an OCR result, an EN16931 payload rendered back to prose – usable.
Defaults to LOCAL, like the vision reader. This paragraph previously said the opposite – that the reader took whatever provider the caller had configured, because “the sensitive-data posture is owned by the calling flow’s consent gate, not by this primitive”. That reasoning was sound and the premise was false: no such consent gate had been built, while the shipped provider default is a cloud vendor. The two together meant reading a taxpayer’s invoice sent the document’s text off-host by configuration alone, with nothing at the call site expressing that choice.
The default is therefore stated here rather than inherited. An off-host read stays possible – the measurement corpus is public, synthetic and explicitly sanctioned for it – but requires naming BOTH the provider and the model, which makes it a deliberate act at the call site instead of a property of the environment. A named provider with no model refuses, mirroring the vision reader’s guard.
This is a floor, not the consent gate. The gate itself is
LLMClient’s per-invocation evidence-consent check, applied at
the client’s dispatch choke point where no caller can reach around it by
constructing a request directly: this reader marks every request it builds as
evidence-derived unless the caller names the public corpus, and an off-host
dispatch of a marked request without a per-invocation consent token refuses.
Language-neutral by design. The vision prompt opens “a scanned Spanish
invoice”; invoices reaching this path are international, in arbitrary languages
and layouts, so the prompt names field concepts and lets the model find them
under whatever heading the document uses. What it does not relax is the safety
contract: copy printed values verbatim, never calculate or infer, and emit
null for anything not printed. Grounded re-validation
(ground_extracted_fields()) then re-checks
every field against an independent authority, so a fabricated value is dropped
even if the prompt fails to prevent it.
See also
InvoiceDraftTyped draft this reader returns after grounded re-validation.
ground_extracted_fields()Shared grounded re-validation this reader and the vision reader both use.
transcribe_document_images()Sibling ACQUISITION stage for evidence carrying no text layer at all. It produces the transcription this reader consumes; it does not read fields.
- default_extraction_authority_values(*, operation)[source]¶
Resolve the authority values for the fallback period.
The one place this package turns “no values were supplied” into values, and it does so by asking the application layer’s compiler rather than by reading any authority itself.
- Returns:
The values in force across the current civil year.
- Return type:
- Parameters:
operation (PinnedAuthorityOperation)
- build_text_field_extraction_prompt(evidence_text, *, operation, values=None, fields=None)[source]¶
Build the extraction prompt for
evidence_text.Separate from the transport so the exact instruction a model will receive is directly assertable without dispatching a request.
The instruction half is the SHARED rendered artefact (
render_invoice_extraction_prompt()), not a second hand-maintained field list: this reader and the vision reader ask for the same eight fields in the same declared forms, and maintaining that agreement by hand is exactly the drift that lost a correctly-read rate.- Parameters:
evidence_text (
str) – The document’s text representation.operation (
PinnedAuthorityOperation) – The caller-owned generation-pinned authority operation used when resolving fallback authority values.values (
InvoiceExtractionAuthorityValues|None) – Regulatory values to enumerate, resolved by the application layer.Noneresolves the current civil year’s, which is the honest fallback for a document not yet bound to a filing period.fields (
Collection[str] |None) – The field names to ask for, orNonefor every declared field. Passed to the shared compiler unchanged; the selection is validated there against the declaration, so a name this reader does not recognise refuses in the one place that knows the vocabulary rather than being silently dropped on the way.
- Returns:
instructions, then the document text under a delimiter that tells the model where its own instructions end.
- Return type:
The full prompt
- Raises:
PurchaseInvoiceEvidenceInputError – When
evidence_textis blank, which would otherwise ask a model to read nothing and invite it to invent an entire invoice.
- class TextInvoiceFieldExtractor(*, model=None, provider=LLMProvider.LOCAL, client=None, operation, settings=None, authority_values=None, consent_token=None, public_corpus=False, fields=None)[source]¶
Bases:
objectRead an invoice’s text with a language model into a grounded
InvoiceDraft.- Parameters:
model (
str|None) – Optional model identifier;Noneuses the configured LOCAL text model. Required whenprovideris not LOCAL, because the only default that exists names a local model no vendor serves.provider (
LLMProvider) – Which provider carries the read. Defaults to LOCAL so a taxpayer’s document does not leave the host by default; naming a cloud provider is a deliberate call-site act.client (
LLMClient|None) – InjectedLLMClient(dependency injection for tests); default-constructed against the resolved settings otherwise.operation (
PinnedAuthorityOperation) – Caller-owned generation-pinned authority operation retained for authority resolution and field grounding.settings (
Settings|None) – Injected settings; defaults toload_settings().authority_values (
InvoiceExtractionAuthorityValues|None) – The regulatory values the compiled prompt enumerates, resolved byresolve_invoice_extraction_authority_values(). Taken as resolved DATA rather than as a period this reader would look up for itself: the rates are the application layer’s to determine, and a reader that resolves its own has quietly become a second consumer of the calculation authorities.Nonefalls back to the current civil year’s values.consent_token (
EvidenceConsentToken|None) – Per-invocation off-host consent proof, minted throughmint_evidence_consent_token(). Required only for an off-host read of real evidence;Noneis correct for every on-host read.public_corpus (
bool) – Whether the text handed to this reader comes from the public, synthetic measurement corpus rather than from a taxpayer’s document. Defaults toFalse– the fail-closed direction, so a caller that says nothing gets the gate. Naming the corpus is the deliberate act, not naming the evidence.fields (
Collection[str] |None) – The field names each read asks for, orNonefor every declared field. Held for the reader’s lifetime rather than passed per read, because it describes the SHAPE of the call this reader makes, and a shape that varied between two reads of one corpus would make those reads incomparable. A measurement comparing call shapes builds one reader per shape.
- property decided_by: str¶
transport, reader, model, and the rates compiled in.
Distinct from the vision stamp so a persisted record always says which reader produced the fields. The model segment is
configuredwhen the caller pinned nothing, because the effective model is then the active provider’s default rather than a fact this object holds.The trailing rate-provenance token answers the question the model name cannot: the prompt now enumerates registry-resolved rates, so which rates were in force for this read is part of how the figure was reached.
The transport segment is DERIVED from the provider actually used, matching the vision reader. It was previously absent, so this stamp could not say whether a read had left the host – and a model name does not answer that, because a vendor model identifier reveals the vendor only to a reader who already knows the catalogue. A consent withdrawal enumerates cloud-derived artefacts BY this segment, so a stamp that omits it makes a withdrawal silently incomplete: the artefact that most needs re-deriving is the one the survey cannot see.
- Type:
Provenance stamp
- extract(*, transcription)[source]¶
Read the acquisition-stage
transcriptionand return the grounded draft.Takes the typed stage-1 artefact rather than a bare string, which is what makes this the second stage of a pipeline instead of a helper that happens to accept text. A string carries no answer to “who read these characters off the document”, and that answer is not decoration: it is the ORIGIN stamped on every value this reader proposes, and the record of whether an independent reader produced the text its anchors are later checked against.
- Parameters:
transcription (
DocumentTranscription) – The acquisition-stage transcription, printed forms intact.- Returns:
Every field the model reported AND that passed grounded re-validation; everything else is
None.- Return type:
- extract_invoice_fields_from_text(transcription, *, operation, model=None, settings=None, authority_values=None)[source]¶
Convenience wrapper: build a
TextInvoiceFieldExtractorand extract.This is the entry point the evidence router calls, and it takes no provider argument. The provider is therefore pinned LOCAL, and the pin is written out below rather than inherited from the extractor’s default: a pin held by NOT passing an argument is the weakest possible statement of a confidentiality property, because widening this signature with a pass-through
providerwould open the off-host route for every router call without a single diff line that looks like a confidentiality change.The pin is documentation, not the boundary. Widening this signature cannot actually send a taxpayer’s document off-host, because the extractor marks every request it builds as evidence-derived and
LLMClient’s per-invocation evidence-consent check refuses a marked request at any off-host provider without a per-invocation consent token. That is the property to preserve if this signature ever changes: the refusal lives below this function, not in it.- Parameters:
transcription (
DocumentTranscription) – The acquisition-stage transcription to read.operation (
PinnedAuthorityOperation) – The caller-owned generation-pinned authority operation used for authority resolution and field grounding.settings (
Settings|None) – Optional resolved settings override.authority_values (
InvoiceExtractionAuthorityValues|None) – Application-resolved regulatory values for the prompt. The routing caller resolves these ONCE per document and passes them here, so a document read through several stages is read under one set of rates rather than one per prompt construction.
- Returns:
The grounded, best-effort extracted fields.
- Return type: