Centralize generic LLM schema assets
This commit is contained in:
15
assets/package.go
Normal file
15
assets/package.go
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
// Package assets exposes embedded LLM-facing content.
|
||||||
|
package assets
|
||||||
|
|
||||||
|
import (
|
||||||
|
"embed"
|
||||||
|
"io/fs"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:embed generic
|
||||||
|
var embedded embed.FS
|
||||||
|
|
||||||
|
// FS returns the embedded read-only asset filesystem.
|
||||||
|
func FS() fs.FS {
|
||||||
|
return embedded
|
||||||
|
}
|
||||||
366
docs/roadmap/assets.md
Normal file
366
docs/roadmap/assets.md
Normal file
@@ -0,0 +1,366 @@
|
|||||||
|
# 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.
|
||||||
695
docs/roadmap/implementation.md
Normal file
695
docs/roadmap/implementation.md
Normal file
@@ -0,0 +1,695 @@
|
|||||||
|
# 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(), "<owned-subtree>")`, 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/<name>` to
|
||||||
|
`prompts/<name>`;
|
||||||
|
- 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/<file>` to
|
||||||
|
`prompts/<file>`. 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/<filename>`, 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.
|
||||||
@@ -2,17 +2,17 @@ package llm
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"embed"
|
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
rootassets "gitea.maximumdirect.net/eric/notarius/assets"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:embed assets/schemas/*.json
|
var schemaAssets = mustSubFS(rootassets.FS(), "generic")
|
||||||
var schemaAssets embed.FS
|
|
||||||
|
|
||||||
// ResponseSchemaKey identifies one structured response schema.
|
// ResponseSchemaKey identifies one structured response schema.
|
||||||
type ResponseSchemaKey string
|
type ResponseSchemaKey string
|
||||||
@@ -49,17 +49,25 @@ var responseSchemaRegistry = map[ResponseSchemaKey]ResponseSchema{
|
|||||||
ID: "notarius.test_artifact",
|
ID: "notarius.test_artifact",
|
||||||
Version: schemaVersionV1,
|
Version: schemaVersionV1,
|
||||||
Name: "notarius_test_artifact_v1",
|
Name: "notarius_test_artifact_v1",
|
||||||
AssetPath: "assets/schemas/test_artifact.v1.json",
|
AssetPath: "schemas/test_artifact.v1.json",
|
||||||
}),
|
}),
|
||||||
TestValidatorDecisionSchemaKey: mustLoadResponseSchema(schemaAssets, ResponseSchemaDefinition{
|
TestValidatorDecisionSchemaKey: mustLoadResponseSchema(schemaAssets, ResponseSchemaDefinition{
|
||||||
Key: TestValidatorDecisionSchemaKey,
|
Key: TestValidatorDecisionSchemaKey,
|
||||||
ID: "notarius.test_validator_decision",
|
ID: "notarius.test_validator_decision",
|
||||||
Version: schemaVersionV1,
|
Version: schemaVersionV1,
|
||||||
Name: "notarius_test_validator_decision_v1",
|
Name: "notarius_test_validator_decision_v1",
|
||||||
AssetPath: "assets/schemas/test_validator_decision.v1.json",
|
AssetPath: "schemas/test_validator_decision.v1.json",
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func mustSubFS(fsys fs.FS, dir string) fs.FS {
|
||||||
|
sub, err := fs.Sub(fsys, dir)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Errorf("scope embedded assets to %s: %w", dir, err))
|
||||||
|
}
|
||||||
|
return sub
|
||||||
|
}
|
||||||
|
|
||||||
// RegisteredResponseSchemas returns all registered response schemas sorted by key.
|
// RegisteredResponseSchemas returns all registered response schemas sorted by key.
|
||||||
func RegisteredResponseSchemas() []ResponseSchema {
|
func RegisteredResponseSchemas() []ResponseSchema {
|
||||||
keys := make([]string, 0, len(responseSchemaRegistry))
|
keys := make([]string, 0, len(responseSchemaRegistry))
|
||||||
|
|||||||
Reference in New Issue
Block a user