Document centralized LLM asset ownership
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# ADR-0004: Package modules by domain, not by stage
|
||||
|
||||
**Status:** Accepted
|
||||
**Status:** Accepted — its asset-co-location rule is superseded by [ADR-0011](0011-centralize-llm-assets.md); its domain-first module packaging decision remains accepted.
|
||||
**Date:** 2026-07-13
|
||||
|
||||
## Context
|
||||
|
||||
69
docs/adr/0011-centralize-llm-assets.md
Normal file
69
docs/adr/0011-centralize-llm-assets.md
Normal file
@@ -0,0 +1,69 @@
|
||||
# ADR-0011: Centralize LLM-facing assets in a content-only package
|
||||
|
||||
**Status:** Accepted
|
||||
**Date:** 2026-08-05
|
||||
|
||||
## Context
|
||||
|
||||
LLM prompts, private response schemas, generic schemas, and fallback profiles
|
||||
are authored and reviewed as content, but package-local embedding scattered that
|
||||
content across implementation trees. Finding all of the assets that contribute
|
||||
to a prompt family required navigating code ownership boundaries rather than a
|
||||
single discoverable content boundary.
|
||||
|
||||
The repository must retain module ownership of prompt semantics, schema
|
||||
identities, registration, and prompt-cache behavior. Durable artifact schemas
|
||||
and non-LLM domain data have different compatibility and ownership rules, so
|
||||
they must not move merely because they are embedded files.
|
||||
|
||||
## Decision
|
||||
|
||||
LLM-facing content is embedded by the root `assets` package. It is a data-only
|
||||
dependency leaf: its single `FS() fs.FS` API returns the read-only embedded
|
||||
filesystem, and the package contains no business logic or internal or PromptKit
|
||||
dependencies. The accepted import path is
|
||||
`gitea.maximumdirect.net/eric/notarius/assets`; it makes repository-owned
|
||||
content available to its consumers, not a public extension contract.
|
||||
|
||||
Consumers scope that filesystem to the subtree they own before reading or
|
||||
registering content. Modules continue to own their manifests, prompt ordering,
|
||||
private response-schema identity, and registration. Centralizing physical files
|
||||
does not centralize domain semantics or transfer those responsibilities to the
|
||||
root package.
|
||||
|
||||
The root package contains prompt content, private LLM response schemas, generic
|
||||
LLM schemas, shared fragments, and fallback profiles. Durable artifact schemas
|
||||
and non-LLM domain data remain with their current owners. A module fingerprint
|
||||
is derived from its manifest-selected module and shared files, rather than from
|
||||
an entire asset tree. The relocation is accepted to cause a one-time checkpoint
|
||||
invalidation.
|
||||
|
||||
This decision supersedes only the physical asset-co-location portion of
|
||||
ADR-0004's decision that places domain-specific prompt fragments and schemas
|
||||
within the domain tree. ADR-0004's domain-first packaging and registrar
|
||||
ownership decisions remain accepted.
|
||||
|
||||
## Alternatives Considered
|
||||
|
||||
- Keep package-local assets. This preserves physical co-location with code but
|
||||
makes prompt-author discovery and cross-family review unnecessarily costly.
|
||||
- Use `internal/llmassets`. This would hide content from legitimate owners
|
||||
outside the `internal` subtree and would make the root asset boundary depend
|
||||
on implementation-layer placement.
|
||||
- Build a behavioral central registry. This would mix content discovery with
|
||||
prompt selection and registration behavior, moving module semantics into a
|
||||
shared registry.
|
||||
- Use runtime filesystem overlays. This would add runtime configuration and
|
||||
failure modes where compile-time embedded content is sufficient.
|
||||
|
||||
## Consequences
|
||||
|
||||
Prompt authors can find in-scope LLM content in one top-level tree while module
|
||||
packages continue to define its meaning and registration. Consumers have an
|
||||
explicit, narrow dependency on only the content they need. The root package is
|
||||
intentionally importable but must remain a stable, content-only leaf rather
|
||||
than becoming a general extension API.
|
||||
|
||||
The initial relocation invalidates existing checkpoints once. Later checkpoint
|
||||
identity changes remain limited to the manifest-selected prompt and shared
|
||||
content, so unrelated files do not trigger recomputation.
|
||||
@@ -43,14 +43,21 @@ the contracts above define durable data.
|
||||
|
||||
## Prompt Construction
|
||||
|
||||
D&D LLM-facing content lives beneath `assets/dnd/`. New extractor content uses
|
||||
its feature subtree; when a family has both extraction and normalization
|
||||
content, keep those in its `extract` and `normalize` subtrees. The owning module
|
||||
still defines the ordered manifest and registers the resulting scoped filesystem.
|
||||
Shared fragments belong to the D&D shared implementation and are selected by
|
||||
name, never copied into individual module subtrees.
|
||||
|
||||
D&D extractors assemble prompts from an ordered manifest of shared and
|
||||
module-owned assets. The location extractor and occurrence extractor reuse the
|
||||
shared D&D system, evidence, identity, reference, and transcript assets instead
|
||||
of copying their text into individual modules. A manifest’s declared sequence,
|
||||
including cache-control placement, is part of the prompt behavior.
|
||||
module-selected assets. The location extractor and occurrence extractor reuse
|
||||
the shared D&D system, evidence, identity, reference, and transcript assets
|
||||
instead of copying their text into individual modules. A manifest’s declared
|
||||
sequence, including cache-control placement, is part of the prompt behavior.
|
||||
|
||||
Every maintained D&D LLM prompt selects `dnd-extraction` as its default
|
||||
profile. The D&D registrar embeds that fallback profile with the maintained
|
||||
profile. The D&D registrar registers that fallback profile with the maintained
|
||||
OpenRouter model, timeout, and service-tier policy. An operator may provide a
|
||||
complete profile with the same ID through the configured PromptKit source; that
|
||||
definition replaces the fallback rather than merging with it. The fallback
|
||||
|
||||
@@ -125,16 +125,24 @@ the corresponding PromptKit filesystems and rejects invalid roots, unreadable
|
||||
assets, duplicate paths, and missing prompt or schema files during preparation.
|
||||
Fallback assets receive a safe content digest for checkpoint identity; raw
|
||||
paths and bytes are never included. The framework’s `promptfs` helper combines
|
||||
module-owned prompt files with reusable domain fragments without making the
|
||||
module-selected prompt files with reusable domain fragments without making the
|
||||
framework depend on D&D content.
|
||||
|
||||
Each LLM-backed module owns its prompt declaration, package-specific assets,
|
||||
and private response schema. Shared D&D wording is owned by the D&D shared
|
||||
asset package; the detailed D&D conventions are in
|
||||
[D&D Module Internals](dnd.md). The mounted prompt assets used by a module also
|
||||
determine its prompt fingerprint. Schema loaders validate JSON, attach identity
|
||||
and digest metadata, make defensive copies, and expose diagnostics without raw
|
||||
schema bytes.
|
||||
LLM-facing content is embedded once by the root `assets` package. Each consumer
|
||||
uses only its scoped subtree, while the module retains ownership of its prompt
|
||||
declaration, ordered manifest, private response-schema identity, and
|
||||
registration. Shared D&D fragments are selected by D&D's shared implementation;
|
||||
the detailed convention is in [D&D Module Internals](dnd.md). This physical
|
||||
arrangement and its data-only boundary are defined by
|
||||
[Architecture](../policy/architecture.md) and
|
||||
[ADR-0011](../adr/0011-centralize-llm-assets.md), rather than by this runtime
|
||||
guide.
|
||||
|
||||
Mounted prompt assets determine a module's fingerprint. The fingerprint hashes
|
||||
only the module and shared files explicitly selected by its manifest, so an
|
||||
unrelated asset does not invalidate a checkpoint. Schema loaders validate JSON,
|
||||
attach identity and digest metadata, make defensive copies, and expose
|
||||
diagnostics without raw schema bytes.
|
||||
|
||||
Private response schemas validate a model transport envelope. They are not the
|
||||
durable artifact schema and should not be documented as an external wire
|
||||
|
||||
@@ -29,6 +29,7 @@ physical state roots.
|
||||
| Generic models | **internal/core/source**, **internal/core/artifacts**, **internal/framework/contracts** | Source documents and chunks, manifests and provenance, plus typed artifact, reference, validation, output, and structured-completion contracts. |
|
||||
| Pipeline framework | **internal/framework/pipeline** | Registries, profile and reference resolution, typed preparation, validation, retry coordination, ordered execution, handoff, and result assembly. |
|
||||
| LLM and prompt runtime | **internal/framework/llm**, **internal/framework/promptfs** | Provider-neutral structured completions, scheduling, profile recording, prompt assets, schema registration, and credential-shaped-value redaction. |
|
||||
| Embedded LLM content | **assets** | Read-only centralized LLM-facing content, scoped by its consuming package; see [LLM Runtime](llm.md#prompt-and-schema-assets) and [D&D Module Internals](dnd.md#prompt-construction). |
|
||||
| Runtime state | **internal/core/fileio**, **internal/core/debugbundle**, **internal/framework/checkpoint**, **internal/framework/chunkplan**, **internal/framework/chunkmap**, **internal/framework/debug** | Confined atomic files, debug bundles, checkpoint and chunk-plan state, accepted chunk maps, and pipeline-facing debug recording. |
|
||||
| Production extensions | **internal/modules/generic**, **internal/modules/seriatim**, **internal/modules/dnd** | Domain-neutral extensions, Seriatim input support, and D&D extraction families registered into the production catalog. |
|
||||
|
||||
|
||||
@@ -44,6 +44,13 @@ must not compose the application or take ownership of process behavior. The
|
||||
current packages implementing these layers are inventoried in
|
||||
[Internal Overview](../internal/overview.md).
|
||||
|
||||
The root `assets` package is a content-only dependency leaf. It may expose a
|
||||
read-only embedded filesystem, but it must contain no business logic and must
|
||||
not depend on `internal` packages or PromptKit. Consumers scope that filesystem
|
||||
to the content they own; the root package is not a behavioral registry or a
|
||||
public extension contract. The rationale and compatibility consequence are
|
||||
recorded in [ADR-0011](../adr/0011-centralize-llm-assets.md).
|
||||
|
||||
The following dependency boundaries are mandatory:
|
||||
|
||||
- extractors and validators do not depend on concrete input adapters;
|
||||
@@ -73,6 +80,12 @@ Extract modules own artifact semantics, prompt use, response schemas, and
|
||||
domain interpretation. Domain-specific concepts remain in the relevant module,
|
||||
validator, shared domain helper, and artifact contract.
|
||||
|
||||
Physical centralization of LLM-facing content does not transfer semantic
|
||||
ownership from those modules. Modules retain their manifests, response-schema
|
||||
identities, prompt ordering, and registration, while reading only their scoped
|
||||
content subtree. Generic framework code remains domain-neutral when it reads
|
||||
its own scoped generic assets from the shared content container.
|
||||
|
||||
Typed artifact registrations declare one stable artifact kind and exact Go
|
||||
type from extraction through merge, normalization, and semantic validation.
|
||||
Pipeline resolution requires a compatible codec and matching kind-specific
|
||||
|
||||
Reference in New Issue
Block a user