ai-agents-metrics

ARCH-021: Tier 3 pylint code-quality gates

Status: done Priority: medium Complexity: low-medium

Rationale

ARCH-019 enabled Tier 1 (correctness / file-size) and ARCH-020 promoted Tier 2 (complexity) to hard-fail. A large number of default pylint rules remained outside any tier — some real-signal (reimported, subprocess-run without check=, unnecessary comprehensions), some noisy style policy (line-too-long, missing docstrings), some semantically wrong on our code (too-few-public-methods on @dataclass, too-many-return-statements on dispatch tables).

ARCH-021 curates the remaining rules into a Tier 3 set that adds real signal without creating style-policy churn, and promotes it to hard-fail alongside Tier 1 and Tier 2.

Rules included in Tier 3

Rule What it catches
W0404 reimported import X twice in the same module
W0621 redefined-outer-name inner-scope shadowing of a module-level name
W1510 subprocess-run-check subprocess.run(...) without check=True/False
R1721 unnecessary-comprehension [x for x in seq] instead of list(seq)
R0916 too-many-boolean-expressions >5 boolean operators in one if
C0325 superfluous-parens parens after not/return/etc.
R0917 too-many-positional-arguments public-ish signatures with >5 positional args (force *, kwonly)
C0415 import-outside-toplevel lazy imports — must be justified
W0613 unused-argument dead-weight parameters (unless interface-conformance)
C0301 line-too-long at max-line-length=250 — catches only genuinely huge lines

Rules deliberately excluded

Rule Reason
C0114 missing-module-docstring every module would need a 1-liner; low ROI
C0115 missing-class-docstring fires on every small @dataclass
C0116 missing-function-docstring 284 findings — docstring-per-private-helper is busywork
R0801 duplicate-code most findings are legitimately similar SQL/insert blocks
R0903 too-few-public-methods fires on every @dataclass / Protocol
W0212 protected-access required for argparse._choices_actions mutation
R0911 too-many-return-statements fires on the intentional cli.main dispatch chain
R0904 too-many-public-methods singular outlier (CommandRuntime Protocol)

Implementation

Real fixes

Kwonly conversion

Twenty-one functions previously took >5 positional arguments. Each now uses *, to force callers to pass kwargs, matching how they are already called:

UsageResolver was upgraded from a plain Callable[...] alias to a Protocol with kwonly __call__ so mypy tracks the keyword-only contract through CostAuditContext.

Top-level import lifts

Lazy imports were hoisted where circular risk is absent (confirmed against lint-imports contracts):

Inline disables with rationale

Four imports stay lazy by design; each now carries a # pylint: disable=import-outside-toplevel with a comment explaining why:

Gate wiring

Acceptance Criteria