Complete single-source semantic validation

This commit is contained in:
2026-09-06 20:19:58 +00:00
parent 0da4260ad6
commit a0cd0977ee
14 changed files with 484 additions and 31 deletions

View File

@@ -38,7 +38,8 @@ The current lifecycle is:
```text
validate options → parse one source → reject reserved directives → build schema
→ check the optional application version → create and clone defaults
→ strictly decode → snapshot configuration and metadata
→ strictly decode → recorded application resolution → semantic validation
→ snapshot configuration and metadata
```
`File`, `Bytes`, and `Reader` each contribute one base source with the deterministic
@@ -46,17 +47,17 @@ ID `source-1`. `NoSource` skips parsing, supplies an absent version to a configu
version checker, contributes no source, and continues through defaults, decode, and
projection. A missing file remains an error; it is never interpreted as no input.
The current `Options` boundary accepts a defaults factory and `VersionRule`.
Imports, active profiles, filesystem context, overrides, semantic validator
callbacks, and dynamic secret classification return an explicit
The current `Options` boundary accepts a defaults factory, `VersionRule`, resolver,
and semantic validator. Imports, active profiles, filesystem context, overrides,
and dynamic secret classification return an explicit
`options.unavailable` error because their lifecycle stages are not implemented.
The reserved profile spelling `default` selects no active profile. `NoSource`
additionally rejects imports, active profiles, and filesystem context as invalid
combinations. Input containing a reserved `_configkit` mapping key is rejected while
imports are disabled.
Every source, options, schema, version, defaults, or decode failure returns a nil
result and a `*LoadError`. Successful results contain caller-owned `Config`, detached
Every source, options, schema, version, defaults, decode, resolution, or validation
failure returns a nil result and a `*LoadError`. Successful results contain caller-owned `Config`, detached
`Metadata`, a defensive source list, and defensive nonfatal diagnostics. Mutating
the returned configuration or inspection records cannot alter ConfigKit's private
snapshot. ConfigKit performs no logging and exposes no effective writer yet.
@@ -122,6 +123,33 @@ retain history. ConfigKit privately snapshots each recorded before/after subtree
later safe explanation; caller mutations of `Result.Config` cannot alter those
snapshots.
### Semantic validation
An optional `Definition.Validate` callback runs after successful resolution and
receives the resolved configuration plus a per-load `Validation` context. It can
collect multiple independent `validate.error` and `validate.warning` reports.
Warnings continue the lifecycle and are returned on success; any error returns a nil
result with the full safe diagnostic and source report.
Primary and related paths must be valid for the application schema. Omitted declared
fields and missing string-map or dynamic keys are valid report targets; unknown
struct fields and malformed paths produce `validate.invalid_path`. ConfigKit attaches
the exact surviving input location when one exists, otherwise the nearest input
container location, or no primary location for defaults-only synthetic state.
Validation is read-only. ConfigKit projects the configuration immediately before and
after the callback and returns `validate.mutation` at every detected net-change path,
including nested mutable state. A value that can no longer be projected is also a
mutation failure. No mutated or otherwise invalid configuration is published.
Callback panics remain programming failures, and retained contexts use the same
fixed closed-context panic as version and resolution callbacks.
Only schema-bound exported state participates in loading, resolution audit,
validation audit, metadata, and snapshots. Ignored or unexported ordinary fields are
zero in returned detached values. Applications retain responsibility for domain
rules and runtime initialization; validators should not start clients or depend on
live services as a substitute for configuration validation.
## YAML documents
The private YAML boundary currently accepts exactly one nonempty document whose root

View File

@@ -3,7 +3,7 @@
This is the contributor entry point for ConfigKit. Read the task-specific owners
below before making changes. The repository is in early implementation: its public
loader currently covers one strict source, typed defaults, schema-version checks,
recorded application resolution, and metadata. The
recorded application resolution, semantic validation, and metadata. The
[component overview](internal/overview.md) owns the implementation inventory.
## Initial orientation

View File

@@ -203,6 +203,16 @@ intent, coalesced repeated writes, private before/after snapshots, deterministic
record ordering, and safe hook diagnostics. Semantic validation remains assigned to
the next lifecycle work.
Validation implementation record (2026-09-06): ConfigKit generalized Narratio's
`TestNormalizeLoadAndValidate`, `TestRepresentativeLoadDefaultsAndValidation`,
strict registry decoding, and maintained extraction-example expectations into the
post-resolution `Validation` lifecycle and synthetic consumer examples. ConfigKit
keeps domain rules application-owned, resolves schema-valid missing/dynamic report
paths to nearest input locations, collects independent warnings/errors, and audits
the full typed projection to reject validator mutation. Live resources, registries,
campaign/session logic, commands, and application runtime initialization were not
extracted.
### Secrets bootstrap
Assigned to the explicit bootstrap operation:

View File

@@ -22,11 +22,13 @@ module and package documentation boundary. Its implemented public primitives are
`load_metadata.go`; and
- recorded application defaulting and normalization in `resolution.go`, including
explicitness queries, helper verification, structural mutation audit, coalesced
intent, private before/after snapshots, and resolution metadata integration.
intent, private before/after snapshots, and resolution metadata integration; and
- post-resolution schema-aware report collection and validator mutation detection in
`validation.go`, completing the public single-source callback lifecycle.
The [configuration contract](../config.md) owns implemented input, schema, decoding,
single-source lifecycle, version checking, recorded resolution, metadata, and
ownership behavior.
single-source lifecycle, version checking, recorded resolution, semantic validation,
metadata, and ownership behavior.
The source-extraction inventory records the application foundations assigned to
future implementation work:

View File

@@ -2,7 +2,7 @@
## Status and ownership
Status: implementation in progress; Stages 1–8 are complete and later stages are
Status: implementation in progress; Stages 1–9 are complete and later stages are
pending.
Audience: a `gpt-5.6-terra` coding agent implementing one stage per prompt, in
@@ -744,7 +744,37 @@ Acceptance:
## Stage 9 — Add semantic validation and finish the single-source lifecycle
Status: pending.
Status: complete.
Completion evidence (2026-09-06):
- Reused `Validation` for post-resolution application reports in
[`validation.go`](../../validation.go), with `validate.error`,
`validate.warning`, and `validate.invalid_path` classifications. Omitted declared
fields and missing string-map/dynamic keys remain valid report paths; unknown
struct fields and malformed primary or related paths fail safely.
- Attached exact or nearest input locations to primary and related reports, retained
independent errors and warnings, continued through warnings, and returned no
configuration on any semantic error. Version, decode, and resolution failures stop
before later hooks.
- Added before/after typed projection around the validator. Any net scalar,
container, or nested mutable-state change, and any newly unprojectable value,
returns `validate.mutation` without publishing the mutated object. Callback
contexts close after invocation and callback panics remain programming failures.
- Removed the semantic-validator options gate, finalized metadata only after
successful resolution/validation, and retained defensive configuration snapshot,
metadata, diagnostic, and source ownership. The
[current semantic-validation contract](../config.md#semantic-validation) owns the
completed single-source lifecycle and application/runtime-state boundary.
- Added compiling executable examples in [`example_test.go`](../../example_test.go)
for minimal loading, defaults-only operation, related-path validation, actionable
schema-version guidance, and resolution followed by validation. Focused tests cover
multiple reports, missing/dynamic paths, related/nearest locations, invalid paths,
validator mutation, hook ordering and stop points, warnings, and final value/
explicitness/origin/history agreement. Verified `go test ./...`,
`go test -race ./...`, `go vet ./...`, `go build ./...`, `go mod tidy -diff`, and
`git diff --check` with Go 1.26.7 on linux/amd64. No deviations were required;
imports and profiles remain deliberately unavailable.
Read: feature [diagnostic callbacks](initial.md#resolution-and-validation-callbacks)
and [schema reports](initial.md#schema-checking-and-secret-classification).

View File

@@ -582,10 +582,10 @@ independently captured resolved results are implemented. The
[current ownership contract](../config.md#typed-projection-and-ownership) owns those
mechanics.
Application semantic validation runs after successful resolution and collects
independent errors in a standard diagnostic form. Validators are read-only and
own domain requirements; checking live S3 buckets or starting runtime clients
is outside this lifecycle. Do not run later hooks on an invalid typed value.
Application semantic validation is implemented. The
[current semantic-validation contract](../config.md#semantic-validation) owns
schema-aware reporting, nearest locations, warning/error behavior, mutation audit,
callback lifetime, and application/runtime responsibility boundaries.
## Provenance, diagnostics, and redaction
@@ -795,9 +795,10 @@ behavior. Layered callback history and safe historical values remain target beha
### Resolution and validation callbacks
The resolution declarations and behavior below are implemented; the
[current recorded-resolution contract](../config.md#recorded-application-resolution)
is authoritative. Semantic validation behavior in this section remains target work.
The resolution and semantic-validation declarations and behavior below are
implemented. The [current recorded-resolution contract](../config.md#recorded-application-resolution)
and [semantic-validation contract](../config.md#semantic-validation) are
authoritative.
```go
func (r *Resolution) IsExplicit(path Path) bool