Align validator identity and span domain checks

This commit is contained in:
2026-09-25 02:48:57 +00:00
parent 31979d4081
commit 640f663ace
19 changed files with 148 additions and 49 deletions

View File

@@ -109,6 +109,26 @@ func TestApplyProposalsStaleProposalSkippedAfterEarlierChange(t *testing.T) {
}
}
func TestApplyProposalsRechecksBlankResultAfterEarlierDeletion(t *testing.T) {
transcript := &schema.Transcript{Segments: []schema.Segment{{ID: 1, Text: "a b"}}}
proposed := []EnrichedCorrectionProposal{
{CorrectionProposal: CorrectionProposal{TargetSegmentID: 1, OriginalText: "a", CorrectedText: "", Confidence: 1}, ProposalMetadata: ProposalMetadata{ProposalIndex: 0}},
{CorrectionProposal: CorrectionProposal{TargetSegmentID: 1, OriginalText: "b", CorrectedText: "", Confidence: 1}, ProposalMetadata: ProposalMetadata{ProposalIndex: 1}},
}
for _, candidate := range proposed {
if preview := PreviewProposalForSegment(&transcript.Segments[0], candidate.CorrectionProposal, ReplacementPolicyRequireUnique); !preview.Applicable {
t.Fatalf("proposal must be initially applicable: %+v", preview)
}
}
result := ApplyProposals(transcript, proposed, ReplacementPolicyRequireUnique)
if got := result.Transcript.Segments[0].Text; got != " b" {
t.Fatalf("expected literal surviving text, got %q", got)
}
if len(result.Applied) != 1 || len(result.Skipped) != 1 || result.Skipped[0].SkipReason != SkipReasonEmptyResultingText {
t.Fatalf("expected second deletion skipped after reevaluation: %+v", result)
}
}
func TestApplyProposalsMissingSegmentSkip(t *testing.T) {
transcript := &schema.Transcript{Segments: []schema.Segment{{ID: 1, Text: "hello"}}}
proposals := []EnrichedCorrectionProposal{

View File

@@ -139,6 +139,30 @@ func TestPreviewProposalForSegmentAllowsEmptyCorrectedTextWhenSegmentRemainsNonE
}
}
func TestPreviewProposalForSegmentWhitespaceSpan(t *testing.T) {
proposal := CorrectionProposal{TargetSegmentID: 8, OriginalText: " ", CorrectedText: " ", Confidence: 0.9}
unique := PreviewProposalForSegment(&schema.Segment{ID: 8, Text: "hello world"}, proposal, ReplacementPolicyRequireUnique)
if !unique.Applicable || unique.CorrectedSegmentText != "hello world" || unique.ReplacementCount != 1 {
t.Fatalf("unexpected spacing preview: %+v", unique)
}
segment := &schema.Segment{ID: 8, Text: "a b c"}
ambiguous := PreviewProposalForSegment(segment, proposal, ReplacementPolicyRequireUnique)
if ambiguous.Applicable || ambiguous.SkipReason != SkipReasonAmbiguousOriginal {
t.Fatalf("expected ambiguity under require_unique: %+v", ambiguous)
}
all := PreviewProposalForSegment(segment, proposal, ReplacementPolicyReplaceAll)
if !all.Applicable || all.CorrectedSegmentText != "a b c" || all.ReplacementCount != 2 {
t.Fatalf("expected replace_all to correct both spans: %+v", all)
}
}
func TestPreviewProposalForSegmentRejectsEmptyOriginalText(t *testing.T) {
preview := PreviewProposalForSegment(&schema.Segment{ID: 8, Text: "hello"}, CorrectionProposal{TargetSegmentID: 8, OriginalText: "", CorrectedText: "x", Confidence: 0.9}, ReplacementPolicyRequireUnique)
if preview.Applicable || preview.SkipReason != SkipReasonInvalidProposal {
t.Fatalf("expected invalid empty original: %+v", preview)
}
}
func TestPreviewProposalForSegmentRejectsEmptyResultingSegment(t *testing.T) {
segment := &schema.Segment{ID: 8, Text: "uh"}
proposal := CorrectionProposal{

View File

@@ -2,7 +2,6 @@ package proposals
import (
"fmt"
"strings"
)
// CorrectionProposal is the base proposal emitted by correction modules.
@@ -35,7 +34,7 @@ func (p CorrectionProposal) Validate() error {
if p.TargetSegmentID <= 0 {
return fmt.Errorf("proposal id must be positive")
}
if strings.TrimSpace(p.OriginalText) == "" {
if p.OriginalText == "" {
return fmt.Errorf("proposal original_text must not be empty")
}
if p.Confidence < 0.0 || p.Confidence > 1.0 {

View File

@@ -48,6 +48,13 @@ func TestCorrectionProposalValidate_AllowsEmptyCorrectedText(t *testing.T) {
}
}
func TestCorrectionProposalValidate_AllowsWhitespaceOriginalText(t *testing.T) {
proposal := CorrectionProposal{TargetSegmentID: 42, OriginalText: " ", CorrectedText: " ", Confidence: 0.95}
if err := proposal.Validate(); err != nil {
t.Fatalf("expected whitespace span to be valid, got %v", err)
}
}
func TestCorrectionProposalValidate_InvalidConfidence(t *testing.T) {
proposal := CorrectionProposal{
TargetSegmentID: 42,