See docs/DISCLAIMER_SNIPPET.md
CI Workflow
The repository uses two distinct CI surfaces:
- ✅ PR CI (
.github/workflows/pr-ci.yml) — canonical pull-request gate. - 🚀 Integration CI — Insight Demo (
.github/workflows/ci.yml) — full matrix for integration/release confidence.
Triggers
✅ PR CI (canonical PR gate)
pull_requesttargetingmainpushtomainmerge_groupworkflow_dispatch
Jobs:
- Lint (ruff)
- Smoke tests
🚀 Integration CI — Insight Demo (non-PR heavy matrix)
pushtomain- release tags:
v*,release-* workflow_dispatch
This workflow intentionally does not run on pull_request or merge_group.
On push to main, it runs the full non-release integration surface (actionlint, lint/type matrix, pytest matrix, Insight ESLint, Windows/macOS smoke, MkDocs, Docs Build, Docker build validation, branch-protection guardrails).
On tags/manual dispatch it additionally runs release-only publish/sign/deploy path checks.
Mutation testing in ci.yml is config-driven: the workflow always runs mutmut run and relies on [tool.mutmut] in pyproject.toml (no legacy --paths-to-mutate/--runner flags) so mutmut CLI changes do not break merge runs. For merge safety the mutmut scope is intentionally bounded to scripts/mutation_smoke_target.py, uses explicit pytest test-selection fields, mutates covered lines only, and runs under a 20-minute timeout guard. The merge surface pins mutmut==3.3.0 via requirements-dev.lock, and tests assert the lock pin and merge-safe config contract remain intact.
The Semgrep pre-commit hook is pinned with an explicit setuptools additional dependency so Python 3.12 hook environments still provide pkg_resources for the OpenTelemetry import path used by Semgrep.
The merge-surface pytest/docs jobs and other merge validators enforce an npm cache lifecycle contract: when actions/setup-node uses cache: npm with NPM_CONFIG_CACHE, the directory is created before setup-node and is not removed later in the job so setup-node's post-step cache save always has a valid, populated path.
All merge-surface Python validation jobs (Ruff + Mypy, Pytest, MkDocs, and Docs Build) install a shared baseline via scripts/ci_install_python_baseline.sh (requirements.lock + requirements-dev.lock) before job-specific setup (--include-backend-lock or --include-docs-lock) and before check_env.py --auto-install, so 3.11/3.12 environments resolve the same dependency contract.
The merge-surface Ruff step now resolves tracked Python targets via scripts/ruff_targets.py --run, preventing Git metadata paths (for example .git/refs/...) from entering lint scope by construction.
Branch protection (required checks)
Configure main branch protection with these required checks:
Lint (ruff)Smoke tests
Keep Require branches to be up to date enabled.
Validate/enforce with:
python scripts/verify_branch_protection.py --apply --branch main
CI health
The 🩺 CI Health workflow hard-monitors pr-ci.yml (required PR gate) and hard-monitors ci.yml for merge-surface contexts. Scheduled/manual runs enforce both workflows on the policy branch, while workflow_run executions evaluate the triggering upstream workflow and remain rerun-only (--rerun-failed) to avoid redundant dispatches when a concrete upstream run already exists. Self-monitoring is opt-in via --include-self, and workflow-run executions keep reruns enabled so Repo-Healer can move past run-attempt-1 report-only triage when failures persist.
scripts/check_ci_status.py also enforces this policy directly: when GITHUB_EVENT_NAME=workflow_run, --dispatch-missing is ignored so watchdog reruns never fan out into unrelated workflow dispatches.
Use:
python scripts/check_ci_status.py --wait-minutes 5 --pending-grace-minutes 45 --stale-minutes 90
# optional: add --dispatch-failed for explicit failed-run redispatches
After editing workflow files, run:
python tools/update_actions.py
pre-commit run --files .github/workflows/ci.yml .github/workflows/pr-ci.yml .github/workflows/ci-health.yml
GitHub Actions runtime hygiene (Node 20 deprecation)
Workflow actions are pinned to Node24-compatible releases where currently available. A small number of third-party
actions still publish Node20 runtimes upstream (for example softprops/action-gh-release@v2.6.1), so those remain
pinned with explicit version comments until maintainers publish Node24 builds.