diff --git a/docs/roadmap/overlays.md b/docs/roadmap/overlays.md new file mode 100644 index 0000000..b9ada44 --- /dev/null +++ b/docs/roadmap/overlays.md @@ -0,0 +1,166 @@ +# Rename Configuration Profiles to Overlays + +Status: approved target, not yet implemented. + +## Purpose and release scope + +ConfigKit's name "profile" collides with application-owned model, pipeline, and +execution profiles. The feature already applies a named configuration overlay; +use that name directly instead of requiring consumers to distinguish another +kind of profile. + +The maintainer has approved a breaking rename for the next minor release, +intended as v0.4.0. There will be no backward-compatibility aliases, deprecated +fields, dual diagnostic names, or legacy-directory fallback. This roadmap does +not authorize publication or changes to downstream repositories. + +The baseline is ConfigKit at `aead20f`, following v0.3.1 and the release-workflow +simplification. Current behavior is owned by the +[selected-profile contract](../config.md#selected-profiles). This roadmap owns +the unimplemented rename; it is not a new current API reference. + +## Target terminology and public surface + +Use **configuration overlay** in introductory prose and **selected overlay** or +**overlay** where context is clear. An overlay is the named configuration input; +overlaying is also the merge operation. CLI overrides may use that operation +without becoming named configuration overlays or changing their CLI provenance. + +| Current surface | Target surface | +| --- | --- | +| `Options[T].Profile string` | `Options[T].Overlay string` | +| `/profiles/.yml` | `/overlays/.yml` | +| Source label `profiles/.yml` | Source label `overlays/.yml` | +| `LayerProfile`, value `"profile"` | `LayerOverlay`, value `"overlay"` | +| `CodeProfileInvalid`, `profile.invalid` | `CodeOverlayInvalid`, `overlay.invalid` | +| `CodeProfileMissing`, `profile.missing` | `CodeOverlayMissing`, `overlay.missing` | +| `CodeProfileOutsideRoot`, `profile.outside_root` | `CodeOverlayOutsideRoot`, `overlay.outside_root` | +| `CodeProfileRepeated`, `profile.repeated` | `CodeOverlayRepeated`, `overlay.repeated` | +| `CodeProfileDirective`, `profile.directive` | `CodeOverlayDirective`, `overlay.directive` | +| `CodeProfileVersion`, `profile.version` | `CodeOverlayVersion`, `overlay.version` | +| `CodeProfileLimitExceeded`, `profile.limit_exceeded` | `CodeOverlayLimitExceeded`, `overlay.limit_exceeded` | +| Maintained example `LoadNarratioProfile` | `LoadNarratioOverlay` | + +Apply these changes to public declarations, engine counterparts, facade +forwarding/conversion, diagnostics, source records, origin/history records, and +rendered explanations. Messages describing this ConfigKit feature use "overlay". +Serialization and output that carry the layer or diagnostic-code strings use +the new values. No legacy values are emitted for compatibility. + +Not every error during loading currently has a `profile.*` code: shared options, +source, import, and parser classifications remain unchanged. This is not an +opportunity to redesign error categories or add new diagnostic guarantees. + +## Behavior preserved + +This is a naming migration, not a new layering model. Preserve the existing +contract except for the explicitly renamed surfaces: + +- Select at most one overlay by name, not a path or list. Preserve the current + ASCII name grammar, case sensitivity, and lack of extension fallback. +- Empty selection and exact lowercase `default` continue to mean no selection. + `overlays/default.yml` is not implicitly loaded. The sentinel is existing + behavior, not a compatibility alias for the old feature name. +- Load the selected mapping after strict base composition and schema-version + checks, before CLI overrides and defaults/typed decoding. Preserve existing + precedence, replacement rules, explicit null/empty behavior, and error ordering. +- Preserve filesystem-context requirements, canonical containment and duplicate + source checks, aggregate limits, directive/version-path rules, and `NoSource` + option validation. Do not strengthen or relax them as part of this rename. +- Preserve source-ID ordering, detached metadata, history, provenance queries, + callback lifetime, secret handling, and load independence. Only the named + layer, selected-file labels/paths, and corresponding diagnostic terminology + change where specified above. +- Keep CLI overrides and strict composition distinct. Do not add overlay stacks, + inheritance, discovery, arbitrary file selection, or new merge options. + +## No backward compatibility + +Old Go identifiers are removed rather than retained as aliases. Applications +using them must update before they compile against the new minor version. + +Selection searches only `overlays/.yml`. A file present solely in +`profiles/` does not satisfy selection and produces the corresponding new +overlay diagnostic. No automatic rename, migration, or search of both locations +is performed. If both directories exist, only the selected path under +`overlays/` participates in this feature. + +Do not introduce a prohibition against a directory named `profiles`, literal +strings containing "profile", or application fields such as `model_profile`. +Ordinary explicit imports retain their existing rules regardless of a file's +directory name. Removing legacy selection support does not reserve or ban these +names elsewhere. + +## Work required from the baseline + +### Public facade and engine + +Update root `lifecycle.go`, `records.go`, and package/API comments along with +their engine counterparts. Rename selection helpers, variables, and tests that +refer to ConfigKit profiles. Preserve root-owned public types and inward-only +dependencies; no facade redesign is needed. + +The existing `internal/engine/overlay.go` owns merge mechanics. Keep that role +distinct from selected-file acquisition: rename `profile.go` and its tests to +`selected_overlay.go` and `selected_overlay_test.go`, with names such as +`loadSelectedOverlayDocument` for acquisition. Do not combine unrelated code +merely to resolve the filename collision. Update option validation, directive +checks, input loading, and explanation rendering consistently. + +### Tests and maintained consumer examples + +Migrate existing coverage and fixtures rather than duplicating the entire suite. +Update assertions for layer/code values, labels, paths, and rendered output; +retain all existing semantic assertions under the new terminology. + +Add focused regression evidence that selection uses `overlays/`, never falls +back to `profiles/`, and chooses only `overlays/` when both exist. Preserve coverage +for empty/default selection, invalid and missing names, root containment, +version/directive rules, source budgets, CLI precedence, and provenance/history. +Existing public-boundary and consumer tests must continue to pass after their +API migration. A source/API review must confirm that old exported names were +removed, not hidden behind aliases. + +Move the maintained Narratio fixture from `profiles/testing.yml` to +`overlays/testing.yml`, update the example helper and callers, and keep its +application-owned `ModelProfile` / `model_profile` unchanged. This distinction is +part of the motivation for the rename, not leftover work. + +### Documentation and consumer migration + +Update the canonical configuration heading and inbound links, public Go +reference comments, README, architecture policy terminology, development +test map, consumer guide, and implemented-component descriptions as applicable. +The architecture itself remains unchanged. + +Do not globally replace every occurrence of "profile". Preserve immutable +historical release notes and accepted ADR decision content. Preserve upstream +symbol names and revision-specific evidence in the extraction inventory while +updating its descriptions of the current ConfigKit implementation. Historical +navigation links may be repaired when headings or files move. + +At release preparation, the version-matched minor-release note must explicitly +describe the breaking API, directory, provenance-layer, and diagnostic-code +changes. Consumer instructions must cover updating Go identifiers, moving +selected files to `overlays/`, and updating any downstream output/diagnostic +handling. Applications own any corresponding CLI flag rename; ConfigKit does +not define or modify downstream CLIs. Do not create a release note before an +actual reviewed release candidate exists. + +## Completion criteria + +The rename is complete when all maintained consumers compile against the new +API, selection and reporting consistently use the new terminology, the legacy +feature surface is absent, and regression coverage confirms unchanged semantics +and no directory fallback. Remaining "profile" references must be intentional +application data, migration explanation, or historical records, not active +ConfigKit feature names. + +Validate locally under the [testing policy](../policy/testing.md), including +affected behavioral tests, examples, documentation links, facade boundaries, +formatting, vet, and builds. Publication is a separate task governed by the +[release procedure](../release.md); neither CI waiting nor additional release +gates are introduced by this roadmap. + +After implementation, current contracts own the renamed behavior and this +roadmap becomes a completion record for retirement during release preparation.