Update ConfigKit adoption plan for version 0.3.0
This commit is contained in:
@@ -16,12 +16,10 @@ 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.
|
||||
|
||||
The selected approach requires an upstream extension: ConfigKit v0.2.0 cannot
|
||||
expose source origins during its resolution callback. See **Upstream
|
||||
Prerequisite**. Stages 1–6 are independent of that missing capability. Stage 7
|
||||
and all later stages have an explicit gate; the sprint is not ready for
|
||||
unattended execution through that gate until the upstream release is available.
|
||||
Do not mark a gated stage complete by weakening the feature contract.
|
||||
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
|
||||
@@ -32,7 +30,8 @@ final stage establishes repository-wide readiness.
|
||||
## Repository Baseline
|
||||
|
||||
Planning examined Notarius at `946fa10` plus the outstanding policy and roadmap
|
||||
changes. The sibling ConfigKit checkout is tagged `v0.2.0`.
|
||||
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:
|
||||
|
||||
@@ -47,7 +46,7 @@ Relevant current owners are:
|
||||
| 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`, `load.go`, `resolution.go`, `metadata.go`, `records.go`, `path.go`, and consumer examples at v0.2.0 |
|
||||
| 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
|
||||
@@ -57,9 +56,8 @@ of these Notarius stages.
|
||||
|
||||
### Configuration And Dependency Boundary
|
||||
|
||||
- Initially pin `gitea.maximumdirect.net/eric/ConfigKit v0.2.0`. Stage 7 may
|
||||
require a reviewed release providing the agreed upstream extension. A later
|
||||
pin must be explicit, never an unreviewed `main` revision.
|
||||
- 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
|
||||
@@ -135,14 +133,18 @@ 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. Relative file references
|
||||
and PromptKit profile sources use the surviving declaration's directory;
|
||||
absolute values remain absolute. Resolve these to absolute paths before
|
||||
runtime conversion, without reading the referenced contents. Output/cache/debug
|
||||
relative directories retain working-directory semantics. CLI reference paths
|
||||
retain the existing working-directory semantics and generated-reference
|
||||
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.
|
||||
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
|
||||
|
||||
@@ -150,7 +152,7 @@ configuration and overlay files.
|
||||
|
||||
**Work:**
|
||||
|
||||
1. Pin v0.2.0 in `go.mod`/`go.sum` and inspect its actual exported API.
|
||||
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.
|
||||
@@ -163,7 +165,8 @@ configuration and overlay files.
|
||||
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 the source-origin dependency without claiming it is implemented.
|
||||
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
|
||||
@@ -191,7 +194,8 @@ small; generic YAML exhaustiveness remains upstream.
|
||||
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 profile-source paths but does not yet resolve their bases.
|
||||
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.
|
||||
@@ -343,46 +347,58 @@ Test rendering failure and caller mutation at these real local boundaries.
|
||||
**Goal:** Normalize file paths using their effective source origins and retain
|
||||
correct ConfigKit inspection history.
|
||||
|
||||
**Prerequisite gate:** A reviewed ConfigKit release must expose surviving input origin and canonical
|
||||
source information during resolution. Confirm the actual API and pin that
|
||||
release before implementing this stage. If only v0.2.0 is available, stop here
|
||||
and report the unmet dependency. Do not implement an upstream fork, reload the
|
||||
configuration twice, parse YAML independently, or silently change the promised
|
||||
effective output.
|
||||
**Work:**
|
||||
|
||||
**Work after the gate:**
|
||||
|
||||
1. Resolve path origins at original input paths before map-key normalization
|
||||
and before recording changes can replace a source origin. Use the scalar
|
||||
origin and source ID to get the canonical declaring file; do not pick the
|
||||
first origin of a composite parent mapping.
|
||||
2. Join nonempty relative external reference paths and PromptKit profile-source
|
||||
paths to that file's directory. Preserve absolute values. Do not read or
|
||||
require existence of referenced files in this callback.
|
||||
3. Record normalized paths and map moves so the frozen effective view matches
|
||||
runtime values and explanation can trace back to the original declaration.
|
||||
Keep map collision checks ahead of mutation; process stable sorted keys.
|
||||
4. Leave destination directories unchanged except existing whitespace
|
||||
normalization. CLI reference paths remain runtime-owned. No configuration
|
||||
root confinement or symlink policy is added to referenced application files.
|
||||
5. Enable imports and selected profiles on the public new loader, using
|
||||
`File` and the selected file's canonical directory as the root. Use
|
||||
ConfigKit's composition and profile behavior directly.
|
||||
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; profile-replaced sequences use the
|
||||
new declarations; normalized enclosing IDs do not lose attribution. Effective
|
||||
and explanation output agree with the actual paths. Removed/overridden file
|
||||
values are not opened or resolved. Root containment affects only ConfigKit
|
||||
configuration sources.
|
||||
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 configuration trees with same-named reference files in different
|
||||
directories, aliases/symlinks accepted by ConfigKit, profile replacements,
|
||||
normalized keys, and absolute external paths outside the config root. Use real
|
||||
reference materialization for one case to prove the intended bytes are chosen.
|
||||
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, with a firm upstream gate; no CLI or example migration.
|
||||
**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
|
||||
|
||||
@@ -392,7 +408,8 @@ reference materialization for one case to prove the intended bytes are chosen.
|
||||
|
||||
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. Keep discovery order and injected test lookup.
|
||||
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
|
||||
@@ -469,12 +486,16 @@ incompatible generated references.
|
||||
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, and `effective-config.yml`.
|
||||
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;
|
||||
@@ -658,43 +679,32 @@ unnecessary for a configuration migration.
|
||||
**Prompt size:** Medium; verification and focused documentation reconciliation,
|
||||
with no planned production redesign.
|
||||
|
||||
## Upstream Prerequisite
|
||||
## Released API And Readiness
|
||||
|
||||
### Source Origins During ConfigKit Resolution
|
||||
ConfigKit v0.3.0 provides both required query methods in its public
|
||||
`lifecycle.go`:
|
||||
|
||||
**Evidence:** In v0.2.0, `Resolution` exports `IsExplicit`, `Record`, `Error`,
|
||||
and `Warning`, with generic `Default` and `Normalize` helpers. It does not
|
||||
expose source metadata. `Result.Metadata()` and `Result.Sources()` become
|
||||
available only after `Load` returns. Mutating `Result.Config` afterward does
|
||||
not change `WriteEffective` or `WriteExplanation`, which use frozen snapshots.
|
||||
Therefore a single v0.2.0 load cannot both use declaration origins to normalize
|
||||
paths and record that normalization in ConfigKit's inspection history.
|
||||
- `(*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.
|
||||
|
||||
**Selected approach:** Request a small upstream API exposing surviving
|
||||
input origins and canonical source records during the existing resolution
|
||||
callback. It should distinguish base/profile/CLI/default origins, identify the
|
||||
declaring file for a scalar, and permit lookup at original paths before
|
||||
application map-key normalization. Keep the existing recorded mutation API.
|
||||
Exact method names and the containing release must be confirmed upstream;
|
||||
none are assumed to exist by this plan. This preserves one load, ConfigKit
|
||||
ownership of composition/provenance, and the agreed effective-output contract.
|
||||
The tradeoff is an upstream release dependency at Stage 7. This plan does not
|
||||
authorize changes to the sibling repository.
|
||||
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.
|
||||
|
||||
**Alternative considered:** Stay on v0.2.0 and resolve paths in the narrow Notarius
|
||||
runtime converter using completed-result metadata. Preserve original document
|
||||
paths for origin lookup. Present ConfigKit's effective configuration as a
|
||||
logical configuration view, and expose resolved runtime paths separately in
|
||||
debug/inspection output. This is implementable without an upstream change and
|
||||
keeps composition centralized, but changes the agreed inspection contract,
|
||||
requires Notarius to own the extra path report, and cannot make ConfigKit's
|
||||
explanation record the post-load normalization. It requires explicit approval
|
||||
and revision of Stage 7 and the feature roadmap before dependent work begins;
|
||||
the user selected the upstream extension instead.
|
||||
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.
|
||||
|
||||
Do not resolve this by silently dropping imports/profiles, changing all file
|
||||
paths to working-directory-relative, reparsing YAML, or performing a second
|
||||
load that might observe different files. All other product decisions in this
|
||||
plan are settled; the upstream release is the sole remaining gate. No product
|
||||
questions remain open. Once the API is released, review its exact signatures,
|
||||
update the pinned version and this stage's API mapping, and then resume Stage 7.
|
||||
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.
|
||||
|
||||
Reference in New Issue
Block a user