Ground NPC occurrences by canonical names
This commit is contained in:
350
docs/roadmap/contextual-entity-grounding.md
Normal file
350
docs/roadmap/contextual-entity-grounding.md
Normal file
@@ -0,0 +1,350 @@
|
||||
# Contextual Entity Grounding
|
||||
|
||||
## Purpose
|
||||
|
||||
Notarius should use an LLM for semantic interpretation of source evidence, not
|
||||
for referential-integrity work that deterministic code can perform more
|
||||
reliably. D&D prompts must therefore stop requiring models to reproduce opaque
|
||||
machine identifiers such as hash-derived entity IDs. Models should identify
|
||||
entities through human-readable, evidence-grounded context, after which
|
||||
Notarius resolves the selection and attaches the canonical durable identity.
|
||||
|
||||
This roadmap defines the policy, affected D&D prompt families, and intended
|
||||
end state. The ordered work needed to reach that state is maintained in
|
||||
[Implementation Plan](implementation.md).
|
||||
|
||||
## User Intent
|
||||
|
||||
The change has two goals:
|
||||
|
||||
- prevent otherwise useful model responses from failing because a long,
|
||||
non-semantic string was copied incorrectly; and
|
||||
- avoid spending prompt space and model effort on exact-copy work that provides
|
||||
no semantic value.
|
||||
|
||||
The policy is not a ban on identifiers. Durable artifacts may continue to use
|
||||
application-owned IDs, and prompts may continue to request source-unit ranges
|
||||
that locate evidence. The policy governs which identity work is assigned to
|
||||
the model.
|
||||
|
||||
## Policy
|
||||
|
||||
An LLM-facing prompt input or private response schema must not require a model
|
||||
to reproduce an opaque machine identifier when Notarius can establish the same
|
||||
association deterministically.
|
||||
|
||||
Opaque machine identifiers include cryptographic hashes, UUIDs, digests,
|
||||
database keys, durable entity IDs, and other tokens whose characters do not
|
||||
carry source-grounded meaning for the model. These values may remain in
|
||||
application state, provenance, diagnostics, checkpoints, and durable artifact
|
||||
contracts, but should be omitted from model-visible material when they do not
|
||||
help the model make a semantic decision.
|
||||
|
||||
The intended responsibility boundary is:
|
||||
|
||||
- the model decides which contextual entity is supported by the supplied
|
||||
evidence and returns the bounded semantic facts requested by the module;
|
||||
- the calling module validates that the contextual selection resolves to
|
||||
exactly one supplied candidate;
|
||||
- deterministic code supplies the canonical display value and durable entity
|
||||
ID; and
|
||||
- existing validators continue to enforce referential integrity at later
|
||||
artifact boundaries.
|
||||
|
||||
Transcript `start_unit_id` and `end_unit_id` values are permitted. They are
|
||||
contextual source coordinates and form part of the evidence contract rather
|
||||
than arbitrary identity tokens. Prompt IDs, schema IDs, fingerprints, session
|
||||
IDs, and digests may also remain in runtime metadata that the model is not
|
||||
asked to reproduce.
|
||||
|
||||
Short request-local labels are a narrowly permitted fallback only when a
|
||||
contextual selector cannot uniquely represent the available choices without
|
||||
unreasonable prompt cost. Such a label must be compact, scoped to one request,
|
||||
validated against the supplied candidate set, and never reused as a durable
|
||||
identity. Current D&D occurrence and reconciliation prompts should be designed
|
||||
without this exception; adopting it later requires a concrete demonstrated
|
||||
need and documented rationale.
|
||||
|
||||
## Current State
|
||||
|
||||
The initial NPC, item, and location registry extractors already follow the
|
||||
desired pattern: the model returns contextual names and evidence, and Notarius
|
||||
derives durable IDs afterward. Spells, combat turns, and enemy events use
|
||||
contextual actor names rather than requiring hash-derived NPC IDs.
|
||||
|
||||
Two current prompt families diverge from that pattern:
|
||||
|
||||
1. `dnd/npc-occurrences`, `dnd/item-occurrences`, and
|
||||
`dnd/location-occurrences` place durable registry IDs in model-visible
|
||||
projections and require the private LLM response to repeat those IDs.
|
||||
2. NPC-, item-, and location-registry normalization use the shared entity
|
||||
reconciliation prompt, which labels candidates with opaque
|
||||
`candidate-000001`-style keys and requires the model to copy those keys into
|
||||
duplicate-group proposals.
|
||||
|
||||
The durable occurrence artifacts correctly retain canonical entity IDs. The
|
||||
problem is the private model transport contract, not the published artifact
|
||||
contract.
|
||||
|
||||
## Target Architecture
|
||||
|
||||
### Model proposals and durable artifacts
|
||||
|
||||
Private LLM response types must express contextual semantic proposals rather
|
||||
than reuse the durable artifact type when that type contains an opaque entity
|
||||
ID. The extractor maps a validated private response into the existing durable
|
||||
artifact only after identity resolution succeeds.
|
||||
|
||||
No affected durable artifact kind, media type, schema ID, schema version, or
|
||||
JSON field changes as part of this work. NPC, item, and location occurrence
|
||||
artifacts continue to publish their exact canonical ID/name pair. Registry
|
||||
artifacts likewise retain their IDs and evidence.
|
||||
|
||||
The private schemas and prompt declarations may remain at their current `v1`
|
||||
identities because Notarius is pre-release and these are not external
|
||||
contracts. Their content hashes, mapping-policy fingerprints, and affected
|
||||
prompt fingerprints must change so incompatible checkpoints are not reused.
|
||||
|
||||
### NPC occurrence grounding
|
||||
|
||||
The NPC occurrence prompt receives an ordered names-only projection of the
|
||||
normalized NPC registry. Its private response contains the canonical NPC name,
|
||||
occurrence kind, and current-transcript source ranges, but no `npc_id`.
|
||||
|
||||
The extractor resolves the returned name under the existing NPC comparison
|
||||
policy. Resolution must produce exactly one registry entry. It then writes that
|
||||
entry's canonical display name and durable ID into the `dnd.NPCOccurrence`.
|
||||
An unknown or ambiguous selection invalidates the extraction operation; the
|
||||
extractor must not guess, use fuzzy matching, silently omit the record, or
|
||||
accept a partial response.
|
||||
|
||||
### Item occurrence grounding
|
||||
|
||||
The item occurrence prompt receives an ordered names-only projection of the
|
||||
normalized item registry. Its private response contains the canonical item
|
||||
name, occurrence kind, kind-specific fields, and current-transcript source
|
||||
ranges, but no `item_id`.
|
||||
|
||||
The extractor resolves the returned name under the existing item comparison
|
||||
and identity policies. Resolution must produce exactly one registry entry,
|
||||
whose canonical name and durable ID are attached deterministically. Unknown or
|
||||
ambiguous selections invalidate the complete extraction operation rather than
|
||||
being guessed, repaired by similarity, or dropped.
|
||||
|
||||
### Location occurrence grounding
|
||||
|
||||
Location identity cannot always be resolved from a display name alone: the
|
||||
current registry intentionally permits same-name locations with distinct
|
||||
source anchors. The location occurrence prompt must therefore receive a
|
||||
contextual registry descriptor that contains the canonical display name plus
|
||||
the minimum source-grounded registry evidence needed to distinguish same-name
|
||||
records. It must not contain the durable `location:sha256:...` value.
|
||||
|
||||
The private response uses two required selector fields: `name` and
|
||||
`registry_refs`. For a comparison-unique canonical name, `registry_refs` is an
|
||||
empty array and Notarius resolves the name under the location comparison
|
||||
policy. For a name shared by multiple registry records, `registry_refs`
|
||||
contains that record's complete canonically ordered registry ranges as
|
||||
`start_unit_id` and `end_unit_id` pairs, without `source_id`.
|
||||
|
||||
Every model-facing registry entry uses one fixed shape with required `name`,
|
||||
`registry_refs`, and `context` fields. `context` is an array of strict objects
|
||||
containing only `unit_id` and `text`. Comparison-unique entries use empty
|
||||
`registry_refs` and `context` arrays. Same-name entries use the complete
|
||||
registry-range selector and the bounded context described below. The model
|
||||
returns only `name` and `registry_refs`; it does not reproduce `context`.
|
||||
|
||||
For same-name groups, the projection also supplies bounded transcript units
|
||||
covered by each record's registry ranges so the model receives meaningful
|
||||
identity context rather than coordinates alone. Those ranges must resolve
|
||||
against the current source document, and the resulting contextual selectors
|
||||
must be unique. An invalid range or selector collision prevents the LLM call
|
||||
and fails the operation. Unique-name entries do not repeat registry ranges or
|
||||
context in the selector, preserving compatibility with a valid registry from
|
||||
another source when the name alone is unambiguous.
|
||||
|
||||
The private response separately supplies current-transcript `source_refs` that
|
||||
prove the occurrence. Registry identity evidence and occurrence evidence must
|
||||
remain different fields and must never be merged. The model should omit an
|
||||
occurrence when the transcript does not support choosing among same-name
|
||||
locations. If a returned selector does not resolve to exactly one supplied
|
||||
registry record, the extractor invalidates the complete operation rather than
|
||||
guessing.
|
||||
|
||||
### Registry reconciliation
|
||||
|
||||
The shared entity-reconciliation input replaces opaque candidate keys with
|
||||
contextual candidate descriptors. At minimum, a descriptor contains the
|
||||
candidate's display name and its canonically ordered source-reference ranges;
|
||||
the existing transcript windows remain available for semantic judgment.
|
||||
|
||||
Duplicate-group members and the canonical member in the private response use
|
||||
the same contextual descriptor shape. The shared reconciliation helper maps
|
||||
each descriptor back to exactly one internal candidate before assessing the
|
||||
proposal. Exact deterministic duplicates should already be removed before the
|
||||
LLM call; any remaining descriptor collision makes the affected candidate
|
||||
ineligible for model-assisted reconciliation rather than authorizing an
|
||||
arbitrary choice.
|
||||
|
||||
Existing safety behavior remains in force: groups must contain at least two
|
||||
supplied candidates, the canonical candidate must be a member, groups must not
|
||||
overlap, and domain-specific eligibility rules remain authoritative. Invalid,
|
||||
ambiguous, or unsafe groups are discarded through the existing bounded
|
||||
fallback and diagnostic behavior. The model never directly mutates the
|
||||
durable registry.
|
||||
|
||||
The shared private reconciliation schema and helper must remain domain-neutral
|
||||
within the D&D family. NPC-, item-, and location-specific duplicate policy
|
||||
continues to live in the owning normalizer.
|
||||
|
||||
## Prompt And Asset Changes
|
||||
|
||||
The following LLM-facing assets are in scope:
|
||||
|
||||
- the prompt instructions, registry input fragments, and private response
|
||||
schemas for NPC, item, and location occurrences;
|
||||
- the prompt manifests where input shape or selected fragments change;
|
||||
- the shared D&D entity-reconciliation fragment and private response schema;
|
||||
and
|
||||
- the NPC-, item-, and location-registry normalization prompt inputs that use
|
||||
the shared reconciliation contract.
|
||||
|
||||
Affected projections must exclude durable entity IDs rather than merely stop
|
||||
mentioning them in prose. Prompt instructions should describe the contextual
|
||||
selection rule once at the narrowest owning asset and must preserve the current
|
||||
distinction between registry grounding and transcript evidence.
|
||||
|
||||
Prompt ordering and cache controls should remain unchanged unless the new
|
||||
contextual input requires an intentional manifest change. Unrelated shared
|
||||
prompt bytes should not be edited. Prompt and schema fingerprints should
|
||||
invalidate only the operations whose selected assets or mapping semantics
|
||||
changed.
|
||||
|
||||
## Code And Validation Changes
|
||||
|
||||
The occurrence extractors need private response types and deterministic
|
||||
registry-resolution paths appropriate to their domain. Shared code is
|
||||
appropriate only for demonstrated mechanics that have identical semantics;
|
||||
NPC, item, and location ambiguity policies must not be forced behind a generic
|
||||
resolver merely to reduce line count.
|
||||
|
||||
Registry projections should expose explicit model-facing methods whose names
|
||||
describe whether they are names-only or contextual identity projections. The
|
||||
existing ID/name projections may remain only for deterministic consumers that
|
||||
genuinely require them; they must no longer be wired to an LLM input.
|
||||
|
||||
Mapping-policy and normalization-policy identifiers must be reviewed and
|
||||
advanced wherever their semantics change. Checkpoint fingerprints must cover
|
||||
the new projection content, private schema, prompt assets, and mapping policy,
|
||||
while continuing to exclude irrelevant internal implementation details.
|
||||
|
||||
Durable occurrence normalizers and registry validators remain defense in
|
||||
depth. They continue to validate exact ID/name pairs on artifacts entering
|
||||
through checkpoints, codecs, or other boundaries even though the LLM no longer
|
||||
produces the ID directly.
|
||||
|
||||
## Testing And Evaluation
|
||||
|
||||
Tests should protect the behavioral boundary rather than prompt prose or
|
||||
private helper structure. The completed work should demonstrate that:
|
||||
|
||||
- affected model-facing registry projections do not contain durable entity
|
||||
IDs;
|
||||
- private occurrence schemas reject opaque ID fields and accept the intended
|
||||
contextual shape;
|
||||
- valid contextual selections map to the exact canonical durable ID/name pair;
|
||||
- unknown, mismatched, and ambiguous selections fail without fuzzy matching,
|
||||
partial acceptance, or arbitrary reassignment;
|
||||
- same-name locations remain distinguishable through contextual evidence;
|
||||
- reconciliation preserves equal-name candidates, resolves valid contextual
|
||||
groups, and discards ambiguous or unsafe proposals;
|
||||
- registry evidence never becomes occurrence evidence;
|
||||
- durable codec, normalization, and validator behavior remains compatible; and
|
||||
- representative assembled D&D pipelines still prepare and execute with fake
|
||||
structured-LLM responses.
|
||||
|
||||
Do not add repository-wide prompt-prose snapshots, exact-message-count tests,
|
||||
or a change-detector test that merely scans for today's field names. Focused
|
||||
projection, schema, mapping, fallback, and integration tests are the stable
|
||||
owners of these risks. Model-quality evaluation with representative
|
||||
transcripts remains a manual development aid rather than an offline test gate.
|
||||
|
||||
## Documentation And Architectural Record
|
||||
|
||||
This policy is durable and applies to future modules, so it warrants
|
||||
`docs/adr/0012-resolve-opaque-entity-identifiers-deterministically.md`, which
|
||||
records:
|
||||
|
||||
- the semantic-proposal versus referential-integrity boundary;
|
||||
- why durable opaque IDs are excluded from model response contracts;
|
||||
- why contextual evidence coordinates remain permitted;
|
||||
- the narrowly scoped request-local-label exception;
|
||||
- alternatives including durable IDs, names-only matching, and short opaque
|
||||
handles; and
|
||||
- the consequences for private schemas, deterministic resolution, debugging,
|
||||
and ambiguous identities.
|
||||
|
||||
`docs/policy/architecture.md` states the general LLM boundary invariant and
|
||||
links to the ADR. `docs/internal/dnd.md` describes the concrete occurrence
|
||||
projections, contextual reconciliation selectors, resolution and failure
|
||||
behavior, and the continued separation of registry grounding from occurrence
|
||||
evidence. `docs/internal/llm.md` contains only a short clarification that
|
||||
caller-owned modules, not PromptKit or the transport adapter, resolve
|
||||
contextual model selections into application identities.
|
||||
|
||||
The NPC, item, and location occurrence and registry integration documents must
|
||||
continue to own their durable wire contracts, while removing current claims
|
||||
that the model-facing consumer projection contains `{id,name}` or that the raw
|
||||
LLM response supplies the durable ID. They should instead explain that
|
||||
Notarius resolves contextual model output and publishes the same exact durable
|
||||
ID/name pair. No public schema examples need to remove those IDs.
|
||||
|
||||
The generic LLM-assisted deduplication entry in `docs/roadmap/future.md` must be
|
||||
reconciled with this policy: stable IDs may exist inside deterministic state,
|
||||
but a future model-facing proposal should use contextual selectors or a
|
||||
documented request-local-label exception rather than durable IDs.
|
||||
|
||||
## Compatibility And Operational Effects
|
||||
|
||||
This work intentionally changes private prompt inputs, private structured
|
||||
responses, and mapping semantics. It will invalidate affected checkpoints
|
||||
through existing prompt, schema, projection, and policy fingerprints. No
|
||||
manual checkpoint migration is required.
|
||||
|
||||
Durable D&D artifacts and generated-reference compatibility remain unchanged.
|
||||
Operators do not receive new configuration fields or CLI controls. The feature
|
||||
does not change PromptKit, provider routing, profile selection, retries,
|
||||
concurrency, or public output placement.
|
||||
|
||||
## Non-Goals
|
||||
|
||||
This work does not:
|
||||
|
||||
- remove canonical IDs from durable registries or occurrence artifacts;
|
||||
- change occurrence categories, evidence rules, or registry identity policy;
|
||||
- add fuzzy, probabilistic, or embedding-based entity resolution;
|
||||
- allow registry provenance to substitute for occurrence evidence;
|
||||
- introduce a general entity graph or cross-artifact identity framework;
|
||||
- redesign unrelated D&D prompts or their schemas;
|
||||
- implement the future generic deduplication normalizer; or
|
||||
- add provider-specific prompt behavior.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
The target state is complete when:
|
||||
|
||||
- no maintained D&D prompt requires a model to reproduce a durable opaque
|
||||
entity ID;
|
||||
- current D&D reconciliation prompts no longer require opaque candidate keys;
|
||||
- NPC, item, and location occurrence LLM outputs are resolved
|
||||
deterministically into their unchanged durable artifacts;
|
||||
- same-name location and reconciliation cases remain safe and unambiguous;
|
||||
- invalid contextual selections preserve the existing extraction-failure or
|
||||
normalization-fallback semantics appropriate to their stage;
|
||||
- affected checkpoint identities change without altering public schema
|
||||
versions;
|
||||
- focused and repository-wide tests pass offline;
|
||||
- the ADR, architecture invariant, D&D internal guide, LLM internal guide,
|
||||
relevant integration contracts, and future roadmap accurately describe
|
||||
their canonical portions of the implemented policy; and
|
||||
- no unrelated code, prompt behavior, or public contract changes are included.
|
||||
609
docs/roadmap/implementation.md
Normal file
609
docs/roadmap/implementation.md
Normal file
@@ -0,0 +1,609 @@
|
||||
# Contextual Entity Grounding Implementation Plan
|
||||
|
||||
## Objective
|
||||
|
||||
Implement [Contextual Entity Grounding](contextual-entity-grounding.md) so D&D
|
||||
LLM prompts return evidence-grounded contextual selectors while Notarius owns
|
||||
canonical entity IDs and referential integrity. Preserve every durable D&D
|
||||
artifact contract and remove opaque IDs only from model-visible inputs and
|
||||
private model responses.
|
||||
|
||||
This plan is written for a gpt-5.6-terra coding agent. Implement the stages in
|
||||
numeric order. Each stage is intentionally scoped to one implementation prompt
|
||||
and must leave the repository buildable and its focused tests passing before
|
||||
the next stage begins.
|
||||
|
||||
## Plan-Wide Decisions
|
||||
|
||||
Apply these decisions throughout every stage:
|
||||
|
||||
- Read `docs/development.md`, all files under `docs/policy/`, the feature
|
||||
roadmap, and the focused implementation/tests named by the stage before
|
||||
editing.
|
||||
- Preserve the fixed pipeline, typed artifact boundaries, root `assets`
|
||||
content-only rule, module ownership, PromptKit boundary, and evidence rules.
|
||||
- Do not change the durable NPC-, item-, location-registry, or occurrence Go
|
||||
types, JSON schemas, schema IDs, schema versions, media types, reference-slot
|
||||
contracts, categories, or generated-reference compatibility.
|
||||
- Keep the affected prompt and private response-schema identities at `v1`.
|
||||
They are private pre-release transport contracts; their changed content
|
||||
hashes provide the required compatibility boundary.
|
||||
- Advance semantic policy identifiers exactly as directed in each stage. Do
|
||||
not bump unrelated policy identifiers.
|
||||
- A contextual name match uses the entity family's existing comparison policy,
|
||||
never fuzzy matching. A model selection must resolve to exactly one supplied
|
||||
record before a durable ID is attached.
|
||||
- An invalid NPC, item, or location selection invalidates the complete
|
||||
extraction operation. Do not silently drop one response record, accept a
|
||||
partial artifact, or defer a known mapping failure to a later validator.
|
||||
- Registry provenance remains grounding only. Only the current extraction
|
||||
chunk's `source_refs` become occurrence evidence.
|
||||
- Preserve prompt message order and cache controls unless a stage explicitly
|
||||
directs otherwise. Edit only the selected module or shared assets; do not
|
||||
rewrite unrelated shared prompt bytes.
|
||||
- Preserve internal opaque IDs where deterministic code needs them. The rule
|
||||
applies to material shown to the model or requested from it, not to maps,
|
||||
fingerprints, checkpoints, diagnostics, or durable artifacts.
|
||||
- Follow `docs/policy/testing.md`: test package-level behavior and meaningful
|
||||
failure modes, not prompt prose, exact message counts, private helper
|
||||
structure, or a repository-wide string-scanning change detector. All tests
|
||||
remain deterministic, offline, and credential-free.
|
||||
- Use `apply_patch` for edits, `gofmt` changed Go files, and preserve unrelated
|
||||
worktree changes.
|
||||
|
||||
## Final Private Selector Contracts
|
||||
|
||||
These shapes are implementation requirements, not public artifact schemas.
|
||||
|
||||
### NPC occurrence response
|
||||
|
||||
Each response record contains exactly the required fields `name`, `kind`, and
|
||||
`source_refs`. It does not contain `npc_id`. Notarius resolves `name` through
|
||||
the normalized NPC registry and writes the matched registry record's `ID` and
|
||||
canonical `Name` into the durable occurrence.
|
||||
|
||||
### Item occurrence response
|
||||
|
||||
Each response record contains the existing required `name`, `kind`,
|
||||
`quantity`, `from`, `to`, and `source_refs` fields. It does not contain
|
||||
`item_id`. Retain the current nullable representation and kind-specific
|
||||
semantics. Notarius resolves `name` through the normalized item registry and
|
||||
adds the matched `ID` and canonical `Name`.
|
||||
|
||||
### Location occurrence response
|
||||
|
||||
Each response record contains exactly the required fields `name`,
|
||||
`registry_refs`, `kind`, and `source_refs`. `registry_refs` is always an array
|
||||
of strict objects containing required integer `start_unit_id` and
|
||||
`end_unit_id`; it may be empty.
|
||||
|
||||
- When `name` has one comparison-identity match in the supplied registry,
|
||||
`registry_refs` must be empty and name resolution selects that record.
|
||||
- When multiple registry records share the comparison identity,
|
||||
`registry_refs` must equal one record's complete canonically ordered source
|
||||
ranges with `source_id` removed.
|
||||
- The model-facing registry projection uses the same `name` plus
|
||||
`registry_refs` selector and adds a required `context` array. Unique-name
|
||||
records project empty `registry_refs` and `context` arrays. The private
|
||||
response does not reproduce `context`.
|
||||
- Same-name records receive bounded identity context consisting of the ordered
|
||||
source units covered by their registry ranges. Each context element is a
|
||||
strict object with exactly the required fields `unit_id` (integer) and
|
||||
`text` (string); do not expose the durable location ID, source ID, digest,
|
||||
or a replacement token.
|
||||
- Building same-name grounding validates that every registry range belongs to
|
||||
and resolves against the current source. If two records still produce the
|
||||
same contextual selector, grounding construction fails before the LLM call.
|
||||
- `registry_refs` never flow into the durable occurrence's `source_refs`.
|
||||
|
||||
### Entity-reconciliation response
|
||||
|
||||
The shared response remains an object with required `duplicate_groups`.
|
||||
Every group has required `members` and `canonical`. A member and the canonical
|
||||
selection are strict contextual objects containing:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "Mira Thorn",
|
||||
"source_refs": [
|
||||
{"start_unit_id": 12, "end_unit_id": 12}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
The candidate prompt input uses the same descriptor and contains no `key`.
|
||||
`source_refs` is required and non-empty for every eligible candidate. The
|
||||
shared helper may retain its existing `candidate-000001`-style keys strictly
|
||||
inside Go state to preserve input-position mapping; those keys must never be
|
||||
serialized into prompt input or accepted in the private response.
|
||||
|
||||
If two candidates produce an identical contextual descriptor, neither is
|
||||
eligible for model-assisted reconciliation because the model cannot identify
|
||||
them independently. Otherwise the helper converts returned descriptors to its
|
||||
internal candidate keys before applying all existing unknown-member,
|
||||
ineligible-member, duplicate-member, canonical-membership, overlap, retry, and
|
||||
fallback rules.
|
||||
|
||||
## Stage 1: Convert NPC Occurrences To Name-Based Resolution
|
||||
|
||||
### Goal
|
||||
|
||||
Remove durable NPC IDs from the NPC-occurrence prompt and private response,
|
||||
then resolve the model's contextual name deterministically without weakening
|
||||
checkpoint identity or downstream validation.
|
||||
|
||||
### Work
|
||||
|
||||
1. Inspect:
|
||||
- `assets/dnd/npc-occurrences/`;
|
||||
- `internal/modules/dnd/extract/npcoccurrences/`;
|
||||
- `internal/modules/dnd/npcs/registry/`;
|
||||
- NPC-occurrence normalizer and validator checkpoint fingerprints; and
|
||||
- their focused tests.
|
||||
2. Change `dnd_npc_occurrences_llm.v1.json` so every occurrence requires only
|
||||
`name`, `kind`, and `source_refs`, continues to reject unknown fields, and
|
||||
no longer declares `npc_id`.
|
||||
3. Revise the NPC-occurrence instructions to require a supplied canonical NPC
|
||||
name and current-chunk evidence, with no instruction to copy or invent an
|
||||
ID. Continue using the existing shared names-only NPC registry fragment and
|
||||
preserve manifest order/cache controls.
|
||||
4. Remove `NPCID` from the private `occurrenceResponse`. After canonicalizing
|
||||
response evidence, resolve every response name with the existing
|
||||
`npcregistry.Registry.Lookup` comparison-key lookup. On the first unknown
|
||||
or non-unique selection, return an extractor-scoped mapping error and no
|
||||
value. For a match, construct the durable occurrence with the registry
|
||||
record's exact `ID` and canonical `Name`.
|
||||
5. Change `mappingPolicy` to
|
||||
`dnd.npc_occurrences.extract_mapping.v3`.
|
||||
6. Stop passing `IdentityPromptInput()` to the LLM; use the existing
|
||||
names-only `PromptInput()`.
|
||||
7. Replace the misleading exported model-input API used only for identity
|
||||
fingerprints: retain the unexported ordered `{id,name}` projection and its
|
||||
digest, expose that value as `IdentityDigest() string`, remove
|
||||
`IdentityPromptInput()`, and update NPC-occurrence extractor, normalizer,
|
||||
invariant-validator, and registry-validator fingerprints to use
|
||||
`IdentityDigest()`. The digest must still distinguish ID/name identity from
|
||||
the names-only prompt projection.
|
||||
8. Rewrite existing focused tests around observable behavior: rendered NPC
|
||||
registry input is names-only; the private schema rejects `npc_id`; valid
|
||||
names acquire the registry ID; comparison-equivalent names canonicalize;
|
||||
unknown names fail the whole extraction; registry identity fingerprints
|
||||
remain distinct and defensive; empty registries accept only empty model
|
||||
results. Remove tests whose only purpose was requiring the model to return
|
||||
exact ID/name pairs.
|
||||
|
||||
### Acceptance Criteria
|
||||
|
||||
- No NPC-occurrence LLM input or private response contains a durable NPC ID.
|
||||
- Durable NPC occurrences still contain the exact registry ID/name pair.
|
||||
- Mapping failures remain extractor failures eligible for the configured
|
||||
pipeline retry behavior.
|
||||
- Deterministic consumers still fingerprint the ordered registry identity,
|
||||
while spells, combat turns, enemy events, and NPC occurrences share the
|
||||
names-only model projection.
|
||||
|
||||
### Validation
|
||||
|
||||
```sh
|
||||
go fmt ./internal/modules/dnd/npcs/registry ./internal/modules/dnd/extract/npcoccurrences ./internal/modules/dnd/normalize/npcoccurrences ./internal/modules/dnd/validate/npcoccurrences/...
|
||||
go test ./internal/modules/dnd/npcs/registry ./internal/modules/dnd/extract/npcoccurrences ./internal/modules/dnd/normalize/npcoccurrences ./internal/modules/dnd/validate/npcoccurrences/...
|
||||
```
|
||||
|
||||
This stage is suitable for one gpt-5.6-terra prompt.
|
||||
|
||||
## Stage 2: Convert Item Occurrences To Name-Based Resolution
|
||||
|
||||
### Goal
|
||||
|
||||
Give item occurrences the same contextual-name/deterministic-ID boundary while
|
||||
preserving item-specific nullable fields and kind rules.
|
||||
|
||||
### Work
|
||||
|
||||
1. Inspect `assets/dnd/item-occurrences/`, the item occurrence extractor, the
|
||||
item registry, the item occurrence normalizer and registry validator, and
|
||||
their focused tests.
|
||||
2. Change `dnd_item_occurrences_llm.v1.json` to remove `item_id` from required
|
||||
fields and properties. Preserve required `name`, `kind`, `quantity`, `from`,
|
||||
`to`, and `source_refs`, all current enums/nullability, and strict unknown
|
||||
field rejection.
|
||||
3. Rewrite the item registry fragment and module instructions to require the
|
||||
supplied canonical name and current-chunk evidence without mentioning an
|
||||
ID. Preserve prompt order and cache controls.
|
||||
4. Change the item registry's model projection from ordered `{id,name}` pairs
|
||||
to ordered names-only objects, add a comparison-key index, and expose a
|
||||
defensive `Lookup(name) (dnd.Item, bool)` analogous to the NPC registry.
|
||||
Retain exact `LookupID` for durable normalizers and validators. Because item
|
||||
IDs are derived from the item comparison identity, the names-only
|
||||
`ProjectionDigest` remains sufficient for model input and existing
|
||||
checkpoint consumers.
|
||||
5. Remove `ItemID` from the private response. During response canonicalization,
|
||||
resolve every contextual name, replace it with the registry record's
|
||||
canonical name, and attach its durable ID when constructing the final
|
||||
`dnd.ItemOccurrence`. Unknown selections fail the complete extraction; do
|
||||
not alter evidence or nullable-field validation ownership.
|
||||
6. Change `mappingPolicy` to
|
||||
`dnd.item_occurrences.extract_mapping.v2`.
|
||||
7. Update focused tests to cover names-only projection, defensive comparison
|
||||
lookup, schema rejection of `item_id`, deterministic durable mapping,
|
||||
unknown-name failure after an otherwise valid record, empty registry/result
|
||||
behavior, and preservation of nullable/kind-specific fields.
|
||||
|
||||
### Acceptance Criteria
|
||||
|
||||
- Model-visible item registry and response content contain no item hash.
|
||||
- Every accepted durable occurrence has the matched registry ID and canonical
|
||||
name.
|
||||
- Invalid selection remains all-or-nothing, and existing normalizer/validator
|
||||
defense in depth remains unchanged.
|
||||
|
||||
### Validation
|
||||
|
||||
```sh
|
||||
go fmt ./internal/modules/dnd/items/registry ./internal/modules/dnd/extract/itemoccurrences
|
||||
go test ./internal/modules/dnd/items/registry ./internal/modules/dnd/extract/itemoccurrences ./internal/modules/dnd/normalize/itemoccurrences ./internal/modules/dnd/validate/itemoccurrences/...
|
||||
```
|
||||
|
||||
This stage is suitable for one gpt-5.6-terra prompt.
|
||||
|
||||
## Stage 3: Add Contextual Location Grounding
|
||||
|
||||
### Goal
|
||||
|
||||
Replace the location registry's ID/name prompt projection with an immutable,
|
||||
source-aware grounding object that can represent same-name locations safely.
|
||||
Introduce the new path alongside the old occurrence input so this stage remains
|
||||
buildable; Stage 4 performs the atomic extractor cutover and removes the old
|
||||
path.
|
||||
|
||||
### Work
|
||||
|
||||
1. Inspect the location registry, location identity and source-reference
|
||||
helpers, the generic source document index, occurrence checkpoint consumers,
|
||||
and their focused tests.
|
||||
2. In `internal/modules/dnd/locations/registry`, define the private-model
|
||||
types needed by both grounding and the location occurrence extractor:
|
||||
- a returned selector with exactly `name` and `registry_refs`;
|
||||
- a registry projection entry with exactly `name`, `registry_refs`, and
|
||||
`context`;
|
||||
- a source-free range with exactly `start_unit_id` and `end_unit_id`; and
|
||||
- a context unit with exactly `unit_id` and `text`.
|
||||
All fields are required in their private JSON shapes, and constructors and
|
||||
accessors must make defensive copies.
|
||||
3. Add an operation-scoped immutable grounding type constructed from a resolved
|
||||
registry and the current `*source.SourceDocument`. Its API must provide:
|
||||
- a cloned `contracts.LLMInputMaterial` for the `location_registry` slot;
|
||||
- deterministic resolution of a returned selector to one cloned
|
||||
`dnd.Location`; and
|
||||
- the digest of the exact model projection.
|
||||
4. Construct the projection in registry order. Group entries by the existing
|
||||
location comparison key:
|
||||
- every projection entry has exactly the required fields `name`,
|
||||
`registry_refs`, and `context`;
|
||||
- comparison-unique entries use empty `registry_refs` and `context` arrays;
|
||||
- every same-name entry uses its complete canonical source ranges stripped
|
||||
of `source_id` and includes ordered context units covered by those ranges;
|
||||
- each context unit contains exactly required integer `unit_id` and string
|
||||
`text` fields, and units are deduplicated in source order; and
|
||||
- same-name ranges must have `SourceID == doc.ID` and pass
|
||||
`source.DocumentIndex.ValidateRef`.
|
||||
5. Fail grounding construction with a bounded, content-safe error if the
|
||||
source is nil, a same-name range is invalid or belongs to another source,
|
||||
a comparison key is empty, or two records produce the same selector. Do not
|
||||
expose transcript text in the error.
|
||||
6. Resolution uses the existing comparison key. A unique-name selector is
|
||||
accepted only with empty `registry_refs`; a same-name selector is accepted
|
||||
only on an exact canonical range match. Reject unknown names, a non-empty
|
||||
range list for a unique name, an empty/partial/reordered range list for an
|
||||
ambiguous name, or any selector not present in the grounding.
|
||||
7. Separate deterministic identity fingerprinting from LLM material. Add
|
||||
`IdentityDigest()` over the registry's ordered `{id,name}` identity
|
||||
projection, and update the location normalizer and registry-validator
|
||||
checkpoint consumers to use it. The new operation grounding owns the model
|
||||
projection digest. Retain the old ID-bearing prompt accessor only as a
|
||||
documented transitional dependency of the still-unchanged location
|
||||
occurrence extractor; do not add new callers.
|
||||
8. Add focused tests for unique names, same-name context and selectors,
|
||||
canonical range order, deterministic projection/digest, defensive copies,
|
||||
exact selector resolution, nil/foreign/invalid references, selector
|
||||
collisions, empty registries, and identity fingerprint stability. Do not
|
||||
assert large rendered prompt strings; decode the JSON projection and assert
|
||||
its semantic shape.
|
||||
|
||||
### Acceptance Criteria
|
||||
|
||||
- The location package can build and resolve contextual selectors without
|
||||
exposing `location_id`, `source_id`, digests, or replacement labels.
|
||||
- Same-name locations remain distinct and receive meaningful bounded context.
|
||||
- Deterministic checkpoint consumers retain an ID-sensitive fingerprint.
|
||||
- Only the existing occurrence extractor remains wired to the legacy
|
||||
ID-bearing prompt path until Stage 4; the repository compiles and tests pass.
|
||||
|
||||
### Validation
|
||||
|
||||
```sh
|
||||
go fmt ./internal/modules/dnd/locations/registry ./internal/modules/dnd/normalize/locationoccurrences ./internal/modules/dnd/validate/locationoccurrences/...
|
||||
go test ./internal/modules/dnd/locations/registry ./internal/modules/dnd/normalize/locationoccurrences ./internal/modules/dnd/validate/locationoccurrences/...
|
||||
```
|
||||
|
||||
This stage is suitable for one gpt-5.6-terra prompt.
|
||||
|
||||
## Stage 4: Convert Location Occurrences To Contextual Resolution
|
||||
|
||||
### Goal
|
||||
|
||||
Wire the Stage 3 grounding object into location occurrence extraction and
|
||||
remove durable location IDs from the prompt and private response.
|
||||
|
||||
### Work
|
||||
|
||||
1. Inspect `assets/dnd/location-occurrences/`, the location occurrence model,
|
||||
schema loader, extractor, canonicalization, prompt tests, and Stage 3
|
||||
grounding tests.
|
||||
2. Change `dnd_location_occurrences_llm.v1.json` so each occurrence requires
|
||||
exactly `name`, `registry_refs`, `kind`, and `source_refs`; remove
|
||||
`location_id`. Keep all four occurrence kinds. Make `registry_refs` a
|
||||
required array, including an empty array, of strict required positive
|
||||
integer ranges. Keep occurrence `source_refs` separate and unchanged.
|
||||
3. Rewrite `location-registry.md` and module instructions to explain the two
|
||||
selector cases, require exact supplied contextual selectors, prohibit
|
||||
invented locations, and state that registry ranges/context are identity
|
||||
grounding rather than occurrence evidence. Preserve manifest order and
|
||||
cache controls.
|
||||
4. Change the private response type to `Name`, `RegistryRefs`, `Kind`, and
|
||||
`SourceRefs`. Do not reuse `source.SourceRef` for the source-free registry
|
||||
range type.
|
||||
5. In `Extract`, construct operation grounding from the resolved registry and
|
||||
`req.Source` before calling the LLM, put its projection in the
|
||||
`location_registry` input, and resolve every returned selector after
|
||||
completion. Attach the selected registry record's exact ID and canonical
|
||||
name to the durable occurrence while retaining only the response's
|
||||
current-source `source_refs` as evidence.
|
||||
6. Fail the whole extraction on grounding-construction failure or the first
|
||||
unknown, malformed, mismatched, or ambiguous selector. This replaces the
|
||||
current behavior that can preserve unknown ID/name pairs for later
|
||||
validators. Keep later normalizer and validator checks as defense in depth
|
||||
for artifacts entering other boundaries.
|
||||
7. Change `mappingPolicy` to
|
||||
`dnd.location_occurrences.extract_mapping.v2`.
|
||||
8. Remove the legacy ID-bearing registry `PromptInput` and its model-projection
|
||||
digest once the extractor uses operation grounding. Update the occurrence
|
||||
checkpoint to combine `IdentityDigest()` with the new grounding projection
|
||||
digest, prompt/schema fingerprint, mapping policy, and its existing inputs;
|
||||
do not retain dead compatibility aliases.
|
||||
9. Update focused schema, prompt, extractor, canonicalization, checkpoint, and
|
||||
generated-reference tests. Cover unique-name empty selectors, successful
|
||||
same-name selection, failure for an unsupported ambiguous mention,
|
||||
partial/reordered ranges, no registry-to-occurrence evidence leakage,
|
||||
all-or-nothing failure, empty registry/result behavior, and unchanged
|
||||
durable ordering/deduplication.
|
||||
|
||||
### Acceptance Criteria
|
||||
|
||||
- The location prompt and private response contain no durable location ID.
|
||||
- Unique and same-name records resolve according to the final selector
|
||||
contract.
|
||||
- Accepted durable output is unchanged in shape and still contains an exact
|
||||
location ID/name pair.
|
||||
- Registry context cannot become durable occurrence evidence.
|
||||
|
||||
### Validation
|
||||
|
||||
```sh
|
||||
go fmt ./internal/modules/dnd/extract/locationoccurrences ./internal/modules/dnd/locations/registry
|
||||
go test ./internal/modules/dnd/locations/registry ./internal/modules/dnd/extract/locationoccurrences ./internal/modules/dnd/normalize/locationoccurrences ./internal/modules/dnd/validate/locationoccurrences/...
|
||||
```
|
||||
|
||||
This stage is suitable for one gpt-5.6-terra prompt.
|
||||
|
||||
## Stage 5: Replace Reconciliation Keys With Contextual Descriptors
|
||||
|
||||
### Goal
|
||||
|
||||
Change the shared NPC/item/location registry-normalization proposal contract so
|
||||
opaque candidate keys remain internal and the model sees and returns only
|
||||
names plus evidence coordinates.
|
||||
|
||||
### Work
|
||||
|
||||
1. Inspect:
|
||||
- `internal/modules/dnd/shared/entityreconcile/`;
|
||||
- `assets/dnd/shared/prompts/common-dnd-entity-reconciliation.md`;
|
||||
- `assets/dnd/entity-reconciliation/schemas/`;
|
||||
- all three registry normalization manifests and prompt tests; and
|
||||
- the NPC, item, and location registry normalizers and reconciliation tests.
|
||||
2. Introduce one exported, defensively copied contextual selector type in
|
||||
`entityreconcile` with JSON `name` and `source_refs`, plus a strict
|
||||
source-free range type. Use it for candidate input views and for
|
||||
`DuplicateGroup.Members` and `.Canonical`.
|
||||
3. Keep deterministic candidate keys only inside `Materials`. During
|
||||
`BuildContext`, validate and canonicalize candidate references as today,
|
||||
serialize candidate views without `key`, derive a stable internal lookup
|
||||
from canonical selector JSON to the corresponding internal candidate key,
|
||||
and detect descriptor collisions before eligibility is established.
|
||||
Colliding candidates must not appear in the prompt input or become
|
||||
eligible; their records remain in deterministic normalization output.
|
||||
4. Update `Materials.Assess` to resolve every returned selector through that
|
||||
internal lookup before running the existing group assessment. Preserve
|
||||
existing issue categories where their meaning still applies. Treat an
|
||||
unknown or collided descriptor as an unknown/ineligible selection, discard
|
||||
only the affected group, and retain existing overlap handling. `SafeGroup`
|
||||
may continue returning internal candidate keys so the three domain
|
||||
normalizers retain their position mapping; those keys are not model-facing.
|
||||
5. Rewrite `dnd_entity_reconcile_llm.v1.json` so members and canonical are
|
||||
strict selector objects. Require non-empty `name` structurally where the
|
||||
current schemas do so, require `source_refs`, and make each range strict
|
||||
with required positive integer endpoints. Preserve `duplicate_groups` and
|
||||
the existing semantic assessment of minimum group size, membership,
|
||||
duplicates, eligibility, and overlap rather than moving every semantic
|
||||
failure into JSON Schema.
|
||||
6. Rewrite the shared reconciliation fragment to tell the model to return
|
||||
supplied contextual descriptors and never invent names or ranges. Remove
|
||||
every instruction about opaque keys. Preserve all three manifests' message
|
||||
ordering and cache controls.
|
||||
7. Change registry normalization policy identifiers to:
|
||||
- `dnd.npc_registry.normalize.v4`;
|
||||
- `dnd.item_registry.normalize.v2`; and
|
||||
- `dnd.location_registry.normalize.v2`.
|
||||
8. Update shared and domain tests to cover candidate JSON without keys,
|
||||
contextual proposal decoding, valid selector-to-internal-key mapping,
|
||||
equal names with different evidence, descriptor collision exclusion,
|
||||
unknown/partial/reordered descriptors, overlapping groups, canonical
|
||||
membership, invalid structured-output fallback, currency safety, and
|
||||
preservation of every non-applied deterministic candidate. Update prompt
|
||||
asset fixtures to the new selector schema; do not snapshot prompt prose.
|
||||
|
||||
### Acceptance Criteria
|
||||
|
||||
- No registry normalization prompt input or private response contains a
|
||||
`candidate-*` key.
|
||||
- Internal keys remain inaccessible to the model but may still support safe
|
||||
deterministic position mapping.
|
||||
- All existing normalizer safety, retry, fallback, warning, currency, and
|
||||
same-name-location policies remain intact.
|
||||
- Identical contextual descriptors cannot be arbitrarily reconciled.
|
||||
|
||||
### Validation
|
||||
|
||||
```sh
|
||||
go fmt ./internal/modules/dnd/shared/entityreconcile ./internal/modules/dnd/normalize/npcregistry ./internal/modules/dnd/normalize/itemregistry ./internal/modules/dnd/normalize/locationregistry
|
||||
go test ./internal/modules/dnd/shared/entityreconcile ./internal/modules/dnd/normalize/npcregistry ./internal/modules/dnd/normalize/itemregistry ./internal/modules/dnd/normalize/locationregistry
|
||||
```
|
||||
|
||||
This is the largest stage, but it is one cohesive shared-contract migration
|
||||
and is suitable for one gpt-5.6-terra prompt when implemented exactly within
|
||||
the listed packages. Do not combine it with occurrence or documentation work.
|
||||
|
||||
## Stage 6: Record The Decision And Update Canonical Documentation
|
||||
|
||||
### Goal
|
||||
|
||||
Document the implemented policy in its durable architectural, internal, and
|
||||
integration homes without duplicating volatile details or presenting roadmap
|
||||
work as current behavior prematurely.
|
||||
|
||||
### Work
|
||||
|
||||
1. Re-read `docs/policy/documentation.md`, ADR-0003, ADR-0009, ADR-0011,
|
||||
`docs/internal/dnd.md`, `docs/internal/llm.md`, and the six affected registry
|
||||
and occurrence integration documents. Verify the code before describing it.
|
||||
2. Add
|
||||
`docs/adr/0012-resolve-opaque-entity-identifiers-deterministically.md` in
|
||||
the repository's Nygard ADR format with status `Accepted` and the actual
|
||||
implementation date. Record the model-semantic/deterministic-identity
|
||||
boundary, source-coordinate allowance, request-local-label exception,
|
||||
alternatives, ambiguity behavior, and consequences. Link ADR-0003 and
|
||||
ADR-0009 rather than repeating their complete decisions.
|
||||
3. Add a concise normative invariant under the LLM boundary in
|
||||
`docs/policy/architecture.md`: callers use contextual model selections and
|
||||
attach opaque application identities deterministically when possible. Link
|
||||
ADR-0012 for rationale.
|
||||
4. Update `docs/internal/dnd.md` to replace exact model-facing `{id,name}`
|
||||
claims with the implemented NPC/item names-only and location contextual
|
||||
selector behavior. Document reconciliation descriptors, internal-only keys,
|
||||
all-or-nothing occurrence mapping failures, normalization fallback, and the
|
||||
separation between registry and occurrence evidence. Do not duplicate the
|
||||
private JSON schemas.
|
||||
5. Add only a short ownership clarification to `docs/internal/llm.md`: the
|
||||
calling module resolves contextual selections; PromptKit and its adapter do
|
||||
not own entity identity.
|
||||
6. Update these durable integration contracts while preserving their public
|
||||
ID-bearing wire examples and schema statements:
|
||||
- `docs/integrations/dnd-npc-registry-artifacts.md`;
|
||||
- `docs/integrations/dnd-npc-occurrence-artifacts.md`;
|
||||
- `docs/integrations/dnd-item-registry-artifacts.md`;
|
||||
- `docs/integrations/dnd-item-occurrence-artifacts.md`;
|
||||
- `docs/integrations/dnd-location-registry-artifacts.md`; and
|
||||
- `docs/integrations/dnd-location-occurrence-artifacts.md`.
|
||||
Remove claims that LLM consumers receive `{id,name}` or that raw model
|
||||
output supplies an ID. State that Notarius maps contextual output into the
|
||||
unchanged exact durable pair.
|
||||
7. Revise the generic LLM-assisted deduplication entry in
|
||||
`docs/roadmap/future.md`: stable unique IDs remain internal deterministic
|
||||
state, while a future model proposal uses contextual descriptors or a
|
||||
specifically justified request-local short label.
|
||||
8. Do not change README, CLI, configuration, operations, examples, or public
|
||||
schema files; this feature has no user-selectable surface or public wire
|
||||
change.
|
||||
|
||||
### Acceptance Criteria
|
||||
|
||||
- ADR-0012 owns rationale; architecture owns the normative boundary; internal
|
||||
docs own mechanics; integration docs own unchanged durable contracts; and
|
||||
the future roadmap no longer proposes durable IDs as the default model
|
||||
selector.
|
||||
- No current-behavior document claims that a model copies hash-based entity
|
||||
IDs or opaque reconciliation keys.
|
||||
- Documentation does not duplicate private schemas or implementation history.
|
||||
|
||||
### Validation
|
||||
|
||||
```sh
|
||||
git diff --check
|
||||
rg -n '\{id,name\}|ID/name grounding|Candidate keys are opaque|candidate-[0-9]' docs assets/dnd
|
||||
```
|
||||
|
||||
Review every search result semantically; durable wire-contract ID/name
|
||||
requirements and internal test fixtures are not automatically errors.
|
||||
|
||||
This stage is suitable for one gpt-5.6-terra prompt.
|
||||
|
||||
## Stage 7: Integration Audit And Final Verification
|
||||
|
||||
### Goal
|
||||
|
||||
Verify the assembled D&D family, remove obsolete identity-copy paths, and
|
||||
finish with a clean, policy-compliant implementation.
|
||||
|
||||
### Work
|
||||
|
||||
1. Audit every maintained D&D prompt manifest, selected fragment, private
|
||||
schema, and constructed prompt projection. Confirm that no model is asked to
|
||||
reproduce `npc:sha256:...`, `item:sha256:...`,
|
||||
`location:sha256:...`, `candidate-*`, a UUID, a digest, or another opaque
|
||||
entity handle. Do not confuse runtime metadata or durable output contracts
|
||||
with model-visible material.
|
||||
2. Trace all former APIs and fields, including `IdentityPromptInput`,
|
||||
ID-bearing item/location prompt projections, private `NPCID`/`ItemID`/
|
||||
`LocationID` response fields, and model-visible candidate keys. Remove dead
|
||||
code, obsolete comments, stale test names, and unused assets. Retain
|
||||
identity-only digests and exact durable lookup APIs used by deterministic
|
||||
consumers.
|
||||
3. Review prompt fingerprint registration and checkpoint fingerprints. Confirm
|
||||
that each affected prompt/schema/policy/projection change invalidates the
|
||||
relevant operation and that unrelated D&D lanes retain their existing
|
||||
fingerprints.
|
||||
4. Run representative production registration and multi-step pipeline tests
|
||||
using existing fakes. Update only tests whose stable behavior changed.
|
||||
Confirm generated NPC/item/location registry handoffs still prepare and
|
||||
that final durable occurrences encode and validate under their existing
|
||||
`v1` codecs.
|
||||
5. Run formatting, focused suites, full tests, vet, build, and documentation
|
||||
whitespace checks. Fix only failures caused by this feature. Report any
|
||||
unrelated pre-existing failure without broadening scope.
|
||||
6. Review the feature roadmap acceptance criteria one by one. Do not delete
|
||||
`contextual-entity-grounding.md` or this implementation plan in this stage;
|
||||
roadmap retirement is a separate maintainer action after review.
|
||||
|
||||
### Acceptance Criteria
|
||||
|
||||
- All feature-roadmap acceptance criteria are met.
|
||||
- The repository contains no obsolete model-facing opaque-identity path.
|
||||
- Public artifacts and generated handoffs remain compatible.
|
||||
- Tests are focused on behavior rather than prose or implementation shape.
|
||||
- The worktree contains only intentional feature and documentation changes.
|
||||
|
||||
### Validation
|
||||
|
||||
```sh
|
||||
go fmt ./internal/modules/dnd/...
|
||||
go test ./internal/modules/dnd/...
|
||||
go test ./internal/modules/integration/...
|
||||
go test ./...
|
||||
go vet ./...
|
||||
go build ./cmd/notarius
|
||||
git diff --check
|
||||
git status --short
|
||||
```
|
||||
|
||||
This stage is suitable for one gpt-5.6-terra prompt.
|
||||
Reference in New Issue
Block a user