Avoid duplicate intermediate source history
This commit is contained in:
@@ -123,7 +123,13 @@ checks effective and historical redaction.
|
|||||||
|
|
||||||
## 2. Intermediate Source Definitions Are Duplicated In Metadata History
|
## 2. Intermediate Source Definitions Are Duplicated In Metadata History
|
||||||
|
|
||||||
Priority: P2. Status: open.
|
Priority: P2. Status: complete.
|
||||||
|
|
||||||
|
Completion: displaced definitions are omitted only when a preceding operation
|
||||||
|
already introduced that concrete path with the same represented origin.
|
||||||
|
`TestTierHistoryRecordsEachContributionOnce` failed before the fix and passes
|
||||||
|
for both differing and equal-valued tiers. The full ordinary suite and
|
||||||
|
`git diff --check` passed, including the existing shape-change regressions.
|
||||||
|
|
||||||
Relevant code: `observeSourceEvidence` in
|
Relevant code: `observeSourceEvidence` in
|
||||||
[history_source.go](../../internal/engine/history_source.go), lines 82–117;
|
[history_source.go](../../internal/engine/history_source.go), lines 82–117;
|
||||||
|
|||||||
43
facade_tier_history_test.go
Normal file
43
facade_tier_history_test.go
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
package configkit_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
configkit "gitea.maximumdirect.net/eric/ConfigKit"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestTierHistoryRecordsEachContributionOnce(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
for _, middle := range []string{"mid", "low"} {
|
||||||
|
t.Run(middle, func(t *testing.T) {
|
||||||
|
result, err := configkit.LoadLayered[map[string]any](
|
||||||
|
configkit.Input{Source: configkit.Bytes("main", []byte("x: high\n"))},
|
||||||
|
configkit.LayeredOptions[map[string]any]{Underlays: []configkit.Underlay{
|
||||||
|
{Inputs: []configkit.Input{{Source: configkit.Bytes("low", []byte("x: low\n"))}}},
|
||||||
|
{Inputs: []configkit.Input{{Source: configkit.Bytes("middle", []byte("x: "+middle+"\n"))}}},
|
||||||
|
}},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
history := result.Metadata().History(configkit.Keys("x"))
|
||||||
|
if len(history) != 3 {
|
||||||
|
t.Fatalf("history has %d records; want the three independent contributions", len(history))
|
||||||
|
}
|
||||||
|
for index, sourceID := range []string{"source-2", "source-3", "source-1"} {
|
||||||
|
change := history[index]
|
||||||
|
if len(change.Origin.Locations) != 1 || change.Origin.Locations[0].SourceID != sourceID {
|
||||||
|
t.Fatalf("contribution %d has origin %#v", index, change.Origin)
|
||||||
|
}
|
||||||
|
if index == 0 {
|
||||||
|
if len(change.Previous) != 0 {
|
||||||
|
t.Fatal("first source contribution has a previous origin")
|
||||||
|
}
|
||||||
|
} else if len(change.Previous) != 1 || len(change.Previous[0].Locations) != 1 ||
|
||||||
|
change.Previous[0].Locations[0] != history[index-1].Origin.Locations[0] {
|
||||||
|
t.Fatalf("contribution %d has incorrect previous origin %#v", index, change.Previous)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -89,6 +89,9 @@ func (builder *historyBuilder) observeSourceEvidence(root *document.Node, origin
|
|||||||
owned.hasApplicationRef = true
|
owned.hasApplicationRef = true
|
||||||
}
|
}
|
||||||
for displacedIndex, displaced := range record.displaced {
|
for displacedIndex, displaced := range record.displaced {
|
||||||
|
if sourceOriginRepresentedByOperation(builder.model, displaced.path, displaced.origin) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
definitionPayload := payload
|
definitionPayload := payload
|
||||||
definitionPayload.substep = displacedIndex + 1
|
definitionPayload.substep = displacedIndex + 1
|
||||||
definition := builder.addAttribution(displaced.origin, nil, nil)
|
definition := builder.addAttribution(displaced.origin, nil, nil)
|
||||||
@@ -249,6 +252,9 @@ func sourceOriginRepresentedByOperation(model *historyModel, path Path, origin O
|
|||||||
if observation.phase != historyPhaseSources || observation.role != historyRoleOperation {
|
if observation.phase != historyPhaseSources || observation.role != historyRoleOperation {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if !observation.afterPresent || !sameConcreteHistoryPath(path, observation.path) {
|
||||||
|
return
|
||||||
|
}
|
||||||
operationOrigin, ok := model.resolveAttribution(observation.attributionRef)
|
operationOrigin, ok := model.resolveAttribution(observation.attributionRef)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
|
|||||||
Reference in New Issue
Block a user