Retain application skip reasons for repaired proposals

This commit is contained in:
2026-11-11 12:25:15 +00:00
parent bcce4729e1
commit 8267eba6a5
3 changed files with 40 additions and 3 deletions

View File

@@ -95,6 +95,7 @@ func BuildCorrectionLedger(input CorrectionLedgerInput) []CorrectionLedgerEntry
}
}
seen := make(map[proposalIdentity]bool)
repairSkips := make(map[proposalIdentity]proposals.SkippedChange)
stages := make(map[string]stageEvidence, len(runOutput.ModuleResults))
for _, module := range runOutput.ModuleResults {
decisionsByProposal := make(map[int][]runner.ValidatorDecisionRecord)
@@ -129,10 +130,12 @@ func BuildCorrectionLedger(input CorrectionLedgerInput) []CorrectionLedgerEntry
})
}
for _, change := range module.SkippedChanges {
if _, ok := repairs[proposalIdentity{module.ModuleInstance, change.ProposalIndex}]; ok {
identity := proposalIdentity{module.ModuleInstance, change.ProposalIndex}
if _, ok := repairs[identity]; ok {
repairSkips[identity] = change
continue
}
seen[proposalIdentity{module.ModuleInstance, change.ProposalIndex}] = true
seen[identity] = true
entries = append(entries, CorrectionLedgerEntry{
StageIndex: module.StageIndex, StageID: module.StageID,
RunID: runID,
@@ -204,6 +207,9 @@ func BuildCorrectionLedger(input CorrectionLedgerInput) []CorrectionLedgerEntry
entry.AppliedSegmentID = &segment
entry.AppliedOriginalText = &before
entry.AppliedCorrectedText = &after
} else if skipped, ok := repairSkips[identity]; ok && repair.Outcome == "approved_skipped" {
entry.DispositionReasonCode = string(skipped.SkipReason)
entry.DispositionMessage = skipped.Message
}
seen[identity] = true
entries = append(entries, entry)

View File

@@ -226,6 +226,35 @@ func TestCorrectionLedgerCombinesRepairLineage(t *testing.T) {
}
}
func TestSkippedRepairLedgerKeepsApplicationReason(t *testing.T) {
const instance = "grammar_1"
original := proposals.EnrichedCorrectionProposal{
CorrectionProposal: proposals.CorrectionProposal{TargetSegmentID: 1, OriginalText: "cat", CorrectedText: "fox"},
ProposalMetadata: proposals.ProposalMetadata{ProposalIndex: 1, ModuleKey: "grammar", ModuleInstance: instance},
}
revision := original
revision.Confidence = 0.99
skip := proposals.SkippedChange{ProposalIndex: 1, SkipReason: proposals.SkipReasonMissingOriginalText, Message: "source span no longer matches"}
output := &runner.RunOutput{
ModuleResults: []runner.ModuleResult{{ModuleInstance: instance, SkippedChanges: []proposals.SkippedChange{skip}}},
WorkUnits: []runner.WorkUnitOutcome{{ModuleInstance: instance, Repairs: []runner.RepairOutcome{{
ProposalIndex: 1, Outcome: "approved_skipped", Original: original, Final: revision,
Attempts: []runner.RepairAttempt{{Revision: &revision}},
}}}},
Candidates: []proposals.EnrichedCorrectionProposal{original},
}
ledger := BuildCorrectionLedger(CorrectionLedgerInput{RunOutput: output})
if len(ledger) != 1 {
t.Fatalf("ledger: %+v", ledger)
}
entry := ledger[0]
if entry.Disposition != "approved_skipped" || entry.DispositionReasonCode != string(skip.SkipReason) ||
entry.DispositionMessage != skip.Message || entry.AppliedSegmentID != nil || entry.AppliedOriginalText != nil ||
entry.AppliedCorrectedText != nil || len(entry.RepairAttempts) != 1 {
t.Fatalf("skipped revision: %+v", entry)
}
}
func TestInterruptedRepairLedgerKeepsEarlierDecisions(t *testing.T) {
original := proposals.EnrichedCorrectionProposal{CorrectionProposal: proposals.CorrectionProposal{TargetSegmentID: 1, OriginalText: "cat", CorrectedText: "dog"}, ProposalMetadata: proposals.ProposalMetadata{ProposalIndex: 1, ModuleKey: "grammar", ModuleInstance: "grammar_1"}}
revision := original