737 lines
40 KiB
Markdown
737 lines
40 KiB
Markdown
# ConfigKit Adoption Implementation Plan
|
|
|
|
## Purpose And Execution Contract
|
|
|
|
Implement the target in [ConfigKit Adoption](configkit.md). That document owns
|
|
the feature scope and operator choices; this document owns the implementation
|
|
sequence. Each numbered stage is one implementation prompt for a
|
|
gpt-5.6-terra coding agent. Execute stages in order and finish the named checks
|
|
before proceeding. Do not combine the configuration cutover with unrelated
|
|
pipeline or security refactoring.
|
|
|
|
Read `AGENTS.md`, `docs/development.md`, all three documents under
|
|
`docs/policy/`, and the relevant focused internal documentation before acting.
|
|
Apply the implementation-discipline policy: use the dependency's actual APIs,
|
|
preserve the requested flexibility, and do not add application restrictions
|
|
under the guise of this migration. Tests protect behavior, not exact helper
|
|
structure, incidental formatting, or a duplicated implementation of ConfigKit.
|
|
|
|
ConfigKit v0.3.0 supplies the required source-origin APIs. Pin that release from
|
|
Stage 1; there is no remaining upstream gate. Stage 7 uses the released
|
|
`Resolution.InputInfo` and `Resolution.Source` methods. Keep the fourteen
|
|
stages ordered and bounded as below.
|
|
|
|
Temporary coexistence of the old production loader and the new loader during
|
|
these stages is implementation scaffolding only. There is no supported dual
|
|
version loader in the final product and no release should be tagged midway
|
|
through the cutover. Each stage must compile and pass its scoped tests; the
|
|
final stage establishes repository-wide readiness.
|
|
|
|
## Repository Baseline
|
|
|
|
Planning examined Notarius at `946fa10` plus the outstanding policy and roadmap
|
|
changes. The dependency review now uses the sibling ConfigKit checkout tagged
|
|
`v0.3.0`, including its release guide and source-aware consumer example.
|
|
|
|
Relevant current owners are:
|
|
|
|
| Area | Repository evidence |
|
|
| --- | --- |
|
|
| Version 4 YAML and conversion | `internal/core/config/file_config.go`, including `FileConfig`, custom `UnmarshalYAML` methods, `ParseFileConfigYAML`, `LoadFileConfig`, and `ApplyFileConfig` |
|
|
| Defaults, runtime ownership, domain validation | `internal/core/config/config.go`, `validation.go`, `effective_config.go`, and their contract tests |
|
|
| Field-level environment overrides | `internal/core/config/env.go` and `env_contract_test.go` |
|
|
| Configuration discovery and command overrides | `internal/cli/run.go`: `loadConfig`, `runConfigValidate`, `runPipelinesList`, and `runPipelineCommand` |
|
|
| Catalog checks and configured/CLI reference behavior | `internal/framework/pipeline/profile.go`, `references.go`, and CLI reference contract tests |
|
|
| Dynamic integer consumers | `internal/modules/generic/chunk/units/chunker.go` and `internal/modules/generic/output/json/encoder.go` currently require native `int` |
|
|
| Debug configuration and resolved-pipeline output | `internal/core/config/redaction.go`, `internal/core/debugbundle/summary.go`, and the CLI debug handoff |
|
|
| Maintained examples | `examples/dnd-minimal.config.yml`, `examples/dnd-complete.config.yml`, `examples/profiles/dnd-extraction.yml`, and CLI production contract tests |
|
|
| Direct YAML test dependency | `internal/cli/production_contract_test.go` also parses embedded prompt definitions using `yaml.v3` |
|
|
| Upstream contract | ConfigKit `docs/config.md`, `docs/consumers/README.md`, public `load.go`, `lifecycle.go`, `metadata.go`, `records.go`, `path.go`, and consumer examples at v0.3.0 |
|
|
|
|
The sibling checkout is reference material, not a production dependency path.
|
|
Do not commit a local `replace`, modify upstream, or invent a future API as part
|
|
of these Notarius stages.
|
|
|
|
## Decisions Applied Throughout
|
|
|
|
### Configuration And Dependency Boundary
|
|
|
|
- Pin `gitea.maximumdirect.net/eric/ConfigKit v0.3.0`. Use the root public
|
|
package, never its private engine or an unreviewed `main` revision.
|
|
- Use a string-backed document version and a `/version` rule accepting exactly
|
|
text `5`; both numeric `version: 5` and quoted `version: "5"` are accepted.
|
|
Maintained examples use the numeric form. Reject missing/null/unsupported
|
|
versions. Numeric v4 fails the application checker with migration guidance.
|
|
- Use plain YAML-tagged document structs in `internal/core/config`, without
|
|
custom YAML hooks. Keep runtime framework types independent of ConfigKit.
|
|
- Keep the existing runtime `Config`, `ResolveInput`, and `EffectiveConfig`
|
|
boundary where it is useful. A new `LoadedConfig` owns the private ConfigKit
|
|
result and exposes runtime configuration plus safe writer methods. No
|
|
caller may mutate a returned `Result.Config` and expect its frozen inspection
|
|
output to change.
|
|
- ConfigKit owns composition, strict decoding, metadata, and safe rendering.
|
|
Notarius owns typed defaults, field semantics, recorded normalization,
|
|
conversion, catalog resolution, and physical run preparation.
|
|
- Application paths use typed ConfigKit key/index constructors; never build
|
|
JSON Pointers by concatenating unescaped pipeline IDs or reference keys.
|
|
|
|
### Document Shape And Presence
|
|
|
|
Use a distinct finite `ValidatorDocument` containing only `module`,
|
|
`llm_profile`, `structured_output_repair_attempts`, `retries`, and `options`.
|
|
The producer `BindingDocument` contains those fields plus references,
|
|
validation policy, and a validator list. This avoids recursive Go schema types
|
|
and makes forbidden nested validator fields strict unknown-field errors.
|
|
|
|
Use pointer scalars only when nil means inheritance or omission, and ordinary
|
|
structs/maps/slices elsewhere as appropriate to the contract. Use ConfigKit
|
|
presence before normalization changes paths. Remove custom parser-presence
|
|
flags. In particular:
|
|
|
|
- omitted validators use the production chain; explicit `[]` selects an empty
|
|
chain; present `null` is invalid, matching the existing array contract;
|
|
- omitted repair attempts inherit; explicit zero disables repair; present
|
|
null is invalid for this integer setting;
|
|
- omitted LLM-profile fields inherit; explicitly blank or null selections are
|
|
invalid;
|
|
- omitted optional module bindings permit existing catalog defaults; a present
|
|
binding must be a valid object with a nonempty module;
|
|
- reference objects have exactly one selected source: nonempty `path` or a
|
|
complete `artifact` object with step and lane; explicit invalid branches must
|
|
not disappear during pointer conversion;
|
|
- preserve the single-step `artifacts` form and the ordered `steps` form;
|
|
reject simultaneous declarations and explicitly empty/null `steps`;
|
|
- retain optional null behavior where the existing contract permits clearing
|
|
an optional object or collection; do not impose a universal no-null rule;
|
|
- remove the lane-level reference alias. Keep the existing treatment of the
|
|
deprecated lane-level validator list during migration (empty allowed,
|
|
nonempty rejected) rather than adding an unrelated contract removal.
|
|
|
|
Static defaults stay as currently documented. Derive omitted extraction workers
|
|
from the final configured total LLM limit. ConfigKit profile null replacement
|
|
is subject to the destination field's existing domain validity; overlay support
|
|
does not make null valid for every setting.
|
|
|
|
### CLI And Path Ownership
|
|
|
|
| Input | Owner / treatment |
|
|
| --- | --- |
|
|
| `--config`, `NOTARIUS_CONFIG`, installed fallback | Existing CLI discovery; ConfigKit receives the selected file |
|
|
| `--config-profile` | ConfigKit profile selection on all five configuration-loading command forms |
|
|
| Explicit `--output-dir` | ConfigKit override at `/output/directory` |
|
|
| Explicit `--debug-dir` | ConfigKit override at `/debug/directory`; preserve `--debug` requirement |
|
|
| Explicit `--chunk_cache` | ConfigKit override at `/cache/chunk_plans/mode` |
|
|
| `--llm-profile` | Existing runtime selection overriding all selected LLM bindings; not a replacement for a single YAML field |
|
|
| Input, lanes, session ID, reasoning effort, references, resume/recompute, debug enablement, JSON output | Existing invocation actions outside ConfigKit |
|
|
| Seven retired operational environment variables | No longer read or applied; no deprecation-warning scan of process environment |
|
|
| PromptKit credential environment variables | Existing PromptKit responsibility |
|
|
|
|
Only explicitly supplied flags create override records, with safe flag names
|
|
as provenance. Preserve current blank-value checks and invocation error classes.
|
|
For `--config-profile`, pass the supplied name through ConfigKit's selection
|
|
rules; empty and exact `default` select no overlay. Do not invent stricter name
|
|
validation or whitespace normalization than the upstream profile contract.
|
|
|
|
Enable imports without a separate Notarius enablement flag. The canonical
|
|
selected file's directory is the configuration root. Every nonempty configured
|
|
relative filesystem path (external references, PromptKit profile sources, and
|
|
output/cache/debug directories) uses the surviving declaration's canonical
|
|
directory. Built-in relative defaults use the main configuration directory;
|
|
explicit CLI values use the invocation directory. Absolute values remain
|
|
unchanged. Empty optional cache paths retain their existing meaning.
|
|
|
|
Resolve paths before runtime conversion without reading target contents.
|
|
CLI references retain their existing runtime handling and generated-reference
|
|
protection. Configuration-root confinement applies only to ConfigKit's imported
|
|
configuration and overlay files, not application paths. Do not infer path
|
|
semantics for arbitrary dynamic module options.
|
|
|
|
## Stage 1 — Add ConfigKit And The Version 5 Document Types
|
|
|
|
**Status:** Completed 2026-09-13.
|
|
|
|
**Goal:** Establish the new file contract without switching production commands.
|
|
|
|
**Work:**
|
|
|
|
1. Pin v0.3.0 in `go.mod`/`go.sum` and inspect its actual exported API.
|
|
2. Add `document.go` and `load.go` in `internal/core/config` (or equivalent
|
|
cohesive files) with the complete plain document types, finite validator
|
|
type, explicit reference union, and YAML-tagged validation-policy fields.
|
|
3. Provide a private reusable definition factory with fresh static defaults and
|
|
the exact version rule. Define a small application `LoadOptions` for profile
|
|
selection and explicit configuration overrides; avoid a generic loader
|
|
abstraction or exposing parser types.
|
|
4. Keep the new load entry point unconnected to production until its
|
|
normalization and validation stages are complete. Mark it internal
|
|
scaffolding; do not advertise partially implemented v5 support.
|
|
5. Add the next available ADR (expected `0018-adopt-configkit.md`) recording
|
|
the accepted ownership, v5 break, imports/profiles, and environment policy.
|
|
Record application path-base policy and the released source-origin APIs;
|
|
do not claim the Notarius migration is implemented merely because upstream is.
|
|
|
|
**Acceptance:** v5 numeric/quoted versions decode; unsupported versions fail
|
|
before document decoding; representative canonical bindings and references
|
|
decode while shorthand/unknown fields fail. Separate loads do not alias
|
|
defaults. The current CLI still works through its existing loader.
|
|
|
|
**Validation:** `go test ./internal/core/config`; `go test ./...` to confirm the
|
|
new dependency and schema types do not break the existing build. Keep tests
|
|
small; generic YAML exhaustiveness remains upstream.
|
|
|
|
**Prompt size:** Small to medium; types, dependency, and version boundary only.
|
|
|
|
## Stage 2 — Implement Operational Defaults And Normalization
|
|
|
|
**Status:** Completed 2026-09-13.
|
|
|
|
**Goal:** Make operational configuration behavior correct and inspectable.
|
|
|
|
**Work:**
|
|
|
|
1. Express existing concurrency, output, cache, debug, and PromptKit-local-backend
|
|
defaults and validations through the definition callbacks.
|
|
2. Use recorded `Default`/`Normalize` operations for derived extraction workers,
|
|
path whitespace, cache mode, and endpoint whitespace. Derived defaults must
|
|
follow profile/CLI overlays and preserve explicit zero for validation.
|
|
3. Use presence-aware checks for explicit empty/null PromptKit source selectors
|
|
and required fields in a present local-backend object. Preserve mutually
|
|
exclusive profile sources and the existing endpoint/range constraints.
|
|
4. Keep filesystem checks and PromptKit profile catalog lookup out of callbacks.
|
|
This stage trims filesystem paths but does not yet resolve their bases;
|
|
Stage 7 owns all source-aware path normalization.
|
|
5. Extract small reusable value checks where needed so runtime validation and
|
|
document validation do not separately implement the same rule. Collect
|
|
independent errors through ConfigKit with safe messages and field paths.
|
|
|
|
**Acceptance:** defaults and explicit values retain their meanings; worker
|
|
derivation follows effective total concurrency; multiple independent field
|
|
errors identify their source locations; normalization appears in explanation
|
|
without generating warnings.
|
|
|
|
**Validation:** `go test ./internal/core/config`. Add load-boundary cases for
|
|
profiles overriding concurrency, CLI overrides, invalid output versus empty
|
|
cache paths, and local backend presence. No live profile resolution.
|
|
|
|
**Prompt size:** Medium; operational fields only.
|
|
|
|
## Stage 3 — Implement Pipeline Document Rules
|
|
|
|
**Status:** Completed 2026-09-13.
|
|
|
|
**Goal:** Validate and normalize the complete pipeline file shape before
|
|
catalog resolution.
|
|
|
|
**Work:**
|
|
|
|
1. Implement one typed traversal of pipelines, steps, lanes, bindings,
|
|
validators, and reference sources. Prefer shared binding helpers and
|
|
explicit walks over reflective generic validation.
|
|
2. Perform all presence-sensitive checks against original input paths before
|
|
renaming map keys. Detect whitespace collisions deterministically before
|
|
writing normalized keys. Report both paths where useful.
|
|
3. Normalize identifiers, selected profiles, and generated selectors with
|
|
recorded changes. For map-key moves, record the parent operation and relevant
|
|
source dependencies; preserve a load-local original-path mapping for Stage
|
|
7. Do not guess origin from a normalized key after it has moved.
|
|
4. Enforce the field and shape contracts above, including global lane-ID
|
|
uniqueness across steps, valid retry values, validation-policy fields, and
|
|
allowed binding-local reference/validator placements.
|
|
5. Keep stage/module compatibility and actual option meaning in the existing
|
|
catalog resolver. Do not reject a module based on an embedded allowlist in
|
|
the document schema.
|
|
6. Factor shared semantic value checks with `Config.Validate` where necessary.
|
|
Keep file presence/shape checks in the document callback and direct runtime
|
|
construction checks at the runtime boundary; avoid parallel complete
|
|
validators with independently copied rules.
|
|
|
|
**Acceptance:** single-step and ordered pipelines behave as specified;
|
|
explicit empty validator chains and zero repair budgets survive; invalid
|
|
references, profile selectors, normalized collisions, and duplicate lane IDs
|
|
fail with useful paths. No mutation is hidden from ConfigKit's change recorder.
|
|
|
|
**Validation:** `go test ./internal/core/config ./internal/framework/pipeline`.
|
|
Migrate meaningful rule cases from the old parser tests to the new load
|
|
boundary as they gain an owner; retain old-loader coverage until cutover.
|
|
|
|
**Prompt size:** Medium to large, bounded to pipeline document semantics; do
|
|
not combine it with source-origin or CLI work.
|
|
|
|
## Stage 4 — Convert Documents Into Runtime Configuration
|
|
|
|
**Status:** Completed 2026-09-13.
|
|
|
|
**Goal:** Produce the existing typed runtime composition from the new document.
|
|
|
|
**Work:**
|
|
|
|
1. Add a narrow explicit conversion after successful ConfigKit loading. Build
|
|
independently owned `Config` and `pipeline.PipelineProfile` values, preserving
|
|
map identities, step order, inheritance pointers, empty chains, and reference
|
|
source forms. Convert the finite validator document to runtime bindings.
|
|
2. Wrap the result in `LoadedConfig`, retaining the private ConfigKit snapshot.
|
|
Provide safe effective/explanation writers and the runtime configuration;
|
|
avoid a public unredacted serialization method.
|
|
3. Stop re-deriving workers on the already finalized new-load path. Retain
|
|
programmatic `Config` validation and ownership checks. Any legacy
|
|
recomputation shim needed by the old loader is temporary and removed at
|
|
Stage 12. Runtime callers needing defaults should use the same default values
|
|
as the document definition, not a second literal default table.
|
|
4. Keep `Config.Resolve`/`pipeline.ResolvePipeline` responsible for selection,
|
|
capabilities, concrete validation-policy inheritance, options, references,
|
|
and digest generation. Do not add configuration profile name or source
|
|
history to semantic pipeline identity.
|
|
|
|
**Acceptance:** equivalent canonical documents produce equivalent runtime
|
|
pipelines; changing a semantic setting changes identity, while merely importing
|
|
an equivalent definition does not. Mutating caller-owned maps/slices cannot
|
|
alter the snapshot or resolved pipeline. ConfigKit changes do not force its
|
|
types into module interfaces.
|
|
|
|
**Validation:** `go test ./internal/core/config ./internal/framework/pipeline`.
|
|
Use a real test catalog and representative reference/validator chains; resolve
|
|
absolute reference fixtures until Stage 7 supplies relative path resolution.
|
|
|
|
**Prompt size:** Medium; conversion and runtime ownership only.
|
|
|
|
## Stage 5 — Support ConfigKit Dynamic Integers In Modules
|
|
|
|
**Status:** Completed 2026-09-13.
|
|
|
|
**Goal:** Ensure the module boundary accepts valid ConfigKit options.
|
|
|
|
**Work:**
|
|
|
|
1. Inspect every production numeric `map[string]any` option consumer. The known
|
|
sites are generic unit chunking and JSON evidence `window_units`.
|
|
2. Add one narrow shared option conversion helper in the existing pipeline
|
|
option-helper area. Accept `int64` from ConfigKit and native `int` from
|
|
programmatically constructed module bindings. Range-check `int64` before
|
|
conversion; keep domain positivity/nonnegativity at the module owner.
|
|
3. Preserve rejection of floats and strings. Do not recursively rewrite all
|
|
options, change their serialized representation, or add general numeric
|
|
coercion. Keep options in ConfigKit form through config conversion.
|
|
4. Update the old test that rejects `int64` to protect the newly accepted
|
|
boundary. Add representative real-loader-to-module tests, including nested
|
|
JSON evidence options.
|
|
|
|
**Acceptance:** integral options work from YAML and programmatic bindings;
|
|
fractional/string inputs and invalid ranges still fail before preparation.
|
|
No unchecked narrowing or YAML round-trip remains at these consumers.
|
|
|
|
**Validation:** `go test ./internal/modules/generic/... ./internal/framework/pipeline ./internal/core/config`.
|
|
|
|
**Prompt size:** Small; two known consumers and a narrow shared helper.
|
|
|
|
## Stage 6 — Prepare Debug Rendering For The ConfigKit Result
|
|
|
|
**Status:** Completed 2026-09-13.
|
|
|
|
**Goal:** Prepare the publication boundary before changing command loading.
|
|
|
|
**Work:**
|
|
|
|
1. Add a small writer interface such as `WriteEffective(io.Writer) error` to
|
|
the debug summary boundary. `LoadedConfig` satisfies it without exposing a
|
|
concrete ConfigKit result to debug storage.
|
|
2. Add publication of `effective-config.yml` through the existing confined,
|
|
atomic summary file writer. Buffer redacted output before publishing if the
|
|
current file API takes bytes; propagate rendering and write errors.
|
|
3. Preserve the existing redacted resolved-pipeline writer and all reference
|
|
content exclusion. The old `effective-config.json` writer remains only until
|
|
the run command switches in Stage 10.
|
|
4. Reuse `sensitiveConfigKey` for the definition's dynamic secret predicate at
|
|
nested options paths, including validator options, containers, and moved
|
|
map keys. Keep scalar classification policy in one owner. Do not log raw
|
|
configuration or metadata snapshots that contain values.
|
|
|
|
**Acceptance:** redacted effective YAML publishes atomically; failure leaves no
|
|
partial artifact; nested sensitive values never appear in effective output or
|
|
explanation. Resolved runtime summaries still omit materialized references.
|
|
|
|
**Validation:** `go test ./internal/core/config ./internal/core/debugbundle`.
|
|
Test rendering failure and caller mutation at these real local boundaries.
|
|
|
|
**Prompt size:** Small to medium; rendering interface and publication only.
|
|
|
|
## Stage 7 — Resolve Declaration-Relative Paths
|
|
|
|
**Status:** Completed 2026-09-13.
|
|
|
|
**Goal:** Normalize file paths using their effective source origins and retain
|
|
correct ConfigKit inspection history.
|
|
|
|
**Work:**
|
|
|
|
1. Query `resolution.InputInfo(originalPath)` for each path-bearing scalar.
|
|
It returns `(FieldInfo, bool)` from fixed entry-state metadata, unaffected by
|
|
earlier normalization, additions, removals, or moves. Use Stage 3's original
|
|
path mapping for renamed keys. Read `Origin.Layer` and the exact scalar's
|
|
`Origin.Locations`; use `resolution.Source(location.SourceID)` to obtain
|
|
`(SourceInfo, bool)` and its canonical `Path`. Do not select an arbitrary
|
|
origin of a composite parent.
|
|
2. Implement one narrow application path-base helper shared by typed traversals.
|
|
Base/profile file values use the declaring file directory; default relative
|
|
values use the canonical main directory; CLI relative values use the
|
|
invocation directory supplied by the CLI load boundary. Capture that
|
|
directory once for the load. Obtain canonical main-file identity consistently
|
|
with ConfigKit's acquired source records; no second parse or load.
|
|
3. Normalize nonempty relative external references, PromptKit profile sources,
|
|
and output/cache/debug directories to absolute paths. Preserve already
|
|
absolute values after existing whitespace handling. Empty optional cache
|
|
paths retain their automatic/disabled semantics. Do not inspect target
|
|
existence or read referenced content.
|
|
4. Record normalized paths and map moves so frozen inspection matches runtime
|
|
and traces the original declaration. Keep collision checks ahead of mutation
|
|
and process stable sorted keys. Use retained input metadata only as provenance,
|
|
not as a substitute for reading the current working value.
|
|
5. Fail with a safe field-level resolution diagnostic if a relative value
|
|
unexpectedly lacks an unambiguous required source/base. Defaults are a known
|
|
case, not missing provenance. Do not copy the upstream example's optional
|
|
warning-and-leave-relative fallback or impose confinement on application
|
|
paths. Queries are callback-scoped; detached records may be retained, but
|
|
never retain the `Resolution` context for post-load queries.
|
|
6. Enable imports and selected profiles on the public new loader, using
|
|
`File` and the selected file's canonical directory as the root. Keep CLI
|
|
references runtime-owned and use ConfigKit's composition semantics directly.
|
|
|
|
**Acceptance:** root, fragment, and overlay values resolve from their own files;
|
|
inherited values retain their base origin; equal-valued replacements identify
|
|
their new source; profile-replaced sequences and normalized enclosing IDs retain
|
|
attribution. Destinations follow the same rule as references. Defaults use the
|
|
main directory; CLI overrides use the invocation directory. Effective and
|
|
explanation output agree with runtime. No second load or new file-access policy.
|
|
|
|
**Validation:** `go test ./internal/core/config ./internal/framework/pipeline`.
|
|
Use temporary trees with same-named references in different directories,
|
|
canonical symlink targets accepted by ConfigKit, profile replacements,
|
|
normalized keys, default and CLI destinations, empty cache paths, and absolute
|
|
paths outside the config root. Change the working directory in a controlled
|
|
test to distinguish the bases. Materialize a real reference in one case to
|
|
prove the intended bytes are chosen. Protect Notarius policy at the load
|
|
boundary; generic fixed-view/record-detachment tests remain upstream.
|
|
|
|
**Prompt size:** Medium; one shared path-base helper and its typed consumers,
|
|
with no CLI activation or example migration.
|
|
|
|
## Stage 8 — Prepare Shared CLI Loading And Diagnostics
|
|
|
|
**Status:** Completed 2026-09-13.
|
|
|
|
**Goal:** Make one command-facing configuration entry point ready for cutover.
|
|
|
|
**Work:**
|
|
|
|
1. Add a CLI helper that discovers the file, passes profile selection and
|
|
explicit override records to the new loader, and returns `LoadedConfig`
|
|
plus the selected config path. Supply the invocation directory needed for
|
|
relative CLI overrides. Keep discovery order and injected test lookup.
|
|
2. Add a shared load-error reporter using `errors.As` for ConfigKit load errors
|
|
and `WriteDiagnostics`; supply safe source context using the dependency's
|
|
source records. Do not flatten multi-error output into repeated wrappers or
|
|
print raw parser/source contents. Preserve status 1 for valid invocations
|
|
whose configuration cannot load.
|
|
3. Add shared flag registration/parsing only where it reduces actual repeated
|
|
code. Use existing CLI parsing conventions, including flags surrounding
|
|
positional arguments. Preserve missing-value and unexpected-argument checks.
|
|
4. Route successful ConfigKit process diagnostics through one reporting owner.
|
|
Define no new application warnings for successful imports, defaulting,
|
|
normalization, or ignored retired environment names. Current application
|
|
rules should ordinarily return no nonfatal configuration diagnostics.
|
|
|
|
**Acceptance:** the helper returns a fully validated loaded value with safe
|
|
diagnostics and uses the requested source/profile. No production command has
|
|
switched accidentally; existing command tests remain green.
|
|
|
|
**Validation:** `go test ./internal/cli ./internal/core/config`. Add direct
|
|
helper tests for explicit flags versus parser defaults, discovery, safe
|
|
multi-error reporting, and profile selection. Use the real ConfigKit boundary.
|
|
|
|
**Prompt size:** Medium; helper and diagnostic wiring only.
|
|
|
|
## Stage 9 — Prepare Validation And Pipeline Listing Commands
|
|
|
|
**Status:** Completed 2026-09-13.
|
|
|
|
**Goal:** Finish the read-only command implementations before the shared
|
|
production cutover.
|
|
|
|
**Work:**
|
|
|
|
1. Implement v5 handlers for `config validate` and `pipelines list` using the
|
|
new helper and `--config-profile`. Preserve `--pipeline`, `--only`, JSON
|
|
listing, sorting, and exit/stream behavior. Keep production dispatch on the
|
|
old handlers until Stage 10 so all configuration commands switch together.
|
|
Use temporary explicit handler names, not a runtime version switch.
|
|
2. Plain validation is configuration-only. Selected-pipeline validation still
|
|
performs catalog and explicit PromptKit profile checks at their existing
|
|
owners, without provider calls or credential requirements beyond existing
|
|
offline profile validation.
|
|
3. Test these handlers with dedicated v5 fixtures and production registries.
|
|
Keep existing dispatch and maintained-example tests intact until Stage 10.
|
|
Do not weaken tests to accept both versions or advertise the unconnected
|
|
handlers as implemented CLI features.
|
|
|
|
**Acceptance:** the new handlers see imported pipelines and overlay changes,
|
|
reject v4, and retain useful module/profile failure context. Existing public
|
|
command behavior stays coherent until all three handlers switch in Stage 10.
|
|
|
|
**Validation:** `go test ./internal/cli ./internal/core/config`; run the focused
|
|
production validation cases using v5 fixtures, including unknown modules and
|
|
incompatible generated references.
|
|
|
|
**Prompt size:** Medium; two closely related read-only commands.
|
|
|
|
## Stage 10 — Switch Run And The Maintained V5 Configurations
|
|
|
|
**Status:** Completed 2026-09-13.
|
|
|
|
**Goal:** Complete production cutover and make all runs use one ConfigKit load.
|
|
|
|
**Work:**
|
|
|
|
1. Switch `runPipelineCommand` to the new loader. Translate only the three
|
|
config-valued flags in the decision table to ConfigKit overrides; remove
|
|
their direct post-load mutations. Add `--config-profile` consistently to
|
|
argument reordering and missing-value checks. Activate Stage 9's validation
|
|
and listing handlers in the same change and remove superseded handlers.
|
|
2. Preserve runtime LLM override, references, input, session identity,
|
|
resume/recompute, scheduler setup, and output receipt semantics. Config
|
|
failures must still occur before source parsing and physical run allocation.
|
|
3. Pass the retained loaded result to the effective YAML debug writer. Continue
|
|
to write the separately redacted resolved pipeline after reference
|
|
materialization. Add effective configuration profile selection to debug
|
|
invocation metadata (`config_profile`), with no overlay represented as empty.
|
|
Do not add profile-selection text to checkpoint or pipeline identity.
|
|
4. Convert both maintained D&D example configurations to v5 object syntax in
|
|
place, still as self-contained files in this stage. Change the complete
|
|
example's PromptKit source path for declaration-relative interpretation.
|
|
Review destination paths in both examples: retain their declared relative
|
|
strings unless an example's intended location requires a deliberate change;
|
|
explain their new configuration-file base.
|
|
5. Migrate run/reference/state tests and the maintained-example loader to v5.
|
|
Split mechanical fixture updates from behavioral assertions within the
|
|
diff so regressions remain reviewable. Retired env-based tests now supply
|
|
YAML or explicit flags; keep one test proving those variables have no effect.
|
|
6. Update current CLI, configuration, operations, and consumer references for
|
|
v5, profile selection, environment retirement, path bases (including defaults
|
|
and destinations), and `effective-config.yml`.
|
|
|
|
**Acceptance:** all production commands use the new helper; imported/profile
|
|
configuration and explicit overrides agree with execution and debug output;
|
|
the maintained minimal and full fake-provider workflows still complete with
|
|
the same artifact families and valid reference handoffs.
|
|
|
|
**Validation:** `go test ./internal/cli ./internal/core/config ./internal/core/debugbundle ./internal/framework/pipeline`.
|
|
Use the existing complete D&D fake LLM test instead of a live backend. Verify
|
|
JSON run receipt and stderr warning behavior remain unchanged.
|
|
|
|
**Prompt size:** Largest cutover prompt, limited to wiring, fixture migration,
|
|
and its current documentation. Schema, paths, numeric adapters, diagnostic
|
|
helpers, and debug writer must already be complete in earlier stages.
|
|
|
|
## Stage 11 — Add Effective And Explanation Commands
|
|
|
|
**Status:** Completed 2026-09-13.
|
|
|
|
**Goal:** Expose the accepted operator inspection workflow.
|
|
|
|
**Work:**
|
|
|
|
1. Add `config effective` and `config explain` with the syntax in the feature
|
|
roadmap, including `--config` and `--config-profile`.
|
|
2. Effective writes only `LoadedConfig.WriteEffective` output. Explain accepts
|
|
exactly one JSON Pointer positional argument, parses it with ConfigKit, and
|
|
calls the safe explanation writer. Accept the empty pointer for the root
|
|
when explicitly supplied; reject malformed escapes/argument shape with
|
|
status 2. A well-formed unknown path returns status 1 and no success output.
|
|
3. Use ConfigKit's contextual sequence-index rules. Signed numeric mapping
|
|
keys remain valid keys; `/steps/+0` cannot identify a sequence element.
|
|
Do not add a blanket numeric-token restriction that rejects legal map keys.
|
|
4. Preserve writer failure handling. Explanations are human-oriented text;
|
|
effective configuration is YAML. Neither output is promised to be a
|
|
reloadable config or a new durable JSON API. Do not print success banners.
|
|
5. Avoid LLM client construction, module preparation, reference materialization,
|
|
state allocation, or pipeline selection. Existing catalog registration at
|
|
CLI composition is acceptable; it must not trigger provider work.
|
|
6. Update `docs/cli.md`, the configuration inspection guidance, and help.
|
|
|
|
**Acceptance:** both commands work against imports/overlays, redaction applies
|
|
to history and effective values, removed keys remain explainable, malformed
|
|
and unknown paths fail appropriately, and stdout contains only requested data.
|
|
|
|
**Validation:** `go test ./internal/cli ./internal/core/config`. Use real
|
|
ConfigKit with temporary files and a provider factory that fails if called.
|
|
|
|
**Prompt size:** Medium; two commands sharing the completed load boundary.
|
|
|
|
## Stage 12 — Remove The Legacy Configuration Machinery
|
|
|
|
**Status:** Completed 2026-09-13.
|
|
|
|
**Goal:** Finish the simplification promised by the adoption.
|
|
|
|
**Work:**
|
|
|
|
1. Remove the unused v4 parser, YAML hooks, `FileConfig` application APIs,
|
|
environment-overlay code, parser-only presence flags, and old loading helper.
|
|
2. Remove `extractWorkersConfigured`/`defaultedExtractWorkers` inference once
|
|
file defaults are finalized by ConfigKit. Programmatically constructed
|
|
configs treat a supplied worker entry as explicit and derive only an absent
|
|
entry; update internal construction tests accordingly. Keep runtime checks
|
|
through `Config.Resolve` for direct callers, without mutating shared maps.
|
|
3. Delete the superseded `effective-config.json` publication method and raw
|
|
configuration summary/redaction functions. Retain runtime ownership cloning
|
|
and resolved-pipeline redaction that still serve real callers.
|
|
4. Remove obsolete parser/env tests; retain behavioral coverage at the new
|
|
owner. Remove `yaml.v3` from the embedded-prompt test in
|
|
`production_contract_test.go`: exercise the production PromptKit loader or
|
|
existing asset-loading seam, rather than adopting ConfigKit to parse
|
|
PromptKit assets or adding another YAML dependency for the test.
|
|
5. Run `go mod tidy`; remove the direct `gopkg.in/yaml.v3` requirement and verify
|
|
Notarius Go files no longer import a YAML parser. Dependencies may retain
|
|
their private YAML implementation.
|
|
|
|
**Acceptance:** no alternate loader, environment application layer, redundant
|
|
configuration redactor, or parser-only clone remains. Legitimate pipeline and
|
|
artifact serialization code is unaffected. Programmatic config behavior has
|
|
an explicit tested ownership/default contract.
|
|
|
|
**Validation:** `go test ./...`; `go vet ./...`; search for `UnmarshalYAML`,
|
|
`ApplyFileConfig`, `ApplyEnvOverrides`, `gopkg.in/yaml`, and old effective-config
|
|
artifact references. Inspect matches rather than treating historical docs or
|
|
negative migration tests as failures.
|
|
|
|
**Prompt size:** Medium; deletion and ownership consolidation after all callers
|
|
have moved.
|
|
|
|
## Stage 13 — Demonstrate Imports And Development Profiles
|
|
|
|
**Status:** Completed 2026-09-13.
|
|
|
|
**Goal:** Supply two maintained operator examples covering simple and composed
|
|
configuration, with a clear distinction between the two profile systems.
|
|
|
|
**Work:**
|
|
|
|
1. Keep `examples/dnd-minimal.config.yml` self-contained.
|
|
2. Keep `examples/dnd-complete.config.yml` as the complete root and move its
|
|
whole `dnd-session` pipeline into
|
|
`examples/pipelines/dnd-session.yml`, imported through `configkit.imports`.
|
|
Only the root declares version. Fix fragment-relative campaign/catalog
|
|
references to `../dnd-party.txt`, `../dnd-glossary.txt`, and
|
|
`../dnd-spell-catalog.json` where applicable.
|
|
3. Move the existing PromptKit example to
|
|
`examples/llm-profiles/dnd-extraction.yml` and point the root's
|
|
`promptkit.profile_file` to `./llm-profiles/dnd-extraction.yml`.
|
|
4. Add `examples/profiles/development.yml` as a ConfigKit overlay. Set
|
|
`concurrency.total_llm: 1` and `stage_workers.extract: 1`, plus a development
|
|
output directory. Include a short comment explaining how an operator can
|
|
change the pipeline's `llm_profile` independently; do not invent an
|
|
unavailable model profile just to demonstrate the field. The overlay has
|
|
no version or import directive.
|
|
5. Extend the existing maintained-example test to load base and development
|
|
configurations through production code, validate catalogs/profiles offline,
|
|
and exercise complete fake-provider reference materialization from a
|
|
working directory other than the example directory.
|
|
6. Update `docs/config.md`, `docs/operations.md`, `docs/consumers/subprocess.md`,
|
|
and `docs/consumers/dnd-pipeline.md` at their canonical scopes. Link the
|
|
examples; explain disjoint composition and whole-sequence replacement
|
|
instead of duplicating complete configs in prose.
|
|
|
|
**Acceptance:** all example paths resolve, the base and development selections
|
|
validate, the full pipeline still contains every implemented D&D lane, and
|
|
operators can distinguish `--config-profile` from `--llm-profile`.
|
|
|
|
**Validation:** `go test ./internal/cli`; production CLI validation for both
|
|
roots and the development overlay. No API key or live generation is needed;
|
|
use only the documented placeholder if offline PromptKit validation requires
|
|
one. Verify all moved example links.
|
|
|
|
**Prompt size:** Medium; examples and their operator-facing documentation.
|
|
|
|
## Stage 14 — Final Architecture And Contract Verification
|
|
|
|
**Goal:** Verify the completed architecture and reconcile canonical docs with
|
|
the implemented boundaries.
|
|
|
|
**Work:**
|
|
|
|
1. Review the complete diff against `configkit.md` and this plan. Check that no
|
|
stage was bypassed, no source-origin workaround weakened the selected
|
|
contract, and no unsupported step-composition semantics slipped in.
|
|
2. Finalize `docs/internal/configuration.md`, `docs/internal/cli.md`,
|
|
`docs/internal/state.md`, and `docs/internal/overview.md`. Add
|
|
`docs/integrations/pkg-configkit.md` for the pinned API boundary and relevant
|
|
upstream semantics; link upstream for general library behavior.
|
|
3. Update architecture's configuration ownership/precedence text and finalize
|
|
the adoption ADR. Document public behavior in its canonical owner; do not
|
|
retroactively edit historical release notes or prior accepted ADR decisions.
|
|
4. Ensure ConfigKit warning/diagnostic handling, safe rendering, source-relative
|
|
paths, runtime option validation, direct construction, and digest semantics
|
|
all have sufficient focused coverage. Do not duplicate upstream's test
|
|
suite or create exact-output change detectors.
|
|
5. Verify current docs no longer recommend v4 syntax, retired environment
|
|
overlays, the former PromptKit example path, or `effective-config.json`.
|
|
Migration explanations and historical records may legitimately name them.
|
|
6. Complete the checks below and report any remaining issue explicitly. Do not
|
|
tag a release, push, or retire the active roadmap during implementation
|
|
without a separate request.
|
|
|
|
**Acceptance:** every feature acceptance criterion holds, current docs and
|
|
examples agree with runtime behavior, all required checks pass, and the
|
|
remaining configuration code expresses Notarius policy rather than rebuilding
|
|
ConfigKit machinery.
|
|
|
|
**Validation:**
|
|
|
|
```sh
|
|
go test ./...
|
|
go vet ./...
|
|
go build ./cmd/notarius
|
|
go run ./cmd/notarius config validate --config examples/dnd-minimal.config.yml --pipeline dnd-session
|
|
go run ./cmd/notarius config validate --config examples/dnd-complete.config.yml --pipeline dnd-session
|
|
go run ./cmd/notarius config validate --config examples/dnd-complete.config.yml --config-profile development --pipeline dnd-session
|
|
go run ./cmd/notarius pipelines list --config examples/dnd-complete.config.yml --config-profile development --json
|
|
go run ./cmd/notarius config effective --config examples/dnd-complete.config.yml --config-profile development
|
|
go run ./cmd/notarius config explain --config examples/dnd-complete.config.yml --config-profile development /concurrency/total_llm
|
|
git diff --check
|
|
```
|
|
|
|
Use the project's normal link-check mechanism if present; otherwise check
|
|
changed relative links and heading anchors manually. Live model evaluation is
|
|
unnecessary for a configuration migration.
|
|
|
|
**Prompt size:** Medium; verification and focused documentation reconciliation,
|
|
with no planned production redesign.
|
|
|
|
## Released API And Readiness
|
|
|
|
ConfigKit v0.3.0 provides both required query methods in its public
|
|
`lifecycle.go`:
|
|
|
|
- `(*Resolution).InputInfo(Path) (FieldInfo, bool)`: fixed decoded entry
|
|
metadata, including retained defaults and explicit null; missing or
|
|
shape-mismatched paths return false.
|
|
- `(*Resolution).Source(string) (SourceInfo, bool)`: detached acquired-source
|
|
records; empty/unknown IDs return false; non-file sources have no invented
|
|
filesystem path.
|
|
|
|
Both methods are callback-scoped and perform no new filesystem or credential
|
|
lookup. Their entry-state contract permits querying original paths even after
|
|
map-key normalization. Existing `Normalize`/`Record` and result renderers
|
|
complete the one-load workflow; no upstream extension remains outstanding.
|
|
|
|
Review `docs/releases/v0.3.0.md`, the recorded-resolution contract in
|
|
`docs/config.md`, and `examples/consumers/consumers.go` /
|
|
`consumers_test.go` in the pinned dependency. The example demonstrates
|
|
`LoadNotariusPaths`; adopt its public-API usage, not its optional fallback
|
|
policy. Its warning-and-leave-relative behavior is not the Notarius contract.
|
|
|
|
The public-facade refactor needs no consumer migration; do not reach into the
|
|
private engine. Go 1.25 compatibility and the private YAML v4 prerelease pin
|
|
are unchanged. Upstream macOS support is best-effort, matching Notarius policy;
|
|
do not add platform gates as part of this adoption.
|
|
|
|
No open product decisions or upstream prerequisites remain.
|