From eec214944c46a49b65b7b764b048dd6f6ff2ae7a Mon Sep 17 00:00:00 2001 From: Eric Rakestraw Date: Sat, 24 Oct 2026 16:24:57 +0000 Subject: [PATCH] Align discovery ownership and contributor documentation --- README.md | 5 +++ docs/consumers/README.md | 15 +++++++++ docs/development.md | 2 ++ docs/internal/overview.md | 27 +++++++++------ docs/policy/architecture.md | 16 ++++++--- docs/roadmap/discovery.md | 61 ++++++++++++++++------------------ docs/roadmap/implementation.md | 4 +-- 7 files changed, 81 insertions(+), 49 deletions(-) diff --git a/README.md b/README.md index e0ef9a4..ae23e85 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,11 @@ ConfigKit does not search conventional application paths implicitly. See the and [ADR 0015](docs/adr/0015-shared-dependency-ready-ordering.md) and [ADR 0016](docs/adr/0016-independent-import-controls.md). +Main-file discovery is explicit too: applications choose and order `Search` +descriptions and pass `SearchConfig` to the existing load APIs. See the +[discovery contract](docs/config.md#configuration-discovery), [consumer guide](docs/consumers/README.md#explicit-main-file-discovery), +and [ADR 0019](docs/adr/0019-explicit-configuration-discovery.md). + ```go type Config struct { Enabled bool `yaml:"enabled"` diff --git a/docs/consumers/README.md b/docs/consumers/README.md index d4766fe..3474fcf 100644 --- a/docs/consumers/README.md +++ b/docs/consumers/README.md @@ -55,6 +55,21 @@ both without redefining their syntax. ConfigKit overlays are configuration overl they do not select or replace an application's LLM, model, pipeline, report, or execution profile concepts. +## Explicit main-file discovery + +Applications choose the search conventions and their precedence, then pass the +resulting `SearchConfig` source to the same `Load` or `LoadLayered` entry point. +For example, the maintained sequence catalog puts a caller-selected file before +a custom directory fallback while keeping its underlay and overlay choices +independent. See [`sequence_catalog.go`](../../examples/consumers/sequence_catalog.go) +and its [behavior tests](../../examples/consumers/sequence_catalog_test.go), plus +the [working-directory executable example](../../examples/consumers/discovery_test.go). +Together, the root-owned [discovery API](../../discovery.go) and [configuration +discovery contract](../config.md#configuration-discovery) define ordered +concatenation, directory-first Cartesian expansion, optional exhaustion, and +selected-file behavior. [ADR 0019](../adr/0019-explicit-configuration-discovery.md) +records why discovery is explicitly selected. + ## Import defaults and selection inspection `Options.ImportDefaults` and `LayeredOptions.ImportDefaults` apply one diff --git a/docs/development.md b/docs/development.md index eb290e7..7754d08 100644 --- a/docs/development.md +++ b/docs/development.md @@ -63,6 +63,7 @@ Accepted decisions: - [Separate import selection controls](adr/0016-independent-import-controls.md) - [Define identity and merge rules for each collection](adr/0017-collection-sequence-policy.md) - [Apply CLI overrides after inheritance and decoding](adr/0018-cli-after-structural-resolution.md) +- [Keep main-file discovery explicit and composable](adr/0019-explicit-configuration-discovery.md) For cross-cutting changes, follow every applicable row. Completed implementation and remediation plans are preserved in Git history at `cb5b435`; use current @@ -231,6 +232,7 @@ code changes. Use the component overview to find the corresponding implementatio | --- | --- | --- | | YAML syntax, diagnostics, parser limits | [Adapter tests](../internal/yaml/parse_test.go), [source translation](../internal/engine/parse_test.go) | `go test ./internal/yaml` and `go test ./internal/engine -run '^TestParseSource'` | | File/reader access, imports, globs, containment | [Sources](../internal/engine/source_test.go), [FIFO](../internal/engine/source_fifo_test.go), [imports](../internal/engine/imports_test.go), [relative destinations](../internal/engine/destination_import_test.go), [globs](../internal/engine/glob_test.go) | `go test ./internal/engine -run 'Source\|Import\|Glob\|Filesystem\|Nonregular\|RegularFile'` | +| Explicit main-file discovery and absent-input loading | [Candidate selection](../internal/engine/discovery_test.go), [load integration](../internal/engine/discovery_load_test.go), [public facade](../facade_discovery_test.go), and maintained [catalog](../examples/consumers/sequence_catalog_test.go) and [preset](../examples/consumers/discovery_test.go) examples | `go test ./internal/engine -run 'Discovery|Search'`, `go test . -run 'Search'`, and `go test ./examples/consumers -run 'WorkingDirectoryPreset|SequenceCatalog'` | | Import defaults, empty-selection evidence, and dependency-ready ordering | [Defaults and facade evidence](../facade_import_defaults_test.go), [engine import evidence](../internal/engine/import_evidence_test.go), [scheduler](../internal/engine/dependency_order_test.go), [scheduling integrations](../internal/engine/imports_test.go) | `go test ./internal/engine -run 'Import|ScheduleDependencies|Inheritance'`, `go test . -run 'ImportDefaults|FacadeImport'`, and `go test ./examples/consumers` | | Native filesystem and mapping sources | [Native acquisition](../internal/engine/native_filesystem_test.go), [filesystem facade](../facade_filesystem_test.go), [mapping facade](../facade_mapping_test.go) | `go test ./internal/engine -run 'NativeFilesystem'` and `go test . -run 'TestFacade'` | | Composition, selected overlays, CLI precedence | [Composition](../internal/engine/compose_test.go), [overlay](../internal/engine/overlay_test.go), [selected overlays](../internal/engine/selected_overlay_test.go), [overrides](../internal/engine/override_test.go) | `go test ./internal/engine -run 'Compose\|Overlay\|Override'` | diff --git a/docs/internal/overview.md b/docs/internal/overview.md index 8d93eac..f0fdeb2 100644 --- a/docs/internal/overview.md +++ b/docs/internal/overview.md @@ -7,10 +7,13 @@ private state; public signatures and fields do not expose engine types. Implemented component owners: -- `internal/engine` owns host and native-filesystem source acquisition, - grouped strict composition, recursive precedence assembly, per-input mapping - and sequence-item placement, YAML collection declarations and operations for - identified sequences, and application identity registrations for strict +- `internal/engine` owns host and native-filesystem source acquisition and + explicitly selected configuration discovery. A search resolves once during + shared acquisition; the selected concrete file or absent-input state then + follows the existing composition, metadata, and resource-context lifecycle. + It also owns grouped strict composition, recursive precedence assembly, + per-input mapping and sequence-item placement, YAML collection declarations + and operations for identified sequences, and application identity registrations for strict composition, inheritance, and final validation. It applies the selected collection operation at precedence boundaries and owns dependency-ready, destination-local inheritance before typed decoding. CLI assignment follows @@ -31,9 +34,9 @@ Implemented component owners: or records. Callback wrappers pass only live engine context during a callback; `Result.Config` is detached and its private inspection remains frozen independently. -- Root conversion files explicitly cross the path, record, callback, secret, and - error boundaries. There are no public aliases, anonymous engine embeddings, or - public engine bridge methods. +- Root conversion files explicitly cross the path, record, callback, secret, + search-description, and error boundaries. There are no public aliases, + anonymous engine embeddings, or public engine bridge methods. - Root `Diff` and `Difference` provide the public comparison boundary and convert detached engine records to root-owned paths and snapshots; consumer examples own presentation of the safe changed regions. @@ -53,7 +56,9 @@ these constraints and rejects exported aliases, fields, or signatures involving internal types. The [configuration contract](../config.md) owns implemented YAML and lifecycle -semantics, including [input destinations](../config.md#input-destinations), +semantics, including +[configuration discovery](../config.md#configuration-discovery), +[input destinations](../config.md#input-destinations), [shared source-version checks](../config.md#shared-source-version-checks), and [effective configuration diffs](../config.md#effective-configuration-diffs). The [strict composition contract](../config.md#strict-document-composition) @@ -78,5 +83,7 @@ records the shared dependency-ready ordering decision; [ADR 0016](../adr/0016-independent-import-controls.md) records the independent selection controls. [ADR 0017](../adr/0017-collection-sequence-policy.md) and [ADR 0018](../adr/0018-cli-after-structural-resolution.md) record collection -operations and CLI ordering. The [import internals](imports.md) document candidate and -namespace identities, discovery and scheduling, and the bounded algorithms. +operations and CLI ordering. [ADR 0019](../adr/0019-explicit-configuration-discovery.md) +records explicit main-file discovery. The [import internals](imports.md) +document candidate and namespace identities, discovery and scheduling, and the +bounded algorithms. diff --git a/docs/policy/architecture.md b/docs/policy/architecture.md index 926ef91..1c6c6c8 100644 --- a/docs/policy/architecture.md +++ b/docs/policy/architecture.md @@ -144,8 +144,12 @@ remains in the roadmap until implemented. ConfigKit owns configuration input processing and the coordination of decoding, resolution, validation, and inspection. Applications own their configuration types, field meanings, defaults, normalization, semantic validation, and schema -version policy. Applications also own main-file search conventions, CLI wiring, -remote acquisition, runtime initialization, and resource checks. +version policy. Applications choose and order their main-file search conventions; +ConfigKit provides explicitly selected search descriptions that resolve during +loading. Applications also own CLI wiring, remote acquisition, runtime +initialization, and resource checks. See the [configuration discovery +contract](../config.md#configuration-discovery) and [ADR +0019](../adr/0019-explicit-configuration-discovery.md). The engine applies each input's mapping destination within the existing source assembly, applies immediate-parent-relative YAML destinations to imports, and @@ -157,11 +161,13 @@ placement, and [ADR 0012](../adr/0012-relative-import-destinations.md) records the import extension. Library code must not depend on consuming applications or initialize their -runtime resources. It must not perform implicit network access, discover -application-specific paths, or change process-global state during ordinary `Load`. +runtime resources. It must not perform implicit network access, implicitly +discover application-specific paths, or change process-global state during +ordinary `Load`. Import discovery is available only through declarations in selected sources: explicit `path`, `dir`, and `glob` selectors may search their declared scope, but -ConfigKit does not search conventional application paths or discover a main +ConfigKit does not search conventional application paths unless the application +explicitly supplies a discovery description, and it never discovers a main configuration file implicitly. Imports and sibling inheritance share dependency-ready scheduling within their existing scopes; acquisition order and precedence-tier boundaries remain distinct. The [configuration contract](../config.md#explicit-imports) diff --git a/docs/roadmap/discovery.md b/docs/roadmap/discovery.md index 00b62fd..4f04808 100644 --- a/docs/roadmap/discovery.md +++ b/docs/roadmap/discovery.md @@ -1,10 +1,10 @@ # Composable Configuration Discovery Roadmap -Status: proposal with OD-1 through OD-5 and the final review clarifications -settled and integrated below. -This document describes future work, not an implemented contract. The -[implementation plan](implementation.md) owns the staged work and concrete API -decisions. +Status: implemented. This document preserves the design rationale and agreed +direction. The [configuration contract](../config.md#configuration-discovery) +owns current behavior, [ADR 0019](../adr/0019-explicit-configuration-discovery.md) +records the decision, and the [implementation plan](implementation.md) records +the completed work sequence. ## Purpose And Ownership @@ -24,23 +24,22 @@ Discovery selects one source for the existing loading lifecycle. It does not create additional configuration tiers or merge every matching file. Existing layered loading remains available when consumers intentionally combine sources. -## Current Baseline +## Baseline Before Implementation -The [source contract](../config.md#sources) provides explicit host files, native -filesystem files, bytes, readers, mappings, and `NoSource()`. A missing explicit -file fails. The zero source is invalid. There is no conventional main-file search. +Before this work, sources included explicit host files, native filesystem files, +bytes, readers, mappings, and `NoSource()`, with no conventional main-file search. +That baseline also restricted `NoSource()` with imports and overlays. The +implemented discovery behavior now lets an exhausted optional search follow the +absent-main lifecycle, including enabled imports and an active overlay when its +required explicit context is supplied. The current [source contract](../config.md#sources), +[single-source loading](../config.md#single-source-loading), and +[layered loading](../config.md#layered-loading) sections define the behavior; +this baseline is retained only to explain the original design problem. -[Ordinary loading](../config.md#single-source-loading) infers a selected overlay's -filesystem context from the main source. `NoSource()` currently rejects enabled -imports, active overlays, and filesystem context. In -[layered loading](../config.md#layered-loading), an absent main input can coexist -with underlays; a selected overlay requires an explicit `OverlayFilesystem`. -These distinctions matter when an optional search finds nothing. - -The [architecture policy](../policy/architecture.md#responsibility-boundaries) -assigns search conventions to consumers and currently excludes implicit main-file -discovery. The addition should clarify that consumers may explicitly select -library-provided search conventions. Consumer ownership remains unchanged. +Applications still choose search conventions and ordering. The architecture +policy now distinguishes those consumer choices from explicitly selected search +descriptions resolved during loading, while continuing to exclude implicit +discovery and network acquisition. ## Agreed Direction @@ -92,11 +91,10 @@ Different directories may select different lists, so ordered expansion and concatenation describes the complete model. Set union does not express its precedence semantics. -The eventual documentation should explain this model using the applicable -mathematical nomenclature: ordered lists, ordered concatenation, and Cartesian -product where a shared filename list applies. Retain these names in relevant -implementation comments where they help readers understand the operations. The -model describes ordering without requiring eager construction of every candidate. +The [configuration contract](../config.md#configuration-discovery) explains this +model using ordered lists, ordered concatenation, and the directory-first +Cartesian product where a shared filename list applies. These terms describe +ordering without requiring eager construction of every candidate. ### Unix System Preset @@ -242,8 +240,8 @@ platform's convention. User, home, and working-directory presets use their nativ Go directory helpers. This keeps search priority predictable when directory resolution fails. Consumers -select the presets appropriate to their application and environment; this proposal -does not add an option to skip unavailable bases or unsupported presets. +select the presets appropriate to their application and environment; there is no +option to skip unavailable bases or unsupported presets. ### No Match, Imports, And Selected Overlays (OD-3 — Settled) @@ -273,10 +271,9 @@ the normal lifecycle. Main-version checking receives an absent main input and may reject it under the application's existing policy. Create no synthetic empty document or source record for the absent main file. -This deliberately relaxes the current `NoSource()` restrictions on imports and +This deliberately relaxes the former `NoSource()` restrictions on imports and on overlays with explicit context. Both ways of obtaining an absent main input -have the same behavior. Implementation must cover this lifecycle change as well -as candidate selection. +have the same behavior, as defined in the [configuration contract](../config.md#configuration-discovery). ### Empty Composition And Implicit Preset Selection (OD-4 — Settled) @@ -339,8 +336,8 @@ Missing candidates are not acquired sources and do not create source IDs, configuration history, or explicit input presence. An entirely absent search contributes no synthetic empty configuration file. Diagnostics should distinguish an exhausted required search from a failed candidate. Existing selected-source -inspection remains the foundation; a new public per-attempt trace is not needed -for this proposal. +inspection remains the foundation; a new public per-attempt trace is not part of +the implemented API. Preserve collection policies, inheritance, source-version rules, CLI ordering, final validation, and frozen inspection after selection. Search-list order does diff --git a/docs/roadmap/implementation.md b/docs/roadmap/implementation.md index 6915f5b..12cdf4a 100644 --- a/docs/roadmap/implementation.md +++ b/docs/roadmap/implementation.md @@ -1,6 +1,6 @@ # Configuration Discovery Implementation Plan -Status: in progress. Stages 1, 2, 3, 4, 5, 6, 7, and 8 are complete. +Status: in progress. Stages 1 through 9 are complete. Implement the target behavior in [the discovery roadmap](discovery.md). That document owns the selected conventions and OD-1 through OD-5; this plan owns the @@ -402,7 +402,7 @@ Acceptance: representative consumers need no application-side fallback loader or provenance reconstruction. Run maintained consumer tests, relevant executable examples, and the everyday check. Mark and commit. -## Stage 9 — Align Architecture And Contributor Documentation +## Stage 9 — Align Architecture And Contributor Documentation (Complete) 1. Update the architecture policy's responsibility boundary narrowly: applications choose main-file conventions; explicit library-provided searches execute