Fix D&D extraction issues and retire the completed audit

This commit is contained in:
2026-07-25 12:30:42 +00:00
parent 84a2854b5e
commit e4471fc300
15 changed files with 295 additions and 1782 deletions

View File

@@ -249,6 +249,9 @@ func TestValidateRefValid(t *testing.T) {
if err := ValidateRef(doc, ref); err != nil {
t.Fatalf("ValidateRef() error = %v, want nil", err)
}
if err := NewDocumentIndex(doc).ValidateRef(ref); err != nil {
t.Fatalf("DocumentIndex.ValidateRef() error = %v, want nil", err)
}
}
func TestValidateRefRejectsMalformedReferences(t *testing.T) {
@@ -301,13 +304,56 @@ func TestValidateRefRejectsMalformedReferences(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := ValidateRef(validDocument(), tt.ref)
requireErrorFragments(t, err, tt.fragments...)
doc := validDocument()
validators := []struct {
name string
validate func(SourceRef) error
}{
{name: "document", validate: func(ref SourceRef) error { return ValidateRef(doc, ref) }},
{name: "index", validate: NewDocumentIndex(doc).ValidateRef},
}
for _, validator := range validators {
t.Run(validator.name, func(t *testing.T) {
requireErrorFragments(t, validator.validate(tt.ref), tt.fragments...)
})
}
})
}
}
func TestDocumentIndexSnapshotsIdentityAndUnitPositions(t *testing.T) {
doc := &SourceDocument{
ID: "source-1",
Units: []SourceUnit{
{ID: 30},
{ID: 10},
{ID: 30},
},
}
index := NewDocumentIndex(doc)
doc.ID = "changed"
doc.Units[0].ID = 99
if position, ok := index.Position(30); !ok || position != 0 {
t.Fatalf("Position(30) = %d, %t, want 0, true", position, ok)
}
if position, ok := index.Position(10); !ok || position != 1 {
t.Fatalf("Position(10) = %d, %t, want 1, true", position, ok)
}
ref := SourceRef{SourceID: "source-1", StartUnitID: 30, EndUnitID: 10}
if err := index.ValidateRef(ref); err != nil {
t.Fatalf("ValidateRef() error = %v, want nil", err)
}
}
func TestZeroDocumentIndexIsSafe(t *testing.T) {
var index DocumentIndex
if position, ok := index.Position(1); ok || position != 0 {
t.Fatalf("Position(1) = %d, %t, want 0, false", position, ok)
}
requireErrorFragments(t, index.ValidateRef(SourceRef{}), "source document must not be nil")
}
func TestUnitIndex(t *testing.T) {
doc := validDocument()

View File

@@ -5,6 +5,46 @@ import (
"strings"
)
// DocumentIndex is an immutable snapshot of a source document's identity and
// unit positions for repeated source-reference operations.
type DocumentIndex struct {
documentID string
positions map[int]int
hasDocument bool
}
// NewDocumentIndex snapshots doc without retaining or mutating it.
func NewDocumentIndex(doc *SourceDocument) DocumentIndex {
if doc == nil {
return DocumentIndex{}
}
positions := make(map[int]int, len(doc.Units))
for position, unit := range doc.Units {
if _, exists := positions[unit.ID]; !exists {
positions[unit.ID] = position
}
}
return DocumentIndex{
documentID: doc.ID,
positions: positions,
hasDocument: true,
}
}
// Position returns the indexed document position for unitID.
func (i DocumentIndex) Position(unitID int) (int, bool) {
position, ok := i.positions[unitID]
return position, ok
}
// ValidateRef validates ref against the indexed document snapshot.
func (i DocumentIndex) ValidateRef(ref SourceRef) error {
if !i.hasDocument {
return fmt.Errorf("source document must not be nil")
}
return validateRef(i.documentID, i.Position, ref)
}
func ValidateDocument(doc *SourceDocument) error {
if doc == nil {
return fmt.Errorf("source document must not be nil")
@@ -60,6 +100,12 @@ func ValidateRef(doc *SourceDocument, ref SourceRef) error {
if doc == nil {
return fmt.Errorf("source document must not be nil")
}
return validateRef(doc.ID, func(unitID int) (int, bool) {
return UnitIndex(doc, unitID)
}, ref)
}
func validateRef(documentID string, position func(int) (int, bool), ref SourceRef) error {
if isBlank(ref.SourceID) {
return fmt.Errorf("source ref source_id must not be empty")
}
@@ -72,15 +118,15 @@ func ValidateRef(doc *SourceDocument, ref SourceRef) error {
if ref.EndUnitID <= 0 {
return fmt.Errorf("source ref end_unit_id must be positive")
}
if ref.SourceID != doc.ID {
return fmt.Errorf("source ref source_id %q does not match document id %q", ref.SourceID, doc.ID)
if ref.SourceID != documentID {
return fmt.Errorf("source ref source_id %q does not match document id %q", ref.SourceID, documentID)
}
startIndex, ok := UnitIndex(doc, ref.StartUnitID)
startIndex, ok := position(ref.StartUnitID)
if !ok {
return fmt.Errorf("source ref start_unit_id %d was not found", ref.StartUnitID)
}
endIndex, ok := UnitIndex(doc, ref.EndUnitID)
endIndex, ok := position(ref.EndUnitID)
if !ok {
return fmt.Errorf("source ref end_unit_id %d was not found", ref.EndUnitID)
}