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

View File

@@ -1,6 +1,6 @@
# Implement Document-Root Configuration Controls # Implement Document-Root Configuration Controls
Status: ready for implementation by a Luna coding agent. Status: complete.
Implementation baseline: `b27fe0598a9540ad05eefe2868a5a243eb28111e`. Implementation baseline: `b27fe0598a9540ad05eefe2868a5a243eb28111e`.
The [feature roadmap](config-directives.md) owns the target and its rationale; 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 ## 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 1. Search current production code, tests, examples, and docs for old root
controls, recursive name bans, and stale declaration paths. Review each controls, recursive name bans, and stale declaration paths. Review each
remaining old spelling in context; retained package names, tags, error 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"` Config settings `yaml:"config"`
} }
entryExplicit := false entryExplicit := false
entryCountExplicit := false
result, err := configkit.Load[app](configkit.NoSource(), configkit.Options[app]{ result, err := configkit.Load[app](configkit.NoSource(), configkit.Options[app]{
Definition: configkit.Definition[app]{ Definition: configkit.Definition[app]{
Defaults: func() app { return app{Config: settings{Enabled: true, Count: 2}} }, Defaults: func() app { return app{Config: settings{Enabled: true, Count: 2}} },
Resolve: func(value *app, r *configkit.Resolution) error { Resolve: func(value *app, r *configkit.Resolution) error {
info, ok := r.EntryInfo(configkit.Keys("config", "enabled")) info, ok := r.EntryInfo(configkit.Keys("config", "enabled"))
entryExplicit = ok && info.Explicit && info.Origin.Layer == configkit.LayerCLI entryExplicit = ok && info.Explicit && info.Origin.Layer == configkit.LayerCLI
entryCountExplicit = r.IsExplicit(configkit.Keys("config", "count"))
value.Config.Count = 7 value.Config.Count = 7
r.RecordNormalization(configkit.Keys("config", "count"), "normalize count") r.RecordNormalization(configkit.Keys("config", "count"), "normalize count")
return nil return nil
@@ -91,12 +93,15 @@ func TestDefaultsOverridesAndResolutionAtConfigRoot(t *testing.T) {
}, },
Overrides: []configkit.Override{{Path: configkit.Keys("config", "enabled"), Value: false, Flag: "--enabled"}}, 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) 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 { 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) 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 { if _, ok := result.Explain(configkit.Keys("config", "count")); !ok {
t.Fatal("missing resolution explanation") 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")}, "root/shared.yml": &fstest.MapFile{Data: []byte("name: imported\n")},
}) })
source := configkit.Mapping("programmatic", map[string]any{ source := configkit.Mapping("programmatic", map[string]any{
"config": map[string]any{"imports": []any{map[string]any{"path": "shared.yml"}}}, "config": map[string]any{"imports": []any{map[string]any{"path": "shared.yml"}}},
"enabled": true, "enabled": true,
}) })
result, err := configkit.Load(source, configkit.Options[mappingFacadeConfig]{ result, err := configkit.Load(source, configkit.Options[mappingFacadeConfig]{
Imports: true, Filesystem: &configkit.FilesystemContext{Root: "root", BaseDir: "root", FS: &namespace}, Imports: true, Filesystem: &configkit.FilesystemContext{Root: "root", BaseDir: "root", FS: &namespace},