Skip to content

Enforce dual complexity ceilings (cyclomatic + cognitive ≤16) and decompose pm next renderer - #523

Merged
unbraind merged 2 commits into
mainfrom
fix/complexity-gate-cognitive-16
Jul 12, 2026
Merged

unbraind merged 2 commits into
mainfrom
fix/complexity-gate-cognitive-16

Conversation

@unbraind

@unbraind unbraind commented Jul 12, 2026 •

Copy link
Copy Markdown
Owner

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 16 and sonarjs/cognitive-complexity: max 16 (policy: no function over 16 on either metric). Calibration evidence documented in the config comment.
  • src/cli/commands/next.ts: renderNextMarkdown decomposed into renderNextSummaryLines / 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_SUPPRESSIONS re-pinned 104 → 180 with the rule-addition exception documented (budget remains lower-only otherwise).
  • package.json: lint:complexity:baseline now covers both rules; adds eslint-plugin-sonarjs (dev).
  • CONTRIBUTING.md: documents the twin ceilings and the Fix 'Complex Method' issue in src\cli\commands\next.ts #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 complexity max 16 and sonarjs/cognitive-complexity max 16; extend lint:complexity:baseline to cover both.
    • Decompose renderNextMarkdown into renderNextSummaryLines / renderNextRecommendedRows / renderNextSection / formatNextBlockedLine; add an inline note explaining the decision_needed ?? [] legacy-payload guard; output remains byte-identical.
    • Grandfather existing violations in eslint-suppressions.json; re-pin static gate MAX_ESLINT_SUPPRESSIONS from 104 to 180 with rule-addition note; document policy in CONTRIBUTING.md.
  • Dependencies

    • Add eslint-plugin-sonarjs for cognitive complexity rules.

Written for commit f4f3d7b. Summary will update on new commits.

Review in cubic

…kdown renderer

CodeFactor's Complex Method detector is nesting-weighted: GH-518 flagged
renderNextMarkdown at cyclomatic 14 (cognitive 22) while flat cyclomatic-16
functions pass, so the old complexity-max-17 cyclomatic gate was structurally
blind to the class. Enforce the no-function-over-16 policy on BOTH metrics:
complexity max 16 + sonarjs/cognitive-complexity max 16, wired into the same
bulk-suppressions ratchet (76 pre-existing violations grandfathered, budget
re-pinned 104 -> 180, burn-down tracked as pm-j8vq under pm-92if).

Decompose renderNextMarkdown (the live CodeFactor finding, pm-2gvp) into
summary/recommended/section/blocked-line helpers with byte-identical output;
cognitive drops 22 -> ~5. Extend lint:complexity:baseline to both rules and
document the twin ceilings in CONTRIBUTING.md.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VGcEVUn53YH2gwpLpUdvEJ
@sourcery-ai

sourcery-ai Bot commented Jul 12, 2026 •

Copy link
Copy Markdown

Reviewer's Guide

Enforces dual complexity ceilings (cyclomatic and cognitive ≤16) for the lint/quality gates and refactors the pm next CLI renderer into smaller helpers while keeping output identical, updating configuration, suppressions, and docs accordingly.

Flow diagram for refactored pm next renderer

flowchart TD
  renderNextMarkdown[renderNextMarkdown]
  renderNextSummaryLines[renderNextSummaryLines]
  renderNextRecommendedRows[renderNextRecommendedRows]
  renderNextSection[renderNextSection]
  formatNextBlockedLine[formatNextBlockedLine]
  formatNextLine[formatNextLine]

  renderNextMarkdown --> renderNextSummaryLines
  renderNextMarkdown -->|recommended| renderNextRecommendedRows
  renderNextMarkdown -->|Recommended section| renderNextSection
  renderNextMarkdown -->|Decision_needed section| renderNextSection
  renderNextMarkdown -->|Ready section| renderNextSection
  renderNextMarkdown -->|Blocked section| renderNextSection

  renderNextRecommendedRows --> formatNextLine
  formatNextBlockedLine --> formatNextLine
  renderNextMarkdown -->|Blocked rows| formatNextBlockedLine
Loading

File-Level Changes

Change Details Files
Refactored pm next Markdown renderer into smaller helpers to reduce cognitive complexity while preserving output.
  • Rewrote renderNextMarkdown to delegate to new helpers for summary, sections, and blocked rendering.
  • Added renderNextSummaryLines to build the top-of-report bullet summary, including optional scope and separator.
  • Added renderNextRecommendedRows to render recommendation item and rationale lines or no rows when absent.
  • Added renderNextSection helper to render a generic markdown section with header, rows or empty-state message, and trailing blank line.
  • Added formatNextBlockedLine to factor out blocked-item line formatting with blocker annotations.
src/cli/commands/next.ts
Tightened ESLint complexity gate and introduced cognitive-complexity enforcement via sonarjs, wiring it into the existing maintainability setup.
  • Lowered cyclomatic complexity limit from 17 to 16 and added sonarjs/cognitive-complexity max 16 in CODEFACTOR_MAINTAINABILITY_RULES.
  • Imported eslint-plugin-sonarjs and registered it in the shared ESLint config plugins.
  • Documented in-config rationale and calibration for dual complexity ceilings based on CodeFactor behaviour.
eslint.config.mjs
Updated contributor documentation to describe the new dual complexity ceilings and their CodeFactor calibration rationale.
  • Replaced single cyclomatic complexity description with explanation of both cyclomatic and cognitive ceilings at 16.
  • Explained why cognitive complexity is considered load-bearing by referencing Fix 'Complex Method' issue in src\cli\commands\next.ts #518 and nesting-weighted detection.
  • Clarified that existing violations are grandfathered via eslint-suppressions.json.
CONTRIBUTING.md
Adjusted static quality gate and baseline tooling to account for newly added cognitive-complexity rule and its suppressions.
  • Increased MAX_ESLINT_SUPPRESSIONS from 104 to 180 with a comment restricting future increases to new-rule rebaselines and documenting this change.
  • Extended lint:complexity:baseline script to suppress both complexity and sonarjs/cognitive-complexity when regenerating the baseline.
scripts/release/static-quality-gate.mjs
package.json
Rebaselined ESLint suppressions and dependency lockfile to include cognitive-complexity violations and sonarjs plugin.
  • Expanded eslint-suppressions.json to grandfather pre-existing cognitive-complexity and additional complexity violations.
  • Updated pnpm-lock.yaml to add eslint-plugin-sonarjs and reflect new dependency graph.
eslint-suppressions.json
pnpm-lock.yaml

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@unbraind

Copy link
Copy Markdown
Owner Author

@codex review

@unbraind

Copy link
Copy Markdown
Owner Author

/gemini review

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

@coderabbitai

coderabbitai Bot commented Jul 12, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR adds SonarJS cognitive-complexity enforcement with a second complexity ceiling and updates grandfathered suppressions. It also refactors pm next markdown generation into reusable local rendering helpers.

Changes

ESLint complexity gate

Layer / File(s) Summary
Configure twin complexity rules
CONTRIBUTING.md, eslint.config.mjs, package.json
Documents and configures cyclomatic and cognitive complexity limits of 16, adds the SonarJS plugin, and updates the baseline lint command.
Update grandfathered suppressions
eslint-suppressions.json, scripts/release/static-quality-gate.mjs
Adds complexity suppressions across scripts, CLI modules, core modules, and tests, and raises the documented suppression baseline from 104 to 180.

Next command markdown rendering

Layer / File(s) Summary
Refactor next markdown rendering
src/cli/commands/next.ts
Uses helpers for summary lines, sections, empty states, recommended rows, and blocked-row formatting while preserving --ready-only behavior.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly summarizes the main change: dual complexity ceilings and the next renderer refactor.
Description check ✅ Passed The description is detailed and directly describes the code, lint, and documentation changes in this PR.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've reviewed your changes and they look great!


Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces twin complexity ceilings of 16 for both cyclomatic complexity and SonarJS cognitive complexity, integrating eslint-plugin-sonarjs and updating the baseline suppressions and static quality gate limits accordingly. Additionally, the renderNextMarkdown function in src/cli/commands/next.ts is refactored into smaller, dedicated helper functions to improve readability and maintainability. A review comment suggests removing a redundant nullish coalescing guard (?? []) on result.decision_needed since the field is typed as non-optional.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread src/cli/commands/next.ts Resolved

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces twin complexity ceilings of 16 for both cyclomatic complexity and SonarJS cognitive complexity, integrating eslint-plugin-sonarjs and updating the baseline suppressions and static quality gate accordingly. Additionally, the markdown rendering logic in src/cli/commands/next.ts has been refactored into cleaner helper functions. Feedback on the changes suggests removing a redundant nullish coalescing operator (?? []) on result.decision_needed since the field is typed as non-optional and guaranteed to be populated.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread src/cli/commands/next.ts Resolved
@greptile-apps

greptile-apps Bot commented Jul 12, 2026 •

Copy link
Copy Markdown

Greptile Summary

This PR adds a stricter maintainability gate and refactors the pm next markdown renderer. The main changes are:

  • Adds eslint-plugin-sonarjs and enforces cognitive complexity at <= 16.
  • Lowers the cyclomatic complexity ceiling to <= 16.
  • Grandfathers existing complexity violations in eslint-suppressions.json.
  • Updates the static quality gate suppression budget for the new rule baseline.
  • Splits renderNextMarkdown into smaller helper functions while preserving output behavior.
  • Documents the dual complexity policy in CONTRIBUTING.md.

Confidence Score: 5/5

Safe to merge with minimal risk.

The changes are focused on lint configuration, baseline accounting, documentation, and a mechanical renderer decomposition. The SonarJS rule configuration matches the added dependency, and the renderer refactor preserves the original section ordering and empty-state behavior.

No files require special attention.

T-Rex T-Rex Logs

What T-Rex did

  • Completed the ESLint quality gate check and confirmed exit code 0.
  • Completed the complexity baseline check and confirmed exit code 0 with the expected suppression-rule invocation.
  • Validated the Next command Vitest run for next-command.spec.ts, with all tests passing (19/19) and exit code 0.
  • Captured the runtime environment information used for validation.

View all artifacts

T-Rex Ran code and verified through T-Rex

Important Files Changed

Filename Overview
eslint.config.mjs Adds eslint-plugin-sonarjs and enforces both cyclomatic and cognitive complexity ceilings at 16.
eslint-suppressions.json Grandfathers existing complexity and cognitive-complexity violations for the shrink-only lint baseline.
scripts/release/static-quality-gate.mjs Raises the ESLint suppression budget with an explicit exception for the newly added cognitive-complexity rule.
src/cli/commands/next.ts Refactors markdown rendering into smaller helpers while preserving section ordering and output behavior.
package.json Extends the complexity baseline command for both rules and adds eslint-plugin-sonarjs as a dev dependency.
pnpm-lock.yaml Updates lockfile entries for eslint-plugin-sonarjs and its dependency graph.
CONTRIBUTING.md Documents the new dual cyclomatic and cognitive complexity ceilings and calibration context.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant Dev as Developer/CI
participant ESLint as ESLint flat config
participant SonarJS as eslint-plugin-sonarjs
participant Supp as eslint-suppressions.json
participant Gate as static-quality-gate

Dev->>ESLint: pnpm lint:eslint
ESLint->>ESLint: "check complexity <= 16"
ESLint->>SonarJS: "check cognitive-complexity <= 16"
ESLint->>Supp: apply grandfathered suppressions
Dev->>Gate: pnpm lint:codefactor
Gate->>Supp: count suppression budget
Gate-->>Dev: fail if baseline exceeds 180
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant Dev as Developer/CI
participant ESLint as ESLint flat config
participant SonarJS as eslint-plugin-sonarjs
participant Supp as eslint-suppressions.json
participant Gate as static-quality-gate

Dev->>ESLint: pnpm lint:eslint
ESLint->>ESLint: "check complexity <= 16"
ESLint->>SonarJS: "check cognitive-complexity <= 16"
ESLint->>Supp: apply grandfathered suppressions
Dev->>Gate: pnpm lint:codefactor
Gate->>Supp: count suppression budget
Gate-->>Dev: fail if baseline exceeds 180
Loading

Reviews (2): Last reviewed commit: "docs(next): document the decision_needed..." | Re-trigger Greptile

@codecov

codecov Bot commented Jul 12, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ All tests successful. No failed tests found.

📢 Thoughts on this report? Let us know!

…call site

Gemini flagged the `?? []` as redundant against the non-optional type; it is
a deliberate tolerance for JSON payloads from builds predating the decision
queue, pinned by the empty-state rendering spec. Say so where it lives.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VGcEVUn53YH2gwpLpUdvEJ
@unbraind

Copy link
Copy Markdown
Owner Author

@sourcery-ai review

@unbraind

Copy link
Copy Markdown
Owner Author

/gemini review

@unbraind

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@sourcery-ai

sourcery-ai Bot commented Jul 12, 2026

Copy link
Copy Markdown

Sorry @unbraind, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@coderabbitai

coderabbitai Bot commented Jul 12, 2026 •

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a new cognitive complexity linting rule (sonarjs/cognitive-complexity max 16) and lowers the cyclomatic complexity ceiling from 17 to 16 in the ESLint configuration. To accommodate these changes, existing violations are grandfathered into eslint-suppressions.json, the maximum allowed suppressions in the static quality gate are increased to 180, and the renderNextMarkdown function in src/cli/commands/next.ts is refactored into smaller helper functions to reduce its complexity. There are no review comments provided for this pull request, so no further feedback is available.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

@unbraind
unbraind merged commit a026fd4 into main Jul 12, 2026
29 checks passed
@unbraind
unbraind deleted the fix/complexity-gate-cognitive-16 branch July 12, 2026 08:05
@unbraind

unbraind commented Aug 4, 2026

Copy link
Copy Markdown
Owner Author

Tracked in PM: pm-2gvp, pm-92if, pm-j8vq.

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