427 lines
20 KiB
Markdown
427 lines
20 KiB
Markdown
# Semantic Reconciliation Roadmap
|
|
|
|
## Purpose
|
|
|
|
This roadmap defines a reusable, LLM-assisted semantic-reconciliation facility
|
|
for source-backed entity registries. The facility will centralize the common
|
|
candidate preparation, prompt execution, proposal validation, safety, retry,
|
|
and consolidation mechanics currently implemented by the D&D NPC, item, and
|
|
location registry normalizers while preserving typed, domain-owned output.
|
|
|
|
The model will remain a constrained proposal source. Notarius will retain
|
|
authority over candidate identity, proposal validation, deterministic mutation,
|
|
provenance, durable identifiers, warnings, and final artifact construction.
|
|
|
|
## Motivation
|
|
|
|
NPC, item, and location registry normalization now demonstrate the same useful
|
|
pattern: deterministic preprocessing produces candidate records, an LLM judges
|
|
whether some candidates describe the same underlying entity, and deterministic
|
|
code applies only safe proposed groups. The current D&D-shared implementation
|
|
proves the approach, but it still duplicates orchestration and application
|
|
logic across normalizers and requires the model to reproduce complete
|
|
contextual selectors containing names and evidence ranges.
|
|
|
|
The target design should provide one efficient and thoroughly tested
|
|
reconciliation core that can support additional artifact families without
|
|
moving domain semantics into generic code. It should also simplify the model's
|
|
task by replacing selector reproduction with small request-local integer
|
|
handles.
|
|
|
|
## Goals
|
|
|
|
- Establish one domain-neutral semantic-reconciliation core for source-backed
|
|
entity candidates.
|
|
- Move all demonstrated common mechanics into that core, including structured
|
|
LLM execution and deterministic proposal assessment.
|
|
- Preserve exact typed artifact ownership from merged input through normalized
|
|
output.
|
|
- Give the model semantic evidence while asking it to return only small,
|
|
request-local candidate identifiers.
|
|
- Provide a conservative generic semantic prompt policy that a typed artifact
|
|
family may use by default.
|
|
- Allow an artifact family to supply narrower domain semantic policy without
|
|
replacing the mandatory shared protocol and safety instructions.
|
|
- Have the NPC, item, and location registry normalizers use the shared core
|
|
without changing their durable artifact contracts, configured module keys,
|
|
domain identity rules, or fallback guarantees.
|
|
- Make addition of another eligible registry normalizer primarily an adapter
|
|
and policy exercise rather than a copy of reconciliation machinery.
|
|
|
|
## Terminology And Ownership
|
|
|
|
A **stage module** remains one configured implementation of one pipeline stage.
|
|
An extractor and a normalizer are separate stage modules even when they
|
|
collaborate on the same artifact kind.
|
|
|
|
An **artifact family** is the cohesive domain feature that owns an artifact's
|
|
types, codec, extractor, merge choice, normalizer, validators, prompt policy,
|
|
schemas, identity helpers, and reference projections. For example, D&D spells
|
|
and the D&D NPC registry are artifact families whose implementations span
|
|
multiple explicit pipeline stages.
|
|
|
|
This terminology clarifies existing ownership without changing Notarius's
|
|
fixed pipeline or combining stages. It is consistent with the accepted
|
|
domain-first organization and typed generic-strategy boundary in
|
|
[ADR-0004](../adr/0004-package-modules-by-domain.md). The D&D registrar remains
|
|
responsible for composing D&D-owned stage modules and their policies; the
|
|
generic core remains unaware of D&D types or semantics.
|
|
|
|
## Target Architecture
|
|
|
|
### Shared Core
|
|
|
|
A domain-neutral framework package should own semantic reconciliation. It may
|
|
depend on generic source and structured-completion contracts and may consume
|
|
its scoped assets under `assets/generic/`, but it must not import a production
|
|
domain or encode D&D identity rules.
|
|
|
|
The shared core owns:
|
|
|
|
- validation and defensive copying of its inputs;
|
|
- candidate eligibility and stable input ordering;
|
|
- assignment of model-visible request-local candidate IDs;
|
|
- construction of bounded candidate and source-context materials;
|
|
- invocation of the configured structured LLM prompt;
|
|
- the private duplicate-group response schema;
|
|
- exact resolution of response IDs to the candidates visible in that request;
|
|
- rejection of malformed, unknown, repeated, ambiguous, or overlapping
|
|
proposals;
|
|
- canonical ordering of accepted groups and group members;
|
|
- construction of an immutable reconciliation plan;
|
|
- shared retry, fallback, cancellation, and invalid-output classification;
|
|
- generic consolidation and provenance mechanics that are demonstrably common
|
|
across typed consumers; and
|
|
- metadata and checkpoint fingerprints for shared prompts, schemas, and policy
|
|
versions.
|
|
|
|
The core should expose stable behavior rather than a collection of unrelated
|
|
helpers. Its API should make the safe path direct: a caller supplies typed
|
|
candidates and a narrow domain policy, and receives either a deterministic
|
|
typed result or a validated reconciliation plan that can only be applied
|
|
through the typed policy boundary.
|
|
|
|
### Typed Artifact-Family Adapter
|
|
|
|
Each consuming artifact family owns a typed adapter or policy that supplies the
|
|
irreducibly domain-specific behavior:
|
|
|
|
- projection of merged typed records into eligible reconciliation candidates;
|
|
- the semantic identity scope being reconciled;
|
|
- an optional domain semantic-policy prompt asset;
|
|
- canonical-field selection beyond choosing the supplied canonical member;
|
|
- domain field and evidence consolidation rules;
|
|
- durable ID derivation;
|
|
- domain warning scopes, reason codes, and messages; and
|
|
- domain postconditions and fallback behavior not covered by the shared core.
|
|
|
|
The adapter must not parse untyped durable JSON or weaken the artifact codec's
|
|
exact Go type. The core must not use reflection to infer domain fields. Shared
|
|
typed consolidation support may use Go generics and a deliberately small policy
|
|
interface where that removes demonstrated duplication without hiding domain
|
|
rules.
|
|
|
|
### Pipeline Boundary
|
|
|
|
Semantic reconciliation remains an implementation of the normalize stage. It
|
|
does not add a pipeline stage, hide normalization inside extraction, or create
|
|
an arbitrary workflow edge. Existing typed normalizer registrations remain the
|
|
public configuration boundary.
|
|
|
|
The initial implementation does not register one universal
|
|
`generic/deduplication` module key. A module key cannot safely accept arbitrary
|
|
artifact kinds under the current exact typed-registration contract. Domain
|
|
registrars instead instantiate the shared strategy for their own artifact
|
|
types.
|
|
|
|
## Request-Local Candidate Protocol
|
|
|
|
### Candidate Presentation
|
|
|
|
After deterministic preprocessing and eligibility filtering, the core assigns
|
|
the candidates visible to one completion request contiguous integer
|
|
`candidate_id` values beginning with `1`. The mapping is owned by that request
|
|
and retains the original typed candidate and input position internally.
|
|
|
|
Each model-facing candidate includes its `candidate_id`, contextual display
|
|
name or label, and the evidence and context needed for semantic judgment. In
|
|
the initial source-backed implementation, that context consists of validated
|
|
source-reference ranges and bounded, source-ordered transcript windows.
|
|
Application-owned durable entity IDs are never included.
|
|
|
|
Candidate IDs:
|
|
|
|
- are identifiers for prompt selections, not entity identities;
|
|
- have meaning only within one structured completion request;
|
|
- restart for each request or future batch;
|
|
- never enter a durable artifact or public schema;
|
|
- are not used to derive durable IDs; and
|
|
- must be resolved through the core's retained request-local mapping.
|
|
|
|
Only model-visible eligible candidates receive IDs. Filtering must not produce
|
|
gaps that increase model burden or reveal unrelated internal ordering.
|
|
|
|
### Proposal Response
|
|
|
|
The private structured response contains an ordered `duplicate_groups` array.
|
|
Each group contains:
|
|
|
|
- `candidate_ids`: at least two distinct supplied integer IDs; and
|
|
- `canonical_candidate_id`: one supplied ID that is also a member of that
|
|
group.
|
|
|
|
The model does not return candidate names, source ranges, replacement records,
|
|
durable IDs, or synthesized canonical values. Choosing a canonical candidate
|
|
means selecting one supplied member; typed deterministic code constructs the
|
|
resulting record.
|
|
|
|
The response schema should reject unknown fields and require every defined
|
|
field. Application validation remains authoritative and must additionally
|
|
reject out-of-range IDs, repeated members, a canonical ID outside its group,
|
|
and any candidate appearing in more than one group. Schema validation is not a
|
|
substitute for these semantic checks.
|
|
|
|
### Deterministic Plan
|
|
|
|
The core resolves accepted IDs to internal candidates, orders members by their
|
|
original deterministic positions, and orders groups by their earliest member.
|
|
Candidates omitted from the response remain distinct. Invalid groups are never
|
|
partially applied.
|
|
|
|
The reconciliation plan retains enough internal provenance for typed
|
|
application, warning generation, debugging, and validation without exposing
|
|
request-local IDs as durable identity.
|
|
|
|
## Prompt Policy
|
|
|
|
### Mandatory Shared Protocol
|
|
|
|
The core owns a shared prompt fragment that defines the response protocol and
|
|
non-negotiable safety behavior. It instructs the model to:
|
|
|
|
- identify only well-supported groups that denote the same underlying entity;
|
|
- preserve candidates that are merely similar or uncertain;
|
|
- return only supplied candidate IDs;
|
|
- select one supplied group member as canonical;
|
|
- omit uncertain groups; and
|
|
- invent no candidates, evidence, attributes, identities, or replacements.
|
|
|
|
This protocol fragment and the private schema are not replaceable by a domain
|
|
adapter. Keeping them shared ensures identical mechanics across consumers and
|
|
provides one prompt prefix for review, testing, and provider caching.
|
|
|
|
### Generic Semantic Default
|
|
|
|
The core provides a conservative generic semantic-policy fragment suitable for
|
|
an artifact family whose notion of entity identity is adequately conveyed by
|
|
its candidate labels and evidence. It asks whether candidates refer to the same
|
|
underlying entity and treats uncertainty as a reason not to collapse them.
|
|
|
|
Use of the generic default is explicit in the typed adapter. It is not an
|
|
implicit fallback for an adapter that failed to declare its policy.
|
|
|
|
### Domain Semantic Policy
|
|
|
|
An artifact family may select a domain-owned semantic-policy fragment in place
|
|
of the generic semantic fragment. The replacement defines only domain judgment
|
|
and canonical-member preferences; it does not replace the shared protocol,
|
|
response schema, or deterministic safety rules.
|
|
|
|
The existing NPC, item, and location policies remain domain-owned because they
|
|
encode meaningful distinctions among people, item types or unique
|
|
designations, currency denominations, parent and child places, and same-name
|
|
physical locations. Their prompt manifests should select the shared protocol
|
|
and their local semantic fragment while using the same generic response
|
|
schema.
|
|
|
|
Prompt selection is initially an implementation-time artifact-family choice.
|
|
This work does not add arbitrary operator-supplied prompt paths or configuration
|
|
that can replace reconciliation safety policy.
|
|
|
|
## Context, Bounds, And Model Invocation
|
|
|
|
The first shared core is intentionally scoped to candidates grounded in a
|
|
Notarius source document. It validates candidate source references, creates
|
|
bounded windows around their evidence, preserves source order, and supplies
|
|
the model with the relationship between each candidate ID and its evidence.
|
|
Source ranges are model input but are never model output.
|
|
|
|
The core skips the LLM call when fewer than two candidates remain eligible. It
|
|
must also impose explicit candidate-count and rendered-context bounds. When an
|
|
input cannot be reconciled safely within those bounds, normalization preserves
|
|
the deterministic preprocessed result and produces bounded diagnostics under
|
|
the consuming module's established fallback policy. It must not silently
|
|
process arbitrary fixed-size slices that could separate duplicates.
|
|
|
|
Every completion uses the injected scheduled structured-LLM client, propagated
|
|
profile and session ID, cancellation, and the normalizer retry contract.
|
|
Invalid structured output or an unusable proposal follows the existing
|
|
retry-then-deterministic-fallback model. Transport and provider failures remain
|
|
execution errors rather than being silently converted into semantic absence.
|
|
|
|
## Deterministic Typed Application
|
|
|
|
The model never mutates the artifact. The shared core and typed adapter apply
|
|
only fully validated groups.
|
|
|
|
Application must preserve these invariants:
|
|
|
|
- no ungrouped candidate is inserted, removed, or changed by semantic
|
|
reconciliation;
|
|
- every accepted group produces exactly one typed output record;
|
|
- canonical display fields come from a supplied group member unless a domain
|
|
policy explicitly performs a deterministic transformation;
|
|
- all required provenance from group members is retained and canonicalized;
|
|
- output order follows the earliest contributing deterministic input position;
|
|
- durable IDs are recomputed by the domain identity policy after
|
|
consolidation;
|
|
- caller-owned input and request material are never mutated;
|
|
- warnings identify every collapsed group using domain-owned scopes and reason
|
|
codes; and
|
|
- warning volume remains bounded.
|
|
|
|
Any shared typed application helper must make these invariants structural while
|
|
leaving domain field merging and ID derivation explicit.
|
|
|
|
## Target D&D Consumers
|
|
|
|
### NPC Registry
|
|
|
|
NPC normalization uses the shared core while preserving its individual-person
|
|
identity semantics, proper-name canonicalization policy, evidence union,
|
|
deterministic NPC ID derivation, warning behavior, retry, and fallback result.
|
|
Its model response uses integer candidate selection rather than copied
|
|
contextual selectors.
|
|
|
|
### Item Registry
|
|
|
|
Item normalization uses the shared core while preserving the distinction
|
|
between item types and unique designations, distinct currency denominations,
|
|
non-inference of item properties or uniqueness, item identity derivation,
|
|
warnings, and fallback behavior.
|
|
|
|
### Location Registry
|
|
|
|
Location normalization uses the shared core while preserving its
|
|
physical-place identity semantics, treatment of parent and child places and
|
|
same-name places, source-reference-dependent durable IDs, warnings, and
|
|
fallback behavior.
|
|
|
|
The migrations must retain the existing durable artifact schemas and public
|
|
module keys. Prompt, schema, policy, and implementation fingerprint changes
|
|
must invalidate only the affected normalization checkpoints through the normal
|
|
checkpoint identity mechanism.
|
|
|
|
The target tree contains no superseded D&D-specific selector-copy response
|
|
schema, shared reconciliation implementation, or obsolete prompt assets. It
|
|
does not retain compatibility shims for the private pre-release LLM response
|
|
contract.
|
|
|
|
## Verification Strategy
|
|
|
|
Tests should protect the reconciliation contract and realistic failure modes,
|
|
not private helper structure or exact prompt length.
|
|
|
|
The shared core warrants focused behavioral coverage for:
|
|
|
|
- contiguous ID assignment after eligibility filtering;
|
|
- absence of durable IDs from model inputs and absence of evidence ranges from
|
|
model outputs;
|
|
- exact ID resolution and rejection of zero, negative, unknown, repeated, and
|
|
overlapping IDs;
|
|
- canonical membership and minimum group size;
|
|
- deterministic group and output ordering regardless of response order;
|
|
- preservation of ungrouped candidates and complete provenance;
|
|
- ownership and defensive-copy guarantees;
|
|
- cancellation, invalid structured output, retry, and fallback behavior;
|
|
- candidate and context bounds; and
|
|
- offline prompt/schema registration and structured response decoding.
|
|
|
|
Use table-driven or property-oriented tests where they efficiently protect
|
|
group-partition and preservation invariants. Fuzzing is appropriate for the
|
|
pure proposal assessor if it remains fast and deterministic. Do not add tests
|
|
that merely freeze prompt text, message counts, asset hashes, private constant
|
|
values, or implementation call choreography.
|
|
|
|
Each migrated D&D normalizer retains focused tests for its domain identity,
|
|
consolidation, warnings, durable IDs, and fallback behavior. A small number of
|
|
integration tests should prove that production registration supplies the
|
|
shared schema and selected prompt policy. Live-model evaluation remains a
|
|
human review tool and is not part of the default offline test suite.
|
|
|
|
## Architectural Decisions And Documentation
|
|
|
|
The target documentation set includes an accepted ADR applying
|
|
[ADR-0012](../adr/0012-resolve-opaque-entity-identifiers-deterministically.md)
|
|
to semantic reconciliation. That decision records:
|
|
|
|
- request-local ordinal candidate handles as the standard reconciliation
|
|
selection mechanism;
|
|
- why requiring the model to reproduce contextual selectors is unnecessary
|
|
and error-prone;
|
|
- the mandatory shared protocol plus generic or domain semantic-policy
|
|
composition;
|
|
- LLM proposal versus deterministic application ownership;
|
|
- the typed adapter boundary; and
|
|
- rejected alternatives, including durable IDs, name-only selection,
|
|
model-synthesized replacement records, and arbitrary untyped normalization.
|
|
|
|
ADR-0012's accepted decision text remains unchanged. The new ADR cites it and
|
|
provides the concrete justification it requires for request-local labels.
|
|
|
|
In the target state, architecture and internal documentation:
|
|
|
|
- distinguish artifact families from configured stage modules;
|
|
- identify the shared reconciliation core and its dependency direction;
|
|
- document the generic prompt protocol and domain semantic-policy ownership;
|
|
- document the integer candidate protocol and deterministic safety boundary;
|
|
- describe the three migrated registry normalizers accurately; and
|
|
- remove descriptions of contextual-selector response copying.
|
|
|
|
Until then, this roadmap remains the canonical description of the proposed
|
|
behavior; current-behavior documents must not describe it as implemented.
|
|
|
|
## Non-Goals
|
|
|
|
This work does not include:
|
|
|
|
- a new pipeline stage or a compound module that combines extraction and
|
|
normalization;
|
|
- a universal configured normalizer for arbitrary artifact kinds or untyped
|
|
JSON;
|
|
- a physical reorganization of every D&D package around artifact-family
|
|
directories;
|
|
- operator-configurable arbitrary prompt assets or replacement of core safety
|
|
instructions;
|
|
- naive batching, cross-batch clustering, or unbounded reconciliation inputs;
|
|
- semantic deduplication of event artifacts whose identity dimensions are
|
|
already handled deterministically;
|
|
- alternate non-source context providers;
|
|
- changes to durable D&D artifact schemas or public module keys; or
|
|
- live provider calls in the default test suite.
|
|
|
|
## Completion Criteria
|
|
|
|
The feature is complete when:
|
|
|
|
- one domain-neutral core owns candidate IDs, source context, prompt execution,
|
|
response assessment, retry classification, and common safe application
|
|
mechanics;
|
|
- the private response schema uses only integer candidate handles for member
|
|
and canonical selection;
|
|
- the generic safety protocol and conservative semantic default exist as
|
|
shared assets;
|
|
- domain adapters can explicitly select the generic semantic default or a
|
|
domain-owned semantic fragment without replacing core safety behavior;
|
|
- NPC, item, and location registry normalizers use the shared core and retain
|
|
their typed domain behavior and durable contracts;
|
|
- the model is not required to reproduce names, evidence ranges, durable IDs,
|
|
or replacement records in reconciliation output;
|
|
- invalid proposals cannot partially mutate or partially collapse an artifact;
|
|
- oversized inputs preserve deterministic results rather than being naively
|
|
divided;
|
|
- the superseded D&D-specific response and reconciliation path is removed;
|
|
- the new ADR and current-behavior documentation accurately reflect the
|
|
implemented boundary; and
|
|
- focused package tests and the repository-wide Go test and vet suites pass.
|