{"id":48023021,"url":"https://github.com/ioplane/mutaktor","last_synced_at":"2026-04-04T13:48:37.889Z","repository":{"id":345962722,"uuid":"1188029535","full_name":"ioplane/mutaktor","owner":"ioplane","description":"Kotlin-first Gradle plugin for PIT mutation testing — git-aware analysis, Kotlin junk filtering, CI/CD integration","archived":false,"fork":false,"pushed_at":"2026-03-22T00:21:40.000Z","size":500,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-22T05:04:59.099Z","etag":null,"topics":["gradle","gradle-9","gradle-plugin","jdk-25","kotlin","kotlin-dsl","mutation-testing","pit","pitest","testing"],"latest_commit_sha":null,"homepage":"https://github.com/dantte-lp/mutaktor/blob/main/docs/en/README.md","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ioplane.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":"SECURITY.md","support":"SUPPORT.md","governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-21T14:21:28.000Z","updated_at":"2026-03-22T00:21:43.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/ioplane/mutaktor","commit_stats":null,"previous_names":["dantte-lp/mutaktor"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/ioplane/mutaktor","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ioplane%2Fmutaktor","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ioplane%2Fmutaktor/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ioplane%2Fmutaktor/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ioplane%2Fmutaktor/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ioplane","download_url":"https://codeload.github.com/ioplane/mutaktor/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ioplane%2Fmutaktor/sbom","scorecard":{"id":1245113,"data":{"date":"2026-03-22T00:21:55Z","repo":{"name":"github.com/ioplane/mutaktor","commit":"ad4ef16471591cde529f0e9ccc02aa5e7e0838ca"},"scorecard":{"version":"v5.0.0","commit":"ea7e27ed41b76ab879c862fa0ca4cc9c61764ee4"},"score":6.1,"checks":[{"name":"Binary-Artifacts","score":9,"reason":"binaries present in source code","details":["Warn: binary detected: gradle/wrapper/gradle-wrapper.jar:1"],"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/ea7e27ed41b76ab879c862fa0ca4cc9c61764ee4/docs/checks.md#binary-artifacts"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/ea7e27ed41b76ab879c862fa0ca4cc9c61764ee4/docs/checks.md#branch-protection"}},{"name":"CI-Tests","score":6,"reason":"3 out of 5 merged PRs checked by a CI test -- score normalized to 6","details":null,"documentation":{"short":"Determines if the project runs tests before pull requests are merged.","url":"https://github.com/ossf/scorecard/blob/ea7e27ed41b76ab879c862fa0ca4cc9c61764ee4/docs/checks.md#ci-tests"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/ea7e27ed41b76ab879c862fa0ca4cc9c61764ee4/docs/checks.md#cii-best-practices"}},{"name":"Code-Review","score":0,"reason":"Found 0/25 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/ea7e27ed41b76ab879c862fa0ca4cc9c61764ee4/docs/checks.md#code-review"}},{"name":"Contributors","score":0,"reason":"project has 0 contributing companies or organizations -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project has a set of contributors from multiple organizations (e.g., companies).","url":"https://github.com/ossf/scorecard/blob/ea7e27ed41b76ab879c862fa0ca4cc9c61764ee4/docs/checks.md#contributors"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/ea7e27ed41b76ab879c862fa0ca4cc9c61764ee4/docs/checks.md#dangerous-workflow"}},{"name":"Dependency-Update-Tool","score":10,"reason":"update tool detected","details":["Info: detected update tool: Dependabot: .github/dependabot.yml:1"],"documentation":{"short":"Determines if the project uses a dependency update tool.","url":"https://github.com/ossf/scorecard/blob/ea7e27ed41b76ab879c862fa0ca4cc9c61764ee4/docs/checks.md#dependency-update-tool"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/ea7e27ed41b76ab879c862fa0ca4cc9c61764ee4/docs/checks.md#fuzzing"}},{"name":"License","score":9,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Warn: project license file does not contain an FSF or OSI license."],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/ea7e27ed41b76ab879c862fa0ca4cc9c61764ee4/docs/checks.md#license"}},{"name":"Maintained","score":0,"reason":"project was created in last 90 days. please review its contents carefully","details":["Warn: Repository was created in last 90 days."],"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/ea7e27ed41b76ab879c862fa0ca4cc9c61764ee4/docs/checks.md#maintained"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/ea7e27ed41b76ab879c862fa0ca4cc9c61764ee4/docs/checks.md#packaging"}},{"name":"Pinned-Dependencies","score":9,"reason":"dependency not pinned by hash detected -- score normalized to 9","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:64: update your workflow using https://app.stepsecurity.io/secureworkflow/ioplane/mutaktor/ci.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:75: update your workflow using https://app.stepsecurity.io/secureworkflow/ioplane/mutaktor/ci.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scorecard.yml:32: update your workflow using https://app.stepsecurity.io/secureworkflow/ioplane/mutaktor/scorecard.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/security.yml:30: update your workflow using https://app.stepsecurity.io/secureworkflow/ioplane/mutaktor/security.yml/main?enable=pin","Info:  18 out of  22 GitHub-owned GitHubAction dependencies pinned","Info:   7 out of   7 third-party GitHubAction dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/ea7e27ed41b76ab879c862fa0ca4cc9c61764ee4/docs/checks.md#pinned-dependencies"}},{"name":"SAST","score":8,"reason":"SAST tool detected but not run on all commits","details":["Info: SAST configuration detected: CodeQL","Warn: 3 commits out of 5 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/ea7e27ed41b76ab879c862fa0ca4cc9c61764ee4/docs/checks.md#sast"}},{"name":"Security-Policy","score":10,"reason":"security policy file detected","details":["Info: security policy file detected: SECURITY.md:1","Info: Found linked content: SECURITY.md:1","Info: Found disclosure, vulnerability, and/or timelines in security policy: SECURITY.md:1","Info: Found text in security policy: SECURITY.md:1"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/ea7e27ed41b76ab879c862fa0ca4cc9c61764ee4/docs/checks.md#security-policy"}},{"name":"Signed-Releases","score":0,"reason":"Project has not signed or included provenance with any releases.","details":["Warn: release artifact v0.1.0 not signed: https://api.github.com/repos/ioplane/mutaktor/releases/299815722","Warn: release artifact v0.1.0 does not have provenance: https://api.github.com/repos/ioplane/mutaktor/releases/299815722"],"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/ea7e27ed41b76ab879c862fa0ca4cc9c61764ee4/docs/checks.md#signed-releases"}},{"name":"Token-Permissions","score":10,"reason":"GitHub workflow tokens follow principle of least privilege","details":["Warn: jobLevel 'checks' permission set to 'write': .github/workflows/ci.yml:15","Info: jobLevel 'contents' permission set to 'read': .github/workflows/ci.yml:14","Info: jobLevel 'contents' permission set to 'read': .github/workflows/ci.yml:58","Info: jobLevel 'contents' permission set to 'read': .github/workflows/release.yml:13","Info: jobLevel 'contents' permission set to 'read': .github/workflows/release.yml:32","Warn: jobLevel 'contents' permission set to 'write': .github/workflows/release.yml:65","Info: jobLevel 'actions' permission set to 'read': .github/workflows/scorecard.yml:17","Info: jobLevel 'contents' permission set to 'read': .github/workflows/scorecard.yml:14","Info: jobLevel 'contents' permission set to 'read': .github/workflows/security.yml:16","Info: found token with 'none' permissions: .github/workflows/ci.yml:1","Info: found token with 'none' permissions: .github/workflows/release.yml:1","Info: found token with 'none' permissions: .github/workflows/scorecard.yml:1","Info: found token with 'none' permissions: .github/workflows/security.yml:1","Info: topLevel 'contents' permission set to 'read': .github/workflows/sonarcloud.yml:10"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/ea7e27ed41b76ab879c862fa0ca4cc9c61764ee4/docs/checks.md#token-permissions"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/ea7e27ed41b76ab879c862fa0ca4cc9c61764ee4/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2026-03-22T18:19:06.923Z","repository_id":345962722,"created_at":"2026-03-22T18:19:06.923Z","updated_at":"2026-03-22T18:19:06.923Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31402276,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-04T10:20:44.708Z","status":"ssl_error","status_checked_at":"2026-04-04T10:20:06.846Z","response_time":60,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["gradle","gradle-9","gradle-plugin","jdk-25","kotlin","kotlin-dsl","mutation-testing","pit","pitest","testing"],"created_at":"2026-04-04T13:48:37.731Z","updated_at":"2026-04-04T13:48:37.881Z","avatar_url":"https://github.com/ioplane.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cstrong\u003emutaktor\u003c/strong\u003e\u003cbr\u003e\n  Kotlin-first Gradle plugin for PIT mutation testing\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://kotlinlang.org\"\u003e\u003cimg src=\"https://img.shields.io/badge/Kotlin-2.3-7F52FF?style=for-the-badge\u0026logo=kotlin\u0026logoColor=white\" alt=\"Kotlin 2.3\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://gradle.org\"\u003e\u003cimg src=\"https://img.shields.io/badge/Gradle-9.4.1-02303A?style=for-the-badge\u0026logo=gradle\u0026logoColor=white\" alt=\"Gradle 9.4.1\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://pitest.org\"\u003e\u003cimg src=\"https://img.shields.io/badge/PIT-1.23.0-green?style=for-the-badge\" alt=\"PIT 1.23.0\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://openjdk.org\"\u003e\u003cimg src=\"https://img.shields.io/badge/JDK-17%2B-ED8B00?style=for-the-badge\u0026logo=openjdk\u0026logoColor=white\" alt=\"JDK 17+\"\u003e\u003c/a\u003e\n  \u003ca href=\"LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/badge/License-Apache_2.0-blue?style=for-the-badge\" alt=\"Apache 2.0\"\u003e\u003c/a\u003e\n  \u003cbr\u003e\n  \u003ca href=\"https://github.com/ioplane/mutaktor/actions/workflows/ci.yml\"\u003e\u003cimg src=\"https://img.shields.io/github/actions/workflow/status/ioplane/mutaktor/ci.yml?branch=main\u0026style=for-the-badge\u0026label=CI\" alt=\"CI\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://codecov.io/gh/ioplane/mutaktor\"\u003e\u003cimg src=\"https://img.shields.io/codecov/c/github/ioplane/mutaktor?style=for-the-badge\u0026logo=codecov\u0026logoColor=white\" alt=\"Codecov\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://sonarcloud.io/summary/new_code?id=ioplane_mutaktor\"\u003e\u003cimg src=\"https://img.shields.io/sonar/quality_gate/ioplane_mutaktor?server=https%3A%2F%2Fsonarcloud.io\u0026style=for-the-badge\u0026logo=sonarcloud\u0026logoColor=white\" alt=\"Quality Gate\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://scorecard.dev/viewer/?uri=github.com/ioplane/mutaktor\"\u003e\u003cimg src=\"https://img.shields.io/ossf-scorecard/github.com/ioplane/mutaktor?style=for-the-badge\u0026label=OpenSSF\" alt=\"OpenSSF Scorecard\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n---\n\n**mutaktor** is a Kotlin-first Gradle plugin that wraps [PIT](https://pitest.org/) mutation testing with production-grade CI/CD features: git-diff scoped analysis that limits work to changed classes, automatic suppression of Kotlin compiler-generated junk mutations, standardized SARIF 2.1.0 and mutation-testing-elements JSON output, GitHub Checks API inline PR annotations, a configurable quality gate with per-package score ratchet, extreme mutation mode for large codebases, GraalVM/Quarkus JDK auto-detection via Gradle Toolchain, and annotation-driven control — all built on Gradle's Provider API for zero configuration-cache overhead.\n\n---\n\n## What makes mutaktor different?\n\n| Feature | gradle-pitest-plugin | ArcMutate ($) | **mutaktor** |\n|---|---|---|---|\n| Primary language | Groovy DSL | Java (closed source) | **Kotlin DSL** |\n| License | Apache 2.0 | Commercial | **Apache 2.0** |\n| Git-diff scoped analysis | No | Yes (paid) | **Yes** |\n| Kotlin junk-mutation filter | No | Yes (paid) | **Yes** |\n| mutation-testing-elements JSON | Separate plugin | No | **Built-in** |\n| SARIF 2.1.0 (GitHub Code Scanning) | No | No | **Built-in** |\n| GitHub Checks API annotations | No | No | **Built-in** |\n| Extreme mutation mode | No | Yes (paid) | **Yes** |\n| Quality gate (threshold) | Manual | Manual | **Built-in** |\n| Per-package score ratchet | No | No | **Built-in** |\n| GraalVM auto-detect (Toolchain) | No | No | **Built-in** |\n| Annotation control (`@SuppressMutations`) | No | No | **Built-in** |\n| Gradle configuration cache | Retrofit | Unknown | **By design** |\n| External runtime dependencies | None | Closed | **Zero** |\n\n---\n\n## Quick Start\n\n### Kotlin DSL\n\n```kotlin\n// build.gradle.kts\nplugins {\n    kotlin(\"jvm\") version \"2.3.0\"\n    id(\"io.github.ioplane.mutaktor\") version \"0.1.0\"\n}\n\nmutaktor {\n    targetClasses.set(setOf(\"com.example.*\"))\n}\n```\n\n### Groovy DSL\n\n```groovy\n// build.gradle\nplugins {\n    id 'org.jetbrains.kotlin.jvm' version '2.3.0'\n    id 'io.github.ioplane.mutaktor' version '0.1.0'\n}\n\nmutaktor {\n    targetClasses = ['com.example.*']\n}\n```\n\nRun mutation analysis:\n\n```bash\n./gradlew mutate\n```\n\nReports are written to `build/reports/mutaktor/`.\n\n---\n\n## Architecture\n\n```mermaid\ngraph TB\n    subgraph \"Gradle Build\"\n        PLG[\"MutaktorPlugin\\napply()\"]\n        EXT[\"mutaktor { ... }\\nMutaktorExtension\\n25 properties\"]\n        TSK[\"mutate task\\nMutaktorTask\\n@CacheableTask\"]\n        GIT[\"GitDiffAnalyzer\\nchangedClasses()\"]\n        CFG[\"mutaktor config\\nPIT + JUnit5 JARs\"]\n    end\n\n    subgraph \"PIT Process (child JVM)\"\n        PIT[\"PIT CLI\\nMutationCoverageReport\"]\n        FLT[\"KotlinJunkFilter\\nMutationInterceptor SPI\\n5 patterns\"]\n        RPT[\"mutations.xml\\nHTML report\"]\n    end\n\n    subgraph \"Post-processing\"\n        JSON[\"MutationElementsConverter\\nmutation-testing-elements JSON\"]\n        SAR[\"SarifConverter\\nSARIF 2.1.0\"]\n        QG[\"QualityGate\\nscore threshold\"]\n        RTC[\"Ratchet\\nper-package floor\"]\n        GH[\"GithubChecksReporter\\nCheck Run + annotations\"]\n    end\n\n    PLG --\u003e EXT\n    PLG --\u003e TSK\n    PLG --\u003e CFG\n    EXT --\u003e|\"Provider chains\"| TSK\n    GIT --\u003e|\"since → targetClasses\"| TSK\n    CFG --\u003e|\"classpath\"| TSK\n    TSK --\u003e|\"JavaExec\"| PIT\n    FLT --\u003e|\"SPI loaded by PIT\"| PIT\n    PIT --\u003e RPT\n    RPT --\u003e JSON\n    RPT --\u003e SAR\n    RPT --\u003e QG\n    RPT --\u003e RTC\n    QG --\u003e GH\n    SAR --\u003e GH\n\n    style PLG fill:#7F52FF,color:#fff\n    style TSK fill:#02303A,color:#fff\n    style PIT fill:#e37400,color:#fff\n    style GH fill:#181717,color:#fff\n```\n\n---\n\n## Features\n\n### Git-diff scoped analysis\n\nScope mutation to only the classes that changed since a given git ref. On a large codebase this can reduce analysis time from hours to minutes:\n\n```kotlin\nmutaktor {\n    since.set(\"main\")        // branch name\n    // since.set(\"HEAD~5\")   // relative ref\n    // since.set(\"a1b2c3d\")  // commit SHA\n}\n```\n\n`GitDiffAnalyzer` runs `git diff --name-only --diff-filter=ACMR` and maps changed source files to class-name glob patterns that are intersected with `targetClasses`.\n\n### Kotlin junk-mutation filter\n\n`KotlinJunkFilter` implements PIT's `MutationInterceptor` SPI and automatically suppresses mutations in five categories of Kotlin compiler-generated bytecode:\n\n| Category | Why it is junk |\n|---|---|\n| `DefaultImpls` inner classes | Interface default-method adapters — never directly exercised |\n| Coroutine state machine | Compiler-generated `invokeSuspend` switch arms |\n| Data class generated methods | `copy`, `componentN`, `equals`, `hashCode`, `toString` |\n| Intrinsics null-checks | `Intrinsics.checkNotNullParameter` — guaranteed by the type system |\n| `when`-expression hashcode dispatch | Compiler switch on string hashcodes — semantic noise |\n\nEnable (on by default):\n\n```kotlin\nmutaktor {\n    kotlinFilters.set(true)  // default\n}\n```\n\n### Reports\n\n| Format | File | Use case |\n|---|---|---|\n| HTML | `build/reports/mutaktor/index.html` | Human review |\n| XML | `build/reports/mutaktor/mutations.xml` | Machine processing |\n| mutation-testing-elements JSON | `build/reports/mutaktor/mutations.json` | [Stryker Dashboard](https://dashboard.stryker-mutator.io/) |\n| SARIF 2.1.0 | `build/reports/mutaktor/mutations.sarif.json` | GitHub Code Scanning |\n\nConfigure output:\n\n```kotlin\nmutaktor {\n    jsonReport.set(true)      // default: true\n    sarifReport.set(true)     // default: false\n    outputFormats.set(setOf(\"HTML\", \"XML\"))\n}\n```\n\n### Quality gate\n\nFail the build if the mutation score drops below a threshold:\n\n```kotlin\nmutaktor {\n    mutationScoreThreshold.set(80)  // fail if score \u003c 80%\n}\n```\n\nThe quality gate runs in post-processing after PIT completes and reports the precise score to the build log before failing.\n\n### Per-package score ratchet\n\nPrevent regression at the package level. The ratchet reads a baseline file, fails the build if any package score decreases, and optionally auto-updates the baseline when scores improve:\n\n```kotlin\nmutaktor {\n    ratchetEnabled.set(true)\n    ratchetBaseline.set(layout.projectDirectory.file(\".mutaktor-baseline.json\"))\n    ratchetAutoUpdate.set(true)   // update baseline on improvement\n}\n```\n\nCommit `.mutaktor-baseline.json` to version control. The build fails if a package score drops below its baseline value.\n\n### Extreme mutation mode\n\nReplace entire method bodies instead of applying fine-grained bytecode mutations. This generates approximately one mutant per method rather than ten, making mutation testing practical for large codebases:\n\n```kotlin\nmutaktor {\n    extreme.set(true)\n}\n```\n\nExtreme mode is effective for identifying pseudo-tested methods — methods covered by tests that do not assert on behavior.\n\n### GraalVM and Quarkus auto-detection\n\nWhen the build JDK is GraalVM, PIT's minion JVM fails on `jrt://` module paths. Mutaktor integrates with Gradle Toolchain API to automatically resolve a standard JDK for the PIT child process:\n\n```kotlin\nmutaktor {\n    javaLauncher.set(javaToolchains.launcherFor {\n        languageVersion.set(JavaLanguageVersion.of(21))\n        vendor.set(JvmVendorSpec.ADOPTIUM)\n    })\n}\n```\n\n### Annotation-based control\n\nAdd the `mutaktor-annotations` dependency (zero transitive dependencies) to control mutation analysis at the class or method level:\n\n```kotlin\n// build.gradle.kts\ndependencies {\n    implementation(\"io.github.ioplane.mutaktor:mutaktor-annotations:0.1.0\")\n}\n```\n\n```kotlin\nimport io.github.ioplane.mutaktor.annotations.MutationCritical\nimport io.github.ioplane.mutaktor.annotations.SuppressMutations\n\n// Require 100% mutation score — build fails if any mutant survives\n@MutationCritical(reason = \"Core payment validation logic\")\nclass PaymentValidator {\n    fun validate(amount: BigDecimal): ValidationResult { ... }\n}\n\n// Exclude from mutation analysis entirely\n@SuppressMutations(reason = \"Generated serialization code — tested by contract\")\nfun toJson(): String { ... }\n```\n\n### GitHub Checks API\n\nWhen `GITHUB_TOKEN` is available, mutaktor posts a GitHub Check Run with inline annotations for every surviving mutant directly on the pull request diff:\n\n```yaml\n# .github/workflows/ci.yml\n- name: Run mutation tests\n  run: ./gradlew mutate\n  env:\n    GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n```\n\n---\n\n## Multi-module projects\n\nApply the aggregate plugin to the root project and the standard plugin to each subproject:\n\n```kotlin\n// settings.gradle.kts\ninclude(\"core\", \"api\", \"service\")\n\n// build.gradle.kts (root)\nplugins {\n    id(\"io.github.ioplane.mutaktor.aggregate\") version \"0.1.0\"\n}\n\n// core/build.gradle.kts, api/build.gradle.kts, service/build.gradle.kts\nplugins {\n    kotlin(\"jvm\")\n    id(\"io.github.ioplane.mutaktor\") version \"0.1.0\"\n}\n\nmutaktor {\n    targetClasses.set(setOf(\"com.example.${project.name}.*\"))\n}\n```\n\nRun per-module and aggregate:\n\n```bash\n./gradlew mutate              # all subprojects in parallel\n./gradlew mutateAggregate     # combined report across all modules\n```\n\n---\n\n## Configuration reference\n\nAll 25 DSL properties are documented in [`docs/en/02-configuration.md`](docs/en/02-configuration.md). Key properties:\n\n| Property | Type | Default | Description |\n|---|---|---|---|\n| `pitVersion` | `String` | `\"1.23.0\"` | PIT version resolved from Maven Central |\n| `targetClasses` | `Set\u003cString\u003e` | auto-inferred | Glob patterns for classes to mutate |\n| `targetTests` | `Set\u003cString\u003e` | same as `targetClasses` | Glob patterns for test classes |\n| `threads` | `Int` | `availableProcessors()` | Parallel mutation threads |\n| `mutators` | `Set\u003cString\u003e` | `{\"DEFAULTS\"}` | Mutator groups or individual mutator IDs |\n| `since` | `String` | unset | Git ref for diff-scoped analysis |\n| `kotlinFilters` | `Boolean` | `true` | Enable Kotlin junk-mutation filter |\n| `extreme` | `Boolean` | `false` | Extreme mutation mode |\n| `mutationScoreThreshold` | `Int` | unset | Quality gate threshold (0–100) |\n| `ratchetEnabled` | `Boolean` | `false` | Per-package score ratchet |\n| `jsonReport` | `Boolean` | `true` | mutation-testing-elements JSON output |\n| `sarifReport` | `Boolean` | `false` | SARIF 2.1.0 output |\n| `javaLauncher` | `JavaLauncher` | build JDK | Toolchain override for PIT child JVM |\n| `verbose` | `Boolean` | `false` | PIT verbose console output |\n\n---\n\n## Documentation\n\n| Document | Audience | Description |\n|---|---|---|\n| [Getting Started](docs/en/01-getting-started.md) | All users | Installation, first run |\n| [Configuration](docs/en/02-configuration.md) | All users | Complete DSL reference |\n| [Kotlin Filter](docs/en/03-kotlin-filters.md) | Kotlin developers | Junk-mutation suppression internals |\n| [Git-Diff Analysis](docs/en/04-git-integration.md) | CI/CD users | Scoped analysis with `since` |\n| [Reports \u0026 Quality Gate](docs/en/05-reporting.md) | CI/CD users | SARIF, JSON, thresholds, ratchet |\n| [Development Guide](docs/en/06-development.md) | Contributors | Build, test, extend |\n| [CI/CD Integration](docs/en/07-ci-cd.md) | DevOps | GitHub Actions, SARIF upload |\n| [Changelog](docs/en/08-changelog.md) | All | Release history |\n\nRussian documentation is available at [`docs/ru/`](docs/ru/).\n\n---\n\n## Requirements\n\n| | Minimum | Tested |\n|---|---|---|\n| Gradle | 9.0 | 9.4.1 |\n| JDK | 17 | 17, 21, 25 (Temurin) |\n| Kotlin | 1.8 | 2.3.0 |\n| PIT | 1.19.0 | 1.23.0 |\n| pitest-junit5-plugin | 1.1.0 | 1.2.3 |\n\n---\n\n## Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for development setup, code standards, and the pull request process.\n\n## Security\n\nSee [SECURITY.md](SECURITY.md) for the vulnerability reporting process and supported versions.\n\n## Support\n\nSee [SUPPORT.md](SUPPORT.md) for support channels and how to file an effective bug report.\n\n## Code of Conduct\n\nThis project follows the [Contributor Covenant v2.1](CODE_OF_CONDUCT.md).\n\n---\n\n## License\n\nApache License 2.0. See [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fioplane%2Fmutaktor","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fioplane%2Fmutaktor","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fioplane%2Fmutaktor/lists"}