Skip to content

ADR-0022: Cognitive Complexity Gate via Pre-commit and SonarQube

Status: Accepted Deciders: elcubonegro, Claude (Sonnet 4.6) Date: 2026-03-27


Context and Problem Statement

Cornerstone generates projects for DeAcero's legacy modernisation workflow. The primary risk when rewriting legacy SQL/COBOL/VB6 logic into Python is translating high-complexity legacy code into equally high-complexity modern code — reproducing the problem rather than solving it.

Cognitive Complexity (Sonar's metric, not cyclomatic) measures how hard a function is to understand: nested control flow, boolean operators in conditions, and recursive structures each add to the score in a human-readable way. A function with score > 15 is statistically correlated with defect introduction and reviewer fatigue.

Without an automated gate, complexity creep is invisible until it becomes a maintenance crisis.


Decision Drivers

  • Legacy modernisation is the primary workflow. New code must not replicate legacy complexity.
  • Two enforcement layers are better than one: catch it locally before CI pays the cost.
  • SonarQube is already planned for the DeAcero toolchain (telemetry, observability).
  • The gate must not block PRs for existing legacy code — only for new code introduced after adoption.

Considered Options

  • Option A: Pre-commit only (flake8-cognitive-complexity) — fast, local, no server dependency.
  • Option B: SonarQube Quality Gate only — catches it in CI, requires server.
  • Option C: Both layers — pre-commit for developer feedback, SonarQube as the merge gate.

Decision Outcome

Chosen option: Option C — both layers.

Layer Tool When Scope Blocks
Pre-commit flake8-cognitive-complexity At every git commit All modified Python files The local commit
CI SonarQube Quality Gate On every PR / push to main New code only The PR merge

Why new code only in SonarQube?

DeAcero projects will contain legacy-ported code that may arrive with pre-existing complexity. Enforcing the gate on overall code would immediately block every PR that touches a legacy module. Enforcing on new code allows the team to port legacy logic, raise findings, and refactor incrementally — without being blocked on every commit.

The pre-commit hook catches new violations immediately, before CI is even involved.

Threshold

Default: 15 (SonarQube's standard). This is a template variable (cognitive_complexity_threshold) in cookiecutter.json so teams can tighten it (10 for greenfield, 20 for aggressive legacy ports).

SonarQube job is opt-in

The CI job runs only if SONAR_TOKEN is set as a GitHub secret. If the secret is absent the job is skipped — allowing teams to adopt Cornerstone before provisioning a SonarQube instance.

Exclusions

Both layers exclude generated artefacts (consistent with AGENTS.md § 2b):

.venv/, venv/, __pycache__/, *.egg-info/, dist/, build/

Positive Consequences

  • Complexity violations caught at commit time — zero CI wait.
  • SonarQube provides trend dashboards, historical complexity reports, and per-file drill-down.
  • Threshold is configurable per project via cookiecutter.json.
  • Teams without SonarQube can still enforce locally via pre-commit.

Negative Consequences

  • Teams need a SonarQube instance and SONAR_TOKEN / SONAR_HOST_URL secrets to unlock the CI gate.
  • flake8 added as a dev dependency alongside ruff (different tools: ruff does not enforce cognitive complexity).
  • Pre-commit hook adds ~1s per commit for Python files changed.

Implementation

File Change
{{cookiecutter.project_slug}}/.pre-commit-config.yaml Add flake8 + flake8-cognitive-complexity hook
{{cookiecutter.project_slug}}/.github/workflows/ci.yml Add sonarqube job after test
{{cookiecutter.project_slug}}/sonar-project.properties New file — project config for sonar-scanner
{{cookiecutter.project_slug}}/pyproject.toml Add flake8, flake8-cognitive-complexity to [dev]
cookiecutter.json Add cognitive_complexity_threshold: 15

  • Related: ADR-0007 (OWASP CI/CD security posture)
  • Related: ADR-0014 (atomic commit policy — same pre-commit layer)
  • Related: ADR-0020 (agentic semver — same commit-msg layer)
  • SonarQube Cognitive Complexity whitepaper: https://www.sonarsource.com/docs/CognitiveComplexity.pdf