Files
OmniRoute/.github/workflows/nightly-mutation.yml
Diego Rodrigues de Sa e Souza 34bde609ae chore(quality): close v3.8.28 cycle gate drift (re-baseline + nightly-mutation scope) (#4135)
* chore(quality): re-baseline v3.8.28 cycle drift (eslint/openapi/i18n)

The post-release push->main Quality Ratchet (run 27725117464) failed on 3
metrics that drifted during the v3.8.28 cycle from legitimate feature merges:
eslintWarnings 3769->3779, openapiCoverage.pct 38.3->37.6, i18nUiCoverage.pct
80.1->79.1. Reproduced locally on release/v3.8.29 (9f14c1294) — identical to CI.

None is hand-cleanable without gaming or unavailable infra:
- eslint +10: no-explicit-any is warn-level and allowed in tests (the drift is
  test `any`), plus 4 react-hooks/exhaustive-deps in RequestLoggerV2.tsx (a
  refresh-sensitive component — touching hook deps without UI tests is risky).
- openapi -0.7: the drop is from new INTERNAL routes (/api/tools/agent-bridge/*,
  LOCAL_ONLY) — documenting them in the public spec would game the metric.
- i18n -1.0: 37/41 locales need ~3000 translations via `npm run i18n:run`, which
  requires OMNIROUTE_TRANSLATION_API_KEY (not available locally).

Re-baselined to the real measured values per the documented v3.8.26 precedent
(_eslint_rebaseline_2026_06_16_v3826_forward_merge). Tighten at cycle end:
eslint/openapi via --require-tighten; i18n via i18n:run with creds.

* ci(mutation): scope nightly to 6 modules to fit the 180min budget

The full 8-module Stryker run timed out at the 180min nightly cap (run
27705123780: 16:47:33 -> 19:47:48 = exactly 180min; the prior 120min scheduled
run also timed out). #4078's DATA_DIR isolation made concurrency=4 safe but not
sufficient: the tap-runner re-spawns a node process per test file per mutant, so
spawn cost dominates and the two god-files chatCore.ts (5874 LOC) + combo.ts
(5282 LOC) — ~2/3 of the ~15k mutants — do not fit.

Removed both god-files from stryker.conf.json `mutate`. The 6 smaller modules fit
the budget and produce real mutation scores now; the god-files regain coverage
after the Onda 3 split into smaller units. Updated the nightly job name/comments
(8->6 modules). Removing entries from `mutate` does not affect the dry-run
baseline (it runs tap.testFiles, unchanged), so the all-green baseline is preserved.
2026-06-18 00:19:36 -03:00

54 lines
2.0 KiB
YAML

name: Nightly Mutation
on:
schedule:
- cron: "17 3 * * *"
workflow_dispatch:
permissions:
contents: read
jobs:
stryker:
name: Stryker mutation testing (6 critical modules — advisory)
runs-on: ubuntu-latest
# Mutation testing is expensive (~5k mutants across 6 modules). It runs only
# on the nightly schedule / manual dispatch, never on PRs. The score is NOT
# yet enforced as a ratchet (wired in a later INT phase) — for now the job
# just produces the HTML/JSON report and uploads it as an artifact.
#
# Runs at stryker concurrency=4 (was 1) now that ./tests/_setup/isolateDataDir.ts
# gives each test process its own DATA_DIR. The full 8-module set still TIMED OUT
# at the 180min cap (run 27705123780 = exactly 180min), because the two god-files
# chatCore.ts/combo.ts dominate ~2/3 of the mutants; they were removed from
# stryker.conf.json `mutate` until the Onda 3 split (see _mutate_godfiles_excluded_comment
# there). The remaining 6 modules fit the budget. 180min leaves cold-run headroom
# before the incremental cache is seeded.
timeout-minutes: 180
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- uses: actions/setup-node@v6
with:
node-version: "24"
cache: npm
- run: npm ci
- name: Restore Stryker incremental cache
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: reports/mutation/stryker-incremental.json
key: stryker-incremental-${{ github.run_id }}
restore-keys: stryker-incremental-
- name: Run Stryker (advisory)
id: stryker
continue-on-error: true
run: npx stryker run
- name: Upload mutation report
if: always()
uses: actions/upload-artifact@v7
with:
name: mutation-report
path: reports/mutation/
if-no-files-found: warn
retention-days: 14