Improve D&D registry normalization efficiency

This commit is contained in:
2026-08-09 02:26:49 +00:00
parent 2a75f40871
commit b70d9f77e3
5 changed files with 93 additions and 49 deletions

View File

@@ -5,7 +5,6 @@ import (
"crypto/sha256"
"encoding/hex"
"encoding/json"
"sort"
"strings"
"gitea.maximumdirect.net/eric/notarius/internal/core/source"
@@ -58,9 +57,13 @@ func ComparisonKey(value string) string {
// available, leaving validation to report the problem instead of manufacturing
// an ID.
func DeriveID(name string, refs []source.SourceRef) string {
comparisonName := ComparisonKey(name)
anchor, ok := earliestReference(refs)
if comparisonName == "" || !ok {
return deriveIDFromAnchor(name, anchor, ok)
}
func deriveIDFromAnchor(name string, anchor source.SourceRef, hasAnchor bool) string {
comparisonName := ComparisonKey(name)
if comparisonName == "" || !hasAnchor {
return ""
}
@@ -111,13 +114,14 @@ func ValidateRegistry(locations []dnd.Location) []Issue {
if ComparisonKey(location.Name) == "" {
issues = append(issues, Issue{Code: IssueEmptyCanonicalName, RecordIndex: recordIndex, Value: location.Name})
}
if _, ok := earliestReference(location.SourceRefs); !ok {
anchor, hasAnchor := earliestReference(location.SourceRefs)
if !hasAnchor {
issues = append(issues, Issue{Code: IssueMissingEvidence, RecordIndex: recordIndex})
}
if !IsValidID(location.ID) {
issues = append(issues, Issue{Code: IssueInvalidID, RecordIndex: recordIndex, Value: location.ID})
} else if expected := DeriveID(location.Name, location.SourceRefs); location.ID != expected {
} else if expected := deriveIDFromAnchor(location.Name, anchor, hasAnchor); location.ID != expected {
issues = append(issues, Issue{Code: IssueIDMismatch, RecordIndex: recordIndex, Value: location.ID})
}
if location.ID != "" {
@@ -135,36 +139,28 @@ func ValidateRegistry(locations []dnd.Location) []Issue {
}
func earliestReference(refs []source.SourceRef) (source.SourceRef, bool) {
canonical := canonicalReferences(refs)
if len(canonical) == 0 {
return source.SourceRef{}, false
var earliest source.SourceRef
found := false
for _, ref := range refs {
if !validIdentityReference(ref) {
continue
}
if !found || referenceLess(ref, earliest) {
earliest = ref
found = true
}
}
return canonical[0], true
return earliest, found
}
func canonicalReferences(refs []source.SourceRef) []source.SourceRef {
canonical := make([]source.SourceRef, 0, len(refs))
for _, ref := range refs {
if validIdentityReference(ref) {
canonical = append(canonical, ref)
}
func referenceLess(left, right source.SourceRef) bool {
if left.SourceID != right.SourceID {
return left.SourceID < right.SourceID
}
sort.Slice(canonical, func(left, right int) bool {
if canonical[left].SourceID != canonical[right].SourceID {
return canonical[left].SourceID < canonical[right].SourceID
}
if canonical[left].StartUnitID != canonical[right].StartUnitID {
return canonical[left].StartUnitID < canonical[right].StartUnitID
}
return canonical[left].EndUnitID < canonical[right].EndUnitID
})
unique := canonical[:0]
for _, ref := range canonical {
if len(unique) == 0 || unique[len(unique)-1] != ref {
unique = append(unique, ref)
}
if left.StartUnitID != right.StartUnitID {
return left.StartUnitID < right.StartUnitID
}
return unique
return left.EndUnitID < right.EndUnitID
}
func validIdentityReference(ref source.SourceRef) bool {