Add safe historical configuration explanations
This commit is contained in:
@@ -1365,7 +1365,43 @@ Acceptance:
|
||||
|
||||
## Stage 19 — Expose safe historical-value explanation
|
||||
|
||||
Status: pending.
|
||||
Status: complete.
|
||||
|
||||
Completion evidence (2026-09-06):
|
||||
|
||||
- Added detached `ValueSnapshot`, `ValueChange`, `SecretReferenceInfo`, and
|
||||
`Explanation` records plus `Result.Explain` and `Result.WriteExplanation` in
|
||||
[`explain.go`](../../explain.go). Effective/default/domain values use canonical
|
||||
typed projection; base/profile/CLI events preserve policy-validated input, with
|
||||
explicit absent, null, equal-write, replacement, and deletion states.
|
||||
- Extended composition, profile, and CLI handling to retain immutable applications
|
||||
in traversal/precedence order. Explanation replays those applications on demand
|
||||
with mapping recursion and atomic sequence replacement, then applies the existing
|
||||
audited resolution subtree deltas. This reconstructs container and descendant
|
||||
histories without a full retained tree per field, including superseded input that
|
||||
could not decode into the final destination type.
|
||||
- Applied tag, predicate, and dependency-cycle sensitivity across final and
|
||||
historical application paths before snapshot projection. Snapshots recursively
|
||||
redact classified descendants, resolved `Secret` metadata retains only successful
|
||||
effective environment names, and classified references omit that annotation.
|
||||
Shared immutable nodes count once toward a fixed 4,000,000-node retained-history
|
||||
budget; excess fails safely with `explain.limit_exceeded`.
|
||||
- Added deterministic human rendering with canonical quoted pointer paths, effective
|
||||
and composite source locations/labels, representation labels, chronological
|
||||
before/after YAML, reasons, dependencies, and secret lookup attribution. Unknown
|
||||
paths write nothing; writer errors and short writes propagate. Added executable
|
||||
`ExampleResult_Explain` and moved normative behavior to the
|
||||
[current explanation contract](../config.md#historical-value-explanation), keeping
|
||||
bootstrap reporting explicitly separate.
|
||||
- Added focused coverage in [`explain_test.go`](../../explain_test.go) for the
|
||||
imported-default/profile sequence 4 → 8 → 1, CLI and normalization, equal writes,
|
||||
removed paths, parent replacement, composite mappings, atomic sequences,
|
||||
superseded invalid input, null/empty values, successful and classified references,
|
||||
historical/dependency-cycle canaries, returned-record mutation, deterministic and
|
||||
failing writers, structural-sharing budgets, and an end-to-end secrets-bootstrap/
|
||||
load/explain flow. 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; consumer ergonomics remain later work.
|
||||
|
||||
Read: [explanation contract](initial.md#historical-value-explanation), redaction
|
||||
rules, and history bounds above.
|
||||
|
||||
@@ -916,7 +916,9 @@ the [current redaction contract](../config.md#secret-classification-and-effectiv
|
||||
`Result.Config`, `Metadata`, `Sources`, `Diagnostics`, and `WriteEffective`, together
|
||||
with `LoadError` and `WriteDiagnostics`, are implemented at the current loading boundary.
|
||||
The [current loading contract](../config.md#single-source-loading) and Go reference
|
||||
comments own their behavior. Historical-value explanation below remains target work.
|
||||
comments own their behavior. Historical-value explanation is also implemented and
|
||||
owned by the
|
||||
[current explanation contract](../config.md#historical-value-explanation).
|
||||
|
||||
```go
|
||||
type Result[T any] struct {
|
||||
@@ -976,74 +978,14 @@ func InspectPipeline(path, profile string, output io.Writer) error {
|
||||
|
||||
Applications can use `Metadata().Lookup`, `Metadata().History`, and `Sources()`
|
||||
for structured inspection without implementing value rendering or importing a
|
||||
parser. The explanation API below supplies safe values and formatting for application-owned
|
||||
`config explain` commands.
|
||||
parser. The implemented explanation API supplies safe values and formatting for
|
||||
application-owned `config explain` commands.
|
||||
|
||||
### Historical-value explanation
|
||||
|
||||
```go
|
||||
func (r *Result[T]) Explain(path Path) (Explanation, bool)
|
||||
func (r *Result[T]) WriteExplanation(output io.Writer, path Path) error
|
||||
|
||||
type Explanation struct {
|
||||
Path Path
|
||||
Effective ValueSnapshot
|
||||
Origin Origin
|
||||
History []ValueChange
|
||||
SecretReference *SecretReferenceInfo
|
||||
}
|
||||
type ValueSnapshot struct {
|
||||
Present bool
|
||||
Redacted bool
|
||||
YAML string
|
||||
}
|
||||
type ValueChange struct {
|
||||
Before, After ValueSnapshot
|
||||
Origin Origin
|
||||
Reasons []string
|
||||
Dependencies []Path
|
||||
}
|
||||
type SecretReferenceInfo struct { Name string } // successful resolved lookup
|
||||
```
|
||||
|
||||
Snapshots contain detached deterministic YAML text, never `any`, parser objects,
|
||||
or mutable internal trees. `Present=false` is absence/deletion and has empty YAML;
|
||||
null is present with `null` YAML. Redacted snapshots use the quoted marker
|
||||
`[REDACTED]`; `Redacted` also marks containers containing redacted descendants.
|
||||
Apply the same historical sensitivity/dependency closure as effective rendering
|
||||
before exposing any snapshots. A `Secret` projects only its environment name;
|
||||
its resolved value is never captured, even privately as history. For classified
|
||||
reference paths omit `SecretReference` as well as masking the projected name.
|
||||
|
||||
Retain private persistent node snapshots or operation deltas with structural
|
||||
sharing; do not copy the entire tree for every changed leaf. Explain a known final
|
||||
or historical path, including removed paths; unknown paths return false, and the
|
||||
writer returns a safe unknown-path error without output. Malformed query paths
|
||||
also fail safely. Render the canonical JSON-pointer path, effective value/source,
|
||||
and chronological history: initial application-default (or Go-zero baseline),
|
||||
base contributions in traversal order, profile, CLI, and recorded domain changes.
|
||||
Include before/after values for changed or explicitly redefined paths, equal-value
|
||||
writes, removals, reasons/dependencies, and composite origins. Inputs overridden
|
||||
before decoding retain policy-validated node values even when they would not fit
|
||||
the final Go type. Defaults/final/domain snapshots use canonical typed projection;
|
||||
label those representations rather than claiming every historical input was typed.
|
||||
|
||||
Container queries reconstruct the value at each relevant operation; descendant
|
||||
queries include ancestor replacement/removal and whole-sequence replacements,
|
||||
without implying element-wise sequence merging. Omitted fields/default retention
|
||||
must agree with the presence/default contract; do not fabricate a write for every
|
||||
import that leaves a path alone. Resolution history records the audited net change
|
||||
per path, not every intermediate Go assignment. Lookup of a secret reference
|
||||
annotates its effective name as resolved from the process environment; bootstrap
|
||||
file outcomes come from the separate report and are never guessed.
|
||||
|
||||
`WriteExplanation` is a deterministic human renderer over this safe structured
|
||||
result. Escape control characters in paths, labels, names, and reasons, propagate
|
||||
writer errors/short writes, and permit partial output only on writer failure.
|
||||
No unredacted switch or bundled command is provided. For example an application
|
||||
can call it for `/transcription/concurrency` to show default `4`, an explicitly
|
||||
imported file's `8`, then a testing profile's `1`, with file line numbers and the
|
||||
profile as effective source. This does not require automatic `conf.d` discovery.
|
||||
Historical explanation is implemented. The
|
||||
[current explanation contract](../config.md#historical-value-explanation) owns its
|
||||
public records, replay ordering, redaction, rendering, and allocation bounds.
|
||||
|
||||
### Module-specific options
|
||||
|
||||
|
||||
Reference in New Issue
Block a user