Lintmax (Rust)
Gotchas
- The gate's completeness is itself audited: a maximum gate runs EVERY check at full scope — gate doctests not just unit tests (a discarded
cargo test --docresult lets a broken doc example pass), pass--workspaceto every per-package command (a workspace with a root package otherwise lints only the root), and denyyanked+unmaintaineddeps (cargo-deny defaults them to warn). A stage that runs but discards its result is a silent hole. - Max-strict rustfmt is not just style options — it includes the GATING levers
error_on_line_overflow+error_on_unformatted, which turn "silently leaves a >max_width line / unformattable comment" into a hard failure; without them a long inlinejson!/macro payload or raw-string literal sails through. Enabling them surfaces real overflow lines (fix the code: split ajson!body multi-line,concat!-join a long raw string), never disable the lever. - A
fixstage that DISCARDS its formatter result false-greens:cargo fmtin write mode returns non-zero whenerror_on_line_overflowhits a line it cannot fit, sorun_fmt_allmust RETURN that result (gate it), exactly like the check path — otherwisefixpasses whilecheck/CI fails on the same tree. - The configs the gate writes into the project dir (rustfmt.toml, etc.) are themselves walked by the formatter stages, so any block the gate appends (e.g. the computed vendored
ignorelist) must already be in the downstream formatter's canonical style (dprint TOML = 2-space array indent) orcheckflags the gate's own written config as unformatted whilefixsilently reformats it. - Maximum strictness spans EVERY child tool, not just rustfmt: shellcheck runs
--severity=style --enable=all(style severity + optional checks are off by default), shfmt runs-s(simplify, a lint-grade normalizer) plus-ci -sr -bnfor one canonical form, and cargo-deny addsmultiple-versions-include-dev(dev-dep version dups slip the default check) +required-git-spec="rev"(force git deps pinned). A stage left at its tool default is a silent strictness gap. - The rustc forbid list is audited by diffing
rustc -W helpallow-by-default lints against the list — but the gate runs STABLE, so a nightly-feature-gated lint (fuzzy_provenance_casts,must_not_suspend,unqualified_local_imports, …) passed as-Fbreaks the build with "unknown lint"; test each candidate withrustc -F <lint>on stable first, add only the ones it accepts (e.g.linker_info,linker_messages). - A per-crate gate (
cargo lintmaxin the crate dir) does NOT reach shell/config files outside the crate (repo-rootscripts/), so a launcher script accretes ungated debt; lint repo-root shell with the sameshellcheck --severity=style --enable=all+shfmt -i=2 -ci -sr -bn -sflags via a root-level gate invocation, never trust the nested per-crate run to cover it. - A lint that fundamentally conflicts with a required language pattern (clippy
arbitrary_source_item_orderingvs serde#[serde(other)]-must-be-last) is fixed in the CONSUMER code (rename the catch-all variant to sort last, or collapse the enum), never by disabling the lint for that item-kind — disabling it for one conflict turns it off everywhere. - Vendored external crates (a committed path-dependency under the repo) are not first-party: exclude them from file-walking stages (dprint, typos, machete via a temp
.ignore) the same way registry deps are never linted — detect them viacargo metadata(null source + non-workspace-member), never by directory name. - A
[workspace] excludedoes NOT stopcargo fmt --allreformatting a vendored crate under a strict root rustfmt config — the formatter still visits it; the rustfmt-native fix is anignore = [...]list computed from the vendored dirs (cargo metadata) and appended to the written rustfmt.toml, andclean_configsmust recognize the appended-ignore form as tool-owned so the consumer repo is left clean. - Strict nightly-only rustfmt options (import grouping, comment normalization) require the nightly rustfmt binary, forced via the
RUSTFMTenv var oncargo fmt—rustup run nightly cargo fmtfails when the PATHcargois not the rustup proxy (itsfmtstill finds stable rustfmt); the gate self-installs nightly + the rustfmt component and fails closed incheckwhen absent. - A
--profile minimaltoolchain (the common CI install:rustup toolchain install stable --profile minimal) OMITS therustfmtandclippyrustup components, so the gate's owncargo fmt/cargo clippystages die with "'cargo-fmt'/'cargo-clippy' is not installed for the toolchain" on a fresh runner — the gate must self-install BOTH components on the ACTIVE toolchain (rustup component add rustfmt/clippy, gated on acargo fmt --version/cargo clippy --versionprobe), not only the nightly rustfmt it forces viaRUSTFMT. This is the toolchain-COMPONENT twin of the child-binary self-install: a stage that shells out to acargo <component>subcommand owns ensuring that component exists, and the failure cascades one stage at a time (fmt green only reveals the clippy gap), so sweep the WHOLE component set the gate uses in one pass. The local machine passes only because its toolchain was installed full-profile. - Incremental clippy can false-green: a warm
cargo clippycache skips a newly-strict lint on a just-edited item, so a localfixreads clean while the fresh pre-commit/CI clippy fails — the fresh gate is the authoritative backstop, never the warm local cache. lintmax fix(the TS gate) on a MIXED-language repo WITHOUT scoping ignores mangles every non-TS file it walks: run blind on a rust+TS repo it reformatted a vendored rust crate, a sourced prompt.txt, generated drizzle migration metadata, andCargo.toml, and eslint errored (Oops! Something went wrong). Before runningfixon a mixed repo, SCOPE the gate to the hand-written TS-family source only (exclude the whole rust crate dir,node_modules,dist, vendored deps, and codegen output) — the rust is gated separately bylintmax-rs. Recover withgit checkout -- .from the clean pre-fix checkpoint (always commit before any autofix).- A corrupt cached build artifact masks the WHOLE gate: a malformed
target/doc/crates.js(or any stale doc/incremental artifact) makes the doc/compile stage exit before clippy runs, so the gate prints a generic stage error while every real restriction-group finding behind it stays hidden — reading clean is the false-green. On any unexplained stage error, blow away the cached artifact (rm -rf target/doc) and re-run from cold before trusting a pass; never let a never-stale toolchain bump's new lints sit behind a masked stage. - Passing the Rust gate's
restrictiongroup shapes the code: no?operator (uselet Ok(x) = e else {…}/match), nolet _ =(afn discard<T>(_v: T){}helper), nounwrap/expect/panic-paths, no indexing (.get/.pointer), no raw arithmetic (wrapping_add/checked_*), noascasts (try_from), explicitreturneverywhere (implicit_returnis active becauseneedless_returnis allowed), alphabetized struct fields + enum variants, a bool fn-param becomes a 2-variant enum, a >2KB async future isBox::pin-ed, and only//////!doc comments survive — every other//is stripped.