feat(hash): three-tier identity + Tier-0 cache + on-demand canonical hash (closes #151 #155, advances #157) #3
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
| # cargo-mutants per-PR mutation testing — Linux-only, observability-only. | |
| # See spec: docs/superpowers/specs/2026-04-24-cargo-mutants-design.md | |
| # | |
| # WHY a separate workflow (not added to ci.yml's matrix): mutation | |
| # testing is CPU-heavy + slow (minutes per file); decoupling lets it | |
| # fail-or-skip independently of the main `just ci` matrix. PR contributors | |
| # see two checks instead of one. Failure of mutants.yml does NOT block | |
| # merge during slice 1 (continue-on-error swallows non-zero exit). | |
| name: mutants | |
| # WHY workflow_dispatch added (2026-04-25): allows on-demand "real deal" | |
| # workspace-wide mutation runs (no --in-diff filter) — much longer than | |
| # per-PR mode (HOURS, not 1-2 minutes). The per-PR `pull_request:` trigger | |
| # stays as-is; the run-step branches on github.event_name to choose mode. | |
| on: | |
| pull_request: | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| env: | |
| CARGO_TERM_COLOR: always | |
| jobs: | |
| mutants: | |
| name: cargo mutants | |
| runs-on: ubuntu-latest | |
| # WHY no `if:` gate: both pull_request AND workflow_dispatch run the job; | |
| # the run-step itself branches on github.event_name to pick --in-diff vs | |
| # workspace-wide mode. Adding an event-name gate here would skip | |
| # workflow_dispatch entirely (the prior `== 'pull_request'` was a leftover | |
| # from PR-only-mode and would now block manual runs). | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| # WHY fetch-depth: 0 — `git diff origin/<base>..` requires the | |
| # base branch in local history; depth 0 fetches the full graph. | |
| fetch-depth: 0 | |
| - uses: dtolnay/rust-toolchain@stable | |
| - uses: Swatinem/rust-cache@v2 | |
| # WHY taiki-e/install-action (NOT cargo-binstall): this workflow | |
| # runs on ubuntu-latest only; the BASH_FUNC_* leak that broke | |
| # taiki-e/install-action on windows-latest (GH #137) does NOT | |
| # affect Linux. Multi-tool comma syntax fetches both binaries in | |
| # one step. | |
| - uses: taiki-e/install-action@v2 | |
| with: | |
| tool: cargo-mutants,cargo-nextest | |
| # WHY Tauri Linux deps even though crates/desktop is excluded from | |
| # mutation: `cargo metadata` (which cargo-mutants invokes | |
| # internally) resolves the WHOLE workspace including | |
| # perima-desktop's transitive deps. Without GTK headers, metadata | |
| # resolution fails before any mutation happens. | |
| - name: Install Tauri Linux deps | |
| run: | | |
| sudo apt-get update -q | |
| sudo apt-get install -yq \ | |
| libgtk-3-dev \ | |
| libwebkit2gtk-4.1-dev \ | |
| libayatana-appindicator3-dev \ | |
| librsvg2-dev \ | |
| patchelf | |
| # WHY `| tee git.diff` (vs `> git.diff`): tee echoes the diff into | |
| # the CI log so reviewers can see what cargo-mutants will operate | |
| # on without downloading the artifact. Matches the canonical | |
| # mutants.rs/in-diff example. | |
| # | |
| # WHY only on pull_request: workflow_dispatch has no base branch to | |
| # diff against; the run-step's workspace mode skips this file. | |
| - name: Compute diff against base branch | |
| if: github.event_name == 'pull_request' | |
| run: git diff origin/${{ github.base_ref }}.. | tee git.diff | |
| # WHY continue-on-error: per spec D-4, observability-only mode. | |
| # cargo-mutants exits 2 when mutants survive, 3 on timeout, 4 on | |
| # baseline failure. Without continue-on-error the very first PR | |
| # (or workspace run) with a survivor blocks the workflow + defeats | |
| # the observability-first calibration goal. Precedent: kani.yml | |
| # uses the same pattern. | |
| # | |
| # WHY branch on event_name: pull_request → --in-diff mode (fast, | |
| # mutates only changed code per spec slice 1 D-2). workflow_dispatch | |
| # → workspace-wide (HOURS, baseline-collection mode). Same workflow | |
| # file serves both cadences. | |
| - name: cargo mutants | |
| continue-on-error: true | |
| run: | | |
| if [ "${{ github.event_name }}" = "pull_request" ]; then | |
| cargo mutants --no-shuffle -vV --in-diff git.diff | |
| else | |
| cargo mutants --no-shuffle -vV | |
| fi | |
| - name: Upload mutants.out | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: mutants-out | |
| path: mutants.out |