# D&D Spell Artifact This document is the durable serialized artifact contract for the production D&D spell extractor. Selectable extractor keys are cataloged in [Configuration](../config.md#implemented-production-modules). ## Identity - Artifact kind: `dnd/spell-list` - Prompt ID: `dnd.spells` - Response schema key: `dnd_spells` - Response schema ID: `notarius.dnd.spells` - Response schema name: `notarius_dnd_spells_v1` - Response schema version: `v1` - Media type: `application/json` The durable JSON Schema is owned by the D&D spell artifact codec. The extractor's private LLM response schema is a separate transport contract: its source-reference objects omit `source_id`, which the extractor assigns while mapping the response to the canonical artifact. The LLM DTO and transport schema are not part of this durable contract. The output contains canonical spell casts derived from transcript evidence. Source IDs are assigned from the input identity; source-unit ranges identify the evidence location. ## Output Shape The extractor payload is a JSON object with one required top-level array. Its structure is: ```text {"spell_casts": [, ...]} ``` `spell_casts` must be present. It may be empty when no spell casts are found. When multiple chunk results are combined, spell casts remain in chunk order. When the payload is written as durable output, its logical path is derived from the configured artifact lane ID as defined by the [JSON output contract](json-output.md#output-payload-files). ## Spell-Cast Fields Each spell cast contains exactly these required fields: - `caster`: in-world character or creature casting the spell; - `spell`: spell name; - `effect`: concise spell effect in the scene; - `narrative_description`: short description of the spell cast in context; - `source_refs`: transcript source references with extractor-assigned source IDs and evidence unit ranges. It must contain at least one entry. All four string fields must be non-empty. `caster` is the canonical in-world caster, not the human player, transcript speaker, or GM when the associated character or creature can be identified. Player and party references may disambiguate that identity, but do not independently establish that a cast occurred. The `spell` value must resolve through the effective SRD-plus-overlay catalog as either a canonical name or alias. Catalog validation accepts aliases but does not rewrite them; unknown fields are rejected. `effect` and `narrative_description` record the casting declaration and its immediate resolution as established by the transcript. They do not follow summoned creatures, persistent spell effects, or other downstream consequences through the rest of the scene. They also do not correct the table from published D&D rules or supplement the transcript with model knowledge. When the transcript contains a nonstandard or disputed ruling, the artifact may preserve the immediate observed resolution and attribute relevant reasoning to the GM or table; it must not present that reasoning as a universal game rule. The spell catalog is name-recognition policy, not evidence for spell mechanics or outcomes. ## Source References Each source reference contains exactly three required fields: `source_id`, `start_unit_id`, and `end_unit_id`. The source ID must match the input identity. The unit IDs must be positive integers present in the input, and the start unit must not appear after the end unit. Unknown fields are rejected. For each cast, the complete `source_refs` collection identifies the transcript evidence for every factual claim in `caster`, `spell`, `effect`, and `narrative_description`. A cast declaration and its immediate resolution may be cited with separate narrow ranges when intervening units are unrelated. A reported target, roll, amount, condition, interruption, or immediate outcome must be supported by the cited units; otherwise the artifact describes only the supported attempt or declaration. Later behavior by summoned creatures, recurring effects, and other downstream consequences are outside the cast artifact's evidence scope. The deterministic validators establish that ranges are structurally valid and that the spell name is related to cited text. Semantic claim completeness is an extraction policy and remains subject to evaluation rather than deterministic proof. Reference slot keys and accepted file types are defined in [Configuration](../config.md#implemented-production-modules). References are supporting disambiguation material, not source evidence, and are not addressable through `source_refs`. ## Optional NPC Grounding The `dnd/spells` extractor accepts an optional `npcs` reference containing one normalized NPC artifact as `application/json`, up to 1 MiB. Preparation uses the approved NPC codec and identity policy to validate the file, re-encodes canonical durable JSON, and supplies that JSON as a spell-owned prompt input. It helps the model prefer canonical caster names and recognize aliases; it does not establish that a spell was cast. NPC source references may identify the run that produced the registry or any other session. They remain registry provenance and are never copied into a spell cast's `source_refs`; every spell evidence range must still identify the current transcript. When the slot is absent, the prompt receives exactly `{"npcs":[]}` and the run has no NPC reference provenance or NPC checkpoint fingerprint. ## Normalization Behavior When the `dnd/spells` normalizer is selected, each recognized spell name is rewritten to the effective catalog's canonical display name. Lookup uses the catalog's case-insensitive, whitespace-normalizing, apostrophe-normalizing, and alias rules. Unknown names are preserved exactly for the normalize validators; the normalizer does not guess or apply fuzzy matching. Each cast's `source_refs` is copied, sorted by exact `source_id`, `start_unit_id`, and `end_unit_id`, and stripped of exact structural duplicates. Adjacent or overlapping ranges are not merged, and the normalizer does not synthesize references or change their boundaries. After those per-cast changes, duplicate identity requires the same canonical spell name, the same caster after case folding and whitespace normalization, and the same complete, non-empty set of source references valid for the source document. Only the first occurrence is retained, in stable order. Its caster, effect, narrative description, and canonical references are preserved without prose merging or source union. Unknown names, empty or invalid evidence, and casts with different evidence remain separate. Mutation and duplicate decisions are returned through the normal warnings surface. Warning scopes use the merged input index, such as `spell_casts[0]`, so they remain meaningful even when a later duplicate is removed. The normalizer uses these reason codes: | Reason code | Meaning | | --- | --- | | `spell_name_canonicalized` | A catalog lookup replaced an input name with its canonical display name. | | `spell_name_unresolved` | A name was not found in the effective catalog and was retained unchanged. | | `source_references_normalized` | Reference order changed or exact duplicate references were removed. | | `duplicate_spell_cast_collapsed` | A later cast matched the retained cast's complete duplicate identity. | Only warnings from an accepted normalize attempt are promoted to `warnings.json`. If an unresolved name reaches the default normalize validator chain, the catalog validator rejects the candidate with `unknown_spell`; the `spell_name_unresolved` warning remains in the attempt's debug artifact. An explicit validator override that accepts the candidate promotes the unresolved warning normally. ## Manifest Metadata The extractor adds prompt and response-schema provenance under the artifact lane manifest metadata: ```json { "metadata": { "extractor": { "prompt_id": "dnd.spells", "prompt_version": "v1", "prompt_sha256": "sha256:...", "response_schema_key": "dnd_spells", "response_schema_id": "notarius.dnd.spells", "response_schema_name": "notarius_dnd_spells_v1", "response_schema_version": "v1", "response_schema_sha256": "sha256:...", "catalog_base_id": "dnd-5e-2014-srd-spells", "catalog_digest": "sha256:...", "catalog_overlay_ids": ["campaign.example"], "npc_registry_digest": "sha256:...", "npc_count": 3 }, "normalizer": { "catalog_base_id": "dnd-5e-2014-srd-spells", "catalog_digest": "sha256:...", "catalog_overlay_ids": ["campaign.example"] } } } ``` `catalog_digest` identifies the effective semantic catalog, while `catalog_overlay_ids` is sorted and empty for a base-only configuration. Raw prompt, schema, catalog, alias, and local overlay-file content are not included in manifest metadata. The `normalizer` metadata uses the same catalog identity fields when that module is selected. Overlay origin, media type, byte size, and raw digest are recorded separately in the manifest's reference provenance; see the [JSON output contract](json-output.md#manifestjson). The `npc_registry_digest` and `npc_count` fields in the example are present only when the optional NPC registry is bound. They contain no NPC names, aliases, source references, paths, or raw bytes. The extractor's prompt hash, private response-schema hash, and effective catalog digest also contribute independently scoped semantic checkpoint fingerprints. Changing any of those prepared contracts intentionally produces a cold checkpoint miss. Fingerprints contain only digests, never prompt, schema, catalog, or reference content. When an NPC registry is bound, its semantic digest contributes an additional local `npc_registry` fingerprint; the manifest metadata contains only that digest and `npc_count`. Raw NPC file provenance remains independently recorded in the manifest's `references` list.