Complete the document-root control migration review

This commit is contained in:
2026-11-02 00:46:56 +00:00
parent 68ec552b52
commit c63f4ff687
4 changed files with 24 additions and 20 deletions

View File

@@ -1,8 +1,8 @@
# Document-Root Configuration Controls
Status: proposed implementation of the agreed `config` spelling and
source-document-root-only reservation. Ordinary application-root `config` data
created through placement or later lifecycle operations is permitted.
Status: implemented. The `config` spelling and source-document-root-only
reservation are in effect. Ordinary application-root `config` data created
through placement or later lifecycle operations is permitted.
Planning baseline: `1e69abc88cf748537cd7febc85e0743755fa2fc1`.
@@ -13,22 +13,19 @@ to use nested `config` fields for their own settings. An application that select
ConfigKit adopts one control syntax; it should not need a configurable keyword
or a second configuration-processing pass.
This roadmap defines the target and the work needed to reach it. The
[implementation plan](implementation.md) owns staged execution and progress.
Neither document changes current behavior. The
[configuration contract](../config.md) and public Go declarations remain
authoritative until implementation lands.
This roadmap records the target and rationale. The [implementation plan](implementation.md)
records execution and validation. The [configuration contract](../config.md)
and public Go declarations own current behavior.
## Current Baseline
## Prior Baseline
ConfigKit uses a root `configkit` mapping for `imports` and `sequences` controls.
The [directive implementation](../../internal/engine/directives.go) extracts
those controls before source placement and composition. Nested occurrences of
`configkit` are rejected, including within application mappings and sequences.
Imports-disabled and selected-overlay paths have their own checks enforcing
that reservation.
At the planning baseline, ConfigKit used a root `configkit` mapping for `imports`
and `sequences` controls, extracted before placement and composition. Nested
occurrences of `configkit` were rejected, including within application mappings
and sequences. Imports-disabled and selected-overlay paths enforced that
reservation separately.
The reservation also reaches beyond parsing:
The reservation also reached beyond parsing:
- [Destination validation](../../internal/engine/destination.go) rejects
`configkit` in every segment. Its helpers also serve import destinations,

View File

@@ -1,6 +1,6 @@
# Implement Document-Root Configuration Controls
Status: ready for implementation by a Luna coding agent.
Status: complete.
Implementation baseline: `b27fe0598a9540ad05eefe2868a5a243eb28111e`.
The [feature roadmap](config-directives.md) owns the target and its rationale;
@@ -323,6 +323,8 @@ document.
## Stage 10 — Complete the integration and scope review
**Status:** Complete. Reviewed the implementation and retained old spellings in context; `./scripts/check.sh` passed with Go 1.26.8 on Linux, including formatting, whitespace, tests, vet, and build.
1. Search current production code, tests, examples, and docs for old root
controls, recursive name bans, and stale declaration paths. Review each
remaining old spelling in context; retained package names, tags, error

View File

@@ -78,12 +78,14 @@ func TestDefaultsOverridesAndResolutionAtConfigRoot(t *testing.T) {
Config settings `yaml:"config"`
}
entryExplicit := false
entryCountExplicit := false
result, err := configkit.Load[app](configkit.NoSource(), configkit.Options[app]{
Definition: configkit.Definition[app]{
Defaults: func() app { return app{Config: settings{Enabled: true, Count: 2}} },
Resolve: func(value *app, r *configkit.Resolution) error {
info, ok := r.EntryInfo(configkit.Keys("config", "enabled"))
entryExplicit = ok && info.Explicit && info.Origin.Layer == configkit.LayerCLI
entryCountExplicit = r.IsExplicit(configkit.Keys("config", "count"))
value.Config.Count = 7
r.RecordNormalization(configkit.Keys("config", "count"), "normalize count")
return nil
@@ -91,12 +93,15 @@ func TestDefaultsOverridesAndResolutionAtConfigRoot(t *testing.T) {
},
Overrides: []configkit.Override{{Path: configkit.Keys("config", "enabled"), Value: false, Flag: "--enabled"}},
})
if err != nil || result == nil || !entryExplicit || result.Config.Config.Enabled || result.Config.Config.Count != 7 {
if err != nil || result == nil || !entryExplicit || entryCountExplicit || result.Config.Config.Enabled || result.Config.Config.Count != 7 {
t.Fatalf("result = %#v, entry explicit = %t, error = %v", result, entryExplicit, err)
}
if info, ok := result.Metadata().Lookup(configkit.Keys("config", "enabled")); !ok || !info.Explicit || info.Origin.Layer != configkit.LayerCLI {
t.Fatalf("final enabled info = %#v, %t", info, ok)
}
if info, ok := result.Metadata().Lookup(configkit.Keys("config", "count")); !ok || info.Origin.Layer != configkit.LayerResolution {
t.Fatalf("final count info = %#v, %t", info, ok)
}
if _, ok := result.Explain(configkit.Keys("config", "count")); !ok {
t.Fatal("missing resolution explanation")
}

View File

@@ -80,8 +80,8 @@ func TestFacadeMappingImportsUseExplicitContext(t *testing.T) {
"root/shared.yml": &fstest.MapFile{Data: []byte("name: imported\n")},
})
source := configkit.Mapping("programmatic", map[string]any{
"config": map[string]any{"imports": []any{map[string]any{"path": "shared.yml"}}},
"enabled": true,
"config": map[string]any{"imports": []any{map[string]any{"path": "shared.yml"}}},
"enabled": true,
})
result, err := configkit.Load(source, configkit.Options[mappingFacadeConfig]{
Imports: true, Filesystem: &configkit.FilesystemContext{Root: "root", BaseDir: "root", FS: &namespace},