From 916a32195b8b3780dc116dc0609f441c27c1cf14 Mon Sep 17 00:00:00 2001 From: Eric Rakestraw Date: Wed, 5 Aug 2026 18:16:37 +0000 Subject: [PATCH] Plan canonical D&D entity registries and occurrences --- docs/roadmap/entity-registries.md | 503 ++++++++++++ docs/roadmap/future.md | 44 +- docs/roadmap/implementation.md | 1234 +++++++++++++++++------------ docs/roadmap/prompts.md | 463 ----------- 4 files changed, 1248 insertions(+), 996 deletions(-) create mode 100644 docs/roadmap/entity-registries.md delete mode 100644 docs/roadmap/prompts.md diff --git a/docs/roadmap/entity-registries.md b/docs/roadmap/entity-registries.md new file mode 100644 index 0000000..9742ec8 --- /dev/null +++ b/docs/roadmap/entity-registries.md @@ -0,0 +1,503 @@ +# Canonical D&D Entity Registries And Occurrences + +## Purpose + +This roadmap defines the target state for D&D entity extraction in Notarius. +NPCs, locations, and items should follow one legible architecture: a registry +lane first identifies canonical entities, and a later occurrence lane consumes +that registry to extract independently evidenced facts about those entities. + +The work is a clean pre-release contract redesign. It should remove the current +mixture of bare plural, interaction, occurrence, and event terminology; add the +missing item registry; tighten entity eligibility; and make generated-reference +relationships visible in module, artifact, schema, prompt, validation, example, +and documentation names. + +This roadmap owns the desired behavior and policy. The +[implementation plan](implementation.md) owns sequencing and task breakdowns. + +## Background + +Notarius already implements most of the required platform mechanics: + +- ordered pipeline steps create a barrier between registry production and + occurrence extraction; +- generated artifact references are validated for topology, media type, + artifact kind, schema, and codec compatibility before execution; +- NPC and location registries have deterministic identities and bounded + LLM-assisted reconciliation; +- NPC interactions and location occurrences consume normalized registry + artifacts as source-free grounding; and +- validators keep registry provenance separate from occurrence evidence. + +The remaining D&D domain contracts are inconsistent: + +- `dnd/npcs` produces a registry, but its name does not communicate that role; +- `dnd/npc-interactions` is an occurrence lane under a narrower name; +- `dnd/locations` produces a registry while `dnd/location-occurrences` already + uses the desired downstream terminology; +- `dnd/item-events` extracts occurrences directly and has no canonical item + registry; and +- current location eligibility permits generic labels that are not suitable + canonical nouns for reuse by downstream consumers. + +[ADR-0009](../adr/0009-minimal-evidence-grounded-extraction-artifacts.md) +already establishes that changing encounter-level facts belong in occurrence +artifacts rather than registry attributes. [ADR-0008](../adr/0008-ordered-pipeline-steps.md) +already establishes explicit ordered artifact handoffs. This feature applies +those decisions consistently; it does not change the platform architecture. + +## Goals + +The completed feature should: + +- make registry producers and occurrence consumers immediately recognizable by + their names; +- provide registry and occurrence lanes for NPCs, locations, and items; +- require every entity occurrence to resolve to one canonical registry ID and + display name; +- tighten registry eligibility so entries are stable nouns or designations + that a downstream consumer can reuse; +- preserve minimal, evidence-grounded durable artifacts; +- keep registry provenance distinct from occurrence evidence; +- use ordered generated references rather than inferred dependencies; +- preserve domain-specific occurrence categories and identity rules where the + entity types genuinely differ; +- use a clean pre-release migration with no aliases or compatibility shims; and +- leave the codebase with three concrete registry implementations from which a + later generic deduplication design can be evaluated. + +## Non-Goals + +This work does not introduce: + +- a general workflow DAG or implicit dependency inference; +- a generic framework-level LLM deduplication module; +- campaign-wide or cross-run registries; +- an inventory, currency balance, possession ledger, or current-state model; +- item-instance tracking for interchangeable objects; +- narrative descriptions, biographies, relationships, ownership summaries, or + other enrichment on registry entries; +- occurrence-derived attributes copied back onto registry entries; +- NPC IDs on spell, combat-turn, or enemy-event artifacts merely because those + lanes consume NPC grounding; +- migration tooling for old checkpoints or durable artifacts; or +- compatibility aliases for retired module keys, artifact kinds, prompt IDs, + reference slots, schemas, or validator keys. + +## Canonical Naming + +### Modules + +Registry extractors and their matching normalizers use +`dnd/-registry`. Occurrence extractors and their matching +normalizers use `dnd/-occurrences`. + +| Role | Current module key | Target module key | +| --- | --- | --- | +| NPC registry | `dnd/npcs` | `dnd/npc-registry` | +| NPC occurrences | `dnd/npc-interactions` | `dnd/npc-occurrences` | +| Location registry | `dnd/locations` | `dnd/location-registry` | +| Location occurrences | `dnd/location-occurrences` | `dnd/location-occurrences` | +| Item registry | none | `dnd/item-registry` | +| Item occurrences | `dnd/item-events` | `dnd/item-occurrences` | + +The same key is used for a lane's extract and normalize modules, as it is for +other current D&D lanes. Stage identity continues to distinguish those module +registrations. + +### Durable artifacts + +Registry artifact kinds name the registry directly. Occurrence artifact kinds +retain the `-list` suffix because their durable value is an ordered collection +of independently evidenced observations. + +| Role | Target artifact kind | Target schema ID | Root collection | +| --- | --- | --- | --- | +| NPC registry | `dnd/npc-registry` | `notarius.dnd.npc_registry` | `npcs` | +| NPC occurrences | `dnd/npc-occurrence-list` | `notarius.dnd.npc_occurrences` | `occurrences` | +| Location registry | `dnd/location-registry` | `notarius.dnd.location_registry` | `locations` | +| Location occurrences | `dnd/location-occurrence-list` | `notarius.dnd.location_occurrences` | `occurrences` | +| Item registry | `dnd/item-registry` | `notarius.dnd.item_registry` | `items` | +| Item occurrences | `dnd/item-occurrence-list` | `notarius.dnd.item_occurrences` | `occurrences` | + +All redesigned durable schemas remain version `v1`. Notarius is pre-release, +and these names replace rather than version or alias the retired contracts. +Schema names should follow the corresponding underscore form, such as +`notarius_dnd_item_registry_v1`. + +Canonical Go types, codec packages, validator packages, prompt IDs, private +response-schema identities, capability names, and asset subtrees should use the +same registry/occurrence vocabulary. Prompt IDs should be +`dnd._registry`, `dnd._registry.normalize`, and +`dnd._occurrences` as applicable. + +The corresponding durable integration contracts should be: + +- `docs/integrations/dnd-npc-registry-artifacts.md`; +- `docs/integrations/dnd-npc-occurrence-artifacts.md`; +- `docs/integrations/dnd-location-registry-artifacts.md`; +- `docs/integrations/dnd-location-occurrence-artifacts.md`; +- `docs/integrations/dnd-item-registry-artifacts.md`; and +- `docs/integrations/dnd-item-occurrence-artifacts.md`. + +Those documents will become canonical only when the contracts are implemented; +until then, this roadmap is the sole owner of the proposed names and behavior. + +### References + +Registry-consuming modules expose explicit reference slots named: + +- `npc_registry`; +- `location_registry`; and +- `item_registry`. + +Generated-reference aliases in maintained examples should use those same names. +The reference slot, not a matching lane label, owns dependency resolution. Each +slot accepts only the corresponding registry artifact kind and media type and +retains an explicit size bound. + +Existing NPC-grounded consumers such as spells, combat turns, enemy events, and +NPC occurrences should use `npc_registry`. Location occurrences should use +`location_registry`, and item occurrences should require `item_registry` at +both extraction and normalization. + +## Registry Contract + +Every registry answers one narrow question: which reusable canonical entities +of this type are established by the current transcript? + +Each registry record contains only: + +- a deterministic application-owned `id`; +- a canonical display `name`; and +- one or more transcript `source_refs` establishing the entity identity. + +Registries do not contain encounter roles, occurrence categories, descriptions, +summaries, aliases, relationships, inventories, holder state, or inferred +attributes. Their source references establish registry provenance only. + +Registry extraction remains chunk-scoped. Merge and normalization combine +candidate records across chunks, canonicalize evidence in source-document +order, apply deterministic identity rules, and may use a bounded structured-LLM +proposal to reconcile semantic duplicates. The model proposes duplicate groups; +deterministic code validates keys, membership, overlap, canonical selection, +and application. Invalid or uncertain proposals preserve the safe deterministic +result and produce bounded diagnostics. + +The existing shared D&D entity-reconciliation substrate should support all +three registries. Entity-specific candidate construction, identity judgment, +canonical-name preference, and consolidation remain in the owning D&D module. +This feature must not move D&D policy into generic framework packages. + +## Entity Eligibility And Identity + +Eligibility is based on whether the transcript establishes a stable reusable +referent, not on capitalization alone. Transcript capitalization is unreliable, +and a capitalized generic phrase is not automatically a canonical entity. + +### NPC registry + +Include an NPC when the transcript establishes an individually identifiable +non-player character through a proper name or a stable unique designation. A +title or descriptive designation qualifies only when the transcript uses it as +a persistent identity, such as `the Masked Envoy`; a transient generic role +such as `a guard`, `the bartender`, or `one of the bandits` does not qualify. + +Exclude player characters, speakers known only by player identity, anonymous +groups, creature categories, generic roles, speculative identities, and labels +invented merely to make an occurrence referable. + +NPC IDs use the `npc:sha256:` prefix and identity policy +`dnd.npc_registry.identity.v1`. The digest is the lowercase SHA-256 of compact +JSON for `[policy, comparison_name]`, where the comparison name uses the +existing Unicode, apostrophe, whitespace, and case normalization. Semantic +reconciliation may collapse supported aliases but may not merge distinct people +merely because their names or roles are similar. + +### Location registry + +Include a location only when the transcript establishes a stable proper name or +unique in-world designation, such as `Waterdeep`, `The Yawning Portal`, or a +uniquely named chamber. Exclude generic, temporary, relative, or purely +descriptive references such as `the room`, `the bar`, `the hallway`, `outside`, +or `upstairs`. + +A later occurrence may resolve a generic phrase such as `the bar` to an existing +named registry location when the current transcript context supports that +coreference. The generic phrase must not create a new registry entry. + +Location IDs use the `location:sha256:` prefix and identity policy +`dnd.location_registry.identity.v1`. The digest is the lowercase SHA-256 of +compact JSON for `[policy, comparison_name, source_id, start_unit_id, +end_unit_id]`, using the earliest canonical evidence anchor. Source anchoring +keeps distinct places with the same display name distinguishable. Nested places +and same-name places remain distinct unless a validated semantic proposal +establishes that candidates identify the same physical place. + +### Item registry + +Items do not need proper names. Include a reusable, transcript-established item +name at the narrowest useful type or unique-designation level, including: + +- named unique objects; +- concrete item types such as `Healing Potion` when the transcript establishes + that type; +- stable unique designations used by the session; and +- individual currency denominations such as `Silver Pieces`. + +Exclude vague or non-reusable descriptions such as `loot`, `treasure`, `some +gear`, `a weapon`, or `something valuable` unless the transcript supplies a +more stable name or designation. Do not infer mechanical subtype, magic +properties, denomination, quantity, or uniqueness. + +An item-registry record identifies a canonical item kind or designation, not a +physical instance. Interchangeable objects with the same canonical name share +one registry identity and are distinguished in occurrences by evidence, +quantity, and holder transitions. A genuinely named unique object naturally +has its own canonical identity. + +Item IDs use the `item:sha256:` prefix and identity policy +`dnd.item_registry.identity.v1`. The digest is the lowercase SHA-256 of compact +JSON for `[policy, comparison_name]`, using the same text normalization family +as other entity registries. Item normalization may reconcile transcript- +supported aliases and abbreviation variants but may not collapse distinct +denominations or materially different item types. + +## Occurrence Contract + +Every occurrence answers a separate question: what source-grounded event or +relationship to a known registry entity occurred in this transcript passage? + +Each occurrence record contains: + +- the exact entity ID from its required registry; +- the exact canonical display name associated with that ID; +- one bounded occurrence kind; and +- one or more source references from the current transcript. + +Entity-specific fields are allowed only when required by that occurrence +contract. Registry IDs and names provide grounding; registry source references +never become occurrence evidence. Unknown IDs and mismatched ID/name pairs are +rejected rather than guessed, reassigned, or repaired from display-name +similarity. + +Occurrence extractors may resolve an alias, pronoun, generic reference, or +abbreviation to an existing registry entry only when the current chunk supports +that coreference. They may not add entities to the registry. Omit an occurrence +when entity resolution or the occurrence itself is not adequately supported. + +Occurrence normalization is deterministic. It validates registry membership, +canonicalizes the display name from the registry, orders and deduplicates source +references, preserves distinct observations, orders records by source-document +chronology and stable domain tie-breakers, and collapses only exact duplicates. + +### NPC occurrences + +The durable record contains required `npc_id`, `name`, `kind`, and +`source_refs`. It retains the current interaction categories: + +- `mentioned`; +- `noncombat_presence`; +- `dialogue`; +- `combat_ally`; +- `combat_opponent`; and +- `other`. + +The precedence and splitting rules of the current NPC-interaction contract +remain applicable. Renaming the artifact does not turn it into a biography, +relationship model, sentiment analysis, or persistent NPC state. + +Enemy-event grounding consumes `combat_opponent` NPC occurrences under the new +contract. Other NPC-grounded lanes continue to consume the registry directly. + +### Location occurrences + +The durable record continues to contain required `location_id`, `name`, `kind`, +and `source_refs`. It retains the current categories and precedence: + +- `visited`; +- `planned`; +- `recalled`; and +- `mentioned`. + +Generic current-chunk language may resolve to a named registry location, but +the occurrence must cite the current transcript passage that supports both the +resolution and the occurrence category. + +### Item occurrences + +The durable record contains required `item_id`, `name`, `kind`, and +`source_refs`, plus the current semantically conditional `quantity`, `from`, +and `to` fields. It retains the current categories: + +- `discovered`; +- `acquired`; +- `lost`; +- `consumed`; and +- `transferred`. + +Holder and quantity rules remain unchanged: discovery has no holder; acquisition +requires a gaining holder; loss and consumption require a losing holder; and +transfer requires distinct losing and gaining holders. Currency remains an +ordinary item occurrence with an explicit denomination and a quantity only +when the transcript establishes one. + +Item occurrences do not compute inventory, merge successive state changes, +convert denominations, infer unspoken holders, or distinguish physical +instances that the transcript does not identify. + +Private LLM response schemas should remain strict and compatible with providers +that require every declared property to be required. Nullable or explicit +absence representations may be used privately for semantically conditional +item fields; deterministic mapping owns omission from the durable artifact when +the public contract calls for an absent field. + +## Pipeline End State + +A complete D&D pipeline produces all three registries in an earlier step and +binds them explicitly into later consumers. Conceptually: + +```text +registry step + npc-registry + location-registry + item-registry + scene-descriptions + +occurrence and action step + npc-occurrences <- npc-registry + location-occurrences <- location-registry + item-occurrences <- item-registry + spells <- optional npc-registry + combat-turns <- optional npc-registry + required scene descriptions + +derived enemy step + enemy-events <- npc-registry + npc-occurrences + combat turns + scene descriptions +``` + +Steps remain barriers with the existing whole-run failure behavior. A required +registry producer that fails, rejects, or does not publish an accepted +normalized artifact prevents its dependent later step and fails the run under +the existing ordered-pipeline contract. Configuration with a same-step or +forward generated reference remains invalid. + +The maintained complete D&D example should use generated references for these +same-run handoffs. Registry slots continue to accept compatible external path +references under the existing configuration contract; this feature does not +remove the ability to supply a previously produced or independently maintained +registry artifact. + +The shared scene plan remains pipeline-wide. This feature changes eligible +lanes and reference bindings, not chunking or scheduling semantics. + +## Validation And Normalization + +Each registry receives production defaults for: + +- JSON and durable-schema validity; +- registry shape and required evidence; +- deterministic identity and uniqueness; +- source-reference validity; +- source relatedness; and +- safe bounded reconciliation during normalization. + +Each occurrence family receives production defaults for: + +- JSON and durable-schema validity; +- occurrence shape and kind-specific invariants; +- exact registry ID/name membership; +- source-reference validity; +- source relatedness; and +- deterministic ordering and exact-duplicate removal. + +Validator and capability keys should adopt the new module vocabulary. Registry +membership validators consume the same immutable registry projection used by +the extractor and normalizer. Validators do not use registry provenance as a +substitute for occurrence evidence and do not mutate supplied artifacts or +references. + +Warnings remain bounded, content-safe, and deterministic. Prompt, schema, +registry, and identity fingerprints remain represented by hashes or stable +identities rather than raw content in manifests and diagnostics. + +## Package And Asset Organization + +Implementation packages should make the two roles visible, using Go-compatible +names such as `npcregistry`, `npcoccurrences`, `locationregistry`, and +`itemoccurrences` beneath the existing extract, normalize, codec, and validate +families. Entity-specific identity and immutable registry-resolution helpers +remain inside the D&D domain. + +LLM assets should use corresponding subtrees beneath `assets/dnd/`, for example +`assets/dnd/npc-registry/{extract,normalize}` and +`assets/dnd/item-occurrences`. The root `assets` package remains a single-file, +content-only filesystem boundary with no business logic, registration, or +PromptKit dependency. + +All extraction prompts retain the shared D&D prompt prefix and chunk scope. +Registry prompts own only entity eligibility and canonical-name policy; +occurrence prompts own only occurrence semantics and entity-specific fields. +Registry input fragments own the meaning of their source-free projections. + +## Migration Policy + +The redesign is intentionally breaking and immediate: + +- remove retired module and validator keys; +- remove retired artifact kinds, schema IDs, schema names, Go types, prompt IDs, + private schema identities, reference slots, capability names, asset paths, + and generated-reference aliases; +- do not register aliases or decode old shapes; +- do not retain duplicate integration documents for old contracts; and +- accept invalidation of old checkpoints, prompt fingerprints, provider caches, + example output, and other reconstructible pre-release state. + +New contracts use version `v1`; `v2` does not communicate useful compatibility +information while there is no supported release to preserve. Current-behavior +documentation, maintained examples, module catalogs, and integration contracts +must change atomically with implementation. + +## Evaluation Expectations + +Implementation should be assessed against representative transcript cases that +cover: + +- named NPCs, stable NPC designations, transient roles, aliases, and anonymous + groups; +- named locations, same-name locations, nested locations, generic spatial + phrases, and supported generic coreferences to named places; +- named items, ordinary item types, ambiguous descriptions, aliases, quantities, + transfers, consumption, and each currency denomination; +- registry candidates mentioned across multiple chunks; +- unsupported occurrence links and mismatched registry ID/name pairs; and +- output from cost-effective smaller models as well as the default production + profile. + +Deterministic tests should protect schemas, identity rules, registry resolution, +reference compatibility, ordering, validation, normalization, and assembled +multi-step configuration. Live model quality remains an opt-in human evaluation +activity rather than a default automated gate. + +## Target End State + +The feature is complete when: + +- the six canonical entity modules are the only selectable NPC, location, and + item registry/occurrence modules; +- all six durable artifacts use the target kinds, schema identities, root + collections, minimal record shapes, and `v1` contracts defined here; +- every occurrence contains and validates an exact registry ID/name pair; +- NPC, location, and item registry eligibility follows the policies above; +- the maintained complete pipeline uses explicit generated registry references + across ordered steps, while compatible external registry references remain + supported; +- item occurrences no longer run independently of an accepted item registry; +- spell, combat, enemy, and occurrence consumers use the renamed registry slots + without treating registry provenance as evidence; +- current module catalogs, default validator chains, prompts, assets, examples, + integration contracts, internal documentation, and tests use only the new + vocabulary; and +- repository searches find no production compatibility aliases or stale current- + behavior claims for `dnd/npcs`, `dnd/npc-interactions`, `dnd/locations`, or + `dnd/item-events`. diff --git a/docs/roadmap/future.md b/docs/roadmap/future.md index ae97ec5..9fe0487 100644 --- a/docs/roadmap/future.md +++ b/docs/roadmap/future.md @@ -24,45 +24,11 @@ not as committed release dates. ### Canonical Entity Registries And Occurrences -- Establish a consistent module and artifact naming convention that makes the - two entity-extraction roles explicit. Prefer `dnd/-registry` for a - module that identifies canonical nouns and `dnd/-occurrences` for a - downstream module that consumes that registry and extracts transcript-backed - evidence about those nouns. Apply the convention coherently to NPCs, - locations, and items rather than preserving the current mixture of bare - plurals, `interactions`, `occurrences`, and `events` names. -- Treat this as a contract-level change rather than a prompt-asset rename. A - full feature roadmap should inventory and update module IDs, artifact kinds - and schema identities where applicable, pipeline dependencies, generated - references, checkpoints, configuration examples, tests, and documentation. - Because Notarius remains pre-release, prefer a clean migration over aliases - or compatibility shims unless the repository has acquired a concrete need - for them before implementation. -- Define the registry contract around stable, canonicalizable entity names. - In particular, tighten location extraction to include explicitly named - in-world places, such as `Waterdeep` or `The Yawning Portal`, while excluding - generic, temporary, relative, or purely descriptive references such as `the - room`, `the bar`, `the hallway`, or `upstairs`. Determine eligibility by - whether the transcript establishes a stable name or unique designation, not - by capitalization alone, because transcript capitalization is unreliable. -- Keep registry identification separate from occurrence evidence. A downstream - occurrence extractor may resolve a generic reference such as `the bar` to an - existing named registry entry when transcript context supports that - coreference, but it must not create a new canonical entity merely from the - generic reference. The occurrence itself must remain independently supported - by transcript ranges; registry membership is grounding, not event evidence. -- Define equivalent eligibility and coreference rules for NPC and item - registries so future entity types follow one architectural pattern while - retaining their domain-specific occurrence kinds. The full roadmap should - decide how unnamed but uniquely identifiable NPCs and items are represented, - and whether an item registry is introduced before or alongside renaming the - existing item-event lane. -- Evaluate the renamed and tightened contracts against representative - transcripts. Review false-positive registry entries, missed named entities, - coreference accuracy, unsupported occurrence links, and the behavior of - cost-effective smaller models. Keep these semantic changes separate from the - prompt-asset consolidation so regressions can be attributed to the correct - work set. +This work has been promoted to the dedicated +[Canonical D&D Entity Registries And Occurrences](entity-registries.md) +roadmap. That document owns the proposed module and artifact vocabulary, +registry eligibility, identity policies, occurrence contracts, ordered +handoffs, migration policy, and target end state. ## Shared Normalization And Quality Work diff --git a/docs/roadmap/implementation.md b/docs/roadmap/implementation.md index 76ed5c2..64b114c 100644 --- a/docs/roadmap/implementation.md +++ b/docs/roadmap/implementation.md @@ -1,618 +1,864 @@ -# D&D Prompt Asset Cleanup Implementation Plan +# Canonical D&D Entity Registries And Occurrences Implementation Plan ## Objective Implement the target state defined in -[D&D Prompt Asset Cleanup](prompts.md): standardize D&D prompt asset names, -clarify transcript scopes, consolidate fixed module instructions, remove prompt -prose duplication, normalize the two outlying private response-schema -identities, and document the resulting authoring conventions. +[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 plan changes internal LLM-facing assets and their owning registration code. -It does not change durable artifact contracts, public prompt IDs, module IDs, -pipeline configuration, reference bindings, profile selection, or extraction -policy. In particular, the proposed registry/occurrence module renaming and the -proper-name-only location policy in [Future Work](future.md) are not part of -this implementation. +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. -The stages are ordered dependencies. Complete and validate each stage before -starting the next. Each stage is sized for one gpt-5.6-terra implementation -prompt. +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. -## Implementation Rules +## Final Contract Matrix -Apply these rules throughout all stages: +Use these exact final identities. Do not invent variants during implementation. -- Read `docs/policy/architecture.md`, `docs/policy/documentation.md`, and - `docs/policy/testing.md` before making changes. -- Keep the root `assets` Go package content-only. Do not add prompt composition, - schema selection, registration, or D&D policy to that package. -- Preserve every public PromptKit prompt `id`, prompt version, default profile, - input name, input requirement, output format, validation mode, and repair - setting unless a stage below expressly changes private schema identity. -- Preserve the message orders and cache boundaries specified in `prompts.md`. - Consolidating fixed prose is not authorization to move variable material or - family-specific policy into the system message. -- Treat prompt prose as an owned contract, not as text to concatenate - mechanically. Merge `task.md` and `instructions.md` by editing the result into - one coherent `instructions.md`, removing duplicated transitions and rules. -- Begin with minimal, non-repetitive prose. Do not retain or reintroduce a - duplicated instruction merely because repetition might help a model. That - decision requires later observational evidence. -- Preserve all lane-specific domain semantics identified in `prompts.md`, even - when removing generic output, evidence, reference, or schema restatements. -- Keep all shared filenames prefixed with `common-dnd-`. -- Do not add compatibility aliases for retired private asset names or private - schema identities. Notarius is pre-release, and one-time prompt fingerprint, - checkpoint, and provider-cache invalidation is accepted. -- Keep default tests deterministic, offline, and credential-free. Do not call a - live LLM during implementation or make live model quality an automated gate. -- Do not add exact prompt snapshots, exact shared-prefix lengths, or tests that - enumerate every private asset merely to detect change. Retain tests of actual - preparation, input placement, cache boundaries, schema registration, and the - byte-identical extraction prefix. +| 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` | -## Stage 1: Establish Shared System And Transcript-Scope Assets +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 -Give universal instructions and each form of transcript material one correct -shared owner, then migrate every current D&D prompt to the appropriate scope in -one coherent change. +Adopt the final NPC registry type, artifact kind, schema identity, and identity +algorithm while the selectable module temporarily remains `dnd/npcs`. ### Required changes -1. Revise `assets/dnd/shared/prompts/common-dnd-system.md` so it contains all - and only behavior applicable to scene chunking, every extraction lane, and - both entity normalizers: - - - the D&D transcript-processing role; - - reliance only on supplied inputs; - - awareness of transcription errors, repetition, incomplete sentences, and - misheard proper nouns; and - - exactly one schema-conforming JSON object with no explanatory prose. - - Refer to supplied inputs generally. Do not limit the statement to transcript - and reference inputs, because grounded extractors and normalizers receive - other material. Do not place rendered inputs, transcript-evidence mechanics, - identity policy, reference policy, registry policy, or reconciliation policy - in the system message. - -2. Revise - `assets/dnd/shared/prompts/common-dnd-extraction-evidence.md` to own only - extraction evidence and source-range policy. Retain transcript-only evidence, - integer range endpoints, omission of `source_id`, and narrow non-contiguous - ranges. Remove the universal JSON-only/output-schema sentences now owned by - the system message. Avoid repeating detailed campaign-reference or registry - semantics owned by their input fragments. - -3. Replace `assets/dnd/shared/prompts/common-dnd-transcript.md` with: - - - `common-dnd-transcript-full.md`, which renders the complete ordered session - for scene chunking and does not imply that the complete session is one - scene; - - `common-dnd-transcript-chunk.md`, which renders one extraction chunk, - limits reporting and inference to that chunk, and states that unit IDs - retain source-wide meaning; and - - `common-dnd-transcript-windows.md`, which renders selected normalization - evidence windows and states that they may be incomplete, non-contiguous, - or overlapping and that absence outside them is not evidence. - - Each file must render `{{ input "transcript" }}` exactly once. Scope files - describe material completeness and permissible use; do not move scene, - extraction-evidence, or reconciliation policy into them. - -4. Update `internal/modules/dnd/shared/assets.go` so `sharedPromptPaths` exposes - the three new names and no longer exposes `common-dnd-transcript.md`. - -5. Update every owning `promptAssetManifest` and current prompt YAML definition - to select exactly one transcript-scope asset: - - | Scope asset | Prompt IDs | - | --- | --- | - | `common-dnd-transcript-full.md` | `dnd.scenes` | - | `common-dnd-transcript-chunk.md` | `dnd.spells`, `dnd.npcs`, `dnd.combat_turns`, `dnd.enemy_events`, `dnd.item_events`, `dnd.npc_interactions`, `dnd.scene_descriptions`, `dnd.locations`, `dnd.location_occurrences` | - | `common-dnd-transcript-windows.md` | `dnd.npcs.normalize`, `dnd.locations.normalize` | - - Preserve the existing message position and cache control while changing the - referenced scope filename. Extraction prompts must continue to share the - same rendered prefix through the chunk transcript. - -6. Update focused prompt-asset and shared-asset tests. A focused assertion that - an owning prompt family selects its required transcript scope is warranted; - do not replace it with exact prose snapshots or a full shared-file inventory. - Expand `internal/modules/dnd/register/prompt_cache_test.go` to include the - location and location-occurrence extraction prompts in its byte-identical - prefix check while retaining the existing other extraction lanes. +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 -- The old `common-dnd-transcript.md` is absent and unreferenced. -- Every D&D prompt prepares with exactly the transcript semantics supplied by - its caller. -- The shared system message is byte-identical across all D&D prompts and - contains no variable input. -- The extraction-evidence fragment no longer repeats the universal output rule. -- Extraction prompts retain a byte-identical rendered prefix through campaign - references and the chunk transcript when given identical inputs. -- No public prompt, module, durable artifact, or pipeline contract changes. +- 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/shared/... ./internal/modules/dnd/... +go test ./internal/modules/dnd/... ./internal/modules/integration/... git diff --check ``` -## Stage 2: Standardize Prompt And Context Filenames +## Stage 2: Move The NPC Registry Module Into Its Canonical Namespace ### Goal -Make prompt definitions and variable context assets predictable without changing -their rendered content or message order. +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. Rename every prompt-ID-derived YAML file below to `prompt.yaml` and update its - owning `promptAssetManifest` entry to mount `prompt.yaml` from - `prompts/prompt.yaml`: - - - `assets/dnd/scenes/prompts/` - - `assets/dnd/spells/prompts/` - - `assets/dnd/npcs/extract/prompts/` - - `assets/dnd/npcs/normalize/prompts/` - - `assets/dnd/combat-turns/prompts/` - - `assets/dnd/enemy-events/prompts/` - - `assets/dnd/item-events/prompts/` - - `assets/dnd/npc-interactions/prompts/` - - `assets/dnd/scene-descriptions/prompts/` - - `assets/dnd/locations/extract/prompts/` - - `assets/dnd/locations/normalize/prompts/` - - `assets/dnd/location-occurrences/prompts/` - - Leave the YAML `id` fields unchanged. PromptKit continues to distinguish the - definitions through each manifest's existing `ModuleDir`. - -2. Apply these context-fragment renames and update both YAML `content_file` - references and manifest `ModuleFiles` entries: - - - `assets/dnd/spells/prompts/catalog.md` to `spell-catalog.md`; - - `assets/dnd/enemy-events/prompts/grounding.md` to - `combat-grounding.md`; and - - `assets/dnd/location-occurrences/prompts/locations.md` to - `location-registry.md`. - - Do not edit their prompt prose in this mechanical stage. - -3. Update tests that intentionally exercise the production asset layout: - - - In `internal/modules/dnd/register/register_test.go`, retain a registrar- - boundary check for one canonical `prompt.yaml` per maintained prompt, but - remove lists of every task, instruction, context, and shared fragment. - - In `internal/cli/production_contract_test.go`, remove private prompt-file - inventory assertions already owned by the D&D registrar and module prompt- - preparation tests. Retain its CLI composition and public catalog contract - checks. - - Update module-local tests only where a renamed file is intentionally part - of the manifest/preparation behavior. - - Do not rewrite generic `internal/framework/llm` or - `internal/framework/promptfs` fixtures merely because they use arbitrary - noncanonical filenames; those tests prove generic filesystem behavior, not - the D&D authoring convention. - -4. Search for and remove all production references to the retired filenames. - Do not preserve copies or aliases. +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 -- Every D&D prompt subtree contains `prompt.yaml` and no prompt-ID-derived YAML - definition. -- The three renamed context files have descriptive names and render in their - original message positions. -- Every module manifest mounts the canonical names and still produces a prompt - fingerprint. -- Production-composition tests protect registration behavior without - enumerating every private content file. -- All prompts prepare through PromptKit with unchanged IDs, versions, inputs, - profiles, output modes, and cache controls. +- `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 3: Consolidate Scene And Entity-Normalization Instructions +## Stage 10: Redesign Item Events As Registry-Backed Item Occurrences ### Goal -Adopt the single `instructions.md` convention for scene chunking, scene -description, NPC normalization, and location normalization while preserving -their distinct message-order contracts. +Adopt the final item occurrence durable contract and required item-registry +grounding while the selectable module temporarily remains `dnd/item-events`. ### Required changes -1. For scene chunking, merge `task.md` and `instructions.md` into one coherent - `instructions.md` and delete `task.md`. Retain: - - - the definition of a coherent scene and meaningful boundary conditions; - - reasons to split and reasons not to split; - - complete ordered transcript coverage with no gaps or overlaps; and - - inclusive, positive source-unit endpoints. - - Remove the generic JSON-only rule now owned by the system prompt and field- - exclusivity prose already enforced by the private response schema. In - `prompt.yaml`, place the combined instructions after campaign references and - before the full transcript. It has no cache control; references and the final - full transcript retain ephemeral cache control. - -2. For scene descriptions, merge `task.md` and `instructions.md` into one - `instructions.md` and delete `task.md`. Retain the one-accepted-chunk scope, - all `kind` definitions and precedence, and title and summary semantics. - Remove schema field-list exclusions and universal JSON-only language. Keep - the combined final instructions message ephemeral. - -3. For both NPC and location normalizers, rename `task.md` to - `instructions.md`, update `prompt.yaml` and the manifest, and edit the prose - against `common-dnd-entity-reconciliation.md`: - - - NPC instructions own same-individual alias judgment and canonical display- - name preferences. - - Location instructions own same-place identity judgment, separation of - nested or uncertain places, and canonical display-name selection. - - The shared reconciliation fragment alone owns opaque keys, valid group - membership, canonical-member constraints, invention prohibitions, and - omission of uncertain groups. - - Preserve the normalizer order: system, module instructions, cacheable shared - reconciliation policy, candidates, cacheable transcript windows. - -4. Update module-local prompt preparation tests to assert meaningful relative - ordering, input isolation, and cache boundaries. Remove exact message-count - assertions whose only purpose was to preserve the former task/instruction - split. +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 -- These four prompt directories each contain one module-owned - `instructions.md` and no `task.md`. -- Scene and normalizer domain policy remains complete but does not repeat - universal system, response-schema, or shared reconciliation rules. -- Scene chunking still receives the full transcript last; normalizers still - receive candidates before transcript windows. -- Prompt preparation and existing scene/normalization behavior tests pass. +- 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/chunk/scenes ./internal/modules/dnd/extract/scenedescriptions ./internal/modules/dnd/normalize/npcs ./internal/modules/dnd/normalize/locations +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 4: Consolidate NPC, Location, And Item-Event Instructions +## Stage 11: Move Item Occurrences Into Their Canonical Namespace ### Goal -Consolidate three comparatively self-contained extraction prompts and remove -their shared or schema-enforced repetition without changing lane semantics. +Complete the item migration by replacing item-event module, package, prompt, +validator, asset, and documentation vocabulary. ### Required changes -1. Merge each prompt's `task.md` and `instructions.md` into its existing - `instructions.md`, delete `task.md`, and update `prompt.yaml` and the owning - manifest for: - - - NPC extraction; - - location extraction; and - - item-event extraction. - -2. NPC instructions must retain individually identifiable non-PC inclusion, - proper-name/stable-title/alias eligibility, all existing exclusion - categories, observed display spelling, and the prohibition on invented - anonymous labels. Remove generic narrow-range, reference-not-evidence, - schema-field, and lore-output restatements already owned elsewhere. - -3. Location instructions must retain the current implemented location policy, - including the current allowance for a generic label used for a specific - place, supported place categories, alias/nesting handling, and domain - exclusions. Do **not** implement the future proper-name-only registry policy - in this stage. Remove only generic evidence, reference, source-range, and - schema-shape repetition. - -4. Item-event instructions must retain event eligibility, all five kind - definitions, currency treatment, quantity semantics, holder transitions, - collective `party` behavior, transfer restrictions, and the distinction - between discovery and acquisition. Remove only generic evidence-range, - output-envelope, and schema-field restatements. - -5. Keep each consolidated extraction instruction as the final ephemeral - message. Update focused tests to protect preparation, inputs, output schema, - and cache placement without asserting the retired two-message structure. +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 -- The three prompt directories contain no `task.md`. -- No domain inclusion, exclusion, event-kind, currency, holder, or location - behavior changes. -- Generic evidence and response-shape rules have one shared/schema owner. -- All three prompts prepare and their extractor tests remain green. +- `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/extract/npcs ./internal/modules/dnd/extract/locations ./internal/modules/dnd/extract/itemevents +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: Consolidate Spell And Combat-Turn Instructions +## Stage 12: Verify The Complete Ordered Entity Pipeline ### Goal -Consolidate the spell and combat-turn prompts while keeping their identity, -catalog, grounding, and event semantics in the correct assets. +Make the maintained complete configuration and representative integration tests +prove the final three-registry/three-occurrence architecture. ### Required changes -1. Merge `task.md` and `instructions.md` into `instructions.md`, delete - `task.md`, and update `prompt.yaml` and manifests for spells and combat turns. - -2. Spell module instructions own: - - - inclusion of actual casts and unambiguous declared casting attempts; - - exclusion of mentions, plans, rules discussion, and unsupported catalog - matches; - - in-world caster attribution, including player-character and GM-narrated - casts; and - - the lane-specific requirement that evidence collectively support caster, - spell, and casting event. - - `spell-catalog.md` alone owns the rendered catalog, exact canonical spelling, - and the fact that the catalog is recognition context rather than evidence. - Shared identity and evidence fragments own their generic rules. - -3. Combat-turn instructions own combat-event eligibility and exclusions, - chronology, unmatched actors, turn-level evidence grouping, and the - `turn_kind` meanings. Remove repeated player/NPC identity grounding, - transcript-only evidence, source-range mechanics, and schema-field lists - owned by shared assets or the response schema. - -4. Keep both consolidated instruction messages final and ephemeral. Preserve - the spell catalog and optional NPC grounding as separate variable-context - messages after evidence policy and before module instructions. +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 -- Both prompt directories contain no `task.md`. -- Spell recognition remains catalog-constrained and caster attribution remains - evidence-grounded. -- Combat-turn categories, event boundaries, actor policy, and evidence grouping - are unchanged. -- Neither prompt repeats generic shared identity, evidence, or output-format - policy. -- Prompt preparation, spell schema/catalog tests, combat tests, and the shared - extraction-prefix test pass. +- 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/dnd/extract/spells ./internal/modules/dnd/extract/combatturns ./internal/modules/dnd/register +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 6: Consolidate Grounded Occurrence And Enemy-Event Instructions +## Stage 13: Consolidate Current Documentation And Examples ### Goal -Finish module prompt consolidation for the three registry- or artifact-grounded -event extractors. +Bring every canonical current-behavior document into alignment with the final +implemented entity family without duplicating contracts across documents. ### Required changes -1. Merge `task.md` and `instructions.md` into `instructions.md`, delete - `task.md`, and update `prompt.yaml` and manifests for: - - - NPC interactions; - - location occurrences; and - - enemy events. - -2. NPC-interaction instructions own registry membership as an eligibility - constraint, occurrence boundaries, all interaction kinds and precedence, - combat-alignment splitting, and domain exclusions. The shared NPC fragment - owns registry rendering, canonical grounding, and its non-evidence status; - shared identity and evidence fragments own their generic rules. - -3. Location-occurrence instructions own occurrence eligibility, all occurrence - kinds and precedence, handling of speculation, independent overlapping - facts, and domain exclusions. `location-registry.md` owns exact ID/name - rendering and registry-not-evidence semantics. Remove repeated schema fields, - `source_id`, narrow-range, and registry-context language from module prose. - -4. Enemy-event instructions own event eligibility, the five event kinds and - outcome definitions, one-engagement-per-scene policy, exclusions, and naming - of registered or grounded unnamed opponents. `combat-grounding.md` and the - shared NPC fragment own rendering and the non-evidence status of auxiliary - inputs. The shared evidence fragment owns source-range mechanics. Remove the - repeated response-field list and generic evidence statements. - -5. Keep each consolidated instruction message final and ephemeral, with all - registry and grounding messages before it and after the chunk transcript. +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 -- No D&D prompt directory contains `task.md`. -- All occurrence kinds, precedence rules, enemy outcomes, splitting rules, and - registry constraints remain intact. -- Registry and auxiliary artifacts remain grounding only and never become - transcript evidence. -- All three prompts prepare, and focused extractor, registry, invariant, and - cache-prefix tests pass. +- 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/modules/dnd/extract/npcinteractions ./internal/modules/dnd/extract/locationoccurrences ./internal/modules/dnd/extract/enemyevents ./internal/modules/dnd/register +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 7: Normalize Private Scene And Spell Schema Identities +## Stage 14: Final Contract Audit And Repository Verification ### Goal -Bring the two outlying private LLM response schemas into the naming convention -already used by the other D&D prompt schemas, without touching durable artifact -schemas. +Perform a final gap audit, remove stale implementation remnants, and prove the +completed feature at repository scope. ### Required changes -1. Normalize the scene private response schema: - - - rename `assets/dnd/scenes/schemas/dnd_scenes.v1.json` to - `dnd_scenes_llm.v1.json`; - - change its `$id` from `notarius.dnd.scenes` to - `notarius.dnd.scenes.llm`; - - change the scene `prompt.yaml` `schema_path` accordingly; and - - update `internal/modules/dnd/chunk/scenes/schema.go` to use key - `dnd_scenes_llm`, ID `notarius.dnd.scenes.llm`, name - `notarius_dnd_scenes_llm_v1`, and the renamed asset path. - -2. Normalize the already correctly named spell private response schema: - - - keep the filename `dnd_spells_llm.v1.json`; - - change its `$id` from `notarius.dnd.spells` to - `notarius.dnd.spells.llm`; and - - update `internal/modules/dnd/extract/spells/schema.go` to use key - `dnd_spells_llm`, ID `notarius.dnd.spells.llm`, and name - `notarius_dnd_spells_llm_v1`. - -3. Keep both versions at `v1`; these are private pre-release response contracts, - not a compatibility migration. Do not alter required fields, property types, - enum values, `additionalProperties`, or any owning Go response type. - -4. Update focused schema-loading, prompt-preparation, registrar, and production - composition expectations. Carefully distinguish the private spell response - schema from the durable spell artifact schema under - `internal/modules/dnd/codec/spells/assets/schemas/`; the durable schema and - `docs/integrations/dnd-spell-artifacts.md` must not change. - -5. Remove every reference to the retired private scene filename and old private - IDs/names/keys. Do not add aliases. +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 -- Scene and spell private schemas use `_llm`/`.llm` consistently in filenames - where applicable, registry keys, schema IDs, and response-schema names. -- Both schemas still load and validate the same private Go response shapes. -- Durable scene chunk-map and spell artifact contracts are unchanged. -- Registrar and module prompt preparation tests pass without schema collisions. +- 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 ./internal/modules/dnd/chunk/scenes ./internal/modules/dnd/extract/spells ./internal/modules/dnd/register ./internal/cli -git diff --check -``` - -## Stage 8: Document Conventions And Perform Final Verification - -### Goal - -Make the implemented conventions discoverable in their canonical documentation, -remove stale references, and verify the complete repository. - -### Required changes - -1. Rewrite the prompt-construction portion of `docs/internal/dnd.md` to describe - current implemented behavior: - - - the canonical `prompt.yaml` and `instructions.md` local names; - - module manifests as the owner of selection, order, and fingerprinting; - - the `common-dnd-` visual provenance prefix; - - the single-owner hierarchy for universal, family, input, module, and schema - rules; - - the eligibility test for system-prompt content; - - the full transcript, chunk transcript, and transcript-window assets and - their consumers; - - the final extraction, scene-chunking, and entity-normalization message - orders and cache controls; - - the rule against default prompt repetition and the observational-evidence - threshold for reintroducing it; and - - the content-only `assets` boundary, with a link to ADR-0011 rather than a - duplicate rationale. - - Remove the current descriptions of separate task and instructions messages - and the generic transcript fragment. - -2. Do not add an assets-package README or a new ADR. Do not modify ADR-0011. - `docs/internal/llm.md` should remain provider-neutral and should not duplicate - D&D filenames or ordering. Update it only if an earlier stage changed a - provider-neutral PromptKit preparation or cache-control fact; no such change - is expected by this plan. - -3. Review all changed prompt definitions and manifests as a set. Confirm that: - - - every prompt has one system message using the shared system asset; - - every prompt selects exactly one correct transcript-scope asset; - - every extraction prompt retains the stable shared prefix and final - ephemeral module instructions; - - scene chunking and normalizers retain their intentional distinct orders; - - no module-specific prompt repeats a rule already owned by its selected - shared assets or response schema; and - - the root `assets` Go package remains a single minimal filesystem file with - no business logic or internal/PromptKit dependency. - -4. Search for stale production references to: - - - `common-dnd-transcript.md`; - - prompt-ID-derived YAML filenames; - - D&D `task.md` prompt files; - - `catalog.md`, `grounding.md`, and the location-occurrence `locations.md`; - - `dnd_scenes.v1.json` and the old scene private schema identity; and - - the old spell private schema key, ID, and response-schema name. - - Exclude historical roadmap text only when the reference intentionally - explains a retired name. There should be no stale reference in current code, - assets, tests, or implemented documentation. - -5. Review tests for policy compliance. Retain behavior-level assertions for - preparation, schema compatibility, input isolation, cache placement, and the - identical extraction prefix. Remove any leftover assertion whose only value - is freezing exact prompt prose, message count, shared-prefix length, or a - complete private asset inventory. - -6. Run formatting where applicable and the complete offline repository checks. - Do not perform live model evaluation. Report that human evaluation with - representative transcripts and cost-effective target models remains the - next observational step after implementation; do not reintroduce prompt - repetition before that evidence exists. - -### Acceptance criteria - -- `docs/internal/dnd.md` accurately describes the implemented prompt layout, - ownership, transcript scopes, and cache ordering without duplicating external - contracts. -- No new ADR or assets README exists, and ADR-0011 remains unchanged. -- No stale production references or retired files remain. -- All maintained prompts prepare offline, all schemas register, all repository - tests and static checks pass, and the CLI builds. -- The final diff contains no durable artifact, public module/configuration, or - pipeline behavior change. - -### Validation - -```sh -go test ./... +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 ``` - -Run `gofmt` on the Go files changed by these stages before the commands above. -Inspect the diff and ensure formatting did not rewrite unrelated user changes; -never format an entire directory when the worktree contains unrelated edits. - -## Open Questions - -None. The feature roadmap and this plan make the prompt ownership, transcript -scope, naming, schema identity, documentation, compatibility, and testing -decisions required for implementation. diff --git a/docs/roadmap/prompts.md b/docs/roadmap/prompts.md deleted file mode 100644 index 5ded9de..0000000 --- a/docs/roadmap/prompts.md +++ /dev/null @@ -1,463 +0,0 @@ -# D&D Prompt Asset Cleanup - -## Purpose - -This roadmap defines the target state for the embedded D&D prompt and private -schema assets. The work is intended to make prompts easier to inspect, compare, -and revise; eliminate unnecessary repetition; preserve useful prompt-cache -boundaries; and establish conventions that future D&D modules can follow. - -The central design principle is that each instruction should have one clear -owner. Shared behavior belongs in a shared prompt asset, module-specific -behavior belongs in the module's instruction asset, variable grounding belongs -in a dedicated input asset, and purely structural requirements belong in the -JSON schema. - -## Current State - -The root `assets` package correctly centralizes embedded prompt and schema -content without owning D&D business logic. The D&D prompt assets nevertheless -retain several conventions inherited from their former module-local layouts: - -- prompt definitions use prompt-ID-derived filenames rather than a consistent - local filename; -- most prompt directories divide fixed module instructions between `task.md` - and `instructions.md`, although that division generally does not represent a - meaningful cache, trust, or input boundary; -- module-specific instructions repeat some rules already supplied by shared D&D - messages or enforced by their response schemas; -- one generic transcript fragment currently describes full-session input, - chunk-scoped input, and selected normalization windows even though those - materials have different completeness and inference boundaries; -- variable context assets use several naming styles, including generic names - such as `catalog.md` and `grounding.md`; -- the private scene and spell response-schema identifiers do not follow the - `_llm`/`.llm` convention used by the other private D&D schemas. - -These are internal authoring and maintenance inconsistencies. The durable -artifact contracts and the separation between content ownership in `assets` -and behavior ownership in `internal/modules` remain sound. - -## Goals - -The completed cleanup should: - -- give every D&D prompt directory the same predictable entry-point names; -- consolidate fixed module-specific instructions into one message unless a - distinct message boundary has a concrete purpose; -- remove module-specific restatements of rules already owned by shared assets; -- retain separate messages for shared policy, stable references, variable - transcript content, and other inputs where the boundary communicates trust, - provenance, reuse, or cache behavior; -- distinguish full-session transcripts, extraction chunks, and normalization - evidence windows through separate shared assets with explicit scope rules; -- keep all shared D&D filenames visibly identifiable in prompt definitions; -- make variable context filenames self-describing; -- normalize private LLM response-schema identities without changing durable - output schemas; -- document the conventions future prompt authors must follow; and -- preserve the rule that the root `assets` Go package contains no business - logic. - -## Decisions - -### Canonical prompt directory layout - -Every D&D prompt directory should use the following local layout: - -```text -prompts/ - prompt.yaml - instructions.md - [optional variable or context fragments] -``` - -The prompt definition filename is always `prompt.yaml`. The prompt's `id` field, -not its filename, remains the canonical global identifier. This is safe because -each module registers a distinct asset subtree with PromptKit; the local -`prompt.yaml` filenames do not share a virtual directory. - -Use the `.yaml` extension consistently. It matches the existing embedded prompt -and profile assets. - -For prompts that currently have both `task.md` and `instructions.md`, combine -their non-duplicative content into `instructions.md`. For prompts that currently -have only `task.md`, rename that asset to `instructions.md`. Do not preserve an -otherwise artificial two-message split merely to distinguish a short task -statement from its rules. - -### Retain the `common-dnd-` prefix - -Shared D&D assets must retain the `common-dnd-` filename prefix, including: - -- `common-dnd-system.md` -- `common-dnd-identity.md` -- `common-dnd-references.md` -- `common-dnd-transcript-full.md` -- `common-dnd-transcript-chunk.md` -- `common-dnd-transcript-windows.md` -- `common-dnd-extraction-evidence.md` -- `common-dnd-npcs.md` -- `common-dnd-entity-reconciliation.md` - -The prefix is a deliberate visual provenance marker. When reviewing a prompt -definition, an author should be able to distinguish shared messages from -module-owned messages immediately. Because asset references are explicit and -machine-resolved, retaining the prefix has no meaningful mechanical cost. - -### One owner per instruction - -Prompt prose should follow this ownership hierarchy: - -1. Universal D&D prompting behavior belongs in a shared D&D asset. -2. Rules shared by a prompt family belong in the narrowest applicable shared - asset. -3. Semantics of a variable input belong in the fragment that renders that - input. -4. Lane-specific extraction, classification, or normalization policy belongs in - that lane's `instructions.md`. -5. Object shape, required fields, enum values, and rejection of unknown fields - belong in the JSON schema unless prose is needed to explain their domain - meaning. - -Module-specific prompt assets should omit instructions already provided by the -shared prompt set. In particular, they should not routinely repeat generic rules -about transcript-only evidence, references not being evidence, omission of -`source_id`, narrow transcript ranges, schema-only output, or explanatory text. - -This cleanup should begin with the minimal instruction set that is both correct -and non-repetitive. Repetition may be reintroduced only when evaluation produces -repeatable observational evidence that a target model needs reinforcement. Any -such repetition should be narrow, placed close to the rule's canonical owner, -and documented as a deliberate model-reliability tradeoff rather than allowed to -become accidental drift. - -This rule does not authorize removal of domain semantics. Similar wording is not -duplication when it defines a distinct lane contract, such as event precedence, -holder transitions, scene-kind definitions, identity inclusion criteria, or the -relationship between a combat actor and an extracted event. - -### System-prompt eligibility - -`common-dnd-system.md` should own every fixed instruction that genuinely applies -to every maintained D&D LLM prompt. Consolidating those universal rules into the -system message gives them one authoritative owner, applies the appropriate -instruction priority, and preserves one byte-identical initial message across -chunking, extraction, and normalization prompts. - -An instruction belongs in the shared system message only when it is: - -- applicable to scene chunking, every extraction lane, and both entity - normalizers; -- independent of prompt-specific or variable inputs; -- static across calls; and -- appropriate to treat as a high-priority behavioral constraint. - -The system message should therefore own the D&D transcript-processing role, -reliance only on supplied inputs, treatment of transcription uncertainty, and -the requirement to return exactly one schema-conforming JSON object without -explanatory prose. - -Rules shared by only a subset of prompts must remain in the narrowest applicable -shared user-message fragment. Transcript-evidence and citation rules, identity -rules, campaign-reference semantics, registry grounding, and reconciliation -policy are not universal system instructions. No rendered transcript, -reference, registry, catalog, candidate, or other variable material belongs in -the system message. - -### Shared prompt ownership - -The shared D&D files should have clear, non-overlapping responsibilities: - -| Asset | Canonical responsibility | -| --- | --- | -| `common-dnd-system.md` | D&D domain role, reliance on supplied inputs, treatment of transcription uncertainty, and the universal requirement to emit exactly one schema-conforming JSON object without commentary. | -| `common-dnd-identity.md` | Rules for resolving supported in-world identities and the distinction between disambiguation and participation evidence. | -| `common-dnd-references.md` | Rendering and interpretation of campaign references, including that references provide context rather than establishing transcript events. | -| `common-dnd-transcript-full.md` | Rendering the complete ordered session transcript and identifying it as complete session input. | -| `common-dnd-transcript-chunk.md` | Rendering one extraction chunk, limiting the task to that chunk, and explaining that its unit IDs retain their source-wide meaning. | -| `common-dnd-transcript-windows.md` | Rendering selected reconciliation evidence windows and explaining that they may be incomplete, non-contiguous, or overlapping. | -| `common-dnd-extraction-evidence.md` | Transcript-evidence policy, source-range construction, omission of `source_id`, and preference for narrow supporting ranges. | -| `common-dnd-npcs.md` | Rendering and interpreting an upstream NPC registry as grounding rather than evidence. | -| `common-dnd-entity-reconciliation.md` | Safe duplicate-group proposal mechanics shared by entity normalizers. | - -As part of normalization, universal output-format prose should move to -`common-dnd-system.md`, while evidence-specific prose should remain in -`common-dnd-extraction-evidence.md`. The system message should refer generally -to supplied inputs rather than only transcripts and references, because -normalizers and grounded extractors receive additional input types. - -### Transcript-scope ownership - -The current `common-dnd-transcript.md` should be replaced rather than retained -as an alias. All three replacements may render the same prompt input named -`transcript`, but each must accurately describe the material supplied by its -caller: - -- `common-dnd-transcript-full.md` is used by scene chunking. It identifies the - material as the complete ordered session and permits whole-session coverage - decisions without implying that the entire session is one scene. -- `common-dnd-transcript-chunk.md` is used by every extraction lane. It states - that only the current chunk is in scope, that source-wide unit IDs remain - authoritative, and that the model must not infer or report events outside the - supplied chunk. -- `common-dnd-transcript-windows.md` is used by NPC and location normalization. - It states that the material consists of selected evidence windows that may be - incomplete, non-contiguous, or overlapping. The model may use those windows - to evaluate candidate identity but must not treat absence outside them as - evidence. - -The scope fragments should describe input completeness and permissible use; -they should not absorb scene policy, extraction evidence mechanics, or entity -reconciliation rules owned by other assets. Future prompt families must select -the fragment matching the material actually passed by code rather than choosing -one based merely on an input variable named `transcript`. - -### Module-specific ownership - -After shared duplication is removed, each module's `instructions.md` should -retain only its substantive lane policy: - -| Prompt | Module-owned policy | -| --- | --- | -| Scene chunking | Scene-boundary rules, ordered coverage, and valid treatment of gaps or overlaps. | -| Scene descriptions | `kind` classification definitions and precedence, plus title and summary semantics. | -| NPC extraction | Inclusion and exclusion rules for individually identifiable NPCs. | -| NPC interactions | Interaction kinds, precedence, occurrence splitting, and NPC-specific event semantics. | -| Location extraction | Inclusion and exclusion rules for identifiable in-world places. | -| Location occurrences | Occurrence kinds, precedence, splitting, and location-specific event semantics. | -| Spell extraction | What constitutes a cast, catalog-name policy, and caster attribution. | -| Combat turns | Combat event boundaries, event kinds, actor semantics, and combat-specific inclusion rules. | -| Item events | Event kinds, possession transitions, holder semantics, quantities, and currency treatment. | -| Enemy events | Enemy-event kinds, outcome semantics, encounter identity, and combat-grounding rules. | -| NPC normalization | NPC-specific duplicate criteria and canonical-name selection. | -| Location normalization | Location-specific duplicate criteria and canonical-name selection. | - -Schema field lists should not be copied into prose solely to restate the schema. -Prose may still explain how a field is interpreted or how two fields relate when -the schema cannot express that semantic rule. - -### Message boundaries and cache ordering - -Combining `task.md` and `instructions.md` must not lead to indiscriminate message -consolidation. Separate messages remain appropriate when they preserve a shared -byte-identical prefix, distinguish fixed instructions from variable material, -or identify the provenance and trust level of an input. - -Extraction prompts should retain this general order: - -```text -system -identity -campaign references -chunk transcript -evidence policy -optional grounding or variable context -module instructions -``` - -The scene chunker should retain this general order: - -```text -system -campaign references -module instructions -full transcript -``` - -Entity normalizers should retain this general order: - -```text -system -module instructions -shared entity-reconciliation policy -candidates -transcript windows -``` - -Existing cache controls should remain attached to the same semantic boundaries -unless PromptKit's contract requires a mechanical adjustment. The cleanup must -not move variable transcript or candidate content into an earlier stable prefix -merely to reduce message count. - -### Variable context asset names - -Optional non-shared fragments should describe the input they render rather than -use generic names. Normalize the current assets as follows where applicable: - -- `catalog.md` to `spell-catalog.md`; -- `grounding.md` to `combat-grounding.md`; -- `locations.md` to `location-registry.md`. - -The name `candidates.md` may remain in normalizer-local directories because its -meaning is clear in that context. Future context assets should use similarly -specific nouns and should remain separate from fixed `instructions.md` content. - -### Private response-schema identity - -Private schemas used only to constrain LLM responses should consistently use -the `_llm` filename/key/name convention and the `.llm` schema-ID suffix already -used by most D&D modules. - -Normalize the scene schema to: - -- file: `dnd_scenes_llm.v1.json`; -- schema ID: `notarius.dnd.scenes.llm`; -- registry key: `dnd_scenes_llm`; -- response-schema name: `notarius_dnd_scenes_llm_v1`. - -Normalize the spell schema metadata to: - -- file: `dnd_spells_llm.v1.json` (already named correctly); -- schema ID: `notarius.dnd.spells.llm`; -- registry key: `dnd_spells_llm`; -- response-schema name: `notarius_dnd_spells_llm_v1`. - -Private schema filenames must remain globally unique. They should not be renamed -to a generic local name because the schema registry exposes a shared namespace. -Durable artifact schema identifiers and shapes are out of scope and must not -change. - -### Explicit prompt definitions remain explicit - -The repeated `version`, `default_profile`, input, message, output, and schema -declarations in `prompt.yaml` files should remain explicit. They are declarative -configuration, not prompt-prose duplication. Introducing a generator, template -layer, or Go builder for these small definitions would make inspection harder -and create another synchronization boundary. - -Similarly, module manifests should continue to declare the assets their prompt -uses. Shared asset selection is module behavior and does not belong in the root -`assets` package. - -## Compatibility and Cache Effects - -This is an intentional internal prompt revision. Renaming prompt definition -files, consolidating messages, editing shared prose, and normalizing private -schema identifiers will change prompt and component fingerprints. Existing -checkpoints may no longer be reusable, and backend prompt caches will experience -a one-time cold start. Those fingerprint, checkpoint, and cache effects are -accepted consequences of reaching the target prompt layout. - -The following contracts must remain stable: - -- public prompt IDs; -- module IDs and configuration fields; -- default profile selection; -- required and optional prompt inputs; -- durable artifact schema IDs and artifact shapes; -- extraction and normalization semantics, except for removing unintended prompt - repetition; and -- pipeline dependency behavior. - -No backward-compatible copies of old private prompt assets or schema aliases are -required while the application remains pre-release. - -## Documentation and Maintenance Rules - -The implemented convention should be documented in the canonical internal D&D -and LLM documentation rather than in an assets-package README that could drift. -The documentation should explain: - -- the canonical `prompt.yaml` and `instructions.md` names; -- why shared assets retain the `common-dnd-` prefix; -- the instruction-ownership hierarchy; -- the eligibility test for moving a rule into `common-dnd-system.md`; -- the full, chunk, and evidence-window transcript contracts and which prompt - families select each one; -- when a separate message boundary is warranted; -- the cache-oriented message ordering; -- the prohibition on business logic in `assets`; and -- the evidence threshold for deliberately repeating an instruction. - -The Go file in the root `assets` package should remain a minimal embedding and -filesystem-access layer. Prompt composition, schema selection, module policy, -and validation logic must remain in their existing owning packages. - -`docs/internal/dnd.md` should be the canonical owner of these D&D prompt -authoring conventions and the concrete message-order patterns. Its existing -prompt-construction section should be revised when the assets change rather -than creating an `assets` README or duplicating the rules in contributor -orientation. `docs/internal/llm.md` should receive only any short update needed -to describe provider-neutral PromptKit preparation or cache-control mechanics; -it should link to the D&D guide instead of repeating domain-specific asset names -or ordering. - -No new ADR is warranted for this cleanup. ADR-0011 already records the -architecturally significant decisions: physical centralization, content-only -package ownership, and retention of prompt semantics and ordering by modules. -The filename, instruction-ownership, transcript-scope, and system-message rules -are internal authoring conventions that should be allowed to evolve with model -evaluation. They do not create a new dependency boundary or reverse an accepted -architectural decision. If a later change promotes these conventions into a -cross-domain runtime-enforced prompt composition contract, that broader -decision should receive its own ADR at that time; ADR-0011 must not be edited to -retrofit the new rationale. - -## Validation and Evaluation Policy - -Automated validation should establish that the refactor preserves executable -contracts without freezing prompt prose. It should cover: - -- preparation of every embedded prompt through PromptKit; -- prompt input declarations and required-input behavior; -- private response-schema registration and compatibility with the owning Go - response types; -- expected cache controls and meaningful stable-prefix boundaries; -- selection of the transcript-scope fragment appropriate to each prompt - family, verified through prompt preparation and owning-module behavior rather - than exact prose snapshots; -- manifest references after asset renames; -- absence of references to retired filenames and private schema identifiers; - and -- the full repository test suite. - -Tests must not assert exact prompt wording, exact message counts, shared-prefix -lengths, or asset inventories solely as change detectors. Such tests would make -intentional prompt iteration unnecessarily expensive and conflict with the -project's testing policy. - -Model quality should be evaluated by running representative transcripts through -all affected lanes, with particular attention to cost-effective smaller models. -Review should compare extraction correctness, unsupported claims, missing -events, source-range quality, and schema reliability. The initial evaluation -should use the minimal non-repetitive prompts. A repeated instruction should be -restored only if failures recur and there is a credible causal reason that -reinforcement will help. - -## Non-Goals - -This roadmap does not include: - -- changes to durable D&D artifact schemas; -- new extraction lanes or pipeline behavior; -- changes to profile selection or model settings; -- a prompt-definition generator or templating framework; -- moving business logic into `assets`; -- collapsing all prompt material into one message; -- placing family-specific rules or rendered variable content in the system - message; -- preserving old prompt fingerprints or warm backend cache entries; or -- introducing brittle prompt snapshots or change-detector tests. - -## Target End State - -Every D&D prompt is discoverable through a local `prompt.yaml`, has one fixed -module-owned `instructions.md`, and uses separately named context fragments only -where inputs or cache boundaries justify them. Shared D&D assets remain visibly -marked with `common-dnd-` and have documented, non-overlapping responsibilities. -Module instructions contain no routine repetition of shared or schema-enforced -rules, while retaining all lane-specific domain semantics. - -The shared system message contains all and only universal, static D&D behavior. -Scene chunking renders the explicitly full transcript fragment, extraction -lanes render the explicitly chunk-scoped fragment, and entity normalizers render -the explicitly incomplete evidence-window fragment. No prompt presents one -scope as another merely because all three inputs use the name `transcript`. - -Private scene and spell response schemas follow the established LLM-only naming -convention, durable contracts are unchanged, all manifests and PromptKit -definitions prepare successfully, and human evaluation begins from a minimal -non-repetitive prompt set. Future modules can follow the same conventions -without copying an existing extractor and inheriting accidental prose or naming -drift.