Skip to content

chore(rustqual): Add structural quality gate - #1190

Open
JeanMertz wants to merge 4 commits into
mainfrom
rustqual
Open

JeanMertz wants to merge 4 commits into
mainfrom
rustqual

Conversation

@JeanMertz

Copy link
Copy Markdown
Collaborator

just qual runs rustqual across the workspace and just qual-ci gates CI on it, failing when a change adds findings beyond the committed baselines. The bar for new code is "no worse than what is already there" rather than an absolute score: the workspace carries known findings, and a score target would push contributors toward suppressing rather than fixing.

The check runs as two passes because rustqual's DRY dimension is all-or-nothing. Disabling [duplicates] also disables DRY-002 dead code and DRY-006 dead types, while leaving it on fires DRY-003 roughly 2038 times inside *_tests.rs, on the repeated setup blocks that keep each #[test] self-contained. .config/rustqual/config.toml therefore covers every dimension except DRY across the full workspace, and dry.toml covers DRY over production code only. Excluding test files from that second pass costs nothing: DRY-002 already ignores calls from #[cfg(test)] code, so the dead-code count is identical with and without them.

Three qual:allow(complexity, magic_numbers) markers cover the provider model catalogues in jp_llm, where context windows, output limits and cutoff dates are data maintained against each provider's published documentation rather than constants worth naming. They cut the main pass from 498 magic-number findings to 193.

Refresh the baselines with just qual-baseline after a change that deliberately moves the count, and commit the result alongside it so the diff shows what moved.

`just qual` runs rustqual across the workspace and `just qual-ci`
gates CI on it, failing when a change adds findings beyond the
committed baselines. The bar for new code is "no worse than what is
already there" rather than an absolute score: the workspace carries
known findings, and a score target would push contributors toward
suppressing rather than fixing.

The check runs as two passes because rustqual's DRY dimension is
all-or-nothing. Disabling `[duplicates]` also disables DRY-002 dead
code and DRY-006 dead types, while leaving it on fires DRY-003
roughly 2038 times inside `*_tests.rs`, on the repeated setup blocks
that keep each `#[test]` self-contained. `.config/rustqual/config.toml`
therefore covers every dimension except DRY across the full
workspace, and `dry.toml` covers DRY over production code only.
Excluding test files from that second pass costs nothing: DRY-002
already ignores calls from `#[cfg(test)]` code, so the dead-code
count is identical with and without them.

Three `qual:allow(complexity, magic_numbers)` markers cover the
provider model catalogues in `jp_llm`, where context windows, output
limits and cutoff dates are data maintained against each provider's
published documentation rather than constants worth naming. They cut
the main pass from 498 magic-number findings to 193.

Refresh the baselines with `just qual-baseline` after a change that
deliberately moves the count, and commit the result alongside it so
the diff shows what moved.

Signed-off-by: Jean Mertz <git@jeanmertz.com>
The `qual` matrix entry failed immediately with `unknown task: qual`.
Adding a task to the `rust` job takes four edits, not two: the
`changes` job output, the path filter, the matrix list, and the
per-task gate that maps `$TASK` to the filter result. The first three
landed with the rustqual gate; this adds the fourth.

The gate's `case` statement has no default arm that lets an unmapped
task through, so the omission failed the job outright instead of
quietly running `qual-ci` on every push. Worth keeping in mind when
adding the next task.

Signed-off-by: Jean Mertz <git@jeanmertz.com>
`cargo binstall --only-signed` has nothing to resolve for rustqual:
the crate declares no `[package.metadata.binstall]`, every GitHub
release from v0.4.2 through v1.8.2 ships zero assets, and it is
absent from cargo-quickinstall. The `qual` job would have failed at
the install step on its first run.

`_install-rustqual` builds from crates.io instead. `cargo install`
no-ops in well under a second once the pinned version is present, so
every recipe can depend on it unconditionally, and a version bump
reinstalls on its own rather than needing `JP_INSTALL=1` the way the
path-installed tools do.

No cache step yet. The `qual` job already runs under sccache, which
covers rustqual's dependency tree from the second run onward; whether
that leaves the install cheap enough is a question for the CI timings
rather than for a guess.

Signed-off-by: Jean Mertz <git@jeanmertz.com>
`qual-ci` went red on its first run with `Findings: 2404 → 2404 (+0)`.
`--fail-on-regression` adds a failure condition rather than replacing
the default one: rustqual returns early when a comparison regresses,
and otherwise falls through to a gate that fails whenever any finding
exists. On a baselined workspace that is every run.

`--no-fail` disables only that second gate. It cannot mask a
regression, because the comparison returns before the gates are
reached: `handle_baseline_and_compare(cli, &analysis)?` sits above
`apply_exit_gates` in rustqual's `run_full_analysis`.

Output is now captured rather than streamed. Each pass printed all of
its baselined findings on every run, burying the comparison block that
carries the verdict; a clean run shows only that block, and a
regression shows the whole log. `--format github` is dropped because it
annotates every baselined finding rather than the new ones, and GitHub
displays at most ten, so the annotations showed pre-existing findings
and hid the regression.

Signed-off-by: Jean Mertz <git@jeanmertz.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant