# D&D Item-Event Artifact Contract This document defines the durable D&D item-event artifact and its production boundaries. It records source-grounded discoveries and possession changes; it does not maintain an inventory or ledger. ## Artifact Identity | Property | Value | | --- | --- | | Extractor key | `dnd/item-events` | | Extract capability | `dnd.item_events` | | Artifact kind | `dnd/item-event-list` | | Schema ID | `notarius.dnd.item_events` | | Schema name | `notarius_dnd_item_events_v1` | | Schema version | `v1` | | Media type | `application/json` | | Normalizer key | `dnd/item-events` | The payload is one strict JSON object containing a required `events` array, which may be empty. Objects reject unknown fields. ## Event Shape And Categories Every event has `name`, `kind`, and a non-empty `source_refs` array. `quantity` is optional and, when present, is a positive integer. `from` and `to` are optional display values whose presence depends on `kind`. | Field | Rule | | --- | --- | | `name` | Non-empty, transcript-supported display value. | | `kind` | One of the categories below. | | `quantity` | Optional positive integer; omitted when the source does not establish a count. | | `from` | Holder that loses possession when the category permits it. | | `to` | Holder that gains possession when the category permits it. | | `source_refs` | One or more current-source references. | | Kind | Meaning and holder rule | | --- | --- | | `discovered` | The party learns of or encounters an item without established possession; neither holder is present. | | `acquired` | A party member or `party` gains possession; `to` is required and `from` is absent. | | `lost` | A party member or `party` ceases to possess an item without consuming it; `from` is required and `to` is absent. | | `consumed` | Use depletes, expends, or destroys an item; `from` is required and `to` is absent. | | `transferred` | Possession moves between distinct party members; both holders are required and neither may be `party`. | `party` is the reserved display holder for collective party possession when an individual holder is not established. Its comparison is case- and Unicode-insensitive. Transfers require distinct normalized holder values. Giving an item to an NPC, spending currency, selling an item, or another move outside party possession is `lost`, not `transferred` or `consumed`. Monetary spending, purchases, and payments are always `lost`. Currency is `consumed` only when the source explicitly describes its physical destruction or expenditure as a non-payment component. Ordinary non-depleting use is not an event. Currency is represented as an ordinary event name plus an explicit quantity when the transcript supplies one. Each denomination remains separate. The artifact never converts denominations, infers a missing count, calculates a balance, or sums nearby events. ## Source Evidence And Normalization Each source reference contains `source_id`, `start_unit_id`, and `end_unit_id`. It must identify an ordered range in the current source document. During extraction, every cited range must also be wholly contained in the current accepted chunk. Campaign references may disambiguate names, but never provide event evidence. The deterministic normalizer trims only display-edge whitespace in names and holders, canonicalizes source-reference order and exact duplicate references, then orders events by earliest valid source position and stable tie-breakers over name, kind, holders, quantity, and complete evidence. It removes only events with the same normalized fields and complete valid evidence sequence. Invalid evidence is never collapsed. It does not rename, singularize, resolve aliases, infer holders or quantities, or merge nearby events. The default extraction validation chain is JSON syntax, item-event shape, source references, durable JSON Schema, then advisory source relatedness. The normalization chain adds normalized invariants after shape validation and before source references and schema validation. Relatedness warnings are advisory so contextual names and currency notation do not reject otherwise valid evidence. ## Representative JSON ```json { "events": [ { "name": "Hidden Cache", "kind": "discovered", "source_refs": [{"source_id": "session-7", "start_unit_id": 1, "end_unit_id": 1}] }, { "name": "Silver Pieces", "kind": "acquired", "quantity": 20, "to": "party", "source_refs": [{"source_id": "session-7", "start_unit_id": 2, "end_unit_id": 2}] }, { "name": "Torch", "kind": "lost", "from": "party", "source_refs": [{"source_id": "session-7", "start_unit_id": 3, "end_unit_id": 3}] }, { "name": "Healing Potion", "kind": "consumed", "from": "Aria", "source_refs": [{"source_id": "session-7", "start_unit_id": 4, "end_unit_id": 4}] }, { "name": "Moonblade", "kind": "transferred", "from": "Aria", "to": "Borin", "source_refs": [{"source_id": "session-7", "start_unit_id": 5, "end_unit_id": 5}] } ] } ``` ## Production Boundary The extractor requires `chunks` and `source.transcript`, and accepts optional `glossary`, `party`, `players`, and deprecated `roster` campaign references for disambiguation only. It has no generated NPC, scene-description, or item-registry dependency. The append-order merger preserves chunk order, and the normalizer has no reference slots. The normalized lane is emitted as `lanes/.json` by the JSON output module. See [Configuration](../config.md#implemented-production-modules) for the selectable keys and default chains, and the [JSON output contract](json-output.md) for bundle paths.