From b27fe0598a9540ad05eefe2868a5a243eb28111e Mon Sep 17 00:00:00 2001 From: Eric Rakestraw Date: Mon, 2 Nov 2026 00:19:10 +0000 Subject: [PATCH] Allow ordinary config data at the application root --- docs/roadmap/config-directives.md | 103 ++++++++++++++---------------- 1 file changed, 47 insertions(+), 56 deletions(-) diff --git a/docs/roadmap/config-directives.md b/docs/roadmap/config-directives.md index c891938..9737bea 100644 --- a/docs/roadmap/config-directives.md +++ b/docs/roadmap/config-directives.md @@ -1,8 +1,8 @@ # Document-Root Configuration Controls Status: proposed implementation of the agreed `config` spelling and -document-root-only reservation. The remaining application-root boundary choice -is recorded under Open Decisions. +source-document-root-only reservation. Ordinary application-root `config` data +created through placement or later lifecycle operations is permitted. Planning baseline: `1e69abc88cf748537cd7febc85e0743755fa2fc1`. @@ -103,21 +103,41 @@ provider settings in the first example, `fragments/provider.yml` can contain `/providers/primary/config`. Its filesystem paths still resolve from the declaring file under the existing resource-context rules. +### Application-root data from non-document operations + +Input placement, mounted imports, typed defaults, CLI overrides, and application +resolution may produce ordinary `config` data at the final application root, +following their existing schema and lifecycle rules. Controls are recognized +only during source-document extraction. For example, a fragment containing +`timeout: 10s` can be placed at destination `[config]`, producing application +data at `/config/timeout`. A CLI assignment to `Keys("config", "timeout")` +addresses that data rather than introducing a control. Collection declarations +and registrations can likewise address actual data at that application path. + +This keeps the reservation document-local. Placement and later lifecycle +operations do not reinterpret their output as another source document, and no +additional schema or callback restriction reserves the final root namespace. +Inspection can show a root `config` value without reinterpreting it; effective +YAML retains its existing lack of a reloadability guarantee. Explain +source-local control coordinates and assembled application coordinates +separately, even when their path text is the same; this requires no new +inspection-record format. + ### Consistent application-path handling -Allow nested application paths containing literal `config` in input placement, -relative import destinations, collection declarations and registrations, CLI -paths and values, version fields, and inspection queries, subject to each -operation's existing rules. In particular, a relative destination beginning -with `config` can legitimately refer to a nested application mapping after the -parent destination is applied. Do not decide its meaning from that relative -segment alone. +Allow application paths containing literal `config`, at root or nested, in +input placement, relative import destinations, collection declarations and +registrations, CLI paths and values, version fields, and inspection queries. +Each operation retains its existing rules. In particular, a relative destination +beginning with `config` can legitimately refer to a nested application mapping +after the parent destination is applied. Do not decide its meaning from that +relative segment alone. Protect actual source-root controls during source-version extraction while allowing version fields below an ordinary nested `config` mapping. Preserve main-version ownership, non-main header consumption, and existing version modes. -Root application values produced through placement or later lifecycle inputs -are the distinct boundary choice recorded under Open Decisions. +An assembled application path beginning with `config` does not by itself +establish overlap with an actual source-document control block. `extends` keeps its existing inheritance meaning, scope, and CLI restrictions. Allowing `config` in application data does not make other invalid paths, unknown @@ -134,9 +154,9 @@ may accept an old block as data without executing its imports. Directive-related paths in diagnostics and source evidence change to the new spelling, such as `/config/imports/0`. Preserve authored locations, source IDs, effective placement, history, sensitivity, and resource ownership. Application -values under nested `config` receive the same metadata and safe inspection as -other ordinary fields, including explicit false, zero, empty, and null values -where supported by the schema. +values under root or nested `config` receive the same metadata and safe +inspection as other ordinary fields, including explicit false, zero, empty, +and null values where supported by the schema. The Go package name, vanity module path, exported symbol names, `configkit:"secret"` struct tag, and library diagnostic prefix remain unchanged. @@ -156,8 +176,8 @@ and version/control overlap detection as a coordinated change. Retain shared helpers when their callers need the same rule; distinguish source-local control coordinates from effective application coordinates where their responsibilities differ. Do not carry a global name ban into a helper merely by replacing its -string constant. Resolve the application-root decision below before preparing -the detailed implementation plan. +string constant. Allow ordinary application-root `config` data through +placement and later lifecycle operations without re-extracting controls. Keep the existing engine and facade boundaries. No configurable control name, new provider abstraction, or change to composition algorithms is needed. @@ -169,7 +189,8 @@ existing accepted decisions as historical records. Update applicable local architecture-policy descriptions when the behavior lands. The current [configuration reference](../config.md), public comments, and [consumer guide](../consumers/README.md) should explain the new syntax, -per-source root boundary, and ordinary nested fields together. +per-source root boundary, ordinary nested fields, and application-root data +created through non-document operations together. Migrate maintained examples, fixtures, and behavioral expectations for genuine control blocks. Preserve literal `configkit` occurrences that identify the Go @@ -197,6 +218,10 @@ behavioral coverage at the boundaries this change affects: - Mounted inputs and relative destinations distinguish source roots from application paths, including a relative destination beginning with `config`. Collection registrations and nested version fields follow that distinction. +- Placement, defaults, CLI overrides, and recorded resolution can produce + ordinary application-root `config` data. Collection declarations, + registrations, and inspection can address it. Source controls are still + extracted before mounting and are not rediscovered in the resulting data. - Ordinary `configkit` and `_configkit` data no longer trigger controls or name-based rejection. Genuine old control syntax is not executed as an alias. - Source-local directive evidence uses `/config/...`; ordinary application @@ -204,42 +229,8 @@ behavioral coverage at the boundaries this change affects: with final values. Existing inheritance and protected-version checks remain effective. -Add cases for the application-root outcome once selected. Verify behavior with -independent expectations, rather than a test that only checks a renamed -constant. Reuse existing coverage for unchanged semantics, run the appropriate -focused checks and everyday validation, and check documentation links. No new -release gate, security guarantee, or performance threshold follows from this -roadmap. - -## Open Decisions - -### May non-document operations produce application-root `config` data? - -The agreed source-document rule settles authored input: root `config` is a -control block and nested `config` is data. It does not by itself settle whether -an effective root `/config` may be produced by `Input.Destination`, mounted -imports, typed defaults, CLI overrides, or application resolution. - -**Recommendation:** Allow these operations to produce ordinary root application -data, following their existing schema and lifecycle rules. Recognize controls -only at source-document extraction. For example, a fragment containing -`timeout: 10s` could be placed at destination `[config]`; a CLI assignment to -`Keys("config", "timeout")` would address data rather than introduce a control. -Collection declarations and registrations could likewise address actual data -at that application path. This keeps the reservation strictly document-local, -avoids adding a separate schema or callback restriction, and treats later -operations as data processing rather than new document parsing. Inspection can -show a root `config` value without reinterpreting it; effective YAML already has -no reloadability guarantee. The cost is that the same textual path can describe -source controls or assembled application data, so documentation must distinguish -those coordinates clearly. - -**Alternative:** Also reserve `/config` as an application-root namespace, -while allowing nested paths such as `/providers/primary/config`. This keeps -source-root and final-root vocabulary aligned. It requires defining consistent -behavior for destinations, collection selectors, CLI values, defaults, -resolution output, and relevant version paths; changing only the source parser -or CLI checks would leave gaps. It also restricts application data beyond the -agreed source-document reservation. Choose this alternative only as an explicit -additional policy decision, with its validation boundary defined before -implementation. +Verify behavior with independent expectations, rather than a test that only +checks a renamed constant. Reuse existing coverage for unchanged semantics, run +the appropriate focused checks and everyday validation, and check documentation +links. No new release gate, security guarantee, or performance threshold follows +from this roadmap.