Classify source relatedness as data-quality advisories
This commit is contained in:
@@ -9,13 +9,14 @@ import (
|
||||
"gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline"
|
||||
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd"
|
||||
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/shared"
|
||||
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/shared/diagnostics"
|
||||
spellshape "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/spells/shape"
|
||||
)
|
||||
|
||||
const (
|
||||
Key = "extract/dnd/spells/source_relatedness"
|
||||
WarningReasonCode = "spell_not_near_source"
|
||||
policy = "dnd.spells.validator.source_relatedness.v1"
|
||||
Key = "extract/dnd/spells/source_relatedness"
|
||||
ReasonCode = "spell_not_near_source"
|
||||
policy = "dnd.spells.validator.source_relatedness.v1"
|
||||
)
|
||||
|
||||
type Options struct{}
|
||||
@@ -51,10 +52,10 @@ func (v *Validator) Validate(_ context.Context, req contracts.TypedValidationReq
|
||||
var warnings []contracts.Warning
|
||||
for spellIndex, spell := range req.Value.SpellCasts {
|
||||
if !spellAppearsInCitedText(citedTexts[spellIndex], spell) {
|
||||
warnings = append(warnings, contracts.Warning{Scope: fmt.Sprintf("spell_casts[%d]", spellIndex), ReasonCode: WarningReasonCode, Message: fmt.Sprintf("spell %q was not found in cited source text", strings.TrimSpace(spell.Spell))})
|
||||
warnings = append(warnings, contracts.Warning{Scope: fmt.Sprintf("spell_casts[%d]", spellIndex), ReasonCode: ReasonCode, Message: fmt.Sprintf("spell %s was not found in cited source text", diagnostics.Quote(strings.TrimSpace(spell.Spell)))})
|
||||
}
|
||||
}
|
||||
return contracts.ValidationResult{Approved: true, Warnings: warnings}, nil
|
||||
return diagnostics.DataQualityResult(warnings)
|
||||
}
|
||||
func spellAppearsInCitedText(citedText string, spell dnd.SpellCast) bool {
|
||||
name := strings.TrimSpace(spell.Spell)
|
||||
|
||||
@@ -18,8 +18,8 @@ func TestValidatorApprovesWithoutWarningWhenSpellAppearsInCitedText(t *testing.T
|
||||
if !result.Approved {
|
||||
t.Fatalf("Approved = false, want true")
|
||||
}
|
||||
if len(result.Warnings) != 0 {
|
||||
t.Fatalf("Warnings = %#v, want none", result.Warnings)
|
||||
if len(result.Diagnostics) != 0 {
|
||||
t.Fatalf("Diagnostics = %#v, want none", result.Diagnostics)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,11 +31,11 @@ func TestValidatorWarnsWhenSpellDoesNotAppearInCitedText(t *testing.T) {
|
||||
if !result.Approved {
|
||||
t.Fatalf("Approved = false, want true")
|
||||
}
|
||||
if len(result.Warnings) != 1 {
|
||||
t.Fatalf("Warnings = %#v, want one warning", result.Warnings)
|
||||
if len(result.Warnings) != 0 || len(result.Diagnostics) != 1 {
|
||||
t.Fatalf("Diagnostics = %#v, want one advisory", result.Diagnostics)
|
||||
}
|
||||
if result.Warnings[0].ReasonCode != WarningReasonCode {
|
||||
t.Fatalf("ReasonCode = %q, want %q", result.Warnings[0].ReasonCode, WarningReasonCode)
|
||||
if result.Diagnostics[0].ReasonCode != ReasonCode || result.Diagnostics[0].Disposition != contracts.DiagnosticDispositionAdvisory {
|
||||
t.Fatalf("diagnostic = %#v", result.Diagnostics[0])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ func TestValidatorMatchesCaseInsensitiveUnicodeMultiwordSpellAcrossCitations(t *
|
||||
},
|
||||
}
|
||||
result, err := New(Options{}).Validate(context.Background(), contracts.TypedValidationRequest[dnd.SpellList]{Source: doc, Value: value})
|
||||
if err != nil || !result.Approved || len(result.Warnings) != 0 {
|
||||
if err != nil || !result.Approved || len(result.Diagnostics) != 0 {
|
||||
t.Fatalf("Validate() = %#v, %v; want normalized multiword spell approval", result, err)
|
||||
}
|
||||
}
|
||||
@@ -66,8 +66,27 @@ func TestValidatorDoesNotMatchShortSpellNameSubstring(t *testing.T) {
|
||||
ID: "session", Kind: "transcript", Format: "application/json", Digest: "sha256:session",
|
||||
Units: []source.SourceUnit{{ID: 1, Kind: "message", Text: "The party said nothing."}},
|
||||
}, "Aid", 1))
|
||||
if err != nil || !result.Approved || len(result.Warnings) != 1 {
|
||||
t.Fatalf("Validate() = %#v, %v; want short-name boundary warning", result, err)
|
||||
if err != nil || !result.Approved || len(result.Diagnostics) != 1 {
|
||||
t.Fatalf("Validate() = %#v, %v; want short-name boundary advisory", result, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidatorBoundsHighCardinalitySpellFindings(t *testing.T) {
|
||||
count := contracts.MaxDiagnosticSamples + 4
|
||||
casts := make([]dnd.SpellCast, count)
|
||||
for index := range casts {
|
||||
casts[index] = dnd.SpellCast{Caster: "Aria", Spell: "Missing Spell", SourceRefs: []source.SourceRef{{SourceID: "session", StartUnitID: 1, EndUnitID: 1}}}
|
||||
}
|
||||
result, err := New(Options{}).Validate(context.Background(), contracts.TypedValidationRequest[dnd.SpellList]{
|
||||
Source: &source.SourceDocument{ID: "session", Units: []source.SourceUnit{{ID: 1, Text: "The party waits."}}},
|
||||
Value: dnd.SpellList{SpellCasts: casts},
|
||||
})
|
||||
if err != nil || !result.Approved || len(result.Warnings) != 0 || len(result.Diagnostics) != 1 {
|
||||
t.Fatalf("Validate() = %#v, %v", result, err)
|
||||
}
|
||||
diagnostic := result.Diagnostics[0]
|
||||
if diagnostic.OccurrenceCount != count || len(diagnostic.Samples) != contracts.MaxDiagnosticSamples || diagnostic.OmittedSampleCount != count-contracts.MaxDiagnosticSamples {
|
||||
t.Fatalf("diagnostic = %#v", diagnostic)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,8 +94,8 @@ func TestValidatorIgnoresInvalidCitations(t *testing.T) {
|
||||
request := requestWithSpell(validDocument(), "Cure Wounds", 2)
|
||||
request.Value.SpellCasts[0].SourceRefs[0].StartUnitID = 99
|
||||
result, err := New(Options{}).Validate(context.Background(), request)
|
||||
if err != nil || !result.Approved || len(result.Warnings) != 0 {
|
||||
t.Fatalf("Validate() = %#v, %v; want approval without relatedness warning", result, err)
|
||||
if err != nil || !result.Approved || len(result.Diagnostics) != 0 {
|
||||
t.Fatalf("Validate() = %#v, %v; want approval without relatedness advisory", result, err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user