From f132cd6468b7cf00caade2e3b46e03fac00f9e44 Mon Sep 17 00:00:00 2001 From: Eric Rakestraw Date: Sun, 25 Oct 2026 23:17:59 +0000 Subject: [PATCH] Index inherited compound identity restoration --- docs/roadmap/implementation.md | 8 ++ .../engine/inheritance_identified_test.go | 77 +++++++++++++++++++ internal/engine/inheritance_scope.go | 28 ++++--- 3 files changed, 102 insertions(+), 11 deletions(-) diff --git a/docs/roadmap/implementation.md b/docs/roadmap/implementation.md index 7ec55ec..e98cbd1 100644 --- a/docs/roadmap/implementation.md +++ b/docs/roadmap/implementation.md @@ -1030,6 +1030,14 @@ templates remain correct. Source review establishes O(K + C + M) lookup work plu required copied values for K identity fields and C/M mapping entries. Focused check: `go test ./internal/engine -run 'Identified|Identity|Inheritance'`. +Status: **complete** (E05). Prior completed commits include `549fca2`, +`3a1b6ff`, `d172a5e`, `1dd94a3`, and `75e209e`. Validation passed: +`env GOTOOLCHAIN=local GOPROXY=off GOTELEMETRY=off go test ./internal/engine -run 'Identified|Identity|Inheritance' -count=1`, +`env GOTOOLCHAIN=local GOPROXY=off GOTELEMETRY=off go test ./internal/engine -count=1`, +`env GOTOOLCHAIN=local GOPROXY=off GOTELEMETRY=off go test ./... -count=1`, +`env GOTOOLCHAIN=local GOPROXY=off GOTELEMETRY=off go test -race ./...`, +and `git diff --check`. + ## Stage 32 — Index Secret Failure Locations Only When Needed Finding: **F08**. diff --git a/internal/engine/inheritance_identified_test.go b/internal/engine/inheritance_identified_test.go index 3e6a3e4..4fd6aa8 100644 --- a/internal/engine/inheritance_identified_test.go +++ b/internal/engine/inheritance_identified_test.go @@ -24,6 +24,83 @@ func parseIdentifiedInheritanceSequence(t *testing.T, sourceID, input string) *d return sequence } +func TestPreserveInheritanceIdentityIndexesCompoundFields(t *testing.T) { + t.Parallel() + + mergedEntries := []document.Entry{ + {Key: "before", Value: &document.Node{Kind: document.String, Text: "keep"}}, + {Key: "id", KeyLocation: document.Location{SourceID: "parent", Line: 2}, ValueLocation: document.Location{SourceID: "parent", Line: 2}, Value: &document.Node{Kind: document.String, Text: "parent-id"}}, + } + for index := 0; index < 64; index++ { + key := "setting-" + string(rune('a'+index)) + mergedEntries = append(mergedEntries, document.Entry{Key: key, Value: &document.Node{Kind: document.String, Text: key}}) + } + mergedEntries = append(mergedEntries, + document.Entry{Key: "a/b~c", KeyLocation: document.Location{SourceID: "parent", Line: 70}, ValueLocation: document.Location{SourceID: "parent", Line: 70}, Value: &document.Node{Kind: document.String, Text: "parent-literal"}}, + document.Entry{Key: "missing", Value: &document.Node{Kind: document.String, Text: "retained"}}, + document.Entry{Key: "after", Value: &document.Node{Kind: document.String, Text: "keep"}}, + ) + merged := &document.Node{Kind: document.Mapping, Mapping: mergedEntries} + child := &document.Node{Kind: document.Mapping, Mapping: []document.Entry{ + {Key: "a/b~c", KeyLocation: document.Location{SourceID: "child", Line: 9, Column: 3}, ValueLocation: document.Location{SourceID: "child", Line: 9, Column: 10}, Value: &document.Node{Kind: document.String, Text: "child-literal", Location: document.Location{SourceID: "child", Line: 9, Column: 10}}}, + {Key: "id", KeyLocation: document.Location{SourceID: "child", Line: 3, Column: 3}, ValueLocation: document.Location{SourceID: "child", Line: 3, Column: 7}, Value: &document.Node{Kind: document.String, Text: "child-id", Location: document.Location{SourceID: "child", Line: 3, Column: 7}}}, + }} + beforeKeys := make([]string, len(merged.Mapping)) + for index, entry := range merged.Mapping { + beforeKeys[index] = entry.Key + } + untouched := merged.Mapping[2].Value + + preserveInheritanceIdentityFields(merged, child, []string{"id", "a/b~c", "missing"}) + + for index, entry := range merged.Mapping { + if entry.Key != beforeKeys[index] { + t.Fatalf("mapping order changed at %d: %q, want %q", index, entry.Key, beforeKeys[index]) + } + } + for _, want := range []struct { + key string + text string + keyLine int + keyColumn int + valueLine int + valueColumn int + }{ + {key: "id", text: "child-id", keyLine: 3, keyColumn: 3, valueLine: 3, valueColumn: 7}, + {key: "a/b~c", text: "child-literal", keyLine: 9, keyColumn: 3, valueLine: 9, valueColumn: 10}, + } { + var got document.Entry + for _, entry := range merged.Mapping { + if entry.Key == want.key { + got = entry + break + } + } + if got.Value == nil || got.Value.Text != want.text || got.KeyLocation.SourceID != "child" || got.KeyLocation.Line != want.keyLine || got.KeyLocation.Column != want.keyColumn || + got.ValueLocation.SourceID != "child" || got.ValueLocation.Line != want.valueLine || got.ValueLocation.Column != want.valueColumn || + got.Value.Location.SourceID != "child" || got.Value.Location.Line != want.valueLine || got.Value.Location.Column != want.valueColumn { + t.Fatalf("restored identity %q = %#v", want.key, got) + } + if got.Value == child.Mapping[0].Value || (want.key == "id" && got.Value == child.Mapping[1].Value) { + t.Fatalf("restored identity %q borrows its child value", want.key) + } + } + if merged.Mapping[2].Value != untouched { + t.Fatal("nonidentity sibling was replaced") + } + for _, entry := range merged.Mapping { + if entry.Key == "missing" && entry.Value.Text != "retained" { + t.Fatalf("identity absent from child was changed: %#v", entry) + } + } + child.Mapping[0].Value.Text = "mutated" + for _, entry := range merged.Mapping { + if entry.Key == "a/b~c" && entry.Value.Text != "child-literal" { + t.Fatal("restored identity value aliases the child template") + } + } +} + func TestIdentifiedInheritanceGraphSchedulesForwardReferencesInPlace(t *testing.T) { sequence := parseIdentifiedInheritanceSequence(t, "identified-graph", `- id: 2 tenant: acme diff --git a/internal/engine/inheritance_scope.go b/internal/engine/inheritance_scope.go index 2597925..f9a5eba 100644 --- a/internal/engine/inheritance_scope.go +++ b/internal/engine/inheritance_scope.go @@ -144,18 +144,24 @@ func preserveInheritanceIdentityFields(merged, child *document.Node, fields []st if len(fields) == 0 || merged == nil || merged.Kind != document.Mapping || child == nil || child.Kind != document.Mapping { return } + identityFields := make(map[string]struct{}, len(fields)) for _, field := range fields { - for _, entry := range child.Mapping { - if entry.Key != field { - continue - } - for index := range merged.Mapping { - if merged.Mapping[index].Key == field { - merged.Mapping[index] = document.Entry{Key: field, Value: document.Clone(entry.Value)} - break - } - } - break + identityFields[field] = struct{}{} + } + positions := make(map[string]int, len(merged.Mapping)) + for index, entry := range merged.Mapping { + if _, exists := positions[entry.Key]; !exists { + positions[entry.Key] = index + } + } + for _, entry := range child.Mapping { + if _, identity := identityFields[entry.Key]; !identity { + continue + } + delete(identityFields, entry.Key) + if index, exists := positions[entry.Key]; exists { + entry.Value = document.Clone(entry.Value) + merged.Mapping[index] = entry } } }