Add feature roadmap and implementation plan for a D&D combat turn extraction module
This commit is contained in:
201
docs/roadmap/dnd-combat-turn-extraction.md
Normal file
201
docs/roadmap/dnd-combat-turn-extraction.md
Normal file
@@ -0,0 +1,201 @@
|
||||
# D&D Combat-Turn Extraction
|
||||
|
||||
Status: Accepted.
|
||||
|
||||
## Purpose
|
||||
|
||||
Add a production D&D combat-turn pipeline that converts session transcripts
|
||||
into an ordered, evidence-backed account of combat activity. This is the next
|
||||
recommended increment because spell and NPC extraction now provide the two
|
||||
most important grounding vocabularies, while combat turns are the next useful
|
||||
artifact explicitly identified by the sequential-pipeline strategy.
|
||||
|
||||
The feature uses the existing fixed pipeline and scene chunks for a more
|
||||
structurally demanding artifact without requiring automatic workflow
|
||||
composition, richer scene routing, or generic semantic deduplication.
|
||||
|
||||
## Target Outcome
|
||||
|
||||
An operator can:
|
||||
|
||||
1. run the NPC pipeline against a transcript;
|
||||
2. run a combat-turn pipeline over the same transcript, explicitly binding the
|
||||
normalized NPC artifact as a reference;
|
||||
3. receive an ordered JSON list of validated combat turns and interrupting
|
||||
combat events; and
|
||||
4. trace every reported declaration and immediate resolution back to the
|
||||
transcript units that support it.
|
||||
|
||||
The runs remain independent CLI invocations. Notarius does not discover prior
|
||||
outputs, schedule dependent pipelines, or reconcile spell and combat artifacts
|
||||
automatically.
|
||||
|
||||
## Combat-Turn Artifact
|
||||
|
||||
The new typed artifact represents an ordered list of combat-turn records. Each
|
||||
record contains:
|
||||
|
||||
- the canonical in-world actor;
|
||||
- a turn kind distinguishing an ordinary turn from a reaction, legendary
|
||||
action, lair action, or other interrupting combat event;
|
||||
- the combat round as a positive integer when it is explicit or unambiguous,
|
||||
and `null` otherwise;
|
||||
- one or more ordered actions;
|
||||
- a concise turn-level summary; and
|
||||
- one or more transcript source references that collectively support every
|
||||
reported field.
|
||||
|
||||
Each action contains a conservative category, a concise declaration, zero or
|
||||
more targets, and its immediate observed resolution. Resolution is `null` when
|
||||
the cited passage establishes the declaration but no immediate resolution.
|
||||
Categories cover attacks, spells, movement, items, ability checks, saving
|
||||
throws, condition or state changes, and an `other` fallback without requiring
|
||||
the transcript to use formal rules terminology.
|
||||
|
||||
Reactions and similar out-of-turn events appear at the point where they occur
|
||||
in transcript chronology rather than being moved to the reacting creature's
|
||||
later turn. Output order is derived from cited source position; numeric source
|
||||
unit IDs are identifiers, not chronology.
|
||||
|
||||
## Inclusion And Evidence Policy
|
||||
|
||||
Include a record when the transcript establishes that an in-world participant
|
||||
takes a combat turn or performs a discrete interrupting combat event. Report
|
||||
only declarations and their immediate resolutions, including directly
|
||||
associated rolls, damage, healing, movement, conditions, or target outcomes.
|
||||
For every detail reported, cite all supporting transcript units.
|
||||
|
||||
Exclude:
|
||||
|
||||
- initiative setup that contains no turn or combat event;
|
||||
- tactical planning, table talk, rules lookup, and hypothetical actions;
|
||||
- corrected or abandoned declarations that never become an attempted action,
|
||||
except where the correction is necessary to describe the final declaration;
|
||||
- recap of combat that occurred outside the current source passage; and
|
||||
- downstream consequences that occur on later turns or elsewhere in the
|
||||
scene.
|
||||
|
||||
Do not infer a round number, action-economy classification, target, roll,
|
||||
amount, condition, or outcome merely from D&D rules knowledge. Preserve the
|
||||
session as played, and attribute nonstandard rulings to the GM or table when
|
||||
that detail is relevant to the immediate resolution.
|
||||
|
||||
## Identity And Reference Grounding
|
||||
|
||||
The extractor uses the existing D&D transcript, player, party, and glossary
|
||||
prompt inputs. It also accepts the normalized NPC artifact through an optional
|
||||
structured `npcs` reference slot with the same validation, size, provenance,
|
||||
content-safety, and semantic-checkpoint rules used by spell extraction.
|
||||
|
||||
The NPC registry helps select canonical actors and targets and recognize
|
||||
aliases. It does not establish that combat occurred and never becomes source
|
||||
evidence. Unmatched actors and targets remain permitted because a session may
|
||||
introduce combatants that were omitted from an earlier NPC run.
|
||||
|
||||
The deterministic normalizer also accepts the registry. Exact canonical-name
|
||||
or alias matches are rewritten to the registry's canonical display name for
|
||||
actors and targets; ambiguous aliases and unmatched values remain unchanged
|
||||
for validation and human review. Opaque player and party references continue
|
||||
to guide the LLM but are not parsed into a new roster contract in this scope.
|
||||
|
||||
## Extraction, Validation, And Normalization
|
||||
|
||||
The extractor uses one structured LLM call per supplied chunk and returns typed
|
||||
combat-turn candidates. It must preserve malformed candidates for the normal
|
||||
validation and retry boundary rather than silently repairing unsupported
|
||||
content in mapping code.
|
||||
|
||||
The production default validator chain is deterministic and covers:
|
||||
|
||||
- required fields, arrays, nullable-round shape, and supported enum values;
|
||||
- a required non-empty evidence collection, source identity, unit existence,
|
||||
and range order;
|
||||
- actor and declared-action relatedness to cited transcript text, expressed as
|
||||
bounded warnings where deterministic substring checks are only advisory; and
|
||||
- normalized identity and duplicate invariants.
|
||||
|
||||
Normalization is deterministic and conservative. It normalizes display
|
||||
whitespace, canonicalizes exact NPC identity matches, orders and deduplicates
|
||||
exact source references, and collapses only exact duplicate records with the
|
||||
same normalized actor, turn kind, round value, and complete valid evidence set.
|
||||
The first record is retained without synthesizing or merging prose. Every
|
||||
mutation or collapse emits a scoped warning.
|
||||
|
||||
An LLM-backed validator and semantic reconciliation normalizer are outside the
|
||||
production chain. Human evaluation owns judgments such as whether the
|
||||
model grouped a long turn correctly or omitted a subtle reaction.
|
||||
|
||||
## Scene Strategy
|
||||
|
||||
The combat extractor processes every chunk delivered by the configured
|
||||
chunker. Existing D&D scene annotations remain useful context, but a
|
||||
`primary_mode` value does not suppress an LLM call. Avoiding a
|
||||
call based on an imperfect non-combat classification could silently lose the
|
||||
very turns this artifact is intended to recover.
|
||||
|
||||
Scene-classification and routing improvements remain separate future work. The
|
||||
combat pipeline stays compatible with generic chunks that carry no D&D
|
||||
annotation.
|
||||
|
||||
## Provenance And Checkpoints
|
||||
|
||||
The extractor, normalizer, and validators report stable semantic identities
|
||||
through the existing manifest and prepared-component fingerprint contracts.
|
||||
Prompt, private response schema, artifact policy, normalization policy, and a
|
||||
bound NPC registry's semantic digest must invalidate incompatible checkpoints.
|
||||
|
||||
Metadata and fingerprints contain identities, counts, and digests only. They
|
||||
must not contain transcript text, combat records, NPC names, reference paths,
|
||||
or raw reference content. Preparation failures remain bounded and content-safe
|
||||
and occur before checkpoint handlers or pipeline execution are constructed.
|
||||
|
||||
## Evaluation
|
||||
|
||||
Use human-reviewed development runs rather than exact model-output goldens.
|
||||
Evaluate at least the existing transcripts used for spell and NPC development,
|
||||
with separate attention to:
|
||||
|
||||
- combat-turn detection precision and recall;
|
||||
- actor and target identity;
|
||||
- turn boundaries and chronological order;
|
||||
- reactions and other interrupting events;
|
||||
- declaration and immediate-resolution fidelity;
|
||||
- round-number restraint;
|
||||
- completeness and precision of evidence; and
|
||||
- duplicate behavior at chunk or scene boundaries.
|
||||
|
||||
Frontier and inexpensive development models may differ substantially in
|
||||
semantic quality. Deterministic tests should protect structure, provenance,
|
||||
identity, ordering, normalization, and orchestration rather than require exact
|
||||
combat prose.
|
||||
|
||||
## Out Of Scope
|
||||
|
||||
- Initiative trackers, current hit points, complete encounter-state replay, or
|
||||
rules-engine validation.
|
||||
- Automatic comparison or reconciliation with spell artifacts.
|
||||
- NPC discovery, campaign-wide entity persistence, or deterministic PC-roster
|
||||
parsing.
|
||||
- LLM-backed validation or generic LLM-assisted deduplication.
|
||||
- Automatic pipeline scheduling, prior-output discovery, or DAG execution.
|
||||
- Scene-classification changes or skipping provider calls for non-combat
|
||||
chunks.
|
||||
- Narrative summaries outside the immediate combat-turn scope.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- A selectable D&D combat lane produces a typed, durable JSON artifact with the
|
||||
turn, action, chronology, and evidence semantics above.
|
||||
- The default deterministic validator chain rejects malformed or invalidly
|
||||
sourced records and emits bounded advisory relatedness warnings.
|
||||
- Deterministic normalization canonicalizes exact NPC identities and collapses
|
||||
only safely identical combat records while preserving chronology and
|
||||
evidence.
|
||||
- A normalized NPC artifact can be bound explicitly to both extraction and
|
||||
normalization without becoming combat evidence.
|
||||
- Semantic contracts and structured references participate in checkpoint
|
||||
identity without leaking application content.
|
||||
- Maintained configuration and operational examples demonstrate independent
|
||||
NPC and combat invocations over the same transcript.
|
||||
- Human review on representative sessions demonstrates useful turn extraction
|
||||
without requiring scene-based call suppression or semantic reconciliation.
|
||||
@@ -18,9 +18,9 @@ not as committed release dates.
|
||||
|
||||
### Add Sequential D&D Artifacts
|
||||
|
||||
- Add combat-turn extraction with explicit event and source-reference
|
||||
semantics. Use earlier NPC output as a reference to improve participant
|
||||
identity and consistency.
|
||||
- The next proposed increment is
|
||||
[D&D combat-turn extraction](dnd-combat-turn-extraction.md), using earlier NPC
|
||||
output as an explicit identity reference while preserving independent runs.
|
||||
- Add narrative extraction for scene summaries, party actions, and NPCs
|
||||
encountered when that output proves useful beyond the dedicated NPC artifact.
|
||||
- Define the preferred operational sequence for independent pipelines on the
|
||||
|
||||
515
docs/roadmap/implementation.md
Normal file
515
docs/roadmap/implementation.md
Normal file
@@ -0,0 +1,515 @@
|
||||
# D&D Combat-Turn Extraction Implementation Plan
|
||||
|
||||
Status: Ready for implementation.
|
||||
|
||||
Implement this plan in order. The feature policy and target state are defined
|
||||
in [D&D Combat-Turn Extraction](dnd-combat-turn-extraction.md); this document
|
||||
owns implementation sequencing and concrete technical decisions.
|
||||
|
||||
Do not introduce a DAG, prior-run discovery, encounter state engine, scene-based
|
||||
provider-call suppression, LLM-backed validator, or semantic reconciliation.
|
||||
Preserve the fixed `input -> chunk -> extract -> merge -> normalize -> output`
|
||||
architecture and the existing framework retry, warning, rejection, checkpoint,
|
||||
debug, and output contracts.
|
||||
|
||||
## Cross-Stage Decisions
|
||||
|
||||
### Production Identities
|
||||
|
||||
Use these exact identities:
|
||||
|
||||
- artifact kind: `dnd/combat-turn-list`;
|
||||
- extractor key and normalizer key: `dnd/combat-turns`;
|
||||
- extractor capability: `dnd.combat_turns`;
|
||||
- prompt ID: `dnd.combat_turns`, version `v1`;
|
||||
- private response-schema key: `dnd_combat_turns_llm`;
|
||||
- private schema ID: `notarius.dnd.combat_turns.llm`;
|
||||
- private schema name: `notarius_dnd_combat_turns_llm_v1`;
|
||||
- durable schema ID: `notarius.dnd.combat_turns`;
|
||||
- durable schema name: `notarius_dnd_combat_turns_v1`;
|
||||
- durable schema version: `v1`; and
|
||||
- durable media type: `application/json`.
|
||||
|
||||
The private response schema omits `source_id`; mapping code assigns the current
|
||||
source identity. No combat-turn ID is added in v1.
|
||||
|
||||
### Canonical Go And JSON Shape
|
||||
|
||||
Add these types to the canonical D&D model:
|
||||
|
||||
```go
|
||||
type CombatTurnList struct {
|
||||
CombatTurns []CombatTurn `json:"combat_turns"`
|
||||
}
|
||||
|
||||
type CombatTurn struct {
|
||||
Actor string `json:"actor"`
|
||||
TurnKind CombatTurnKind `json:"turn_kind"`
|
||||
Round *int `json:"round"`
|
||||
Actions []CombatAction `json:"actions"`
|
||||
Summary string `json:"summary"`
|
||||
SourceRefs []source.SourceRef `json:"source_refs"`
|
||||
}
|
||||
|
||||
type CombatAction struct {
|
||||
Category CombatActionCategory `json:"category"`
|
||||
Declaration string `json:"declaration"`
|
||||
Targets []string `json:"targets"`
|
||||
Resolution *string `json:"resolution"`
|
||||
}
|
||||
```
|
||||
|
||||
Define string types and only these lowercase durable values:
|
||||
|
||||
- `CombatTurnKind`: `turn`, `reaction`, `legendary_action`, `lair_action`,
|
||||
`other`;
|
||||
- `CombatActionCategory`: `attack`, `spell`, `movement`, `item`,
|
||||
`ability_check`, `saving_throw`, `condition`, `other`.
|
||||
|
||||
All object fields and the top-level `combat_turns` array are required.
|
||||
`combat_turns` may be empty. Every turn requires a non-empty actor, supported
|
||||
turn kind, at least one action, non-empty summary, and at least one source
|
||||
reference. `round` is either `null` or a positive integer. Every action requires
|
||||
a supported category, non-empty declaration, and present `targets` array;
|
||||
targets may be empty but may not contain empty strings. `resolution` is either
|
||||
`null` or non-empty after trimming. Unknown fields are rejected at every object
|
||||
level.
|
||||
|
||||
Strict raw decoding must distinguish a missing required `round` or `resolution`
|
||||
key from an explicitly present JSON `null`, even though the accepted Go value
|
||||
represents `null` with a nil pointer. Use presence-aware wire decoding or raw
|
||||
key validation at codec and private-response boundaries; do not silently turn a
|
||||
missing nullable field into an accepted null.
|
||||
|
||||
One turn-level source-reference collection collectively supports the actor,
|
||||
kind, round, actions, summary, targets, and resolutions. Do not add per-action
|
||||
references in v1.
|
||||
|
||||
### Ordering And Duplicate Identity
|
||||
|
||||
Source-document slice position is chronology. Numeric unit IDs are identifiers
|
||||
only. An item's earliest evidence position is the minimum valid start-unit
|
||||
index across all its ranges. Stable ordering puts records with valid evidence
|
||||
in ascending earliest-position order, preserves encounter order for ties, and
|
||||
puts records without valid evidence after valid records without reordering
|
||||
them.
|
||||
|
||||
The normalizer may collapse two records only when all of these match:
|
||||
|
||||
- actor under `npcs/identity.ComparisonKey`;
|
||||
- exact `turn_kind`;
|
||||
- both round values, including `nil` versus a value; and
|
||||
- the complete, non-empty, canonically ordered set of exact source references.
|
||||
|
||||
Every reference in the duplicate key must pass `source.ValidateRef` against the
|
||||
current document. Invalid or empty evidence never participates in duplicate
|
||||
collapse. Actions and prose do not participate in identity because two model
|
||||
representations of the same cited turn should collapse; retain the complete
|
||||
first record without merging prose or action lists.
|
||||
|
||||
### NPC Registry Contract And Prompt Reuse
|
||||
|
||||
Promote NPC registry preparation from the spell extractor into
|
||||
`internal/modules/dnd/npcs/registry`. It owns:
|
||||
|
||||
- slot name `npcs` and maximum size 1,048,576 bytes;
|
||||
- exact-one-item and `application/json` validation when bound;
|
||||
- approved NPC codec decoding, whole-registry identity validation, canonical
|
||||
re-encoding, semantic SHA-256 digest, and content-safe bounded failures;
|
||||
- the exact unbound prompt value `{"npcs":[]}`;
|
||||
- immutable accessors for bound state, a defensive NPC list, canonical bytes,
|
||||
digest, count, and prompt input; and
|
||||
- exact canonical-name/alias lookup using the NPC identity comparison policy.
|
||||
|
||||
Registry source references may identify another session and are not checked
|
||||
against the current source. The resolver never returns content, names, aliases,
|
||||
paths, or raw decoder errors in failures. Identity failures use issue codes and
|
||||
record/alias indexes under the established 20-issue, 128-rune, and 4,096-byte
|
||||
limits.
|
||||
|
||||
Move the generic bounded diagnostic helper from `dnd/npcs/diagnostics` to
|
||||
`dnd/shared/diagnostics`, updating existing NPC consumers. This is an internal
|
||||
package move with no diagnostic-policy change.
|
||||
|
||||
Add `common-dnd-npcs.md` to the shared D&D prompt assets. Its generic policy
|
||||
allows exact canonical participant names and alias recognition while stating
|
||||
that registry content is context, not event evidence. Both spell and combat
|
||||
prompts use this exact fragment immediately after the existing shared campaign
|
||||
reference message. Remove the spell-owned NPC fragment and include the shared
|
||||
fragment in both prompt hashes. This intentionally changes the spell prompt
|
||||
fingerprint once but must not change its request inputs, metadata shape,
|
||||
registry semantics, or output contract.
|
||||
|
||||
Both combat extraction and normalization declare the same optional registry
|
||||
slot. A bound registry contributes manifest metadata `npc_registry_digest` and
|
||||
`npc_count` and a local checkpoint fingerprint `npc_registry`. An absent slot
|
||||
contributes neither metadata fields nor that fingerprint.
|
||||
|
||||
### Validation And Diagnostics
|
||||
|
||||
Add deterministic validators with these exact identities:
|
||||
|
||||
| Validator key | Result reason | Policy fingerprint |
|
||||
| --- | --- | --- |
|
||||
| `extract/dnd/combat-turns/shape` | rejection `invalid_combat_turn_shape` | `dnd.combat_turns.validator.shape.v1` |
|
||||
| `extract/dnd/combat-turns/source_refs` | rejection `invalid_combat_turn_source_refs` | `dnd.combat_turns.validator.source_refs.v1` |
|
||||
| `extract/dnd/combat-turns/source_relatedness` | warning `combat_turn_not_near_source` | `dnd.combat_turns.validator.source_relatedness.v1` |
|
||||
| `normalize/dnd/combat-turns/invariants` | rejection `invalid_combat_turn_normalization` | `dnd.combat_turns.validator.normalized.v1` |
|
||||
|
||||
Shape owns required arrays, enum membership, nullable fields, positive rounds,
|
||||
and non-empty strings. Source-reference validation owns source identity, unit
|
||||
existence, and range order through `source.ValidateRef`. Later validators defer
|
||||
when shape is invalid; relatedness also defers when any source range is invalid.
|
||||
|
||||
Relatedness combines the turn's cited units once in document order, removing
|
||||
overlap. The actor is related when its NPC comparison key is a substring of the
|
||||
comparison-normalized cited text. For each action declaration, split its
|
||||
comparison-normalized form on runes that are not Unicode letters or digits,
|
||||
retain tokens of at least four Unicode code points, and require at least one
|
||||
retained token to occur as a complete cited-text token. No retained token means
|
||||
the declaration is unrelated. Emit at most one approved warning per turn,
|
||||
listing whether the actor and which action indexes were not related. Do not
|
||||
check targets deterministically.
|
||||
|
||||
The normalize invariant validator requires display-normalized strings,
|
||||
comparison-unique targets within each action, canonical exact source-reference
|
||||
order without duplicates, chronological record order for valid evidence, and
|
||||
absence of the duplicate identity defined above. It does not require every
|
||||
actor or target to exist in the optional NPC registry.
|
||||
|
||||
All rejection and warning messages use the shared diagnostic helper: at most 20
|
||||
displayed issues, at most 128 Unicode code points per displayed value, valid
|
||||
UTF-8, at most 4,096 bytes, Go quoting for control characters, and the exact
|
||||
total omitted count. Validators use strict empty-options decoders and provide
|
||||
one local `policy` checkpoint fingerprint with the value in the table.
|
||||
|
||||
### Normalization Policy
|
||||
|
||||
Use normalization policy `dnd.combat_turns.normalize.v1` and these warning
|
||||
reason codes:
|
||||
|
||||
- `combat_turn_fields_normalized`;
|
||||
- `combat_actor_canonicalized`;
|
||||
- `combat_target_canonicalized`;
|
||||
- `source_references_normalized`;
|
||||
- `combat_turns_reordered`; and
|
||||
- `duplicate_combat_turn_collapsed`.
|
||||
|
||||
Deep-clone all nested slices and pointers. Normalize actor, summary,
|
||||
declarations, targets, and non-null resolutions by collapsing Unicode
|
||||
whitespace through `npcs/identity.NormalizeDisplay`. Preserve `nil` resolution.
|
||||
Remove comparison-duplicate targets while retaining the first display value and
|
||||
target order. Do not deduplicate or reorder actions.
|
||||
|
||||
When a registry is bound, rewrite an actor or target only if its comparison key
|
||||
matches exactly one validated canonical name or alias. Preserve unmatched
|
||||
values. Registry validation makes ambiguous lookup impossible at preparation;
|
||||
do not guess or perform fuzzy matching.
|
||||
|
||||
Sort every source-reference list by exact `source_id`, `start_unit_id`, and
|
||||
`end_unit_id`, then remove exact duplicates. Stable-sort records by the
|
||||
chronology rule before duplicate detection. Collapse duplicates in that order
|
||||
and retain the first record unchanged after its per-record normalization.
|
||||
|
||||
Warning scopes use merged input indexes such as `combat_turns[3]`, even after
|
||||
sorting or collapse. Emit one bounded warning for each affected record or
|
||||
collapsed group; group warnings identify the retained and removed input indexes.
|
||||
Only warnings from a validator-approved attempt become durable, under existing
|
||||
framework policy.
|
||||
|
||||
The normalizer exposes manifest metadata `normalization_policy`,
|
||||
`identity_policy`, and optional registry digest/count. Its checkpoint
|
||||
fingerprints are `normalization_policy`, `identity_policy`, and optional
|
||||
`npc_registry`; bump the normalization policy when any transformation,
|
||||
ordering, or duplicate rule changes.
|
||||
|
||||
### Testing Rules
|
||||
|
||||
Follow `docs/policy/testing.md`. Tests are offline and deterministic. Use a fake
|
||||
structured LLM only at the completion boundary. Protect durable shapes, domain
|
||||
invariants, preparation failures, reference sensitivity, registration, and one
|
||||
representative assembled workflow.
|
||||
|
||||
Do not add prompt-prose change detectors or tests requiring particular words or
|
||||
phrases. Prompt tests may verify registration, message/input wiring, prompt and
|
||||
schema identities, stable shared-fragment use, and absence of raw content from
|
||||
metadata or diagnostics. Human evaluation owns semantic output quality.
|
||||
|
||||
## Stage 1: Shared NPC Registry And Prompt Grounding
|
||||
|
||||
### Goal
|
||||
|
||||
Create one reusable, content-safe NPC registry boundary before adding a second
|
||||
consumer, while preserving spell behavior.
|
||||
|
||||
### Changes
|
||||
|
||||
- Add the domain registry resolver and immutable lookup described above; migrate
|
||||
spell extraction from its private resolver without changing the spell
|
||||
extractor's public module contract.
|
||||
- Relocate bounded D&D diagnostics to the shared domain package and update all
|
||||
NPC imports and tests.
|
||||
- Add the shared NPC prompt fragment, move the spell prompt to it, place it
|
||||
immediately after shared campaign references, and remove the spell-owned
|
||||
fragment.
|
||||
- Keep raw reference provenance in framework identity independently from the
|
||||
semantic registry fingerprint. Preserve the exact empty prompt input and all
|
||||
existing content-safe error behavior.
|
||||
- Update the internal overview, module, and LLM documentation in this stage so
|
||||
the implemented registry owner and shared prompt-fragment ownership remain
|
||||
accurate; do not claim combat extraction exists yet.
|
||||
|
||||
### Tests
|
||||
|
||||
- Move resolver contract tests to the domain package: absent, valid, formatted-
|
||||
equivalent, malformed, unknown-field, invalid-ID, collision, media type,
|
||||
item count, byte limit, defensive copies, lookup, digest, and bounded
|
||||
content-free diagnostics.
|
||||
- Retain spell-level tests only for spell request wiring, metadata/fingerprint
|
||||
behavior, and no-regression output; remove duplicated resolver cases.
|
||||
- Verify the shared prompt asset registers for spells and hashes the shared
|
||||
fragment without asserting its prose.
|
||||
|
||||
### Completion Check
|
||||
|
||||
Run `go test ./internal/modules/dnd/npcs/... ./internal/modules/dnd/extract/spells ./internal/modules/dnd/validate/npcs/...`
|
||||
and `git diff --check`.
|
||||
|
||||
## Stage 2: Combat Domain Contract And Codec
|
||||
|
||||
### Goal
|
||||
|
||||
Establish the typed artifact and durable serialization boundary without making
|
||||
the combat module selectable.
|
||||
|
||||
### Changes
|
||||
|
||||
- Add the canonical combat types, enums, constants, and artifact kind using the
|
||||
exact shape and values above.
|
||||
- Add `internal/modules/dnd/codec/combatturns`, following the existing candidate
|
||||
versus approved codec boundary:
|
||||
- strict single-value JSON with unknown-field rejection;
|
||||
- candidate encode/decode preserving validator-visible invalid values;
|
||||
- approved encode/decode enforcing structural validity only;
|
||||
- defensive schema and metadata values; and
|
||||
- metadata containing `combat_turn_count` only.
|
||||
- Add the durable v1 JSON Schema with required nullable fields, enum values,
|
||||
source-reference shape, array rules, and `additionalProperties: false`.
|
||||
- Add `docs/integrations/dnd-combat-turn-artifacts.md`, describing only the
|
||||
implemented artifact and codec at this stage.
|
||||
|
||||
### Tests
|
||||
|
||||
- Test approved round trips and candidate preservation for every nullable,
|
||||
enum, required-array, required-string, target, and source-reference boundary.
|
||||
- Test malformed, trailing, unknown-field, and invalid structural input without
|
||||
snapshotting complete errors.
|
||||
- Test defensive schema/metadata copies, nil versus present-empty arrays, and
|
||||
exact codec identity.
|
||||
- Keep one compact durable v1 fixture for intentional compatibility coverage.
|
||||
|
||||
### Completion Check
|
||||
|
||||
Run `go test ./internal/modules/dnd/codec/combatturns` and `git diff --check`.
|
||||
|
||||
## Stage 3: Combat Extractor And Extraction Validators
|
||||
|
||||
### Goal
|
||||
|
||||
Implement package-complete LLM extraction and deterministic candidate
|
||||
validation without production composition.
|
||||
|
||||
### Changes
|
||||
|
||||
- Add `internal/modules/dnd/extract/combatturns` with the exact module, prompt,
|
||||
schema, capability, artifact, and reference identities above. It accepts no
|
||||
options and requires `chunks` and `source.transcript`. The prompt manifest is
|
||||
`dnd.combat_turns.yaml`, uses default profile `gemini-2-flash`, JSON Schema
|
||||
validation, and zero provider-side repair attempts so pipeline retries remain
|
||||
the only extraction retry policy.
|
||||
- Declare existing optional `players`, `party`, `glossary`, and deprecated
|
||||
`roster` slots plus the optional structured NPC registry slot. Reuse shared
|
||||
D&D prompt inputs and the shared NPC prompt fragment.
|
||||
- Embed a private response schema matching the durable shape except that source
|
||||
ranges omit `source_id`. Require present arrays and nullable round/resolution
|
||||
values exactly as in the durable contract.
|
||||
- Prompt for the inclusion, exclusion, chronology, identity, round restraint,
|
||||
and immediate-resolution policy in the feature roadmap. Instruct the model
|
||||
that campaign and NPC references disambiguate identities but are never combat
|
||||
evidence.
|
||||
- Preserve malformed response values for validators. Canonicalize and exactly
|
||||
deduplicate source ranges, assign the current source ID, and stable-sort
|
||||
records by earliest valid source-document position. Do not merge records,
|
||||
canonicalize NPC names deterministically, or skip any chunk in the extractor.
|
||||
- Expose prompt and private-schema manifest metadata plus optional registry
|
||||
digest/count. Fingerprint local names `prompt`, `response_schema`,
|
||||
`mapping_policy` with value `dnd.combat_turns.extract_mapping.v1`, and optional
|
||||
`npc_registry`.
|
||||
- Implement shape, source-reference, and source-relatedness validators with the
|
||||
exact contracts and policies above.
|
||||
|
||||
### Tests
|
||||
|
||||
- Through a fake LLM, test request identity, profile/session propagation,
|
||||
chunk-scoped source input, campaign and NPC inputs, response mapping, source
|
||||
assignment, non-monotonic-unit chronology, invalid-candidate preservation,
|
||||
cancellation, and contextual provider failures.
|
||||
- Test prompt/schema registration, required input wiring, metadata and
|
||||
fingerprint sensitivity, defensive copies, and content redaction without
|
||||
asserting prompt prose.
|
||||
- Test each validator's meaningful approval, rejection, deferral, and warning
|
||||
categories, including Unicode comparison, overlapping evidence, declaration
|
||||
tokenization, bounded diagnostics, strict options, and typed registration.
|
||||
- Verify that a bound NPC registry affects grounding metadata and checkpoint
|
||||
identity but never supplies combat source references.
|
||||
|
||||
### Completion Check
|
||||
|
||||
Run `go test ./internal/modules/dnd/extract/combatturns ./internal/modules/dnd/validate/combatturns/...`
|
||||
and `git diff --check`.
|
||||
|
||||
## Stage 4: Combat Normalization And Final Invariants
|
||||
|
||||
### Goal
|
||||
|
||||
Implement conservative identity canonicalization, chronological ordering, and
|
||||
exact-evidence duplicate collapse.
|
||||
|
||||
### Changes
|
||||
|
||||
- Add `internal/modules/dnd/normalize/combatturns` with key
|
||||
`dnd/combat-turns`, requirements `merged`, capability `normalized`, no
|
||||
options, and the optional NPC registry slot.
|
||||
- Resolve and retain the immutable registry during preparation. Runtime uses
|
||||
the prepared view; it does not parse references repeatedly.
|
||||
- Apply the exact per-record, registry, source-reference, chronology, duplicate,
|
||||
warning, metadata, and fingerprint policies above. Never mutate or retain
|
||||
caller-owned slices, pointers, registry data, or source data.
|
||||
- Add the normalized-invariants validator. It remains deterministic, accepts no
|
||||
references of its own, and defers malformed shape or invalid source evidence
|
||||
to their owning validators.
|
||||
|
||||
### Tests
|
||||
|
||||
- Use table-driven cases for whitespace, nullable resolution, target
|
||||
deduplication, actor/target registry matches, unmatched names, reference
|
||||
normalization, non-monotonic source IDs, stable ties, and warning scopes.
|
||||
- Cover duplicate collapse and non-collapse for every identity dimension,
|
||||
especially invalid evidence, distinct ranges, different turn kinds, and
|
||||
`nil` versus numbered rounds.
|
||||
- Prove actions/prose come only from the first retained record, merged input is
|
||||
immutable, and all nested output storage is independent.
|
||||
- Test absent and bound registries, preparation failures, metadata,
|
||||
fingerprints, policy sensitivity, cancellation, strict options, and module
|
||||
registration.
|
||||
- Test normalized-invariant rejection for each owned invariant without
|
||||
duplicating shape and source-validator case matrices.
|
||||
|
||||
### Completion Check
|
||||
|
||||
Run `go test ./internal/modules/dnd/normalize/combatturns ./internal/modules/dnd/validate/combatturns/...`
|
||||
and `git diff --check`.
|
||||
|
||||
## Stage 5: Production Composition, Sequential Workflow, And Documentation
|
||||
|
||||
### Goal
|
||||
|
||||
Make the complete combat lane selectable, verify the assembled workflow, and
|
||||
document current behavior in canonical locations.
|
||||
|
||||
### Changes
|
||||
|
||||
- Extend the D&D registrar with the combat codec, extractor and prompt assets,
|
||||
typed append-order merger, combat normalizer, typed no-op normalizer, all four
|
||||
validators, and typed always-accept/always-reject variants.
|
||||
- Add append behavior that preserves present-empty versus nil output and chunk
|
||||
record order before normalization.
|
||||
- Register the extract default chain in this order:
|
||||
`generic/valid_json`, `generic/valid_json_schema`, combat shape, combat source
|
||||
references, combat source relatedness.
|
||||
- Register the normalize default chain in this order:
|
||||
`generic/valid_json`, `generic/valid_json_schema`, combat shape, normalized
|
||||
invariants, combat source references, combat source relatedness.
|
||||
- Do not add a merge validator chain or change framework defaults.
|
||||
- Add `examples/dnd-combat-turns.config.yml` and
|
||||
`examples/dnd-npc-combat-sequential.config.yml`. Use version 3, safe relative
|
||||
state paths, explicit checkpoint `enabled: false`, a generic chunker, combat
|
||||
extraction with `retries: 2`, and combat normalization. Keep the dynamic NPC
|
||||
output unbound in the static sequential example.
|
||||
- Demonstrate runtime binding to both stage-local slots with selectors
|
||||
`combat.extract.npcs=<npc-run>/lanes/npcs.json` and
|
||||
`combat.normalize.npcs=<npc-run>/lanes/npcs.json`.
|
||||
- Update canonical current-behavior documentation:
|
||||
- Configuration owns module/validator catalogs, reference slots, limits,
|
||||
default chains, and maintained examples;
|
||||
- CLI owns the explicit two-selector invocation syntax;
|
||||
- Operations owns the independent NPC-then-combat workflow and state
|
||||
sensitivity;
|
||||
- the combat integration contract owns durable fields, enum values,
|
||||
evidence, normalization, warnings, and manifest metadata;
|
||||
- the NPC integration contract notes combat as a consumer without redefining
|
||||
combat fields;
|
||||
- JSON output links the new lane payload; and
|
||||
- internal overview, module, and LLM docs describe concrete packages,
|
||||
preparation, prompt reuse, and fingerprints.
|
||||
- At completion, mark this plan and the feature roadmap complete. Remove the
|
||||
implemented combat proposal from `future.md` while retaining scene-routing,
|
||||
narrative, generic deduplication, and other unimplemented work.
|
||||
|
||||
### Tests
|
||||
|
||||
- Extend registrar tests for production keys, typed variants, prompt assets,
|
||||
default chain order, nil dependencies, and duplicate registration behavior.
|
||||
- Add config/example resolution coverage for stage-local NPC bindings,
|
||||
capabilities, codec compatibility, strict options, and invalid validator
|
||||
placement.
|
||||
- Add one assembled pipeline integration covering extract, retry-capable
|
||||
validation, append merge, registry-backed normalization, final validation,
|
||||
JSON output, warnings, manifest metadata, and checkpoint fingerprints using a
|
||||
fake LLM.
|
||||
- Add one sequential integration that materializes normalized NPC output as
|
||||
both combat references and verifies canonical actor/target output, reference
|
||||
provenance, and that NPC source ranges never become combat evidence.
|
||||
- Add preparation-boundary coverage showing malformed or oversized NPC input
|
||||
fails before checkpoint construction or pipeline execution. Do not duplicate
|
||||
the shared resolver's complete malformed-input matrix.
|
||||
- Validate maintained examples and documentation links through existing test
|
||||
mechanisms.
|
||||
|
||||
### Completion Check
|
||||
|
||||
Run the final verification suite.
|
||||
|
||||
## Final Verification
|
||||
|
||||
Run:
|
||||
|
||||
```sh
|
||||
git diff --check
|
||||
go test ./...
|
||||
go vet ./...
|
||||
go build ./cmd/notarius
|
||||
go test -race ./internal/modules/dnd/... ./internal/framework/pipeline \
|
||||
./internal/cli ./internal/modules/integration
|
||||
```
|
||||
|
||||
Review the final diff for:
|
||||
|
||||
- D&D or provider behavior leaking into generic framework packages;
|
||||
- accidental scene-based call suppression or automatic pipeline composition;
|
||||
- mutation or aliasing of typed artifacts, schemas, references, metadata, or
|
||||
fingerprints;
|
||||
- transcript, registry, prompt, schema, path, or decoder content leaking into
|
||||
errors, manifests, fingerprints, or redacted summaries;
|
||||
- prompt-prose change-detector tests, redundant cross-layer cases, or exact LLM
|
||||
output goldens;
|
||||
- current-behavior documentation claiming features before the implementing
|
||||
stage lands; and
|
||||
- unrelated worktree changes.
|
||||
|
||||
## Open Questions
|
||||
|
||||
None. Artifact fields and enums, nullable behavior, chronology, duplicate
|
||||
identity, reference reuse, prompt composition, validator placement,
|
||||
normalization, checkpoint semantics, documentation ownership, and stage
|
||||
boundaries are fixed by this plan.
|
||||
Reference in New Issue
Block a user