Audit combat and enemy event processing

This commit is contained in:
2026-08-08 22:54:00 +00:00
parent 0fc2f9ee01
commit e3839f8620

View File

@@ -20,9 +20,10 @@ change only roadmap audit documents do not change that production target.
Pending final synthesis. The initial baseline is healthy. The architecture,
configuration/CLI, pipeline composition, reference/handoff, runtime, state,
LLM, generic/Seriatim, shared D&D, registry-family, occurrence-family, and
spell/scene-family reviews have found three High findings, six Medium findings,
and twenty-three Low findings, with no production dependency inversion,
LLM, generic/Seriatim, shared D&D, registry-family, occurrence-family,
spell/scene-family, and combat/enemy-family reviews have found three High
findings, seven Medium findings, and twenty-three Low findings, with no
production dependency inversion,
unbounded framework worker pool, completion-order-dependent result assembly,
debug-to-cache coupling, model-visible credential material in the embedded LLM
assets, or domain leakage across the Seriatim and generic module boundaries.
@@ -57,14 +58,15 @@ Final cross-area ordering is pending synthesis.
| MOD-003 | Low | Simplicity | Remove unreachable JSON metadata clone helpers |
| DND-CORE-001 | Low | Simplicity | Remove the unused lossy unit-reference constructor |
| DND-REG-001 | Low | Correctness | Reject reversed evidence ranges at durable D&D codec boundaries |
| DND-REG-002 | Low | Correctness | Keep NPC and spell extraction evidence inside the current chunk |
| DND-REG-003 | Low | Efficiency | Index item and location duplicate groups |
| DND-REG-002 | Low | Correctness | Keep extraction evidence inside the current chunk |
| DND-REG-003 | Low | Efficiency | Index duplicate groups across D&D families |
| DND-REG-004 | Low | Efficiency | Select location identity anchors without sorting |
| DND-OCC-001 | Medium | Correctness | Align item occurrence evidence fields with the shared prompt |
| DND-OCC-002 | Low | Simplicity | Remove unused campaign references from NPC occurrence normalization |
| DND-OCC-003 | Low | Efficiency | Reuse canonical item occurrence evidence |
| DND-SCENE-001 | Medium | Correctness | Expose catalog aliases to spell extraction |
| DND-SCENE-002 | Low | Correctness | Make scene and spell normalization diagnostics complete and bounded |
| DND-SCENE-002 | Low | Correctness | Make D&D normalization and advisory diagnostics complete and bounded |
| DND-COMBAT-001 | Medium | Correctness | Enforce enemy-event semantics at the durable codec boundary |
## Findings
@@ -876,26 +878,31 @@ Final cross-area ordering is pending synthesis.
- **Severity:** Low
- **Category:** Correctness
- **Evidence:** The three registry, three occurrence, spell, and scene-
description integration contracts require that a source range's start not
follow its end
- **Evidence:** The three registry, three occurrence, spell, scene-description,
combat-turn, and enemy-event integration contracts require that a source
range's start not follow its end
(`docs/integrations/dnd-npc-registry-artifacts.md:32``34`,
`dnd-item-registry-artifacts.md:33``35`, and
`dnd-location-registry-artifacts.md:34``36`; and
`dnd-npc-occurrence-artifacts.md:33``36`,
`dnd-item-occurrence-artifacts.md:41``43`,
`dnd-location-occurrence-artifacts.md:33``35`,
`dnd-spell-artifacts.md:31``35`, and
`dnd-scene-description-artifacts.md:33``35`). All eight reviewed durable
codec validators check only that both endpoints are positive
`dnd-spell-artifacts.md:31``35`,
`dnd-scene-description-artifacts.md:33``35`,
`dnd-combat-turn-artifacts.md:31``33`, and
`dnd-enemy-event-artifacts.md:33``35`). Nine of the ten durable codecs check
at most that both endpoints are positive
(`internal/modules/dnd/codec/npcregistry/codec.go:96``106`,
`codec/itemregistry/codec.go:97``107`, and
`codec/locationregistry/codec.go:97``107`; and
`codec/npcoccurrences/codec.go:99``109`,
`codec/itemoccurrences/codec.go:117``127`,
`codec/locationoccurrences/codec.go:100``110`,
`codec/spells/codec.go:89``99`, and
`codec/scenedescriptions/codec.go:101``109`). Direct registry references are
`codec/spells/codec.go:89``99`,
`codec/scenedescriptions/codec.go:101``109`, and
`codec/combatturns/codec.go:95``106`); the enemy-event codec checks only JSON
field presence and accepts even non-positive endpoints
(`codec/enemyevents/codec.go:86``135`). Direct registry references are
decoded and identity-checked by `npcs/registry.loadRegistry`,
`items/registry.loadRegistry`, and `locations/registry.loadRegistry`, but do
not pass through the generated-output source-reference validators. A durable
@@ -912,12 +919,14 @@ Final cross-area ordering is pending synthesis.
interval.
NPC and item prompt projections then hide the malformed provenance, a
location can derive and retain a durable ID from it, and scene gating can
retain the impossible interval as eligibility metadata; only later consumers
with source context may reject it. Generated pipeline outputs remain
retain the impossible interval as eligibility metadata. A malformed combat-
turn artifact can likewise be accepted for enemy grounding, whose compact
projection then strips the malformed provenance; only later consumers with
source context may reject it. Generated pipeline outputs remain
protected by their source-reference validator chains, which limits current
exposure.
- **Recommendation:** Add the order-independent structural condition
`start_unit_id <= end_unit_id` to all eight reviewed codecs' durable
`start_unit_id <= end_unit_id` to all ten codecs' durable
validation, and make location identity reject reversed anchors as a defense
in depth.
Keep document membership and current-chunk coverage in the existing
@@ -926,52 +935,64 @@ Final cross-area ordering is pending synthesis.
field/trailing-value rejection, location identity's earliest canonical
anchor policy, and the separation between source-independent durable shape
validation and source-dependent evidence validation.
- **Validation:** Add codec encode/decode cases for reversed ranges in all eight
reviewed families, a location identity case that refuses a reversed-only
anchor, and direct registry, occurrence, spell, and scene-eligibility
reference cases proving malformed referenced JSON is rejected; run the
- **Validation:** Add codec encode/decode cases for reversed ranges in all ten
families, a location identity case that refuses a reversed-only
anchor, and direct registry, occurrence, spell, scene-eligibility, combat-
turn, and enemy-event reference cases proving malformed referenced JSON is
rejected; run the
codec, identity, registry, spell, scene, occurrence, and assembled CLI suites.
- **Grouping:** Independent.
- **Grouping:** Coordinate the enemy-event codec change with DND-COMBAT-001;
the remaining nine codec changes are otherwise independent.
### DND-REG-002 — Keep NPC and spell extraction evidence inside the current chunk
### DND-REG-002 — Keep extraction evidence inside the current chunk
- **Severity:** Low
- **Category:** Correctness
- **Evidence:** The NPC, item, location, and spell extractors receive only the
current chunk and all four default extract chains run their family source-
reference validator. Item and location validators require a non-nil
- **Evidence:** The NPC, item, location, spell, combat-turn, and enemy-event
extractors receive only the current chunk, and all six default extract chains
run their family source-reference validator. Item and location validators require a non-nil
extraction chunk and reject references whose endpoints are not in it
(`internal/modules/dnd/validate/itemregistry/source_refs/validator.go:37``55`
and `validate/locationregistry/source_refs/validator.go:37``55`). The NPC
validator at `validate/npcregistry/source_refs/validator.go:36``53` checks
only that a reference is valid somewhere in the complete source document; it
neither requires `req.Chunk` during extraction nor checks chunk membership.
The spell validator has the same document-only behavior
(`validate/spells/source_refs/validator.go:35``51`). Its tests exercise
The spell and combat-turn validators have the same document-only behavior
(`validate/spells/source_refs/validator.go:35``51` and
`validate/combatturns/source_refs/validator.go:36``60`), while the enemy-
event validator correctly requires an extraction chunk and checks every
unit in each range (`validate/enemyevents/source_refs/validator.go:37``99`).
Spell and combat-turn tests exercise
valid, out-of-document, missing-document, malformed-shape, and bounded-
aggregate cases, but supply no stage or chunk and do not cover an existing
off-chunk range (`validator_test.go:15``73`).
- **Impact:** If an NPC or spell extraction response supplies a valid unit ID
off-chunk range (`validate/spells/source_refs/validator_test.go:15``73` and
`validate/combatturns/source_refs/validator_test.go:15``73`).
- **Impact:** If an NPC, spell, or combat-turn extraction response supplies a
valid unit ID
from another chunk, the candidate can pass evidence validation despite the
model never receiving that passage. Relatedness can also succeed when the NPC
name or spell appears only at the cited off-chunk range, causing duplicated
actor, NPC name, or spell appears only at the cited off-chunk range, causing
duplicated
or misattributed provenance across chunk results. The model usually copies
visible unit IDs, which limits the likelihood.
- **Recommendation:** Match the item/location extraction contract: require the
current chunk when `req.Stage` is extract and reject NPC and spell references
current chunk when `req.Stage` is extract and reject NPC, spell, and combat-
turn references
outside that chunk. Keep whole-document validation for normalize and other
non-extraction validation calls.
- **Preserve:** Retain full-document source-ID/range validation, shape deferral,
bounded aggregate diagnostics, normalization without a chunk, direct factual
third-party mentions, and source-relatedness as an advisory check rather than
an identity gate.
- **Validation:** Add NPC and spell source-reference cases for an existing off-
- **Validation:** Add NPC, spell, and combat-turn source-reference cases for an
existing off-
chunk range, a missing extraction chunk, an accepted in-chunk range, and
normalize-stage validation without a chunk; run both source-reference
validators, their extractors, and assembled pipeline tests.
normalize-stage validation without a chunk; run the affected source-reference
validators, their extractors, and assembled pipeline tests; retain the enemy-
event in-chunk, off-chunk, and missing-chunk cases as the reference behavior.
- **Grouping:** Independent.
### DND-REG-003 — Index item and location duplicate groups
### DND-REG-003 — Index duplicate groups across D&D families
- **Severity:** Low
- **Category:** Efficiency
@@ -982,25 +1003,38 @@ Final cross-area ordering is pending synthesis.
comparison key. `exactDuplicateGroups` in
`normalize/locationregistry/normalizer.go:229``246` repeats that nested scan
and performs `reflect.DeepEqual` over canonical source-reference slices for
each candidate group. With distinct records, both paths are quadratic before
any LLM reconciliation request is built.
- **Impact:** Large merged registries spend avoidable deterministic CPU in
each candidate group. Enemy-event normalization likewise scans all retained
events for every record and calls exact equality, which recanonicalizes both
evidence lists (`normalize/enemyevents/normalizer.go:207``227` and
`enemyevents/enemyevents.go:42``64`); its invariant validator repeats a
previous-event scan at `validate/enemyevents/invariants/validator.go:138``145`.
The knowledge graph reports loop depth two and transitive loop depth four for
enemy `collapseDuplicates`. With distinct records, all four paths are
quadratic.
- **Impact:** Large merged registries or enemy observation lists spend
avoidable deterministic CPU in
normalization, with the location cost also proportional to citation-list
comparisons. Normal registry sizes and the later LLM request dominate today,
so the issue is low severity.
comparisons. Normal artifact sizes bound the impact, and registry
reconciliation's later LLM request dominates its two paths today, so the
issue is low severity.
- **Recommendation:** Preserve first-seen group order while maintaining a local
index from the complete duplicate identity to its group position. Use the
existing comparison key for items and an exact, collision-safe key over the
comparison name plus canonical source-reference sequence for locations;
verify equality on any hash collision rather than using lossy concatenation.
apply the same collision-safe complete identity index to enemy events in both
normalization and invariant validation. Verify equality on any hash
collision rather than using lossy concatenation.
- **Preserve:** Item duplicates remain name-identity duplicates regardless of
evidence; locations collapse only equal comparison names with exactly equal
canonical evidence; group/member order, input-index provenance, warning
scopes, and later proposal-only semantic reconciliation remain unchanged.
Enemy events continue to collapse only equal normalized subject identity,
kind, and complete canonical evidence; different outcomes, evidence, and
repeated observations remain distinct.
- **Validation:** Add many-distinct and repeated-key cases that compare output
groups and warning order with current fixtures, plus a focused benchmark or
comparison-count hook demonstrating linear expected grouping work; run the
item and location normalizer tests.
item and location normalizer tests plus enemy normalizer and invariant tests.
- **Grouping:** Independent.
### DND-REG-004 — Select location identity anchors without sorting
@@ -1182,7 +1216,7 @@ Final cross-area ordering is pending synthesis.
validator, and CLI suites.
- **Grouping:** Independent.
### DND-SCENE-002 — Make scene and spell normalization diagnostics complete and bounded
### DND-SCENE-002 — Make D&D normalization and advisory diagnostics complete and bounded
- **Severity:** Low
- **Category:** Correctness
@@ -1198,26 +1232,79 @@ Final cross-area ordering is pending synthesis.
(`normalize/scenedescriptions/normalizer.go:70``124`) but always returns the
value without any warnings (lines 5368). Its primary test performs all three
mutations without asserting diagnostic provenance
(`normalizer_test.go:15``43`).
(`normalizer_test.go:15``43`). Combat-turn normalization also emits per-
actor, per-reference, per-reorder, and per-duplicate-group warnings without
applying the shared limiter (`normalize/combatturns/normalizer.go:131``188`
and 235273). Its advisory relatedness validator returns one warning per
unrelated turn without a limiter
(`validate/combatturns/source_relatedness/validator.go:45``67`), whereas
both enemy-event equivalents use `diagnostics.LimitWarnings`.
- **Impact:** A large spell list can publish an unbounded number of warnings,
inflating manifests, debug artifacts, output files, and checkpoint payloads.
Scene normalization silently changes accepted durable content, so operators
Combat lists can have the same warning amplification. Scene normalization
silently changes accepted durable content, so operators
cannot distinguish an unchanged scene list from repaired whitespace/order or
collapsed duplicates. Artifact values remain deterministic and valid.
- **Recommendation:** Pass spell warnings through the shared deterministic
limiter with a stable omission reason. Add bounded scene warnings that
- **Recommendation:** Pass spell and combat-turn normalization warnings and
combat-turn relatedness warnings through the shared deterministic limiter
with stable omission reasons. Add bounded scene warnings that
distinguish prose trimming, canonical reordering, and exact duplicate
collapse while retaining stable input scopes and order. Emit no warning for
an already canonical value.
- **Preserve:** Keep current normalized values, source-position ordering,
conflict rejection, duplicate identities, input immutability, per-record
diagnostic order below the limit, and idempotent warning-free second passes.
- **Validation:** Add spell cases beyond `diagnostics.MaxWarnings` that assert
the stable omission summary, and scene cases for each mutation, combined
overflow, canonical input, and idempotence; run both normalizer suites and
assembled output/checkpoint warning tests.
- **Validation:** Add spell, combat-normalizer, and combat-relatedness cases
beyond `diagnostics.MaxWarnings` that assert stable omission summaries, and
scene cases for each mutation, combined overflow, canonical input, and
idempotence; run all affected normalizer/validator suites and assembled
output/checkpoint warning tests.
- **Grouping:** Independent.
### Combat Turns And Enemy Events
### DND-COMBAT-001 — Enforce enemy-event semantics at the durable codec boundary
- **Severity:** Medium
- **Category:** Correctness
- **Evidence:** The enemy-event contract and embedded durable schema require a
non-empty subject, one of five event kinds, at least one source reference,
and a non-empty source ID with positive endpoints
(`docs/integrations/dnd-enemy-event-artifacts.md:19``35` and
`internal/modules/dnd/codec/enemyevents/assets/schemas/dnd_enemy_events.v1.json:4``34`).
`Codec.Decode` checks strict JSON and literal field presence, but
`validateRequiredJSONFields` does not enforce any of those value constraints;
`Codec.Encode` checks only that the event and reference slices are non-nil
(`codec/enemyevents/codec.go:52``95` and 98160). The focused codec test
explicitly proves durable `Decode` accepts a whitespace name, unsupported
kind, blank source ID, zero start, and negative end
(`codec/enemyevents/codec_test.go:76``92`). The combat-turn codec, by
contrast, enforces all equivalent value constraints except the separately
recorded reversed-range condition (`codec/combatturns/codec.go:80``108`).
- **Impact:** A direct enemy-event artifact decode can report contract-invalid
JSON as approved typed data. More importantly, the supported validator-
override surface can replace both family validation chains; a model response
with these invalid values can then reach durable output because the final
codec encode does not re-establish its published schema. Default chains
reject the values, so maintained production configuration is protected.
- **Recommendation:** Preserve candidate encode/decode as the permissive retry
boundary, but make durable `Encode` and `Decode` apply one shared value
validator covering the schema's name, kind, non-empty references, source ID,
and positive endpoint constraints. Also apply the forward-range check in
DND-REG-001. Keep the raw-object presence pass on decode where omitted versus
zero-valued JSON fields must remain distinguishable.
- **Preserve:** Retain strict unknown-field and trailing-value rejection,
defensive source-reference ownership, empty top-level event lists, candidate
preservation before validators, and document/chunk membership checks in the
source-aware validator rather than the codec.
- **Validation:** Replace the semantic-acceptance durable codec case with
paired candidate-preservation and durable-rejection cases for every field,
including empty and reversed reference ranges. Add an assembled lane case
showing permissive validator overrides still cannot publish schema-invalid
enemy events; run the codec, enemy-event, pipeline, and CLI suites.
- **Grouping:** Coordinate with DND-REG-001; that finding owns the common
forward-range gap, while this finding owns enemy-event schema enforcement.
<!--
Finding template for later audit stages:
@@ -1249,16 +1336,16 @@ family-owned, uses media type `application/json`, embeds its own v1 durable
schema, publishes count metadata, and has a registered direct-source-reference
evidence projector.
| Family | Durable kind / Go type | Modules and execution class | Default validator chains (E / N) | Reference dependencies (E / N) | Codec, prompt, and schema ownership | Documented exception and later confirmation |
| Family | Durable kind / Go type | Modules and execution class | Default validator chains (E / N) | Reference dependencies (E / N) | Codec, prompt, and schema ownership | Documented exception and review result |
| --- | --- | --- | --- | --- | --- | --- |
| Spells | `dnd/spell-list` / `dnd.SpellList` | `dnd/spells` (LLM) → typed `appendorder` (deterministic) → `dnd/spells` (deterministic) | `B + catalog` / `B + catalog` | `C` plus optional `spell_catalog` and `npc_registry` / optional `spell_catalog` | `codec/spells`; extractor owns its prompt and private response schema; normalizer has no prompt | Confirmed: catalog and NPC grounding remain source-free recognition context; canonicalization, retry, and checkpoint identities are deterministic. DND-REG-001, DND-REG-002, DND-SCENE-001, and DND-SCENE-002 record codec, chunk-evidence, alias-projection, and warning gaps. |
| NPC registry | `dnd/npc-registry` / `dnd.NPCRegistry` | `dnd/npc-registry` (LLM) → typed `appendorder` (deterministic) → `dnd/npc-registry` (LLM) | `B` / `B + identity` | `C` / none | `codec/npcregistry`; extractor and normalizer own prompts; extractor owns its response schema, while normalize uses the shared private entity-reconciliation schema | Confirmed: normalized comparison-name identity, deterministic exact duplicate consolidation, proposal-only semantic groups, collision-safe application, retry/fallback, and immutable name/identity projections; DND-REG-001 and DND-REG-002 record evidence-boundary gaps. |
| Combat turns | `dnd/combat-turn-list` / `dnd.CombatTurnList` | `dnd/combat-turns` (LLM) → typed `appendorder` (deterministic) → `dnd/combat-turns` (deterministic) | `B` / `B + invariants` | `C`, optional `npc_registry`, required `scene_descriptions` / optional `npc_registry` | `codec/combatturns`; extractor owns its prompt and private response schema; normalizer has no prompt | Scene descriptions gate LLM execution and NPC grounding is not evidence; confirm gate and empty-result semantics in the combat/enemy review. |
| Combat turns | `dnd/combat-turn-list` / `dnd.CombatTurnList` | `dnd/combat-turns` (LLM) → typed `appendorder` (deterministic) → `dnd/combat-turns` (deterministic) | `B` / `B + invariants` | `C`, optional `npc_registry`, required `scene_descriptions` / optional `npc_registry` | `codec/combatturns`; extractor owns its prompt and private response schema; normalizer has no prompt | Confirmed: exact combat classification alone enables prompting; exact non-combat and unavailable classifications produce accepted empty lists, with one warning only for unavailable classification. NPC names remain optional source-free grounding. DND-REG-001, DND-REG-002, and DND-SCENE-002 record codec, chunk-evidence, and warning gaps. |
| Item occurrences | `dnd/item-occurrence-list` / `dnd.ItemOccurrenceList` | `dnd/item-occurrences` (LLM) → typed `appendorder` (deterministic) → `dnd/item-occurrences` (deterministic) | `B + registry` / `B + registry + invariants` | `C` plus required `item_registry` / required `item_registry` | `codec/itemoccurrences`; extractor owns its prompt and private response schema; normalizer has no prompt | Confirmed: exact names-only registry resolution is all-or-nothing, registry provenance never becomes evidence, and quantity/holder rules survive canonical ordering and duplicate collapse. DND-REG-001, DND-OCC-001, and DND-OCC-003 record bounded codec, prompt/schema, and repeated-work gaps. |
| Item registry | `dnd/item-registry` / `dnd.ItemRegistry` | `dnd/item-registry` (LLM) → typed `appendorder` (deterministic) → `dnd/item-registry` (LLM) | `B` / `B + identity` | `C` / none | `codec/itemregistry`; extractor and normalizer own prompts; extractor owns its response schema, while normalize uses the shared private entity-reconciliation schema | Confirmed: name identity, exact duplicate evidence union, proposal-only aliases, collision safety, and denomination/type-preserving currency gate; DND-REG-001 and DND-REG-003 record boundary/grouping gaps. |
| NPC occurrences | `dnd/npc-occurrence-list` / `dnd.NPCOccurrenceList` | `dnd/npc-occurrences` (LLM) → typed `appendorder` (deterministic) → `dnd/npc-occurrences` (deterministic) | `B + registry` / `B + registry + invariants` | `C` plus required `npc_registry` / `C` plus required `npc_registry` | `codec/npcoccurrences`; extractor owns its prompt and private response schema; normalizer has no prompt | Confirmed: names-only selection resolves to exact registry pairs, registry provenance cannot become occurrence evidence, `mentioned` remains factual, and current-source evidence is canonicalized before exact duplicate collapse. DND-REG-001 and DND-OCC-002 record the codec and unused-normalizer-reference gaps. |
| Scene descriptions | `dnd/scene-description-list` / `dnd.SceneDescriptionList` | `dnd/scene-descriptions` (LLM) → typed `appendorder` (deterministic) → `dnd/scene-descriptions` (deterministic) | `B` / `B + invariants` | optional `glossary`, `party`, and `players` / none | `codec/scenedescriptions`; extractor owns its prompt and private response schema; normalizer has no prompt | Confirmed: one model classification is mapped onto the current chunk's local ID and exact range, while an immutable source-free ID/range/kind projection alone controls later eligibility. DND-REG-001 and DND-SCENE-002 record codec and warning gaps. |
| Enemy events | `dnd/enemy-event-list` / `dnd.EnemyEventList` | `dnd/enemy-events` (LLM) → typed `appendorder` (deterministic) → `dnd/enemy-events` (deterministic) | `B + engagements` / `B + invariants` | `C` plus required `npc_registry`, `scene_descriptions`, `combat_turns`, and `npc_occurrences` / required `npc_registry` | `codec/enemyevents`; extractor owns its prompt and private response schema; normalizer has no prompt | Four generated artifacts ground extraction without becoming event evidence; durable decode separately proves required JSON-field presence. Confirm combat gating, engagement uniqueness, and observation ordering in the combat/enemy review. |
| Enemy events | `dnd/enemy-event-list` / `dnd.EnemyEventList` | `dnd/enemy-events` (LLM) → typed `appendorder` (deterministic) → `dnd/enemy-events` (deterministic) | `B + engagements` / `B + invariants` | `C` plus required `npc_registry`, `scene_descriptions`, `combat_turns`, and `npc_occurrences` / required `npc_registry` | `codec/enemyevents`; extractor owns its prompt and private response schema; normalizer has no prompt | Confirmed: exact combat gating precedes prompt grounding; compact NPC, combat-turn, and opponent-occurrence projections contain no evidence or opaque IDs; extraction admits one engagement per comparison identity, while normalization preserves later observations and orders them by chronology, subject, kind, and evidence. DND-REG-001, DND-REG-003, and DND-COMBAT-001 record codec and duplicate-work gaps. |
| Location registry | `dnd/location-registry` / `dnd.LocationRegistry` | `dnd/location-registry` (LLM) → typed `appendorder` (deterministic) → `dnd/location-registry` (LLM) | `B` / `B + identity` | `C` / none | `codec/locationregistry`; extractor and normalizer own prompts; extractor owns its response schema, while normalize uses the shared private entity-reconciliation schema | Confirmed: comparison name plus earliest canonical evidence identity, same-name/different-anchor preservation, proposal-only aliases, and immutable context-qualified selectors without durable IDs; DND-REG-001, DND-REG-003, and DND-REG-004 record bounded gaps. |
| Location occurrences | `dnd/location-occurrence-list` / `dnd.LocationOccurrenceList` | `dnd/location-occurrences` (LLM) → typed `appendorder` (deterministic) → `dnd/location-occurrences` (deterministic) | `B + registry` / `B + registry + invariants` | `C` plus required `location_registry` / required `location_registry` | `codec/locationoccurrences`; extractor owns its prompt and private response schema; normalizer has no prompt | Confirmed: source-free contextual selectors disambiguate same-name locations without exposing durable IDs, unresolved selections reject the whole response, registry evidence remains separate, and explicit kind precedence preserves speculation/mention distinctions. DND-REG-001 records the codec gap. |
@@ -1344,6 +1431,17 @@ mechanics that recur without erasing those distinctions.
production policy. Later D&D stages may evaluate individual shared
mechanics, but should not replace these lists with a dynamically typed
registration engine.
- Combat-turn and enemy-event extractors deliberately own separate explicit
scene gates. Both consult the same immutable eligibility registry before any
LLM call, but the enemy lane must then resolve three required source-free
grounding projections while combat turns have only optional NPC grounding.
A callback-driven shared extractor would obscure required-reference and
empty-result ownership without removing meaningful policy duplication.
- Enemy engagement uniqueness deliberately belongs only to extraction. One
chunk represents one classified combat scene, so a comparison-key map can
reject repeated `engaged` observations there; the merged/normalized artifact
may contain later engagements for the same subject in separate scenes and
must preserve them rather than apply a terminal-state model.
- `internal/framework/pipeline.RegisterArtifactCodec` and
`exactTypedValue` perform apparently repetitive exact-type checks around
private erasure. The checks deliberately turn incompatible values into
@@ -2015,14 +2113,14 @@ mechanics that recur without erasing those distinctions.
helpers already consolidate prompt assets, candidate JSON, reference slots,
comparison, diagnostics, resolution, and reconciliation. No additional
callback- or reflection-driven helper reduced demonstrated drift.
- **Deferred lane questions:** Registry identity, reconciliation, immutable
- **Completed lane questions:** Registry identity, reconciliation, immutable
projections, occurrence-category/grounding policy, spell catalogs, scene
chunking, scene identity, and scene classification are now confirmed,
with DND-REG-001 through DND-REG-004 and DND-OCC-001 through DND-OCC-003
plus DND-SCENE-001 and DND-SCENE-002 recording the bounded gaps. Combat gates,
engagement uniqueness, collective labels, and enemy observation ordering
remain assigned to the combat/enemy review. This area therefore remains
`Revisit` until that review confirms the remaining matrix exceptions.
chunking, scene identity/classification, combat gates, engagement uniqueness,
collective labels, and enemy observation ordering are now confirmed. The
convention matrix records every family exception, with DND-CORE-001,
DND-REG-001 through DND-REG-004, DND-OCC-001 through DND-OCC-003,
DND-SCENE-001, DND-SCENE-002, and DND-COMBAT-001 recording the bounded gaps.
No shared D&D question remains deferred to the final synthesis.
### NPC, Item, And Location Registries
@@ -2185,6 +2283,51 @@ mechanics that recur without erasing those distinctions.
checkpoint/retry, and production chunk-map tests cover the reviewed contracts,
and the prescribed package suite passes.
### Combat Turns And Enemy Events
- **Eligibility and extraction:** Both extractors prepare the current chunk and
consult the immutable scene-description registry before prompt construction.
Only an exact `combat` match reaches the model; an exact non-combat match
returns an accepted present-empty list, while a missing/mismatched match adds
exactly one bounded `scene_classification_unavailable` warning. Scene title,
summary, evidence, and provenance never enter either model input or output
evidence.
- **Grounding and identity:** Combat turns optionally project canonical NPC
names without copying registry references. Enemy events require normalized
NPCs, scene eligibility, combat turns, and NPC occurrences, but project only
NPC names, combat actor/kind pairs, and named `combat_opponent` occurrence
pairs. The prompt and maintained CLI test exclude source ranges and opaque
IDs from these projections; unmatched transcript-grounded actors and narrow
collective enemy labels remain valid durable display subjects.
- **Canonicalization and validation:** Extractors inject the current source ID,
canonicalize exact reference order/deduplication, and order candidates by
valid document chronology while preserving malformed candidates for their
validators. Combat normalization uses a collision-safe complete duplicate
key; enemy normalization applies explicit chronology, subject identity,
display, kind, and evidence ordering and collapses only exact observations.
Shape, source, relatedness, normalized-invariant, and extract-only engagement
validators retain their documented ownership. DND-REG-002 records combat's
missing extraction-chunk check; DND-REG-003 records enemy's pairwise exact-
duplicate work; DND-SCENE-002 records combat warning bounds.
- **Handoffs, retries, and publication:** The maintained three-step example
produces NPC and scene artifacts before combat/NPC occurrences, then binds all
four approved generated artifacts into enemy extraction and the NPC registry
into normalization. Pipeline reference identities, module prompt/schema/
policy fingerprints, bounded extraction retries, rejection suppression, and
accepted checkpoint hydration apply unchanged. Focused CLI execution proves
only the classified combat chunk prompts for enemy events and publishes typed
combat/enemy JSON plus direct evidence context. DND-REG-001 and
DND-COMBAT-001 record the remaining durable codec gaps.
- **Tests and complexity:** Extractor fixtures cover exact/non-combat/missing/
mismatched gates, source-free grounding, generated references, chronology,
malformed candidates, and metadata; normalizer/validator fixtures cover
canonical names, reference and event order, exact duplicate identity,
engagement uniqueness, collective subjects, warning bounds where implemented,
and idempotence. Graph traces and complexity inspection found no unbounded
family loop; the intentional generated-reference sequencing is linear, while
the pairwise enemy duplicate paths are isolated in DND-REG-003. All prescribed
family and CLI tests pass.
## Validation Record
| Date | Scope | Command or check | Result |
@@ -2241,6 +2384,12 @@ mechanics that recur without erasing those distinctions.
| 2026-08-08 | Audit target integrity before spell/scene-family review | `git diff --quiet 92e89076a268089e703978fb9d7176200e93344c..HEAD -- . ':(exclude)docs/roadmap/**'` | Pass; production target unchanged |
| 2026-08-08 | Spell and scene graph/code review | Scoped architecture, exact symbol reads, complexity inspection, and call traces across whole-source scene planning, framework plan canonicalization/materialization, chunk-map serialization/publication, per-chunk scene extraction, normalization, validation and eligibility projection, effective spell catalog composition, NPC grounding, response canonicalization, normalization, validation, checkpoint identity, retry, codecs, prompt assets, schemas, and focused tests | DND-SCENE-001 and DND-SCENE-002 recorded; DND-REG-001, DND-REG-002, and PIPE-002 broadened; structural/evidence separation, exact scene eligibility, and catalog/checkpoint behavior otherwise confirmed |
| 2026-08-08 | Required spell, scene chunking, and scene-description tests | `go test ./internal/modules/dnd/chunk/scenes ./internal/modules/dnd/extract/scenedescriptions ./internal/modules/dnd/normalize/scenedescriptions ./internal/modules/dnd/validate/scenedescriptions/... ./internal/modules/dnd/scenedescriptions/... ./internal/modules/dnd/extract/spells ./internal/modules/dnd/normalize/spells ./internal/modules/dnd/validate/spells/... ./internal/modules/dnd/spells/...` | Pass |
| 2026-08-08 | Audit target integrity before combat/enemy review | `git diff --quiet 92e89076a268089e703978fb9d7176200e93344c..HEAD -- . ':(exclude)docs/roadmap/**'` | Pass; production target unchanged |
| 2026-08-08 | Combat and enemy graph/code review | Scoped architecture, exact symbol reads, complexity inspection, and call traces across scene gates, optional NPC grounding, required enemy projections, response mapping, chronology, normalization/deduplication, extract/normalize validator chains, engagement identity, codecs, prompts, private schemas, generated references, retry/checkpoint identity, maintained CLI example, and focused tests | DND-COMBAT-001 recorded; DND-REG-001 through DND-REG-003 and DND-SCENE-002 broadened; exact eligibility, source-free grounding, collective labels, engagement uniqueness, observation preservation/order, and generated handoffs otherwise confirmed |
| 2026-08-08 | Required combat-turn and enemy-event tests | `go test ./internal/modules/dnd/extract/combatturns ./internal/modules/dnd/normalize/combatturns ./internal/modules/dnd/validate/combatturns/... ./internal/modules/dnd/extract/enemyevents ./internal/modules/dnd/normalize/enemyevents ./internal/modules/dnd/validate/enemyevents/... ./internal/modules/dnd/enemyevents` | Pass |
| 2026-08-08 | Combat and enemy durable codec tests | `go test ./internal/modules/dnd/codec/combatturns ./internal/modules/dnd/codec/enemyevents` | Pass |
| 2026-08-08 | Assembled combat and generated-reference integration tests | `go test ./internal/modules/integration/...` | Pass |
| 2026-08-08 | Generated combat/enemy handoff and publication tests | `go test ./internal/cli` | Pass |
## Coverage Matrix
@@ -2254,9 +2403,9 @@ mechanics that recur without erasing those distinctions.
| State, checkpoints, debugging, and file safety | Reviewed | State and operations docs plus architecture state/security policy; CLI output, cache-root, checkpoint identity, recomputation, debug allocation, and terminal owners; core file I/O, debug bundle, and source digest/clone helpers; framework checkpoint, chunk-plan, chunk-map, debug, evidence-context implementations and focused tests | Target-integrity check, graph architecture/complexity/call traces, state collaborator race tests, CLI tests | STATE-001, STATE-002, STATE-003 |
| LLM runtime, prompt filesystems, and assets | Reviewed | LLM internal/integration/configuration/operations docs and related ADRs; scheduled client, scheduler, PromptKit adapter/profile inspector, profile/source fingerprints, redaction, debug, asset registry, schema loader, promptfs implementations and focused tests; root assets, fallback profile, all fourteen module manifests and prompt YAML files, shared/model-visible fragments, private response schemas, and representative composed loaders | Target-integrity check, graph architecture/symbol/call review, content scan and exact prompt-order comparison, focused race tests, composed CLI and D&D prompt-cache tests | LLM-001, LLM-002, LLM-003, LLM-004 |
| Generic and Seriatim modules | Reviewed | Internal module guide; Seriatim, JSON output, chunk-map, and evidence-context integration contracts; all implementation/tests under `internal/modules/generic/` and `internal/modules/seriatim/`; framework evidence preparation/output paths and focused tests; maintained CLI example and production output contracts | Target-integrity check, graph architecture/symbol/call/caller review, direct import map, required module and codec tests, focused composed evidence/output tests | MOD-001, MOD-002, MOD-003 |
| Shared D&D types, codecs, and family mechanics | Revisit | D&D internal/module docs and all D&D integration contracts; root durable types; all ten codec packages and candidate JSON; shared references, ordering, citations, inputs, comparison, diagnostics, registry resolver, entity reconciliation, and assets; typed merger/evidence/default-chain/fallback/family registration; representative module asset declarations and focused tests | Target-integrity check, scoped graph architecture/search/traces, ten-family convention matrix, required codec/shared/register tests | DND-CORE-001 |
| Shared D&D types, codecs, and family mechanics | Reviewed | D&D internal/module docs and all D&D integration contracts; root durable types; all ten codec packages and candidate JSON; shared references, ordering, citations, inputs, comparison, diagnostics, registry resolver, entity reconciliation, and assets; typed merger/evidence/default-chain/fallback/family registration; representative module asset declarations and focused tests; all lane-specific identity, grounding, order, and eligibility exceptions | Target-integrity checks, scoped graph architecture/search/traces, completed ten-family convention matrix, required codec/shared/register and lane-family tests | DND-CORE-001, DND-REG-001, DND-COMBAT-001 |
| NPC, item, and location registries | Reviewed | NPC/item/location registry integration contracts and relevant identity/evidence ADRs; extractors, candidate models and response schemas; identity, immutable registry, prompt/identity projection, location grounding, reconciliation, normalizer, validators, codecs, prompt assets, and focused tests for all three families | Target-integrity check, scoped graph architecture/complexity/search/traces, full family comparison, required extractor/identity/registry/normalizer/validator tests | DND-REG-001, DND-REG-002, DND-REG-003, DND-REG-004 |
| NPC, item, and location occurrences | Reviewed | NPC/item/location occurrence integration contracts and deterministic opaque-ID ADR; extractors, private response models/schemas, semantic registry projections and resolvers, canonicalizers, normalizers, validator chains, codecs, prompt assets, and generated/external registry handoff tests for all three families | Target-integrity check, scoped graph architecture/complexity/search/traces, full family comparison, required extractor/normalizer/validator tests, generated CLI handoff tests | DND-REG-001, DND-OCC-001, DND-OCC-002, DND-OCC-003 |
| Spells, scene chunking, and scene descriptions | Reviewed | Spell, overlay, scene-description, and accepted chunk-map integration contracts; D&D scene chunker and prompt/schema assets; framework plan canonicalization, validation, materialization, accepted chunk-map serialization/publication and production tests; scene-description extractor, normalizer, validators, immutable eligibility registry, codec, prompts, schemas, and tests; spell extractor, effective/base/overlay catalogs, NPC grounding, canonicalizer, normalizer, validators, codec, prompts, schemas, checkpoint/retry/CLI tests | Target-integrity check, scoped graph architecture/complexity/symbol/call review, full family comparison, required chunker/extractor/normalizer/validator/registry/catalog tests | PIPE-002, DND-REG-001, DND-REG-002, DND-SCENE-001, DND-SCENE-002 |
| Combat turns and enemy events | Pending | — | — | — |
| Combat turns and enemy events | Reviewed | Combat/enemy integration contracts and D&D internals; extractors, scene/NPC resolvers, compact combat/opponent projections, canonicalizers, normalizers, shared enemy ordering/identity helpers, shape/source/relatedness/engagement/invariant validators, codecs, prompt assets, private schemas, focused and assembled integration tests, generated-reference CLI contracts, and maintained complete example | Target-integrity check, scoped graph architecture/complexity/symbol/call review, full family comparison, required extractor/normalizer/validator/helper tests, codec tests, assembled integration tests, generated CLI handoff/publication tests | DND-REG-001, DND-REG-002, DND-REG-003, DND-SCENE-002, DND-COMBAT-001 |
| Test ownership, comments, and final synthesis | Pending | — | — | — |