Document deterministic entity identity resolution

This commit is contained in:
2026-08-08 15:08:57 +00:00
parent fc449863f2
commit 20397ef710
11 changed files with 136 additions and 41 deletions

View File

@@ -0,0 +1,64 @@
# ADR-0012: Resolve opaque entity identifiers deterministically
**Status:** Accepted
**Date:** 2026-08-08
## Context
Entity IDs in durable Notarius artifacts are application-owned, deterministic
identifiers. They are useful to artifact consumers, but their hash-based form
does not help a model distinguish entities and would make the model reproduce
an opaque implementation detail. A plain name is likewise insufficient where
multiple supplied records share that name.
The LLM boundary must preserve the typed artifact and durable-schema ownership
of [ADR-0003](0003-strongly-typed-stage-interfaces.md) and the distinction
between disambiguating references and source evidence in
[ADR-0009](0009-prefer-minimal-evidence-grounded-extraction-artifacts.md).
## Decision
Callers present a model with semantic selections: a canonical name when it is
unique in the request, or a contextual descriptor containing the name and
source coordinates when that context is needed to distinguish supplied
records. The model returns only those supplied selections. The caller resolves
each accepted selection against the request-local supplied records and attaches
the opaque application ID deterministically.
Source coordinates are permitted in a selection solely as identity context.
They neither establish an occurrence fact nor replace that occurrence's
current-transcript evidence. A selector must resolve exactly; unknown,
ambiguous, partial, reordered, or otherwise unsafe selections are not mapped.
Where an operation requires a complete grounded artifact, that failure rejects
the complete artifact rather than accepting a partially mapped result.
An explicitly scoped request-local short label is permitted only when a
contextual descriptor would be impractical and the caller can deterministically
map the label within that one request. Such a label is not a durable ID, must
not escape the request boundary, and requires a concrete justification in its
own module contract.
## Alternatives considered
- Ask the model to return durable IDs. This exposes opaque implementation
state, does not improve semantic disambiguation, and makes model output
depend on hash formatting.
- Select by name alone. This cannot safely distinguish same-name records.
- Make request-local labels durable identifiers. This would turn prompt
presentation into a public identity contract and create avoidable migration
pressure.
- Let the model invent identifiers or resolve ambiguity. This makes identity
assignment non-deterministic and weakens validation.
## Consequences
Durable integration contracts retain their exact ID/name pairs while models
operate on readable contextual selections. Calling modules must own selector
construction, exact resolution, ambiguity handling, and conversion into their
durable artifact type; PromptKit and its adapter remain transport-only.
Some ambiguous or invalid proposals are deliberately omitted, retried, or
rejected according to the caller's existing failure policy. Internal candidate
keys may support deterministic request-local mapping, but they are not
model-visible selectors or durable data. This adds local validation work while
keeping identity assignment auditable and stable.

View File

@@ -24,12 +24,13 @@ An incompatible shape change requires a new schema version.
Both extraction and normalization require an `item_registry` reference bound to Both extraction and normalization require an `item_registry` reference bound to
an earlier normalized `dnd/item-registry` artifact. The registry is immutable an earlier normalized `dnd/item-registry` artifact. The registry is immutable
for an operation and contributes only its ordered `{id,name}` projection after for an operation and contributes names-only grounding after the shared evidence
the shared evidence message. It is never occurrence evidence. message. Notarius resolves the model's selected name into the unchanged exact
durable ID/name pair. It is never occurrence evidence.
Each occurrence must use one exact registry ID/name pair. An extraction response Each occurrence must use one exact registry ID/name pair. An extraction response
with an unknown ID or mismatched name is rejected as invalid model output; the with an unknown or ambiguous selected name is rejected as invalid model output;
configured pipeline may retry it and never accepts a partial artifact. the configured pipeline may retry it and never accepts a partial artifact.
Normalization and validation remain defense in depth for artifacts entering Normalization and validation remain defense in depth for artifacts entering
through other boundaries: normalization canonicalizes a recognized name by ID, through other boundaries: normalization canonicalizes a recognized name by ID,
preserves unknown values for the registry validator, and the registry validator preserves unknown values for the registry validator, and the registry validator

View File

@@ -85,9 +85,10 @@ for later artifacts.
`dnd/item-occurrences` requires one approved item registry through its `dnd/item-occurrences` requires one approved item registry through its
`item_registry` reference slot for both extraction and normalization. Its `item_registry` reference slot for both extraction and normalization. Its
consumer receives only an ordered, source-free `{id,name}` projection; the consumer receives names-only grounding; Notarius resolves the selected name
registrys source references are never occurrence evidence. Unknown IDs and into the unchanged exact durable ID/name pair. The registrys source references
mismatched pairs are rejected by the occurrence contract. See the are never occurrence evidence. Unknown or ambiguous selections are rejected by
the occurrence contract. See the
[item-occurrence artifact](dnd-item-occurrence-artifacts.md) for that strict [item-occurrence artifact](dnd-item-occurrence-artifacts.md) for that strict
wire contract, [Configuration](../config.md#d-d-reference-slots) for binding wire contract, [Configuration](../config.md#d-d-reference-slots) for binding
rules and validator selection, and the [JSON output contract](json-output.md) rules and validator selection, and the [JSON output contract](json-output.md)

View File

@@ -73,10 +73,12 @@ complete canonical evidence sequence.
Both extraction and normalization require exactly one `location_registry` reference of Both extraction and normalization require exactly one `location_registry` reference of
kind `dnd/location-registry`, media type `application/json`, and at most 1 MiB. The kind `dnd/location-registry`, media type `application/json`, and at most 1 MiB. The
registry provides identity grounding only: unknown IDs and mismatched ID/name registry provides identity grounding only. The model selects a supplied
pairs are rejected rather than guessed or reassigned. The current transcript is contextual name-and-registry-reference descriptor, and Notarius resolves it
the only evidence source for an occurrence; registry evidence and provenance into the exact durable ID/name pair. Unknown, partial, or ambiguous selections
never become occurrence evidence. are rejected rather than guessed or reassigned. The current transcript is the
only evidence source for an occurrence; registry evidence and provenance never
become occurrence evidence.
See [Configuration](../config.md#d-d-reference-slots) for the selectable slot See [Configuration](../config.md#d-d-reference-slots) for the selectable slot
and generated-handoff compatibility, [D&D module internals](../internal/dnd.md) and generated-handoff compatibility, [D&D module internals](../internal/dnd.md)

View File

@@ -83,9 +83,11 @@ not evidence for later artifacts.
## Consumers and publication ## Consumers and publication
`dnd/location-occurrences` requires one approved location registry through its `dnd/location-occurrences` requires one approved location registry through its
`location_registry` reference slot. Its prompt receives an ordered source-free `{id, `location_registry` reference slot. Its prompt receives contextual selectors
name}` projection and must not treat registry references as occurrence containing a canonical name and registry references; Notarius resolves a
evidence. See the [location-occurrence artifact](dnd-location-occurrence-artifacts.md) selection into the unchanged exact durable ID/name pair. Registry references
must not be treated as occurrence evidence. See the
[location-occurrence artifact](dnd-location-occurrence-artifacts.md)
for that contract, [Configuration](../config.md#references-and-ordered-handoffs) for that contract, [Configuration](../config.md#references-and-ordered-handoffs)
for binding rules, and the [JSON output contract](json-output.md) for for binding rules, and the [JSON output contract](json-output.md) for
publication. publication.

View File

@@ -67,10 +67,12 @@ for uncertain classification.
## Identity, evidence, and order ## Identity, evidence, and order
The required normalized [NPC registry artifact](dnd-npc-registry-artifacts.md) resolves The required normalized [NPC registry artifact](dnd-npc-registry-artifacts.md)
the exact `{npc_id, name}` pair. Unknown IDs and names that do not match their supplies names-only contextual grounding to the model. Notarius resolves the
ID are rejected; normalization does not repair names by similarity. Registry selected name and writes the exact `{npc_id, name}` pair. An unknown or
references are provenance only and never replace an occurrence's own evidence. ambiguous selection rejects the complete model result; normalization does not
repair names by similarity. Registry references are provenance only and never
replace an occurrence's own evidence.
The registry may include an identity established by a factual third-party The registry may include an identity established by a factual third-party
mention; that provenance alone does not create a `mentioned` occurrence. Each mention; that provenance alone does not create a `mentioned` occurrence. Each
occurrence remains a separately cited fact in the current transcript. occurrence remains a separately cited fact in the current transcript.

View File

@@ -82,9 +82,10 @@ with its own cited evidence and category.
This registry can ground actor or caster names in the [spell](dnd-spell-artifacts.md) 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 and [combat-turn](dnd-combat-turn-artifacts.md) artifacts. It is required to
resolve the canonical `name` in an [NPC occurrence](dnd-npc-occurrence-artifacts.md). resolve the canonical `name` in an [NPC occurrence](dnd-npc-occurrence-artifacts.md).
Occurrence consumers receive an ordered source-free `{id,name}` projection; Occurrence consumers receive names-only grounding; Notarius resolves the
spells, combat turns, and the [enemy-event artifact](dnd-enemy-event-artifacts.md) selected canonical name and writes the unchanged exact durable ID/name pair.
receive names-only grounding for actor or subject display. None of these Spells, combat turns, and the [enemy-event artifact](dnd-enemy-event-artifacts.md)
also receive names-only grounding for actor or subject display. None of these
projections supply later-artifact evidence. [Configuration](../config.md#d-d-reference-slots) projections supply later-artifact evidence. [Configuration](../config.md#d-d-reference-slots)
owns the `npc_registry` binding rules. owns the `npc_registry` binding rules.
The [JSON output contract](json-output.md) defines publication, and The [JSON output contract](json-output.md) defines publication, and

View File

@@ -127,14 +127,17 @@ combine results from distinct scenes, so it intentionally does not apply that
rule. Configuration owns the exact validator key and chain position. rule. Configuration owns the exact validator key and chain position.
Normalizers are deterministic for spells, combat turns, item occurrences, NPC Normalizers are deterministic for spells, combat turns, item occurrences, NPC
occurrences, scene descriptions, enemy events, and location occurrences. They canonicalize display occurrences, scene descriptions, enemy events, and location occurrences. They
values and evidence, use source-document order for stable output, and issue canonicalize display values and evidence, use source-document order for stable
bounded warnings for changes or collapsed duplicates. The NPC and location output, and issue bounded warnings for changes or collapsed duplicates. NPC,
normalizers are intentional exceptions: each first produces a deterministic item, and location registry normalizers are intentional exceptions: each first
candidate set, then may use a bounded structured-LLM proposal to reconcile produces a deterministic candidate set, then may use a bounded structured-LLM
identity groups. Invalid or unusable proposals retain the deterministic result proposal to reconcile identity groups. The proposal selects supplied
and surface retry or fallback diagnostics; the model does not directly replace descriptors—names with their candidate source referencesnot durable IDs.
durable records. Request-local candidate keys may support resolution internally, but are never
included in model input or output. Colliding descriptors are ineligible, and
invalid or unusable proposals retain the deterministic result with retry or
fallback diagnostics; the model does not directly replace durable records.
## Generated References And Grounding ## Generated References And Grounding
@@ -144,11 +147,19 @@ producer provenance; consumers resolve the handed-off artifact into an
immutable, validated projection for each operation. External files are checked immutable, validated projection for each operation. External files are checked
during preparation, while generated artifacts are resolved at the handoff. during preparation, while generated artifacts are resolved at the handoff.
NPC, location, and item registries project ordered, source-free `{id, name}` NPC and item registry consumers receive names-only grounding. Location
pairs to their respective occurrence extractors and normalizers. Exact ID/name consumers receive a contextual selector containing the canonical name and the
matching preserves every identity the registry recognizes, including same-name registry references needed to distinguish same-name places. The calling module
locations with distinct source anchors. The NPC registry additionally supplies resolves those supplied selections locally and maps them into the unchanged
names-only actor grounding to spells, combat turns, and enemy events. durable ID/name pair; an unknown or ambiguous selection rejects the complete
occurrence result rather than accepting a partial mapping. The NPC registry
additionally supplies names-only actor grounding to spells, combat turns, and
enemy events.
Registry references establish a registry identity and may disambiguate a
selection, but never become occurrence evidence. Each occurrence keeps its own
current-transcript source references, even when it was grounded through the
same registry record.
Scene descriptions are eligibility-only projections: they retain current-chunk Scene descriptions are eligibility-only projections: they retain current-chunk
classification data, not scene prose or evidence, and exist to route combat classification data, not scene prose or evidence, and exist to route combat
extraction. Enemy-event extraction also projects combat turns to `actor` and extraction. Enemy-event extraction also projects combat turns to `actor` and
@@ -170,7 +181,7 @@ checkpoint fingerprint.
| Spells | May use a spell-catalog overlay and optional NPC grounding; the catalog validator supplies domain-specific semantic checks. | | Spells | May use a spell-catalog overlay and optional NPC grounding; the catalog validator supplies domain-specific semantic checks. |
| NPC registry | Establishes transcript-grounded NPC identities, including factual third-party mentions, without assigning occurrence categories. It does not consume an NPC registry, and its normalizer is the LLM-assisted reconciliation exception described above. | | NPC registry | Establishes transcript-grounded NPC identities, including factual third-party mentions, without assigning occurrence categories. It does not consume an NPC registry, and its normalizer is the LLM-assisted reconciliation exception described above. |
| Combat turns | Requires a scene-description artifact. It calls the LLM only for an exact `combat` classification; exact non-combat classifications return an accepted empty result, while missing or mismatched classifications return an empty result with a bounded warning. Optional NPC grounding never becomes evidence. | | Combat turns | Requires a scene-description artifact. It calls the LLM only for an exact `combat` classification; exact non-combat classifications return an accepted empty result, while missing or mismatched classifications return an empty result with a bounded warning. Optional NPC grounding never becomes evidence. |
| Item occurrences | Requires the normalized item registry for exact ID/name grounding at extraction and normalization. Campaign context may disambiguate, but the registry never becomes occurrence evidence. | | Item occurrences | Requires the normalized item registry for exact deterministic grounding at extraction and normalization. Campaign context may disambiguate, but the registry never becomes occurrence evidence. |
| Item registry | Produces source-grounded item types and unique designations. Its LLM-assisted reconciliation is proposal-only, preserves distinct currency denominations and item types, and does not create per-instance identities. | | Item registry | Produces source-grounded item types and unique designations. Its LLM-assisted reconciliation is proposal-only, preserves distinct currency denominations and item types, and does not create per-instance identities. |
| NPC occurrences | Requires the normalized NPC registry at extraction and normalization, using it for canonical actor grounding only. It separately emits cited current-transcript occurrence facts, including `mentioned`, rather than deriving them from registry provenance. | | NPC occurrences | Requires the normalized NPC registry at extraction and normalization, using it for canonical actor grounding only. It separately emits cited current-transcript occurrence facts, including `mentioned`, rather than deriving them from registry provenance. |
| Scene descriptions | Produces the classifications consumed by combat routing; it does not consume an NPC registry or provide evidence for combat artifacts. | | Scene descriptions | Produces the classifications consumed by combat routing; it does not consume an NPC registry or provide evidence for combat artifacts. |

View File

@@ -24,6 +24,9 @@ adapter does not own source evidence, artifact conversion, normalization, or
durable schemas. Those responsibilities remain with the module and its durable schemas. Those responsibilities remain with the module and its
[integration contract](../integrations/). [integration contract](../integrations/).
The calling module also resolves contextual entity selections and attaches any
application identity; PromptKit and this adapter do not own entity identity.
`PromptKitClient` validates the request target and prompt identity, maps each `PromptKitClient` validates the request target and prompt identity, maps each
named material to a PromptKit inline artifact while preserving its origin URI, named material to a PromptKit inline artifact while preserving its origin URI,
passes the supplied request session through to PromptKit's direct per-run passes the supplied request session through to PromptKit's direct per-run

View File

@@ -183,6 +183,12 @@ The caller of the LLM owns prompt selection, prompt inputs, response schema,
and interpretation of structured output. Provider adapters do not own source- and interpretation of structured output. Provider adapters do not own source-
or domain-specific prompt logic. or domain-specific prompt logic.
When a model selects an application entity, callers must supply a contextual
selection and deterministically attach the opaque application identity whenever
the selection resolves exactly. Models do not receive or reproduce opaque
application identifiers; [ADR-0012](../adr/0012-resolve-opaque-entity-identifiers-deterministically.md)
records the rationale and limited request-local-label exception.
LLM calls and other external operations accept cancellation and respect LLM calls and other external operations accept cancellation and respect
timeouts. Concurrency control belongs in shared runtime plumbing rather than in timeouts. Concurrency control belongs in shared runtime plumbing rather than in
individual modules. individual modules.

View File

@@ -29,13 +29,15 @@ not as committed release dates.
- Add a reusable normalizer that asks an LLM to identify duplicate sets in a - Add a reusable normalizer that asks an LLM to identify duplicate sets in a
list and propose one replacement element for each set. list and propose one replacement element for each set.
- Define the minimum domain-neutral input contract, initially an ordered list - Define the minimum domain-neutral input contract, initially an ordered list
whose elements have stable unique IDs. Artifact-kind registrations or whose elements retain stable unique IDs as internal deterministic state.
adapters may expose that structure without moving domain rules into the Model proposals use contextual descriptors, or a specifically justified
generic package. request-local short label, rather than durable IDs. Artifact-kind
registrations or adapters may expose that structure without moving domain
rules into the generic package.
- Keep mutation deterministic: parse and validate the model's duplicate groups, - Keep mutation deterministic: parse and validate the model's duplicate groups,
require every referenced ID to exist, reject overlapping or malformed groups, resolve every supplied descriptor or local label exactly, reject overlapping
prevent unrelated insertion or deletion, and apply only approved replacement or malformed groups, prevent unrelated insertion or deletion, and apply only
operations in code. approved replacement operations in code.
- Preserve provenance needed for audit and downstream validation, and emit - Preserve provenance needed for audit and downstream validation, and emit
warnings describing every collapsed group. warnings describing every collapsed group.
- Evaluate batching and context-window limits before applying the normalizer to - Evaluate batching and context-window limits before applying the normalizer to