Add semantic paths and safe diagnostics

This commit is contained in:
2026-09-06 19:19:24 +00:00
parent 8e3cc40c78
commit 14b10cb6a5
11 changed files with 936 additions and 45 deletions

View File

@@ -1,8 +1,14 @@
# Internal Component Overview
ConfigKit currently contains the root `configkit` package, which establishes the
module and package documentation boundary. It intentionally exposes no loading API
or implemented configuration behavior yet.
module and package documentation boundary. Its implemented public primitives are:
- immutable semantic `Path` construction and strict JSON Pointer parsing;
- detached provenance and diagnostic record types with empty `Metadata` queries;
- canonical, control-safe diagnostic rendering and structured `LoadError` access.
It intentionally exposes no loading, source, parsing, or decoding API yet. Private
metadata population will be integrated with loading when that lifecycle exists.
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; Stage 1 is complete and later stages are
Status: implementation in progress; Stages 1–2 are complete and later stages are
pending.
Audience: a `gpt-5.6-terra` coding agent implementing one stage per prompt, in
@@ -333,7 +333,25 @@ Acceptance:
## Stage 2 — Implement semantic paths and safe diagnostic records
Status: pending.
Status: complete.
Completion evidence (2026-09-06):
- Implemented immutable key/index paths, strict JSON Pointer parsing, canonical
spelling, parsed numeric-token preservation, and private traversal intent in
[`path.go`](../../path.go).
- Implemented detached metadata/provenance records and empty/unknown query behavior
in [`records.go`](../../records.go) and [`metadata.go`](../../metadata.go).
- Implemented canonical diagnostic ordering, related-location normalization,
control-safe rendering, short/error writer propagation, and defensive
`LoadError` access in [`diagnostic.go`](../../diagnostic.go). No raw values,
parser errors, source parsing, or loading surface was introduced.
- Added focused tests for escaped slash/tilde/empty/dotted/numeric keys, literal
dot/percent tokens, malformed escapes, builder immutability, detached nested
records, `errors.As`, ordering independence, control escaping, and failing/short
writers. Verified `go test ./...`, `go vet ./...`, `go build ./...`, and
`git diff --check` with Go 1.26.7 on linux/amd64. No deviations were required;
metadata population and configuration lifecycle behavior remain later work.
Read: feature [paths](initial.md#paths-and-presence),
[diagnostics](initial.md#provenance-diagnostics-and-redaction), public metadata API.

View File

@@ -451,16 +451,10 @@ large integers are not rounded through an intermediate floating-point value.
## Paths and presence
Use structured key/index segments internally. Public textual paths use
JSON Pointer escaping (`~0` for tilde and `~1` for slash), with the empty string
for the root. For example, `/transcription/concurrency` names a nested field;
`/outputs/a.b` addresses the literal key `a.b`. Numeric segments are interpreted
using the containing node's kind, distinguishing mapping keys from list indices.
Use YAML field names, not Go field names.
Semantic paths are not filesystem paths or URLs. Empty keys, literal `.`/`..`
keys, and percent sequences retain their meaning; do not clean path components
or percent-decode them. Only JSON Pointer escape processing applies.
Semantic path construction, JSON Pointer parsing, and current metadata query
declarations are implemented. Their current contracts are owned by the Go
documentation in [`path.go`](../../path.go) and [`metadata.go`](../../metadata.go).
The remaining presence behavior below is target lifecycle work.
Distinguish absent, explicitly null, explicitly zero/false/empty, and other
explicit values. An explicit value equal to its default remains explicit.
@@ -680,6 +674,11 @@ is outside this lifecycle. Do not run later hooks on an invalid typed value.
## Provenance, diagnostics, and redaction
Safe diagnostic/provenance value records, canonical diagnostic rendering, and
`LoadError` access are implemented. Their current contracts are owned by
[`records.go`](../../records.go) and [`diagnostic.go`](../../diagnostic.go).
Attaching those records to the loading lifecycle remains target work below.
Retain input sources, layer, line/column where available, import sites, effective
origins, overridden definition records, and resolution operations. Container
origins may be composite; never invent one file location for a mapping assembled
@@ -866,32 +865,11 @@ func ReadWorkerDefaults() (*configkit.Result[Config], error) {
### Paths and metadata
```go
func Keys(keys ...string) Path
func ParsePath(pointer string) (Path, error)
func (p Path) Key(key string) Path
func (p Path) Index(index int) Path
func (p Path) String() string
func (m Metadata) Lookup(path Path) (FieldInfo, bool)
func (m Metadata) IsExplicit(path Path) bool
func (m Metadata) History(path Path) []Change
```
`Path` is an immutable key/index representation with the textual form specified
in [paths and presence](#paths-and-presence). `Keys()` is the root. Key/index
builders escape dynamic names correctly; applications should not concatenate
pointer strings. Invalid indices and paths supplied to hooks become structured
errors. Path spelling uses YAML names throughout.
`FieldInfo` reports explicitness, null state, and effective `Origin`. An origin
identifies defaults, input, or application resolution and associated source
locations; it may be composite. `Change` reports layer/operation, prior origins,
safe reasons, dependency paths, and related locations. Safe historical values
are available through `Explain`, rather than unrestricted raw-value references. These are library-owned metadata types, never parser nodes. Queries
return copies or immutable views. Unknown paths yield no lookup/history and
false explicitness. Callback mutation/validation paths are checked more strictly:
misspelled struct fields are errors, while valid missing map entries are allowed.
The path API, detached metadata records, and empty/unknown query behavior are now
implemented; [`path.go`](../../path.go), [`records.go`](../../records.go), and
[`metadata.go`](../../metadata.go) own their current Go contracts. Populating
effective presence, origins, and history belongs to the loading stages. Callback
path checking and safe historical values remain target behavior below.
### Resolution and validation callbacks