171 lines
7.8 KiB
Markdown
171 lines
7.8 KiB
Markdown
# D&D Combat-Turn Artifact Contract
|
|
|
|
This document defines the durable artifact, serialization, extraction,
|
|
candidate-validation, normalization, and production lane boundaries for D&D
|
|
combat turns.
|
|
|
|
## Artifact identity
|
|
|
|
| Property | Value |
|
|
| --- | --- |
|
|
| Artifact kind | `dnd/combat-turn-list` |
|
|
| Schema ID | `notarius.dnd.combat_turns` |
|
|
| Schema name | `notarius_dnd_combat_turns_v1` |
|
|
| Schema version | `v1` |
|
|
| Media type | `application/json` |
|
|
|
|
The top-level JSON object contains the required `combat_turns` array, which
|
|
may be empty. Every object rejects unknown fields.
|
|
|
|
## JSON shape
|
|
|
|
Each combat turn contains these required fields:
|
|
|
|
| Field | Shape |
|
|
| --- | --- |
|
|
| `actor` | Non-empty string. |
|
|
| `turn_kind` | One of `turn`, `reaction`, `legendary_action`, `lair_action`, or `other`. |
|
|
| `round` | Required JSON field containing a positive integer or `null`. |
|
|
| `actions` | Required array with at least one action. |
|
|
| `summary` | Non-empty string. |
|
|
| `source_refs` | Required array with at least one source reference. |
|
|
|
|
Each action contains these required fields:
|
|
|
|
| Field | Shape |
|
|
| --- | --- |
|
|
| `category` | One of `attack`, `spell`, `movement`, `item`, `ability_check`, `saving_throw`, `condition`, or `other`. |
|
|
| `declaration` | Non-empty string describing what was declared. |
|
|
| `targets` | Required array of strings; the array may be empty, but entries may not be empty. |
|
|
| `resolution` | Required JSON field containing a non-empty string or `null`. |
|
|
|
|
Source references use the shared source-reference shape:
|
|
|
|
```json
|
|
{
|
|
"source_id": "session-alpha",
|
|
"start_unit_id": 1,
|
|
"end_unit_id": 2
|
|
}
|
|
```
|
|
|
|
`source_id` must be non-empty and both unit IDs must be positive integers. The
|
|
codec does not resolve references against a source document or enforce source
|
|
range ordering; those checks belong to the later source-reference validation
|
|
boundary.
|
|
|
|
## Codec behavior
|
|
|
|
The codec exposes two representations of the same typed artifact:
|
|
|
|
- Candidate encode/decode preserves invalid enum values, nullable values,
|
|
required-array presence, required strings, targets, and source references so
|
|
later validators can report them. Candidate decoding still requires valid
|
|
JSON, one JSON value, known fields, and the explicitly present `round` and
|
|
`resolution` keys; `null` is distinct from a missing key.
|
|
- Approved encode/decode enforces the structural rules in this contract.
|
|
|
|
The codec owns the durable JSON Schema, whose object layers all set
|
|
`additionalProperties` to `false`. Codec metadata contains only
|
|
`combat_turn_count`.
|
|
|
|
The maintained compact fixture is
|
|
`internal/modules/dnd/codec/combatturns/testdata/dnd_combat_turns.v1.json`.
|
|
|
|
## Extraction boundary
|
|
|
|
The standalone extractor uses these identities:
|
|
|
|
| Property | Value |
|
|
| --- | --- |
|
|
| Extractor key | `dnd/combat-turns` |
|
|
| Capability | `dnd.combat_turns` |
|
|
| Prompt ID | `dnd.combat_turns` |
|
|
| Prompt version | `v1` |
|
|
| Private response-schema key | `dnd_combat_turns_llm` |
|
|
| Private response-schema ID | `notarius.dnd.combat_turns.llm` |
|
|
| Default profile | `gemini-2-flash` |
|
|
|
|
It requires `chunks` and `source.transcript`, accepts no options, and makes one
|
|
structured completion for each supplied chunk. The prompt receives the
|
|
chunk-scoped transcript plus the existing `players`, `party`, and `glossary`
|
|
inputs, and optionally the deprecated `roster` reference through the shared
|
|
party mapping. The optional `npcs` reference is an approved normalized NPC
|
|
artifact used only for identity grounding; it never supplies combat evidence.
|
|
|
|
The private response envelope has the same fields and JSON types as the durable
|
|
turn/action shape except that source references contain only `start_unit_id`
|
|
and `end_unit_id`. It enforces required and nullable field presence, types, and
|
|
unknown-field rejection, while deterministic validators own enum membership,
|
|
non-empty values and collections, and positive-number requirements. The
|
|
extractor assigns the current source ID, removes exact duplicate ranges, and
|
|
stable-sorts turns by the earliest valid source-document position. Numeric unit
|
|
IDs are identifiers; source-document slice position determines chronology.
|
|
Semantically malformed candidate fields remain in the typed result for the
|
|
configured validation and retry boundary.
|
|
|
|
## Deterministic candidate validation
|
|
|
|
The standalone validator keys are:
|
|
|
|
| Validator | Responsibility |
|
|
| --- | --- |
|
|
| `extract/dnd/combat-turns/shape` | Required arrays, strings, nullable fields, positive rounds, and supported enum values. |
|
|
| `extract/dnd/combat-turns/source_refs` | Source identity, source-unit existence, and range order through the source document. |
|
|
| `extract/dnd/combat-turns/source_relatedness` | At most one advisory warning per turn when the actor or declared action is not related to cited transcript text. |
|
|
|
|
Source-reference and relatedness validators defer malformed shape to the shape
|
|
validator. Relatedness also defers when any cited source range is invalid. It
|
|
combines overlapping cited ranges once in document order, compares actors with
|
|
the shared Unicode-aware NPC identity policy, and checks declaration tokens of
|
|
at least four Unicode code points against complete cited-text tokens. Targets
|
|
are not checked deterministically.
|
|
|
|
The production D&D registrar exposes the extractor and these validators. Its
|
|
default extraction chain preserves this order: JSON syntax, private response
|
|
schema, combat shape, source references, then source relatedness.
|
|
|
|
## Normalization boundary
|
|
|
|
The standalone normalizer uses key `dnd/combat-turns`, requires `merged`,
|
|
provides `normalized`, accepts no options, and accepts only the optional
|
|
structured `npcs` reference. Campaign references are LLM extraction context and
|
|
are not normalizer inputs. The NPC registry is resolved during preparation;
|
|
runtime normalization uses that immutable prepared view.
|
|
|
|
Normalization policy is `dnd.combat_turns.normalize.v1`. It display-normalizes
|
|
actor, summary, declarations, targets, and non-null resolutions; canonicalizes
|
|
exact registry actor and target matches; orders and deduplicates exact source
|
|
references; stable-sorts records by earliest valid source-document position; and
|
|
collapses only records with the same actor identity, turn kind, round value, and
|
|
complete valid evidence set. The first normalized record is retained without
|
|
merging its actions or prose. Invalid evidence is never eligible for duplicate
|
|
collapse. Every mutation and collapse emits a bounded warning using the merged
|
|
input index in its scope.
|
|
|
|
The normalizer reports `normalization_policy` and `identity_policy` metadata and
|
|
fingerprints, plus `npc_registry_digest`, `npc_count`, and `npc_registry` only
|
|
when a registry is bound. The normalized-invariants validator is
|
|
`normalize/dnd/combat-turns/invariants`; it defers shape and source-reference
|
|
failures, then checks display normalization, target identity uniqueness,
|
|
canonical evidence ordering, chronology, and duplicate identity. It rejects
|
|
with `invalid_combat_turn_normalization` under policy
|
|
`dnd.combat_turns.validator.normalized.v1`.
|
|
|
|
The production D&D registrar exposes the normalizer and normalized-invariants
|
|
validator. Its default normalization chain is JSON syntax, durable schema,
|
|
combat shape, normalized invariants, source references, then source
|
|
relatedness. The lane uses the framework's typed append-order merger and has no
|
|
merge validator chain.
|
|
|
|
## Production manifest and references
|
|
|
|
The selectable lane uses extractor and normalizer key `dnd/combat-turns`,
|
|
`appendorder` for the typed merger, and the durable codec above. A bound `npcs`
|
|
reference contributes raw-file provenance to the run manifest. Prepared combat
|
|
extractor and normalizer metadata and checkpoint fingerprints contain only the
|
|
NPC registry's semantic digest and count; the registry content, path, and NPC
|
|
source ranges are not copied into combat output. The normalized lane is emitted
|
|
as `lanes/<lane-id>.json` by the JSON output module, and warnings and rejection
|
|
summaries remain in their shared companion files.
|