From 406ad1d3623a064b4d34090f18b361075f4f4301 Mon Sep 17 00:00:00 2001 From: Eric Rakestraw Date: Wed, 5 Aug 2026 13:23:00 +0000 Subject: [PATCH] Retire the completed asset migration roadmaps --- docs/roadmap/assets.md | 366 ----------------- docs/roadmap/implementation.md | 695 --------------------------------- 2 files changed, 1061 deletions(-) delete mode 100644 docs/roadmap/assets.md delete mode 100644 docs/roadmap/implementation.md diff --git a/docs/roadmap/assets.md b/docs/roadmap/assets.md deleted file mode 100644 index 3cea3fb..0000000 --- a/docs/roadmap/assets.md +++ /dev/null @@ -1,366 +0,0 @@ -# Centralized LLM Assets - -## Purpose - -Centralize Notarius's embedded LLM-facing assets in a top-level `assets/` -package so prompt declarations, prompt fragments, private structured-response -schemas, shared prompt text, and built-in LLM profiles are easy to find, -inspect, compare, and revise. - -This is an ownership and repository-layout change, not a prompt redesign or a -change to any durable artifact contract. Modules continue to own all behavior -associated with their assets. - -## Motivation - -The D&D module family currently distributes its LLM assets across the packages -that consume them. Twelve D&D prompt consumers collectively embed 46 prompt -files. Their private response schemas, shared entity-reconciliation schema, -shared prompt fragments, and built-in `dnd-extraction` profile are likewise -spread across chunk, extract, normalize, shared, and registrar packages. - -Co-location made each original module self-contained, but the growing family -now makes prompt inspection and cross-module editing unnecessarily difficult. -Prompt authors commonly need to: - -- review all sibling prompts together; -- preserve exact shared bytes and cache-compatible message prefixes; -- compare declarations, instructions, tasks, and response schemas; -- identify duplicated or drifting language; and -- iterate on prompt content without navigating implementation packages. - -A centralized, predictable asset tree makes those operations straightforward -while leaving executable behavior with the module packages. - -## Decisions - -### Top-Level Asset Package - -All production LLM-facing assets will live beneath a repository-root -`assets/` directory. That directory will also be a Go package named `assets` -because Go embed patterns cannot embed files outside the embedding package's -directory tree. - -The package will contain one Go source file, `assets/package.go`, unless a -future Go toolchain constraint makes that impractical. Its entire production -API will expose the embedded, read-only filesystem. The intended shape is -equivalent to: - -```go -package assets - -import ( - "embed" - "io/fs" -) - -//go:embed dnd generic -var embedded embed.FS - -func FS() fs.FS { return embedded } -``` - -The exact embed patterns may reflect the final asset tree, but the package must -retain this minimal character. Adding a new asset domain may require extending -the embed directive; it must not require adding domain behavior to the package. - -### Strict Data-Only Boundary - -The `assets` package is a content container and dependency leaf. No business, -domain, framework, or PromptKit behavior may live there. - -In particular, the package must not own: - -- prompt IDs, schema IDs, schema names, or schema versions; -- prompt manifests, message order, cache controls, or input construction; -- module, schema, profile, or PromptKit registration; -- asset selection rules or module-to-path catalogs; -- parsing, validation, normalization, transformation, or hashing; -- checkpoint or fingerprint policy; -- fallback-profile precedence or model defaults; or -- imports of Notarius internal packages, PromptKit, or module packages. - -It should expose no path-aware lookup helpers. Consumers obtain the root -read-only filesystem and use the standard library's `fs.Sub` to select the -smallest subtree they own. A module must not depend on an unrelated module's -asset subtree merely because both are available from the same embedded -filesystem. - -The package's top-level location and exported accessor are an intentional -tradeoff in favor of human discoverability. They do not establish a supported -public extension API or transfer semantic ownership away from modules. - -### Behavioral Ownership Remains With Modules - -Each LLM-backed module continues to own: - -- its prompt and response-schema identity constants; -- its ordered prompt-asset manifest; -- prompt input preparation and rendered message order; -- its response-schema definition and loading; -- prompt and schema registration with the shared LLM asset registry; -- output decoding and interpretation; -- its component fingerprint composition; and -- tests of its observable prompt and schema behavior. - -The D&D shared package continues to own the manifest mechanism and the declared -set of reusable D&D prompt fragments. The D&D registrar continues to own family -composition and registration of the built-in fallback profile. The generic LLM -framework continues to own filesystem flattening, duplicate detection, schema -loading, PromptKit construction, and content hashing. - -Physical storage is therefore centralized without creating a central package -that understands or composes every module. - -### Asset Scope - -The centralized tree includes embedded content whose direct purpose is to -configure or constrain an LLM interaction: - -- PromptKit prompt declarations; -- module-owned prompt fragments; -- byte-identical shared prompt fragments; -- private JSON Schemas for structured LLM response envelopes; -- shared private response schemas such as D&D entity reconciliation; and -- built-in fallback LLM profiles. - -The migration also includes the generic private LLM response schemas currently -embedded by the LLM framework. The framework may depend on the content-only -asset package for those generic files, but it must refer only to its own scoped -subtree and must not acquire D&D knowledge. - -The following embedded files remain with their current owners: - -- durable artifact schemas owned by D&D codec packages; -- framework-owned durable schemas such as chunk-map and evidence-context - contracts; -- the D&D spell catalog and other domain data that is not itself a prompt, - private LLM response schema, or built-in LLM profile; -- maintained configuration examples; and -- operator-supplied PromptKit profiles and other runtime files. - -Private LLM response schemas must remain clearly distinguishable from durable -artifact schemas. Centralization must not turn a model transport envelope into -an external Notarius contract. - -## Target Asset Tree - -The target tree groups assets first by domain and then by conceptual module. -Directory names use readable kebab case; Go package names, module keys, prompt -IDs, and schema identities do not change to match the directory spelling. - -```text -assets/ - package.go - generic/ - schemas/ - dnd/ - shared/ - prompts/ - profiles/ - entity-reconciliation/ - schemas/ - scenes/ - prompts/ - schemas/ - spells/ - prompts/ - schemas/ - npcs/ - extract/ - prompts/ - schemas/ - normalize/ - prompts/ - combat-turns/ - prompts/ - schemas/ - enemy-events/ - prompts/ - schemas/ - item-events/ - prompts/ - schemas/ - npc-interactions/ - prompts/ - schemas/ - scene-descriptions/ - prompts/ - schemas/ - locations/ - extract/ - prompts/ - schemas/ - normalize/ - prompts/ - location-occurrences/ - prompts/ - schemas/ -``` - -Each prompt-bearing leaf retains predictable filenames for its declaration, -task, instructions, and any lane-specific fragments. Existing filenames should -be preserved where practical so this migration does not create gratuitous -content churn. Shared content must have one physical source file rather than a -copy in each consuming subtree. - -Future LLM-backed domains and modules follow the same taxonomy. A future module -with both extraction and LLM-backed normalization assets uses explicit -`extract/` and `normalize/` children; a module with only one LLM-backed -operation may keep its prompt and schema directories directly beneath the -module directory. - -## Filesystem And Registration Model - -Consumers use `assets.FS()` plus `fs.Sub` to obtain a domain-, module-, or -asset-class-specific filesystem. Existing manifests continue to enumerate the -exact files used by each prompt. Registration continues through -`llm.AssetRegistry`, which presents PromptKit with its existing flattened -prompt, schema, and fallback-profile filesystems. - -The virtual PromptKit layout is stable even though repository source paths -move. In particular: - -- prompt IDs and declaration names remain unchanged; -- schema keys, IDs, versions, names, and registered filenames remain unchanged; -- fallback profile IDs, contents, and precedence remain unchanged; -- shared fragments remain mounted at the paths expected by existing prompt - declarations; and -- duplicate-path and missing-file failures continue to occur during - preparation. - -No consumer receives a precomposed global prompt catalog from the `assets` -package. Module manifests and the D&D registrar remain the explicit composition -points. - -## Prompt Caching And Fingerprints - -The migration must preserve every prompt's rendered roles, bytes, input -placement, message order, and cache-control metadata. Merely moving source -files must not reduce backend prompt-cache compatibility or alter model-visible -content. - -Each component fingerprint must remain scoped to the exact assets declared by -that component. An edit to one lane must not invalidate checkpoints belonging -to unrelated lanes. The implementation must not replace manifest-scoped -hashing with a digest of the complete root asset filesystem. - -Current asset hashes include source paths as well as bytes, so moving the files -may produce a one-time checkpoint fingerprint change for affected components. -That safe invalidation is acceptable. Preserving old internal fingerprints is -not a reason to retain duplicate files, compatibility shims, or legacy asset -paths. After migration, changing an unrelated asset must not affect a -component's fingerprint. - -## Architectural Documentation - -Central storage refines the accepted domain-packaging decision in ADR-0004, -which currently says domain-specific prompt fragments and schemas live within -the domain implementation tree. Implementation must add a new ADR recording -the content-only root package, module ownership rules, alternatives, and -consequences, and mark only the conflicting asset-co-location portion of -ADR-0004 as superseded. Its remaining domain-first module packaging decision -continues to apply. - -Once implemented, the canonical architecture and internal documentation must -describe current behavior: - -- architecture documents the data-only asset-package boundary and dependency - direction; -- LLM internals document embedding, scoped filesystem consumption, - registration, and private-schema ownership; -- D&D internals document the domain asset taxonomy, shared-fragment ownership, - manifest-scoped fingerprints, and the convention for new modules; and -- the internal component overview links to the focused owner without - duplicating volatile paths. - -The roadmap remains the only documentation of this unimplemented target until -the migration lands. - -## Work Scope - -Completing this feature requires: - -- creating the top-level asset package and target directory structure; -- moving all in-scope files without editing their semantic content; -- replacing package-local `embed.FS` declarations for migrated assets with - scoped views of the central filesystem; -- updating module manifests, response-schema loaders, shared-fragment - resolution, generic schema loading, fallback-profile registration, and asset - hashes to use those scoped views; -- removing obsolete module-local prompt, private-schema, and profile asset - directories and their embedding files; -- preserving module-local behavioral declarations and registration methods; -- updating tests and documentation at their durable ownership boundaries; and -- recording the architectural decision described above. - -## Verification Expectations - -Verification should protect behavior and architectural boundaries rather than -freeze prompt prose or count files. The completed migration must demonstrate -that: - -- all registered prompts and private response schemas prepare successfully; -- all built-in fallback profiles remain available with unchanged effective - configuration; -- rendered prompt messages and cache controls are unchanged for representative - extraction, chunking, and normalization prompts; -- shared prompt fragments come from one physical source and render identically - wherever reused; -- schema loading retains the existing identities and content digests; -- duplicate, missing, or malformed assets still fail at the established - preparation boundary; -- component fingerprints use only their declared assets; -- D&D family and production composition tests pass; -- no package-local migrated copies remain; and -- `assets/` contains only the single minimal Go source file and in-scope data - files, with no business logic or internal/PromptKit dependencies. - -Tests must follow the testing policy: do not add exact prompt-prose snapshots, -asset-count assertions, source-path snapshots, or other change-detector tests. -Use existing preparation, rendering, registration, schema, fingerprint, and -composition boundaries to protect meaningful behavior. - -Repository-wide validation includes: - -```sh -go test ./... -go vet ./... -go build ./cmd/notarius -``` - -## Non-Goals - -This work does not: - -- rewrite, consolidate, or otherwise tune prompt content; -- change prompt message order, caching policy, or profile defaults; -- change private or durable schema shapes; -- move durable schemas or the spell catalog into the root package; -- add runtime prompt overrides or live filesystem reloading; -- expose asset paths as configuration or a supported public API; -- replace the existing LLM asset registry or PromptKit filesystem boundary; -- centralize module behavior, registration, or identity constants; or -- preserve reuse of checkpoints created with the pre-migration internal asset - paths. - -An optional development-time filesystem overlay may be considered separately -if prompt iteration without rebuilding becomes valuable. It requires distinct -precedence, provenance, fingerprint, reproducibility, and security decisions -and is not implied by this repository-layout change. - -## Target End State - -Prompt authors can inspect every embedded LLM interaction asset from one -predictable top-level tree. Reusable prompt content has one physical owner, and -private LLM schemas are visibly separated from durable artifact contracts. - -The `assets` Go package consists only of `package.go`, embeds the content, and -exposes one read-only filesystem accessor. It contains no application logic and -has no Notarius-internal or PromptKit dependencies. Modules select scoped -subtrees and retain complete ownership of prompt semantics, schema identity, -registration, interpretation, and fingerprints. The framework remains -domain-neutral, the D&D registrar remains the family composition root, and all -observable prompt, schema, profile, and pipeline behavior is unchanged apart -from the accepted one-time invalidation of checkpoints whose fingerprints -include moved source paths. diff --git a/docs/roadmap/implementation.md b/docs/roadmap/implementation.md deleted file mode 100644 index d92814f..0000000 --- a/docs/roadmap/implementation.md +++ /dev/null @@ -1,695 +0,0 @@ -# Centralized LLM Assets Implementation Plan - -## Objective - -Implement the target state defined in [Centralized LLM Assets](assets.md): move -embedded LLM-facing content into a minimal top-level `assets` package while -leaving prompt semantics, schema identities, registration, interpretation, and -fingerprint composition with their current framework and module owners. - -This plan is ordered. Implement each stage in sequence and complete its focused -validation before beginning the next stage. Do not retire either roadmap when -the stages are complete; roadmap cleanup is a separate maintainer decision. - -## Plan-Wide Constraints - -These constraints apply to every stage: - -- Treat [the feature roadmap](assets.md) as the canonical source for scope, - ownership, target layout, and non-goals. -- Follow the architecture, documentation, and testing policies under - `docs/policy/`. -- Move asset files without changing their bytes. Use Git rename detection or - content hashes to investigate any move reported as a content edit. -- Move a coherent asset set and update every consumer in the same stage. Never - leave a second authoritative copy in the old package. -- Keep `assets/package.go` as the only Go source file under `assets/`. Do not add - tests, generated Go files, path constants, module descriptors, lookup - helpers, registration, validation, hashing, or other behavior to that - package. -- The root package may import only `embed` and `io/fs`. It exposes one - read-only `FS() fs.FS` accessor and contains no Notarius-internal or PromptKit - dependency. -- A consuming package must import the root package consistently as - `rootassets`, call `fs.Sub(rootassets.FS(), "")`, and operate - only on its own subtree. The alias distinguishes content from local registry - parameters commonly named `assets`. Do not pass the global filesystem - through the application or introduce a global asset catalog. -- Retain prompt IDs, schema keys, IDs, versions, names, registered filenames, - profile IDs and contents, prompt message order, rendered bytes, and cache - controls. -- Keep `promptAssetRoot = "assets/prompts"` and each manifest's `ModuleDir` - unchanged where they define the synthesized PromptKit filesystem. Only the - source paths inside the manifest change. -- Register a scoped module filesystem's `schemas` directory as the schema root - so the flattened PromptKit schema filenames remain unchanged. -- Keep prompt fingerprints manifest-scoped. Accept the feature roadmap's - one-time fingerprint change caused by new source paths; do not preserve old - paths through compatibility files or hash the complete root filesystem. -- Do not move codec schemas, chunk-map or evidence-context durable schemas, the - spell catalog, examples, or operator-provided profiles. -- Do not rewrite prompts or schemas during this migration. -- Update existing tests only where their setup refers to the old filesystem or - path. Add a test only for a meaningful behavior not already protected. Do not - add prompt-prose snapshots, asset counts, source-path snapshots, exact shared - prefix lengths, or other change-detector tests. - -For each moved set, inspect `git diff --summary` and the ordinary diff before -finishing the stage. Asset files should appear as exact renames unless their -parent directory changes prevent Git from displaying the move immediately; -their content must nevertheless be identical. - -## Stage 1: Establish The Data-Only Package And Move Generic LLM Schemas - -### Goal - -Create the minimal root package and use it for the two generic private response -schemas currently embedded by the LLM framework. This proves the dependency -direction and scoped-filesystem pattern before any D&D assets move. - -### Changes - -1. Create `assets/package.go` with: - - - a package comment explaining that it exposes embedded LLM-facing content; - - imports of only `embed` and `io/fs`; - - an unexported `embed.FS` populated initially with `//go:embed generic`; - - one exported `FS() fs.FS` accessor returning the embedded filesystem; and - - no other declarations or behavior. - -2. Move these files without editing their contents: - - - `internal/framework/llm/assets/schemas/test_artifact.v1.json` to - `assets/generic/schemas/test_artifact.v1.json`; - - `internal/framework/llm/assets/schemas/test_validator_decision.v1.json` to - `assets/generic/schemas/test_validator_decision.v1.json`. - -3. Update `internal/framework/llm/schema_registry.go`: - - - remove its `embed` import, embed directive, and package-local embedded - filesystem; - - import the root `assets` package; - - create its existing package-private schema filesystem from - `fs.Sub(rootassets.FS(), "generic")`; - - keep the existing fail-fast initialization behavior for an invalid - compile-time subtree, using a small private helper in the LLM package if - needed; and - - change only the two source paths from `assets/schemas/...` to - `schemas/...`. Preserve every schema definition identity and the existing - defensive loading behavior. - -4. Remove the now-empty `internal/framework/llm/assets/` tree. - -Do not introduce a reusable root-package subdirectory helper. The private -framework helper, if used, is an initialization mechanism for the existing -framework registry and does not belong in `assets`. - -### Acceptance Criteria - -- `assets/package.go` is the sole Go file beneath `assets/` and has the exact - minimal responsibility above. -- The two generic schemas exist only in `assets/generic/schemas/`. -- `RegisteredResponseSchemas`, lookup, schema identities, and schema content - digests behave exactly as before. -- The generic framework imports no D&D package or path. -- No unrelated D&D asset has moved. - -### Validation - -```sh -gofmt -w assets/package.go internal/framework/llm/schema_registry.go -go test ./assets ./internal/framework/llm -go vet ./assets ./internal/framework/llm -git diff --check -git diff --summary -``` - -This stage is sized for one gpt-5.6-terra implementation prompt. - -## Stage 2: Centralize Shared D&D Prompts, Reconciliation Schema, And Profile - -### Goal - -Create the shared D&D asset foundation required by every later D&D migration, -including the single physical copy of shared prompt wording, the shared private -entity-reconciliation schema, and the built-in fallback profile. - -### Changes - -1. Extend the embed directive in `assets/package.go` to embed both `generic` and - `dnd`. Make no other root-package API change. - -2. Move the seven files under - `internal/modules/dnd/shared/assets/prompts/` unchanged to - `assets/dnd/shared/prompts/`. - -3. Update `internal/modules/dnd/shared/assets.go`: - - - remove the local embed declaration and `embed` import; - - import the root `assets` package; - - obtain a scoped filesystem with - `fs.Sub(rootassets.FS(), "dnd/shared")` inside the shared package; - - update `sharedPromptPaths` from `assets/prompts/` to - `prompts/`; - - continue resolving only the names explicitly declared by a - `PromptAssetManifest`; and - - retain the existing validation, virtual `sharedassets` mount names, - defensive copying, ordering, and manifest-scoped hashing. - - Propagate subtree errors through the existing `PromptFS` and `Hash` error - paths. Do not panic for D&D module asset preparation and do not move the - manifest implementation into the root package. - -4. Update the shared asset tests to obtain the scoped shared filesystem through - the shared package's private mechanism instead of referring to the removed - `embeddedAssets`. Retain the behavioral coverage for missing files, unknown - names, exact declared parts, and deterministic hashing without asserting the - repository tree or prompt prose. - -5. Move - `internal/modules/dnd/shared/entityreconcile/assets/schemas/dnd_entity_reconcile_llm.v1.json` - unchanged to - `assets/dnd/entity-reconciliation/schemas/dnd_entity_reconcile_llm.v1.json`. - In `entityreconcile/schema.go`, scope the root filesystem to - `dnd/entity-reconciliation`, change `SchemaAssetPath` to - `schemas/dnd_entity_reconcile_llm.v1.json`, and use the same scoped - filesystem for loading and registration. Register the `schemas` root so the - flattened filename remains `dnd_entity_reconcile_llm.v1.json`. Delete the - obsolete `entityreconcile/assets.go`. - -6. Move - `internal/modules/dnd/register/assets/profiles/dnd-extraction.yaml` - unchanged to `assets/dnd/profiles/dnd-extraction.yaml`. Update - `register/profiles.go` to scope `rootassets.FS()` to `dnd/profiles` and - register that filesystem at `.`. Preserve the profile's virtual filename, - ID, contents, fallback precedence, and digest behavior. - -7. Remove the now-empty local shared/profile asset directories. Do not touch - module-local prompt or schema assets in this stage. - -### Acceptance Criteria - -- Every shared D&D prompt fragment has one physical source under - `assets/dnd/shared/prompts/`. -- Existing D&D manifests still select shared files explicitly and mount them - at the same virtual names. -- Entity reconciliation loads and registers the same private schema identity - and bytes. -- The `dnd-extraction` fallback profile resolves with unchanged effective - content and precedence. -- Full D&D registration succeeds while the remaining modules still consume - their package-local assets. -- `assets/package.go` remains the only Go file in the root package. - -### Validation - -```sh -gofmt -w assets/package.go internal/modules/dnd/shared/assets.go internal/modules/dnd/shared/entityreconcile/schema.go internal/modules/dnd/register/profiles.go -go test ./assets ./internal/framework/llm ./internal/modules/dnd/shared/... ./internal/modules/dnd/register -git diff --check -git diff --summary -``` - -This stage is sized for one gpt-5.6-terra implementation prompt. - -## Stage 3: Migrate Scene Planning And Scene Descriptions - -### Goal - -Move the two scene-oriented prompt/schema sets and establish the repeatable -module-consumer pattern used in subsequent stages. - -### Changes - -Move these directories without editing asset contents: - -| Current source | Target | -| --- | --- | -| `internal/modules/dnd/chunk/scenes/assets/prompts/` | `assets/dnd/scenes/prompts/` | -| `internal/modules/dnd/chunk/scenes/assets/schemas/` | `assets/dnd/scenes/schemas/` | -| `internal/modules/dnd/extract/scenedescriptions/assets/prompts/` | `assets/dnd/scene-descriptions/prompts/` | -| `internal/modules/dnd/extract/scenedescriptions/assets/schemas/` | `assets/dnd/scene-descriptions/schemas/` | - -For both consuming packages: - -1. Delete the package-local `assets.go` embed file. -2. In `prompt_assets.go`, add a private `moduleAssetFS() (fs.FS, error)` that - scopes the root filesystem to the package's exact target subtree. -3. Change manifest source paths from `assets/prompts/` to - `prompts/`. Do not change `ModuleDir`, the declared file order, shared - file order, or `promptAssetRoot`. -4. Resolve the scoped filesystem in `RegisterPromptAssets`, pass it to the - existing manifest, and register its `schemas` root. -5. Resolve the same scoped filesystem in the synchronized prompt fingerprint - initializer and hash only the manifest's declared assets. -6. Update the response-schema loader to use the scoped filesystem and - `schemas/`, preserving all identity constants. -7. Update focused tests that directly used `embeddedAssets` or old source paths - to use `moduleAssetFS`. Preserve tests of prepared inputs, message placement, - cache control, diagnostics redaction, schema compatibility, and - registration. - -Keep scene planning in the chunk module and scene-description semantics in the -extractor; the common asset location must not merge their behavior. - -### Acceptance Criteria - -- Both scene asset sets exist only in their target root directories. -- Both packages use scoped filesystems and retain their own manifests, schema - definitions, registration, and fingerprints. -- Prepared prompt IDs, rendered messages, schema identities, and PromptKit - virtual filenames are unchanged. -- Scene chunking and scene-description extraction tests pass, including D&D - family registration. - -### Validation - -```sh -gofmt -w internal/modules/dnd/chunk/scenes/*.go internal/modules/dnd/extract/scenedescriptions/*.go -go test ./internal/modules/dnd/chunk/scenes ./internal/modules/dnd/extract/scenedescriptions ./internal/modules/dnd/register -git diff --check -git diff --summary -``` - -This stage is sized for one gpt-5.6-terra implementation prompt. - -## Stage 4: Migrate The NPC Prompt Family - -### Goal - -Centralize NPC extraction, NPC normalization, and NPC-interaction assets while -preserving their distinct module behavior and shared-prefix contracts. - -### Changes - -Move these directories unchanged: - -| Current source | Target | -| --- | --- | -| `internal/modules/dnd/extract/npcs/assets/prompts/` | `assets/dnd/npcs/extract/prompts/` | -| `internal/modules/dnd/extract/npcs/assets/schemas/` | `assets/dnd/npcs/extract/schemas/` | -| `internal/modules/dnd/normalize/npcs/assets/prompts/` | `assets/dnd/npcs/normalize/prompts/` | -| `internal/modules/dnd/extract/npcinteractions/assets/prompts/` | `assets/dnd/npc-interactions/prompts/` | -| `internal/modules/dnd/extract/npcinteractions/assets/schemas/` | `assets/dnd/npc-interactions/schemas/` | - -Apply the module-consumer pattern established in Stage 3 to all three packages: - -- delete each local embed-only `assets.go`; -- add a private scoped filesystem accessor in the owning `prompt_assets.go`; -- make manifest and response-schema paths relative to the scoped subtree; -- retain virtual prompt roots, module directories, IDs, manifest ordering, and - shared file selection; -- use the scoped filesystem for registration, schema loading, and - manifest-scoped fingerprinting; and -- update focused tests only for the filesystem/path move. - -NPC normalization has no module-private response schema; it must continue using -the shared entity-reconciliation schema migrated in Stage 2. NPC extraction and -NPC interactions retain their own private response schemas. Do not combine the -three manifests or add NPC behavior to the root package. - -### Acceptance Criteria - -- NPC extraction, normalization, and interaction assets exist only in the - target directories. -- The modules retain three independent manifests and their existing semantic - responsibilities. -- NPC normalization still registers and loads the shared reconciliation - schema rather than a copied schema. -- Extraction prompt prefix order, normalization ordering, generated-reference - grounding, cache controls, schema identities, and diagnostics behavior are - unchanged. -- Focused and family registration tests pass. - -### Validation - -```sh -gofmt -w internal/modules/dnd/extract/npcs/*.go internal/modules/dnd/normalize/npcs/*.go internal/modules/dnd/extract/npcinteractions/*.go -go test ./internal/modules/dnd/extract/npcs ./internal/modules/dnd/normalize/npcs ./internal/modules/dnd/extract/npcinteractions ./internal/modules/dnd/register -git diff --check -git diff --summary -``` - -This stage is sized for one gpt-5.6-terra implementation prompt. - -## Stage 5: Migrate The Location Prompt Family - -### Goal - -Centralize location extraction, location normalization, and -location-occurrence assets while preserving registry grounding and shared -entity-reconciliation behavior. - -### Changes - -Move these directories unchanged: - -| Current source | Target | -| --- | --- | -| `internal/modules/dnd/extract/locations/assets/prompts/` | `assets/dnd/locations/extract/prompts/` | -| `internal/modules/dnd/extract/locations/assets/schemas/` | `assets/dnd/locations/extract/schemas/` | -| `internal/modules/dnd/normalize/locations/assets/prompts/` | `assets/dnd/locations/normalize/prompts/` | -| `internal/modules/dnd/extract/locationoccurrences/assets/prompts/` | `assets/dnd/location-occurrences/prompts/` | -| `internal/modules/dnd/extract/locationoccurrences/assets/schemas/` | `assets/dnd/location-occurrences/schemas/` | - -Apply the Stage 3 module-consumer pattern to all three packages. In particular: - -- delete local embed-only files; -- scope each package to only its target subtree; -- update manifest and schema source paths without altering identities or - virtual PromptKit paths; -- keep fingerprints limited to each manifest's module and selected shared - assets; and -- update focused tests that refer to the old filesystem. - -Location normalization continues to use the shared entity-reconciliation -schema. Location occurrence extraction retains its own private response schema -and its existing required location-registry input. Do not conflate the -locations registry artifact with occurrence events. - -### Acceptance Criteria - -- All three location-oriented asset sets exist only under their target root - directories. -- Extraction, normalization, and occurrence modules retain separate manifests, - schema ownership, prompt inputs, and fingerprints. -- Reconciliation and location-registry grounding behavior is unchanged. -- Prompt preparation, schema compatibility, normalization, reference handoff, - and family registration tests pass. - -### Validation - -```sh -gofmt -w internal/modules/dnd/extract/locations/*.go internal/modules/dnd/normalize/locations/*.go internal/modules/dnd/extract/locationoccurrences/*.go -go test ./internal/modules/dnd/extract/locations ./internal/modules/dnd/normalize/locations ./internal/modules/dnd/extract/locationoccurrences ./internal/modules/dnd/register -git diff --check -git diff --summary -``` - -This stage is sized for one gpt-5.6-terra implementation prompt. - -## Stage 6: Migrate Spell And Combat-Turn Assets - -### Goal - -Move the spell and combat-turn LLM assets while preserving their distinct -catalog, NPC-grounding, and combat-scene eligibility behavior. - -### Changes - -Move these directories unchanged: - -| Current source | Target | -| --- | --- | -| `internal/modules/dnd/extract/spells/assets/prompts/` | `assets/dnd/spells/prompts/` | -| `internal/modules/dnd/extract/spells/assets/schemas/` | `assets/dnd/spells/schemas/` | -| `internal/modules/dnd/extract/combatturns/assets/prompts/` | `assets/dnd/combat-turns/prompts/` | -| `internal/modules/dnd/extract/combatturns/assets/schemas/` | `assets/dnd/combat-turns/schemas/` | - -Apply the Stage 3 module-consumer pattern to both extractors. Preserve the -spell manifest's catalog fragment and optional NPC registry placement. Preserve -combat-turn routing so the LLM runs only for exact combat scene -classifications; this refactor must not move eligibility logic into the assets -package or prompt declaration. - -Do not move or modify -`internal/modules/dnd/spells/catalog/assets/dnd_5e_2014_srd_spells.json`; it is -domain reference data, not an LLM interaction asset. - -### Acceptance Criteria - -- Spell and combat-turn prompts and private response schemas exist only in the - new root subtrees. -- Both packages retain independent manifests, response-schema definitions, - registrations, and component fingerprints. -- Spell catalog overlay identity, NPC grounding, combat eligibility, prompt - message order, cache controls, schema identities, and diagnostics remain - unchanged. -- The spell catalog stays with its existing package. -- Focused and family registration tests pass. - -### Validation - -```sh -gofmt -w internal/modules/dnd/extract/spells/*.go internal/modules/dnd/extract/combatturns/*.go -go test ./internal/modules/dnd/extract/spells ./internal/modules/dnd/extract/combatturns ./internal/modules/dnd/spells/catalog ./internal/modules/dnd/register -git diff --check -git diff --summary -``` - -This stage is sized for one gpt-5.6-terra implementation prompt. - -## Stage 7: Migrate Item-Event And Enemy-Event Assets - -### Goal - -Complete the module asset migration with item-event and enemy-event extraction, -leaving every D&D LLM prompt and private response schema under the root asset -tree. - -### Changes - -Move these directories unchanged: - -| Current source | Target | -| --- | --- | -| `internal/modules/dnd/extract/itemevents/assets/prompts/` | `assets/dnd/item-events/prompts/` | -| `internal/modules/dnd/extract/itemevents/assets/schemas/` | `assets/dnd/item-events/schemas/` | -| `internal/modules/dnd/extract/enemyevents/assets/prompts/` | `assets/dnd/enemy-events/prompts/` | -| `internal/modules/dnd/extract/enemyevents/assets/schemas/` | `assets/dnd/enemy-events/schemas/` | - -Apply the Stage 3 module-consumer pattern to both packages. Preserve the -enemy-event grounding fragment, required generated references, combat-scene -eligibility, and observation semantics. Preserve item-event categories and -prompt structure. Do not change deterministic normalizers or durable codecs. - -### Acceptance Criteria - -- Item-event and enemy-event LLM assets exist only in their target directories. -- Both extractors retain their module-owned manifests, schema definitions, - registrations, response interpretation, and fingerprints. -- Prompt preparation, reference grounding, scene gating, schema compatibility, - normalization, and family registration behavior is unchanged. -- No D&D prompt, private LLM schema, shared fragment, or built-in profile - remains beneath an `internal/modules/dnd/**/assets/` directory. - -### Validation - -```sh -gofmt -w internal/modules/dnd/extract/itemevents/*.go internal/modules/dnd/extract/enemyevents/*.go -go test ./internal/modules/dnd/extract/itemevents ./internal/modules/dnd/extract/enemyevents ./internal/modules/dnd/register -git diff --check -git diff --summary -``` - -This stage is sized for one gpt-5.6-terra implementation prompt. - -## Stage 8: Audit Asset Boundaries And Consolidate Behavioral Verification - -### Goal - -Review the completed physical migration as one system, remove obsolete -embedding surfaces, and ensure existing behavior-level tests protect the -meaningful asset contracts without introducing structural change detectors. - -### Changes - -1. Inventory every remaining `//go:embed` directive and every directory named - `assets` under `internal/`. Classify each remaining file against the feature - roadmap. Expected retained local embeds include durable codec/framework - schemas and the spell catalog; no migrated LLM interaction asset may remain. -2. Confirm all prompt-bearing consumers import the root package, scope it with - `fs.Sub`, and expose no root filesystem beyond their package. -3. Confirm every old embed-only module `assets.go` has been deleted. Keep files - named `assets.go` that still own actual manifest behavior, such as the D&D - shared implementation; file names alone are not grounds for deletion. -4. Inspect all `PromptAssetManifest` values and response-schema definitions: - - - source paths are relative to the correct scoped filesystem; - - virtual `ModuleDir`, prompt IDs, schema identities, and registration names - are unchanged; - - shared fragments remain explicitly enumerated in order; and - - hashes consume only the manifest's selected files. - -5. Run and review the existing family-wide prompt-prefix, schema-compatibility, - profile, registration, and composition tests. Repair coverage only if a - meaningful behavior lost protection during the move. Prefer existing public - or package-level preparation boundaries; do not test the literal root tree - shape, exact prose, file counts, or private call sequences. -6. Verify that only `assets/package.go` is Go code in the root asset tree and - that its imports and declarations still satisfy the strict data-only rule. - -Useful non-test inspection commands include: - -```sh -rg -n '//go:embed' --glob '*.go' . -find internal -type f -path '*/assets/*' | sort -find assets -type f | sort -find assets -name '*.go' -print -go list -f '{{join .Imports "\n"}}' ./assets -``` - -These are manual audit checks, not assertions to encode in permanent tests. - -### Acceptance Criteria - -- The root tree contains every in-scope LLM asset and no out-of-scope durable - contract or domain-data asset. -- Old module-local LLM assets and embed declarations are gone. -- There is one physical copy of each shared prompt fragment. -- Modules and framework consumers access only scoped subtrees. -- PromptKit preparation, response schemas, fallback profiles, family - registration, and production composition remain operational. -- No low-value structural or prose change-detector test has been added. - -### Validation - -```sh -go test ./assets ./internal/framework/llm/... ./internal/modules/dnd/... ./internal/cli/... -go vet ./assets ./internal/framework/llm/... ./internal/modules/dnd/... -git diff --check -git diff --summary -``` - -This audit and focused remediation stage is sized for one gpt-5.6-terra -implementation prompt. - -## Stage 9: Record The Decision And Update Canonical Documentation - -### Goal - -Document the implemented ownership boundary in its canonical homes without -duplicating volatile details or presenting the root package as a public -extension contract. - -### Changes - -1. Add `docs/adr/0011-centralize-llm-assets.md` in the policy-required Nygard - format. Record: - - - why prompt-author discoverability now outweighs package-local physical - co-location; - - the data-only top-level package and single-filesystem API; - - continued module ownership of semantics and registration; - - scoped consumer access and dependency direction; - - exclusion of durable schemas and non-LLM domain data; - - the accepted public import path and one-time checkpoint invalidation; - - alternatives of package-local assets, `internal/llmassets`, a behavioral - central registry, and runtime filesystem overlays; and - - the exact portion of ADR-0004 that this decision supersedes. - -2. Change only ADR-0004's status metadata to state that its asset-co-location - rule is superseded by ADR-0011 while its domain-first module packaging - decision remains accepted. Do not rewrite its accepted decision text. -3. Update `docs/policy/architecture.md` at the layer/domain and LLM boundaries: - - - define the root package as a content-only dependency leaf; - - prohibit business logic and internal/PromptKit dependencies there; - - state that physical centralization does not transfer semantic ownership - from modules; and - - keep generic framework code domain-neutral even when it reads its own - scoped generic assets from the shared container. - -4. Update `docs/internal/llm.md` to describe the implemented root filesystem, - scoped consumers, asset registry flattening, private schema distinction, and - manifest-scoped fingerprints. Link to architecture and the ADR instead of - repeating their rationale. -5. Update `docs/internal/dnd.md` to document the convention for locating new - D&D LLM assets, shared-fragment ownership, extract/normalize subtrees, and - module-owned manifests. Preserve its existing canonical prompt-order and - caching guidance. -6. Update `docs/internal/overview.md` with a concise current component entry for - `assets/` and links to the focused LLM/D&D documents. Do not duplicate the - full directory tree. -7. Search current documentation for claims that LLM assets are physically - package-local and revise only the canonical owners. Do not change user, - operator, configuration, or integration contracts unless inspection finds a - directly false statement caused by this internal-only move. - -### Acceptance Criteria - -- ADR-0011 records the durable decision and ADR-0004's status identifies the - limited supersession without altering its historical decision. -- Architecture contains the normative data-only boundary. -- Internal documentation accurately describes the implemented mechanics and - convention for future modules. -- No document outside `docs/roadmap/` describes unimplemented behavior. -- Documentation does not duplicate prompt contents, schema definitions, - module inventories, or volatile asset path lists unnecessarily. -- Relative links resolve to existing files. - -### Validation - -```sh -rg -n 'package-specific assets|module-owned assets|internal/modules/dnd/.*/assets|internal/framework/llm/assets' README.md docs -git diff --check -go test ./internal/framework/llm/... ./internal/modules/dnd/... -``` - -Manually verify changed Markdown links because the repository currently has no -dedicated documentation link checker. - -This documentation stage is sized for one gpt-5.6-terra implementation prompt. - -## Stage 10: Final Repository Verification - -### Goal - -Perform a clean final review of the complete migration, correct any remaining -in-scope defect, and demonstrate that the repository builds and tests as a -coherent whole. - -### Changes - -1. Re-read the feature roadmap and inspect the complete diff from the base - commit, not only the most recent stage. -2. Confirm every target-tree entry is present and every excluded asset remains - with its original owner. -3. Confirm moved prompt, schema, and profile files have unchanged content. -4. Confirm `assets/package.go` is still the sole Go file under `assets`, exposes - only `FS() fs.FS`, and imports only `embed` and `io/fs`. -5. Confirm no consumer uses an unrelated subtree and no generic package names a - D&D asset path. -6. Confirm all old local LLM embed declarations, files, and directories are - gone, without deleting retained durable schemas or the spell catalog. -7. Review test changes for compliance with the testing policy and remove any - redundant structural or exact-content assertion introduced during the - migration. -8. Review documentation changes for canonical ownership, current-state - wording, correct links, and absence of duplicated volatile content. -9. Run formatting and repository-wide validation. Fix only defects within this - roadmap's scope; report unrelated pre-existing failures separately. - -### Acceptance Criteria - -- Every target-end-state and verification expectation in `assets.md` is met. -- The complete diff contains no prompt, schema, profile, module key, profile - default, durable contract, or pipeline behavior change beyond source - relocation and the accepted internal fingerprint invalidation. -- The working tree contains no accidental generated files or obsolete empty - asset directories. -- All repository-wide checks pass. - -### Validation - -```sh -go fmt ./... -go test ./... -go vet ./... -go build ./cmd/notarius -git diff --check -git status --short -``` - -Review `git diff --stat`, `git diff --summary`, and the full diff before -reporting completion. Do not delete `docs/roadmap/assets.md` or -`docs/roadmap/implementation.md` in this stage. - -This final verification stage is sized for one gpt-5.6-terra implementation -prompt. - -## Open Questions - -None. The feature roadmap and this plan resolve the package API, target tree, -asset scope, consumer pattern, fingerprint policy, documentation ownership, -and accepted compatibility consequences needed for implementation.