5.9 KiB
Module Internals
This guide owns the mechanics for implementing and registering production modules. Configuration owns selectable keys, binding syntax, reference configuration, and default validator chains. Durable input and output shapes belong in integration contracts.
The D&D family has additional shared conventions and domain-specific exceptions. See D&D Module Internals rather than adding them here.
Module Boundary
A module is a typed implementation registered for one pipeline stage. Its
ModuleSpec is the public-to-the-framework declaration of its stable key,
stage, execution class, required and provided capabilities, artifact kind, and
accepted reference slots. The execution class states whether a module is
deterministic or llm_backed; registries retain it for catalog inspection and
resolved-pipeline debug data without constructing the module. The framework
uses the declaration to resolve a configured binding before it builds the
implementation. Profile inheritance and deterministic-profile validation are
not implemented at this boundary yet.
Implementations that accept options must provide both an option validator and
a builder. The validator is used while resolving configuration; the builder
decodes the same options and constructs the implementation from the prepared
BuildRequest. Reject unknown options in both paths. A builder receives only
the dependencies and materialized references that the framework prepared for
that operation, so it must not re-read configuration or files.
Registry helpers register the typed builder for a stage-specific registry. They are preferable to hand-written untyped registration because they retain the artifact type at the framework boundary. Registrars validate the registries they need, register each leaf implementation, and add any family-owned assets or default validator chains. They return contextual errors so production composition fails at startup rather than at the first run.
An artifact family can register an optional typed evidence projector alongside its codec. The projector returns defensive copies of the artifact's direct generic source references and must use the codec's exact Go type. It does not interpret surrounding context or publish files; the pipeline validates the capability during preparation and the output boundary owns publication. See the Published Evidence Context contract for the durable result.
Production Composition
Production composition is intentionally split by family:
- The generic registrar provides the unit chunker, generic JSON validators, and JSON output encoder.
- The Seriatim registrar provides the transcript input adapter. Its external input behavior is defined by the Seriatim contract.
- The D&D registrar provides its codecs, extractors, mergers, normalizers, validators, prompt assets, and default chains. Its behavioral conventions are documented in D&D Module Internals.
The CLI owns the composition that invokes these registrars. A module package may register its own family but must not assemble the CLI or make framework packages depend on production extensions.
Adding Or Changing A Module
- Choose the pipeline stage and the typed artifact boundary. Put external input or durable artifact formats in the relevant integration contract, not in this guide or in a private LLM response type.
- Define a stable
ModuleSpecwith an explicit execution class, the exact capabilities, and reference slots needed for the operation. Model a producer/consumer handoff as an artifact-compatible slot; configuration then chooses an external file or a generated binding. - Implement strict option decoding, construction, and the typed stage interface. Preserve caller ownership: do not retain mutable request data and return defensive copies where an implementation exposes stored data.
- Register the module through its typed registry helper and add it to the owning family registrar. Add a default validator chain only when that family owns the behavior; otherwise require an explicit compatible chain.
- Update the selectable-key and chain reference in Configuration, the applicable integration contract, and focused tests. Keep the configuration document as the sole list of production keys and validator order.
Validation And References
Validators operate on the value produced at their configured stage. A default chain is ordered behavior, not a set: JSON parsing, structural checks, domain-specific checks, durable-schema checks, and advisory checks may have different responsibilities and failure handling. The active default chains and override rules are maintained in Configuration.
Reference slots are part of the module specification. They describe the accepted artifact kind, media type, size, and whether a binding is required; the framework validates those constraints before construction. An external reference is materialized during preparation. A generated reference is a compatible normalized artifact handed from an earlier pipeline step at operation time. The configuration reference rules, including precedence and ordered-handoff requirements, are maintained in Configuration.
Focused Verification
Exercise the leaf implementation and its registration path when changing a module. Registry and registrar tests cover duplicate keys, required registries, and typed construction; pipeline resolution tests cover capabilities, options, and reference compatibility. Domain packages should additionally test their codecs, validators, normalizers, and any integration handoffs they own.
Run the affected package tests while iterating. The complete module suite is:
go test ./internal/modules/...