Report moved history at final record paths

This commit is contained in:
2026-11-02 17:29:36 +00:00
parent 25382a112b
commit 34c3241dae
3 changed files with 65 additions and 6 deletions

View File

@@ -74,7 +74,13 @@ enumeration or new public addressing mechanism.
## Finding 2 — Deep descendant history reports the old record's operation path
**Priority:** P2. **Status:** Open.
**Priority:** P2. **Status:** Complete.
Completion: pre-resolution operation paths now use the matched record-prefix
translation, preserving ancestor scope and suffixes. Resolution records already
in final coordinates are left unchanged. A regression covers deep inherited
fields, record/container queries, original source coordinates, and overlapping
final-position records. Focused history checks and `./scripts/check.sh` passed.
**Code:** [shared history selection](../../internal/engine/history_select.go),
`selectHistory`, especially the reported-path translation at lines 116–120.

View File

@@ -113,11 +113,10 @@ func (model *historyModel) selectHistory(path Path) []historySelection {
} else if !historyObservationMatchesQuery(query, observation.path) {
continue
}
if query.String() != path.String() && pathContains(query, reportedPath) {
suffix := reportedPath.segments[len(query.segments):]
reportedPath = Path{segments: append(clonePathSegments(path.segments, len(suffix)), suffix...)}
} else if query.String() != path.String() && pathContains(reportedPath, query) && len(reportedPath.segments) >= len(query.segments)-1 {
reportedPath = path.clone()
if observation.phase != historyPhaseResolution && query.String() != path.String() {
if translated, matched := model.resolutionPayload.correspondence.finalPath(reportedPath); matched {
reportedPath = translated
}
}
selectionIndex, found := selectionByPayload[observation.payload]
if !found {

View File

@@ -40,3 +40,57 @@ func TestMovedRemovedFieldHasConsistentHistory(t *testing.T) {
}
}
}
func TestMovedInheritedHistoryUsesFinalRecordPrefix(t *testing.T) {
type config struct {
Items []map[string]any `yaml:"items"`
}
field := Keys("items").Index(0).Key("nested").Key("more").Key("value")
definition := DefinitionWithSequenceIdentityRegistrations(Definition[config]{
Resolve: func(value *config, r *Resolution) error {
value.Items[0], value.Items[1] = value.Items[1], value.Items[0]
r.RecordNormalization(Keys("items"), "reorder")
r.RecordNormalization(field, "retain inherited field")
return nil
},
}, []SequenceIdentityRegistrationInput{{ExactPath: pathPointer(Keys("items")), IdentityFields: []string{"id"}}})
result, err := testLoad(Bytes("records", []byte("items:\n - id: parent\n nested: {more: {value: old}}\n - id: child\n extends: {id: parent}\n")), Options[config]{Definition: definition})
if err != nil {
t.Fatal(err)
}
physical := result.Metadata().History(Keys("items"))
sourceID := result.Inspection.Sources()[0].ID
for _, query := range []Path{field, Keys("items").Index(0)} {
inherited, recorded := false, false
for _, change := range result.Metadata().History(query) {
if change.Origin.Operation == ChangeInheritance {
inherited = true
if !pathContains(Keys("items").Index(0), change.Path) {
t.Errorf("inheritance path for %s = %s", query.String(), change.Path.String())
}
if query.String() == field.String() && change.Path.String() != "/items/0" {
t.Errorf("container operation replaced by leaf path: %s", change.Path.String())
}
for _, location := range change.Origin.Locations {
if location.SourceID != sourceID || (query.String() == field.String() && location.Line != 3) {
t.Errorf("source coordinates changed: %#v", location)
}
}
}
if change.Origin.Layer == LayerResolution && len(change.Reasons) == 1 && change.Reasons[0] == "retain inherited field" {
recorded = true
if change.Path.String() != field.String() {
t.Errorf("final resolution path translated twice: %s", change.Path.String())
}
}
}
if !inherited || !recorded {
t.Errorf("missing inherited or recorded evidence for %s", query.String())
}
}
for _, change := range physical {
if change.Origin.Operation == ChangeInheritance && !pathContains(Keys("items").Index(1), change.Path) {
t.Errorf("collection history lost physical coordinates: %s", change.Path.String())
}
}
}