diff --git a/docs/internal/llm.md b/docs/internal/llm.md index 6b32ba6..b837868 100644 --- a/docs/internal/llm.md +++ b/docs/internal/llm.md @@ -102,19 +102,52 @@ The D&D scene chunker and spell, NPC, and combat-turn extractors each declare an ordered prompt asset manifest. The manifest lists the package-owned YAML and Markdown files, then the exact shared fragments rendered by that prompt; the same ordered list drives both filesystem mounting and the prompt fingerprint. -The three extraction prompts share system, extraction evidence, in-world -identity, transcript, and campaign-reference messages. Spell and combat prompts -then render immediate resolution and the ephemeral NPC registry before their -lane-specific material; the NPC prompt renders its task and instructions -instead. The scene prompt uses system, transcript, and campaign-reference -messages before its task and instructions. Identity, transcript, and -campaign-reference messages are ephemeral in the extraction prompts; the scene -prompt marks transcript and campaign references ephemeral, and the NPC registry -is ephemeral where spell and combat prompts use it. Unused shared assets are -neither mounted nor fingerprinted. Universal extraction-evidence and output -policy lives only in the shared extraction assets; package-owned prompt files -retain artifact-specific rules. The scene prompt keeps its separate output rule -because it does not render the extraction-evidence asset. +Unused shared assets are neither mounted nor fingerprinted. Universal +extraction-evidence and output policy lives only in the shared extraction +assets; package-owned prompt files retain artifact-specific rules. The scene +prompt keeps its separate output rule because it does not render the +extraction-evidence asset. + +### D&D Extraction Prompt Ordering And Cache Boundaries + +D&D extraction prompts order messages from the most reusable content to the +most variable content. New extraction lanes use these tiers in order: + +1. universal shared content, including the system, extraction-evidence, and + in-world identity messages; +2. stable campaign or run context shared across lanes, including campaign + references; +3. stable subset- and lane-specific context and instructions, including an NPC + registry, catalog, task, or extraction instructions when applicable; +4. the chunk transcript as the final user message. + +This ordering lets requests reuse the longest identical prefix before the +per-chunk transcript changes. Cache reuse requires the preceding message +sequence and content to be exactly identical; semantic similarity is not +sufficient. Cache boundaries belong at the ends of reusable stable tiers, +subject to the provider's cache-boundary limit. The shared identity and +campaign-reference messages form the first two extraction boundaries. Spell +and combat prompts add a boundary at the shared NPC registry. Each extraction +prompt places its final boundary on its lane-specific instructions, immediately +before the transcript. The transcript does not carry cache control because no +reusable content follows it. + +Accordingly, the common prefix of all three extraction prompts is system, +extraction evidence, identity, and campaign references. The NPC prompt then +renders task, instructions, and transcript. Spell renders immediate resolution, +NPC registry, catalog, task, instructions, and transcript. Combat renders +immediate resolution, NPC registry, task, instructions, and transcript. The +scene chunker is not an extraction lane: it retains its separate system, +transcript, campaign-reference, task, and instruction order and marks its +transcript and campaign-reference messages ephemeral. + +Shared wording belongs in the canonical assets under +`internal/modules/dnd/shared`; extraction packages reference those assets in +their manifests instead of copying similar text into package-local files. +Package-local assets contain only lane-specific content. An extraction lane may +depart from the tier order only when prompt-quality evidence or a provider +constraint makes the exception necessary; document the exception and rationale +here when it becomes implemented behavior. Schema helpers load embedded JSON Schema with identity and digest metadata, return defensive copies, and expose a diagnostics map that omits schema bytes. diff --git a/docs/internal/modules.md b/docs/internal/modules.md index 96833b0..31fffc4 100644 --- a/docs/internal/modules.md +++ b/docs/internal/modules.md @@ -51,15 +51,12 @@ declarations, prompt-input assembly, and source-unit/citation helpers belong in D&D scene chunker and spell, NPC, and combat-turn extractors use ordered package-local prompt manifests for both rendering and prompt fingerprinting, so only the shared fragments each prompt actually renders participate in either -operation. The three extraction prompts share the order system, extraction -evidence, in-world identity, transcript, and campaign references, with -ephemeral cache control on identity, transcript, and references. Spell and -combat prompts append immediate resolution and an ephemeral NPC registry before -lane-specific material; the NPC prompt appends its task and instructions. The -scene prompt uses system, transcript, and campaign references before its -lane-specific task and instructions, with ephemeral cache control on transcript -and references. Stage contracts expose only Notarius structured-completion -types, not Scriptorium public types. +operation. Extraction prompts place stable shared and lane-specific context +before the variable transcript and use shared assets for wording common across +lanes. The canonical ordering and cache-boundary policy is documented in +[LLM Runtime](llm.md#dd-extraction-prompt-ordering-and-cache-boundaries). Stage +contracts expose only Notarius structured-completion types, not Scriptorium +public types. The shared `ChunkPromptMaterial` helper owns common transcript material preparation for the spell, NPC, and combat-turn extractors. It clones supplied @@ -240,15 +237,14 @@ assigns source identity and deterministic NPC IDs, and preserves source references for deterministic validation. It uses the shared campaign references only for disambiguation and does not consume the optional NPC registry slot. Its prompt and private response schema are package-owned. The -prompt uses the common evidence, identity, transcript, and campaign-reference -messages, then the NPC-specific task and instructions; only the identity, -transcript, and campaign-reference messages carry ephemeral cache control. +prompt follows the shared D&D extraction ordering and cache policy documented +in [LLM Runtime](llm.md#dd-extraction-prompt-ordering-and-cache-boundaries). ### `internal/modules/dnd/extract/combatturns` The combat extractor prepares one structured request per supplied chunk using -the shared extraction-evidence, identity, transcript, campaign-reference, -immediate-resolution, and NPC-grounding prompt inputs. It +the shared extraction-evidence, identity, campaign-reference, +immediate-resolution, NPC-grounding, and transcript prompt inputs. It maps the private response to `dnd.CombatTurnList`, assigns the current source identity, removes exact duplicate source ranges, and orders turns by valid source-document position while preserving malformed candidate fields for @@ -256,11 +252,11 @@ deterministic validators. Its package-owned private response schema enforces only the structural JSON envelope; semantic artifact constraints remain with the validator chain. Its prepared metadata and checkpoint fingerprints contain only prompt/schema/mapping identities plus an optional NPC registry digest. -The prompt renders immediate resolution and the NPC registry before the -combat-specific task and instructions; identity, transcript, campaign -references, and the NPC registry use ephemeral cache control. The package -exposes typed registration and is included in the production D&D registrar with -the default combat extraction chain. +The prompt follows the shared D&D extraction ordering and cache policy +documented in +[LLM Runtime](llm.md#dd-extraction-prompt-ordering-and-cache-boundaries). The +package exposes typed registration and is included in the production D&D +registrar with the default combat extraction chain. The combat normalizer accepts only the optional structured NPC registry. Campaign references remain extractor-only LLM context and are not materialized @@ -448,6 +444,10 @@ When adding a production module or validator: 2. expose and test its spec, constructor, and registration function; 3. keep format or domain parsing inside the concrete package; 4. add package-owned prompt/schema assets when the extension is LLM-backed; + new LLM-backed D&D extraction modules must follow the stable-to-variable + prompt ordering, shared-asset ownership, and cache-boundary policy in + [LLM Runtime](llm.md#dd-extraction-prompt-ordering-and-cache-boundaries), or + document the implemented exception and its evidence there; 5. register it through its package-family registrar and add a default chain there only when production policy requires one; 6. add resolution and composition coverage for capabilities, options, diff --git a/internal/modules/dnd/extract/combatturns/assets/prompts/dnd.combat_turns.yaml b/internal/modules/dnd/extract/combatturns/assets/prompts/dnd.combat_turns.yaml index 4a721cc..388f62a 100644 --- a/internal/modules/dnd/extract/combatturns/assets/prompts/dnd.combat_turns.yaml +++ b/internal/modules/dnd/extract/combatturns/assets/prompts/dnd.combat_turns.yaml @@ -26,10 +26,6 @@ messages: content_file: ./sharedassets/common-dnd-identity.md cache_control: type: ephemeral - - role: user - content_file: ./sharedassets/common-dnd-transcript.md - cache_control: - type: ephemeral - role: user content_file: ./sharedassets/common-dnd-references.md cache_control: @@ -44,6 +40,10 @@ messages: content_file: ./task.md - role: user content_file: ./instructions.md + cache_control: + type: ephemeral + - role: user + content_file: ./sharedassets/common-dnd-transcript.md output: format: json validation_mode: json_schema diff --git a/internal/modules/dnd/extract/npcs/assets/prompts/dnd.npcs.yaml b/internal/modules/dnd/extract/npcs/assets/prompts/dnd.npcs.yaml index 8cb01ce..fc9f53c 100644 --- a/internal/modules/dnd/extract/npcs/assets/prompts/dnd.npcs.yaml +++ b/internal/modules/dnd/extract/npcs/assets/prompts/dnd.npcs.yaml @@ -23,10 +23,6 @@ messages: content_file: ./sharedassets/common-dnd-identity.md cache_control: type: ephemeral - - role: user - content_file: ./sharedassets/common-dnd-transcript.md - cache_control: - type: ephemeral - role: user content_file: ./sharedassets/common-dnd-references.md cache_control: @@ -35,6 +31,10 @@ messages: content_file: ./task.md - role: user content_file: ./instructions.md + cache_control: + type: ephemeral + - role: user + content_file: ./sharedassets/common-dnd-transcript.md output: format: json validation_mode: json_schema diff --git a/internal/modules/dnd/extract/spells/assets/prompts/dnd.spells.yaml b/internal/modules/dnd/extract/spells/assets/prompts/dnd.spells.yaml index 3c820f4..5d8834b 100644 --- a/internal/modules/dnd/extract/spells/assets/prompts/dnd.spells.yaml +++ b/internal/modules/dnd/extract/spells/assets/prompts/dnd.spells.yaml @@ -29,10 +29,6 @@ messages: content_file: ./sharedassets/common-dnd-identity.md cache_control: type: ephemeral - - role: user - content_file: ./sharedassets/common-dnd-transcript.md - cache_control: - type: ephemeral - role: user content_file: ./sharedassets/common-dnd-references.md cache_control: @@ -49,6 +45,10 @@ messages: content_file: ./task.md - role: user content_file: ./instructions.md + cache_control: + type: ephemeral + - role: user + content_file: ./sharedassets/common-dnd-transcript.md output: format: json validation_mode: json_schema