Code Quality Gate
Overview
Wraps cqa-analyzer — an offline
static analyzer where no source leaves the machine — and converts its findings
into one decision: did this diff introduce new issues on the lines it
touched? Built for the pre-PR moment and for CI, where you need a
deterministic yes/no plus a short, actionable finding list, not a wall of JSON.
The analyzer deliberately never invokes git, so it cannot know what changed.
This skill supplies the missing piece: scripts/changed_lines_manifest.py
turns a git diff into the changed-lines manifest the analyzer accepts, and
scripts/run-gate.sh drives the whole flow with the correct flags.
Usage
Use this skill when:
- Preparing a PR and you want a quality read on the diff before reviewers see it.
- Wiring a
pre-commit hook or a CI step that must fail the build only on new issues.
- The analyzer emitted JSON/SARIF and you need it triaged into "must-fix vs. accept".
- The user mentions code quality, cyclomatic complexity, changed-line gating, baselines, or SARIF.
Do not use it for runtime profiling or security-vulnerability scanning — it is a
static quality gate, not a SAST or APM tool.
Core Concepts
- Changed-line gate. Findings are intersected with the lines the diff touched.
A pre-existing issue on an untouched line does not fail the gate; a new one does.
This is what makes it safe to drop into CI on a legacy repository.
- Baseline + new-findings-only. On a legacy repo, record today's findings once
(
--write-baseline), then gate only findings absent from that baseline. The
analyzer hashes fingerprints, so the baseline contains no source text.
- Offline and deterministic. Same input → same output, no network. The wrapper
always passes
--offline, which makes the analyzer deny socket operations while
it runs. A green local run predicts a green CI run.
- Two machine formats.
json for caches and dashboards, sarif (2.1.0) for
code-host annotations on the changed lines. text for humans.
- Configuration is pinned outside the tree being gated. A pull request could
otherwise edit
.code-quality.toml to disable a rule or exclude a path and
pass the gate. --config <file> (use a file the PR cannot touch),
--no-project-config (defaults only), or --expect-config-fingerprint <sha256>
(analyzer exits 6 before scanning if the effective config differs) close that
hole. Read the fingerprint once from configuration_fingerprint in a trusted
JSON run and commit it to CI config.
- Analysis health. Every run reports what it could and could not analyze
(
analysis_health in JSON). Zero findings with parse failures means the scan was
blind, not clean — --strict turns that into a non-zero exit.
Quick Reference
pipx install cqa-analyzer # or: pip install cqa-analyzer
# One-time on a legacy repo: record the accepted floor (no gate)
scripts/run-gate.sh --write-baseline .code-quality-baseline.json
# Gate a branch: only NEW warning+ findings on CHANGED lines can fail (exit 4)
scripts/run-gate.sh --base origin/main --baseline .code-quality-baseline.json --format sarif > results.sarif
# Pre-commit: gate the lines you are about to commit
scripts/run-gate.sh --staged --baseline .code-quality-baseline.json
# Clean repo (no legacy debt): gate every changed-line finding, be strict about scan health
scripts/run-gate.sh --base origin/main --strict
# CI-hardened: the PR cannot weaken the gate by editing the repo's own config
scripts/run-gate.sh --base origin/main --baseline .code-quality-baseline.json \
--expect-config-fingerprint "$CQA_CONFIG_FINGERPRINT" --strict --format sarif > results.sarif
| Wrapper flag |
Analyzer flags it drives |
Meaning |
--base <ref> |
--changed-lines-manifest (generated from git diff <ref>...HEAD) |
Gate only lines changed since the merge-base |
--staged |
--changed-lines-manifest (from git diff --cached) |
Gate staged lines (pre-commit) |
--baseline <file> |
--baseline <file> --new-findings-only |
Ignore findings already in the accepted floor |
--write-baseline <file> |
--write-baseline <file> |
Record the floor; no gate |
--format json|sarif|text |
--output-format |
Machine cache / code-host annotations / human |
--fail-on warning|error |
--fail-on |
Severity that fails the gate (default warning) |
--strict |
--strict |
Non-zero exit if any requested analysis could not run |
--config <file> |
--config |
Use this config; ignore the repo's .code-quality.toml |
--no-project-config |
--no-project-config |
Analyzer defaults only |
--expect-config-fingerprint <sha256> |
--expect-config-fingerprint |
Exit 6 before scanning if the effective config differs |
--report-only |
(drops --fail-on) |
Always exit 0. Prints a loud warning. |
CQA_CMD=/abs/path |
— |
Pin the analyzer binary; must be absolute (PATH-hijack guard) |
Exit codes: 0 clean · 4 gate failed · 6 config fingerprint mismatch (both
the analyzer's own) · 2 usage error · 3 environment error (missing analyzer,
missing baseline) from the wrapper. --report-only remaps only 4; a 6 still fails.
Pre-PR Gate Checklist
Gate Progress:
- [ ] cqa-analyzer installed (or CQA_CMD set to an absolute path)
- [ ] Baseline exists (legacy repo) — or repo is clean and no baseline is needed
- [ ] In CI: config pinned (--expect-config-fingerprint or --config outside the tree)
- [ ] Ran: scripts/run-gate.sh --base origin/main [--baseline ...]
- [ ] analysis_health shows 0 parse failures (else the result is not trustworthy)
- [ ] Reviewed must-fix findings on changed lines
- [ ] SARIF uploaded if annotating the PR
Integration Patterns
- Pre-commit: a
.pre-commit-hooks.yaml entry calling
scripts/run-gate.sh --staged --baseline .code-quality-baseline.json blocks
the commit before it reaches a PR.
- GitHub Actions: run with
--format sarif > results.sarif and upload with
github/codeql-action/upload-sarif so findings annotate the changed lines.
Fetch enough history for the merge-base (fetch-depth: 0) and pin the config
with --expect-config-fingerprint from a repository variable, so a PR cannot
turn the gate off by editing .code-quality.toml.
- Agent-driven PR prep: the agent runs the gate with
--format json, reads
the selected findings, and reports the must-fix list to the user before
opening the PR.
See references/output-contracts.md for the JSON/SARIF field shapes and
references/changed-lines-manifest.md for the manifest schema the generator emits.
Common Mistakes
- With
--report-only you MUST lead with the warning the wrapper prints:
REPORT ONLY: this run exits 0 and will not block the build even when findings
exist. Do not bury it in exit-code details.
- You MUST NOT gate a legacy repo without a baseline, because the first CI run
drowns in pre-existing findings and the team disables the gate. Write a
baseline once, then gate with
--baseline.
- You MUST check
analysis_health before trusting an empty result; zero
findings with N parse failures means the scan was blind, not clean.
- You MUST NOT feed JSON to a code host expecting inline annotations; hosts
annotate from SARIF. JSON is for caches and dashboards.
- You MUST NOT run an unpinned gate in CI on a repository where pull requests
can edit
.code-quality.toml; the gate is then advisory, not a gate.
- You MUST NOT claim a scan ran if the analyzer was not found. The wrapper
exits 3 with an install hint; relay that, never fabricate findings.
1---2name: code-quality-gate3description: Use when preparing a pull request and you want a quality read on the diff, wiring a pre-commit hook or CI step that must fail only on NEW issues, triaging analyzer JSON/SARIF findings, or the user mentions code quality, complexity, changed-line gating, baselines, or SARIF. Runs the privacy-first offline analyzer cqa-analyzer (Python, Go, TypeScript/JS, Java, Kotlin, C#, C/C++, and an experimental Rust pilot) and turns findings into a deterministic pass/fail gate scoped to the lines you changed.4license: MIT5---67# Code Quality Gate89## Overview1011Wraps [`cqa-analyzer`](https://pypi.org/project/cqa-analyzer/) — an offline12static analyzer where no source leaves the machine — and converts its findings13into one decision: **did this diff introduce new issues on the lines it14touched?** Built for the pre-PR moment and for CI, where you need a15deterministic yes/no plus a short, actionable finding list, not a wall of JSON.1617The analyzer deliberately never invokes git, so it cannot know what changed.18This skill supplies the missing piece: `scripts/changed_lines_manifest.py`19turns a git diff into the changed-lines manifest the analyzer accepts, and20`scripts/run-gate.sh` drives the whole flow with the correct flags.2122## Usage2324Use this skill when:2526- Preparing a PR and you want a quality read on the diff before reviewers see it.27- Wiring a `pre-commit` hook or a CI step that must **fail the build** only on new issues.28- The analyzer emitted JSON/SARIF and you need it triaged into "must-fix vs. accept".29- The user mentions code quality, cyclomatic complexity, changed-line gating, baselines, or SARIF.3031Do **not** use it for runtime profiling or security-vulnerability scanning — it is a32static quality gate, not a SAST or APM tool.3334## Core Concepts3536- **Changed-line gate.** Findings are intersected with the lines the diff touched.37 A pre-existing issue on an untouched line does not fail the gate; a new one does.38 This is what makes it safe to drop into CI on a legacy repository.39- **Baseline + new-findings-only.** On a legacy repo, record today's findings once40 (`--write-baseline`), then gate only findings absent from that baseline. The41 analyzer hashes fingerprints, so the baseline contains no source text.42- **Offline and deterministic.** Same input → same output, no network. The wrapper43 always passes `--offline`, which makes the analyzer deny socket operations while44 it runs. A green local run predicts a green CI run.45- **Two machine formats.** `json` for caches and dashboards, `sarif` (2.1.0) for46 code-host annotations on the changed lines. `text` for humans.47- **Configuration is pinned outside the tree being gated.** A pull request could48 otherwise edit `.code-quality.toml` to disable a rule or exclude a path and49 pass the gate. `--config <file>` (use a file the PR cannot touch),50 `--no-project-config` (defaults only), or `--expect-config-fingerprint <sha256>`51 (analyzer exits 6 before scanning if the effective config differs) close that52 hole. Read the fingerprint once from `configuration_fingerprint` in a trusted53 JSON run and commit it to CI config.54- **Analysis health.** Every run reports what it could and could not analyze55 (`analysis_health` in JSON). Zero findings with parse failures means the scan was56 blind, not clean — `--strict` turns that into a non-zero exit.5758## Quick Reference5960```bash61pipx install cqa-analyzer # or: pip install cqa-analyzer6263# One-time on a legacy repo: record the accepted floor (no gate)64scripts/run-gate.sh --write-baseline .code-quality-baseline.json6566# Gate a branch: only NEW warning+ findings on CHANGED lines can fail (exit 4)67scripts/run-gate.sh --base origin/main --baseline .code-quality-baseline.json --format sarif > results.sarif6869# Pre-commit: gate the lines you are about to commit70scripts/run-gate.sh --staged --baseline .code-quality-baseline.json7172# Clean repo (no legacy debt): gate every changed-line finding, be strict about scan health73scripts/run-gate.sh --base origin/main --strict7475# CI-hardened: the PR cannot weaken the gate by editing the repo's own config76scripts/run-gate.sh --base origin/main --baseline .code-quality-baseline.json \77 --expect-config-fingerprint "$CQA_CONFIG_FINGERPRINT" --strict --format sarif > results.sarif78```7980| Wrapper flag | Analyzer flags it drives | Meaning |81|---|---|---|82| `--base <ref>` | `--changed-lines-manifest` (generated from `git diff <ref>...HEAD`) | Gate only lines changed since the merge-base |83| `--staged` | `--changed-lines-manifest` (from `git diff --cached`) | Gate staged lines (pre-commit) |84| `--baseline <file>` | `--baseline <file> --new-findings-only` | Ignore findings already in the accepted floor |85| `--write-baseline <file>` | `--write-baseline <file>` | Record the floor; no gate |86| `--format json\|sarif\|text` | `--output-format` | Machine cache / code-host annotations / human |87| `--fail-on warning\|error` | `--fail-on` | Severity that fails the gate (default `warning`) |88| `--strict` | `--strict` | Non-zero exit if any requested analysis could not run |89| `--config <file>` | `--config` | Use this config; ignore the repo's `.code-quality.toml` |90| `--no-project-config` | `--no-project-config` | Analyzer defaults only |91| `--expect-config-fingerprint <sha256>` | `--expect-config-fingerprint` | Exit 6 before scanning if the effective config differs |92| `--report-only` | (drops `--fail-on`) | Always exit 0. Prints a loud warning. |93| `CQA_CMD=/abs/path` | — | Pin the analyzer binary; must be absolute (PATH-hijack guard) |9495Exit codes: `0` clean · `4` gate failed · `6` config fingerprint mismatch (both96the analyzer's own) · `2` usage error · `3` environment error (missing analyzer,97missing baseline) from the wrapper. `--report-only` remaps only `4`; a `6` still fails.9899## Pre-PR Gate Checklist100101```102Gate Progress:103- [ ] cqa-analyzer installed (or CQA_CMD set to an absolute path)104- [ ] Baseline exists (legacy repo) — or repo is clean and no baseline is needed105- [ ] In CI: config pinned (--expect-config-fingerprint or --config outside the tree)106- [ ] Ran: scripts/run-gate.sh --base origin/main [--baseline ...]107- [ ] analysis_health shows 0 parse failures (else the result is not trustworthy)108- [ ] Reviewed must-fix findings on changed lines109- [ ] SARIF uploaded if annotating the PR110```111112## Integration Patterns113114- **Pre-commit:** a `.pre-commit-hooks.yaml` entry calling115 `scripts/run-gate.sh --staged --baseline .code-quality-baseline.json` blocks116 the commit before it reaches a PR.117- **GitHub Actions:** run with `--format sarif > results.sarif` and upload with118 `github/codeql-action/upload-sarif` so findings annotate the changed lines.119 Fetch enough history for the merge-base (`fetch-depth: 0`) and pin the config120 with `--expect-config-fingerprint` from a repository variable, so a PR cannot121 turn the gate off by editing `.code-quality.toml`.122- **Agent-driven PR prep:** the agent runs the gate with `--format json`, reads123 the selected findings, and reports the must-fix list to the user before124 opening the PR.125126See `references/output-contracts.md` for the JSON/SARIF field shapes and127`references/changed-lines-manifest.md` for the manifest schema the generator emits.128129## Common Mistakes130131- With `--report-only` you **MUST** lead with the warning the wrapper prints:132 **REPORT ONLY: this run exits 0 and will not block the build even when findings133 exist.** Do not bury it in exit-code details.134- You **MUST NOT** gate a legacy repo without a baseline, because the first CI run135 drowns in pre-existing findings and the team disables the gate. Write a136 baseline once, then gate with `--baseline`.137- You **MUST** check `analysis_health` before trusting an empty result; zero138 findings with N parse failures means the scan was blind, not clean.139- You **MUST NOT** feed JSON to a code host expecting inline annotations; hosts140 annotate from SARIF. JSON is for caches and dashboards.141- You **MUST NOT** run an unpinned gate in CI on a repository where pull requests142 can edit `.code-quality.toml`; the gate is then advisory, not a gate.143- You **MUST NOT** claim a scan ran if the analyzer was not found. The wrapper144 exits 3 with an install hint; relay that, never fabricate findings.