Skip to content

fix(suggest): connectivity guard — sparse package no longer false-'split'#257

Merged
zaebee merged 3 commits into
mainfrom
fix/suggest-sparse-guard
Jun 14, 2026
Merged

fix(suggest): connectivity guard — sparse package no longer false-'split'#257
zaebee merged 3 commits into
mainfrom
fix/suggest-sparse-guard

Conversation

@zaebee

@zaebee zaebee commented Jun 14, 2026

Copy link
Copy Markdown
Owner

Summary

Modularity Q is unreliable on a near-disconnected package: when most files have no intra-package edge, a single tiny cluster holds all the edges and inflates Q, producing a false split on what is really a bag of independent helpers.

Found cross-repo, dogfooding owner-api/utils through the MCP tool: 12 files, only 3 internal edges, 58% of files isolated → Q=0.44 → split — the textbook "independent helpers, nothing to split" (the very counter-example the cohesion RFC used).

Fix

A connected-fraction guard: the fraction of files with ≥1 intra-package edge must clear thresholds["min_connected"] (0.5) before a split/borderline verdict is trusted. Below it, the verdict is downgraded to leave with a note explaining the sparse-graph artifact. A new connected_fraction field on the report makes the signal visible in CLI/MCP JSON.

owner-api/utils:            split → leave   (conn_frac 0.42, "only 42% of files coupled — … sparse-graph artifact")
owner-api/api.dependencies: borderline      (conn_frac 0.97 — guard doesn't fire)
cgis.query:                 split           (conn_frac 0.68 — legit, kept)

Threshold = 0.5 (calibrated, not invented)

Measured connected-fraction on owner-api + cgis for every split/borderline package — a clean empty gap separates the artifact from the real splits:

package conn_frac verdict (pre-guard)
owner-api/utils 0.42 split suppress
cgis.query 0.68 split keep
cgis.guardian 0.89 borderline keep
owner-api/core 0.90 split keep

0.5 = "a majority of files must be coupled" — suppresses utils (0.42) with margin, keeps every legit split (≥0.68). Same "measure before fixing the threshold" discipline as the divergence gate.

Test Plan

  • Regression: sparse package (two tiny clusters + 7 isolated, conn_frac 0.42, Q≥0.35) → leave with the sparse note
  • Guard does NOT over-suppress: dense two-clique package (conn_frac 1.0) → still split
  • End-to-end on real owner-api/utils → now leave; api.dependencies unaffected
  • make format && lint && type-check && pytest && doc-coverage — green (1064 passed, mypy strict 64 files, interrogate 99.6%)

Follow-up to RFC #242, found by cross-repo validation.

🤖 Generated with Claude Code

…lit'

Modularity Q is unreliable on a near-disconnected package: when most files have
no intra-package edge, a single tiny cluster holds all the edges and inflates Q,
producing a false 'split' on what is really a bag of independent helpers.

Found cross-repo dogfooding owner-api/utils: 12 files, 3 edges, 58% isolated →
Q=0.44 → 'split', when it's the textbook "independent helpers, nothing to split".

Add a connected-fraction guard: the fraction of files with >=1 intra-package edge
must clear thresholds["min_connected"] (0.5) before a split/borderline verdict is
trusted; below it the verdict is downgraded to 'leave' with a note explaining the
sparse-graph artifact. New `connected_fraction` field on the report makes the
signal visible (CLI/MCP JSON).

Threshold 0.5 calibrated on owner-api + cgis: utils 0.42 (suppress) vs cgis.query
0.68 / owner-api.core 0.90 / cgis.guardian 0.89 (keep) — a clean empty gap
0.42→0.68. Regression test (sparse → leave) + guard-does-not-over-suppress test
(dense → still split).

Refs #242

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@zaebee

zaebee commented Jun 14, 2026

Copy link
Copy Markdown
Owner Author

/guardian review

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Summary: Checked for logic correctness (division by zero, edge cases), type safety, and test coverage. Found critical division-by-zero risk, major logic bug in connected_fraction calculation, and minor issues with float comparisons and threshold key access. No ontology or library contract violations detected.


🤖 mistral-medium-latest · 6,757 prompt + 1,586 completion = 8,343 tokens · graph 2/3 files (67%)

Comment thread src/cgis/query/analysis/suggest_service.py Outdated
Comment thread src/cgis/query/analysis/suggest_service.py
Comment thread src/cgis/query/analysis/suggest_service.py
Comment thread tests/unit/test_suggest_service.py
Comment thread tests/unit/test_suggest_service.py
github-actions Bot added a commit that referenced this pull request Jun 14, 2026

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

Copy link
Copy Markdown
Contributor

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 sparse-graph guard to prevent unreliable package splits on near-disconnected graphs where modularity Q is artificially inflated by a single small cluster. It adds a min_connected threshold (default 0.5) and calculates the fraction of coupled files (connected_fraction). If the fraction is below the threshold, a "split" or "borderline" verdict is downgraded to "leave". Tests are added to verify this behavior. The reviewer suggested simplifying the calculation of connected_fraction to len(graph.adj) / len(graph.files) to improve performance and readability.

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/cgis/query/analysis/suggest_service.py Outdated
…review)

gemini: adj keys are exactly the connected files (build_file_graph never creates
empty entries), so len(graph.adj)/len(files) is equivalent and O(1).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@zaebee

zaebee commented Jun 14, 2026

Copy link
Copy Markdown
Owner Author

/gemini review

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

Copy link
Copy Markdown
Contributor

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 sparse-graph guard to prevent false "split" or "borderline" package suggestions when modularity Q is inflated by a small cluster in an otherwise disconnected package. It adds a min_connected threshold (defaulting to 0.5), calculates the fraction of coupled files, and downgrades the verdict to "leave" with an explanatory note if the connectivity is below the threshold. Unit tests are also added to verify this behavior. The review feedback suggests enhancing the diagnostic note by including the exact counts of coupled and total files to avoid rounding confusion near the threshold.

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/cgis/query/analysis/suggest_service.py
gemini: include len(adj)/len(files) alongside the % so a 0.499→'50%' rounding
near the threshold isn't confusing.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@sonarqubecloud

Copy link
Copy Markdown

@zaebee zaebee merged commit 0e1ddf7 into main Jun 14, 2026
3 checks passed
@zaebee zaebee deleted the fix/suggest-sparse-guard branch June 14, 2026 17:49
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