329 lines
15 KiB
Markdown
329 lines
15 KiB
Markdown
# D&D NPC Semantic Normalization
|
|
|
|
## Status
|
|
|
|
Accepted scope; not implemented.
|
|
|
|
## Purpose
|
|
|
|
Reconcile NPC records that extraction produced under different display names
|
|
when the complete transcript establishes that they represent the same
|
|
individual. This work addresses identities split across scene or chunk
|
|
boundaries while preserving the existing rule that extraction records narrow
|
|
source evidence and normalization owns document-wide reconciliation.
|
|
|
|
The model should make only the semantic identity judgment. Deterministic code
|
|
must continue to own identity derivation, proposal validation, artifact
|
|
mutation, evidence preservation, ordering, diagnostics, and final validation.
|
|
|
|
## Target Behavior
|
|
|
|
The target `dnd/npcs` normalization contract combines:
|
|
|
|
- the current deterministic display-name normalization, stable-ID derivation,
|
|
source-reference canonicalization, and equal-comparison-key consolidation;
|
|
- one LLM determination of whether remaining, distinctly named NPC records
|
|
represent the same individual and which existing display name is canonical;
|
|
and
|
|
- deterministic proposal validation and application followed by the configured
|
|
normalize validator chain.
|
|
|
|
Each configured normalization attempt should make at most one semantic pass
|
|
over the merged document-level NPC list, not one pass per extraction chunk or
|
|
candidate pair. The pass should be skipped when fewer than two distinct
|
|
candidate identities remain after deterministic preprocessing.
|
|
|
|
False consolidation is more damaging than a missed consolidation. Prompt
|
|
policy should therefore require affirmative contextual evidence that names
|
|
identify the same individual and should prefer no group when identity remains
|
|
ambiguous.
|
|
|
|
Canonical selection should favor the most complete stable proper name supported
|
|
by the transcript. A complete proper name is preferable to an abbreviation,
|
|
while an unadorned proper name is preferable to the same name plus a contextual
|
|
class, role, title, or relationship descriptor unless the transcript establishes
|
|
that descriptor as part of the character's name. The model must still select
|
|
one supplied display name rather than synthesize a better one.
|
|
|
|
## Model Proposal Contract
|
|
|
|
The private structured response should contain only proposed duplicate groups:
|
|
|
|
```json
|
|
{
|
|
"duplicate_groups": [
|
|
{
|
|
"members": [
|
|
"Billy",
|
|
"Billy the druid"
|
|
],
|
|
"canonical_name": "Billy"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
`members` identifies candidates by their supplied display names.
|
|
`canonical_name` selects one existing member as the retained display name. An
|
|
empty `duplicate_groups` array is a valid determination that no sufficiently
|
|
supported duplicates exist.
|
|
|
|
The model must not receive or return deterministic `npc:sha256:` IDs. Those IDs
|
|
are long, non-semantic implementation identities and remain exclusively owned
|
|
by deterministic code. The model must not invent a replacement name, rewrite
|
|
an NPC record, propose new source references, or return a complete replacement
|
|
artifact.
|
|
|
|
Before the call, deterministic preprocessing ensures that each supplied display
|
|
name has a unique NPC identity comparison key. Returned names may resolve using
|
|
the existing comparison-key equivalences for case, whitespace, Unicode
|
|
compatibility, and supported apostrophes. Resolution must not use fuzzy,
|
|
substring, edit-distance, embedding, or other approximate matching.
|
|
|
|
An applicable group must:
|
|
|
|
- contain at least two distinct, known members;
|
|
- resolve every member uniquely against the supplied candidate set;
|
|
- select a known `canonical_name` that belongs to the group;
|
|
- contain no repeated member; and
|
|
- share no resolved member with any other proposed group.
|
|
|
|
Unknown or ambiguous names, singleton groups, invalid canonical selections, and
|
|
other unsafe groups must not mutate the artifact. Groups are otherwise
|
|
independent: a locally valid group may be applied when none of its resolved
|
|
members appears in any other proposed group.
|
|
|
|
Overlap is a proposal conflict even when one participating group is already
|
|
locally invalid. Deterministic code must discard every group in the connected
|
|
conflict set rather than selecting a winner by response order. Locally valid,
|
|
non-conflicting groups remain safe to apply. This permits useful partial
|
|
reconciliation without allowing an unsafe group to influence an NPC identity
|
|
that another group would mutate.
|
|
|
|
## Retry And Safe Fallback
|
|
|
|
An invalid or partially unsafe private proposal is a retryable normalization
|
|
attempt. This includes:
|
|
|
|
- structurally invalid model output classified by the LLM boundary as an
|
|
invalid structured completion; and
|
|
- a structurally valid response containing any locally invalid or conflicting
|
|
group.
|
|
|
|
The framework owns retry counting and attempt diagnostics. The normalizer
|
|
returns a safe candidate together with a bounded, content-safe retry
|
|
diagnostic. For structurally invalid output, that candidate is the
|
|
deterministic pre-LLM result. For a decoded proposal with unsafe groups, it
|
|
also includes every independently valid, non-conflicting group from that
|
|
attempt. When normalize retries remain, the framework invokes the normalizer
|
|
again from the same merged input; safe groups are not accumulated across
|
|
attempts. A later completely safe proposal is applied normally.
|
|
|
|
When the configured attempt budget is exhausted, the framework validates and
|
|
accepts the final attempt's safe fallback instead of failing or rejecting the
|
|
NPC lane, provided that fallback passes the configured normalize validators.
|
|
It promotes one durable warning stating that one or more proposed groups were
|
|
omitted. The fallback may therefore contain a safe partial reconciliation, or
|
|
only the deterministic pre-LLM result when no group could be applied. Earlier
|
|
retry diagnostics, candidate values, and warnings remain attempt-local in
|
|
debug artifacts.
|
|
|
|
The normal module-binding default remains `retries: 0`, meaning one total
|
|
normalization attempt and immediate fallback after its invalid proposal.
|
|
Retries occur only when the user configures a positive normalize retry count.
|
|
For example, `retries: 2` permits the initial proposal plus two additional
|
|
attempts before fallback.
|
|
|
|
Transport, authentication, prompt-preparation, cancellation, input-encoding,
|
|
and other operational errors are not safe-proposal failures. They retain the
|
|
existing module/framework error behavior rather than being converted into an
|
|
accepted fallback.
|
|
|
|
## Transcript Context Policy
|
|
|
|
The model should receive every candidate's display name and source references,
|
|
together with transcript windows derived from those references. It should not
|
|
receive the complete transcript by default.
|
|
|
|
Each window must contain:
|
|
|
|
- the complete inclusive source range cited by the NPC record;
|
|
- up to two source units immediately before the cited range; and
|
|
- up to two source units immediately after the cited range.
|
|
|
|
The surrounding-unit count is defined once as a named module policy constant
|
|
with value `2`; it is not a user-accessible configuration field. Window
|
|
construction consumes that value through one clear boundary so a later
|
|
configuration option can replace the fixed value without changing prompt or
|
|
reconciliation contracts. The context-radius policy participates in module
|
|
metadata and checkpoint identity so changing it invalidates incompatible
|
|
normalize checkpoints.
|
|
|
|
The value was selected by reviewing the July 19 evaluation transcript. Its NPC
|
|
citations are generally self-contained; where additional context is useful,
|
|
two surrounding units capture the relevant question-and-answer exchange,
|
|
speaker transition, or short anaphora chain. A third unit frequently begins a
|
|
separate joke or table exchange and adds distraction without improving the
|
|
identity evidence.
|
|
|
|
Window expansion must use source-document positions rather than arithmetic on
|
|
unit IDs. It must clamp at document boundaries, preserve document order, and
|
|
coalesce overlapping or adjacent expanded windows without duplicating units.
|
|
The prepared model input must distinguish originally cited units from
|
|
surrounding context.
|
|
|
|
Only records with a non-empty NPC identity comparison key and a non-empty
|
|
source-reference collection that is wholly valid against the current source
|
|
document are eligible for semantic reconciliation. Ineligible records remain
|
|
unchanged so the configured deterministic validators retain ownership of their
|
|
rejection. They are not supplied to the model and cannot participate in a
|
|
proposed group.
|
|
|
|
Surrounding units inform the semantic decision but do not automatically become
|
|
durable NPC evidence. An applied group unions only the source references
|
|
already present on its member records. The LLM cannot add references from the
|
|
context window.
|
|
|
|
Full-transcript mode and a configurable context radius may be evaluated later.
|
|
They are not part of this scope. Provider prompt-cache behavior should be
|
|
measured rather than assumed before expanding context solely for cache
|
|
economics.
|
|
|
|
## Deterministic Application
|
|
|
|
For each approved group, deterministic code should:
|
|
|
|
- retain the model-selected existing display name;
|
|
- union source references from every group member;
|
|
- canonicalize and exact-deduplicate those references in source-document order;
|
|
- derive the resulting stable NPC ID from the retained display name under the
|
|
existing NPC identity policy; and
|
|
- emit one bounded duplicate-collapse warning describing the applied group.
|
|
|
|
The consolidated record should occupy the earliest original member position so
|
|
model response ordering cannot reorder the artifact. Unrelated records must
|
|
remain present and retain their relative order. Every input record must be
|
|
represented by exactly one output record, either unchanged or through one
|
|
approved consolidation.
|
|
|
|
The existing NPC shape, identity, source-reference, schema, and relatedness
|
|
validators remain the final artifact boundary. No LLM-backed validator is
|
|
needed: model judgment occurs in the normalizer, while deterministic validators
|
|
continue to enforce the durable artifact contract.
|
|
|
|
## Prompt, Provenance, And Diagnostics
|
|
|
|
NPC semantic-normalization instructions and the private response schema should
|
|
be module-owned prompt assets. Stable D&D-wide identity or transcript guidance
|
|
may be reused through the existing shared prompt-asset mechanism where its
|
|
meaning is genuinely common.
|
|
|
|
The normalizer should use the configured normalize-stage LLM profile and the
|
|
application-wide scheduled LLM client. Invalid structured output and unsafe
|
|
semantic proposals use the framework-owned retryable-fallback contract;
|
|
operational failures retain existing error semantics.
|
|
|
|
Manifest metadata and component checkpoint fingerprints should identify the
|
|
semantic-normalization policy, prompt identity, private response-schema
|
|
identity, deterministic NPC identity policy, and evidence-context policy.
|
|
They must not contain transcript text, NPC names, source paths, raw model
|
|
responses, or other source content.
|
|
|
|
Warnings and preparation or runtime errors must follow the established bounded
|
|
diagnostic and content-safety policies. Debug artifacts may retain the normal
|
|
attempt-local model request, response, proposal decisions, and warnings under
|
|
the existing debug sensitivity contract.
|
|
|
|
## Configuration And Documentation
|
|
|
|
The maintained complete D&D configuration should demonstrate a normalize-stage
|
|
LLM profile and an explicit positive retry count for the NPC lane. The
|
|
application-wide default remains zero additional retries. No new configuration
|
|
field is introduced for the context radius in this scope.
|
|
|
|
Canonical documentation ownership is:
|
|
|
|
- Configuration owns the LLM-backed `dnd/npcs` selection and its use of the
|
|
existing normalize binding's profile and retry fields.
|
|
- Operations owns the document-level semantic reconciliation call and its
|
|
checkpoint behavior.
|
|
- Pipeline internals own the provider-neutral invalid-structured-output
|
|
classification and normalize retryable-fallback contract.
|
|
- The NPC integration contract owns externally observable consolidation,
|
|
evidence, ordering, and warning behavior.
|
|
- Internal LLM and module documentation own the proposal boundary,
|
|
context-window construction, deterministic application, metadata, and
|
|
fingerprints.
|
|
- The broader generic LLM-assisted deduplication item in
|
|
[future.md](future.md) remains future work until another artifact demonstrates
|
|
that extracting a shared generic facility is worthwhile.
|
|
|
|
## Quality Expectations
|
|
|
|
Tests should protect the semantic and safety boundaries through deterministic
|
|
LLM fakes rather than live-provider calls. Coverage should demonstrate:
|
|
|
|
- distinct display variants can be consolidated when the model proposes a
|
|
valid group;
|
|
- model-facing requests and responses use display names rather than stable
|
|
hash IDs;
|
|
- the selected existing canonical name controls ID derivation while all member
|
|
evidence is preserved;
|
|
- window construction uses source-document position, handles document edges,
|
|
coalesces overlap, and distinguishes cited evidence from context;
|
|
- no surrounding context is promoted into durable source references;
|
|
- empty proposals and fewer-than-two-candidate inputs preserve deterministic
|
|
normalization behavior;
|
|
- unknown, ambiguous, repeated, overlapping, and otherwise malformed semantic
|
|
groups cannot corrupt or reorder the artifact;
|
|
- locally valid groups are applied independently, while every group that
|
|
participates in a resolved-member conflict is discarded;
|
|
- an invalid proposal consumes only configured retry budget, a later valid
|
|
proposal can succeed, and exhaustion accepts the final attempt's safe
|
|
fallback with one durable warning;
|
|
- the default zero-retry binding makes exactly one proposal attempt before
|
|
fallback;
|
|
- warnings and failures remain bounded and do not expose transcript content;
|
|
- prompt, schema, policy, or context-policy changes invalidate relevant
|
|
checkpoint reuse; and
|
|
- an assembled ordered D&D pipeline supplies the reconciled NPC registry to
|
|
downstream consumers.
|
|
|
|
Prompt tests should assert prepared message structure, supplied materials, and
|
|
cache-boundary behavior. They must not act as change detectors for particular
|
|
words or phrases in natural-language prompt text.
|
|
|
|
Human review of representative transcripts should compare missed and false
|
|
consolidations, latency, input-token cost, and provider cache use. Probabilistic
|
|
model quality is an evaluation activity, not a deterministic CI assertion.
|
|
|
|
## Non-Goals
|
|
|
|
This scope does not:
|
|
|
|
- change the durable NPC artifact schema;
|
|
- add a durable alias collection or identity history;
|
|
- expose the context radius or full-transcript selection as configuration;
|
|
- ask an LLM to read, reproduce, or derive stable NPC IDs;
|
|
- permit model-authored source references or arbitrary replacement records;
|
|
- add fuzzy deterministic name matching;
|
|
- add an LLM-backed normalize validator;
|
|
- change the global default retry count;
|
|
- reconcile NPCs concurrently across lanes or runs;
|
|
- add canonical NPC IDs to downstream artifact schemas;
|
|
- implement a general DAG or implicit cross-lane dependency; or
|
|
- implement the generic cross-artifact deduplication normalizer described in
|
|
`future.md`.
|
|
|
|
## Completion Criteria
|
|
|
|
The scope is complete when `dnd/npcs` can use one document-level LLM proposal
|
|
to reconcile differently named records conservatively, deterministic code
|
|
validates and independently applies only safe non-conflicting name-based
|
|
groups, the resulting NPC preserves all member evidence under a newly derived
|
|
stable ID, the two-unit context policy is centralized and fingerprinted,
|
|
invalid or partially unsafe proposals use configured framework retries and
|
|
then an accepted safe fallback, downstream ordered steps receive the
|
|
reconciled registry, and the canonical current-behavior documentation reflects
|
|
the implemented contract.
|