diff --git a/docs/adr/0006-public-facade.md b/docs/adr/0006-public-facade.md index db32c36..90c413c 100644 --- a/docs/adr/0006-public-facade.md +++ b/docs/adr/0006-public-facade.md @@ -37,8 +37,9 @@ relocation mechanism, not a second supported package, feature path, or runtime selection mechanism; the final cutover removed it and the old root implementation. The [architecture policy](../policy/architecture.md#public-api-and-dependency-direction) -owns the binding boundary. The [public-facade roadmap](../roadmap/public.md) -owns the intended end state and its implementation plan owns progress. +owns the binding boundary. The [component overview](../internal/overview.md) +describes the implemented layout; the [development guide](../development.md) +locates the completed roadmap and implementation history. ## Alternatives considered diff --git a/docs/development.md b/docs/development.md index ec0eedb..f278a78 100644 --- a/docs/development.md +++ b/docs/development.md @@ -47,11 +47,12 @@ The completed string-and-integer schema-version implementation and remediation records are preserved in Git history at `244104f`. The [configuration contract](config.md#application-schema-versions) owns current behavior. -The completed [source-origins during resolution record](roadmap/source-origins-during-resolution.md) -links to the current contract and evidence. Its completed implementation handoffs -are preserved at `28e7fc5:docs/roadmap/implementation.md`; inspect them with -`git show 28e7fc5:docs/roadmap/implementation.md` until release preparation -retires the completed roadmap material. +The completed source-origins and public-facade roadmaps, implementation plan, and +resolved review findings are preserved in Git history at `5760614`, for example +`git show 5760614:docs/roadmap/remediation.md`. The earlier source-origins staged +plan remains at `28e7fc5:docs/roadmap/implementation.md`. Current resolution +behavior belongs to the [configuration contract](config.md#recorded-application-resolution), +and current facade ownership belongs to the [component overview](internal/overview.md). ## Baseline validation diff --git a/docs/policy/architecture.md b/docs/policy/architecture.md index 32f1bf4..2d7ffbf 100644 --- a/docs/policy/architecture.md +++ b/docs/policy/architecture.md @@ -85,8 +85,8 @@ but internal production packages must not import the root. Explicit forwarding and local conversion are acceptable where they preserve type identity, ownership, callback lifetime, and inspection behavior. The accepted root-wrapper boundary and its migration rationale are recorded in -[ADR 0006](../adr/0006-public-facade.md); completed implementation evidence is -recorded in the public-facade roadmap. +[ADR 0006](../adr/0006-public-facade.md); the implemented layout is described in +the [component overview](../internal/overview.md). Separate input access, document processing, composition, decoding, metadata, and rendering responsibilities without prescribing an interface or package for each. diff --git a/docs/policy/release.md b/docs/policy/release.md index 3e6ff52..449b89e 100644 --- a/docs/policy/release.md +++ b/docs/policy/release.md @@ -46,7 +46,7 @@ is no guarantee that each release has been validated on macOS. The [release procedure](../release.md#release-identity-and-support) owns target architectures and required Linux checks. This support change applies to upcoming releases; historical release notes and their validation records remain unchanged. -The next release note must explain the change in Compatibility, with version +The v0.3.0 release note must explain the change in Compatibility, with version selection following this policy's existing compatibility rules. ## Release Model diff --git a/docs/releases/v0.3.0.md b/docs/releases/v0.3.0.md new file mode 100644 index 0000000..fff4f9d --- /dev/null +++ b/docs/releases/v0.3.0.md @@ -0,0 +1,70 @@ +# ConfigKit v0.3.0 + +This release adds source provenance during application resolution, separates the +public API from its internal engine, and moves macOS to best-effort support. + +## Summary + +Resolvers can query fixed entry-state metadata and already-acquired sources using +`Resolution.InputInfo` and `Resolution.Source`. This supports application-owned +decisions such as resolving relative paths against their declaring configuration +files. See the [resolution contract](../config.md#recorded-application-resolution) +and the maintained [source-aware path example](../consumers/README.md#source-aware-application-path-policy). + +The root `configkit` package now owns public types and explicit wrappers around a +single private engine. Internal changes no longer automatically expand public +method sets through shared type aliases. See the [component overview](../internal/overview.md) +and [facade decision](../adr/0006-public-facade.md). + +## Compatibility + +Existing consumer imports, exported API signatures, configuration syntax, +precedence, secret handling, callback lifetime, and ownership behavior are +preserved. The two resolution query methods are additive and available only +during an active resolution callback; returned records remain detached. The +library supplies provenance, not a new filesystem normalization policy. + +macOS on amd64 and arm64 is now best-effort rather than release-validated. +Neither native macOS evidence nor Darwin cross-builds are required for publication, +and macOS-specific failures do not by themselves block a release. Linux on amd64 +and arm64 retains release-gated builds and native Linux validation. See the +[platform support policy](../policy/release.md#platform-support). + +The module still requires Go 1.25 or newer. The private YAML dependency remains +pinned to `go.yaml.in/yaml/v4 v4.0.0-rc.6`, confirmed as the newest available v4 +release during preparation. It is still a prerelease dependency, isolated behind +the existing private parser boundary; no dependency upgrade is included. + +Linux candidate validation uses Go 1.25.14 and Go 1.26.8, including the complete +release checker, race tests, consumer examples, filesystem fixtures, and Linux +cross-builds. No native macOS validation is claimed for this candidate. + +## Upgrade + +```sh +go get gitea.maximumdirect.net/eric/ConfigKit@v0.3.0 +``` + +No code or configuration migration is required for the facade refactor. Adopt the +new provenance queries only if your resolver needs them. Applications retain +ownership of relative-path bases and fallback/error behavior. + +macOS consumers should account for the reduced validation commitment and perform +their own application checks when upgrading if macOS behavior is important to +their deployment. + +## Changes + +- Added callback-scoped, fixed entry metadata and source lookup without additional + filesystem access or credential resolution. +- Added a maintained Notarius-shaped path-normalization example with provenance, + frozen effective output, and explanation coverage. +- Moved loading, schema, resolution, provenance/history, secret, and rendering + machinery into one internal engine while keeping public named types root-owned. +- Added exact-type secret and callback adapters, with regression coverage for + missing version checkers and nil/zero closed-context failures. +- Added type-aware public-boundary checks covering aliases, collections, generic + constraints, and exported method sets; restored public reference documentation. +- Removed macOS release gates and retained required Linux validation. +- Retired completed feature, implementation, and remediation documents to Git + history and repaired navigation to current contract and component owners. diff --git a/docs/roadmap/implementation.md b/docs/roadmap/implementation.md deleted file mode 100644 index 01e9b71..0000000 --- a/docs/roadmap/implementation.md +++ /dev/null @@ -1,571 +0,0 @@ -# Public facade: implementation plan - -Status: complete (2026-09-12). Baseline: `28e7fc5f690b36c60e4d03586afcff00fb1dee90`. -The [feature roadmap](public.md) owns the implemented architecture and user intent. -This completed plan records implementation decisions, ordered work, validation, and handoffs. -Each numbered stage is sized for one gpt-5.6-terra coding-agent assignment; -no stage requires subagents or changes to downstream repositories. - -Historical navigation: this filename previously held the completed source-origins -plan, including its Stage 5 completion record. That record is preserved at the -baseline above: `git show 28e7fc5:docs/roadmap/implementation.md`. Existing incoming -links from the source-origins roadmap, remediation record, and development guide -refer to that historical plan, not the stages below. Stage 1 repairs those links. - -## Working rules - -Before each stage read [development](../development.md), the feature roadmap, -the preceding completion records, and all applicable policies: -[architecture](../policy/architecture.md), [documentation](../policy/documentation.md), -[testing](../policy/testing.md), and [release](../policy/release.md). -Read the owning configuration/API contracts and implementation before editing. -Prefer the code graph for discovery, verifying its results against current code. -Preserve unrelated work and the baseline's already-fixed resolution-history copy. - -Complete stages in order. Every handoff must build and pass its relevant tests; -do not leave placeholder public methods, skipped regressions, or known failures -for a later stage. Run `./scripts/check.sh` at every code-stage handoff, in addition -to the focused gates below. Keep default tests deterministic and offline. Follow -the development guide for dependency acquisition and supported toolchains. - -Record completion beneath each stage: changed owners, tests and actual toolchain, -results, deviations, remaining risks, and the next handoff. Update current -documentation with actual changes, not promised completion. Commit stage work -when authorized; this plan does not authorize pushes, tags, release selection, -or publication. Release notes and native-platform release evidence remain part -of the separate release procedure. - -## Fixed implementation decisions - -### Package and migration strategy - -Final production packages are the public root, `internal/engine`, and the existing -`internal/document` and `internal/yaml`. Keep the engine cohesive; do not create -separate packages for every phase. Root imports engine; engine imports its -supporting packages; no internal production package imports root. Only the YAML -adapter imports the upstream YAML dependency. - -Public named types remain defined in root. Use named private fields for delegated -state, explicit forwarding methods, and ordinary public record declarations. -Do not alias public types to engine types, anonymously embed engine types, expose -engine types in public signatures/fields, or add public bridge methods. -Internal type aliases used only inside implementation are not public aliases. - -Because private-state references span most root implementation files, use a -bounded relocation candidate rather than attempting a live package split in -every stage. Stage 2 copies the existing implementation into `internal/engine`; -Stages 4–7 build the eventual root facade in temporary `internal/facade` (package -name `configkit`). Root remains the sole consumer entry point until Stage 8. -The temporary facade is staging space, not a second supported API/package. - -This temporary duplication is a migration mechanism only: no feature development, -runtime selector, fallback engine, or new consumer import is introduced. Baseline -semantics remain fixed; necessary corrections must be reconciled explicitly. -Stage 8 moves the facade to root and removes the old implementation and temporary -directory in the same handoff. There is one production implementation at completion. -This makes the large textual move mechanical while separating it from the more -demanding ownership and callback work. Do not keep two engines as a final design. - -### Type and state ownership - -| Public family | Selected representation and adaptation | -| --- | --- | -| `Path` | Root struct with named private `engine.Path` value; constructors and methods delegate. Preserve semantic segment kinds and invalid state by direct private wrapping, never stringify/reparse. | -| `Layer`, `ChangeKind`, `Severity`, `Code`, `SecretFileStatus` | Root-defined string types and explicitly typed constants with unchanged values. Convert to engine equivalents at the boundary; engine constants may supply values without making public aliases. | -| `Location`, `SourceInfo`, `Diagnostic`, `Origin`, `FieldInfo`, `Change` | Root-defined records with unchanged exported fields. Explicit private conversions cover nested pointers, slices, and paths. | -| `ValueSnapshot`, `ValueChange`, `SecretReferenceInfo`, `Explanation`, `SecretFileResult` | Root-defined output records. Convert detached engine records; preserve nil/empty distinctions and field semantics. | -| `Source` | Root struct with private `engine.Source` value. Engine owns bytes, constructor validity, and the shared reader claim; wrapper copies must not create new claims or re-read/copy source input. | -| `Metadata` | Root struct with private engine metadata value; explicit query methods convert detached results. Engine retains effective and historical indexes. | -| `Resolution`, `Validation` | Root structs with private pointers to their engine contexts. Engine alone owns activity and audit state; wrappers never recreate that state. | -| `Definition[T]`, `Options[T]`, `FilesystemContext`, `Override`, `VersionRule`, `Version` | Root records retaining all current fields and signatures. Private option/callback conversion into engine records; no extra configuration clone or reflection-based generic record mapper. | -| `Result[T]` | Root struct retaining `Config T`, plus private pointer to a non-generic engine inspection result. Engine load returns configuration and inspection separately; facade stores configuration exactly once. | -| `Secret` | Root-owned opaque scalar retaining value-copy semantics and existing public methods. Private exact-type adapter lets engine read/build it; no public accessor for plumbing. | -| `LoadError`, `SecretsError`, `SecretsReport` | Root structs with private engine backing state and explicit methods. Translate engine typed failures at entry points; never return or unwrap an engine error as the public structured error. | - -The inventory in Stage 1 verifies every baseline exported declaration, not just -these grouped examples. Public type identity stays rooted in `configkit`. -Preserve receivers, generics, supported zero/nil behavior, interface satisfaction, -error assertions, and supported construction/copy behavior. Private field layout -and incidental formatting are not new compatibility promises. - -Use handwritten, local conversion helpers. For detached outputs, transfer already -detached data where safe instead of deep-copying everything again. Never expose -engine-owned mutable slices/maps through public records. Preserve order and -missing/null distinctions. Do not round-trip records through JSON/YAML or use -`unsafe`, registration globals, or reflection to bypass private fields. - -### Exact-type secret bridge - -Introduce an engine-internal `SecretBinding` containing `Type reflect.Type`, -`Read func(reflect.Value) SecretState`, and -`Make func(SecretState) reflect.Value`. `SecretState` carries the existing name, -value, specified, and resolved fields. It is operation data, never inspection -data. The root constructs the binding privately for exactly `reflect.TypeFor[Secret]()`; -Read and Make use ordinary type assertions/construction in the owning package. - -Supply the binding explicitly to the engine load and schema construction. Store -it in the per-operation schema/value-operation context, available to recursive -decoding, projection, cloning, dynamic-value checks, resolution, and validation. -Keep the application configuration type `T` unchanged: no mirror configuration -structs and no conversion of arbitrary application objects. - -Replace all direct engine assertions/constructions of the old `Secret`, not just -schema recognition. Include decoding, unresolved versus validated clone modes, -projection, required/optional references, lookup caching, and validator mutation -audit. Recognition remains exact-type recognition, not acceptance of any type -implementing an interface. Bindings are fixed by the facade, not configurable by -consumers, and perform no environment access themselves. Environment lookup -remains in its existing lifecycle phase and its existing private test seam. - -Engine unit tests use a test-local secret type and binding. Root integration -tests exercise the actual public `Secret`. There is no production engine-owned -replacement secret type that consumers must put in their configuration. - -### Callback, option, result, and error bridges - -Keep the engine lifecycle generic in the real `T`. Convert each supplied options -value without selecting/validating options in the facade: engine retains original -validation order and diagnostics, including multiple-options rejection. Preserve -nil callbacks, version pointers, defaults behavior, and override values without -eagerly invoking callbacks or evaluating `any` values. - -Adapt Resolve/Validate/Version.Check by closures wrapping the exact engine context -pointer and passing the same `*T` received from engine. Convert version records and -semantic paths at those boundaries. The secret-classification predicate similarly -wraps the engine path. Do not recover, retry, close, or extend callbacks in the -facade; engine retains the existing lifetime and failure behavior. - -Generic public Default/Normalize forward to generic engine helper functions with -the original target pointer and value. Do not implement them as just assignment -plus Record: existing target validation and projected expected-value audit matter. -Nil wrapper handling must preserve current inactive-context behavior. - -Refactor engine publication to return a short-lived generic loaded value containing -`Config T` and an inspection pointer. Inspection owns frozen trees, metadata, -history, sources, diagnostics, and sensitivity; it does not retain `T` or callback -bindings. Public `Result[T]` holds `Config` and that pointer, not another complete -generic engine result. Result inspection must not reread caller-mutated Config. -Existing caller-constructed zero results and nil result receivers retain behavior. - -Translate engine load/bootstrap failures into root `*LoadError`/`*SecretsError`, -respectively. Their backing state can be delegated privately, but no public -Unwrap exposes internal failures. Retain bootstrap partial reports and ordinary -writer errors/short-write behavior. Do not wrap arbitrary render/write errors into -new structured load errors or add error-disclosure guarantees. - -## Stage 1 — Record the boundary and establish compatibility evidence - -Status: not started. - -1. Run baseline everyday checks. Inventory the root's exported types, constants, - fields, functions, receiver method sets, generics, and interface implementations - with Go tooling. Record the baseline revision and concise ownership mapping in - the stage handoff; do not create a second normative API specification. -2. Add the next available ADR (currently `0006-public-facade.md`) recording wrappers, - private delegation, the dependency direction, and the alias-first alternative. - Record the temporary migration mechanism here, not as durable architecture policy. -3. Update architecture policy's public API/dependency section for the agreed - boundary, preserving proportionality and existing behavior contracts. Explain - that this is accepted design, not completed implementation. Add ADR navigation. -4. Repair the three historical incoming references described at the top of this - plan to identify the old plan by Git revision. Preserve the completed provenance - evidence; do not label this facade plan as its completion record. -5. Retain/add a compact external-package facade compatibility test covering the - realistic boundary risks: root named-type identity, exported construction, - generic helper use, structured error assertions, and relevant interfaces. - Use existing tests for behavior already protected. Inspect the complete exported - surface separately; do not add golden dumps of private struct layouts. - -Acceptance: baseline passes, public surface is understood, ADR/policy accurately -distinguish decision from implementation, and documentation links pass. -Run `go test . -run 'LocalDocumentationLinks|DependencyImportBoundary|Example|Facade'` -and the everyday check. No engine migration in this stage. - -### Completion - -Status: complete (2026-09-12). - -Baseline behavior was verified at `28e7fc5f690b36c60e4d03586afcff00fb1dee90`; -this plan was introduced by `eb7de8e40ab944f022a2b6984f4d4e0086f1484d`. The -complete root surface was inventoried with `go doc -all .`: lifecycle and generic -entry points; root value/input types (`Path`, `Source`, `Secret`); callback and -option records; metadata, provenance, diagnostics, history, and rendering -records; typed errors and bootstrap reports; and the scalar enum families. The -inventory also covered receiver methods, generic instantiations, and relevant -interfaces (`error`, `fmt.Formatter`, `fmt.Stringer`, `json.Marshaler`, and -`io.WriterTo`). Existing behavioral tests remain the source of detailed API -semantics; `facade_compatibility_test.go` supplies compact external-package -coverage for the migration boundary. - -Added ADR 0006 and the architecture rule for root-owned public wrappers and -inward-only implementation dependencies. They describe the accepted target, not -an already-completed extraction. Repaired the development guide, source-origins -record, and remediation record to identify the old provenance plan by its Git -revision instead of linking to this plan. No engine or lifecycle migration was -introduced. - -Validation on Linux with Go 1.26.7 passed: the focused documentation, -import-boundary, executable-example, and facade checks, followed by -`./scripts/check.sh`. There were no deviations. The next handoff copies the -unchanged root implementation into the bounded internal relocation candidate; -it must retain the documented public behavior while proving engine independence. - -## Stage 2 — Establish the internal relocation candidate - -Status: not started. - -1. Copy root production implementation except public package orientation into - `internal/engine`, changing package declarations/import references mechanically. - Preserve file divisions and existing document/YAML packages. Keep internal - functions private unless a later facade connection actually needs an export. -2. Copy behavior/mechanism tests and needed fixtures for engine validation, excluding - repository documentation, release-script, import-boundary, public examples, - and consumer integration tests. Keep root unchanged and passing. Repair fixture - paths explicitly; do not make tests depend on arbitrary working directories. -3. Avoid blind replacements inside user-facing strings, diagnostic codes, fixture - YAML, or documentation comments. The package rename is not permission to rename - messages or behavior. Record the candidate's source baseline. -4. Update the component overview with an explicitly temporary candidate entry. - Do not claim root loads delegate yet. - -Acceptance: `go test ./internal/engine` and the everyday check pass. Engine imports -no root code, existing internal/parser boundaries remain intact, and root consumers -still execute the unchanged original implementation. This stage is deliberately -mechanical; do not mix ownership redesign into the relocation diff. - -### Completion - -Status: complete (2026-09-12). - -Copied the 39 root production files from the Stage 1 baseline `f81def9` into -`internal/engine`, excluding only root package orientation in `doc.go`, and -changed package declarations mechanically. Copied the 29 applicable root -behavior and fuzz tests. Repository documentation, release-script and -import-boundary checks, root external-package/API tests, and maintained consumer -integration tests remain at their existing owners; root has not been changed to -delegate to the candidate. No root testdata fixtures exist to copy. - -`docs/internal/overview.md` now labels the candidate as temporary and unused. -`go list -deps` confirms that the engine has no dependency on the root module -package; its existing dependencies remain the private document and YAML -boundaries. Linux validation with Go 1.26.7 passed `go test ./internal/engine` -and `./scripts/check.sh`. There were no behavioral deviations or package-renamed -diagnostics. The next handoff replaces the copied engine's concrete public -secret assumption with an explicit per-operation exact-type binding. - -## Stage 3 — Decouple reflection from the public secret type - -Status: not started. - -1. Implement the exact-type SecretBinding/SecretState design above in engine. - Thread it through schema and recursive value operations explicitly; do not use - a global binding or make it an application option. -2. Replace concrete-secret assumptions in `schema.go`, `decode.go`, `clone.go`, - `projection.go`, `value_operation.go`, `secret_reference.go`, and their callers. - Find all additional references using the graph/text search; the list is not a - reason to leave a direct assertion behind. -3. Move engine tests to their local secret type/binding and remove the candidate's - production concrete Secret and public-style constructor. Preserve named-type - rejection/acceptance semantics and dynamic-value checks from the baseline. -4. Exercise unresolved/default secrets, pointer and container shapes, borrowed - callback values, lookup-once behavior, and validator replacements without - disclosing canary credentials in diagnostic expectations. - -Acceptance: engine secret/schema/decode/clone/projection/validation tests and race -tests pass; binding instances cannot affect each other. Run -`go test ./internal/engine -run 'Secret|Schema|Decode|Clone|Projection|Validation|Callback'`, -`go test -race ./internal/engine`, and the everyday check. - -### Completion - -Status: complete (2026-09-12). - -`internal/engine` now receives a per-operation `SecretBinding` at schema and -load construction. Its exact `reflect.Type`, `Read`, and `Make` functions carry -the facade-owned `SecretState` through decoding, projection, unresolved and -validated cloning, dynamic-value rejection, secret lookup, resolution helpers, -and validator mutation auditing. The binding is retained by each schema only; -there is no package-global registration or engine-owned replacement secret. - -Removed the candidate's production `Secret` and `SecretEnv` declarations. -`secret_binding_test.go` provides a local test secret type, fresh binding for -every test load, and exact-type/isolation coverage using a second local secret -type. Existing secret tests continue to cover defaults, pointers and containers, -resolution-selected names, lookup-once behavior, borrowed callback values, -redaction, and validator replacement without credential disclosure. The root -implementation remains unchanged for this migration handoff. - -Linux validation with Go 1.26.7 passed the focused secret/schema/decode/clone/ -projection/validation/callback suite, `go test -race ./internal/engine`, and -`./scripts/check.sh`. There were no deviations. The next handoff creates the -temporary facade's root-owned value, source, diagnostic, and secret wrappers. - -## Stage 4 — Build candidate value, source, and diagnostic wrappers - -Status: not started. - -1. Create temporary `internal/facade`, package `configkit`, importing engine. - Implement root-owned Path, Source, Secret, scalar enums/constants, and provenance - records according to the ownership table. Preserve declaration comments for - their eventual root placement. There must be no aliases or embedded engine types. -2. Implement private path/record conversions and the real facade secret binding. - Keep public Secret's small access/format/JSON methods local; its private scalar - state remains value-based, not a shared mutable reference. -3. Add LoadError and WriteDiagnostics delegation/conversion. Candidate engine may - export narrow constructors/accessors as needed internally, not public bridge - functions on the candidate facade. Preserve nil handling and typed errors. -4. Test candidate public operations from its external test package. Verify that - numeric-key versus index versus parsed paths are not collapsed; source copies - share the same reader claim; bytes are snapshotted at construction; formatting - and JSON do not expose resolved secret values. - -Acceptance: candidate wrapper tests and engine tests pass. Run -`go test ./internal/facade ./internal/engine` and the everyday check. Lifecycle -entry points are added in Stage 6; do not add nonfunctional stubs here. - -### Completion - -Status: complete (2026-09-12). - -Created the temporary `internal/facade` package (named `configkit`) with -root-owned `Path`, `Source`, and `Secret` wrappers; root-owned scalar and -provenance records; explicit private conversions; `LoadError`; and -`WriteDiagnostics`. Public fields and signatures contain only facade types. -`Path` carries its engine value privately without text round-tripping, `Source` -retains the engine's source value so copied reader sources preserve their shared -claim, and the facade builds the exact-type secret binding locally. No lifecycle -entry point or placeholder was added. - -Candidate tests cover semantic path distinctions, source byte snapshotting and -copied-reader ownership, external-package type ownership and interfaces, and -safe secret formatting/JSON. Linux validation with Go 1.26.7 passed -`go test ./internal/facade ./internal/engine` and `./scripts/check.sh`. There -were no deviations. The next handoff separates engine publication from its -generic result before lifecycle delegation begins. - -## Stage 5 — Separate engine publication and inspection - -Status: complete (2026-09-12). - -1. Split generic engine Result into the short-lived loaded configuration carrier - and non-generic inspection state specified above. Move inspection methods to - the inspection receiver without changing their snapshots or algorithms. -2. Adapt `load_result.go`, `load_metadata.go`, `metadata.go`, `explain.go`, - `explain_render.go`, `render.go`, `history.go`, and `snapshot.go` as necessary. - Keep the fixed entry-state view independent of final history, including the - baseline fix that avoids copying unused resolution history. -3. Update engine tests for the internal receiver/return changes while preserving - observable expectations. Do not broaden nil/result-construction contracts. - -Acceptance: engine loading, historical provenance, detached metadata, explanation, -and rendering behavior pass. Verify publication still performs its existing -configuration detachment but does not store Config in inspection. Run -`go test ./internal/engine -run 'Load|Metadata|Provenance|Historical|Explain|Effective|Render|Independence'`, -`go test -race ./internal/engine`, and the everyday check. - -### Completion - -Replaced the engine's generic result with `Loaded[T]`, a short-lived carrier of -the detached configuration and a non-generic `Inspection`. `Inspection` now -owns the frozen metadata, sources, diagnostics, document snapshots, history, -resolution snapshots, and sensitivity state; its query, explanation, and -rendering methods retain their previous behavior. The published configuration -is detached as before and is not retained by `Inspection`. - -Engine tests use a test-only adapter while exercising the moved inspection -receiver, and a direct `Loaded` test verifies that mutating `Config` cannot -change its frozen effective view. Linux validation with Go 1.26.7 passed -`go test ./internal/engine -run 'Load|Metadata|Provenance|Historical|Explain|Effective|Render|Independence'`, -`go test -race ./internal/engine`, and `./scripts/check.sh`. There were no -deviations or remaining risks. The next handoff wires the candidate facade's -lifecycle and callback wrappers to the split engine result. - -## Stage 6 — Wire candidate lifecycle and callback wrappers - -Status: complete (2026-09-12). - -1. Add candidate Definition, Options, VersionRule, Version, FilesystemContext, - Override, Resolution, and Validation with unchanged public declarations. - Implement the private option and callback bridges specified above. -2. Add candidate Load using the engine and facade secret binding. Add Result[T] - with Config and private inspection, initially with Metadata, Sources, and - Diagnostics. Implement Metadata's complete public query methods. -3. Forward all resolution methods, including InputInfo and Source, and the generic - Default/Normalize helpers. Engine owns context activity, helper verification, - resolution snapshots, and validation mutation detection. -4. Add focused external candidate tests using actual public wrapper types inside - application configuration. Exercise version callbacks, defaulting/normalization, - retained/copy contexts, root typed error assertions, and public Secret recognition. - Private engine secret tests alone are insufficient evidence for this bridge. - -Acceptance: real candidate loads with callbacks succeed/fail identically to the -baseline, no callback is called by option conversion, no extra lookup occurs, -and detached entry provenance stays fixed. Run -`go test ./internal/facade ./internal/engine -run 'Load|Resolution|Validation|Version|Metadata|Secret|Callback|Facade'`, -`go test -race ./internal/facade ./internal/engine`, and the everyday check. - -### Completion - -Added the temporary facade's root-owned lifecycle declarations, option conversion, -live callback wrappers, `Load`, `Result`, and `Metadata`. Callback wrappers carry -only the active engine context during callback execution; `Result` stores the -published configuration once and keeps its non-generic engine inspection private. -All record and path crossings use explicit conversion, and facade loads translate -engine load failures to the root-owned `LoadError` type. - -External candidate tests exercise public version, default, resolution, validation, -metadata, source, and secret behavior, including inactive retained contexts and -typed load errors. Linux validation with Go 1.26.7 passed -`go test ./internal/facade ./internal/engine -run 'Load|Resolution|Validation|Version|Metadata|Secret|Callback|Facade'`, -`go test -race ./internal/facade ./internal/engine`, and `./scripts/check.sh`. -There were no deviations or remaining risks. The next handoff completes the -candidate inspection and secrets-bootstrap surface. - -## Stage 7 — Complete candidate inspection and bootstrap surface - -Status: complete (2026-09-12). - -1. Add the public explanation/value records and Result Explain, WriteEffective, - and WriteExplanation delegation. Inspection uses the frozen engine state, - not the mutable public Config field. Complete every remaining public method. -2. Add SecretsReport, SecretsError, bootstrap records/status constants, and - LoadSecretsDir. Preserve opt-in writes, partial reports, detached entries, - writer counts/errors, and non-unwrapping typed errors. -3. Exercise complete load-to-inspection workflows through the candidate. Prove - that caller mutation of Config or returned records does not rewrite inspection - history or affect a later query/load. Include malformed paths and nil receivers - where the baseline already defines behavior. -4. Compare the complete candidate exported surface with the baseline inventory, - normalizing only the temporary import path. Resolve all signature/method/field - omissions before cutover. No placeholder methods or ignored API mismatches. - -Acceptance: the candidate implements the entire supported API and has real -integration evidence for inspection, credentials, bootstrap, and writer failures. -Run `go test ./internal/facade ./internal/engine`, race tests for both packages, -and the everyday check. Root remains unchanged until Stage 8. - -### Completion - -Completed the candidate's inspection and bootstrap API with root-owned -explanation, snapshot, secret-reference, and bootstrap records. Result delegates -to the private frozen engine inspection for explanation and rendering, so public -configuration mutation cannot affect historical or effective output. Bootstrap -delegates to the engine while returning facade-owned report and error types with -detached converted entries and diagnostics. - -The candidate's exported declarations and methods now match the root surface -after normalizing its temporary import path. External integration tests cover -frozen inspection, secret-safe explanation/rendering, malformed and nil result -handling, bootstrap application/skips, detached report entries, and typed -bootstrap failures. Linux validation with Go 1.26.7 passed -`go test ./internal/facade ./internal/engine`, `go test -race ./internal/facade ./internal/engine`, -and `./scripts/check.sh`. There were no deviations or remaining risks. The next -handoff moves the verified candidate to the root and removes migration copies. - -## Stage 8 — Cut over the root and remove migration duplication - -Status: complete (2026-09-12). - -1. Replace root production plumbing with the tested candidate facade, retaining - root package documentation and the root named types. Move files; do not leave - forwarding aliases to the temporary facade. Remove `internal/facade` entirely. -2. Root-owned unit/integration tests remain at root; engine mechanism tests remain - with engine. Remove duplicated baseline copies after confirming coverage owners. - Split mixed tests by boundary: assertions requiring private engine state move - internally, while public lifecycle/consumer assertions still exercise root. - Do not move all tests inward simply to avoid adapting public wrappers. -3. Run existing executable API examples and maintained consumers unchanged in - their imports/configuration types. Fix wrapper defects rather than migrating - consumers to a different API. Test the actual root Secret binding after the move. -4. Keep repository check tests at root. Repair documentation/fixture references, - fuzz target locations, and development task commands as files move. For links - formerly pointing at mixed implementation files, point API references at root - and implementation references at engine as appropriate. -5. Remove old root algorithms, temporary candidate tests superseded by root tests, - and staging documentation. Preserve useful narrow private test seams, but no - root accessors solely exposing engine internals to tests. - -Acceptance: one engine serves the sole root facade; no candidate directory, -parallel implementation, or root import from internal production code remains. -Run the everyday check, `go test ./examples/consumers`, root examples, and -`go test -race ./...`. All gates must pass in this handoff; do not leave a broken -root suite for the final audit. - -### Completion - -Moved the verified facade into the root package and removed the temporary -`internal/facade` directory and the former root implementation copies. The root -now owns the public wrappers and delegation only; `internal/engine` is the single -production lifecycle implementation. Retained root tests cover public facade -behavior, examples, documentation links, import boundaries, and checker behavior; -mechanism tests remain with the engine. Development and remediation links now -point to their engine-owned tests and metadata implementation. - -Linux validation with Go 1.26.7 passed `./scripts/check.sh`, -`go test ./examples/consumers`, root examples, and `go test -race ./...`. -There were no deviations or remaining risks. The final handoff audits the public -boundary and brings documentation in line with the completed architecture. - -## Stage 9 — Audit the public boundary and finalize documentation - -Status: complete (2026-09-12). - -1. Compare the final complete exported API against the baseline. Audit public - signatures, fields, aliases, embedded types, method sets, and error returns - for internal-type exposure. Review root code for remaining substantive - algorithms; explain small value operations deliberately retained there. -2. Extend the existing import-boundary check for inward production dependencies. - Add a narrowly scoped public-boundary check that detects exported aliases to, - embedded exposure of, and exported signatures/fields involving internal types. - Use standard Go tooling and avoid private-field/layout snapshots. Account for - generic declarations and public records referencing other public records. - Keep behavior tests as the evidence for adapter correctness. -3. Verify source ownership, secret binding isolation, zero/nil handling, helper - audit semantics, typed errors, final Config versus frozen inspection, and the - baseline resolution-entry optimization. Add tests only for uncovered risks. -4. Finalize architecture-policy wording, ADR navigation, component overview, - development test/fuzz commands, and public declaration comments. Add a concise - internal facade mechanism document if needed for the secret/callback/record - connections; do not spread implementation recipes across consumer docs. -5. Update consumer orientation only where useful. Keep YAML behavior in its - existing contract. Convert the feature roadmap to an implemented summary with - canonical links and evidence; record remaining release preparation separately. - -Acceptance: documented target matches code and no unapproved API/behavior change -is hidden by the refactor. Run the everyday check, full race suite, consumer -examples, documentation/import/public-boundary checks, and tests/builds using the -supported baseline and newer Go toolchains recorded in the release procedure. -Record actual versions/platforms; do not treat Linux tests or cross-builds as -native macOS release evidence. Do not publish or select a version in this stage. - -### Completion - -Audited the final root facade against the established public surface and added a -root AST boundary check for exported aliases, fields, and signatures involving -internal types. The dependency boundary check now also rejects root production -imports that bypass the engine and internal production imports of the root. -The completed root retains only facade wrappers, records, conversions, and -entry-point delegation; engine mechanism tests own lifecycle behavior. - -Updated the architecture policy, ADR status, component overview, development -test/fuzz navigation, and public-facade roadmap to describe the implemented -layout. The roadmap is now a completed implementation record rather than a -future plan. Root facade integration and engine tests cover source ownership, -exact-type secret binding, callback activity/audit, structured errors, detached -configuration versus frozen inspection, and resolution entry snapshots. - -Linux validation passed with Go 1.25.5 and Go 1.26.7 through -`CONFIGKIT_BASELINE_TOOLCHAIN=go1.25.5 CONFIGKIT_NEWER_TOOLCHAIN=go1.26.7 ./scripts/release-check.sh`. -It also passed the everyday check, full race suite, consumer examples, and local -documentation/import/public-boundary tests. This is not native macOS evidence -and no release version, tag, or publication was selected. There were no -deviations or remaining risks. - -## Open Questions - -None requiring a user decision were identified. Wrappers, public type ownership, -one final engine, per-operation exact-type secret adaptation, and a single cutover -are specified above. Internal helper names and file grouping remain ordinary -implementation choices. A newly discovered conflict with an existing contract -must be surfaced with evidence and alternatives rather than resolved by changing -consumer behavior or reverting to public aliases. diff --git a/docs/roadmap/public.md b/docs/roadmap/public.md deleted file mode 100644 index 56d16bc..0000000 --- a/docs/roadmap/public.md +++ /dev/null @@ -1,187 +0,0 @@ -# Public facade and internal implementation - -Status: implemented on 2026-09-12. This roadmap records the intended architecture -and user intent; the completed [implementation plan](implementation.md) records -the ordered work, validation, and handoffs. - -## Intent - -Make ConfigKit easier for humans and coding agents to navigate by separating its -consumer-facing API from its implementation machinery. Consumers should find a -readable, documented public surface in the root `configkit` package; maintainers -should find the loading and inspection machinery under `internal/`. - -Long-term maintainability is the primary objective. The public API should remain -stable while internal implementation can evolve without becoming a consumer -commitment. An internal implementation change must not expand or alter the public -API merely because the facade exposes the same underlying type. Repository -aesthetics and easier navigation are useful secondary benefits, not the reason -to minimize public-package code. - -This is an organizational and API-boundary refactor, not a new configuration -feature or security boundary. Unexported root-package details are already private -under ordinary Go access rules. The concern is accidentally exposing internal -types or exported methods that consumers can depend on even without documentation. -Wrappers provide structural separation; they do not make internal changes that -alter observable public behavior automatically compatible. - -The [architecture policy](../policy/architecture.md) and -[implementation discipline](../../AGENTS.md#implementation-discipline) govern the -design. Existing [configuration contracts](../config.md) and exported Go -declaration comments remain authoritative. The user-approved wrapper boundary is -a contributor design choice, not a strengthening of consumer behavior contracts. - -## Implemented architecture - -The root owns public declarations, records, wrappers, and deliberate forwarding. -`internal/engine` owns source acquisition, imports, composition and overlays, -reflection descriptors, decoding, resolution and validation coordination, -provenance, history, secret handling, and rendering. The -[component overview](../internal/overview.md) owns the detailed inventory. - -Two established internal boundaries already exist: `internal/document` owns the -parser-independent tree, and `internal/yaml` owns upstream YAML integration. -[ADR 0002](../adr/0002-own-yaml-semantics.md) remains applicable. - -Public types are not merely passive records. For example, `Result[T]` combines -its public `Config` field with private inspection snapshots; `Resolution` holds -callback state; `Path` holds semantic segments; and `Secret` holds private -reference and resolved-value state. Moving implementation requires deliberate -type ownership, not just file relocation. - -## Architecture - -### Public root package - -The root remains the single supported consumer import path. It contains: - -- package and API reference documentation; -- public-owned type declarations, including wrappers and ordinary public records; -- public constants, constructors, entry points, and lightweight delegation; -- public contract tests and executable API examples where appropriate. - -Substantial source processing, decoding, lifecycle bookkeeping, history replay, -and rendering mechanics live internally. Small value operations or adapters may -remain in the root when moving them would introduce disproportionate machinery. -Public API documentation remains beside public declarations and must be useful -through ordinary Go documentation and editor navigation. - -### Public-owned types and private delegation - -The agreed approach is root-defined public types, with private delegation to -internal implementation where needed. Public wrappers expose deliberately chosen -methods; internal state is held privately rather than exported or embedded in a -way that promotes internal methods into the public surface. Public signatures -and fields do not expose internal plumbing types. Adding an internal exported -method must not add a public method automatically. - -Simple public records and small value operations can remain directly implemented -in the root. There is no requirement to wrap every value or move every method. -Aliases to internally owned implementation types are not the facade strategy: -they would couple the public method set to the implementation this work is meant -to separate. - -Straightforward forwarding code is an acceptable maintenance cost. Adapters must -avoid competing mutable state and unnecessary conversions, particularly around -`Result[T].Config`, frozen inspection data, callback lifetime, source ownership, -and reflection-sensitive secret handling. These connections are private -implementation details, not public bridge APIs or a generic registration framework. - -### Internal engine and supporting packages - -A cohesive internal engine owns the loading lifecycle and the closely coupled -schema, decoding, resolution, provenance, and inspection implementation. The -selected package is `internal/engine`. - -The existing document and YAML packages retain their responsibilities. Additional -packages are appropriate only where a cohesive responsibility and practical -dependency boundary justify them. There is no requirement for one package per -phase, file category, or component in the current inventory. - -Dependencies run from the facade into internal implementation and from the -engine into its supporting packages. Internal packages do not import the public -root. Public types remain root-owned; internal collaborators use internally owned -state and narrow implementation connections. Internal code does not gain direct -access to private fields of public types across packages. - -The engine may initially remain fairly large. A smaller root alone does not -justify a network of adapters, generic provider interfaces, or a framework. -Internal exports needed between packages are implementation surfaces, not new -supported consumer APIs. Existing parser isolation remains intact. - -## Compatibility and scope - -The target is a behavior-preserving refactor requiring no consumer migration: - -- Preserve the module/import path, exported names, function and method - signatures, generic use, public fields, and supported construction patterns. -- Preserve loading order, source ownership, defaults, composition and overlay - behavior, resolution and validation semantics, and structured diagnostics. -- Preserve callback lifetime, fixed entry provenance, detached query results, - final inspection snapshots, and independence across loads. -- Preserve secret recognition, credential timing, explicit access, redaction, - and opt-in bootstrap behavior. -- Preserve the supported Go and platform baseline and the existing dependency - isolation; this work does not require a toolchain or third-party dependency - change. - -Type restructuring can affect more than compilation. The implementation must -assess method sets, interface satisfaction, zero values, copying and equality -where supported, error assertions, reflection-based special-type recognition, -and public documentation. Keeping public named types in the root preserves their -defining package identity, but does not by itself prove compatibility of their -state or behavior. Observable effects must be evaluated and reported, not silently -declared compatible or newly guaranteed forever. - -No new input restrictions, resource limits, lifecycle restrictions, security -guarantees, configuration semantics, or public extension hooks are in scope. -Do not expose plumbing publicly merely to solve an import cycle. A discovered -need to change an established contract requires a separate explicit decision. -Version selection and publication remain governed by the -[release policy](../policy/release.md), not by this roadmap. - -## Completion evidence - -Completion means the root is a legible public surface, substantive plumbing is -internally owned, consumers require no migration, and representative -load-to-inspection workflows still pass through the facade. Public exported -members are deliberate declarations, not incidental exposure of engine methods -or state. The completed architecture has one engine, no parallel implementation, -and no competing mutable configuration state. Small operations deliberately -retained in the root are justified by maintainability, not a numerical size gate. - -Public behavior and maintained consumer examples exercise the root facade; -mechanism tests live with their implementation owners. Test-only access does not -expand the public API. Repository checks preserve parser isolation and the public -boundary. Validation follows the [testing policy](../policy/testing.md); -release-candidate validation remains separate under the -[release procedure](../release.md). - -Tests should protect behavior and intentional dependency boundaries, not exact -private layouts, forwarding call sequences, or an arbitrary package count. -Implementation completion must be backed by evidence; this proposal is not -evidence that the target architecture already exists. Completed roadmap material -is retired during release preparation under the documentation policy. - -## Documentation ownership in the target architecture - -Under the [documentation policy](../policy/documentation.md), architecture policy -owns the public-wrapper and inward-dependency rules, preserving proportionality. -An ADR records the accepted decision and why an alias-first facade was rejected: -it reduces forwarding but couples public methods to internal implementation. -The additional wrapper code is justified by long-term API independence. - -The component overview describes actual facade, engine, supporting packages, and -state ownership. Development navigation locates the tests and mechanisms at their -new owners. Internal documentation explains the private adapters. Exported API -reference comments remain in the public package; consumer guidance identifies -the supported root import without requiring knowledge of the engine. - -Configuration semantics remain in the existing contract, not in package-layout -documentation. Internal layouts do not become public stability guarantees. -Release documentation describes the behavior-preserving refactor without -replacing canonical API or architecture documentation. - -The alias-versus-wrapper decision is resolved by the user's explicit selection -of wrappers. An implementation convenience is not authority to change that -decision or an established consumer contract. diff --git a/docs/roadmap/remediation.md b/docs/roadmap/remediation.md deleted file mode 100644 index 5e46b2f..0000000 --- a/docs/roadmap/remediation.md +++ /dev/null @@ -1,206 +0,0 @@ -# Public facade remediation - -Review baseline: `5dc7e18`. Reviewed commits `f81def9` through `5dc7e18` against -`eb7de8e`, the agreed [roadmap](public.md), and [implementation plan](implementation.md). -Status: all four findings resolved. Review evidence below describes the -original baseline; resolution records describe the subsequent fixes. - -The previous provenance finding remains resolved; its record is preserved at -`5dc7e18:docs/roadmap/remediation.md`. The field-only resolution-entry snapshot -construction remains intact in `internal/engine/load_metadata.go`. - -## F1 — Preserve a nil schema-version checker during option conversion - -Priority: high. Status: resolved. - -Resolution: option conversion preserves nil Check and installs a wrapper only for -a real checker. The public regression failed with the original panic before the -fix, then passed with typed rejection, no reads/callbacks, and successful source -reuse with a valid checker. Focused facade/version tests, the everyday check, -and the full race suite passed on Linux with Go 1.26.7. - -### Evidence and impact - -In [lifecycle.go](../../lifecycle.go), `toEngineDefinition` (lines 233–237 at the -review baseline) installs a non-nil Check closure whenever Version is non-nil, -even if the supplied VersionRule.Check is nil. This defeats the existing -nil-checker rejection in `internal/engine/options.go`. Loading then consumes input -and invokes a nil function through the closure, panicking. - -Reproduced through the public API with a struct containing a `version` string, -a counting Reader over `version: v1`, and this option: - -```go -configkit.Options[Config]{ - Definition: configkit.Definition[Config]{ - Version: &configkit.VersionRule{Path: configkit.Keys("version")}, - }, -} -``` - -At `eb7de8e`, this returns `*configkit.LoadError` with `CodeOptionsInvalid` and -zero reader calls. At `5dc7e18`, it reads the source and panics. Reading also claims -the single-use source, so recovering does not restore the old behavior. This is -a regression in established validation and failure ordering, not a proposed new -restriction on version rules. - -### Required correction and validation - -Convert Version and Path while preserving a nil Check. Install the forwarding -closure only when the supplied Check is non-nil. Leave validation and diagnostic -order in the engine; do not add facade validation or recover-and-reclassify. - -Add a public-root regression test asserting typed `CodeOptionsInvalid`, no result, -no source consumption, and no application callback execution. Reusing the same -Reader source with a valid rule should still succeed. Retain valid checker -coverage for version/context conversion. Run root facade/version tests, the -everyday check, and the race suite. - -## F2 — Close the public-boundary check's type-resolution gaps - -Priority: medium. Status: resolved. - -Resolution: [public_boundary_test.go](../../public_boundary_test.go) loads the -active build's compiler export data and walks resolved Go types, exported method -sets, and generic constraints. Declaration fixtures cover exposure and valid -private-backed wrappers. The original three probe declarations now each fail -the actual root check; the temporary probe was removed afterwards. The everyday -check passed with Go 1.26.7, and boundary tests passed with Go 1.25.5 and Go 1.26.7 -on Linux. No production behavior or public surface was changed. - -### Evidence and impact - -`TestPublicFacadeBoundary` in -[import_boundary_test.go](../../import_boundary_test.go) checks selector syntax in -function signatures and public struct fields, but skips non-struct type bodies -and does not resolve local type names or inspect type-declaration constraints. -No current public engine-type leak was identified; the gap is in the guard meant -to prevent future accidental exposure. - -In a disposable archive of `5dc7e18`, these production declarations all compiled -and `go test . -run '^TestPublicFacadeBoundary$' -count=1` still passed: - -```go -type ReviewPaths []engine.Path -type reviewHidden = engine.Path -func ReviewLeak() reviewHidden { return engine.Path{} } -type ReviewGeneric[T interface{ ~[]engine.Path }] struct{} -``` - -The collection exposes engine values; the private alias hides an engine return -type from the scanner; the constraint exposes an internal type despite an empty -struct body. These are ordinary declarations that can create exactly the -accidental public commitments the selected wrapper boundary is meant to prevent. - -### Required correction and validation - -Resolve types across root declarations and inspect exported/reachable type -surfaces, including named collection/function/interface types and generic -constraints. Prefer a small type-aware implementation using standard Go tooling -over isolated selector-pattern exceptions. Keep private backing fields legal; -their layout is not public API. Do not add runtime restrictions or broaden the -check into a general security scanner. - -Use focused positive/negative declaration fixtures covering the reproduced misses, -existing direct-exposure cases, and legitimate wrappers, public records, and -generic public types. Fixtures need not enter production. Run boundary tests and -the everyday check. - -## F3 — Restore consumer contracts on public Go declarations - -Priority: medium. Status: resolved. - -Resolution: restored the baseline comments on root source, path, secret, and -diagnostic declarations. The complete `go doc -all .` output now matches the -pre-refactor `eb7de8e` reference, with no missing declarations or contract prose. -Documentation-link and whitespace checks passed. No behavior or new guarantee -was introduced. - -### Evidence and impact - -Comparing `go doc -all .` at `eb7de8e` and `5dc7e18` found unchanged exported -declaration signatures but lost substantive reference documentation. Much of that -text now remains only on internal engine declarations: - -- [source.go](../../source.go): Reader omits that ConfigKit never closes the - reader; Bytes omits label requirements and deferred constructor errors; - NoSource omits that it creates no source record. -- [diagnostic.go](../../diagnostic.go): LoadError loses its non-unwrapping contract; - Error, Diagnostics, and Sources have no reference comments; WriteDiagnostics - omits control-character escaping and writer/short-write behavior. -- [path.go](../../path.go): Path loses concrete semantic/escaping details; - Index loses the negative-index behavior. -- [secret.go](../../secret.go): SecretEnv omits that invalid names are reported - if the reference survives loading. - -These are consumer ownership and usage facts, not plumbing to hide with the -engine. Their loss diverges from the documented root-facade goal and the -documentation policy's declaration-level API ownership. - -### Required correction and validation - -Restore substantive existing comments on root declarations, linking to the -configuration contract for shared semantics where appropriate. Review the complete -reference diff, not just these examples. Do not invent stronger guarantees or -require consumers to inspect engine documentation. Internal comments can explain -mechanics without becoming a competing public contract. - -Validate with `go doc -all .`, documentation-link checks, and content review; -no golden full-documentation snapshot is required. - -## F4 — Repair the duplicated development-guide tail and table row - -Priority: low. Status: resolved. - -Resolution: removed the duplicate tail and stray table terminator, escaped the -boundary command's alternation pipes, and linked the new public-boundary test -owner. Content/structure review confirms one task table and one fuzz section. -The documented boundary command, documentation links, and whitespace checks pass. - -### Evidence and impact - -[docs/development.md](../development.md), lines 122–134 at the review baseline, -contains a stray backtick/table terminator, a duplicate checker row outside its -table, and a second copy of the Fuzz validation section. The boundary-check -command in the table at line 109 also contains unescaped pipes, splitting the -Markdown row into unintended cells. The link checker passes because these are -rendering/content errors rather than missing targets. - -### Required correction and validation - -Retain one well-formed task table and one fuzz section with the current engine/YAML -commands. Escape regex alternation pipes in the table consistently with other -rows. Review the rendered structure and run local documentation-link and -whitespace checks. No new documentation framework or test is needed. - -## Architecture assessment and validation boundaries - -The principal target is implemented: public named wrappers and records remain in -root; substantial machinery lives in one internal engine; document and YAML -boundaries remain separate. The temporary facade and old root engine are gone. -Callbacks wrap engine context pointers, configuration remains the actual application -type, and inspection is frozen non-generic state separate from public Config. -The exact-type secret binding is per-operation, not a public registration API. - -Review validation passed on Linux: - -- `./scripts/check.sh` with Go 1.26.7 (formatting, whitespace, tests, vet, build); -- `go test -race ./...` with Go 1.26.7; -- `GOTOOLCHAIN=go1.25.5 GOPROXY=off go test ./...`; -- public reference comparison and isolated baseline/current F1 reproduction; -- the isolated F2 negative probe, demonstrating the guard's missed violations. - -Passing existing tests did not waive these findings. The review did not repeat -the complete release checker or native macOS validation and is not release -approval. The two knowledge-graph artifact modifications present before review -were left untouched. Only this remediation document was changed during review. - -## Remediation completion - -All four corrections are implemented and committed as coherent units. Final -validation passed on Linux: the everyday check and full race suite on Go 1.26.7, -and `go test ./...` on Go 1.25.5. The full public Go reference matches `eb7de8e`; -the new version regression was verified failing before its fix; and the original -boundary probes now fail the real boundary check and are not retained in production. -No release was prepared, and pre-existing knowledge-graph changes are not included -in remediation commits. diff --git a/docs/roadmap/source-origins-during-resolution.md b/docs/roadmap/source-origins-during-resolution.md deleted file mode 100644 index 92089ef..0000000 --- a/docs/roadmap/source-origins-during-resolution.md +++ /dev/null @@ -1,52 +0,0 @@ -# Source origins during resolution - -Status: implemented (2026-09-12); release preparation remains separate. - -ConfigKit now exposes fixed entry-state provenance during an active -`Definition.Resolve` callback: - -```go -func (r *Resolution) InputInfo(path Path) (FieldInfo, bool) -func (r *Resolution) Source(id string) (SourceInfo, bool) -``` - -These methods support application-owned normalization and other domain decisions -before ConfigKit publishes its frozen result. They are additive: existing loading, -composition, decoding, resolution recording, credential timing, and inspection -semantics remain unchanged. - -## Canonical behavior - -Go reference comments on `Resolution` own the API/lifetime definition. The -[configuration contract](../config.md#recorded-application-resolution) owns entry -state, exact path matching, source records, misses, detachment, and callback-scope -behavior. The [consumer adoption guide](../consumers/README.md#source-aware-application-path-policy) -and maintained [`NotariusPathConfig` example](../../examples/consumers/consumers.go) -own the application workflow, including its canonical symlink-base choice. - -`InputInfo` describes decoded configuration at callback entry, including retained -defaults and explicit nulls, and is unaffected by subsequent application changes. -`Source` resolves records already acquired for that load without filesystem, -credential, or parsing work. Both return detached records and require the existing -active callback context. - -ConfigKit continues to provide provenance rather than filesystem policy. Consumers -choose how to interpret relative paths, select default and CLI bases, and handle -missing or composite file provenance. The maintained example leaves values unchanged -with a warning when its chosen base is unavailable; it performs no existence or -confinement check. - -## Evidence and handoff - -The completed staged record is preserved at -`28e7fc5:docs/roadmap/implementation.md`; retrieve it with -`git show 28e7fc5:docs/roadmap/implementation.md`. It maps all twelve acceptance -criteria to focused lifecycle, provenance, ownership, consumer, explanation, and -secret tests. The final implementation commit is expected to run the source -checker and the documented two-toolchain gate before any release candidate is -selected. - -Publication remains a maintainer decision. Release preparation must choose the -version, write a version-matched note, retire this completed roadmap with link -repair, obtain the required exact-candidate Linux evidence, and follow the -[release procedure](../release.md).