Document field-level resolution and matched sequence history
This commit is contained in:
@@ -772,6 +772,15 @@ in history. Across tiers, history follows the selected
|
|||||||
whole-record upsert. Incoming contributions use their assigned positions, and
|
whole-record upsert. Incoming contributions use their assigned positions, and
|
||||||
replaced payload remains available as historical evidence.
|
replaced payload remains available as historical evidence.
|
||||||
|
|
||||||
|
During resolution, eligible application-registered records are matched between
|
||||||
|
entry and final snapshots by identity at the same collection destination.
|
||||||
|
Queries at a surviving final position follow that record's entry history, while
|
||||||
|
collection queries retain physical ordering and removed evidence. For example,
|
||||||
|
if `[reports, invoices]` becomes `[invoices]`, item 0 follows invoices' earlier
|
||||||
|
position, the collection retains reports' removal, and the absent old item 1
|
||||||
|
remains available through historical-position queries. An added identity does
|
||||||
|
not inherit the old occupant's history. Source locations stay source-local.
|
||||||
|
|
||||||
A mapping assembled from the selected file and imports has one composite base origin
|
A mapping assembled from the selected file and imports has one composite base origin
|
||||||
whose locations follow [scoped assembly order](#explicit-imports), not source-record
|
whose locations follow [scoped assembly order](#explicit-imports), not source-record
|
||||||
acquisition order. A mapping also visited by an overlay has an overlay-layer
|
acquisition order. A mapping also visited by an overlay has an overlay-layer
|
||||||
@@ -1198,6 +1207,18 @@ records, helper targets, and unrecorded mutations fail the load. Equal-valued
|
|||||||
derived assignments may still record application intent even when there is no
|
derived assignments may still record application intent even when there is no
|
||||||
structural change.
|
structural change.
|
||||||
|
|
||||||
|
Resolution compares equal-length ordinary lists recursively by position, so an
|
||||||
|
edit to `/resources/0/path` can be recorded at that field. A length change needs
|
||||||
|
a list or ancestor record. For application-registered collections, valid unique
|
||||||
|
entry and final identities match records at the same destination; changing order
|
||||||
|
or membership still requires list or ancestor coverage. Invalid or duplicate
|
||||||
|
endpoint identities make a changed list atomic for auditing, without an early
|
||||||
|
identity error; final registration validation remains at its normal boundary.
|
||||||
|
YAML-only declarations do not provide this correspondence. Records and helper
|
||||||
|
targets use final positions, and helpers never follow a later move automatically.
|
||||||
|
Fixed entry queries continue to use entry positions. See
|
||||||
|
[ADR 0021](adr/0021-sequence-resolution-correspondence.md) for the decision.
|
||||||
|
|
||||||
`Resolution.Error` and `Resolution.Warning` attach exact or nearest available input
|
`Resolution.Error` and `Resolution.Warning` attach exact or nearest available input
|
||||||
locations. Reported errors fail the load; warnings survive on a successful result. A
|
locations. Reported errors fail the load; warnings survive on a successful result. A
|
||||||
returned resolver error adds one generic `resolve.hook_failed` error only when the
|
returned resolver error adds one generic `resolve.hook_failed` error only when the
|
||||||
@@ -1356,7 +1377,7 @@ Incompatible overlaps and invalid registrations produce `options.invalid` before
|
|||||||
source acquisition. Unused and root registrations are allowed and have no effect.
|
source acquisition. Unused and root registrations are allowed and have no effect.
|
||||||
|
|
||||||
Registrations provide identity for strict composition, sequence operations,
|
Registrations provide identity for strict composition, sequence operations,
|
||||||
inheritance lookup, and final validation. Dynamic selectors apply at concrete
|
inheritance lookup, resolution correspondence, and final validation. Dynamic selectors apply at concrete
|
||||||
strict-composition, inheritance, and final-result destinations without requiring
|
strict-composition, inheritance, and final-result destinations without requiring
|
||||||
the application to enumerate mapping keys. Each strict tier has independent
|
the application to enumerate mapping keys. Each strict tier has independent
|
||||||
duplicate-identity state among its peers; layered precedence and inheritance
|
duplicate-identity state among its peers; layered precedence and inheritance
|
||||||
@@ -2056,10 +2077,10 @@ rebuilt by unmarshaling their canonical text into fresh values, detaching privat
|
|||||||
backing storage. Ignored and unexported struct fields are zeroed rather than copied.
|
backing storage. Ignored and unexported struct fields are zeroed rather than copied.
|
||||||
|
|
||||||
Private structural comparison operates on canonical trees. Mapping additions,
|
Private structural comparison operates on canonical trees. Mapping additions,
|
||||||
removals, and descendant replacements retain semantic paths. A sequence is atomic:
|
removals, and descendant replacements retain semantic paths. The shared
|
||||||
any sequence change reports the sequence path and never invents correspondence
|
comparison used by effective diff treats sequences atomically. Resolution uses
|
||||||
between old and new indices. Cross-kind and null/container changes replace the
|
its separate positional and registered-identity comparison described above.
|
||||||
affected path.
|
Cross-kind and null/container changes replace the affected path.
|
||||||
|
|
||||||
These mechanisms support decoding, resolution auditing, metadata,
|
These mechanisms support decoding, resolution auditing, metadata,
|
||||||
and rendering. They are not a public generic conversion or cloning API.
|
and rendering. They are not a public generic conversion or cloning API.
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ Accepted decisions:
|
|||||||
- [Apply CLI overrides after inheritance and decoding](adr/0018-cli-after-structural-resolution.md)
|
- [Apply CLI overrides after inheritance and decoding](adr/0018-cli-after-structural-resolution.md)
|
||||||
- [Keep main-file discovery explicit and composable](adr/0019-explicit-configuration-discovery.md)
|
- [Keep main-file discovery explicit and composable](adr/0019-explicit-configuration-discovery.md)
|
||||||
- [Scope configuration controls to document roots](adr/0020-document-root-controls.md)
|
- [Scope configuration controls to document roots](adr/0020-document-root-controls.md)
|
||||||
|
- [Match registered records during resolution inspection](adr/0021-sequence-resolution-correspondence.md)
|
||||||
|
|
||||||
For cross-cutting changes, follow every applicable row. Completed implementation
|
For cross-cutting changes, follow every applicable row. Completed implementation
|
||||||
and remediation plans are preserved in Git history at `cb5b435`; use current
|
and remediation plans are preserved in Git history at `cb5b435`; use current
|
||||||
@@ -285,6 +286,7 @@ code changes. Use the component overview to find the corresponding implementatio
|
|||||||
| 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` |
|
| 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 | [Implementation flow](internal/overview.md#implementation-flow), [schema](../internal/engine/schema_test.go), [decoding](../internal/engine/decode_test.go), [projection and typed cloning](../internal/engine/projection_test.go) | `go test ./internal/engine -run 'Schema\|Decode\|Projection\|Clone\|Inline\|CompareDocument'` |
|
| Schema, defaults, projection, cloning | [Implementation flow](internal/overview.md#implementation-flow), [schema](../internal/engine/schema_test.go), [decoding](../internal/engine/decode_test.go), [projection and typed cloning](../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'` |
|
| 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'` |
|
||||||
|
| Resolution sequence matching and inspection | [Correspondence](../internal/engine/resolution_correspondence_test.go), [auditing and history](../internal/engine/resolution_compare_test.go), [public integration](../facade_resolution_sequences_test.go) | `go test ./internal/engine -run 'Resolution\|History\|Explain\|Sensitivity'` and `go test . -run 'Resolution\|SequenceIdentity\|Diff'` |
|
||||||
| 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'` |
|
| 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'` |
|
| 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'` |
|
| 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'` |
|
||||||
|
|||||||
@@ -161,6 +161,9 @@ before application resolution begins. The callback retains its separate fixed
|
|||||||
entry view; it does not read a builder that continues to change. After successful
|
entry view; it does not read a builder that continues to change. After successful
|
||||||
resolution auditing, [`resolveLoadInput`](../../internal/engine/load_result.go)
|
resolution auditing, [`resolveLoadInput`](../../internal/engine/load_result.go)
|
||||||
adds the original resolution records and their net replay groups. At the existing
|
adds the original resolution records and their net replay groups. At the existing
|
||||||
|
resolution boundary, [`resolution_correspondence.go`](../../internal/engine/resolution_correspondence.go)
|
||||||
|
matches eligible registered records and the shared history retains their paired
|
||||||
|
coordinates for selection and safe replay. At the existing
|
||||||
pre-secret admission boundary, [`prepareInspectionHistory`](../../internal/engine/load_result.go)
|
pre-secret admission boundary, [`prepareInspectionHistory`](../../internal/engine/load_result.go)
|
||||||
freezes that builder and counts the retained document roots before secret lookup
|
freezes that builder and counts the retained document roots before secret lookup
|
||||||
and validation.
|
and validation.
|
||||||
|
|||||||
@@ -376,6 +376,11 @@ it does not cover every intermediate callback state or later caller mutations.
|
|||||||
YAML-only declarations carry no such final guarantee through defaults, CLI
|
YAML-only declarations carry no such final guarantee through defaults, CLI
|
||||||
assignments, or application resolution.
|
assignments, or application resolution.
|
||||||
|
|
||||||
|
For resolution auditing and inspection, eligible registered collections match
|
||||||
|
entry and final records by identity within each destination. Structural changes
|
||||||
|
still require container coverage, and this correspondence does not change source
|
||||||
|
composition or move final validation earlier. Public diff remains sequence-atomic.
|
||||||
|
|
||||||
Preserve source attribution, presence, history, sensitivity, and resource context
|
Preserve source attribution, presence, history, sensitivity, and resource context
|
||||||
as records survive, move, or are replaced. Identity diagnostics use paths and
|
as records survive, move, or are replaced. Identity diagnostics use paths and
|
||||||
available origin information without exposing identity values. The guarantee
|
available origin information without exposing identity values. The guarantee
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
# Sequence resolution and inspection implementation plan
|
# Sequence resolution and inspection implementation plan
|
||||||
|
|
||||||
|
Status: complete.
|
||||||
|
|
||||||
## Scope and execution
|
## Scope and execution
|
||||||
|
|
||||||
Implement the agreed [feature roadmap](resolution-sequences.md) from baseline
|
Implement the agreed [feature roadmap](resolution-sequences.md) from baseline
|
||||||
@@ -423,6 +425,8 @@ no exported type, selector, or callback lifecycle change is needed.
|
|||||||
|
|
||||||
## Stage 13 — Document the implemented contract and validate the sprint
|
## Stage 13 — Document the implemented contract and validate the sprint
|
||||||
|
|
||||||
|
**Status:** Complete. Focused engine, facade, and consumer checks, `go test -race ./...`, and `./scripts/check.sh` passed with Go 1.27.0 on Linux.
|
||||||
|
|
||||||
**Scope:** canonical documentation and final integration checks.
|
**Scope:** canonical documentation and final integration checks.
|
||||||
|
|
||||||
1. Update `docs/config.md` resolution, layered metadata, historical explanation,
|
1. Update `docs/config.md` resolution, layered metadata, historical explanation,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Field-level resolution and identity-aware sequence history
|
# Field-level resolution and identity-aware sequence history
|
||||||
|
|
||||||
Status: agreed direction; not implemented. This roadmap describes field-level
|
Status: implemented. This roadmap records field-level
|
||||||
resolution auditing and identity-aware inspection of registered collections.
|
resolution auditing and identity-aware inspection of registered collections.
|
||||||
The [implementation plan](implementation.md) owns execution order and verification.
|
The [implementation plan](implementation.md) owns execution order and verification.
|
||||||
|
|
||||||
@@ -17,27 +17,25 @@ inspection. For ordinary lists, position is the only available correspondence;
|
|||||||
compare positions as addresses without inferring which application object an
|
compare positions as addresses without inferring which application object an
|
||||||
element represents.
|
element represents.
|
||||||
|
|
||||||
## Current baseline
|
## Prior baseline
|
||||||
|
|
||||||
The [resolution contract](../config.md#recorded-application-resolution) audits
|
At the planning baseline, the resolution contract audited the typed configuration
|
||||||
the typed configuration before and after `Definition.Resolve`. Mappings are
|
before and after `Definition.Resolve`. Mappings were compared recursively, while
|
||||||
compared recursively, while the private structural comparator reports any list
|
the private structural comparator reported any list change at the whole-list
|
||||||
change at the whole-list path. A field-level record inside a changed list
|
path. A field-level record inside a changed list therefore failed to cover that
|
||||||
therefore fails to cover that list-level delta. Recording the whole list works.
|
list-level delta. Recording the whole list worked.
|
||||||
|
|
||||||
For example, changing `/resources/0/path` and recording only that path currently
|
For example, changing `/resources/0/path` and recording only that path previously
|
||||||
produces an unrecorded-change diagnostic at `/resources`. This is established
|
produced an unrecorded-change diagnostic at `/resources`. That was established
|
||||||
behavior rather than a new regression associated with v1.0.0.
|
behavior rather than a new regression associated with v1.0.0.
|
||||||
|
|
||||||
The comparator also serves other inspection and metadata operations. Making
|
The comparator also serves other inspection and metadata operations. Making
|
||||||
resolution auditing more precise must account for those callers rather than
|
resolution auditing more precise must account for those callers rather than
|
||||||
silently changing the public diff contract.
|
silently changing the public diff contract.
|
||||||
|
|
||||||
Resolution currently captures before and after values at the same numeric path.
|
The prior resolution implementation captured before and after values at the
|
||||||
Its metadata refresh also consults entry metadata at that path. Following a
|
same numeric path and refreshed metadata at that path. Following a registered
|
||||||
registered record through a move therefore requires more than changing which
|
record through a move requires the matching entry and final record evidence.
|
||||||
deltas pass the coverage audit: the retained evidence must identify the matching
|
|
||||||
entry and final record.
|
|
||||||
|
|
||||||
Application registrations already define identities for collections and constrain
|
Application registrations already define identities for collections and constrain
|
||||||
their final values. YAML-only declarations have a shorter lifetime. The
|
their final values. YAML-only declarations have a shorter lifetime. The
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ type Explanation struct {
|
|||||||
// or historical path, hiding sensitive information. History follows processing
|
// or historical path, hiding sensitive information. History follows processing
|
||||||
// order: inheritance appears after source combination and before the transition
|
// order: inheritance appears after source combination and before the transition
|
||||||
// to typed values. Unknown and malformed paths return false.
|
// to typed values. Unknown and malformed paths return false.
|
||||||
|
// Surviving registered records use their matched resolution-entry history.
|
||||||
func (r *Result[T]) Explain(path Path) (Explanation, bool) {
|
func (r *Result[T]) Explain(path Path) (Explanation, bool) {
|
||||||
if r == nil {
|
if r == nil {
|
||||||
return Explanation{}, false
|
return Explanation{}, false
|
||||||
|
|||||||
@@ -140,7 +140,8 @@ type Override struct {
|
|||||||
|
|
||||||
// Resolution lets a resolver inspect supplied values and record derived defaults
|
// Resolution lets a resolver inspect supplied values and record derived defaults
|
||||||
// or normalization. Its input queries describe the state at callback entry,
|
// or normalization. Its input queries describe the state at callback entry,
|
||||||
// even after the resolver changes the configuration. Use the context only during
|
// even after the resolver changes the configuration. Records and helpers use
|
||||||
|
// final paths; helpers do not follow moved records. Use the context only during
|
||||||
// the callback; do not retain it or use it concurrently.
|
// the callback; do not retain it or use it concurrently.
|
||||||
type Resolution struct{ value *engine.Resolution }
|
type Resolution struct{ value *engine.Resolution }
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ func (m Metadata) IsExplicit(path Path) bool {
|
|||||||
// History returns detached definition, inheritance, and resolution records for path. A record's
|
// History returns detached definition, inheritance, and resolution records for path. A record's
|
||||||
// Path can be an ancestor when that container operation replaced or removed path.
|
// Path can be an ancestor when that container operation replaced or removed path.
|
||||||
// Removed historical paths can have history even though Lookup returns false.
|
// Removed historical paths can have history even though Lookup returns false.
|
||||||
|
// Surviving registered records follow their matched resolution-entry history;
|
||||||
|
// collection queries retain removed evidence at physical positions.
|
||||||
// Unknown and invalid paths return nil.
|
// Unknown and invalid paths return nil.
|
||||||
func (m Metadata) History(path Path) []Change {
|
func (m Metadata) History(path Path) []Change {
|
||||||
values := m.value.History(toEnginePath(path))
|
values := m.value.History(toEnginePath(path))
|
||||||
|
|||||||
@@ -26,7 +26,8 @@ func SequenceAnyMappingKey() SequenceSelectorSegment {
|
|||||||
|
|
||||||
// SequenceIdentity records the identity fields used for strict sequence
|
// SequenceIdentity records the identity fields used for strict sequence
|
||||||
// composition, identified-record parent lookup, and final typed-result
|
// composition, identified-record parent lookup, and final typed-result
|
||||||
// validation during loading.
|
// validation during loading. Eligible entry and final records also correspond
|
||||||
|
// during resolution auditing and inspection.
|
||||||
type SequenceIdentity struct {
|
type SequenceIdentity struct {
|
||||||
exactPath bool
|
exactPath bool
|
||||||
path Path
|
path Path
|
||||||
|
|||||||
Reference in New Issue
Block a user