Files
notarius/docs/roadmap/implementation.md

374 lines
20 KiB
Markdown

# Minimal D&D Extraction Contracts Implementation Plan
**Status:** Ready for implementation
## Objective
Implement the durable contract redesign defined by
[Minimal D&D Extraction Contracts](minimal-dnd-extraction-contracts.md) and
[ADR-0009](../adr/0009-minimal-evidence-grounded-extraction-artifacts.md).
The result is a coordinated in-place redesign of NPC, spell-cast, and combat-turn
extraction. Each lane must emit only its narrow, evidence-grounded facts; no
removed rich-schema field may survive as an optional field, placeholder, compatibility
shim, or deterministic synthesis.
This plan deliberately starts with NPCs because the NPC registry is a generated
reference consumed by spell and combat extraction. Spell and combat then change
independently, followed by one repository-wide contract and documentation
pass.
## Fixed Decisions And Guardrails
The implementing agent must treat these as decisions, not open design choices:
- Keep the artifact kinds `dnd/npc-list`, `dnd/spell-list`, and
`dnd/combat-turn-list`, their module keys and capabilities, their media types,
and their prompt IDs stable.
- Retain exactly the existing v1 schema keys, IDs, names, versions, filenames,
prompt IDs, and prompt versions listed in the feature roadmap. Change their
unpublished shapes and content in place; do not harmonize the private spell
identity as part of this work.
- Do not add v2 assets, runtime version negotiation, migration code, dual-write
behavior, a second module registration, or compatibility fixtures for the
superseded pre-release shapes. Existing fixtures should be rewritten or
deleted according to whether they still protect current behavior.
- Require the top-level list field and every record field. A list may be empty,
but every returned record must have at least one source reference. Use strict
JSON objects with unknown fields rejected and no nullable or optional legacy
fields.
- Keep private source references limited to `start_unit_id` and `end_unit_id`.
Mapping assigns the current source document ID; campaign references and an
NPC registry never become event evidence.
- Keep the shared prompt ordering policy: stable shared instructions first,
stable campaign and generated references next, module task material after
those references, and the chunk-variable transcript last.
- Preserve the existing production validator-chain order and the rule that a
configured chain is authoritative. Remove or simplify validators; do not
silently reorder chains.
- Preserve the existing NPC ID derivation algorithm and comparison/display
normalization for canonical names. Retain existing semantic-policy
identifiers as well as schema and prompt versions; pre-redesign development
state is disposable. Unchanged canonical names must not receive new IDs.
- Use deterministic code only for display normalization, known catalog or NPC
canonicalization, application-owned IDs, evidence canonicalization, ordering,
and exact duplicate collapse. Do not introduce fuzzy matching or inferred
enrichment.
- Follow the testing policy: protect schemas and behavior at their owning
boundaries, delete obsolete tests, and avoid tests that snapshot prompt prose
or detect exact shared-prefix length. No live or paid model call is a stage
completion requirement.
- Each stage must leave the repository compiling and `go test ./...` passing.
Update all affected fixtures and callers within the stage that changes a
public Go type; do not leave an intentionally broken intermediate commit.
## Stage 1: Cut Over The NPC Contract And Name Projection
This stage establishes the redesigned generated reference on which later stages
depend.
### 1.1 Replace the durable and private data shapes
- Reduce `dnd.NPC` in `internal/modules/dnd/types.go` to exactly `ID`, `Name`,
and `SourceRefs`. Delete `NPCRelationship` and every alias, description, and
relationship field or helper that becomes unused.
- Rewrite the existing strict durable schema `dnd_npcs.v1.json` with required
top-level `npcs`, and records containing only required `id`, `name`, and
`source_refs`. Keep the NPC codec at schema version `v1`, name
`notarius_dnd_npcs_v1`, and its existing schema ID and media type.
- Rewrite the strict private schema `dnd_npcs_llm.v1.json`. Its records contain
only required `name` and model-facing source ranges. Keep the extractor schema
identity and prompt ID/version unchanged.
- Reduce the private response DTO and mapping accordingly. Preserve candidate
data at the mapping boundary so deterministic validators, rather than mapping
defaults, reject blank names or invalid ranges. Assign the current source ID
and derive the NPC ID in application code.
- Rewrite the NPC task and instruction assets to ask only for individually
identifiable NPC names and supporting transcript ranges. Explicitly exclude
anonymous groups, generic roles, invented labels, descriptions, aliases, and
relationships. Keep transcript material last in the manifest.
### 1.2 Simplify NPC identity, normalization, and validation
- Keep the identity policy at `dnd.npcs.identity.v1`. Retain display
normalization, comparison keys, ID syntax, and deterministic ID derivation.
Validate nonblank canonical names, exact ID/name agreement, duplicate
canonical names, and duplicate IDs. Delete alias validation and alias-specific
issue locations/codes.
- Keep NPC normalization at `dnd.npcs.normalize.v1`. Normalize the retained
display name, derive its ID, canonicalize and deduplicate source references,
consolidate records only by the canonical-name comparison key, preserve the
first stable record, and union exact evidence. Remove alias promotion,
relationship merge/rewrites, and their warning codes.
- Keep the existing NPC shape and source-relatedness policy identifiers. The
shape validator checks only list presence, nonblank `id` and `name`, and
nonempty source references; source-relatedness grounds a record only through
its retained name. The existing source-ref validator remains the owner of
range validity.
- Keep the default validation order domain-first, then JSON Schema, then the
advisory relatedness validator. Simplify only the validator implementations
and selections whose owned behavior changed.
### 1.3 Separate durable registry provenance from model input
- Continue to canonicalize and retain the complete redesigned NPC artifact for
registry validation, cache identity, manifests, and provenance.
`Registry.Digest()` remains the digest of that complete canonical artifact
when bound and remains empty when no registry was supplied.
- Build a second structural JSON projection for model grounding with the exact
shape `{"npcs":[{"name":"Mira Thorn"}]}` in normalized registry order. It
contains names only: no IDs, source references, origin URI, aliases, or other
provenance. Generate it with typed values and `json.Marshal`, not string
concatenation. The empty projection is exactly `{"npcs":[]}`.
- Add an explicit projection digest accessor. The digest is SHA-256 over the
exact projected bytes, including for an absent or empty registry, and
`PromptInput().Digest` must equal it. Keep full-artifact and projection digests
distinct even when their content happens to coincide.
- Index `Registry.Lookup` by canonical name only. Retain immutable return values
and defensive copies. Remove alias indexing and alias-aware comments.
- In spell extraction, combat extraction, and combat normalization, use the NPC
name-projection digest for the component-local checkpoint fingerprint because
it exactly describes the names that affect those operations. Keep the full
registry digest and count in manifest metadata for provenance. Framework-owned
generated-reference fingerprints may still invalidate a run when any upstream
artifact byte changes; do not broaden this stage into a framework cache
redesign.
### 1.4 Update owners, consumers, and tests
- Update NPC codec, schema, extractor, identity, validator, normalizer, registry,
registration, pipeline-integration, and CLI fixtures to the new shape. Adapt
spell and combat tests that construct `dnd.NPC` values so the repository
remains buildable, but do not change their own artifact contracts yet.
- Add or rewrite focused tests for strict schema acceptance/rejection,
codec round trips, unchanged ID derivation for known names, name-only
consolidation, evidence union, registry immutability, and canonical-name-only
lookup. Rewrite the existing fixture for the minimal current contract; do not
retain the superseded rich fixture solely to test backwards incompatibility.
- Test the projection as a data contract: it contains only ordered names,
equivalent normalized registries produce identical bytes and digest,
evidence/ID-only changes do not change the projection digest, and name/order
changes do. This is not authorization to snapshot assembled prompt prose or
prefix lengths.
- Update `docs/integrations/dnd-npc-artifacts.md` to own the redesigned v1
durable schema. Update `docs/internal/modules.md` and
`docs/internal/llm.md` only for current NPC behavior that lands in this stage.
### Stage 1 completion criteria
- NPC durable and private schemas expose no removed enrichment fields.
- The generated NPC prompt input contains names only while manifests retain
full registry provenance.
- Spell and combat consumers accept generated or external registries in the
redesigned v1 shape; rich pre-redesign registry JSON fails strict decoding.
- Focused NPC, spell-wiring, combat-wiring, integration, and CLI tests pass, and
`go test ./...` passes.
## Stage 2: Cut Over Spell-Cast Extraction
### 2.1 Replace the spell contract and prompt
- Reduce `dnd.SpellCast` to exactly `Caster`, `Spell`, and `SourceRefs`.
- Rewrite `dnd_spells.v1.json` in place. Keep the durable codec at version v1,
name `notarius_dnd_spells_v1`, and its existing schema ID. Its strict record
contains only required `caster`, `spell`, and `source_refs`.
- Rewrite `dnd_spells_llm.v1.json` with the same logical fields and model-facing
ranges. Keep the existing private key, ID, name, prompt version, and schema
path unchanged.
- Reduce the private DTO, canonicalization, and mapping to the retained fields.
Continue assigning current source IDs, stable-ordering candidates by evidence,
and preserving semantically invalid candidates for deterministic validation.
- Rewrite spell task and instruction assets around the narrow casting-event
boundary. Retain the spell catalog and name-only NPC projection as
disambiguation inputs, never evidence. Remove effect, outcome, and narrative
duties and remove the `common-dnd-immediate-resolution.md` message from the
spell manifest and spell asset registration. Do not delete the shared file in
this stage because combat still uses it.
### 2.2 Simplify spell policies
- Keep the spell shape policy identifier unchanged and validate only list
presence, nonblank caster/spell, and nonempty source references.
- Keep catalog validation, source-reference validation, and source-relatedness
behavior and policy identities unchanged where their actual semantics are
already limited to spell name, caster, and evidence.
- Simplify normalization and duplicate comparison to caster, catalog-canonical
spell name, and the complete valid evidence set. Remove all prose selection,
copying, fixture fields, and assertions. Preserve catalog fingerprints and
metadata.
- Keep the exact inclusion rule from the feature roadmap: an actual casting or
unambiguous declared attempt is included; mentions, plans, rules discussion,
and catalog matches are not.
### 2.3 Update owners and tests
- Update spell codec, private schema, extractor, validators, normalizer, merge
and registration tests, pipeline integration, CLI output fixtures, and any
maintained examples to the minimal shape. Rewrite or delete rich-schema
fixtures rather than retaining them as compatibility cases.
- Replace tests of effects and narrative descriptions with focused tests of the
retained contract: strict unknown-field rejection, codec round trips, current
source-ID assignment, catalog canonicalization, evidence ordering, duplicate
collapse, and NPC name-projection wiring.
- Update `docs/integrations/dnd-spell-artifacts.md` as the canonical redesigned
v1 contract and update current internal module/LLM documentation for the
smaller prompt and response. Do not duplicate the spell catalog contract
owned by its existing integration document.
### Stage 2 completion criteria
- No production spell type, schema, prompt, validator, normalizer, fixture, or
documentation contract refers to effect or narrative description.
- Spell prompt/schema identities remain exactly their existing v1 values.
- Focused spell and pipeline tests pass, and `go test ./...` passes.
## Stage 3: Cut Over Combat-Turn Extraction
### 3.1 Replace the combat contract and prompt
- Reduce `dnd.CombatTurn` to exactly `Actor`, `TurnKind`, and `SourceRefs`.
Delete `CombatAction`, `CombatActionCategory`, their constants, and all
now-unused helpers. Retain the existing five `CombatTurnKind` values.
- Rewrite `dnd_combat_turns.v1.json` in place. Keep the durable codec at version
v1, name `notarius_dnd_combat_turns_v1`, and its existing schema ID. Use a
strict required record with `actor`, `turn_kind`, and `source_refs` only.
- Simplify the durable codec to direct strict encoding/decoding if its custom
wire representation exists only to distinguish removed nullable fields.
Preserve presence semantics for the top-level list and strict unknown-field
rejection.
- Rewrite `dnd_combat_turns_llm.v1.json` while retaining its private schema and
prompt identities, and reduce the DTO/mapping to actor, turn kind, and
model-facing ranges. Keep the semantic mapping policy identifier unchanged.
- Rewrite combat task/instruction assets around detecting ordered turns and
discrete interrupting events. Remove round, action, target, declaration,
resolution, outcome, and summary duties. Remove the shared immediate-
resolution message from the combat manifest.
- Once both spell and combat manifests no longer use it, delete
`common-dnd-immediate-resolution.md` and its shared and module asset
registrations. Retain all other shared evidence, identity, reference, NPC,
and transcript assets in their cache-friendly order.
### 3.2 Simplify combat normalization and validation
- Keep combat normalization at `dnd.combat_turns.normalize.v1`. Continue to
display-normalize and registry-canonicalize actors, canonicalize evidence,
order records chronologically, and collapse exact duplicates by actor, turn
kind, and complete valid evidence. Delete action/target/prose normalization
and warning codes.
- Keep the invariant policy identifier unchanged. It checks canonical actor
display, canonical and chronological evidence, stable event ordering, and
absence of duplicate event identities; it performs no nested-action checks.
- Keep the shape policy identifier unchanged and validate only list presence,
nonblank actor, allowed turn kind, and nonempty source references.
- Keep the source-relatedness policy identifier unchanged and compare only the
actor against cited transcript material. Remove declaration-token heuristics
and their now-unused helpers. Keep source-reference validation unchanged if
its semantics did not change.
- Simplify merge/clone behavior to copy only retained values and source refs.
Preserve stable ordering and defensive ownership.
### 3.3 Update owners and tests
- Update codec, private schema, extractor, normalizer, validators, merge,
registration, pipeline integration, CLI fixtures, and examples to the minimal
shape. Rewrite or delete rich-schema fixtures rather than retaining them as
compatibility cases.
- Delete tests whose sole policy was round/action/summary handling. Add or
rewrite focused tests for strict schemas, enum validation, mapping and
source-ID assignment, actor canonicalization through the redesigned NPC
registry, chronology, exact duplicate collapse, and invariant validation.
- Update `docs/integrations/dnd-combat-turn-artifacts.md` as the canonical
redesigned v1 contract and update current internal module/LLM documentation
for the implemented behavior.
### Stage 3 completion criteria
- No production combat type, prompt, schema, policy, normalizer, fixture, or
current documentation refers to rounds, actions, summaries, declarations,
targets, resolutions, or action categories.
- The immediate-resolution shared asset has no remaining registration or file.
- Focused combat and pipeline tests pass, and `go test ./...` passes.
## Stage 4: Complete The Repository-Wide Cutover
### 4.1 Audit contract identity and stale surface area
- Search code, embedded assets, tests, examples, and current documentation for
all removed field names and unintended v2 schema/prompt names. Removed fields
may remain only in historical ADR or roadmap context; active schema, prompt,
fixture, and current-behavior surfaces must describe the minimal v1 contract.
- Verify the three artifact registrations still bind their original kinds and
exact redesigned Go types through extract, merge, normalize, codec, and
validators.
- Verify all prompt manifests still point at their v1 private schemas, stable
reference material precedes module-variable material, and transcript content
remains last. Do not add a change-detector test for prompt message count,
prose, shared-prefix content, or prefix length.
- Verify pre-redesign development checkpoints naturally miss through changed
prompt/schema content and generated-dependency fingerprints. Do not add
migration or compatibility handling for disposable pre-release state.
### 4.2 Exercise representative assembled behavior
- Keep unit case matrices at their owning schema, validator, normalizer, and
registry boundaries. At the assembled-pipeline boundary, retain only
representative tests proving each redesigned lane is registered, strict
JSON/schema failures are attributed to the correct validator, semantic
failures are attributed to the correct domain validator, and generated NPC
output is accepted by later spell/combat stages.
- Cover an ordered multi-step run in which NPC extraction produces the minimal
artifact and spell/combat consume its name projection. Assert that downstream
event source references point only to the current transcript and not to NPC
registry evidence.
- Verify CLI logical output and manifests retain the v1 schema/prompt identities,
full NPC registry provenance, and the relevant component fingerprints without
exposing prompt bodies or reference payloads.
### 4.3 Finish documentation and lifecycle state
- Reconcile the three integration documents, `docs/internal/modules.md`, and
`docs/internal/llm.md` with the final code. Correct any stale validator-order
descriptions while doing so; current docs must describe the registered order,
not preserve an older generic ordering example.
- Mark ADR-0009 `Accepted` and the feature roadmap `Implemented` when the code,
tests, and current-behavior documentation all land. Remove the completed item
from `docs/roadmap/future.md`; retain the feature roadmap and ADR as design
rationale unless the repository's normal roadmap-retirement practice calls
for moving the completed roadmap later.
- Record any human-reviewed rich/minimal model evaluation separately from CI
results. Evaluation may motivate later prompt tuning but does not reopen the
approved durable minimal field set within this implementation.
### 4.4 Final verification
Run, in order:
```sh
gofmt -w <changed Go files>
go test ./...
go vet ./...
go build ./cmd/notarius
go test -race ./internal/modules/dnd/...
git diff --check
```
If the repository-wide race command exposes an unrelated, pre-existing failure,
document it with the narrower affected package result; do not weaken or skip
ordinary tests for the changed D&D packages.
### Stage 4 completion criteria
- All three lanes use only their minimal v1 contracts from model response
through durable output.
- No compatibility shim, removed-field policy, unintended v2 asset, or stale
current-behavior documentation remains.
- Generated NPC references are name-only for LLM input and remain full-fidelity
for durable provenance.
- Repository tests, vet, build, race checks for the changed domain, and diff
hygiene checks pass.
## Open Questions
None. The feature roadmap, ADR, and fixed decisions above define the cutover,
pre-release schema, evidence, projection, validation, testing, and documentation
policies needed to implement each stage without further product decisions.