diff --git a/docs/roadmap/remediation.md b/docs/roadmap/remediation.md index a13f3d6..857f7e3 100644 --- a/docs/roadmap/remediation.md +++ b/docs/roadmap/remediation.md @@ -4,7 +4,7 @@ **Scope:** The four implementation commits after `31979d4`, compared with [span-deletion.md](span-deletion.md), [implementation.md](implementation.md), the agreed user intent, and repository policies. -**Status:** R15 open. Earlier findings R1–R14 are resolved; their evidence and +**Status:** R15 addressed; see the resolution record below. Earlier findings R1–R14 are resolved; their evidence and resolution records remain in Git history through `24b8992`. ## Architecture Assessment @@ -71,3 +71,15 @@ test rather than adding overlapping coverage. behavior, not a guarantee that a model will always propose or approve good edits. - This review records remediation only; it does not implement the test correction or any deferred feature. + +## Resolution Record + +**R15:** Updated the existing conflict test to use `outcomeModule` with a successful +proposal operation. The test requires that operation to be present and checks for +absent failure reasons, recovery reasons, and filtered-proposal records, while +retaining the final-text and skipped-decision assertions. Production code is unchanged. + +Validation: `go test ./internal/framework/runner` passed. Repeating the temporary +overlay experiment now fails at the accounting assertion with an erroneous +`proposals_filtered` recovery for the second deletion, confirming that the test +detects the intended regression. The overlay did not modify repository source. diff --git a/internal/framework/runner/runner_test.go b/internal/framework/runner/runner_test.go index 77c5a52..12a6c9c 100644 --- a/internal/framework/runner/runner_test.go +++ b/internal/framework/runner/runner_test.go @@ -876,12 +876,18 @@ func TestRunnerApplicationSkipAfterValidatorApprovalReported(t *testing.T) { func TestRunnerApplyConflictAfterTwoInitiallyValidDeletions(t *testing.T) { transcript := &schema.Transcript{Segments: []schema.Segment{{ID: 1, Text: "a b"}}} r := New(fakeFactory{modules: map[string]contracts.TranscriptModule{ - "m": fakeModule{key: "m", policy: proposals.ReplacementPolicyRequireUnique, validators: []contracts.Validator{validators.ProposalShapeValidator{}, validators.NonEmptyResultingSegmentValidator{}}, proposeF: func(req contracts.ProposalRequest) ([]proposals.CorrectionProposal, error) { - return []proposals.CorrectionProposal{ - {TargetSegmentID: 1, OriginalText: "a", CorrectedText: "", Confidence: 1}, - {TargetSegmentID: 1, OriginalText: "b", CorrectedText: "", Confidence: 1}, - }, nil - }}, + "m": outcomeModule{ + fakeModule: fakeModule{key: "m", policy: proposals.ReplacementPolicyRequireUnique, validators: []contracts.Validator{validators.ProposalShapeValidator{}, validators.NonEmptyResultingSegmentValidator{}}}, + proposeResult: func(req contracts.ProposalRequest) (contracts.ProposalResult, error) { + return contracts.ProposalResult{ + Proposals: []proposals.CorrectionProposal{ + {TargetSegmentID: 1, OriginalText: "a", CorrectedText: "", Confidence: 1}, + {TargetSegmentID: 1, OriginalText: "b", CorrectedText: "", Confidence: 1}, + }, + Operations: []outcomes.Operation{{Reference: outcomes.Reference{Kind: outcomes.OperationProposal}, Succeeded: true}}, + }, nil + }, + }, }}) out, err := r.Run(context.Background(), RunInput{Transcript: transcript, ModuleSpecs: []contracts.ModuleRunSpec{{ModuleKey: "m", InstanceName: "m"}}, CaptureCandidates: true}) if err != nil { @@ -896,11 +902,18 @@ func TestRunnerApplyConflictAfterTwoInitiallyValidDeletions(t *testing.T) { if len(out.ModuleResults[0].ValidatorRejected) != 0 || len(out.WorkUnits) != 1 || out.WorkUnits[0].CorrectionsApplied != 1 { t.Fatalf("unexpected validation or application outcome: %+v", out) } + foundProposal := false for _, operation := range out.WorkUnits[0].Operations { - if operation.FailureReason != "" || len(operation.RecoveryReasons) != 0 { + if operation.Reference.Kind == outcomes.OperationProposal && operation.Succeeded { + foundProposal = true + } + if operation.FailureReason != "" || len(operation.RecoveryReasons) != 0 || len(operation.Filtered) != 0 { t.Fatalf("apply-time conflict must not count as model error or filtering recovery: %+v", operation) } } + if !foundProposal { + t.Fatalf("expected successful proposal operation: %+v", out.WorkUnits[0].Operations) + } } func ptrConfig(c config.Config) *config.Config { return &c }