diff --git a/README.md b/README.md index d139570..ce75c18 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ Notarius is a Go CLI for turning source material into structured artifacts with configured extraction pipelines. The implemented D&D workflow reads Seriatim transcript JSON and can produce scene descriptions, item and currency events, -NPC identities, combat turns, NPC interactions, and spell casts. +NPC identities, combat turns, NPC interactions, enemy events, and spell casts. ## Quickstart diff --git a/docs/config.md b/docs/config.md index f1ead4f..c457b65 100644 --- a/docs/config.md +++ b/docs/config.md @@ -370,14 +370,17 @@ selected target declares them: | **players** | Optional text player context. | | **glossary** | Optional text campaign glossary. | | **spell_catalog** | Optional JSON spell-catalog overlay for spell extraction and normalization. See [spell-catalog overlays](integrations/dnd-spell-catalog-overlays.md). | -| **npcs** | Normalized NPC registry. Optional for spells and combat turns; required for NPC interactions. | -| **scene_descriptions** | Required normalized scene-description artifact for combat-turn extraction. | +| **npcs** | Normalized NPC registry. Optional for spells and combat turns; required for NPC interactions and enemy-event extraction and normalization. | +| **scene_descriptions** | Required normalized scene-description artifact for combat-turn and enemy-event extraction. | +| **combat_turns** | Required normalized combat-turn artifact for enemy-event extraction. | +| **npc_interactions** | Required normalized NPC-interaction artifact for enemy-event extraction. | Scene descriptions accept **party**, **players**, and **glossary**, but not **roster**. NPC interactions require **npcs** for both extraction and normalization. Combat turns require **scene_descriptions** for extraction; the -normalized combat-turn module may use optional **npcs**. The complete example -shows generated **npcs** and **scene_descriptions** bindings. +normalized combat-turn module may use optional **npcs**. Enemy-event extraction +requires all four JSON artifact slots; its normalizer requires **npcs**. The +complete example shows the ordered generated bindings. ## Production Module Keys @@ -385,9 +388,9 @@ shows generated **npcs** and **scene_descriptions** bindings. | --- | --- | | Input | **seriatim** | | Chunk | **generic**, **dnd/scenes** | -| Extract | **dnd/spells**, **dnd/npcs**, **dnd/combat-turns**, **dnd/item-events**, **dnd/npc-interactions**, **dnd/scene-descriptions** | +| Extract | **dnd/spells**, **dnd/npcs**, **dnd/combat-turns**, **dnd/item-events**, **dnd/npc-interactions**, **dnd/scene-descriptions**, **dnd/enemy-events** | | Merge | **appendorder** | -| Normalize | **noop**, **dnd/spells**, **dnd/npcs**, **dnd/combat-turns**, **dnd/item-events**, **dnd/npc-interactions**, **dnd/scene-descriptions** | +| Normalize | **noop**, **dnd/spells**, **dnd/npcs**, **dnd/combat-turns**, **dnd/item-events**, **dnd/npc-interactions**, **dnd/scene-descriptions**, **dnd/enemy-events** | | Output | **json** | The D&D artifact contracts define each emitted schema: @@ -396,7 +399,8 @@ The D&D artifact contracts define each emitted schema: [NPC interactions](integrations/dnd-npc-interaction-artifacts.md), [combat turns](integrations/dnd-combat-turn-artifacts.md), [item events](integrations/dnd-item-event-artifacts.md), and -[scene descriptions](integrations/dnd-scene-description-artifacts.md). +[scene descriptions](integrations/dnd-scene-description-artifacts.md), and +[enemy events](integrations/dnd-enemy-event-artifacts.md). ## Production Validator Keys And Default Chains @@ -411,6 +415,7 @@ Available validator keys are: | Item events | **extract/dnd/item-events/shape**, **extract/dnd/item-events/source_refs**, **extract/dnd/item-events/source_relatedness**, **normalize/dnd/item-events/invariants** | | NPC interactions | **extract/dnd/npc-interactions/shape**, **extract/dnd/npc-interactions/registry**, **extract/dnd/npc-interactions/source_refs**, **extract/dnd/npc-interactions/source_relatedness**, **normalize/dnd/npc-interactions/invariants** | | Scene descriptions | **extract/dnd/scene-descriptions/shape**, **extract/dnd/scene-descriptions/source_refs**, **extract/dnd/scene-descriptions/source_relatedness**, **normalize/dnd/scene-descriptions/invariants** | +| Enemy events | **extract/dnd/enemy-events/shape**, **extract/dnd/enemy-events/source_refs**, **extract/dnd/enemy-events/source_relatedness**, **normalize/dnd/enemy-events/invariants** | When no override is configured, production D&D bindings use the following ordered chains. Each row lists extract then normalize; spell chains are the @@ -424,6 +429,7 @@ same at both stages. | Item events | generic/valid_json, extract/dnd/item-events/shape, extract/dnd/item-events/source_refs, generic/valid_json_schema, extract/dnd/item-events/source_relatedness | generic/valid_json, extract/dnd/item-events/shape, normalize/dnd/item-events/invariants, extract/dnd/item-events/source_refs, generic/valid_json_schema, extract/dnd/item-events/source_relatedness | | NPC interactions | generic/valid_json, extract/dnd/npc-interactions/shape, extract/dnd/npc-interactions/registry, extract/dnd/npc-interactions/source_refs, generic/valid_json_schema, extract/dnd/npc-interactions/source_relatedness | generic/valid_json, extract/dnd/npc-interactions/shape, extract/dnd/npc-interactions/registry, normalize/dnd/npc-interactions/invariants, extract/dnd/npc-interactions/source_refs, generic/valid_json_schema, extract/dnd/npc-interactions/source_relatedness | | Scene descriptions | generic/valid_json, extract/dnd/scene-descriptions/shape, extract/dnd/scene-descriptions/source_refs, generic/valid_json_schema, extract/dnd/scene-descriptions/source_relatedness | generic/valid_json, extract/dnd/scene-descriptions/shape, normalize/dnd/scene-descriptions/invariants, extract/dnd/scene-descriptions/source_refs, generic/valid_json_schema, extract/dnd/scene-descriptions/source_relatedness | +| Enemy events | generic/valid_json, extract/dnd/enemy-events/shape, extract/dnd/enemy-events/source_refs, generic/valid_json_schema, extract/dnd/enemy-events/source_relatedness | generic/valid_json, extract/dnd/enemy-events/shape, normalize/dnd/enemy-events/invariants, extract/dnd/enemy-events/source_refs, generic/valid_json_schema, extract/dnd/enemy-events/source_relatedness | Chains are only registered for the D&D extract and normalize modules shown above; select an explicit override when a different compatible chain is diff --git a/docs/integrations/dnd-combat-turn-artifacts.md b/docs/integrations/dnd-combat-turn-artifacts.md index 5beeee0..23019d7 100644 --- a/docs/integrations/dnd-combat-turn-artifacts.md +++ b/docs/integrations/dnd-combat-turn-artifacts.md @@ -64,6 +64,8 @@ kind, and complete valid evidence. It does not infer turns, initiative, or actions from registry or scene data. 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. +broader NPC occurrences. The [enemy-event artifact](dnd-enemy-event-artifacts.md) +uses combat turns as grounding only; turns do not establish an enemy event or +its outcome. The [JSON output contract](json-output.md) defines publication, +and [D&D module internals](../internal/dnd.md) describes routing and validation +mechanics. diff --git a/docs/integrations/dnd-enemy-event-artifacts.md b/docs/integrations/dnd-enemy-event-artifacts.md new file mode 100644 index 0000000..444751f --- /dev/null +++ b/docs/integrations/dnd-enemy-event-artifacts.md @@ -0,0 +1,113 @@ +# D&D Enemy-Event Artifact + +This contract defines the durable, source-grounded enemy-event occurrence list. +It records enemies directly established as opposing the party and explicitly +observed combat outcomes. It is an ordered observation artifact from which a +consumer may derive a ledger; it is not a ledger, encounter roster, or terminal +state model. + +## Identity and compatibility + +| Property | Value | +| --- | --- | +| Artifact kind | `dnd/enemy-event-list` | +| Schema ID | `notarius.dnd.enemy_events` | +| Schema name | `notarius_dnd_enemy_events_v1` | +| Schema version | `v1` | +| Media type | `application/json` | + +`v1` is a strict JSON object with required `events`; the array may be empty. +Event and source-reference objects reject unknown fields. An incompatible shape +change requires a new schema version. + +## Wire shape + +Every event has these required fields: + +| Field | Contract | +| --- | --- | +| `name` | Non-empty display name or directly grounded collective subject label. | +| `kind` | `engaged`, `killed`, `fled`, `captured`, or `incapacitated`. | +| `source_refs` | One or more current-transcript evidence ranges. | + +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 +{ + "events": [ + { + "name": "Ashfang", + "kind": "engaged", + "source_refs": [ + {"source_id": "session-7", "start_unit_id": 41, "end_unit_id": 42} + ] + }, + { + "name": "Ashfang", + "kind": "fled", + "source_refs": [ + {"source_id": "session-7", "start_unit_id": 57, "end_unit_id": 58} + ] + } + ] +} +``` + +## Event semantics and evidence + +| Kind | Required evidence | +| --- | --- | +| `engaged` | The subject is directly established as actively opposing the party in combat. At most one engagement is emitted for one subject in one combat scene. | +| `killed` | The transcript explicitly establishes that the subject died or was killed. Damage, defeat, disappearance, or combat ending is insufficient. | +| `fled` | The subject explicitly escapes, retreats, or otherwise leaves combat to avoid continued engagement. Movement or absence from later turns is insufficient. | +| `captured` | The subject is explicitly taken prisoner or secured under the party's control. A grapple or temporary restraint alone is insufficient. | +| `incapacitated` | The subject is explicitly rendered unable to continue acting without being established as killed or captured. A missed turn is insufficient. | + +The current transcript is the only event evidence. Campaign context and +normalized NPC, scene-description, combat-turn, and NPC-interaction artifacts +can ground names or control combat eligibility, but none may supply event +evidence. An outcome may share evidence with an engagement, in which case both +events are retained. + +Extraction is limited to chunks with an exact combat-scene classification. An +exact non-combat classification produces an accepted empty list. Missing or +mismatched classification also produces an accepted empty list and a +`scene_classification_unavailable` warning. + +## Subjects, normalization, and order + +A subject matching the normalized NPC registry uses that registry's canonical +display name. Unmatched hostile creatures, summoned entities, and directly +grounded groups remain valid subjects. An unnamed homogeneous group uses the +narrowest transcript-grounded label, such as `Orcs`, `One orc`, or `Remaining +orcs`; the artifact never invents synthetic member identities or quantities. +Party members, allies, neutral observers, mentioned-but-absent enemies, hazards, +traps, and environmental effects are excluded. + +Normalization trims subject whitespace, canonicalizes recognized registry +names, canonicalizes and deduplicates exact source ranges, then orders events +by valid evidence chronology, normalized subject identity, display name, kind, +and reference sequence. The deterministic kind tie order is `engaged`, +`incapacitated`, `captured`, `fled`, then `killed`. Only entries with the same +normalized name, kind, and complete canonical evidence sequence are collapsed. +Different kinds, evidence, repeated engagement in separate scenes, and later +outcomes remain separate. A later engagement for the same named subject is +preserved after an earlier outcome because the artifact does not assert an +irreversible state transition. + +## Non-goals + +The artifact has no NPC or scene ID, quantity, confidence, description, +rationale, summary, current state, or inferred terminal outcome. It does not +emit `active` or `unresolved`; consumers may derive an unresolved ledger view +only when an engagement has no later explicit outcome. It never infers an +outcome from turn absence, scene termination, initiative order, hit-point +guesses, or other artifacts. + +The [JSON output contract](json-output.md) defines publication. Configuration +keys, required generated-reference slots, and validator-chain selection are +defined in the [configuration reference](../config.md). Implementation and +prompt-grounding mechanics are described in the +[D&D module internals](../internal/dnd.md). diff --git a/docs/integrations/dnd-npc-artifacts.md b/docs/integrations/dnd-npc-artifacts.md index 530e7a7..221ce2b 100644 --- a/docs/integrations/dnd-npc-artifacts.md +++ b/docs/integrations/dnd-npc-artifacts.md @@ -60,10 +60,13 @@ relationship fields. Only individually identifiable NPC names with transcript evidence belong in this artifact. Groups, generic roles, invented labels, and descriptive enrichment are excluded. Its source references prove registry provenance; they -do not become evidence for a spell, interaction, or combat occurrence. +do not become evidence for a spell, interaction, combat, or enemy-event +occurrence. This registry can ground actor or caster names in the [spell](dnd-spell-artifacts.md) and [combat-turn](dnd-combat-turn-artifacts.md) artifacts. It is required to resolve the canonical `name` in an [NPC interaction](dnd-npc-interaction-artifacts.md). +The [enemy-event artifact](dnd-enemy-event-artifacts.md) also uses it only for +subject grounding and canonical display names. The [JSON output contract](json-output.md) defines publication, and [D&D module internals](../internal/dnd.md) owns pipeline mechanics. diff --git a/docs/integrations/dnd-npc-interaction-artifacts.md b/docs/integrations/dnd-npc-interaction-artifacts.md index 3944926..2e8d512 100644 --- a/docs/integrations/dnd-npc-interaction-artifacts.md +++ b/docs/integrations/dnd-npc-interaction-artifacts.md @@ -74,5 +74,8 @@ Only entries with the same canonical name, kind, and complete valid evidence sequence are collapsed; distinct categories or evidence remain separate. See the [combat-turn artifact](dnd-combat-turn-artifacts.md) for combat-action -occurrences and the [JSON output contract](json-output.md) for publication. -Pipeline mechanics are described in [D&D module internals](../internal/dnd.md). +occurrences. The [enemy-event artifact](dnd-enemy-event-artifacts.md) consumes +only `combat_opponent` interactions as grounding; they never establish an enemy +event or outcome. The [JSON output contract](json-output.md) defines +publication. Pipeline mechanics are described in +[D&D module internals](../internal/dnd.md). diff --git a/docs/integrations/dnd-scene-description-artifacts.md b/docs/integrations/dnd-scene-description-artifacts.md index fefa756..5d3f313 100644 --- a/docs/integrations/dnd-scene-description-artifacts.md +++ b/docs/integrations/dnd-scene-description-artifacts.md @@ -62,8 +62,9 @@ durable fields, or the same source range with different kind, title, or summary, is invalid. It does not merge adjacent ranges, alter prose, or infer missing scenes. -The [combat-turn artifact](dnd-combat-turn-artifacts.md) uses an exact matching +The [combat-turn artifact](dnd-combat-turn-artifacts.md) and +[enemy-event artifact](dnd-enemy-event-artifacts.md) use an exact matching `combat` scene only as eligibility control; scene title, summary, and source -reference never become combat evidence. Publication is defined by the +reference never become their evidence. Publication is defined by the [JSON output contract](json-output.md); implementation details live in [D&D module internals](../internal/dnd.md). diff --git a/docs/integrations/json-output.md b/docs/integrations/json-output.md index 70ddd48..47d3db8 100644 --- a/docs/integrations/json-output.md +++ b/docs/integrations/json-output.md @@ -75,7 +75,8 @@ than infer a lane schema from its name. The current D&D payload contracts are [NPC interactions](dnd-npc-interaction-artifacts.md), [combat turns](dnd-combat-turn-artifacts.md), [item events](dnd-item-event-artifacts.md), and -[scene descriptions](dnd-scene-description-artifacts.md). +[scene descriptions](dnd-scene-description-artifacts.md), and +[enemy events](dnd-enemy-event-artifacts.md). ## `manifest.json` diff --git a/docs/internal/dnd.md b/docs/internal/dnd.md index 2d19d1d..e286f94 100644 --- a/docs/internal/dnd.md +++ b/docs/internal/dnd.md @@ -7,7 +7,7 @@ selectable keys, bindings, reference syntax, and default validator chains. ## Durable Artifact Contracts -The six lanes have separate durable wire contracts. This guide deliberately +The seven lanes have separate durable wire contracts. This guide deliberately does not repeat their JSON shapes or schemas. | Lane | Durable contract | @@ -18,6 +18,7 @@ does not repeat their JSON shapes or schemas. | Item events | [item-event artifacts](../integrations/dnd-item-event-artifacts.md) | | NPC interactions | [NPC-interaction artifacts](../integrations/dnd-npc-interaction-artifacts.md) | | Scene descriptions | [scene-description artifacts](../integrations/dnd-scene-description-artifacts.md) | +| Enemy events | [enemy-event artifacts](../integrations/dnd-enemy-event-artifacts.md) | ## Family Composition @@ -102,13 +103,13 @@ is documented in [Configuration](../config.md#production-validator-keys-and-default-chains). Normalizers are deterministic for spells, combat turns, item events, NPC -interactions, and scene descriptions. They canonicalize display values and -evidence, use source-document order for stable output, and issue bounded -warnings for changes or collapsed duplicates. The NPC normalizer is the -intentional exception: it first produces a deterministic candidate set, then -uses a bounded structured-LLM proposal to reconcile identity groups. Invalid -or unusable proposals retain the deterministic result and surface retry or -fallback diagnostics; the model does not directly replace durable records. +interactions, scene descriptions, and enemy events. They canonicalize display +values and evidence, use source-document order for stable output, and issue +bounded warnings for changes or collapsed duplicates. The NPC normalizer is +the intentional exception: it first produces a deterministic candidate set, +then uses a bounded structured-LLM proposal to reconcile identity groups. +Invalid or unusable proposals retain the deterministic result and surface retry +or fallback diagnostics; the model does not directly replace durable records. ## Generated References And Grounding @@ -122,7 +123,10 @@ NPC registries are names-only grounding projections: they may canonicalize actors for spells and combat turns and are required for NPC interactions, but they do not supply evidence. Scene-description registries are eligibility-only projections: they retain the current chunk’s classification data, not scene -prose or evidence, and exist to route combat extraction. +prose or evidence, and exist to route combat extraction. Enemy-event extraction +also projects combat turns to `actor` and `turn_kind` and filters NPC +interactions to `combat_opponent` names and kinds. These compact projections, +like NPC grounding, are source-free guidance and never event evidence. ## Lane-Specific Rules @@ -137,11 +141,15 @@ shared helper changes. | Item events | Uses campaign context for disambiguation but has no NPC-registry or scene-description dependency. | | NPC interactions | Requires the normalized NPC registry at extraction and normalization, using it for canonical actor grounding only. | | Scene descriptions | Produces the classifications consumed by combat routing; it does not consume an NPC registry or provide evidence for combat artifacts. | +| Enemy events | Requires NPC, scene-description, combat-turn, and NPC-interaction artifacts. It calls the LLM only for an exact `combat` classification, records ordered observations rather than terminal state, and normalizes recognized names through the NPC registry while preserving grounded collective labels. | The combat and scene-description contracts describe their exact handoff and empty-result behavior in more detail: [combat turns](../integrations/dnd-combat-turn-artifacts.md) and [scene descriptions](../integrations/dnd-scene-description-artifacts.md). +The [enemy-event contract](../integrations/dnd-enemy-event-artifacts.md) +defines its durable semantics; [Configuration](../config.md) owns its +selectable bindings and validation chains. ## Focused Verification diff --git a/docs/roadmap/future.md b/docs/roadmap/future.md index fd1c7a2..d308902 100644 --- a/docs/roadmap/future.md +++ b/docs/roadmap/future.md @@ -7,24 +7,6 @@ not as committed release dates. ## Near-Term D&D Pipeline -### Combat Enemy Ledger - -- Add a D&D artifact that identifies enemies faced during combat and supports - an end-of-session encounter ledger. -- Track each enemy's observed state using a small controlled vocabulary such as - `active`, `killed`, `fled`, `captured`, or `incapacitated`, while preserving - an explicit unresolved state when the transcript does not establish an - outcome. -- Preserve the evidence for enemy participation and state changes rather than - inferring a terminal outcome from combat ending or an enemy disappearing - from the conversation. -- Define how repeated mentions, groups of unnamed enemies, summoned or allied - creatures, and the same enemy appearing in multiple combats affect identity - and ledger entries. -- Evaluate whether the ledger should be extracted directly, derived from - combat-turn artifacts, or use a sequential pipeline that consumes combat - turns and the normalized NPC registry as grounding references. - ### Location Extraction - Add a D&D artifact for locations visited by the party or otherwise mentioned