Skip to content

feat(testing): mutation testing on DepthBiasCalculator + retargeting samplers (#282) - #284

Draft
arkavo-com wants to merge 17 commits into
mainfrom
issue/282-mutation-testing
Draft

feat(testing): mutation testing on DepthBiasCalculator + retargeting samplers (#282)#284
arkavo-com wants to merge 17 commits into
mainfrom
issue/282-mutation-testing

Conversation

@arkavo-com

@arkavo-com arkavo-com commented May 21, 2026

Copy link
Copy Markdown
Contributor

Closes #282

Stands up mutation testing for VRMMetalKit and runs it against two targets to answer issue #282's scoping question: is mutation testing worth adopting as a routine?

Target 1 — DepthBiasCalculator (POC)

  • Bootstraps muter from a pinned master SHA into .build/tools/, with a local patch for a v16 schemata-identity bug (.muter/patches/v16-schemata-content-fallback.patch) that otherwise made every run report 0% killed.
  • 32-test direct oracle suite. 87% mutation score (7/8 killed); the lone survivor is a Metal GPU side-effect, classified accepted-gap.
  • Finding: the original tests had 100% line coverage of the priority if-chain but killed nothing — the partial-match safety net masked the mutants. Multi-keyword tests that exercise the priority chain fixed it.

Target 2 — VRMA retargeting samplers

  • Extracts makeRotationSampler / makeTranslationSampler / makeScaleSampler from the 977-line VRMAnimationLoader.swift into a testable RetargetingSamplers.swift (behavior-preserving refactor).
  • 15-test direct oracle suite. 100% mutation score (6/6 killed).
  • Finding that matters more than the score: all 6 mutants landed in the safeDivide guard helper. The quaternion/SIMD retargeting math generated zero mutants — muter v16's four scalar operators (relational / side-effect / logical / ternary) have nothing to grab in simd-based code.

Verdict (see docs/mutation-testing/retargeting-samplers-baseline.md)

Validated, not adopted — lean stop. Mutation testing has real value for scalar control-flow code but is nearly blind to the simd math that makes up most of VRMMetalKit's core. Recommendation: do not adopt as a routine/CI gate; keep it as an opt-in spot-check for scalar-logic-heavy files. Infrastructure stays in place (make mutation-test-*) for future use.

Out of scope

  • Other modules; CI integration; custom muter operators (considered and rejected — maintenance not justified).

Test plan

  • make muter-bootstrap builds patched muter from the pinned SHA
  • make mutation-test-depth-bias → 7/8 killed (87%)
  • make mutation-test-retargeting → 6/6 killed (100%)
  • swift test --filter DepthBiasCalculatorTests --disable-sandbox — 32 pass
  • swift test --filter RetargetingSamplersTests --disable-sandbox — 15 pass
  • RetargetingSamplers extraction is behavior-preserving — full suite unchanged
  • Both baseline docs classify every surviving mutant

🤖 Generated with Claude Code

arkavo-com and others added 10 commits May 21, 2026 19:59
First-target proof-of-concept: muter built from a pinned SHA, direct
unit suite written before any mutation run, ≥80% mutation score with
every survivor classified.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds make muter-bootstrap to build muter from a pinned master SHA into
.build/tools/, and make mutation-test as the run target. The 2023 tagged
release (16) predates Swift 6.2 toolchain changes; building from source
is the only reliable path until muter cuts a new release.

Note: build command uses --product muter to skip test targets, which
fail under Swift 6.2 due to @testable import muterCore incompatibility
in XCTestExtensions.swift. The muter executable itself builds cleanly.

Issue #282

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds 22 direct unit tests covering construction, exact-match lookups,
priority ordering, case-insensitive matching, default fallback, overlay
offset, scale multiplication, and cache observability. This suite is
the muter target for issue #282; HipSkirtTests stays as the integration
suite and is not part of the mutation oracle.

Issue #282

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…282)

Mutates Sources/GLTFCore/Utilities/DepthBiasCalculator.swift using
muter's default operator set. Tests run via swift test --filter
DepthBiasCalculatorTests --disable-sandbox (sandbox-disabled because
project tests need FS access for fixtures, and muter needs FS write
access for source rewrites). JSON output path is deterministic for
future CI artifact consumption.

Issue #282

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
muter v16's config file schema does not support filesToMutate or
output-path keys — those are CLI flags. Update the mutation-test target
to pass --files-to-mutate, --format json, --output, and --skip-coverage
so the run is correctly scoped to DepthBiasCalculator and writes the
deterministic JSON artifact.

Issue #282

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…n run (#282)

Survivor-driven additions to the oracle suite. Added 10 new tests: one for
each individual keyword in the clothing OR-chain (cloth, clothing, skirt,
bottoms, pants), one each for mouth and lip alone, one for brow alone, and
two absolute-value overlay assertions that pin the SwapTernary mutant.

Also adds .muter/depth-bias.yml (YAML config required by muter v16's
--configuration path resolution) and switches Makefile to use it. Adds
--build-path /tmp/vrm-muter-build to avoid module-cache path conflicts when
muter copies the project to the _mutated directory.

Mutation score: 0% (tool bug; see PR for analysis). Manual review confirms
all 7 kill-pending survivors are now covered by the 35-test suite; 1 survivor
(RemoveSideEffects on MTLRenderCommandEncoder) is accepted-gap.

Issue #282

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
muter v16's SchemataMutationMapping keys schemata by SwiftSyntax
tree-position identity, but ApplySchemata re-parses files so the
identity-based dict lookup always misses — producing zero-killed
mutation runs even when the test suite would kill mutants.

Add a parallel mappingsByDescription index (populated at insertion
while arenas are alive) as a content-based fallback in schemata(_:).
The matched entry is removed immediately after use to prevent
re-injection into the else branch of the injected schemata switch,
which would otherwise recurse until stack overflow.

Apply the patch during muter-bootstrap via git apply, preceded by
git checkout -- . to keep bootstrap idempotent.

Issue #282

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The prior single-keyword 'alone' tests didn't kill the ChangeLogicalConnector
mutants on the explicit if-chains: the partial-match scan in computeBias()
is a safety net that returns the same value for single-keyword inputs.

Replace with multi-keyword tests (cloth_body, skirt_body, bottoms_body,
mouth_eye, brow_eye) that exploit the priority chain — original code hits
the higher-priority branch via the if-chain, mutated code falls through to
a lower-priority branch with a different result.

Mutation score climbs from 12% to 87.5%. Remaining survivor is the Metal
GPU side-effect (encoder.setDepthBias), classified as accepted-gap.

Issue #282

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
First-target proof-of-concept baseline at 87% mutation score (7/8 killed).
Documents the one surviving Metal GPU side-effect as accepted-gap, the
muter v16 schemata-identity patch applied during bootstrap, and follow-ups
for upstream submission + scope expansion.

Issue #282

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@arkavo-com
arkavo-com force-pushed the issue/282-mutation-testing branch from 9d1aae2 to 04cab90 Compare May 22, 2026 00:00
@arkavo-com
arkavo-com changed the base branch from issue/280-platform-specific-metallibs to main May 22, 2026 00:00
arkavo-com and others added 7 commits May 21, 2026 21:00
Second mutation-testing target and the agreed go/no-go run: extract the
three retargeting samplers from VRMAnimationLoader into a testable
RetargetingSamplers file, then mutation-test that. Baseline doc carries
a Verdict section feeding the expand/stop decision.

Issue #282

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…282)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…der (#282)

Move makeRotationSampler / makeTranslationSampler / makeScaleSampler and
their safeDivide helper into a focused RetargetingSamplers.swift so the
VRMA retargeting math is an isolated, directly-testable unit. KeyTrack,
Interpolation, sampleQuaternion and sampleVector3 are promoted private to
internal so the new file (and tests) can reach them. No behavior change.

Issue #282

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
15 direct unit tests covering all three retargeting samplers and
safeDivide: nil-model-rest passthrough, identity-rest collapse, the
W_A==W_B delta-formula collapse, the full W-term change-of-basis, and
additive/ratio/edge-case behavior. The muter target for issue #282's
second mutation run.

Issue #282

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Issue #282

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ate (#282)

mutation-test becomes an aggregate of mutation-test-depth-bias and
mutation-test-retargeting, each writing its own JSON artifact. Mirrors
the shaders aggregate pattern. DepthBiasCalculator baseline doc updated
for the renamed target and report path.

Issue #282

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Second mutation target. 100% score (6/6) but every mutant landed in the
safeDivide guard helper — muter v16's four scalar operators generate zero
mutants against simd quaternion/vector math. Verdict: validated not
adopted, lean stop; keep mutation testing as an opt-in spot-check for
scalar-logic-heavy files only.

Issue #282

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@arkavo-com arkavo-com changed the title feat(testing): mutation testing on DepthBiasCalculator (#282) feat(testing): mutation testing on DepthBiasCalculator + retargeting samplers (#282) May 22, 2026
@arkavo-com
arkavo-com marked this pull request as draft May 22, 2026 03:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add mutation testing to validate test-suite effectiveness

1 participant