Story-2328 Walkthrough

Change: Blake (the registrar runtime) gains a fourth mode — insight — that writes THE READ: the insight brief for one document, read with the whole matter behind it. Agent half only. The broker seam (invoke, byte-verify, persist) is the twin, pramaan-functions Bug-2320, and it merges after this.

Why this exists (the founder ruling). THE READ's OpenRouter call lived inside the pramaan-context-embed Lambda. That Lambda is a data plane: it holds no OPENROUTER_API_KEY and its VPC has no egress to openrouter.ai — so every staging brief failed brief_failed and the Insights tab said "Read pending" forever, while CI stayed green (a unit test has no VPC). Ruling, Bug-2320: agents think; lambdas move. A model homed in a Lambda is a P0 bug.

What moved, and what deliberately did not

Before (Story-2169)After (this story)
The prompt, the model choice, the model call context-embed Lambda (src/shared/context/insight_brief.py) Blake, on AgentCore — where OpenRouter is the model plane and the secret arrives via the pramaan-docs ADR-121 D2 bootstrap
Span construction · V-CITE byte verification · ring law · drop-unverifiable-pins · the context.document_insight_briefs write the Lambda the Lambda — unchanged. The guarantees stay with the data.

That split is the whole design. Blake proposes LEAN pins — a page/block plus a verbatim quote, a matter index, or a bare general_law label — and nothing else. It cannot mint a SourceSpan, a span_id, a char offset or a section_id. An unverifiable pin is only droppable by the broker if what the model proposed was coordinates + bytes it can check: citations are data flow plus a deterministic gate, never a citation agent (desk RFD §4).

The shape — the card/segment discipline, a fourth time

PieceFileWhat it does
Typed I/O + the ring-law gateagents/registrar/insight_models.py The feedstock (document card + anchored pages + the document's named sections + the broker's PRE-NUMBERED matter assertions) → flat gen DTO → the wire brief, rebuilt key-by-key. Every strip and drop is recorded on an InsightGate.
Promptagents/registrar/prompts/insight.py The retired seat's prompt carried over intact — same role, same JSON shape, same three-source ring law, same section-structured == SECTION == reading and 40,000-char anchored ceiling (truncation MARKED, never silent) — plus Blake's recursive injection fence and ambient output cell. prompt_version → document_insight_brief.v3.
Orchestrationagent.py::run_insight One bounded non-streaming attempt through Pydantic AI + PromptedOutput (Bug-1357-safe). NEVER raises: a producer error is a typed error result, not an exception that unwinds the enrichment chain.
Runtime seamruntime.py mode "insight" → events.document_insight_event Parse-before-run.started (fail-closed), then model.usage → document.insight → run.completed; on a producer error, status='error' + run.failed. Never a silent truncation.

The three-source ring law, enforced in code

Pin kindCarriesWhat the gate does
this_documentpage_number, block_index, a VERBATIM quote An unquoted or page-less pin DROPS its item. The bytes are checked broker-side (V-CITE) — deliberately not re-checked here, so the two verifications can never disagree.
mattermatter_ref (an index into the broker's numbered list) An index outside the list DROPS its item. The numbering is the broker's — never renumbered or reordered in the answer.
general_lawverify: true and nothing else Any record coordinate the model attaches is STRIPPED — the claim survives as the model's knowledge, labelled for the reader; the false pin dies. The law is never dressed as a fact in the record.

The wire — five keys, frozen

{"schema": "agent_event_stream.v1", "type": "document.insight",
 "run_id": "<meta.run_id>",                    // event-level, never inside the payload
 "payload": {"document_id": "...", "status": "ok|needs_review|error",
             "brief": { ...lean-pin draft... } | null,
             "model_id": "...", "prompt_version": "document_insight_brief.v3"}}

Exactly those five keys: the broker's DocumentInsightPayload is extra="forbid", so a sixth key would fail parse_event_line and store nothing. Gate stats therefore ride the operator log (registrar.insight.gate), not the wire. model_id + prompt_version are REQUIRED: the model call lives here now, so this event is the brief's provenance stamp — the broker records it rather than inferring it, and an unstamped brief is stored by nobody.

Two properties of the retired seat that survived the move

Ambient seat, no cache writes (S-9) Background, non-interactive enrichment: no prompt-cache creation is requested anywhere on this path, so no cache-write spend rides an ambient seat. Blake's existing ambient audit (tests/test_registrar_ambient_audit.py) greps the source for the marker and holds this.
Anchored-text ceiling 40,000 chars (REGISTRAR_INSIGHT_MAX_ANCHORED_CHARS) — the card has already distilled the document. The truncation is marked in the feed, so the model knows where its sight ends.

Observability (pramaan-docs ADR-124)

No new span names: the invoke rides agents.registrar.invoke and the model call rides agents.registrar.context_extract, both already in the registry. Token/cost metrics ride the existing model-call spans (_record_cost → record_genai_token_usage_and_cost), which is now the ONLY place the brief's spend is visible — the Lambda no longer pays for a model. meta.traceparent from the invoke is the parent, so trace_id stays continuous Lambda → AgentCore.

Proof (offline, per-PR)

TestProves
test_general_law_pin_never_carries_a_record_coordinatethe ring law holds even when the model dresses law as record
test_blake_never_emits_a_span_id_section_id_or_char_offseta model that smuggles a minted coordinate into its output still puts none on the wire
test_matter_pin_index_must_exist_or_the_item_drops · test_this_document_pin_without_a_quote_drops_its_item · test_a_bad_extra_source_drops_only_itself_not_the_punch_cardthe drop rules, item by item
test_insight_mode_emits_the_document_insight_effect_and_completesthe mode is accepted and answers in the frozen event language with EXACTLY the five payload keys
test_producer_failure_is_loud_never_a_silent_truncation · test_run_insight_never_raises_when_the_provider_is_absentfailure is loud and typed; the pass never unwinds its caller
test_anchored_feed_is_section_structured_and_fenced · test_anchored_feed_marks_its_truncation_honestlythe document is fed as its NAMED PARTS, fenced as evidence, honestly bounded

346 registrar tests + 179 governance tests green; ruff clean.

Deploy

Registrar/agents deploys are MANUAL dispatch — registrar-deploy.yml in pramaan-infra. Merging this PR does not put mode="insight" on the staging runtime; the orchestrator runs that leg. Until it does, the functions twin (Bug-2320) logs context_insight.brief_failed loudly — never a silent "Read pending".