# D&D Prompt Asset Cleanup 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.

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.

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.

## Implementation Rules

Apply these rules throughout all stages:

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

## Stage 1: Establish Shared System And Transcript-Scope Assets

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

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

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

### Validation

```sh
go test ./internal/modules/dnd/shared/... ./internal/modules/dnd/...
git diff --check
```

## Stage 2: Standardize Prompt And Context Filenames

### Goal

Make prompt definitions and variable context assets predictable without changing
their rendered content or message order.

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

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

### Validation

```sh
go test ./internal/modules/dnd/... ./internal/cli/...
git diff --check
```

## Stage 3: Consolidate Scene And Entity-Normalization Instructions

### Goal

Adopt the single `instructions.md` convention for scene chunking, scene
description, NPC normalization, and location normalization while preserving
their distinct message-order contracts.

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

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

### Validation

```sh
go test ./internal/modules/dnd/chunk/scenes ./internal/modules/dnd/extract/scenedescriptions ./internal/modules/dnd/normalize/npcs ./internal/modules/dnd/normalize/locations
git diff --check
```

## Stage 4: Consolidate NPC, Location, And Item-Event Instructions

### Goal

Consolidate three comparatively self-contained extraction prompts and remove
their shared or schema-enforced repetition without changing lane semantics.

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

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

### Validation

```sh
go test ./internal/modules/dnd/extract/npcs ./internal/modules/dnd/extract/locations ./internal/modules/dnd/extract/itemevents
git diff --check
```

## Stage 5: Consolidate Spell And Combat-Turn Instructions

### Goal

Consolidate the spell and combat-turn prompts while keeping their identity,
catalog, grounding, and event semantics in the correct assets.

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

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

### Validation

```sh
go test ./internal/modules/dnd/extract/spells ./internal/modules/dnd/extract/combatturns ./internal/modules/dnd/register
git diff --check
```

## Stage 6: Consolidate Grounded Occurrence And Enemy-Event Instructions

### Goal

Finish module prompt consolidation for the three registry- or artifact-grounded
event extractors.

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

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

### Validation

```sh
go test ./internal/modules/dnd/extract/npcinteractions ./internal/modules/dnd/extract/locationoccurrences ./internal/modules/dnd/extract/enemyevents ./internal/modules/dnd/register
git diff --check
```

## Stage 7: Normalize Private Scene And Spell Schema Identities

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

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

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

### 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 vet ./...
go build ./cmd/notarius
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.
