From 6112ee8fb43602ff3ee3dc5519025539f68ac3d4 Mon Sep 17 00:00:00 2001 From: Eric Rakestraw Date: Thu, 5 Nov 2026 14:00:57 +0000 Subject: [PATCH] Merge provider defaults into one owned copy --- docs/roadmap/implementation.md | 7 +++++++ internal/configuration/targets.go | 21 +++++++++++++++------ internal/configuration/targets_test.go | 22 ++++++++++++++++++++++ 3 files changed, 44 insertions(+), 6 deletions(-) diff --git a/docs/roadmap/implementation.md b/docs/roadmap/implementation.md index cb915b0..2b48559 100644 --- a/docs/roadmap/implementation.md +++ b/docs/roadmap/implementation.md @@ -397,6 +397,13 @@ disjoint keys, nulls, arrays, and input mutation. Repeat the roadmap's chain/ width/disjoint baseline after implementation and record actual allocations/work; do not assert exact benchmark thresholds as tests. +Completion: overlapping maps now merge into one owned lower copy; focused +configuration tests pass. On Go 1.27.3, the documented 50-iteration, three-run +workloads measured: depth/width 2/2 overlap 5,144 B and 131 allocations; 12/2 +overlap 19,952 B and 464; 40/2 overlap 72,962 B and 1,392; 4/16 overlap +29,608 B and 765; 12/2 disjoint 32,496 B and 686. These are measurements, +not performance guarantees. + ## Stage 15: Centralize Trusted JSON Clone Ownership **Catalog:** 24. **Files:** `convert.go`, `internal/jsonvalue`, projection tests. diff --git a/internal/configuration/targets.go b/internal/configuration/targets.go index e4691a4..7072a7b 100644 --- a/internal/configuration/targets.go +++ b/internal/configuration/targets.go @@ -138,24 +138,33 @@ func overlayProviderMap(lower, upper map[string]any) (map[string]any, error) { if merged == nil { merged = make(map[string]any) } + if err := overlayOwnedProviderMap(merged, upper); err != nil { + return nil, err + } + return merged, nil +} + +func overlayOwnedProviderMap(merged, upper map[string]any) error { for key, value := range upper { if child, ok := value.(map[string]any); ok { if existing, ok := merged[key].(map[string]any); ok { - combined, err := overlayProviderMap(existing, child) - if err != nil { - return nil, err + if existing == nil { + existing = make(map[string]any) + merged[key] = existing + } + if err := overlayOwnedProviderMap(existing, child); err != nil { + return err } - merged[key] = combined continue } } copied, err := jsonvalue.Copy(value) if err != nil { - return nil, err + return err } merged[key] = copied } - return merged, nil + return nil } func (state *loaded) lookupProfile(ctx context.Context, id string) (domain.ExecutionProfile, error) { diff --git a/internal/configuration/targets_test.go b/internal/configuration/targets_test.go index 06ca78c..72eb8fe 100644 --- a/internal/configuration/targets_test.go +++ b/internal/configuration/targets_test.go @@ -42,6 +42,28 @@ func TestLoadIndexesIdentifiedTargets(t *testing.T) { } } +func TestOverlayProviderMapOwnsInputsAndReplacesValues(t *testing.T) { + lower := map[string]any{"nested": map[string]any{"keep": "lower", "replace": []any{"old"}, "null": "old"}, "disjoint": []any{"original"}} + upper := map[string]any{"nested": map[string]any{"replace": []any{"new"}, "null": nil, "added": map[string]any{"value": "upper"}}} + got, err := overlayProviderMap(lower, upper) + if err != nil { + t.Fatal(err) + } + want := map[string]any{"nested": map[string]any{"keep": "lower", "replace": []any{"new"}, "null": nil, "added": map[string]any{"value": "upper"}}, "disjoint": []any{"original"}} + if !reflect.DeepEqual(got, want) { + t.Fatalf("overlay = %#v", got) + } + lower["disjoint"].([]any)[0] = "changed" + upper["nested"].(map[string]any)["replace"].([]any)[0] = "changed" + if !reflect.DeepEqual(got, want) { + t.Fatalf("overlay shares input storage: %#v", got) + } + got["nested"].(map[string]any)["added"].(map[string]any)["value"] = "changed" + if upper["nested"].(map[string]any)["added"].(map[string]any)["value"] != "upper" { + t.Fatal("result mutation reached upper") + } +} + func TestRequestCompletesLoadedPartialProfile(t *testing.T) { state, err := load(mapping("partial profile", map[string]any{ "profiles": []any{map[string]any{"id": "partial"}},