test(daemon): kill 38 surviving mutants across three pure helpers - #81
Merged
Merged
Conversation
Targets the exact surviving-mutant lists the mutation gate produced at b697493 for agents/capabilities.rs (12), policy/tester.rs (12) and intelligence/context.rs (19). Each new test is written against a specific mutation and asserts a value that only the unmutated code produces, rather than a value that merely happens to be right. Fixtures are chosen so the correct answer differs from what the arithmetic mutations would give: for example optimize_context's budget walk uses a cost of 16 against a budget of 80 so that `remaining` lands on exactly 16, which is the only input that separates `< 16` from `<= 16` and `== 16`. Every mutant was hand-applied and the suite confirmed to fail: capabilities.rs 10 of 12 killed policy/tester.rs 12 of 12 killed context.rs 16 of 16 killed The four not counted above are equivalent mutants, documented in place rather than chased: - deleting the ("planner","high") or ("implementer",_) arms of recommend_provider: both fall through to `_ => Provider::Claude`, so no input can observe the difference. - the `full_cost > budget` comparison in optimize_context's trailing truncation guard is unreachable. The guard only fires for a message that is neither pinned nor a system message, and such a message reaches the result only by being selected, which required role_tokens + full_cost + 4 <= remaining <= budget. So full_cost is always strictly below budget and the branch is dead. Inline `mod tests` blocks move to `<module>/tests.rs` with the existing cases kept verbatim, matching the layout used by the other suites added in this series. No production code changes.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Targets the exact surviving-mutant lists the mutation gate produced at
b697493for three pure, in-scope helpers.agents/capabilities.rspolicy/tester.rsintelligence/context.rsEvery mutant was hand-applied and the suite confirmed to fail. A green test proves nothing about whether it kills anything, so each one was patched into the source one at a time, the suite run, and the source restored — 28 of 28 killed on
tester.rs+context.rs, 10 of 12 oncapabilities.rs, with the 2 survivors matching the pair predicted to be equivalent.Fixtures are built so the right answer is not an accident
The arithmetic mutations (
+→*,-=→+=,<→<=) only die if the correct value differs from what the mutation produces, which rules out the obvious round numbers. Some of what that forced:optimize_context's budget walk uses a per-message cost of 16 against a budget of 80, soremainingsteps80 → 64 → 48 → 32 → 16 → 0and lands on exactly 16. That is the only input separatingremaining < 16(5 messages survive) from<= 16and== 16(4 survive).2+9+4 = 15leaves room for 4 regular messages,2*9+4 = 22leaves room for 3, and2+9*4 = 38leaves room for 2 — three different answers, so both+→*mutations are separable.truncate_to_tokens(40 chars, max_tokens=4)is asserted to be exactly 12xplus an ellipsis. Undermax_tokens + 4it is 4; under<=it is 13; under==and>thetake_whilepredicate fails on the very first index, the iterator is empty, andunwrap_or(0)yields a bare ellipsis.run_all_policy_testsgets a directory holding a 3-case.yaml, a 2-case.ymland a 4-case.txt. The sizes are picked so no wrong subset sums to the right answer of 5: mutating the first==collects.yml + .txt = 6, the second collects.yaml + .txt = 7, and&&collects nothing.Equivalent mutants, documented rather than chased
("planner", "high")or("implementer", _)arms ofrecommend_provider— both fall through to_ => Provider::Claude, so no input can observe the difference. Confirmed empirically: these are the 2 that survived the hand-application run.full_cost > budgetcomparison inoptimize_context's trailing truncation guard is unreachable. The guard only fires for a message that is neither pinned nor a system message, and such a message reaches the result only by being selected — which requiredrole_tokens + full_cost + 4 <= remaining <= budget. Sofull_costis always strictly belowbudgetand the branch is dead code. Its<,==and>=mutations are therefore indistinguishable.The guard's other three mutations are not equivalent and are killed:
&&→||and thedelete !both make the condition true for a pinned message, and!=→==makes it true for an unpinned system message. Two tests pin that an oversized pinned message and an oversized system prompt are each returned at their full 200 characters, because silently trimming a system prompt is the actual bug hiding behind that operator.Layout
Inline
mod testsblocks move to<module>/tests.rswith existing cases kept verbatim, matching the other suites in this series. No production code changes —git show --statis test files plus themod tests;declarations.cargo fmt --check,cargo clippy --all-targets -- -D warningsand the full 832-test lib suite are clean.