Files
notarius/docs/roadmap/implementation.md

865 lines
44 KiB
Markdown

# Canonical D&D Entity Registries And Occurrences Implementation Plan
## Objective
Implement the target state defined in
[Canonical D&D Entity Registries And Occurrences](entity-registries.md). NPCs,
locations, and items will each have one canonical registry lane and one
registry-backed occurrence lane, with consistent module, artifact, schema,
prompt, reference, validation, package, asset, example, and documentation
vocabulary.
This is a breaking pre-release migration. The completed implementation must not
retain compatibility aliases for old module keys, artifact kinds, types,
schemas, prompts, validators, reference slots, or asset paths. The stages below
deliberately change durable contracts before moving the corresponding module
namespace so that each prompt remains bounded for gpt-5.6-terra and the
repository can compile and pass focused tests after every stage.
Complete the stages in numerical order. Each stage is sized for one
implementation prompt. Do not combine stages unless a later review explicitly
revises this plan.
## Final Contract Matrix
Use these exact final identities. Do not invent variants during implementation.
| Entity role | Module key | Go artifact type | Artifact kind | Durable schema ID | Durable root |
| --- | --- | --- | --- | --- | --- |
| NPC registry | `dnd/npc-registry` | `dnd.NPCRegistry` | `dnd/npc-registry` | `notarius.dnd.npc_registry` | `npcs` |
| NPC occurrences | `dnd/npc-occurrences` | `dnd.NPCOccurrenceList` | `dnd/npc-occurrence-list` | `notarius.dnd.npc_occurrences` | `occurrences` |
| Location registry | `dnd/location-registry` | `dnd.LocationRegistry` | `dnd/location-registry` | `notarius.dnd.location_registry` | `locations` |
| Location occurrences | `dnd/location-occurrences` | `dnd.LocationOccurrenceList` | `dnd/location-occurrence-list` | `notarius.dnd.location_occurrences` | `occurrences` |
| Item registry | `dnd/item-registry` | `dnd.ItemRegistry` | `dnd/item-registry` | `notarius.dnd.item_registry` | `items` |
| Item occurrences | `dnd/item-occurrences` | `dnd.ItemOccurrenceList` | `dnd/item-occurrence-list` | `notarius.dnd.item_occurrences` | `occurrences` |
All durable contracts use schema version `v1` and media type
`application/json`. Registry records have required `id`, `name`, and
`source_refs`. NPC, location, and item occurrences have required `npc_id`,
`location_id`, or `item_id` respectively, plus required `name`, `kind`, and
`source_refs`. Item occurrence `quantity`, `from`, and `to` remain semantically
conditional durable fields.
Use these exact identity policies and digest inputs:
- NPC: `dnd.npc_registry.identity.v1`, SHA-256 of compact JSON
`[policy, comparison_name]`, prefix `npc:sha256:`;
- location: `dnd.location_registry.identity.v1`, SHA-256 of compact JSON
`[policy, comparison_name, source_id, start_unit_id, end_unit_id]` using the
earliest canonical evidence anchor, prefix `location:sha256:`; and
- item: `dnd.item_registry.identity.v1`, SHA-256 of compact JSON
`[policy, comparison_name]`, prefix `item:sha256:`.
Registry reference slots and corresponding PromptKit inputs are exactly
`npc_registry`, `location_registry`, and `item_registry`. Enemy-event grounding
uses `npc_occurrences` for the renamed NPC occurrence artifact.
## Rules For Every Stage
- Read and follow `docs/policy/architecture.md`,
`docs/policy/documentation.md`, and `docs/policy/testing.md` before editing.
- Preserve the fixed pipeline architecture, typed artifact zone, ordered-step
barrier, generated-reference provenance, whole-run failure behavior,
scheduler, checkpoint, and output boundaries. This feature requires no new
framework workflow primitive and no new ADR.
- Keep `assets/assets.go` as the root assets package's only Go file. It remains
a read-only content boundary with no business logic, PromptKit dependency,
registry behavior, or module registration.
- Keep D&D semantics inside `internal/modules/dnd` and `assets/dnd`. Do not
implement the future generic LLM-assisted deduplicator in this work set.
- Do not create compatibility type aliases, duplicate module registrations,
legacy schema decoders, fallback reference-slot names, copied prompt assets,
or deprecated-key shims. Intermediate stages may retain a current module key
until its explicit namespace-migration stage, but must not register both old
and new keys.
- Preserve minimal evidence-grounded contracts. Registry references are
source-free grounding and never occurrence evidence. Every occurrence must
cite current-transcript ranges independently.
- Private structured-response schemas must reject unknown fields and include
every declared property in `required`. Use nullable private fields for
semantically absent item values and map them deterministically to omitted
durable fields.
- Preserve prompt-cache construction: extraction prompts share the byte-identical
system/identity/reference/chunk prefix; evidence and registry projections
follow that prefix; module instructions remain final. Registry normalizers
retain system, instructions, shared reconciliation policy, candidates, and
transcript-window order.
- Update current-behavior documentation when a stage changes an implemented
contract. Do not describe a not-yet-registered item module outside
`docs/roadmap/` before its production-registration stage.
- Keep default tests offline, deterministic, and credential-free. Use package
behavior tests for codecs, identity, registry resolution, normalization, and
validators; integration tests for generated handoffs; and CLI tests for
assembled examples. Do not add live-LLM tests, exact prompt snapshots, private
asset inventories, or duplicate change-detector tests.
- Preserve unrelated user changes. Use `gofmt`, `git diff --check`, and focused
tests in every stage. Do not retire this roadmap or the feature roadmap as
part of implementation.
## Stage 1: Migrate The NPC Registry Durable Contract And Identity
### Goal
Adopt the final NPC registry type, artifact kind, schema identity, and identity
algorithm while the selectable module temporarily remains `dnd/npcs`.
### Required changes
1. In `internal/modules/dnd/types.go`, replace `NPCListKind` and `NPCList` with
`NPCRegistryKind` and `NPCRegistry`. Retain `NPC` with required `ID`, `Name`,
and `SourceRefs`, and retain the durable root field `npcs`.
2. Update every typed consumer, merger, evidence projection, validator,
normalizer, extractor, test fixture, integration helper, and registry
registration to use `dnd.NPCRegistry` and `dnd.NPCRegistryKind`. Do not leave
a Go alias for the retired names.
3. In the existing NPC codec package, replace the durable schema with
`dnd_npc_registry.v1.json`, schema ID `notarius.dnd.npc_registry`, schema name
`notarius_dnd_npc_registry_v1`, and version `v1`. Keep the strict `npcs`
envelope and `application/json` media type.
4. Change the NPC identity policy to `dnd.npc_registry.identity.v1`. Derive IDs
from compact JSON `[policy, comparison_name]`, not the current bare comparison
string. Preserve Unicode NFKC, apostrophe normalization, whitespace collapse,
case folding, empty-input rejection, lowercase SHA-256, and the existing ID
prefix.
5. Update registry validation and tests to prove the documented bytes, policy
namespace, deterministic IDs, uniqueness, concurrency safety, malformed-ID
rejection, and non-mutation. Update dependent fixtures to use newly derived
IDs rather than copied old digests.
6. Update the current `docs/integrations/dnd-npc-artifacts.md` in place so its
artifact kind, schema identity, Go-independent ID algorithm, and wire example
match this stage. It must continue to name `dnd/npcs` as the current producer
until Stage 2.
### Acceptance criteria
- No production Go code refers to `NPCList` or `NPCListKind`.
- The registered codec round-trips the strict `NPCRegistry` `v1` contract and
reports the target kind and schema identity.
- All current NPC-grounded consumers compile against `NPCRegistry` without
changing their reference-slot names yet.
- There is no compatibility alias or decoder for `dnd/npc-list` or
`notarius.dnd.npcs`.
### Validation
Run `gofmt` on every Go file changed in this stage, then run:
```sh
go test ./internal/modules/dnd/... ./internal/modules/integration/...
git diff --check
```
## Stage 2: Move The NPC Registry Module Into Its Canonical Namespace
### Goal
Rename the NPC registry's selectable modules, packages, prompts, assets,
validators, capabilities, and reference slots without changing the durable
record shape completed in Stage 1.
### Required changes
1. Move the stage packages to Go-compatible canonical paths:
`codec/npcregistry`, `extract/npcregistry`, `normalize/npcregistry`, and
`validate/npcregistry/...`. Domain helpers under `internal/modules/dnd/npcs`
may remain because they own NPC identity rather than a selectable module.
2. Set extract and normalize module keys to `dnd/npc-registry`. Rename all NPC
validator keys from `.../dnd/npcs/...` to `.../dnd/npc-registry/...`, and
rename the provided capability to `dnd.npc_registry`.
3. Move `assets/dnd/npcs/{extract,normalize}` to
`assets/dnd/npc-registry/{extract,normalize}`. Use prompt IDs
`dnd.npc_registry` and `dnd.npc_registry.normalize`; use private schema ID
`notarius.dnd.npc_registry.llm`, schema name
`notarius_dnd_npc_registry_llm_v1`, and filename
`dnd_npc_registry_llm.v1.json`.
4. Rename `common-dnd-npcs.md` to `common-dnd-npc-registry.md`. Change the
rendered PromptKit input and every module-facing reference slot from `npcs`
to `npc_registry` in spells, combat turns, the still-current NPC-interaction
modules, and enemy events. Preserve requiredness: optional for spell and
combat grounding, required where the current consumer already requires an
NPC registry.
5. Update immutable NPC registry projections to render ordered `{id, name}`
pairs where identity is required and the narrowest source-free name
projection where a consumer intentionally needs names only. Do not expose
registry source references to prompts.
6. Update central module, codec, merger, evidence, validator, default-chain,
prompt, and profile registration. Update the cross-lane prompt composition
test for the new prompt ID and `npc_registry` input without duplicating its
ordering assertions in module-local tests.
7. Rename the integration contract to
`docs/integrations/dnd-npc-registry-artifacts.md`, update inbound links, and
update the implemented module catalog, configuration reference, current
internal D&D guide, and maintained examples for the new key and slot.
8. Remove the old package trees, asset tree, prompt IDs, module/validator keys,
capability, shared filename, and reference-slot name. The durable JSON field
`npcs`, the record type `NPC`, and domain helper package name `npcs` are not
legacy module identifiers and should remain.
### Acceptance criteria
- `dnd/npc-registry` is the only selectable NPC registry extract/normalize key.
- All NPC-registry consumers expose `npc_registry` and accept only
`dnd/npc-registry` artifacts.
- Prompt and schema assets load only from `assets/dnd/npc-registry` and retain
the documented cache order.
- Current docs and examples contain no claim that `dnd/npcs` is selectable.
### Validation
```sh
go test ./internal/modules/dnd/... ./internal/modules/integration/... ./internal/cli/...
go run ./cmd/notarius config validate --config examples/dnd-minimal.config.yml --pipeline dnd-session
git diff --check
```
## Stage 3: Redesign The NPC Occurrence Durable Contract
### Goal
Replace the NPC-interaction value contract with the final registry-ID-backed
NPC occurrence contract while the selectable module temporarily remains
`dnd/npc-interactions`.
### Required changes
1. Replace `NPCInteractionListKind`, `NPCInteractionList`,
`NPCInteractionKind`, and `NPCInteraction` with `NPCOccurrenceListKind`,
`NPCOccurrenceList`, `NPCOccurrenceKind`, and `NPCOccurrence`. The envelope
field is `occurrences`; each record has required `npc_id`, `name`, `kind`,
and `source_refs`.
2. Retain the six existing category values and their precedence and splitting
semantics. Change only the contract vocabulary and registry identity link;
do not add relationship, sentiment, biography, or persistent-state fields.
3. In the current codec package, adopt `dnd/npc-occurrence-list`, durable schema
ID `notarius.dnd.npc_occurrences`, schema name
`notarius_dnd_npc_occurrences_v1`, and strict file
`dnd_npc_occurrences.v1.json`.
4. Change the current NPC-interaction private response contract to require
`npc_id` as well as `name`, `kind`, and `source_refs`. Use private schema ID
`notarius.dnd.npc_occurrences.llm`, schema name
`notarius_dnd_npc_occurrences_llm_v1`, and a renamed schema file even though
the prompt ID moves in Stage 4.
5. Project ordered `{id, name}` NPC registry entries into extraction. Require
the model to return an exact supplied pair. Extraction, normalization, and
registry validators must reject unknown IDs and mismatched ID/name pairs
rather than repairing by name similarity.
6. Update deterministic ordering, exact-duplicate identity, clone/evidence
helpers, merge functions, normalizers, validators, and diagnostics to include
`npc_id`. Preserve source chronology and distinct kinds/evidence.
7. Update enemy-event grounding to consume `NPCOccurrenceList`, filtering
`combat_opponent` occurrences while carrying only source-free grounding
values. Do not add NPC IDs to the enemy-event durable contract.
8. Update `docs/integrations/dnd-npc-interaction-artifacts.md` in place to the
new durable schema, root, and fields while accurately retaining the current
producer key until Stage 4.
### Acceptance criteria
- No production Go code refers to an `NPCInteraction*` artifact type.
- The durable artifact uses `occurrences` and validates exact NPC ID/name pairs.
- Unknown IDs and mismatches are detected independently at extraction,
normalization, and validation boundaries without mutation.
- Enemy-event grounding behavior remains source-free and category-filtered.
### Validation
```sh
go test ./internal/modules/dnd/codec/npcinteractions ./internal/modules/dnd/extract/npcinteractions ./internal/modules/dnd/normalize/npcinteractions ./internal/modules/dnd/validate/npcinteractions/... ./internal/modules/dnd/extract/enemyevents ./internal/modules/dnd/normalize/enemyevents
go test ./internal/modules/dnd/... ./internal/modules/integration/...
git diff --check
```
## Stage 4: Move NPC Occurrences Into Their Canonical Namespace
### Goal
Complete the NPC migration by replacing interaction module/package vocabulary
and updating the enemy-event dependency.
### Required changes
1. Move the codec, extract, normalize, validate, and D&D helper packages from
`npcinteractions` to `npcoccurrences` where they own the occurrence artifact.
2. Set extract and normalize keys to `dnd/npc-occurrences`; rename validator
keys and the provided capability to the `npc-occurrences`/
`dnd.npc_occurrences` vocabulary.
3. Move `assets/dnd/npc-interactions` to `assets/dnd/npc-occurrences`. Change the
extraction prompt ID to `dnd.npc_occurrences`, update instructions from
“interactions” to “occurrences” without changing category semantics, and
keep the target private schema identity established in Stage 3.
4. Rename the generated reference and PromptKit grounding input consumed by
enemy events from `npc_interactions` to `npc_occurrences`. Update combat
grounding assets, reference specs, fingerprint metadata, checkpoint inputs,
and tests consistently.
5. Update central registration, default validator chains, artifact evidence and
merge registration, prompt-cache tests, configuration keys, examples, and
current documentation.
6. Rename the integration contract to
`docs/integrations/dnd-npc-occurrence-artifacts.md` and update every link from
NPC registry, enemy event, combat, internal D&D, configuration, and JSON
output documentation.
7. Delete every old package, key, schema, prompt, capability, asset, and current-
behavior reference for `dnd/npc-interactions` and `npc_interactions`. Do not
retain a module alias.
### Acceptance criteria
- `dnd/npc-occurrences` is the only selectable NPC occurrence key.
- Enemy events require `npc_occurrences` of kind
`dnd/npc-occurrence-list`.
- Current catalogs, examples, and documentation use occurrence vocabulary.
- No production package or asset directory named `npcinteractions` or
`npc-interactions` remains.
### Validation
```sh
go test ./internal/modules/dnd/... ./internal/modules/integration/... ./internal/cli/...
OPENROUTER_API_KEY=validation-placeholder go run ./cmd/notarius config validate --config examples/dnd-complete.config.yml --pipeline dnd-session
git diff --check
```
## Stage 5: Migrate The Location Registry Durable Contract And Identity
### Goal
Adopt the final location registry type, artifact kind, schema identity, and
identity-policy namespace while the selectable module remains `dnd/locations`.
### Required changes
1. Replace `LocationListKind` and `LocationList` with `LocationRegistryKind` and
`LocationRegistry`. Retain `Location` and the durable `locations` root.
2. Update all typed location-registry consumers, especially location-occurrence
extraction, normalization, validation, reference resolution, merge, evidence,
registration, and tests. Do not leave aliases.
3. In the current location codec package, use kind `dnd/location-registry`,
schema ID `notarius.dnd.location_registry`, schema name
`notarius_dnd_location_registry_v1`, and strict file
`dnd_location_registry.v1.json`.
4. Change the identity policy to `dnd.location_registry.identity.v1` and retain
the exact compact JSON input `[policy, comparison_name, source_id,
start_unit_id, end_unit_id]`. Continue to select the earliest canonical
evidence anchor without mutating caller data. Accept the resulting pre-release
ID invalidation.
5. Update identity, registry, codec, same-name-location, normalization, and
dependent occurrence fixtures. Tests must prove same-name distinct anchors,
deterministic ordering, invalid component rejection, and exact documented
bytes.
6. Update `docs/integrations/dnd-location-artifacts.md` in place for the target
kind, schema, and identity policy while retaining `dnd/locations` as the
current module key until Stage 6.
### Acceptance criteria
- No production Go code refers to `LocationList` or `LocationListKind`.
- Same-name locations with distinct evidence anchors remain distinguishable.
- The codec and generated-reference compatibility use
`dnd/location-registry`.
- No old kind, schema identity, or identity-policy compatibility path remains.
### Validation
```sh
go test ./internal/modules/dnd/locations/... ./internal/modules/dnd/codec/locations ./internal/modules/dnd/extract/locations ./internal/modules/dnd/normalize/locations ./internal/modules/dnd/extract/locationoccurrences ./internal/modules/dnd/normalize/locationoccurrences ./internal/modules/dnd/validate/locations/... ./internal/modules/dnd/validate/locationoccurrences/...
go test ./internal/modules/dnd/... ./internal/modules/integration/...
git diff --check
```
## Stage 6: Move And Tighten The Location Registry Module
### Goal
Move location registry code and assets into the canonical namespace and enforce
the roadmap's named-or-uniquely-designated eligibility policy.
### Required changes
1. Move the stage packages to `codec/locationregistry`,
`extract/locationregistry`, `normalize/locationregistry`, and
`validate/locationregistry/...`. Entity identity and immutable registry
helpers may remain under `internal/modules/dnd/locations`.
2. Set extract and normalize keys to `dnd/location-registry`; rename validator
keys and the provided capability to `dnd.location_registry`.
3. Move `assets/dnd/locations/{extract,normalize}` to
`assets/dnd/location-registry/{extract,normalize}`. Use prompt IDs
`dnd.location_registry` and `dnd.location_registry.normalize`; use private
schema ID `notarius.dnd.location_registry.llm`, schema name
`notarius_dnd_location_registry_llm_v1`, and filename
`dnd_location_registry_llm.v1.json`.
4. Change the location-registry extraction instructions to accept only a stable
proper name or unique in-world designation. Explicitly exclude generic,
temporary, relative, and descriptive phrases such as `the room`, `the bar`,
`the hallway`, `outside`, and `upstairs`. Do not use capitalization as the
eligibility test and do not add a brittle deterministic word blacklist.
5. Rename the required location-occurrence reference slot and PromptKit input
from `locations` to `location_registry`. Preserve the ordered source-free
`{id, name}` projection and exact ID/name validation at extraction and
normalization.
6. Update location-occurrence instructions so a generic current-chunk phrase
may resolve to an existing named registry location only when context supports
that coreference; it may not create a registry entity or substitute registry
provenance for evidence.
7. Update central registration, prompt composition, validator chains,
configuration, examples, and current docs. Rename the integration contract
to `docs/integrations/dnd-location-registry-artifacts.md` and update links.
8. Remove old module/package/asset/prompt/validator/capability identities and
old reference-slot names. The durable `locations` field and domain helper
package remain valid.
### Acceptance criteria
- `dnd/location-registry` is the only selectable location registry key.
- Registry prompts exclude generic locations, while occurrence prompts permit
supported coreference to an existing registry entity.
- Location occurrences require `location_registry` of kind
`dnd/location-registry` at extract and normalize stages.
- No production compatibility alias for `dnd/locations` remains.
### Validation
```sh
go test ./internal/modules/dnd/... ./internal/modules/integration/... ./internal/cli/...
OPENROUTER_API_KEY=validation-placeholder go run ./cmd/notarius config validate --config examples/dnd-complete.config.yml --pipeline dnd-session
git diff --check
```
## Stage 7: Add The Item Registry Domain Foundation
### Goal
Implement the item registry's typed durable contract, deterministic identity,
codec, and immutable reference projection without registering a selectable
pipeline module yet.
### Required changes
1. Add `ItemRegistryKind`, `ItemRegistry`, and `Item` to the D&D domain types.
The strict envelope is `{"items":[...]}`; each item has required `id`,
`name`, and `source_refs`.
2. Add an item identity package under `internal/modules/dnd/items/identity`.
Implement comparison normalization consistent with the NPC identity text
family, policy `dnd.item_registry.identity.v1`, compact JSON
`[policy, comparison_name]`, prefix `item:sha256:`, syntax checks, registry
uniqueness validation, and deterministic errors.
3. Add immutable item registry resolution under
`internal/modules/dnd/items/registry`. It must decode through the canonical
codec, validate IDs, preserve same-name/type policy, return defensive copies,
and produce an ordered source-free `{id, name}` projection suitable for a
later reference slot.
4. Add `internal/modules/dnd/codec/itemregistry` with strict durable schema
`dnd_item_registry.v1.json`, ID `notarius.dnd.item_registry`, name
`notarius_dnd_item_registry_v1`, version `v1`, and media type
`application/json`.
5. Test codec round trips, strict unknown-field rejection, candidate encoding,
metadata, identity bytes, empty/malformed identities, duplicate IDs,
defensive copies, projection order, and non-mutation.
6. Do not register the codec or describe the item registry as selectable in
current configuration or integration docs yet. The feature roadmap remains
the canonical description until Stage 9.
### Acceptance criteria
- The new type, identity, codec, and registry packages pass independently.
- Item IDs are name/type identities rather than per-instance identities.
- The projection exposes IDs and names but no source references.
- No generic framework package depends on D&D item types.
### Validation
Run `gofmt` on every Go file changed in this stage, then run:
```sh
go test ./internal/modules/dnd/items/... ./internal/modules/dnd/codec/itemregistry
go test ./internal/modules/dnd/...
git diff --check
```
## Stage 8: Implement Item Registry Extraction And Validation
### Goal
Add the item-registry extraction module, private response contract, prompt
assets, canonical mapping, and extraction validators without production
registration.
### Required changes
1. Add `internal/modules/dnd/extract/itemregistry` with key
`dnd/item-registry`, artifact kind `dnd/item-registry`, LLM-backed execution,
the ordinary campaign reference slots, and prompt ID `dnd.item_registry`.
2. Add `assets/dnd/item-registry/extract` containing `prompt.yaml`, one coherent
`instructions.md`, and strict private schema `dnd_item_registry_llm.v1.json`
with ID `notarius.dnd.item_registry.llm` and name
`notarius_dnd_item_registry_llm_v1`. The private response contains required
item `name` and `source_refs`; deterministic code supplies source identity
and derives the durable item ID.
3. Encode the roadmap eligibility policy precisely: accept named unique items,
concrete reusable item types, stable unique designations, and separate
currency denominations; reject vague `loot`, `treasure`, `some gear`,
generic weapons, inferred properties, quantities, and uniqueness.
4. Reuse the shared extraction prompt prefix and evidence policy. Keep the item
registry instructions final and ephemeral. Do not add item occurrence,
holder, inventory, or ledger rules to this prompt.
5. Canonicalize display whitespace and evidence, derive IDs through the item
identity package, preserve candidate evidence for validation, and order
candidates deterministically. Do not semantically collapse aliases in the
extractor.
6. Add `validate/itemregistry/shape`, `source_refs`, and
`source_relatedness` packages and keys using the final module vocabulary.
Keep relatedness advisory according to existing D&D conventions.
7. Add focused behavior, schema, prompt preparation, metadata-redaction,
cancellation/error, and validator tests. Do not call a live model and do not
snapshot full prompt text.
8. Do not add the module to the production D&D registrar until its normalizer
and complete default chains exist in Stage 9.
### Acceptance criteria
- Direct module construction prepares and maps a strict item-registry response.
- Currency denominations and reusable item types are eligible; vague categories
are excluded by prompt policy without a capitalization heuristic.
- Extracted records contain deterministic IDs and owned evidence slices.
- No current module catalog advertises an incomplete lane.
### Validation
```sh
go test ./internal/modules/dnd/extract/itemregistry ./internal/modules/dnd/validate/itemregistry/...
go test ./internal/modules/dnd/...
git diff --check
```
## Stage 9: Implement Item Registry Normalization And Production Registration
### Goal
Complete and register the item registry as the third production registry
family.
### Required changes
1. Add `internal/modules/dnd/normalize/itemregistry` with key
`dnd/item-registry`, LLM-backed execution, prompt ID
`dnd.item_registry.normalize`, and the same retry/fallback contract used by
NPC and location registry normalization.
2. Deterministically preprocess candidate names, evidence, IDs, and exact
duplicates. Then use the existing shared D&D entity-reconciliation proposal
mechanics with item-specific candidates and selected transcript windows.
Validated groups may choose one supplied canonical display name and union
evidence; unsafe, overlapping, unknown, or uncertain groups preserve the
deterministic result with bounded diagnostics.
3. Add `assets/dnd/item-registry/normalize` with `prompt.yaml`,
`instructions.md`, and `candidates.md`. Item instructions own only same-item-
kind/designation judgment and canonical display preference. The shared
reconciliation fragment alone owns opaque keys and safe group mechanics.
4. Explicitly prevent reconciliation across currency denominations, materially
different item types, or merely nearby objects. Do not create per-instance
identities or infer properties.
5. Add `validate/itemregistry/identity` and its default normalize-chain position.
Test retry, invalid structured output, operational error, warning bounds,
idempotence, order, non-mutation, and content-safe diagnostics.
6. Register the item registry codec, evidence projection, append-order merger,
extractor, normalizer, validators, default chains, prompt assets, and module
metadata in the D&D registrar. Add it to the centralized extraction prompt
composition test.
7. Create the current durable contract at
`docs/integrations/dnd-item-registry-artifacts.md`. Update configuration and
internal module catalogs enough to describe the now-selectable registry,
but defer the complete multi-step example until item occurrences consume it.
### Acceptance criteria
- `dnd/item-registry` is selectable for extraction and normalization with
complete production validator chains.
- The normalizer uses proposal-only LLM semantics and deterministic application.
- Codec, merge, evidence, prompt, metadata, and registry registrations are all
type-compatible.
- The current docs accurately describe the implemented item registry without
claiming that item occurrences consume it yet.
### Validation
```sh
go test ./internal/modules/dnd/items/... ./internal/modules/dnd/codec/itemregistry ./internal/modules/dnd/extract/itemregistry ./internal/modules/dnd/normalize/itemregistry ./internal/modules/dnd/validate/itemregistry/... ./internal/modules/dnd/register
go test ./internal/modules/dnd/... ./internal/cli/...
git diff --check
```
## Stage 10: Redesign Item Events As Registry-Backed Item Occurrences
### Goal
Adopt the final item occurrence durable contract and required item-registry
grounding while the selectable module temporarily remains `dnd/item-events`.
### Required changes
1. Replace `ItemEventListKind`, `ItemEventList`, `ItemEventKind`, and `ItemEvent`
with `ItemOccurrenceListKind`, `ItemOccurrenceList`, `ItemOccurrenceKind`,
and `ItemOccurrence`. Use durable root `occurrences`; each record has required
`item_id`, `name`, `kind`, and `source_refs`, plus conditional `quantity`,
`from`, and `to`.
2. Preserve the five existing kinds and all holder, quantity, currency,
ordering, and exact-duplicate semantics. Rename the D&D helper behavior to
occurrence vocabulary in code, but defer physical package moves to Stage 11.
3. In the current codec package, adopt kind `dnd/item-occurrence-list`, schema
ID `notarius.dnd.item_occurrences`, schema name
`notarius_dnd_item_occurrences_v1`, and strict file
`dnd_item_occurrences.v1.json`.
4. Change the private response schema to
`notarius.dnd.item_occurrences.llm`/
`notarius_dnd_item_occurrences_llm_v1` in
`dnd_item_occurrences_llm.v1.json`. Require every property. Represent absent
`quantity`, `from`, and `to` as nullable private fields and map them to the
durable conditional fields without fabricating values.
5. Add required `item_registry` reference slots to both extraction and
normalization, accepting only `dnd/item-registry`, `application/json`, and an
explicit size bound. Resolve one immutable registry per operation and render
ordered source-free `{id, name}` entries after the shared evidence message.
6. Require the model to return an exact registry ID/name pair. Extraction must
reject or omit unknown/mismatched pairs without creating an item. The
deterministic normalizer must canonicalize recognized names by ID and retain
unknown values for the registry validator to reject according to the current
validation architecture.
7. Add a registry membership validator to the item occurrence extract and
normalize chains. Update shape, invariant, source-reference, relatedness,
merge, evidence, clone, metadata, warning, and ordering behavior for
`item_id` and the new envelope.
8. Update the maintained complete example immediately: produce
`dnd/item-registry` in the earlier registry step and bind its generated
artifact as `item_registry` to the still-current `dnd/item-events` extract
and normalize stages. Keep the example valid at the end of this stage.
9. Update `docs/integrations/dnd-item-event-artifacts.md` in place to the target
durable shape and required registry behavior while retaining the current
producer key until Stage 11.
### Acceptance criteria
- No production Go code uses an `ItemEvent*` artifact type.
- Every item occurrence carries an exact item-registry ID/name pair.
- Extraction and normalization both declare the identical required registry
slot; validation detects unknown and mismatched identities.
- The complete example resolves with an earlier item registry and no same-step
dependency.
### Validation
```sh
go test ./internal/modules/dnd/itemevents ./internal/modules/dnd/codec/itemevents ./internal/modules/dnd/extract/itemevents ./internal/modules/dnd/normalize/itemevents ./internal/modules/dnd/validate/itemevents/... ./internal/modules/dnd/register ./internal/modules/integration/...
OPENROUTER_API_KEY=validation-placeholder go run ./cmd/notarius config validate --config examples/dnd-complete.config.yml --pipeline dnd-session
git diff --check
```
## Stage 11: Move Item Occurrences Into Their Canonical Namespace
### Goal
Complete the item migration by replacing item-event module, package, prompt,
validator, asset, and documentation vocabulary.
### Required changes
1. Move `internal/modules/dnd/itemevents` to `itemoccurrences` and move codec,
extract, normalize, and validate packages to the corresponding
`itemoccurrences` paths.
2. Set extract and normalize keys to `dnd/item-occurrences`; rename validator
keys and the provided capability to `dnd.item_occurrences`.
3. Move `assets/dnd/item-events` to `assets/dnd/item-occurrences`. Use prompt ID
`dnd.item_occurrences`, the target private schema identity from Stage 10, and
occurrence terminology throughout module instructions.
4. Update all imports, central registrations, default chains, metadata,
fingerprints, prompt composition cases, configuration keys, example lanes,
generated references, output expectations, and tests.
5. Rename the integration contract to
`docs/integrations/dnd-item-occurrence-artifacts.md` and update links from
item registry, configuration, internal D&D, and JSON output documentation.
6. Delete every old `itemevents`, `item-events`, `dnd/item-events`,
`dnd.item_events`, `notarius.dnd.item_events`, `events`-envelope fixture, and
old schema/asset path that represented the retired artifact. Do not remove
unrelated uses of the ordinary word “event” in other D&D lanes.
### Acceptance criteria
- `dnd/item-occurrences` is the only selectable item occurrence key.
- All item occurrence packages, prompts, validators, schemas, and docs use the
canonical vocabulary.
- The complete example binds `item_registry` into both stages of the renamed
lane.
- No compatibility alias for item events remains.
### Validation
```sh
go test ./internal/modules/dnd/... ./internal/modules/integration/... ./internal/cli/...
OPENROUTER_API_KEY=validation-placeholder go run ./cmd/notarius config validate --config examples/dnd-complete.config.yml --pipeline dnd-session
git diff --check
```
## Stage 12: Verify The Complete Ordered Entity Pipeline
### Goal
Make the maintained complete configuration and representative integration tests
prove the final three-registry/three-occurrence architecture.
### Required changes
1. Finalize `examples/dnd-complete.config.yml` with an earlier registry step
containing `npc-registry`, `location-registry`, and `item-registry` lanes
alongside scene descriptions. The next step contains NPC, location, and item
occurrences plus spell and combat lanes. The derived enemy step consumes
`npc_registry`, `npc_occurrences`, combat turns, and scene descriptions.
2. Use generated-reference aliases `npc_registry`, `location_registry`,
`item_registry`, and `npc_occurrences`. Preserve explicit step-and-lane
selectors and stage-local spell-catalog bindings. Do not infer dependencies
from matching names.
3. Update scene-plan eligibility configuration for all renamed lane labels while
preserving the shared chunk plan and exact combat-scene routing semantics.
4. Add or revise one representative integration workflow that executes the
ordered handoffs with deterministic fake LLM responses and proves exact
artifact-kind compatibility, registry projection, independent occurrence
evidence, and final publication for all three entity families.
5. Test compatible external path references for each registry through existing
reference preparation. Do not duplicate the framework's exhaustive topology
and failure-propagation cases; add only D&D-specific compatibility coverage.
6. Test rejection of a wrong registry artifact kind and invalid same-step or
forward binding at the existing resolver/integration boundary if those risks
are not already credibly covered with the new kinds.
7. Update CLI maintained-example contract tests and production catalog tests so
both D&D examples load, validate, resolve, and list only implemented module
and validator identities.
### Acceptance criteria
- The complete example validates offline and resolves all generated handoffs.
- A representative assembled run proves all three registry-to-occurrence paths.
- External compatible registry artifacts remain supported.
- Cross-family integration tests protect compatibility without repeating
package-level identity and validator cases.
### Validation
```sh
go test ./internal/modules/integration/... ./internal/cli/... ./internal/modules/dnd/register
go run ./cmd/notarius config validate --config examples/dnd-minimal.config.yml --pipeline dnd-session
OPENROUTER_API_KEY=validation-placeholder go run ./cmd/notarius config validate --config examples/dnd-complete.config.yml --pipeline dnd-session
git diff --check
```
## Stage 13: Consolidate Current Documentation And Examples
### Goal
Bring every canonical current-behavior document into alignment with the final
implemented entity family without duplicating contracts across documents.
### Required changes
1. Update `docs/config.md` as the canonical owner of selectable module keys,
validator keys, default chains, reference slots, requiredness, size limits,
execution classes, profile behavior, and ordered binding examples.
2. Update `docs/internal/dnd.md` for ten final D&D artifact lanes, the three
registry normalizers, source-free ID/name projections, occurrence grounding,
package/asset ownership, and lane-specific differences. Link to integration
contracts instead of repeating their schemas or categories.
3. Update `docs/internal/modules.md`, `docs/internal/overview.md`, README, CLI,
operations, JSON output, and other current documents only where they actually
name affected modules, artifacts, examples, or links. Preserve each
document's canonical scope under the documentation policy.
4. Ensure the six target integration contracts are the only canonical durable
entity contracts:
`dnd-npc-registry-artifacts.md`, `dnd-npc-occurrence-artifacts.md`,
`dnd-location-registry-artifacts.md`,
`dnd-location-occurrence-artifacts.md`,
`dnd-item-registry-artifacts.md`, and
`dnd-item-occurrence-artifacts.md`.
5. Each integration contract must define its exact kind, schema ID/name/version,
media type, strict wire shape, identity or occurrence policy, evidence
boundary, normalization behavior, consumers, and compatibility statement.
Cross-link rather than copying common reference or output semantics.
6. Verify that only `examples/dnd-minimal.config.yml` and
`examples/dnd-complete.config.yml` remain as maintained D&D configurations,
that both are secret-free, and that documentation links to rather than
reproduces them.
7. Keep future or historical discussion in `docs/roadmap/` and ADRs. Do not
rewrite accepted ADRs as current reference documentation, add a changelog,
or delete the active roadmap files.
### Acceptance criteria
- Current docs contain only implemented final names and contracts.
- Each volatile fact has one canonical owner and all links resolve.
- Maintained examples are valid, copyable, and tested.
- No documentation claims compatibility with the retired pre-release names.
### Validation
```sh
go test ./internal/cli/... ./internal/modules/integration/...
go run ./cmd/notarius config validate --config examples/dnd-minimal.config.yml --pipeline dnd-session
OPENROUTER_API_KEY=validation-placeholder go run ./cmd/notarius config validate --config examples/dnd-complete.config.yml --pipeline dnd-session
git diff --check
```
## Stage 14: Final Contract Audit And Repository Verification
### Goal
Perform a final gap audit, remove stale implementation remnants, and prove the
completed feature at repository scope.
### Required changes
1. Search production code, assets, tests, examples, and current documentation
for retired exact identities, including:
`dnd/npcs`, `dnd/npc-interactions`, `dnd/locations`, `dnd/item-events`,
`dnd/npc-list`, `dnd/npc-interaction-list`, `dnd/location-list`,
`dnd/item-event-list`, old schema IDs/names, old prompt IDs, old capability
names, `common-dnd-npcs.md`, and old reference-slot names. Exclude
`docs/roadmap/`, where migration context intentionally names the old values.
2. Search for retired Go artifact identifiers `NPCList`, `NPCInteraction`,
`LocationList`, and `ItemEvent`. Distinguish legitimate words or unrelated
concepts from compatibility remnants; remove every actual old contract or
alias.
3. Verify the final package and asset trees contain only canonical registry and
occurrence stage packages. Confirm every D&D prompt subtree has
`prompt.yaml` and `instructions.md`, manifests select only existing assets,
and all prompt/schema fingerprints are content-safe.
4. Verify every private D&D response schema has `additionalProperties: false`,
includes every declared property in `required`, and uses the exact final
private identity. Verify durable schemas independently through their codecs;
do not conflate private and durable contracts.
5. Review default validator chains for all six entity modules. Each registry
must have shape, identity, source-reference, schema, and relatedness coverage;
each occurrence must additionally enforce exact registry membership and
domain invariants at the appropriate stages.
6. Review tests against `docs/policy/testing.md`. Consolidate redundant
cross-layer assertions, retain regression coverage for identities and
handoffs, and do not add asset inventories or exact prefix-length detectors.
7. Run repository-wide tests, vet, build, example validation, and whitespace
checks. Fix any defect discovered; do not merely document it as follow-up if
it is within this roadmap's scope.
8. Report any optional live-model observations separately. Live model quality
is useful human evaluation but is not a credentialed automated acceptance
gate and must not block deterministic completion.
### Acceptance criteria
- The target end state in `entity-registries.md` is fully implemented.
- No production compatibility alias or stale current-behavior name remains.
- All six entity modules register with exact typed contracts and default chains.
- Both maintained configurations validate offline.
- The full repository test, vet, and build checks pass with a clean diff check.
### Validation
```sh
go test -count=1 ./...
go vet ./...
go build ./cmd/notarius
go run ./cmd/notarius config validate --config examples/dnd-minimal.config.yml --pipeline dnd-session
OPENROUTER_API_KEY=validation-placeholder go run ./cmd/notarius config validate --config examples/dnd-complete.config.yml --pipeline dnd-session
git diff --check
```