Enforce dual complexity ceilings (cyclomatic + cognitive ≤16) and decompose pm next renderer
Summary
Closes the gate gap behind GH-518 (CodeFactor "Complex Method" in src/cli/commands/next.ts, tracked as pm-2gvp) and fixes the finding itself.
Why the old gate missed it
The existing complexity: max 17 rule was calibrated to an assumption that CodeFactor flags at cyclomatic ≥ 18. GH-518 disproved that: the flagged renderNextMarkdown scores cyclomatic 14 but cognitive complexity 22 (deeply nested sections), while runNext in the same file (cyclomatic 16, cognitive 5 — flat early returns) was never flagged. CodeFactor's detector is nesting-weighted, so a purely cyclomatic gate is structurally blind to this finding class.
Changes
- eslint.config.mjs: twin ceilings —
complexity: max 16andsonarjs/cognitive-complexity: max 16(policy: no function over 16 on either metric). Calibration evidence documented in the config comment. - src/cli/commands/next.ts:
renderNextMarkdowndecomposed intorenderNextSummaryLines/renderNextRecommendedRows/renderNextSection/formatNextBlockedLine; output byte-identical (all rendering specs unchanged and green); cognitive 22 → ≤3 per function. - eslint-suppressions.json: 76 pre-existing violations grandfathered (62 cognitive >16, 14 at cyclomatic 17); the shrink-only ratchet still fails lint on any new violation or stale suppression. Burn-down tracked as pm-j8vq (child of pm-92if) with the worst offenders enumerated.
- static-quality-gate.mjs:
MAX_ESLINT_SUPPRESSIONSre-pinned 104 → 180 with the rule-addition exception documented (budget remains lower-only otherwise). - package.json:
lint:complexity:baselinenow covers both rules; addseslint-plugin-sonarjs(dev). - CONTRIBUTING.md: documents the twin ceilings and the GH-518 calibration evidence.
Verification
pnpm lint(ESLint + jscpd + static quality gate + token budget): green- Full coverage gate: 100% statements/branches/functions/lines (34,726/34,726 statements)
- next/cli rendering suites: 393 tests green
🤖 Generated with Claude Code
https://claude.ai/code/session_01VGcEVUn53YH2gwpLpUdvEJ
Summary by Sourcery
Enforce dual cyclomatic and cognitive complexity ceilings in ESLint and refactor the pm next CLI renderer to comply while keeping output unchanged.
Enhancements:
- Refactor the pm next markdown renderer by extracting summary, section, recommendation, and blocked-row helpers to reduce per-function complexity while preserving existing output.
- Tighten the maintainability gate by adding a sonarjs-based cognitive-complexity rule alongside a lower cyclomatic-complexity limit and wiring the plugin into the shared ESLint config.
- Document the new dual complexity ceilings and their CodeFactor calibration details in CONTRIBUTING.
Build:
- Update the static quality gate’s ESLint suppression budget to account for newly grandfathered complexity violations.
- Extend the complexity baseline lint script to cover both cyclomatic and cognitive complexity rules and add eslint-plugin-sonarjs as a dev dependency.
Summary by cubic
Enforce dual complexity ceilings (cyclomatic and cognitive ≤16) and refactor the pm next markdown renderer into small helpers to close the CodeFactor “Complex Method” gap. Addresses GH-518, tracked as pm-2gvp; behavior and output are unchanged.
-
Refactors
- ESLint: add
complexitymax 16 andsonarjs/cognitive-complexitymax 16; extendlint:complexity:baselineto cover both. - Decompose
renderNextMarkdownintorenderNextSummaryLines/renderNextRecommendedRows/renderNextSection/formatNextBlockedLine; add an inline note explaining thedecision_needed ?? []legacy-payload guard; output remains byte-identical. - Grandfather existing violations in
eslint-suppressions.json; re-pin static gateMAX_ESLINT_SUPPRESSIONSfrom 104 to 180 with rule-addition note; document policy inCONTRIBUTING.md.
- ESLint: add
-
Dependencies
- Add
eslint-plugin-sonarjsfor cognitive complexity rules.
- Add