Add a mutation gate that proves a green guard test goes red on a broken patch #875
Labels
No labels
P0
P1
P2
P3
bug
category/code-change
category/cross-repo
category/eval-run
category/investigation
category/no-test-target
category/owner-ruling
category/prose-artifact
category/recurring-chore
category/structure
category/umbrella
crc-refactor
create
delete
enhancement
filed-by/agent
filed-by/user
frozen
lint-rule
needs-info
needs-triage
next
plugin/cc-architect
plugin/os
plugin/os-adr
plugin/os-aidd-lint
plugin/os-backlog
plugin/os-context
plugin/os-doc-hygiene
plugin/os-sdlc
plugin/os-vault
project/cc-os
ready-for-agent
ready-for-human
recurring
review
rule-proposal
update
waiting
wayfinder:grilling
wayfinder:map
wayfinder:map
wayfinder:research
wayfinder:task
wayfinder:task
wontfix
worklist/deviations
worklist/lint-rule
worklist/new-implement-build
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Blocks
Reference
jared/cc-os#875
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
A guard test proves behavior that already exists. ADR-0258 (decision 12) proves such a test with a mutation, not red-first: the test must go red when the guarded code is broken. No gate does this.
Gate::Name::ALL(lib/os_sdlc/model/gate/name.rb:12) has nomutationname, andGate::Commands#to_h(lib/os_sdlc/query/gate/commands.rb:13) has no command for it. cc-plugins #79 (commit 84bac12) is the motivating case: a tier1 parity test was green on day one, the pipeline escalatedunexpected_pass, and the work was not merged.Reproduce
n/a: design change, nothing to reproduce.
Approach
Add a
mutationgate. The test-writer handoff carriesmutation: { path:, patch: }:pathis a production file under the target path, andpatchis a unified diff that breaks the guarded code.Gates on a node run inside the agent turn, before the handoff exists (
CompletionIntake#gate_verdict_outcome, command/completion_intake.rb:99, reads the verdict the in-turn gate recorded). So the mutation gate cannot run on the test-writer node. It runs on the next node of the guard map, a gate-only node whose agent runsos-sdlc-gateonce (the guard-map ticket adds that node). The check reads the patch fromImplementation#latest_handoff_from("test-writer")(model/implementation.rb:74).MUTATION = "mutation"toGate::Nameand toALL.Name::MUTATION => "os-sdlc-mutation-check #{implementation.id}"toGate::Commands#to_h.bin/os-sdlc-mutation-check IMPLEMENTATION_IDand the Boot entrymutation-check(controller/boot/commands.rb), the same shape asrequired-work-check.mutationreader toHandoffContent(parser/handoff_content.rb). It returns nil when the field is absent.path, runs the diff-test command (Gate::Commands#plan), and restores the file inensure. It exits 0 only when the test run is red (executed and failed). It exits nonzero with a reason when the field is missing, the patch does not apply,pathis outside the target path, or the test stays green ("mutation survived").Required work:
MUTATION = "mutation"inplugins/os-sdlc/lib/os_sdlc/model/gate/name.rbName::MUTATIONinplugins/os-sdlc/lib/os_sdlc/query/gate/commands.rbmutation-checkinplugins/os-sdlc/bin/os-sdlc-mutation-checkdef mutationinplugins/os-sdlc/lib/os_sdlc/parser/handoff_content.rbAcceptance criteria
mutationpatch breaks the code the new test guards, whenos-sdlc-mutation-checkruns, then it exits 0 and the production file is byte-identical to its content before the run.mutationpatch leaves the new test green, when the check runs, then it exits nonzero, the output says the mutation survived, and the production file is restored.mutationfield, when the check runs, then it exits nonzero and names the missing field.mutationpatch that does not apply topath, when the check runs, then it exits nonzero, names the path, and leaves the file unchanged.gates: [mutation], when the gate commands are built, then themutationcommand isos-sdlc-mutation-check <implementation id>.Owner sketch
Origin
Parent: #859
Work started: os-sdlc pipeline on branch ticket-875 (worktree .claude/worktrees/ticket-875).
Resolution
Done: Added the mutation gate: Gate::Name::MUTATION, Gate::Commands maps it to os-sdlc-mutation-check , HandoffContent#mutation reads mutation: {path:, patch:}, Mutation::Check applies the patch, runs the diff-test plan, restores the file, and passes only on a red run.
Evidence: Pipeline implementation 8 completed with no rejections (8 dispatches, 9 min 49 s); commit
461ff366merged to main; History row5b49309e; bin/test 9 suites passed on main.Follow-ups: #893 (mutation gate counts a load failure as a kill; ticket-skeptic VERDICT: CREATE)