Document and audit effective configuration diffs
This commit is contained in:
@@ -20,7 +20,11 @@ secrets-directory bootstrap is available as a separate startup operation. Explic
|
||||
CLI override records apply above overlays. Value explanation is available through
|
||||
detached structured records and deterministic redacted output. Built-in
|
||||
`extends` relationships let a mapping inherit from a named sibling during the
|
||||
same load, retaining explicit presence and source/derivation history.
|
||||
same load, retaining explicit presence and source/derivation history. The root
|
||||
`Diff` API compares frozen effective values from two successful same-type loads;
|
||||
the [configuration contract](docs/config.md#effective-configuration-diffs) and
|
||||
[consumer guide](docs/consumers/README.md#effective-configuration-diffs) describe
|
||||
its safe changed-region records and maintained workflows.
|
||||
|
||||
```go
|
||||
type Config struct {
|
||||
|
||||
@@ -423,6 +423,46 @@ an explicit `LoadSecretsDir` bootstrap, then use `WriteDiagnostics`,
|
||||
ConfigKit does not infer bootstrap outcomes from a secret reference and does not
|
||||
bundle these independent reports into a command framework.
|
||||
|
||||
## Effective configuration diffs
|
||||
|
||||
`configkit.Diff(left, right)` compares two completed successful loads of the same
|
||||
configuration type. `left` is the earlier state and `right` is the later state.
|
||||
Applications load both sides with the sources and options they choose; to inspect
|
||||
an overlay's impact, load the same base once without the overlay and once with it
|
||||
selected. The [consumer guide](consumers/README.md#effective-configuration-diffs)
|
||||
links to maintained examples. The public API returns safe changed-region records;
|
||||
applications own their presentation.
|
||||
|
||||
Comparison uses the frozen canonical effective inspection values, not mutable
|
||||
`Result.Config`, source text, provenance, or history. It does not reopen sources,
|
||||
reread environment variables, or rerun defaults or callbacks. Equal effective
|
||||
values produce no records even when sources, explicit-input status, defaults, or
|
||||
resolution histories differ; for example, explicit zero and defaulted zero are
|
||||
equal. Mappings compare recursively, sequences compare atomically, and scalar,
|
||||
kind, or null/container replacements report their affected region. Records use
|
||||
the existing comparator's canonical pointer ordering. `Present=false` with empty
|
||||
YAML means absence; explicit null is present and renders as `null`.
|
||||
|
||||
Before either side is returned, sensitivity from both loads is applied to both
|
||||
snapshots, including historical and dependency-derived classification. A
|
||||
classification on either side protects the corresponding values on both sides.
|
||||
`Redacted` reports masking, while `HiddenChanged` reports an actual concealed
|
||||
value or presence change; it is not implied merely by redaction. A structural
|
||||
replacement that prevents safe correspondence masks the complete reported
|
||||
region, and an absent side remains absent. Record membership establishes that a
|
||||
change occurred even when safe snapshots render identically. Literal
|
||||
marker-looking input is ordinary input; consumers use the record fields rather
|
||||
than interpreting marker text.
|
||||
|
||||
Typed secret references contribute their configured environment names to the
|
||||
frozen comparison, never resolved credential bytes. Credential rotation behind
|
||||
an unchanged reference is therefore not detected. The records contain changed
|
||||
regions only, not paired full-document context; independently calling
|
||||
`WriteEffective` on each result does not create cross-protected context. Nil or
|
||||
uninitialized results return an error with no records. A failed `Load` retains
|
||||
its normal nil-result/`LoadError` behavior, which callers handle before invoking
|
||||
`Diff`.
|
||||
|
||||
## Typed secret references
|
||||
|
||||
Credential-bearing fields use the opaque `Secret` type and store an environment
|
||||
|
||||
@@ -18,6 +18,7 @@ sanitized shapes using only ConfigKit and the Go standard library:
|
||||
| Bundled file | Simple native `fs.FS` source through ordinary `Load` | Selection and lifetime of the application-owned embedded filesystem |
|
||||
| Layered catalog | Embedded defaults with an import, a mapping underlay, an independent host main file, explicit false/zero input, and source-relative resource access | Domain validation and opening/interpreting the template resource |
|
||||
| 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 |
|
||||
|
||||
The YAML under [`testdata`](../../examples/consumers/testdata) is loaded by the
|
||||
executable examples and ordinary tests. It contains no private application data,
|
||||
@@ -51,6 +52,25 @@ 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.
|
||||
|
||||
## Effective configuration diffs
|
||||
|
||||
[`CompareFiles`](../../examples/consumers/diff.go) loads two caller-selected files
|
||||
with one application definition, handles each load error, calls `configkit.Diff`,
|
||||
and presents the safe records through consumer-owned `FormatDifferences`.
|
||||
[`CompareRolloutOverlay`](../../examples/consumers/diff.go) loads the same base
|
||||
once without an overlay and once with the selected overlay, so omitted lower
|
||||
priority values remain present. Its resolver records a derived endpoint URL after
|
||||
overlay application, and its nested typed secret reference is classified before
|
||||
the resulting records are presented.
|
||||
|
||||
The maintained [behavior tests and executable examples](../../examples/consumers/diff_test.go)
|
||||
use temporary files and disposable secret values. Presenters should use
|
||||
`ValueSnapshot.Present` for absence, record membership for change, and
|
||||
`HiddenChanged` for a withheld change indicator. Do not parse the redaction marker
|
||||
or add separately rendered full contexts that lack combined sensitivity. The
|
||||
[configuration contract](../config.md#effective-configuration-diffs) owns shared
|
||||
equality, granularity, and disclosure semantics.
|
||||
|
||||
## Named sibling inheritance
|
||||
|
||||
[`LoadPresets`](../../examples/consumers/inheritance.go) loads the maintained
|
||||
@@ -168,6 +188,7 @@ focused behavioral owner:
|
||||
| `LoadSecretsDir`, bootstrap reporting, typed lookup, CLI explanation | `Example_weatherStartup` |
|
||||
| Native filesystem, grouped underlays, programmatic mapping, retained resource context | `Example_nativeFilesystem`, `Example_layeredCatalog`, and their focused consumer tests |
|
||||
| Named sibling inheritance, presence, and derivation | `Example_inheritedPresets` and `TestPresetCatalogOneLoadAndDerivation` |
|
||||
| Effective configuration diffs and consumer-owned presentation | `ExampleDiff`, `ExampleCompareFiles`, and `ExampleCompareRolloutOverlay` |
|
||||
| Results, metadata, diagnostics, effective output, and writer failures | Focused root-package load, provenance, rendering, and explanation tests |
|
||||
|
||||
The package-level import-boundary test covers the consumer examples too: supported
|
||||
|
||||
@@ -54,6 +54,7 @@ Accepted decisions:
|
||||
- [Secret references and explicit bootstrap](adr/0004-secret-references-and-explicit-bootstrap.md)
|
||||
- [Explicit overrides and safe explanation](adr/0005-explicit-overrides-and-safe-explanation.md)
|
||||
- [Keep the public facade root-owned](adr/0006-public-facade.md)
|
||||
- [Compare frozen effective configuration snapshots](adr/0010-effective-configuration-diff.md)
|
||||
|
||||
For cross-cutting changes, follow every applicable row. Completed implementation
|
||||
and remediation plans are preserved in Git history at `cb5b435`; use current
|
||||
@@ -161,6 +162,7 @@ code changes. Use the component overview to find the corresponding implementatio
|
||||
| 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'` |
|
||||
| Passive resource contexts | [Engine contexts](../internal/engine/resource_context_test.go), [public contexts](../facade_resource_context_test.go) | `go test ./internal/engine -run 'Resource'` and `go test . -run 'SourceContext'` |
|
||||
| Secrets, bootstrap, redaction, explanation | [References](../internal/engine/secret_reference_test.go), [bootstrap](../internal/engine/secrets_test.go), [rendering](../internal/engine/render_test.go), [explanation](../internal/engine/explain_test.go) | `go test ./internal/engine -run 'Secret\|Bootstrap\|Effective\|Explain\|Explanation\|History\|Sensitivity'` |
|
||||
| Effective configuration diff | [Engine comparison and masking tests](../internal/engine/diff_test.go), [engine operation tests](../internal/engine/diff_operation_test.go), [root facade tests](../facade_diff_test.go), and [consumer examples](../examples/consumers/diff_test.go) | `go test ./internal/engine -run 'Diff|Explain|History|Secret|Independent'`, `go test . -run 'Diff|FacadeInspection|PublicFacadeBoundary|DependencyImportBoundary'`, `go test ./examples/consumers`, and `go test . -run '^ExampleDiff$'` |
|
||||
| Consumer examples and migration fixtures | [Consumer tests](../examples/consumers/consumers_test.go), [native and layered examples](../examples/consumers/layered_test.go), [API examples](../example_test.go) | `go test ./examples/consumers` and `go test . -run '^Example'` |
|
||||
| Assembly and layered scaling evidence | [Assembly benchmarks](../internal/engine/assembly_bench_test.go), [layered benchmarks](../internal/engine/underlay_bench_test.go) | `go test ./internal/engine -run '^$' -bench '^BenchmarkUnderlay' -benchmem`; repeat with `^BenchmarkCompose` and `^BenchmarkOverlay` |
|
||||
| Inheritance scaling evidence | [Expansion benchmarks](../internal/engine/inheritance_bench_test.go) | `go test ./internal/engine -run '^$' -bench '^BenchmarkInheritance' -benchmem` |
|
||||
|
||||
@@ -12,7 +12,8 @@ Implemented component owners:
|
||||
sibling inheritance before typed decoding. It also owns schema
|
||||
inspection, lifecycle coordination, callback auditing,
|
||||
provenance/history, passive source-context retention, secret resolution and
|
||||
bootstrap, and safe inspection rendering. It never imports the root package.
|
||||
bootstrap, safe inspection rendering, and effective-value comparison over
|
||||
frozen inspection snapshots. It never imports the root package.
|
||||
- Root `Source`, `Filesystem`, `Input`, `Underlay`, `Path`, `Secret`, records,
|
||||
lifecycle callbacks, results, and bootstrap reports are root-defined wrappers
|
||||
or records. Callback wrappers pass only live engine context during a callback;
|
||||
@@ -21,6 +22,9 @@ Implemented component owners:
|
||||
- Root conversion files explicitly cross the path, record, callback, secret, and
|
||||
error boundaries. There are no public aliases, anonymous engine embeddings, or
|
||||
public engine bridge methods.
|
||||
- Root `Diff` and `Difference` provide the public comparison boundary and
|
||||
convert detached engine records to root-owned paths and snapshots; consumer
|
||||
examples own presentation of the safe changed regions.
|
||||
- `internal/document` owns the parser-independent ordered tree and cloning.
|
||||
`internal/yaml` is the sole upstream YAML adapter and parser/dumper boundary.
|
||||
- Engine mechanism tests own source, composition, inheritance, decoding,
|
||||
@@ -37,9 +41,11 @@ these constraints and rejects exported aliases, fields, or signatures involving
|
||||
internal types.
|
||||
|
||||
The [configuration contract](../config.md) owns implemented YAML and lifecycle
|
||||
semantics. The [consumer adoption guide](../consumers/README.md) owns application
|
||||
guidance. The [architecture policy](../policy/architecture.md) owns contributor
|
||||
boundaries, and [ADR 0006](../adr/0006-public-facade.md) records the facade
|
||||
semantics, including [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
|
||||
boundaries; [ADR 0006](../adr/0006-public-facade.md) records the facade decision
|
||||
and [ADR 0010](../adr/0010-effective-configuration-diff.md) records the diff
|
||||
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
|
||||
|
||||
@@ -201,6 +201,13 @@ See [ADR 0005](../adr/0005-explicit-overrides-and-safe-explanation.md).
|
||||
Detailed syntax and operation tables belong to the
|
||||
[current configuration contract](../config.md).
|
||||
|
||||
The frozen inspection boundary also supports comparing completed same-type
|
||||
results without reopening sources or rerunning the load lifecycle. The
|
||||
[configuration contract](../config.md#effective-configuration-diffs) owns
|
||||
comparison and disclosure behavior, the [component overview](../internal/overview.md)
|
||||
owns implementation responsibility, and [ADR 0010](../adr/0010-effective-configuration-diff.md)
|
||||
records the accepted decision.
|
||||
|
||||
## Ownership And Confidentiality
|
||||
|
||||
Returned configuration and metadata must not share mutable state across loads.
|
||||
|
||||
@@ -23,12 +23,18 @@ The following remain deliberately excluded:
|
||||
- automatic schema migrations;
|
||||
- hot reload, runtime resource replacement, and remote resource validation;
|
||||
- a bundled CLI framework or application commands; and
|
||||
- configuration diffs and fingerprints.
|
||||
- configuration fingerprints.
|
||||
|
||||
Applications may build their own validate, effective-value, source, bootstrap, and
|
||||
explanation commands around the library. Broadening these boundaries requires
|
||||
concrete consumer evidence, compatibility review, and an explicit design change.
|
||||
|
||||
Effective configuration diffs are implemented over frozen successful-load
|
||||
inspections; their current comparison and disclosure contract is in the
|
||||
[configuration contract](../config.md#effective-configuration-diffs), with
|
||||
consumer workflows in the [adoption guide](../consumers/README.md#effective-configuration-diffs).
|
||||
Fingerprints remain deferred.
|
||||
|
||||
Built-in sibling inheritance using `extends` is implemented as described in the
|
||||
[configuration contract](../config.md#sibling-inheritance). It is distinct from
|
||||
inheritance between selected overlay files, which remains excluded above.
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
# Effective Configuration Diff Roadmap
|
||||
|
||||
Status: design agreed; implementation has not started. This document owns the
|
||||
targeted end state, selected contract, and work needed from the current baseline.
|
||||
The [implementation plan](implementation.md) owns execution order. No diff API
|
||||
is available yet.
|
||||
Status: implemented. This document preserves the selected contract and scope;
|
||||
the [configuration contract](../config.md#effective-configuration-diffs) owns
|
||||
current behavior, and the [implementation record](implementation.md) preserves
|
||||
the completed sequence and validation evidence.
|
||||
|
||||
## Targeted end state
|
||||
|
||||
@@ -158,11 +158,10 @@ renderer. A diff may describe removals that existing overlay semantics cannot
|
||||
express. These boundaries define this feature's selected scope, not intrinsic
|
||||
correctness restrictions on every possible future extension.
|
||||
|
||||
## Current baseline
|
||||
## Implementation references
|
||||
|
||||
- [Deferred scope](deferred.md) currently excludes configuration diffs and
|
||||
fingerprints. This design reconsiders only the diff boundary; fingerprints
|
||||
and unrelated exclusions remain deferred.
|
||||
- [Deferred scope](deferred.md) continues to exclude fingerprints and unrelated
|
||||
items; effective configuration diffs are implemented.
|
||||
- The [configuration contract](../config.md#typed-projection-and-ownership)
|
||||
describes canonical typed projection and private structural comparison.
|
||||
[The existing comparator](../../internal/engine/document_compare.go) reports
|
||||
@@ -181,69 +180,20 @@ correctness restrictions on every possible future extension.
|
||||
- The [public facade](../internal/overview.md) is root-owned and delegates to
|
||||
the engine. The new operation and records follow that same boundary.
|
||||
|
||||
## Work needed from the baseline
|
||||
## Implementation outcome
|
||||
|
||||
### Architecture and scope documentation
|
||||
The accepted inspection boundary is recorded in
|
||||
[ADR 0010](../adr/0010-effective-configuration-diff.md), and the deferred
|
||||
inventory retains fingerprints while recognizing implemented diffs. The engine
|
||||
owns canonical comparison and paired disclosure in
|
||||
[internal/engine/diff.go](../../internal/engine/diff.go); the root facade exposes
|
||||
detached records in [diff.go](../../diff.go). The configuration
|
||||
contract, consumer guidance, component overview, architecture policy, and
|
||||
development guide now link to their respective behavior and implementation
|
||||
owners.
|
||||
|
||||
Record the inspection boundary extension in an ADR and reconcile the diff
|
||||
exclusion in `deferred.md`, retaining fingerprints and unrelated exclusions.
|
||||
Keep planned behavior here until implementation lands. The staged implementation
|
||||
plan should reference the selected contract above rather than reopen it.
|
||||
|
||||
### Private comparison and disclosure
|
||||
|
||||
Add an engine operation over two successful frozen inspections, reusing the
|
||||
existing comparator where its semantics match this contract. Sharing helpers
|
||||
must preserve resolution and validation auditing behavior.
|
||||
|
||||
Implement cross-configuration masking, structural-replacement fallback, and
|
||||
`HiddenChanged`. Compare canonical values rather than serialized redacted
|
||||
output, caller-mutated configuration values, or historical replay. Construct
|
||||
the needed safe snapshots without replaying every path's full explanation
|
||||
history. Keep comparison and disclosure distinct so masking does not erase
|
||||
change detection.
|
||||
|
||||
### Root API and consumer guidance
|
||||
|
||||
Add root-owned records, the comparison entry point, and explicit conversion
|
||||
across the engine boundary. Document direction, equality, failures, ownership,
|
||||
secret behavior, and the credential limitation beside declarations.
|
||||
|
||||
Add executable examples for loading both files and handling each load failure,
|
||||
and for comparing a base result with a base-plus-overlay result. Include
|
||||
resolution and sensitive nested values, demonstrating consumer-owned formatting
|
||||
and changed-secret indicators with disposable data.
|
||||
|
||||
### Behavioral validation and completion
|
||||
|
||||
Use engine tests for comparison and combined sensitivity, root tests for the
|
||||
facade and ownership, and consumer examples for the complete workflows. Cover
|
||||
meaningful risks without duplicating all existing loading tests:
|
||||
|
||||
- equality despite mapping order, provenance, or explicit-input differences;
|
||||
canonical equality after defaults and resolution;
|
||||
- addition/removal versus explicit null, empty containers, scalar and kind
|
||||
replacements, atomic sequence changes, and escaped or numeric mapping keys;
|
||||
- deterministic ordering and reported subtree granularity;
|
||||
- changed and unchanged sensitive values, classification on only one side,
|
||||
removed secrets, classified containers, and mixed public/sensitive changes;
|
||||
- cross-kind replacement of a classified descendant, incompatible key/index
|
||||
shapes, and complete-region masking without changing absence semantics;
|
||||
- hidden changes with identical safe YAML, public-only changes alongside
|
||||
unchanged masked values with `HiddenChanged=false`, and literal marker-like
|
||||
input;
|
||||
- changed secret reference names and unchanged names with credential rotation,
|
||||
using controlled environment state;
|
||||
- invalid left/right loads, unavailable results, caller mutation after loading,
|
||||
and returned-record mutation isolation.
|
||||
|
||||
Use disposable canaries to check non-disclosure, including failure paths. Follow
|
||||
the focused, everyday, ownership-race, and documentation checks in the
|
||||
[development guide](../development.md). New performance benchmarks are not
|
||||
required for this feature.
|
||||
|
||||
Update the configuration contract, consumer guidance, and component overview
|
||||
when their behavior lands. Keep symbol details in Go declaration documentation.
|
||||
Review compatibility and release notes under the release policy; publication is
|
||||
separate from feature completion. Completion means the selected contract is
|
||||
implemented, checks pass, and maintained examples and documentation agree.
|
||||
Validation and coverage are recorded in the completed
|
||||
[implementation plan](implementation.md). The implementation compares frozen
|
||||
effective values, protects both sides with combined sensitivity, retains the
|
||||
selected credential boundary, and provides executable file and overlay
|
||||
workflows. Publication and release preparation remain separate.
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
# Implement effective configuration diffs
|
||||
|
||||
Status: planned. Audience: a Luna coding agent implementing one stage per prompt,
|
||||
in numerical order. The [diff roadmap](diff.md) owns the agreed target contract
|
||||
and scope. This document owns implementation steps and completion evidence.
|
||||
Status: complete. The [diff roadmap](diff.md) owns the agreed target contract and
|
||||
scope. This document preserves the implementation sequence and completion
|
||||
evidence; completed planning records retire during separately authorized release
|
||||
preparation.
|
||||
|
||||
Planning baseline: `e82b1c90543a6ab92138ee8c0c2a4cd4daea8af0`.
|
||||
No diff API exists at this baseline. This plan adds comparison of successful
|
||||
@@ -385,7 +386,7 @@ redaction marker; no full-context rendering supplements the diff records.
|
||||
|
||||
## Stage 10 — Reconcile documentation and audit the complete feature
|
||||
|
||||
Status: planned. Scope: current-behavior documentation, integration audit, and
|
||||
Status: complete. Scope: current-behavior documentation, integration audit, and
|
||||
completion evidence; no release publication.
|
||||
|
||||
1. Add an effective-diff section to `docs/config.md` for shared equality,
|
||||
@@ -417,6 +418,20 @@ completion evidence; no release publication.
|
||||
Done: the agreed feature is implemented, validated, and documented without
|
||||
stronger unrelated guarantees or changes to the publication contract.
|
||||
|
||||
Evidence: the planned feature baseline was `e82b1c90543a6ab92138ee8c0c2a4cd4daea8af0`;
|
||||
the reviewed implementation through consumer examples is commit `a37e689`,
|
||||
following the accepted decision at `3697a51` and public facade at `8ae542b`.
|
||||
The complete baseline-to-implementation diff was reviewed against this plan and
|
||||
the selected contract. `go test ./internal/engine -run 'Diff|Explain|History|Secret|Independent'`,
|
||||
`go test . -run 'Diff|FacadeInspection|PublicFacadeBoundary|DependencyImportBoundary'`,
|
||||
`go test ./examples/consumers`, `go test . -run '^ExampleDiff$'`, the local
|
||||
documentation-link test, and `./scripts/check.sh` passed on
|
||||
`go1.26.8 linux/amd64`. `GOTOOLCHAIN=local GOPROXY=off go test -race ./...` also passed.
|
||||
The feature does not compare resolved credential bytes or supply paired full-
|
||||
document rendering context; credential rotation behind the same reference is
|
||||
not reported. Fingerprints remain deferred, no performance claim is made, and
|
||||
release publication remains separate.
|
||||
|
||||
## Open Questions
|
||||
|
||||
None required for this scope. The roadmap's four choices are approved; the
|
||||
|
||||
Reference in New Issue
Block a user