2026-11-11 04:23:34 +00:00
|
|
|
package runner
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"math"
|
|
|
|
|
|
|
|
|
|
"gitea.maximumdirect.net/eric/audita/v3/internal/core/modulecatalog"
|
|
|
|
|
"gitea.maximumdirect.net/eric/audita/v3/internal/framework/contracts"
|
|
|
|
|
"gitea.maximumdirect.net/eric/audita/v3/internal/framework/proposal_generation"
|
|
|
|
|
"gitea.maximumdirect.net/eric/audita/v3/internal/framework/proposals"
|
|
|
|
|
"gitea.maximumdirect.net/eric/audita/v3/internal/framework/validators"
|
|
|
|
|
validatormetadata "gitea.maximumdirect.net/eric/audita/v3/internal/validators/metadata"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// feedbackCandidates submits only candidates for which the validator has usable evidence.
|
2026-11-11 12:28:00 +00:00
|
|
|
func feedbackCandidates(input validateSectionCandidatesInput, validator contracts.Validator, noEffect map[int]bool, evidence contracts.ValidationRequest) []proposals.EnrichedCorrectionProposal {
|
2026-11-11 04:23:34 +00:00
|
|
|
var result []proposals.EnrichedCorrectionProposal
|
|
|
|
|
for _, candidate := range input.SectionEnriched {
|
|
|
|
|
if noEffect[candidate.ProposalIndex] {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
usableSpan := candidate.OriginalText != ""
|
|
|
|
|
target := candidate.TargetSegmentID > 0
|
|
|
|
|
confidence := !math.IsNaN(candidate.Confidence) && candidate.Confidence >= 0 && candidate.Confidence <= 1
|
|
|
|
|
var applicable bool
|
|
|
|
|
switch validator.Name() {
|
|
|
|
|
case "proposal_shape":
|
|
|
|
|
applicable = true
|
|
|
|
|
case "no_effect":
|
|
|
|
|
applicable = usableSpan
|
|
|
|
|
case "confidence_threshold":
|
|
|
|
|
applicable = confidence
|
|
|
|
|
case "original_text_presence":
|
|
|
|
|
applicable = usableSpan && target
|
|
|
|
|
case "protected_terms":
|
|
|
|
|
applicable = usableSpan
|
|
|
|
|
if input.Spec.ModuleKey == modulecatalog.KeyGlossary || input.Spec.ModuleKey == modulecatalog.KeySpokenWord {
|
2026-11-11 12:28:00 +00:00
|
|
|
preview := evidence.Preview(candidate)
|
2026-11-11 04:47:43 +00:00
|
|
|
applicable = preview.Applicable || preview.SkipReason == proposals.SkipReasonEmptyResultingText
|
2026-11-11 04:23:34 +00:00
|
|
|
}
|
|
|
|
|
case "non_empty_resulting_segment":
|
2026-11-11 12:28:00 +00:00
|
|
|
preview := evidence.Preview(candidate)
|
2026-11-11 04:23:34 +00:00
|
|
|
applicable = preview.Applicable || preview.SkipReason == proposals.SkipReasonEmptyResultingText
|
|
|
|
|
default:
|
|
|
|
|
if validatormetadata.ClassOf(validator) == validatormetadata.ExecutionClassLLMBacked {
|
2026-11-11 12:28:00 +00:00
|
|
|
applicable = evidence.Preview(candidate).Applicable
|
2026-11-11 04:23:34 +00:00
|
|
|
} else {
|
|
|
|
|
applicable = true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if applicable {
|
|
|
|
|
result = append(result, candidate)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return result
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// repairFindings extracts ordered, safe feedback for one candidate version.
|
|
|
|
|
func repairFindings(index int, rejected []ValidatorRejectedChange) []proposal_generation.RepairFinding {
|
|
|
|
|
var findings []proposal_generation.RepairFinding
|
|
|
|
|
for _, decision := range rejected {
|
|
|
|
|
if decision.ProposalIndex != index {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
finding := proposal_generation.RepairFinding{Validator: decision.ValidatorName, Reason: decision.ReasonCode, Explanation: decision.Message}
|
|
|
|
|
if decision.Disposition == validators.DispositionUnavailable {
|
|
|
|
|
finding.Status = "unavailable"
|
|
|
|
|
finding.Explanation = "assessment was unavailable"
|
|
|
|
|
}
|
|
|
|
|
findings = append(findings, finding)
|
|
|
|
|
}
|
|
|
|
|
return findings
|
|
|
|
|
}
|