Files
notarius/docs/roadmap/references.md

239 lines
9.5 KiB
Markdown

# Feature Roadmap: Extraction References
## Status
This document defines the target state and policy choices for the planned
extraction-reference feature in Notarius. It describes planned behavior, not
implemented behavior. The staged implementation plan lives in
[implementation.md](implementation.md).
## Goal
Extraction quality improves when an LLM-backed extractor receives stable
reference material alongside the source input. For the initial D&D spell
extractor, useful reference material includes a party roster, a player list, and
a campaign glossary.
Notarius should support passing this material to extractors as **named reference
items** without introducing domain-specific concepts into core or framework
packages. The framework should know only that:
- extractors declare named reference slots they accept;
- pipeline config and CLI flags bind content, initially files, to those slots;
- bound content is rendered into module-owned prompt templates;
- bound content is digested and recorded as run provenance.
Only extract modules should know what a "roster" or "glossary" means. Domain
semantics live in module-owned slot declarations and prompt templates.
## Definitions
- **Reference slot**: a named, typed-by-convention input declared by an
extractor, with a human-readable description, required/optional status, and
optional guardrails such as accepted media types and maximum bytes.
- **Reference item**: resolved content bound to a slot for a given run: slot
name, content bytes, media type, content digest, size, origin, and binding
source.
- **Reference binding**: the association of a slot name to a content source,
defined in pipeline config and overridable per run via CLI.
- **Reference set**: the lane-scoped collection of resolved reference items
delivered to an extractor.
## Architectural Principles
- References are opaque to the framework. Core and framework packages must not
interpret reference content or recognize domain slot names.
- References are inputs. Anything that can change extraction output must be
digested into the run manifest and participate in any cache or idempotency key.
- References are not evidence. `SourceRef` values must only ever reference
source units. Reference items must not receive unit IDs and must not be
addressable by source references.
- Slots are declared, not ad hoc. Binding an undeclared slot name, or omitting a
required slot, should fail before any LLM call.
- Reference delivery is lane-scoped. Pipeline-level bindings may apply to
multiple lanes, but each lane receives only the references declared by its
extractor after pipeline, lane, CLI override, and CLI unbind rules are
resolved.
- Optional slots degrade gracefully. Prompt templates should render cleanly
whether or not an optional slot is bound.
- Rendering must be deterministic. Identical source input, config, prompts, and
reference bytes should produce byte-identical rendered prompts. Reference
slots should render in declaration order, with stable binding order within a
slot.
## Target Contracts
Extractors should declare accepted reference slots directly on the extractor
contract. This is a first-class feature, so mechanical updates to existing
extractors and test fakes are acceptable.
The target slot declaration includes:
- `Name`;
- `Description`;
- `Required`;
- `AcceptedMediaTypes`;
- `Multiple`;
- `MaxBytes`.
Extractors with no reference needs return an empty slot list.
Resolved reference items should be content-bearing values, not unresolved file
paths. The MVP producer is "read this file," but the item shape should permit
future producers such as prior-run artifacts, derived summaries, or entity
registries without changing extractor-facing contracts.
The extraction request should carry the lane-scoped resolved reference set.
Framework and core code should treat the set as opaque bytes plus metadata.
## Binding Lifecycle
Reference handling should be split across existing lifecycle boundaries:
1. Config parsing records pipeline-level and lane-level reference bindings
without reading files.
2. Pipeline resolution validates selected lanes, declared extractor slots,
missing required slots, unknown bindings, and ambiguous flat CLI bindings.
3. Run preparation resolves paths, reads files, validates media type and size,
computes digests, and materializes reference items.
4. Extraction receives the lane-specific resolved reference set.
Config-relative paths resolve relative to the config file. CLI-relative paths
resolve relative to the current working directory.
## Configuration and CLI
Reference bindings should live in pipeline config because the initial use cases
are campaign-invariant more often than run-variant. Bindings should be supported
at two levels:
- pipeline level: defaults shared by artifact lanes whose extractors declare
matching slots;
- lane level: additions or overrides for a single artifact lane.
Illustrative config shape:
```yaml
pipelines:
dnd-session:
input: seriatim
references:
roster: ./campaign/party_roster.md
glossary: ./campaign/glossary.md
artifacts:
spells:
extract: dnd/spells
npcs:
extract: dnd/npcs
references:
npc_registry: ./campaign/npcs.md
```
Per-run CLI binding overrides should be repeatable:
```text
notarius run dnd-session --input session-014.json --reference roster=./alt_roster.md
```
Flat CLI slot names are allowed when unambiguous across selected lanes. Lane
qualified names, such as `spells.roster=./alt_roster.md`, disambiguate or target
a specific lane. CLI bindings override config bindings for the same lane and
slot.
Users should also be able to unbind a config-bound optional slot for a run with
an explicit repeatable flag:
```text
notarius run dnd-session --input session-014.json --without-reference roster
```
Unbinding a required slot should fail during pipeline/reference resolution.
## Prompt Template Integration
Prompt templates are module-owned. Template rendering should expose:
- `{{ reference "roster" }}`: renders the content of the bound item;
- `{{ hasreference "glossary" }}`: predicate for conditional sections, so
optional slots can be included only when bound.
Rules:
- Referencing an undeclared slot from a template is a module bug and should fail
at prompt registration/build time or the earliest feasible equivalent.
- Referencing a declared but unbound optional slot should render as empty;
templates should use `hasreference` to avoid dangling section headers.
- Rendering must be deterministic and independent of map iteration order.
- Prompt identity should be computed over the template, not the rendered prompt.
Reference digests are recorded separately in the manifest so a reference edit
is visible as a reference change, not a prompt change.
Reference content is repeated in every per-chunk prompt in the MVP. Per-slot or
per-chunk inclusion policies are deferred until cost data justifies them.
## Provenance
The run manifest must record resolved references separately from source
digests. For every bound lane and slot, it should record:
- lane ID;
- slot name;
- origin type and URI;
- content digest;
- media type;
- size in bytes;
- whether the binding came from config or CLI override.
Reference digests must participate in any idempotency/cache key alongside source
digests, prompt hashes, schema versions, model, and parameters. Two runs that
differ only in reference content must be distinguishable from the manifest
alone.
Diagnostics for a run should include the resolved binding set with digests, not
full reference content, consistent with the existing redacted-effective-config
pattern.
## Validation and Guardrails
### References Are Not Evidence
The primary new failure mode is the model extracting facts from references
rather than from the source input. For example, a roster may list a player
character's known spells, and the model might emit a spell-cast artifact for a
spell that was never cast in the session.
Defenses, in priority order:
1. **Structural.** `SourceRef` remains the only grounding mechanism and can only
reference source units. No contract change should make references
addressable as evidence.
2. **Prompt discipline.** Module templates should frame references explicitly as
reference material, such as "use the roster to resolve speakers to
characters; extract only events that occur in the transcript."
3. **Validator support.** The source-reference validator, or a sibling
deterministic validator, should warn when referenced source text does not
plausibly relate to the extracted fact. Severity should be `warn`, not
`fail`, because transcripts can use paraphrase, nicknames, and abbreviations.
4. **Regression fixtures.** Tests should include a fixture in which a bound
roster mentions a spell that is never cast in the transcript, asserting no
artifact record is produced for it.
### Size and Sanity Guardrails
- MVP accepts UTF-8 text content only. Other media types should be rejected with
a clear error.
- A slot-level `MaxBytes` value should be enforced when declared.
- Empty bound files should produce a warning because they are likely user error.
## Out of Scope
- Token budgeting and model context-window management for references.
- Non-file reference producers, including prior-run artifacts, derived
summaries, and entity registries.
- Per-chunk or per-slot inclusion policies.
- Structured or parsed references such as typed roster schemas. References are
opaque text handed to prompts.
- Reference caching, preprocessing, summarization, embedding, or retrieval.
- Making references addressable as evidence in any form.