Files
notarius/docs/roadmap/implementation.md

21 KiB

D&D Location Tracking Implementation Plan

Objective

Complete the target state in D&D Location Tracking by correcting the behavioral and maintainability issues found in the post-implementation audit. The location registry and occurrence lanes are already implemented and production-selectable; the remaining work restores one NPC normalization contract, aligns location-occurrence classification with the roadmap, narrows a module's declared references, and factors demonstrated registry-resolution mechanics into a D&D-shared helper.

This is an ordered implementation plan for a gpt-5.6-terra coding agent. Stages 1 through 14 are complete and must not be reimplemented. Implement one new stage per prompt, beginning with Stage 15, and complete each stage's focused validation before proceeding.

All remaining stages must follow:

Use behavior-level tests. Do not add tests that freeze exact prompt wording, message counts, source layout, shared-prefix length, or other incidental implementation details. Prompts and canonical documentation must agree, but that agreement is a review responsibility rather than a reason to add a change-detector test.

Completed Work Summary

Stages 1 through 14 delivered the following production state:

Completed stage Result
Stage 1 Added location and location-occurrence domain types plus evidence-anchored location identity.
Stage 2 Added strict v1 durable codecs and JSON Schemas for both artifact kinds.
Stage 3 Added shared, opaque-key D&D entity-reconciliation context and proposal safety infrastructure.
Stage 4 Migrated NPC normalization to the shared reconciliation machinery.
Stage 5 Added evidence-grounded dnd/locations extraction.
Stage 6 Added conservative LLM-assisted location normalization.
Stage 7 Added immutable location-registry resolution and source-free {id, name} projection.
Stage 8 Added registry-grounded dnd/location-occurrences extraction.
Stage 9 Added deterministic location-occurrence normalization.
Stage 10 Added location shape, identity, evidence, and advisory validators.
Stage 11 Added location-occurrence shape, registry, invariant, evidence, and advisory validators.
Stage 12 Registered both lanes, their assets, evidence projectors, default profiles, and validator chains.
Stage 13 Added the ordered generated-reference handoff to the complete D&D example and integration coverage.
Stage 14 Published the current integration, configuration, internal, output, and top-level documentation and ran final verification.

The post-implementation audit confirmed that the feature's durable types, identity derivation, codecs, registration, validators, generated handoff, evidence publication, maintained example, and integration coverage are in place. At the audit baseline, go test ./..., focused race tests, go vet ./..., go build ./cmd/notarius, and git diff --check all passed.

Stage 15: Restore NPC Canonical-Name Selection Semantics

Goal

Restore the NPC-specific canonical display-name policy that was weakened during the shared reconciliation migration, without changing the shared proposal contract or any durable artifact shape.

Work

  • Update the NPC normalization task asset under internal/modules/dnd/normalize/npcs/assets/prompts/ so canonical selection again applies all of these rules:
    • choose only a supplied candidate from an evidence-supported duplicate group;
    • prefer a complete, stable proper name over an abbreviation; and
    • prefer an unadorned proper name over that name plus a contextual class, role, title, or relationship descriptor unless the transcript establishes the descriptor as part of the person's name.
  • Preserve the opaque-key shared reconciliation instructions, prompt-message ordering, response schema, retry/fallback behavior, and deterministic group application. Do not move NPC-specific naming policy into shared/entityreconcile.
  • Update the canonical NPC artifact contract in docs/integrations/dnd-npc-artifacts.md with the observable canonical-name selection rule. Keep docs/internal/dnd.md focused on normalization mechanics and link to the integration contract rather than maintaining a competing definition; add or adjust a link only if needed for clarity.
  • Allow the prompt fingerprint and any derived manifest/checkpoint metadata to change through the existing asset-fingerprint mechanism. Do not manually pin a digest.
  • Retain existing behavior tests for opaque candidate selection, evidence union, ID derivation, retry/fallback, and non-mutation. Add a test only if it exercises deterministic code behavior; do not assert prompt prose.

Acceptance Criteria

  • The rendered NPC normalization prompt contains one unambiguous NPC-owned policy that distinguishes proper names from contextual descriptors.
  • Captain Aria is not preferred over Aria solely because it is longer when Captain is only a contextual title, while an established full name may still outrank an abbreviation.
  • No module key, schema, identity policy, response schema, validator chain, or shared reconciliation asset changes.
  • Canonical current documentation, rather than this implementation plan, owns the restored externally observable rule.
  • go test ./internal/modules/dnd/normalize/npcs/... ./internal/modules/dnd/shared/entityreconcile/... ./internal/modules/dnd/register/... passes offline.
  • git diff --check reports no errors.

Prompt Size

Small and suitable for one implementation prompt.

Stage 16: Correct Hypothetical Location-Occurrence Classification

Goal

Make the location-occurrence prompt and durable documentation implement the roadmap's distinction between an explicit speculative mention and an inferred or unsupported occurrence.

Work

  • Update the location-occurrence task asset under internal/modules/dnd/extract/locationoccurrences/assets/prompts/ to encode these exact semantic outcomes:
    • explicit non-actionable speculation or a mere hypothetical reference to a registry location is mentioned;
    • an explicit proposal, intention, or agreement to travel is planned;
    • a mere hypothetical or speculation is not planned; and
    • an inferred, unstated, uncertain, or unsupported place or occurrence is omitted.
  • Preserve the documented precedence visited, planned, recalled, then mentioned, including the ability to return multiple independently evidenced facts from one passage.
  • Update the mentioned definition in docs/integrations/dnd-location-occurrence-artifacts.md to explicitly include non-actionable speculation. Keep durable category semantics in that integration contract and link from internal documentation rather than duplicating the taxonomy elsewhere.
  • Do not change the occurrence enum, durable schema, normalizer, validators, or generated-reference contract.
  • Allow existing prompt fingerprinting to record the asset change. Do not add an exact-text or exact-digest test.

Acceptance Criteria

  • The prompt no longer instructs the model to omit every hypothetical reference.
  • An explicit statement such as “What if we went to Moon Gate?” is eligible as mentioned when it is supported by a narrow transcript range, but is not a planned occurrence without an actual proposal or intention.
  • An unstated location inferred only from surrounding events remains omitted.
  • The feature roadmap, prompt, and canonical integration contract agree on all four categories and their precedence.
  • go test ./internal/modules/dnd/extract/locationoccurrences/... ./internal/modules/dnd/register/... passes offline.
  • git diff --check reports no errors.

Prompt Size

Small and suitable for one implementation prompt.

Stage 17: Narrow Location-Occurrence Normalizer References

Goal

Make the deterministic normalizer advertise exactly the reference material it uses.

Work

  • Change internal/modules/dnd/normalize/locationoccurrences so its ReferenceSlots and ModuleSpec expose only the required locations slot.
  • Keep that slot's existing contract unchanged: exactly one dnd/location-list artifact, application/json, at most 1,048,576 bytes, required at extraction and normalization.
  • Remove the normalizer's unused party, roster, players, and glossary declarations and any imports or description tables made dead by that change. Do not remove those optional slots from the LLM-backed occurrence extractor, which actually presents campaign material to the model.
  • Add or revise focused module-contract tests to compare the normalizer's complete declared slot set, including requiredness, media type, artifact kind, and size. This is a stable module contract test, not a source-layout test.
  • Verify that pipeline-level campaign reference defaults continue to bind only to eligible targets and that the complete example still resolves. Current configuration documentation already states that locations is required by both occurrence stages; update it only if repository inspection finds a claim that optional campaign references are consumed by the normalizer.
  • Do not change normalization output, registry fingerprints, warnings, or checkpoint handling for the required generated registry.

Acceptance Criteria

  • Catalog and ModuleSpec inspection report exactly one normalizer reference slot: required locations.
  • The extractor continues to accept its existing optional campaign context and required location registry.
  • Binding optional campaign references no longer implies that deterministic occurrence normalization consumes them.
  • The complete configuration and generated location handoff still resolve and run through existing tests.
  • go test ./internal/modules/dnd/normalize/locationoccurrences/... ./internal/modules/dnd/register/... ./internal/modules/integration/... ./internal/cli/... passes offline.
  • git diff --check reports no errors.

Prompt Size

Small and suitable for one implementation prompt.

Stage 18: Add Shared Registry-Resolution Infrastructure

Goal

Introduce a focused D&D-shared primitive for the demonstrated immutable registry-resolution mechanics, without changing any production consumer in the same prompt.

Work

  • Add internal/modules/dnd/shared/registryresolver as a domain-shared package; do not put this helper in the generic framework.
  • Provide an idiomatic generic resolver driven by callbacks or a small adapter so it can operate on immutable domain registry views without importing NPC, location, scene-description, or codec packages.
  • The resolver core must own the behavior currently duplicated by the NPC and location resolvers:
    • validate and retain one construction-time seeded view;
    • treat a declared generated-reference placeholder with zero construction- time items as absent only during construction;
    • use the seeded view when an operation does not supply the target slot;
    • resolve an operation-time override when the target slot is present;
    • memoize valid immutable views by a raw key and by semantic identity;
    • reuse the seeded view when bound state and semantic identity match;
    • synchronize concurrent resolution; and
    • never retain caller-owned reference maps, item content, or mutable values.
  • Raw cache identity must normalize the media-type spelling and hash the actual item content. Do not trust a caller-supplied digest as proof that different bytes are equal.
  • Provide a narrow helper for resolving an optional single reference item that validates the configured slot name, exact item count when bound, parsed media type, and maximum size. Return owned bytes or require immediate decode so the helper cannot retain caller-owned content.
  • Keep artifact decoding, semantic identity validation, canonical encoding, prompt projection, lookup indexes, clone policy, and domain-specific error context in the owning registry packages.
  • Keep errors bounded and content-free. Do not include raw reference bytes, origin paths, or campaign data in diagnostics.
  • Add focused tests for absent construction state, zero-item generated placeholders, seeded fallback, operation overrides, malformed cardinality, media types, size limits, raw reuse, semantic reuse, caller-supplied digest mismatch, concurrent access, loader failure, and non-retention/non-mutation.

Acceptance Criteria

  • The shared package depends only on generic source/framework contracts and Go standard-library packages, not concrete D&D artifact or codec packages.
  • The helper owns only demonstrated resolution, validation, caching, and ownership mechanics; it does not become a universal artifact registry.
  • Invalid values and loader errors are never cached.
  • Concurrent callers resolving identical bytes receive the same prepared immutable view without races.
  • Existing production registry packages remain unchanged in this stage.
  • go test -race ./internal/modules/dnd/shared/registryresolver/... passes offline.
  • git diff --check reports no errors.

Prompt Size

Medium and suitable for one implementation prompt. Keep production migrations out of this stage so the generic ownership and concurrency contract can be reviewed independently.

Stage 19: Migrate The NPC Registry To The Shared Resolver

Goal

Make the established NPC registry the first production consumer of the shared resolver while preserving all public and operational behavior.

Work

  • Refactor internal/modules/dnd/npcs/registry to compose the Stage 18 helper for construction/operation selection, single-item validation, raw caching, semantic caching, and synchronization.
  • Preserve the existing package API used by extractors, normalizers, validators, manifests, and tests, including NewResolver, Resolve, Seeded, Bound, NPCs, List, CanonicalBytes, Digest, ProjectionDigest, Count, PromptInput, CanonicalName, and Matches.
  • Keep NPC-owned behavior in the NPC package:
    • strict approved NPC codec use;
    • NPC identity validation;
    • canonical durable JSON and names-only prompt projection;
    • comparison-key lookup;
    • defensive NPC/source-reference cloning; and
    • NPC-specific redacted error context.
  • Preserve the exact empty projection, semantic and projection digest behavior, seeded/generated resolution semantics, manifest metadata, checkpoint fingerprints, and source-free prompt input.
  • Remove superseded NPC-private resolver/cache/media/digest code only after the shared helper supplies the same behavior. Do not migrate locations or scene descriptions in this stage.
  • Update focused tests as needed to verify behavior through the NPC package, including malformed static and operation-time references, raw/semantic cache reuse, concurrent resolution, defensive copies, prompt projection, and downstream grounding.

Acceptance Criteria

  • Existing NPC consumers compile without API changes.
  • NPC registry output bytes, prompt projection, lookup behavior, digests, reference limits, errors, manifests, and checkpoints retain their established semantics.
  • The NPC package no longer contains a second implementation of resolver selection, caching, or synchronization.
  • go test -race ./internal/modules/dnd/npcs/registry/... ./internal/modules/dnd/extract/npcinteractions/... ./internal/modules/dnd/normalize/npcinteractions/... ./internal/modules/dnd/validate/npcinteractions/... passes offline.
  • go test ./internal/modules/dnd/register/... passes offline.
  • git diff --check reports no errors.

Prompt Size

Medium and suitable for one implementation prompt.

Stage 20: Migrate The Location Registry To The Shared Resolver

Goal

Remove the newly introduced NPC/location resolver duplication while preserving the location identity and generated-handoff contracts.

Work

  • Refactor internal/modules/dnd/locations/registry to compose the Stage 18 helper for the same resolver, reference-item validation, cache, and synchronization responsibilities migrated in Stage 19.
  • Preserve the existing package API, including NewResolver, Resolve, Seeded, Bound, Locations, List, CanonicalBytes, Digest, ProjectionDigest, Count, PromptInput, Lookup, and Matches.
  • Keep location-owned behavior in the location package:
    • strict approved location codec use;
    • evidence-anchored identity validation;
    • canonical durable JSON and ordered source-free {id, name} projection;
    • exact ID lookup and exact ID/name matching;
    • defensive location/source-reference cloning; and
    • location-specific redacted error context.
  • Preserve absent/empty/bound distinctions, same-name locations with distinct IDs, seeded/generated resolution, semantic and projection digests, manifest metadata, checkpoint fingerprints, and the 1 MiB limit.
  • Remove superseded location-private resolver/cache/media/digest code only after parity is established.
  • Do not migrate the scene-description eligibility registry in this stage. It has a different projection and matching contract; including it is not needed to eliminate the exact NPC/location duplication identified by the audit.
  • Update focused and integration tests as needed for static and generated references, malformed inputs, raw/semantic reuse, concurrency, defensive copies, source-free projections, same-name ID lookup, normalizer grounding, validator grounding, and handoff checkpoint invalidation.

Acceptance Criteria

  • Existing location consumers compile without API changes.
  • Location registry output bytes, projection, identity validation, lookup, digests, reference errors, manifests, and checkpoints retain their established semantics.
  • NPC and location registries share one implementation of construction/ operation resolution, raw and semantic caching, and synchronization.
  • No registry evidence or provenance appears in the occurrence prompt projection.
  • go test -race ./internal/modules/dnd/locations/registry/... ./internal/modules/dnd/extract/locationoccurrences/... ./internal/modules/dnd/normalize/locationoccurrences/... ./internal/modules/dnd/validate/locationoccurrences/... ./internal/modules/integration/... passes offline.
  • git diff --check reports no errors.

Prompt Size

Medium and suitable for one implementation prompt.

Stage 21: Final Regression And Documentation Verification

Goal

Verify the remediations as one coherent production state without expanding the feature or prematurely retiring its roadmap documents.

Work

  • Run gofmt on all changed Go files and inspect the final diff for unrelated changes, stale private resolver implementations, unused imports, and accidental artifact-contract changes.
  • Re-read the affected prompt assets and canonical integration documents to verify that:
    • NPC canonical-name selection retains the proper-name/title distinction;
    • explicit non-actionable speculation maps to mentioned;
    • inferred, uncertain, and unsupported occurrences remain omitted; and
    • prompt changes did not reorder or duplicate shared cacheable prompt assets.
  • Inspect module catalog output or registration tests to confirm the location-occurrence normalizer declares only locations, while its extractor retains the intended optional campaign slots.
  • Confirm the shared resolver has exactly the NPC and location consumers planned here and that domain-specific codecs, identity, projections, lookups, and error context remain in their owning packages.
  • Run the maintained complete example/configuration loading path and all repository-wide validation.
  • Leave docs/roadmap/location.md and this implementation plan in place for the user's separate roadmap-retirement step. Do not delete them in this stage.

Acceptance Criteria

  • go test ./internal/modules/dnd/... passes.
  • go test ./internal/modules/integration/... ./internal/cli/... passes.
  • go test -race ./internal/modules/dnd/shared/registryresolver/... ./internal/modules/dnd/npcs/registry/... ./internal/modules/dnd/locations/registry/... passes.
  • go test ./... passes.
  • go vet ./... passes.
  • go build ./cmd/notarius passes.
  • Maintained configuration/example validation passes through its repository test target.
  • git diff --check reports no errors.
  • Current documentation contains no stale contradiction about hypothetical location mentions or NPC canonical-name selection.
  • The worktree contains only the intended remediation changes and the roadmap documents remain available for later retirement.

Prompt Size

Small-to-medium and suitable for one implementation prompt.

Open Questions

None. The feature roadmap and audit findings determine the required behavioral semantics, module reference contract, abstraction boundary, migration order, and validation expectations. The scene-description eligibility registry is explicitly outside this remediation because its projection and matching semantics differ from the duplicated NPC/location grounding registries.