Story-2058 Walkthrough

Change: CE-6 of the Context Engine (Epic-2049, RFD pramaan-functions docs/notes/rfd-context-engine.md §5.1 / §3 / §4). It gives Blake (the registrar) a new capability: from the same document he registers, produce the L1 document_card.v1 — what the document is (type, dates, parties, amounts, 3–12 key assertions) — with a byte-verifiable SourceSpan on every evidential field. Provenance is law: no naked facts.

The core move — "resolution == find"

A card field is only valid if its quote is byte-present in the exact document_pages block it claims (RFD §4, the anti-hallucination gate the >20% kill criterion rides on). The model cannot count bytes, so it never invents char offsets: it names a page + block + a verbatim quote. Code does the rest — a byte-exact block_text.find(quote):

found  → compute char_start/char_end, mint the SourceSpan   (RESOLVED)
absent → drop the field                                    (REJECTED)

So "the model fabricated a quote" and "the span fails to resolve" are the same event, measured deterministically, offline, per-PR. str.find is exact — no whitespace normalization, no case-folding ("a court reads the bytes").

What ships

FileRole
agents/registrar/context_contracts/Vendored CE-1 DocumentCard closure (DocumentCard, SourceSpan, CitedValue, Card*, EnrichmentStamp), byte-faithful to pramaan-functions src/shared/context_contracts/ (commit 5b20208). A CodeZip brain can't import that tree, so we vendor + drift-guard, exactly as Atlas vendors query_matters_server_params.json. Do NOT redefine the shape.
agents/registrar/anchor.pyPure plumbing: the page/block-tagged evidence renderer, the byte-exact resolve_quote_span, the SpanGateResult reject-rate metric, the sp1: span-id composite, and measure_token_inflation.
agents/registrar/card_models.pyThe flat generation DTO RegistrarCardOutput (shallow, Bug-1357-safe) and assemble_document_card — the bridge that byte-resolves every quote into the canonical span-carrying card, dropping what won't resolve.
agents/registrar/prompts/card.pyBlake's card system prompt (PROMPTING.md: teach-by-contract, recursive injection fence, provenance-is-law, self-check-before-emit) + the anchored user-prompt builder.
agents/registrar/agent.py_card_agent + extract_document_card — the fail-closed producer that NEVER raises.
agents/registrar/runtime.py, events.pyA new card mode that emits a document.card effect the broker persists (CE-7 ingest boundary). Off the classify turn.
agents/registrar/evals/card_golden_corpus.jsonl, evals/card_gate.pyThe kill-criterion harness: a golden Indian-legal corpus + the deterministic reject-rate gate and the periodic live measurement.

Failure isolation — card failure never blocks registration

The card is a separate pass, not part of the interactive classify turn (RFD §5.1; matches CE-7's separate SQS enrich kick). Two guarantees, both test-asserted:

Acceptance criteria → proof

ACProof
card failure never blocks registration apply (test-asserted)test_registrar_card_isolation.py — extract never raises (provider-down, model explodes); classify never calls the producer; card mode completes on failure, never run.failed.
anchored-input token inflation measuredanchor.measure_token_inflation + test_anchored_input_token_inflation_is_measured — flat vs anchored token counts + ratio, serialized for the record.
< 20% span rejects on golden corpus (kill criterion)test_registrar_card_golden_corpus.py over card_golden_corpus.jsonl — well-formed corpus resolves at 0% (far under 20%); fabricated cases ARE rejected (the gate has teeth). Live Blake reject-rate is evals.card_gate.measure_live_reject_rate (periodic, needs a key).

Verification

uv run --package registrar pytest tests -q           # 270 passed
uv run ruff check agents/registrar/                  # All checks passed!
python scripts/check_brain_egress.py                 # brain-egress check: clean
python scripts/check_prompt_leakage.py               # prompt-leakage check: clean
uv run pytest tests/ -q -m unit                      # 170 passed (governance)

Brain stays config+brain only (pramaan-docs ADR-110 §6): the card producer holds no DB/DSN, calls no tool, and its only egress is the inference provider. The context_contracts package is pure (no sqlalchemy/boto3). The broker-side card persistence (CE-7) and the registration-consumer enrich kick are downstream stories.