Harmonize D&D artifact contracts
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
# D&D Combat-Turn Artifact Contract
|
||||
# D&D Combat-Turn Artifact
|
||||
|
||||
This document defines the durable artifact, serialization, extraction,
|
||||
candidate-validation, normalization, and production lane boundaries for D&D
|
||||
combat turns.
|
||||
This contract defines the durable combat-action occurrence list produced by
|
||||
`dnd/combat-turns`. It records source-grounded turns and actions; it is not a
|
||||
complete initiative tracker, combat summary, or state model.
|
||||
|
||||
## Artifact identity
|
||||
## Identity and compatibility
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
@@ -14,167 +14,56 @@ combat turns.
|
||||
| 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.
|
||||
`v1` is a strict JSON object with required `combat_turns`; the array may be
|
||||
empty. Turn and source-reference objects reject unknown fields. A future
|
||||
incompatible shape requires a new schema version.
|
||||
|
||||
## JSON shape
|
||||
## Wire shape
|
||||
|
||||
Each combat turn contains these required fields:
|
||||
Each combat turn has these required fields:
|
||||
|
||||
| Field | Shape |
|
||||
| Field | Contract |
|
||||
| --- | --- |
|
||||
| `actor` | Non-empty string. |
|
||||
| `turn_kind` | One of `turn`, `reaction`, `legendary_action`, `lair_action`, or `other`. |
|
||||
| `source_refs` | Required array with at least one source reference. |
|
||||
| `actor` | Non-empty acting character or creature name. |
|
||||
| `turn_kind` | `turn`, `reaction`, `legendary_action`, `lair_action`, or `other`. |
|
||||
| `source_refs` | One or more transcript evidence ranges. |
|
||||
|
||||
Source references use the shared source-reference shape:
|
||||
Each source reference has exactly `source_id`, `start_unit_id`, and
|
||||
`end_unit_id`. It identifies an inclusive current-transcript range; unit IDs
|
||||
are positive and the start may not follow the end.
|
||||
|
||||
```json
|
||||
{
|
||||
"source_id": "session-alpha",
|
||||
"start_unit_id": 1,
|
||||
"end_unit_id": 2
|
||||
"combat_turns": [
|
||||
{
|
||||
"actor": "Mira Thorn",
|
||||
"turn_kind": "turn",
|
||||
"source_refs": [
|
||||
{"source_id": "session-7", "start_unit_id": 31, "end_unit_id": 32}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
`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.
|
||||
## Eligibility, evidence, and normalized form
|
||||
|
||||
## Codec behavior
|
||||
The extractor requires an approved [scene-description artifact](dnd-scene-description-artifacts.md).
|
||||
It emits combat turns only for a chunk with an exact matching scene classified
|
||||
`combat`; an exact non-combat scene produces an accepted empty list. The scene
|
||||
record controls eligibility only: its title, summary, and reference do not
|
||||
become turn evidence. No exact matching scene also produces an empty list and
|
||||
the `scene_classification_unavailable` warning.
|
||||
|
||||
The codec exposes two representations of the same typed artifact:
|
||||
An optional normalized [NPC artifact](dnd-npc-artifacts.md) can ground an
|
||||
actor name. Its registry references are provenance, never combat evidence.
|
||||
Normalization trims and, where possible, canonicalizes actor names; orders and
|
||||
deduplicates exact source references; orders valid-evidence turns by source
|
||||
chronology; and collapses only duplicates with the same actor identity, turn
|
||||
kind, and complete valid evidence. It does not infer turns, initiative, or
|
||||
actions from registry or scene data.
|
||||
|
||||
- Candidate encode/decode preserves invalid actor and turn-kind values,
|
||||
collection presence, and source references so later validators can report
|
||||
them. Candidate decoding still requires valid JSON, one JSON value, known
|
||||
fields, and compatible JSON types.
|
||||
- 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 requires
|
||||
one `scene_descriptions` reference. That reference must be exactly one approved
|
||||
`dnd/scene-description-list` artifact with media type `application/json` and a
|
||||
maximum size of 1 MiB (1048576 bytes). It may be an external file validated
|
||||
during preparation or a canonical generated artifact supplied at an ordered
|
||||
step handoff. An unbound slot is a configuration error.
|
||||
|
||||
The scene artifact controls eligibility, not evidence. The extractor calls the
|
||||
LLM only when exactly one record has the current chunk's ID, source ID, start
|
||||
unit ID, and end unit ID, and that record has `kind: combat`. An exact
|
||||
`narrative`, `recap`, or `meta` record returns an accepted empty
|
||||
`combat_turns` array without an LLM call, warning, or retry attempt. A missing
|
||||
or mismatched exact record returns the same accepted empty result without an
|
||||
LLM call or retry and emits one content-safe
|
||||
`scene_classification_unavailable` warning. The scene artifact, its title and
|
||||
summary, and its source references are never copied into combat turns.
|
||||
|
||||
For an eligible combat 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. `scene_descriptions` is never a
|
||||
combat prompt input.
|
||||
|
||||
The private response envelope has the same turn fields and JSON types as the
|
||||
durable shape except that source references contain only `start_unit_id`
|
||||
and `end_unit_id`. It enforces required 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 list, actor, turn kind, and source references, plus supported turn-kind 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 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 and compares actors
|
||||
with the shared Unicode-aware NPC identity policy.
|
||||
|
||||
The production D&D registrar exposes the extractor and these validators. Its
|
||||
default extraction chain preserves this order: JSON syntax, combat shape,
|
||||
source references, private response schema, 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. For an external file, the NPC registry is resolved
|
||||
during preparation; for a generated binding, it is resolved at the operation-
|
||||
time handoff. Runtime normalization uses that immutable prepared or handed-off
|
||||
view.
|
||||
|
||||
Normalization policy is `dnd.combat_turns.normalize.v1`. It display-normalizes
|
||||
the actor, canonicalizes exact registry actor 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,
|
||||
and complete valid evidence set. The first normalized record is retained.
|
||||
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. An external registry may additionally contribute
|
||||
`npc_registry_digest` and `npc_count`; generated registry identity is retained
|
||||
in framework handoff provenance and dependency fingerprints. The
|
||||
normalized-invariants validator is
|
||||
`normalize/dnd/combat-turns/invariants`; it defers shape and source-reference
|
||||
failures, then checks actor display normalization, 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, combat shape,
|
||||
normalized invariants, source references, durable schema, 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. Bound external
|
||||
references contribute raw-file provenance to the run manifest. Generated
|
||||
bindings contribute artifact kind, schema identity, media type, canonical
|
||||
digest, size, and bounded producer provenance. This includes the generated
|
||||
scene-description artifact for the combat extractor. Consumer metadata and
|
||||
checkpoint fingerprints contain no reference names, content, paths, source
|
||||
ranges, scene titles, or scene summaries. For an external scene artifact,
|
||||
component metadata records the gate policy plus a semantic eligibility digest
|
||||
and record count; generated scene identity remains in framework handoff
|
||||
provenance and dependencies. The eligibility digest changes with scene ID,
|
||||
exact source range, or kind, but not with title or summary. 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.
|
||||
The [NPC-interaction artifact](dnd-npc-interaction-artifacts.md) records
|
||||
broader NPC occurrences. The [JSON output contract](json-output.md) defines
|
||||
publication, and [D&D module internals](../internal/dnd.md) describes routing
|
||||
and validation mechanics.
|
||||
|
||||
Reference in New Issue
Block a user