Files
notarius/docs/roadmap/combat.md

16 KiB

Combat Enemy Event Extraction

Purpose

Define a minimal, evidence-grounded D&D artifact that records enemies engaged and their explicitly observed combat outcomes. The artifact is the durable primitive from which an end-of-session encounter ledger can be derived; this scope does not ask an LLM to synthesize a final ledger or infer an outcome from silence.

This roadmap follows ADR-0009: the extractor answers one narrow question, every reported fact has direct transcript evidence, and generated artifacts provide grounding rather than evidence.

Context

Notarius can currently identify NPCs, classify NPC interactions, record combat turns, and classify scenes. Those artifacts answer useful but different questions:

  • the NPC registry establishes individually identifiable names;
  • NPC interactions identify such occurrences as combat_opponent but do not record outcomes;
  • combat turns establish actors and action boundaries but deliberately omit action contents and state; and
  • scene descriptions determine which chunks are combat scenes.

None can establish by itself that an opponent was killed, fled, captured, or incapacitated. Deriving those outcomes from an absent later turn, the end of a scene, or a combat-opponent classification would create unsupported claims. The new extractor therefore reads the combat transcript directly while using the four normalized artifacts above as explicit auxiliary grounding.

Goals

  • Produce an ordered list of directly evidenced enemy engagement and outcome events.
  • Keep the durable event shape to name, kind, and source_refs.
  • Run the LLM only for chunks with an exact combat scene classification.
  • Ground named subjects in the normalized NPC registry and use prior combat artifacts to constrain participation and allegiance without treating them as evidence.
  • Support unnamed individuals and groups without inventing synthetic member identities.
  • Preserve repeated engagements and state changes rather than collapsing them into one synthesized terminal record.
  • Integrate the lane into the maintained complete D&D pipeline as a later ordered step.
  • Follow the existing D&D codec, prompt, normalization, validation, registration, evidence-publication, checkpoint, and documentation conventions.

Target End State

Durable Artifact Contract

The new production module key is dnd/enemy-events. Its typed artifact is:

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
Root field events

The root is a strict object with one required events array. The array may be empty. Each event is a strict object with exactly 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 inclusive current-transcript evidence ranges.

Each source reference has exactly source_id, start_unit_id, and end_unit_id, following the existing generic source-reference contract. The durable schema rejects unknown fields and incompatible types.

Example:

{
  "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}
      ]
    }
  ]
}

The artifact does not contain an NPC ID, scene ID, quantity, confidence, description, rationale, summary, current state, or inferred terminal outcome. Scene membership remains deterministically derivable by intersecting event evidence with scene ranges. Cross-artifact durable NPC IDs remain governed by the separate future identity-link design consideration.

Event Semantics

Kind Required evidence
engaged The subject is directly established as actively opposing the party in combat. Emit at most one engagement for the same subject in one combat scene.
killed The transcript explicitly establishes that the subject died or was killed. Damage, defeat, disappearance, or the end of combat is insufficient.
fled The subject explicitly escapes, retreats, or otherwise leaves the combat to avoid continued engagement. Mere 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. Do not infer this from a missed turn.

An outcome may share evidence with an engagement, in which case both events are emitted. A later engagement for the same named subject is preserved, even after an earlier outcome, because enemies may escape, recover, return, or be revived. The event list records observations rather than asserting irreversible state transitions.

active and unresolved are not model-produced event kinds. A downstream ledger may report the most recent explicit outcome for a subject and use unresolved when an engagement has no later evidenced outcome. It must not use active merely because no terminal event was extracted. A distinct future contract would be required if operators need an evidenced ongoing-combat state.

Subject Identity And Groups

  • An individually named subject that matches the normalized NPC registry uses the registry's canonical display name.
  • A hostile creature or summoned entity is included when it directly opposes the party, whether or not it has an NPC-registry entry.
  • An unnamed homogeneous group is represented collectively with the narrowest transcript-grounded label, such as Orcs. The extractor does not invent Orc 1, Orc 2, or other synthetic identities.
  • When evidence applies only to a subgroup or one unidentified member, use the narrowest supported phrase, such as One orc or Remaining orcs. Do not claim a deterministic identity link between that phrase and another group event.
  • Named subjects may be compared across scenes through the canonical NPC name. Generic or collective subjects are scoped to their combat scene by their evidence range and are not assumed to be the same group in another scene.
  • Party members, combat allies, neutral observers, mentioned-but-absent enemies, hazards, traps, and environmental effects are excluded. Uncertain allegiance is not enough to emit an event.

These conservative rules prefer separate, explicitly evidenced observations over a falsely precise encounter roster.

Ordered Pipeline And References

The extractor is an LLM-backed lane in a third maintained D&D pipeline step. It requires four JSON artifact reference slots at extraction:

Slot Artifact kind Purpose
npcs dnd/npc-list Canonical grounding for individually named subjects.
scene_descriptions dnd/scene-description-list Eligibility gate for exact combat scenes.
combat_turns dnd/combat-turn-list Grounding for observed combat actors and action boundaries.
npc_interactions dnd/npc-interaction-list Grounding for named combat_opponent occurrences.

Each slot is required, accepts application/json, accepts only its listed artifact kind, and has a 1,048,576-byte limit consistent with the current D&D registry references. The framework may satisfy the contract with a compatible external artifact, but the maintained complete pipeline uses generated references from earlier steps.

The deterministic normalizer requires only the npcs slot. The other three artifacts inform extraction and scene routing but do not participate in final name canonicalization.

The maintained complete pipeline has this topology:

describe-session
  -> npcs
  -> scene-descriptions

extract-events
  -> combat-turns
  -> npc-interactions

track-enemies
  -> enemy-events

track-enemies consumes npcs and scene-descriptions from describe-session, and combat-turns and npc-interactions from extract-events. An invalid, rejected, absent, ambiguous, or incompatible upstream generated artifact prevents the dependent step from starting under the existing single-run failure semantics. No new DAG or workflow mechanism is introduced.

Eligibility And Grounding Projections

The extractor reuses the scene-description registry's exact chunk matching:

  • exact combat match: prepare grounding inputs and call the LLM;
  • exact non-combat match: return an accepted non-nil empty event list without an LLM call; and
  • missing or mismatched classification: return an accepted non-nil empty event list with the bounded scene_classification_unavailable warning and no LLM call.

Auxiliary artifacts are decoded and projected into compact, canonical prompt inputs:

  • NPCs retain only canonical name values;
  • combat turns retain only actor and turn_kind;
  • NPC interactions retain only name and kind, and only combat_opponent records are included; and
  • scene descriptions are used only for eligibility and are not rendered into the extraction prompt.

All artifact IDs, source references, summaries, producer provenance, and origin URIs are excluded from the projections. Projection content receives its own digest. Full generated-reference content and producer provenance continue to participate in the framework's existing handoff and checkpoint identity. Neither a projection nor its source references may be copied into event evidence.

Prompt And Private Response Contract

The extractor uses prompt ID dnd.enemy_events, PromptKit default profile dnd-extraction, and a strict private response schema named notarius_dnd_enemy_events_llm_v1. The private schema contains required name, kind, and segment-range candidates; deterministic mapping attaches the current source ID and preserves semantic candidates for validators.

Prompt construction follows the shared D&D extraction convention. The first four rendered messages remain exactly the shared system, identity, campaign reference, and chunk-transcript messages in their existing cache-control arrangement. Evidence policy, the NPC registry, module-owned compact combat grounding, task, and final instructions follow the transcript. The new module reuses shared assets instead of copying their text, and its final instructions message carries ephemeral cache control.

The prompt makes clear that grounding artifacts are hints, not proof; the current combat transcript is the only evidence; every event requires its own chunk-confined ranges; and absence from a turn list or opponent list does not establish an outcome.

Deterministic Normalization

dnd/enemy-events also identifies a deterministic normalizer for the same typed artifact. It:

  1. clones caller-owned data;
  2. collapses display whitespace in every subject name;
  3. replaces a recognized subject with the canonical NPC-registry display name, while retaining normalized unmatched group labels;
  4. canonically orders and removes exact duplicate source ranges;
  5. orders events by earliest valid source position, then normalized comparison name, display name, the explicit kind order engaged, incapacitated, captured, fled, killed, and complete reference sequence; invalid evidence sorts after valid evidence for deterministic validation; and
  6. collapses only records with the same normalized subject identity, kind, and complete canonical evidence sequence, retaining the earliest display value.

Distinct event kinds, distinct evidence, repeated engagements in different scenes, and later outcome changes remain separate. Normalization never manufactures an engagement or outcome and never aggregates the list into a ledger. It is idempotent and emits bounded warnings for name changes, evidence normalization, reordering, and exact duplicate collapse.

Validation And Production Policy

The D&D registrar provides these validators:

  • extract/dnd/enemy-events/shape;
  • extract/dnd/enemy-events/engagements;
  • extract/dnd/enemy-events/source_refs;
  • extract/dnd/enemy-events/source_relatedness; and
  • normalize/dnd/enemy-events/invariants.

The extraction default chain is:

generic/valid_json
extract/dnd/enemy-events/shape
extract/dnd/enemy-events/engagements
extract/dnd/enemy-events/source_refs
generic/valid_json_schema
extract/dnd/enemy-events/source_relatedness

The normalization default chain inserts normalize/dnd/enemy-events/invariants after the shape validator. Shape owns non-empty names, the closed event-kind vocabulary, and non-empty evidence. Source-reference validation owns current-document range validity. Durable schema validation owns the public JSON shape. Relatedness remains advisory. The invariant validator owns canonical display values, registry-aware canonical names where applicable, canonical evidence, deterministic ordering, and absence of exact duplicates.

No production LLM-backed validator is added. Semantic quality should first be evaluated through the extractor prompt and human review rather than adding a second model judgment without a concrete policy.

The registrar also supplies the strict codec, typed append-order merger, deterministic normalizer, typed no-op normalizer compatibility, typed evidence projection, prompt and schema assets, safe manifest metadata, and stable checkpoint fingerprints. Operation-varying generated reference content stays in framework-owned reference/checkpoint identity rather than static module metadata.

Output, Examples, And Documentation

The JSON output encoder publishes normalized enemy events like every other typed lane. The maintained complete example adds enemy-events to its evidence context allowlist and demonstrates the third generated-reference step. The minimal example remains unchanged.

When implemented, canonical documentation adds a D&D enemy-event integration contract, adds the production keys, slots, and default chains to docs/config.md, and updates docs/internal/dnd.md for the seventh lane, grounding projections, prompt ordering, eligibility, and normalization. Current-behavior documents do not describe the feature before its code lands.

Out Of Scope

  • A separately published aggregated enemy-ledger artifact or inventory-like state store.
  • Model-produced active, unresolved, confidence, rationale, description, or summary fields.
  • Synthetic identities or quantities for indistinguishable enemies.
  • Durable NPC-ID links, alias resolution beyond the normalized registry, or a general cross-artifact entity graph.
  • Inferring outcomes from turn absence, scene termination, hit-point guesses, initiative order, or other artifacts.
  • Deriving enemy events solely from combat turns or NPC interactions.
  • Changing existing combat-turn, NPC, NPC-interaction, or scene-description schemas.
  • A general workflow DAG, general reference-query system, or generic semantic deduplication framework.
  • Paid or live-model tests in the default suite.

Acceptance Criteria

  • dnd/enemy-events produces the strict minimal v1 event artifact and preserves direct transcript evidence for every record.
  • Only exact combat scenes invoke the LLM; non-combat and unclassified chunks follow the defined empty-result behavior.
  • The extractor consumes validated NPC, scene-description, combat-turn, and NPC-interaction references through source-free grounding projections.
  • Named enemies canonicalize through the NPC registry while unmatched individuals and collective labels remain supported without invented IDs.
  • The normalizer is deterministic, idempotent, ownership-safe, warning-bounded, and collapses exact duplicates only.
  • The codec, validators, default chains, merger, no-op compatibility, evidence projector, prompt assets, fingerprints, and module specs are registered by the D&D family.
  • The maintained complete pipeline resolves and runs the new third step with compatible generated references from both earlier steps.
  • Canonical documentation and maintained examples describe only implemented behavior, remain secret-free, and pass their existing offline contract tests.