Plan canonical D&D entity registries and occurrences

This commit is contained in:
2026-08-05 18:16:37 +00:00
parent 299c110267
commit 916a32195b
4 changed files with 1248 additions and 996 deletions

View File

@@ -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/<singular-entity>-registry`. Occurrence extractors and their matching
normalizers use `dnd/<singular-entity>-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.<entity>_registry`, `dnd.<entity>_registry.normalize`, and
`dnd.<entity>_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`.

View File

@@ -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/<entity>-registry` for a
module that identifies canonical nouns and `dnd/<entity>-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

File diff suppressed because it is too large Load Diff

View File

@@ -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.