diff --git a/docs/developers-guide.md b/docs/developers-guide.md index 1e92900b..47d86a49 100644 --- a/docs/developers-guide.md +++ b/docs/developers-guide.md @@ -80,6 +80,66 @@ If a workflow's behaviour genuinely depends on a feature only present from a particular commit onwards, express that as a comment or a changelog note, not as a test assertion on the SHA string. +## Mutation-testing workflow contract tests + +This repository runs scheduled, informational mutation testing through a thin +caller workflow, +[`.github/workflows/mutation-testing.yml`](../.github/workflows/mutation-testing.yml), +which delegates to the shared reusable workflow +`leynos/shared-actions/.github/workflows/mutation-cargo.yml`. The heavy lifting +— running `cargo-mutants`, sharding, and summarizing survivors — lives in +`shared-actions`; this repository carries only declarative configuration. The +run is **informational only**: it never gates a pull request. Survivors are +reported through the job summary and downloadable artefacts so they can be +triaged into tests, not enforced as a blocking check. + +The workflow runs in two modes. A **daily schedule** fires a change-scoped run +that mutates only the source files touched within the detection window, so +quiet days are cheap no-ops. A **manual dispatch** (the Actions "Run workflow" +control) mutates the whole workspace, fanned out across shards; select a +branch in that control to exercise a feature branch. + +The caller passes a small set of configuration inputs, each carrying intent: + +- `paths` — the change-detection globs that decide whether a scheduled run has + anything to mutate; here `crates/`, because every workspace crate lives + under that directory and there is no root `src/`. +- `exclude-globs` — test infrastructure whose surviving mutants are noise + rather than genuine test gaps: the end-to-end harness crate + (`weaver-e2e`), the proc-macro fixture helpers (`weaver-test-macros`), and + the feature-gated `test_support` modules in `sempai-core` and + `weaver-plugins`. +- `extra-args` — `--all-features --test-workspace=true`, so the mutation run + matches the CI baseline (`make test` runs `--all-features` across the whole + workspace): feature-gated code is exercised, and each crate's mutants also + face the dependent crates' tests, avoiding false survivors in crates that + are only covered by a sibling crate's suite. + +The `uses:` reference pins the shared workflow to a full 40-character commit +SHA rather than a branch or tag, so a force-push upstream cannot silently +change what runs here. The contract test asserts only that the pin is a full +commit SHA, not a particular value, so Dependabot bumps it automatically +without any accompanying test edit, per the shape-only policy described +above. + +Because the caller is configuration rather than code, a contract test in +`tests/workflow_contracts/mutation_testing_test.py` pins the shape it must +uphold, failing the pull request when the caller drifts — repointing the pin +at a branch, widening the token scope, or dropping a configuration input — +rather than letting the breakage surface only in a scheduled run. Run it +locally with `make test-workflow-contracts`. The test validates: + +- the `uses:` reference targets `mutation-cargo.yml` pinned to a full commit + SHA; +- the `with:` block is exactly the expected configuration (the workspace + path, scaffolding excludes, and feature-baseline arguments above); +- job permissions are least-privilege (`contents: read`, `id-token: write`) + and the workflow-level default token scope is empty; +- `concurrency` serializes runs per ref without cancelling one in progress; + and +- the triggers keep the daily schedule and a plain `workflow_dispatch` with + no legacy branch input. + ## Adding or renaming public commands ADR 007 makes the 0.1.0 public command surface resource-first and generated