diff --git a/docs/config.md b/docs/config.md index 08be599..8a12a6d 100644 --- a/docs/config.md +++ b/docs/config.md @@ -306,6 +306,61 @@ error without reporting one, ConfigKit emits a generic `version.hook_failed` diagnostic and suppresses the returned error text. Warnings alone are retained on a successful result. Callback panics remain programming failures. +#### Shared source-version checks + +`Options.SourceVersionMode` and `LayeredOptions.SourceVersionMode` select how +one `Definition.Version` policy applies across source documents. The zero value +`SourceVersionModeDefault` preserves the existing main-only check at its +effective path and existing protected-path behavior. `SourceVersionModeIfPresent` +checks each participating document that declares a version and permits absent +non-main declarations. `SourceVersionModeRequired` rejects a participating +document without a declaration. Enabled modes require a usable `VersionRule` +and checker; an unknown mode or unusable rule is an options error before source +access or callbacks. + +In enabled modes, `Definition.Version.Path` is interpreted in each acquired +document's own coordinates, before placement and composition. The main document, +direct underlay documents, imported documents (including transitive and glob +matches), and the selected overlay participate. `NoSource`, absent optional +imports, empty underlay groups, defaults, resolution output, inheritance, and +synthetic CLI overrides are not documents to check. An absent declaration in an +actual main document still reaches the checker in if-present mode; required mode +rejects it first. With `NoSource`, the existing single absent-main checker +behavior remains in both enabled modes. If-present omissions in non-main +documents skip the checker. Explicit null is present and reaches the checker; +unsupported selected values produce `version.type`. No equality with the main +declaration or non-null rule is imposed. Acceptance establishes only that the +declaration is accepted by the consumer's checker; it does not establish that +each fragment conforms to a complete application schema. Final assembled +decoding and application validation still run once. + +Accepted non-main declarations are consumed from their owned payload before +composition; their authored ancestors remain, even if empty. The main +declaration remains in the application. Ordinary release metadata should use a +different path. Enabled main protection uses the main input's effective path: +its `Destination` prefixed to the source-local `VersionRule.Path`. This protects +the remaining payload against imports, underlays, inheritance, and CLI +overrides. Thus a mounted main looks up a local header while ownership checks +protect its destination-prefixed application path. Main checker diagnostics and +declaration locations use source-local coordinates; ordinary payload +diagnostics continue to use effective paths. Default-mode diagnostics are +unchanged. + +`SourceInfo.VersionCheck` is nil when enabled declaration processing did not +occur. Otherwise it records a source-local `Path`, the observed `Version` state +(`Present`, `Null`, and, when disclosed, exact `Text`), an actual or nearest +available `Location`, and whether text was redacted. A non-nil record with +`Present == false` records observed absence; it does not say the checker ran or +accepted a declaration. During callbacks and in failed-load source records, +text is conservatively withheld because final classification may not be +available. Successful final source records reflect completed sensitivity +classification at the declaration's mounted path and ancestors, including +historical classification. Redaction empties `Text` while retaining presence +and null state. Returned copies are detached; evidence does not reopen inputs. +Consult [ADR 0013](adr/0013-shared-source-version-checks.md) for the accepted +decision and the [source-version roadmap](roadmap/source-version-checks.md) for +its implementation record. + ### Layered metadata `Result.Metadata` describes every final canonical path. Queries retain explicit diff --git a/docs/consumers/README.md b/docs/consumers/README.md index c43e4ed..dae7a86 100644 --- a/docs/consumers/README.md +++ b/docs/consumers/README.md @@ -20,6 +20,7 @@ sanitized shapes using only ConfigKit and the Go standard library: | Mounted collections | Entry-declared relative destinations, nested metadata/prompt/profile imports, local inheritance, and a version-only higher-tier override | Collection IDs, profile meaning, and opening/interpreting prompt resources | | Named presets | One-load sibling inheritance, explicit false, nested destination resolution, and source/derivation inspection | Choosing and executing a preset | | Effective configuration diff | Same-type frozen effective comparisons for two selected files or base-versus-overlay impact | Source/options selection and consumer-owned safe presentation | +| Shared source-version checks | One `Definition.Version` policy for accepted declarations across participating source documents, with optional or required declarations and sanitized evidence | Choosing which declarations the application accepts; final assembled schema and domain validation | The YAML under [`testdata`](../../examples/consumers/testdata) is loaded by the executable examples and ordinary tests. It contains no private application data, @@ -53,6 +54,18 @@ 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. +## Shared source-version checks + +[`LoadVersionedService`](../../examples/consumers/source_version.go) demonstrates +if-present and required modes with one `Definition.Version` rule across a mounted +main input and an underlay. The example reads only sanitized +`SourceInfo.VersionCheck` fields; its executable test is in +[`layered_test.go`](../../examples/consumers/layered_test.go). The +[configuration contract](../config.md#shared-source-version-checks) defines +participation, source-local lookup and diagnostics, non-main header consumption, +main-path protection, default behavior, and evidence disclosure. Accepted +declarations do not replace final assembled decoding or application validation. + ## Effective configuration diffs [`CompareFiles`](../../examples/consumers/diff.go) loads two caller-selected files diff --git a/docs/development.md b/docs/development.md index 827ea48..cddd010 100644 --- a/docs/development.md +++ b/docs/development.md @@ -40,6 +40,7 @@ public behavior. | --- | --- | | Repository orientation or component responsibility | [Component overview](internal/overview.md) | | Input destinations | [Configuration contract](config.md#input-destinations), [ADR 0011](adr/0011-input-destinations.md), and the destination tests below | +| Shared source-version checks | [Configuration contract](config.md#shared-source-version-checks), [ADR 0013](adr/0013-shared-source-version-checks.md), and the version/source-version tests below | | Documentation changes | The owning document | | Licensing, dependencies, attribution, or release-document changes | [Project grant](../COPYRIGHT) and [attribution](oss/attribution.md); release changes also follow the release procedure | | Architecture decisions or future work | [Deferred scope](roadmap/deferred.md) and relevant ADRs listed below | @@ -168,6 +169,7 @@ code changes. Use the component overview to find the corresponding implementatio | Sibling inheritance, provenance, history, sensitivity | [Expansion](../internal/engine/inheritance_test.go), [destination scopes](../internal/engine/inheritance_walk_test.go), [origins](../internal/engine/inheritance_origin_test.go), [history](../internal/engine/inheritance_history_test.go), [secrets](../internal/engine/inheritance_secret_test.go), [public loading](../facade_inheritance_test.go) | `go test ./internal/engine -run 'Inheritance\|Inherited'` and `go test . -run '^TestFacadeInheritance\|^TestFacadeInheritedSecrets'` | | Layered loading and source equivalence | [Grouped lifecycle](../internal/engine/load_request_test.go), [layered facade](../facade_layered_test.go), [equivalence](../facade_equivalence_test.go) | `go test ./internal/engine -run '^TestGrouped'`, `go test . -run '^TestFacadeLayered'`, and `go test . -run '^TestEquivalentSourceForms'` | | Input and relative-import destinations, mounted sources, and source ownership | [Destination engine tests](../internal/engine/destination_test.go), [tier tests](../internal/engine/destination_tiers_test.go), [import traversal and version tests](../internal/engine/destination_import_test.go), [accounting tests](../internal/engine/destination_accounting_test.go), [lifecycle inspection tests](../internal/engine/destination_import_lifecycle_test.go), [public source/error tests](../facade_destination_test.go), [resource contexts](../facade_resource_context_test.go), and [consumer examples](../examples/consumers/destinations_test.go) | `go test ./internal/engine -run 'Destination|Import|Glob|Mounted'`, `go test . -run 'Destination|Import|SourceContext|FacadeMounted'`, and `go test ./examples/consumers` | +| Shared source-version modes and evidence | [Engine source-version tests](../internal/engine/source_version_test.go), [public facade tests](../facade_source_version_mode_test.go), and [consumer example tests](../examples/consumers/layered_test.go) | `go test ./internal/engine -run 'SourceVersion'`, `go test . -run 'SourceVersion'`, and `go test ./examples/consumers` | | Schema, defaults, projection, cloning | [Schema](../internal/engine/schema_test.go), [decoding](../internal/engine/decode_test.go), [projection](../internal/engine/projection_test.go) | `go test ./internal/engine -run 'Schema\|Decode\|Projection\|Clone\|Inline\|CompareDocument'` | | Lifecycle, resolution, validation, callback ownership | [Loading](../internal/engine/load_test.go), [resolution](../internal/engine/resolution_test.go), [validation](../internal/engine/validation_test.go), [ownership](../internal/engine/callback_ownership_test.go), [independence](../internal/engine/independence_test.go) | `go test ./internal/engine -run 'Load\|Resolution\|Validation\|Validator\|Hook\|Callback\|Parallel'` | | Paths, metadata, provenance | [Paths](../internal/engine/path_test.go), [metadata](../internal/engine/metadata_test.go), [provenance](../internal/engine/provenance_test.go) | `go test ./internal/engine -run 'Path\|Metadata\|Provenance\|Queries'` | diff --git a/docs/internal/overview.md b/docs/internal/overview.md index 8331bd7..1019f3d 100644 --- a/docs/internal/overview.md +++ b/docs/internal/overview.md @@ -10,7 +10,8 @@ Implemented component owners: - `internal/engine` owns host and native-filesystem source acquisition, grouped strict composition, recursive precedence assembly, per-input mapping placement and immediate-parent-relative import placement within that - assembly, and destination-local sibling inheritance before typed decoding. + assembly, destination-local sibling inheritance before typed decoding, and + shared source-version checking with sanitized declaration evidence. It retains each source's effective placement alongside physical source identity and owns schema inspection, lifecycle coordination, callback auditing, @@ -44,7 +45,8 @@ 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) and +semantics, including [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 [consumer adoption guide](../consumers/README.md) owns application guidance. The [architecture policy](../policy/architecture.md) owns contributor @@ -55,4 +57,5 @@ decision. See the [development guide](../development.md) for validation commands and [release procedure](../release.md) for source-candidate gates. [ADR 0009](../adr/0009-sibling-inheritance.md) records why inheritance is a built-in post-assembly structural operation. [ADR 0012](../adr/0012-relative-import-destinations.md) -records the relative-import extension. +records the relative-import extension; [ADR 0013](../adr/0013-shared-source-version-checks.md) +records the source-version decision. diff --git a/docs/roadmap/implementation.md b/docs/roadmap/implementation.md index 73d627a..23b5bf7 100644 --- a/docs/roadmap/implementation.md +++ b/docs/roadmap/implementation.md @@ -1,6 +1,6 @@ # Implement shared source version checks -Status: Stages 1–13 complete; documentation reconciliation remains. +Status: complete. All 14 implementation stages are validated. Audience: a Luna coding agent implementing one numbered stage per prompt, in order. The [feature roadmap](source-version-checks.md) owns target behavior and @@ -668,3 +668,27 @@ No environmental limitation affected validation; checks ran on Linux/amd64. Done: implementation, coverage, documentation, and approved scope agree. No product questions remain open under the roadmap and concrete decisions above. + +Completion evidence: updated the public Go comments, configuration contract, +consumer guidance, development guide, and component ownership summary for the +implemented behavior. Reconciled the original source-version request with later +accepted decisions, marked the source-version roadmap implemented, and repaired +relative-import/remediation references to the overwritten plan using the +confirmed `d9f08ff:docs/roadmap/implementation.md` history pointer. The scope +audit found no default-mode expansion, equality/non-null rule, extra path +restriction, fragment decoding, callback-order promise, new uniqueness/cap, +unsafe evidence query, or release gate. Reviewed behavioral coverage in +`internal/engine/source_version_test.go`, +`facade_source_version_mode_test.go`, +`internal/engine/secret_classification_test.go`, +`internal/engine/inheritance_secret_test.go`, and +`examples/consumers/layered_test.go`. These checks passed with Go +`go1.26.8 linux/amd64`: + +- `GOTOOLCHAIN=local ./scripts/check.sh` +- `GOTOOLCHAIN=local GOPROXY=off go test . -run '^TestLocalDocumentationLinks$' -count=1` +- `git diff --check` + +No runtime code changed in this documentation unit, so the race suite was not +rerun. No environmental limitation affected validation; checks ran on +Linux/amd64 only. Publication and release preparation remain outside this work. diff --git a/docs/roadmap/promptkit-feature-request.md b/docs/roadmap/promptkit-feature-request.md index 39fc2ba..0936542 100644 --- a/docs/roadmap/promptkit-feature-request.md +++ b/docs/roadmap/promptkit-feature-request.md @@ -284,6 +284,12 @@ new limit values or their accounting machinery. ## Partially Accepted Addition: Shared Source Specification Checks +Status: the shared-policy portion below is implemented. Current behavior is +defined by the [configuration contract](../config.md#shared-source-version-checks), +and the accepted decision and implementation evidence are in +[ADR 0013](../adr/0013-shared-source-version-checks.md) and the +[source-version roadmap](source-version-checks.md). + ### Accepted Scope A ConfigKit consumer defines one configuration specification, which may evolve @@ -322,16 +328,19 @@ separate from `Definition.Version`, with ordinary imports exempt from independen checks. It also recommended consuming accepted entry headers and exposing them as source evidence while leaving imported release metadata untouched. -That full set of semantics has not been accepted. The accepted direction uses -one shared `Definition.Version` policy and optional or required declarations -across participating sources. Separately versioned subsets or collections are -outside this addition's scope and may be considered independently in the future. -Header consumption and inspection from the original proposal remain design -suggestions, not accepted requirements. +The independent collection-entry policies and exemption for ordinary imports +were not accepted. The accepted direction instead uses one shared +`Definition.Version` policy and optional or required declarations across +participating sources. Separately versioned subsets or collections remain +outside this addition's scope. Header consumption and sanitized source evidence, +which were suggestions in the original proposal, were subsequently accepted for +this shared-policy design and are implemented as described by the linked +contract. -### Remaining Design Work +### Design Questions Resolved by the Accepted Roadmap -The following details remain to be resolved before implementation: +The following questions were open in the original request and are resolved by +the accepted roadmap and ADR 0013: - How the configured declaration path is interpreted for individual sources, particularly before destination placement. @@ -345,10 +354,11 @@ The following details remain to be resolved before implementation: existing string/decimal-integer version vocabulary. - The opt-in API, callback lifecycle, and source-local diagnostic attribution. -In particular, the original example of an imported `version: "2.4.0"` release -label is not guaranteed to remain outside checking in an enabled mode. That -depends on the chosen header lookup semantics. No automatic field consumption, -new coercion, or per-collection checker should be inferred from partial acceptance. +In particular, an imported `version: "2.4.0"` at the configured source-local +header path is checked and consumed in an enabled mode. Consumers that need an +ordinary release label retain it at a different path. No automatic field +consumption applies in the default mode, and no new coercion or per-collection +checker is part of the implemented design. ## Requested Addition: Relative Import Destinations diff --git a/docs/roadmap/relative-import-destinations.md b/docs/roadmap/relative-import-destinations.md index d96bc46..d7afb7f 100644 --- a/docs/roadmap/relative-import-destinations.md +++ b/docs/roadmap/relative-import-destinations.md @@ -1,12 +1,12 @@ # Relative Import Destinations Roadmap -Status: complete. The -[implementation plan](implementation.md) preserves sequencing, behavior -evidence, and the final compatibility audit. +Status: complete. The implementation plan and its evidence were replaced by the +shared source-version plan and remain in Git history at +`d9f08ff:docs/roadmap/implementation.md`. This roadmap addresses only the relative-import-destination addition in the [PromptKit request](promptkit-feature-request.md#requested-addition-relative-import-destinations). -Independent source specification headers are deferred for reconsideration after -this work is implemented; they are not a prerequisite or part of this feature. +Source-version checks were outside this roadmap's scope and are now implemented +separately in the [shared source-version roadmap](source-version-checks.md). ## Targeted end state diff --git a/docs/roadmap/remediation.md b/docs/roadmap/remediation.md index fff280f..b38f7bb 100644 --- a/docs/roadmap/remediation.md +++ b/docs/roadmap/remediation.md @@ -2,7 +2,7 @@ Reviewed `d3d468a..945e111` against the approved [input-destinations roadmap](input-destinations.md), -input-destination implementation plan (preserved at +input-destination implementation plan (preserved in Git history at `315f464:docs/roadmap/implementation.md`), and [ADR 0011](../adr/0011-input-destinations.md). @@ -93,7 +93,8 @@ Required remediation: Reviewed `7248a8b..10edd95` against the [relative-import roadmap](relative-import-destinations.md), completed -[implementation plan](implementation.md), and +implementation plan (preserved in Git history at +`d9f08ff:docs/roadmap/implementation.md`), and [ADR 0012](../adr/0012-relative-import-destinations.md). The implementation matches the selected architecture: literal string segments diff --git a/docs/roadmap/source-version-checks.md b/docs/roadmap/source-version-checks.md index defabb5..862e38f 100644 --- a/docs/roadmap/source-version-checks.md +++ b/docs/roadmap/source-version-checks.md @@ -1,9 +1,10 @@ # Shared Source Version Checks Roadmap -Status: design decisions are recorded in [ADR 0013](../adr/0013-shared-source-version-checks.md); -implementation has not started. The -[implementation plan](implementation.md) owns execution order, concrete API and -integration decisions, and completion evidence. This roadmap develops the +Status: implemented and validated. Current behavior is owned by the +[configuration contract](../config.md#shared-source-version-checks), and the +accepted decision is recorded in [ADR 0013](../adr/0013-shared-source-version-checks.md). +The completed [implementation plan](implementation.md) records execution and +validation evidence. This roadmap develops the partially accepted source-version request in [PromptKit's proposal](promptkit-feature-request.md#partially-accepted-addition-shared-source-specification-checks) using the consumer's single `Definition.Version` policy. The design direction @@ -19,8 +20,10 @@ is one consumer-owned configuration specification and one acceptance policy. Different accepted declarations may coexist: ConfigKit does not require exact equality with the main declaration, impose SemVer, or invent an expected value. -The consumer selects a load-wide enum on ordinary and layered options. Its zero -value retains current behavior; the implementation plan selects exported names. +The consumer selects `SourceVersionMode` on ordinary and layered options. Its +zero value retains current behavior. The modes are +`SourceVersionModeDefault`, `SourceVersionModeIfPresent`, and +`SourceVersionModeRequired`. The same `Definition.Version` can be reused across loads with different strictness. The three modes are: @@ -204,8 +207,9 @@ outside this feature's completion criteria. The maintainer has accepted all three decisions below. Together with the mode API location, source participation, main-path handling, source-record evidence, and nested mapping ancestor preservation above, these settle the discussed -product decisions. The [implementation plan](implementation.md) selects public -names and integration mechanics; the feature is not yet implemented. +product decisions. Public names and integration mechanics are recorded in the +completed [implementation plan](implementation.md); current behavior belongs +to the [configuration contract](../config.md#shared-source-version-checks). ### Sensitivity of consumed declaration evidence diff --git a/layered.go b/layered.go index 1cf945d..423a67d 100644 --- a/layered.go +++ b/layered.go @@ -25,7 +25,9 @@ type Underlay struct{ Inputs []Input } // ignores it. Overrides remain explicit CLI records, not general mappings. // SourceVersionMode applies one declaration policy to main, underlay, import, // and selected overlay documents. Enabled modes interpret the version path -// source-locally while protecting main's destination-prefixed path. +// source-locally, consume accepted non-main declarations, and protect main's +// destination-prefixed path. The zero value preserves existing behavior; see +// the shared source-version contract in docs/config.md. type LayeredOptions[T any] struct { Definition Definition[T] SourceVersionMode SourceVersionMode diff --git a/lifecycle.go b/lifecycle.go index 41e3926..262ab6e 100644 --- a/lifecycle.go +++ b/lifecycle.go @@ -18,7 +18,10 @@ type Definition[T any] struct { } // SourceVersionMode controls schema-version declarations across one complete -// load. The zero value preserves the existing effective-path version check. +// load. The zero value preserves the existing main-only effective-path check +// and its protected-path behavior. Enabled modes check participating documents +// at source-local Definition.Version.Path coordinates and consume accepted +// non-main declarations. See the shared source-version contract in docs/config.md. type SourceVersionMode uint8 const ( @@ -77,7 +80,10 @@ type Override struct { type Resolution struct{ value *engine.Resolution } // VersionRule declares the input path and application checker for a schema version. -// At that path, string and decimal-integer input is supplied as Version.Text. +// Default source-version mode interprets Path as the existing effective path; +// enabled modes interpret it in each participating document's local coordinates. +// At the selected path, strings and strict decimal integers supply their exact +// spelling as Version.Text. See docs/config.md for the complete contract. type VersionRule struct { Path Path Check func(Version, *Validation) error diff --git a/records.go b/records.go index c840e26..cde66ae 100644 --- a/records.go +++ b/records.go @@ -197,14 +197,21 @@ type SourceInfo struct { Kind SourceKind UnderlayIndex int ImportedFrom *Location - // VersionCheck is the sanitized source-local version declaration observed - // during an enabled source-version load. It is nil otherwise. + // VersionCheck is sanitized evidence for source-local declaration processing + // in an enabled source-version load. It is nil when that processing did not + // occur, including default mode and synthetic CLI sources. During callbacks + // and failed loads, text is conservatively withheld; successful final source + // records reflect completed sensitivity classification. VersionCheck *SourceVersionCheck } // SourceVersionCheck describes a source-local version declaration observed -// during an enabled load. Text is empty when classification or conservative -// early-access redaction withholds it; Present and Null retain their meaning. +// during an enabled load. A non-nil record with Present false records observed +// absence, but does not imply that a checker ran or accepted a value. Text is +// empty when sensitivity classification or conservative callback-time/failed- +// load redaction withholds it; Present and Null retain their meaning. Copies +// returned by source queries are detached. See docs/config.md for disclosure +// and lifecycle details. type SourceVersionCheck struct { Path Path Version Version