Document deterministic entity identity resolution
This commit is contained in:
@@ -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.
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
registry’s source references are never occurrence evidence. Unknown IDs and
|
into the unchanged exact durable ID/name pair. The registry’s 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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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 references—not 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. |
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user