diff --git a/.github/frontend-hot-path-files.txt b/.github/frontend-hot-path-files.txt index 51698e1d..03c4e7b8 100644 --- a/.github/frontend-hot-path-files.txt +++ b/.github/frontend-hot-path-files.txt @@ -3,13 +3,8 @@ # Mirrors `.github/hot-path-files.txt` for the Rust crates. Each entry is a # workspace-relative path; the gate script (`scripts/check-frontend-hot-path- # coverage.sh`) reads `coverage/coverage-summary.json` produced by -# `vitest run --coverage` and warns when a listed file drops below the floor. -# -# Soft today (warnings only — the workflow carries `continue-on-error: true`). -# Flip to a hard PR-blocker by removing `continue-on-error` from the -# `frontend-tests` workflow at the start of M4 in the pre-refactor testing -# plan (2026-05-11), once Phase 1–3 characterization tests have proven the -# gate stable on a handful of real PRs. +# `vitest run --coverage` and fails the frontend-tests coverage job when a +# listed file drops below the floor. # # Curation rule (mirrors the backend list): a file belongs here when its # hot-path code dominates the file and ≥70 % is a reasonable floor. Files diff --git a/.github/hot-path-files.txt b/.github/hot-path-files.txt index 0cb48529..d74a0210 100644 --- a/.github/hot-path-files.txt +++ b/.github/hot-path-files.txt @@ -20,8 +20,7 @@ # # Each line is a path relative to the workspace root (so `src-tauri/...`). # `#` for comments. CI runs cargo-llvm-cov + this gate; PRs that drop -# any listed file below the threshold get a warning annotation today -# and (after watching it run cleanly) eventually a hard fail. +# any listed file below the threshold fail the rust-tests coverage job. # ── psysonic-syncfs ────────────────────────────────────────────────── src-tauri/crates/psysonic-syncfs/src/cache/fs_utils.rs diff --git a/.github/workflows/frontend-tests.yml b/.github/workflows/frontend-tests.yml index 52ae2acf..9482b3c2 100644 --- a/.github/workflows/frontend-tests.yml +++ b/.github/workflows/frontend-tests.yml @@ -61,12 +61,7 @@ jobs: coverage: name: vitest --coverage (baseline + hot-path file gate) - # Two-layer gate: the script exits 1 when any listed file drops below the - # threshold (warning annotations show in the PR checks panel), but - # `continue-on-error: true` keeps it from BLOCKING merges. Drop the flag - # to flip the gate hard once we've watched a few PRs run cleanly. runs-on: ubuntu-24.04 - continue-on-error: true steps: - uses: actions/checkout@v5 - uses: actions/setup-node@v6 @@ -78,7 +73,7 @@ jobs: - run: npm ci - name: vitest run --coverage run: npx vitest run --coverage - - name: hot-path file coverage soft gate + - name: hot-path file coverage gate run: bash scripts/check-frontend-hot-path-coverage.sh - uses: actions/upload-artifact@v4 with: diff --git a/.github/workflows/rust-tests.yml b/.github/workflows/rust-tests.yml index 395d71e6..46707649 100644 --- a/.github/workflows/rust-tests.yml +++ b/.github/workflows/rust-tests.yml @@ -59,13 +59,7 @@ jobs: coverage: name: cargo llvm-cov (baseline + hot-path file gate) - # Layered: the gate script exits 1 when any hot-path file drops below - # threshold (see scripts/check-hot-path-coverage.sh) — the failure is - # visible in the PR's checks panel. `continue-on-error: true` keeps it - # from BLOCKING merges. Drop continue-on-error to flip the gate to a - # PR-blocker once we've watched a few PRs run cleanly. runs-on: ubuntu-24.04 - continue-on-error: true steps: - uses: actions/checkout@v5 - name: install Linux build dependencies @@ -89,7 +83,7 @@ jobs: mkdir -p target/llvm-cov cargo llvm-cov --workspace --lcov --output-path lcov.info cargo llvm-cov --workspace --json --output-path target/llvm-cov/cov.json - - name: hot-path function coverage soft gate + - name: hot-path file coverage gate run: bash scripts/check-hot-path-coverage.sh - uses: actions/upload-artifact@v4 with: diff --git a/CHANGELOG.md b/CHANGELOG.md index a6e50bce..fbd9ec1c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -172,6 +172,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Changed +### CI — hot-path coverage gates block merges + +**By [@cucadmuh](https://github.com/cucadmuh), PR [#921](https://github.com/Psychotoxical/psysonic/pull/921)** + +* Frontend and Rust `coverage` jobs no longer carry `continue-on-error`; listed hot-path files must stay at ≥70% line coverage or the PR fails. + + + ### Linux — session GDK, WebKitGTK mitigations, and Wayland text **By [@cucadmuh](https://github.com/cucadmuh), PR [#731](https://github.com/Psychotoxical/psysonic/pull/731)** diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index bd756569..53880206 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -117,7 +117,7 @@ Workflows are path-filtered (see the YAML for exact `paths` / `paths-ignore`): - **Frontend** (`src/**`, lockfile, Vitest/Vite/tsconfig, etc.): `npm test` (Vitest), `npx tsc --noEmit`, then a coverage run. - **Rust** (`src-tauri/**`): `cargo test --workspace --all-targets`, `cargo clippy --workspace --all-targets -- -D warnings`, then coverage. -Hot-path coverage gates are currently **soft** (warnings only — the workflow carries `continue-on-error: true`). They will be flipped to required when the floors stabilise; see the headers in [`frontend-hot-path-files.txt`](.github/frontend-hot-path-files.txt) and [`hot-path-files.txt`](.github/hot-path-files.txt) for the current state of each list. +Hot-path coverage gates are **required** on pull requests: the `coverage` jobs in [`frontend-tests.yml`](.github/workflows/frontend-tests.yml) and [`rust-tests.yml`](.github/workflows/rust-tests.yml) fail when any listed file drops below the floor. See the headers in [`frontend-hot-path-files.txt`](.github/frontend-hot-path-files.txt) and [`hot-path-files.txt`](.github/hot-path-files.txt) for curation rules and thresholds. --- diff --git a/scripts/check-frontend-hot-path-coverage.sh b/scripts/check-frontend-hot-path-coverage.sh index b9b2aabc..aea68ef7 100755 --- a/scripts/check-frontend-hot-path-coverage.sh +++ b/scripts/check-frontend-hot-path-coverage.sh @@ -1,13 +1,11 @@ #!/usr/bin/env bash # -# Hot-path file coverage gate — frontend, soft mode. +# Hot-path file coverage gate — frontend. # # Mirrors `scripts/check-hot-path-coverage.sh` for the Rust workspace. For # each source file listed in `.github/frontend-hot-path-files.txt`, verifies # that line coverage is at least $THRESHOLD %. Emits GitHub Actions warning -# annotations for files below the floor; exits 1 when any file is below, but -# the wrapping CI job carries `continue-on-error: true` so it doesn't block -# merges yet (drop that flag once we've watched a few PRs run cleanly). +# annotations for files below the floor and exits 1 when any file is below. # # Why files instead of per-function: v8 coverage's per-function data is # fragile under React Compiler / Vite minification — file-level line diff --git a/scripts/check-hot-path-coverage.sh b/scripts/check-hot-path-coverage.sh index 4e3d7491..99e80af5 100644 --- a/scripts/check-hot-path-coverage.sh +++ b/scripts/check-hot-path-coverage.sh @@ -1,11 +1,11 @@ #!/usr/bin/env bash # -# Hot-path file coverage gate — soft mode. +# Hot-path file coverage gate. # # For each source file listed in `.github/hot-path-files.txt`, verifies # that line coverage is at least $THRESHOLD %. Emits GitHub Actions -# warning annotations for files below the floor; never sets a non-zero -# exit code (soft gate). +# warning annotations for files below the floor and exits 1 when any +# file is below. # # Why files instead of per-function: cargo-llvm-cov's per-function # region data is unreliable for async state-machines (most regions live @@ -104,14 +104,6 @@ echo "Checked: $TOTAL hot-path file(s)" echo "Below threshold: $BELOW" echo "Not found: $NOT_FOUND" -# Two-layer gate: -# - This script exits 1 when any hot-path file regresses below the -# threshold. That gives an unambiguous CI signal in the workflow log. -# - The `coverage` job in `.github/workflows/rust-tests.yml` carries -# `continue-on-error: true`, so the failing exit is visible in the -# PR's checks panel but does NOT block merges yet. -# - Flip to a hard PR-blocker by removing `continue-on-error` from the -# workflow once we've watched a few PRs run cleanly. if [[ "$BELOW" -gt 0 ]]; then exit 1 fi diff --git a/src/test/README.md b/src/test/README.md index 70e0da4b..b82a9d5f 100644 --- a/src/test/README.md +++ b/src/test/README.md @@ -207,9 +207,9 @@ wrappers when the hook reads from a provider. hot-path gate consumes. - `.github/frontend-hot-path-files.txt` lists the files held to ≥70% line coverage by `scripts/check-frontend-hot-path-coverage.sh`. -- CI runs both. The gate is soft today (`continue-on-error: true`) — - it flips to a hard PR-blocker at the start of M4 in the pre-refactor - testing plan. Mirrors the backend rust-tests rollout. +- CI runs both. The gate is a **required PR check** — the `coverage` job in + `frontend-tests` fails when any listed file drops below the floor. Mirrors + the backend rust-tests rollout. ## Process isolation