200 lines
9.4 KiB
Markdown
200 lines
9.4 KiB
Markdown
# 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 private schema owns required
|
|
fields, JSON types, object and array shapes, and unknown-field rejection;
|
|
deterministic validators own the durable artifact's semantic constraints.
|
|
|
|
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-cast object>, ...]}
|
|
```
|
|
|
|
`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;
|
|
- `source_refs`: transcript source references with extractor-assigned source
|
|
IDs and evidence unit ranges. It must contain at least one entry.
|
|
|
|
Both 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.
|
|
|
|
The artifact includes an actual casting event or an unambiguous declared
|
|
casting attempt. Spell mentions, hypothetical plans, rules discussion, and
|
|
catalog matches without a casting event are excluded. The spell catalog is a
|
|
name-recognition policy and never evidence that a cast occurred.
|
|
|
|
## 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 the caster, spell name, and occurrence of the cast or declared
|
|
attempt. The deterministic validators establish that ranges are structurally
|
|
valid and that the spell name is related to cited text. Semantic evidence
|
|
sufficiency 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. An external file is
|
|
validated during preparation; an ordered generated binding is validated at the
|
|
step handoff. Both paths use the approved NPC codec and identity policy,
|
|
re-encode canonical durable JSON for registry provenance, and supply only the
|
|
registry's ordered names as the operation-time spell prompt input. It helps the
|
|
model prefer canonical caster names; 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. Generated provenance records producer and canonical
|
|
artifact identity without payload content or a path. When the slot is absent,
|
|
the prompt receives exactly `{"npcs":[]}` with its projection digest, and the
|
|
run has no NPC reference provenance.
|
|
|
|
## 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
|
|
and canonical references are preserved. 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 for
|
|
an external NPC registry when the extractor publishes its prepared module
|
|
metadata. They contain no NPC names, source references, paths, or raw
|
|
bytes. A generated registry's identity is instead represented by the framework
|
|
handoff provenance and dependency fingerprint, so the consumer module metadata
|
|
does not duplicate it.
|
|
|
|
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 for an
|
|
external binding; the manifest metadata contains only that digest and
|
|
`npc_count`. Raw NPC file provenance remains independently recorded in the
|
|
manifest's `references` list. Generated bindings contribute the canonical
|
|
artifact dependency fingerprint and bounded producer provenance instead.
|