Deduplicate parsed sensitivity paths correctly
This commit is contained in:
@@ -308,7 +308,13 @@ coarsen semantic identity.
|
||||
|
||||
## 6. Sensitivity Candidate Deduplication Cannot Match Parsed Paths
|
||||
|
||||
Priority: P3. Status: open.
|
||||
Priority: P3. Status: complete.
|
||||
|
||||
Completion: candidate and dependency deduplication uses structural segment
|
||||
equality, including parsed tokens, without conflating explicit keys and indexes.
|
||||
`TestSensitivityCandidatesMergeRepeatedParsedPaths` failed before the fix and
|
||||
now verifies unique semantic/dependency candidates and merged sensitivity facts.
|
||||
The full ordinary suite and `git diff --check` passed.
|
||||
|
||||
Relevant code: `sensitivityCandidates` and `appendDistinctHistoryPath` in
|
||||
[history_select.go](../../internal/engine/history_select.go), especially
|
||||
|
||||
@@ -210,7 +210,7 @@ func (model *historyModel) sensitivityCandidates() []historySensitivityCandidate
|
||||
}
|
||||
pointer := path.String()
|
||||
for _, index := range indices[pointer] {
|
||||
if sameConcreteHistoryPath(candidates[index].path, path) {
|
||||
if slices.Equal(candidates[index].path.segments, path.segments) {
|
||||
candidates[index].sensitive = candidates[index].sensitive || sensitive
|
||||
candidates[index].classify = candidates[index].classify || classify
|
||||
return index
|
||||
@@ -254,7 +254,7 @@ func (model *historyModel) sensitivityCandidates() []historySensitivityCandidate
|
||||
|
||||
func appendDistinctHistoryPath(paths *[]Path, path Path) {
|
||||
for _, existing := range *paths {
|
||||
if sameConcreteHistoryPath(existing, path) {
|
||||
if slices.Equal(existing.segments, path.segments) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,11 +2,48 @@ package engine
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"slices"
|
||||
"testing"
|
||||
|
||||
"gitea.maximumdirect.net/eric/ConfigKit/internal/document"
|
||||
)
|
||||
|
||||
func TestSensitivityCandidatesMergeRepeatedParsedPaths(t *testing.T) {
|
||||
t.Parallel()
|
||||
builder := newHistoryBuilder()
|
||||
key := Keys("shape", "0")
|
||||
index := Keys("shape").Index(0)
|
||||
parsed := parseOverrideTestPath(t, "/shape/0")
|
||||
dependency := parseOverrideTestPath(t, "/dependency")
|
||||
attribution := builder.addAttribution(Origin{Layer: LayerResolution}, nil, []Path{dependency})
|
||||
payload := builder.nextPayload(historyPhaseResolution)
|
||||
for repeat := 0; repeat < 3; repeat++ {
|
||||
for _, path := range []Path{key, index} {
|
||||
builder.addObservation(historyObservation{
|
||||
path: path, phase: historyPhaseResolution, payload: payload,
|
||||
reportedPath: Keys("shape"), role: historyRoleOperation,
|
||||
afterPresent: true, sensitive: repeat == 2,
|
||||
attributionRef: attribution,
|
||||
})
|
||||
}
|
||||
}
|
||||
candidates := builder.freeze().sensitivityCandidates()
|
||||
for _, path := range []Path{key, index, parsed, dependency} {
|
||||
count := 0
|
||||
for _, candidate := range candidates {
|
||||
if slices.Equal(candidate.path.segments, path.segments) {
|
||||
count++
|
||||
if path.String() == "/shape/0" && !candidate.sensitive {
|
||||
t.Fatal("merged candidate lost a later sensitivity fact")
|
||||
}
|
||||
}
|
||||
}
|
||||
if count != 1 {
|
||||
t.Fatalf("semantic candidate %#v occurs %d times; want one", path, count)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestHistorySelectionSeparatesNumericShapesAndGroupsParsedSides(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user