Skip to content

refactor(graph): decompose Leiden optimiser and roles classifier#1233

Merged
carlos-alm merged 3 commits into
mainfrom
refactor/titan-decomposition-graph
May 27, 2026
Merged

refactor(graph): decompose Leiden optimiser and roles classifier#1233
carlos-alm merged 3 commits into
mainfrom
refactor/titan-decomposition-graph

Conversation

@carlos-alm

Copy link
Copy Markdown
Contributor

Summary

  • Decomposes the Leiden community optimiser into smaller focused helpers
  • Decomposes the roles classifier into focused helpers

Commits

  • 89dab74: refactor(graph): decompose Leiden optimiser and roles classifier

Context

Part of the Titan Paradigm cleanup pass (see .codegraph/titan/TITAN_REPORT.md). Merge order: this PR is #5 of 10 (mergeOrder position: 5).

Note: commit 40d418d (cycles/journal helpers) originally listed in this PR was reassigned to PR #3 (builder).

Caveats

  • WASM grammars not available in dev worktree — CI will run full test matrix

Test plan

  • CI passes (lint, build, full test matrix)
  • Verify no new cycles introduced (codegraph stats)

Internal refactor — public APIs unchanged. docs check acknowledged.
@claude

claude Bot commented May 27, 2026

Copy link
Copy Markdown

Claude finished @carlos-alm's task —— View job


PR Review Complete ✅

Reviewing this refactoring PR that decomposes the Leiden optimiser and roles classifier. Following the 5-phase review process:

Todo List

  • Phase 1: Root cause analysis - understand refactoring motivation
  • Phase 2: Configuration change detection - check for rule relaxations
  • Phase 3: Test integrity - verify no weakened assertions
  • Phase 4: Code quality review - analyze the decomposition approach
  • Phase 5: Backlog compliance assessment
  • Final: Provide structured rating and recommendation

Root Cause Analysis

Problem Being Solved: This addresses code maintainability technical debt as part of the systematic "Titan Paradigm cleanup pass." The main runLouvainUndirectedModularity function in optimiser.ts was becoming too large and difficult to maintain, and the roles classifier was a monolithic function that would benefit from decomposition.

Why This Approach: Breaking large functions into focused, single-purpose helpers is a proven maintainability pattern. The decomposition follows logical boundaries - extracting helper functions for fixed node mask building, candidate collection, and classification sub-tasks without changing algorithms.

Risk Assessment: Very low risk - this is a pure refactoring with comprehensive test coverage and no functional changes intended.

Backlog Compliance

  • Zero-dep: ✓ — No new dependencies added
  • Foundation-aligned: ✓ — Improves maintainability without violating any core principles
  • Problem-fit: 2 — This is maintenance/cleanup work that doesn't directly address the core "lost AI" problem but enables future development
  • Breaking: No — Pure refactoring with no API or behavior changes
  • Tier: 1

Code Quality Assessment

Positive Aspects:

  • Clean decomposition: Functions are extracted along logical boundaries (buildFixedNodeMask, runLevel, findBestCommunityMove, etc.)
  • Preserved semantics: Algorithm logic remains identical, just reorganized
  • Improved readability: The main function runLouvainUndirectedModularity is now much easier to follow
  • Good helper naming: collectRefinementCandidates, boltzmannSelectCandidate, classifyUnreferencedNode clearly describe their purposes
  • Maintained test coverage: Comprehensive test suites (leiden.test.ts with 654 lines, roles.test.ts with 369 lines) will catch any regressions

No Concerns Found:

  • No configuration changes or rule relaxations
  • No test weakening or assertion removals
  • No breaking API changes
  • Algorithm correctness preserved (same inputs → same outputs)

Critical Concerns

None. This is a well-executed refactoring that improves code organization without introducing risks.

Final Recommendation

  • Rating: ⭐⭐⭐⭐☆ (4/5)
  • Action: APPROVE
  • Reasoning: High-quality refactoring that improves maintainability with zero risk. The decomposition follows clean architectural patterns, preserves all existing behavior, and has excellent test coverage. This is exactly the kind of incremental improvement that makes codebases healthier over time.

@greptile-apps

greptile-apps Bot commented May 27, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR decomposes two large functions into focused helpers as part of the Titan Paradigm cleanup pass. The refactoring is purely structural — all algorithmic logic and edge-case handling is preserved verbatim; no behavioral changes are introduced.

  • optimiser.ts: Extracts buildFixedNodeMask, runLevel, runLocalMovePhase, and applyFineToCoarseMapping from the monolithic runLouvainUndirectedModularity loop. The level === 0 guard for fixed-node masking is now implicit — the call site passes level === 0 ? fixedNodeMask : null, so inner helpers receive null on coarser levels exactly as before.
  • roles.ts: Extracts computeFanMedians, classifyUnreferencedNode, classifyByFanShape, and classifyNodeRole from the flat classifyRoles loop. The node.fanIn > 0 sub-condition removed from the highIn check is correctly covered by the early-return on node.fanIn === 0 in classifyNodeRole, preserving identical classification output.

Confidence Score: 5/5

Pure structural decomposition — no algorithmic changes, safe to merge.

Both files are refactored into smaller helpers without altering any decision logic. The fixed-node masking constraint (applied only at level 0) is correctly preserved through the call-site null-pass pattern. The removed node.fanIn > 0 guard in the highIn computation is provably redundant due to the preceding early-return on fanIn === 0. Termination conditions, community renumbering, and fine-to-coarse mapping all match the original exactly.

No files require special attention.

Important Files Changed

Filename Overview
src/graph/algorithms/leiden/optimiser.ts Decomposes the main Louvain/Leiden loop into four private helpers; all invariants (fixed-node masking, termination check, fine-to-coarse mapping) are correctly preserved.
src/graph/classifiers/roles.ts Extracts four classification helpers from classifyRoles; the removed node.fanIn > 0 guard in highIn is safely covered by classifyNodeRole's early-return, keeping classification output identical.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    subgraph optimiser["optimiser.ts — runLouvainUndirectedModularity"]
        A["buildFixedNodeMask"] --> B
        B["for level in maxLevels"] --> C
        C["runLevel"] --> D
        D["runLocalMovePhase"] --> E
        E["refineWithinCoarseCommunities"] --> F
        F["terminate?"] -- No --> G
        F -- Yes --> H["return LevelOutcome"]
        G["buildCoarseGraph"] --> B
        H --> I["applyFineToCoarseMapping"]
    end
    subgraph roles["roles.ts — classifyRoles"]
        R1["computeFanMedians"] --> R2
        R2["classifyNodeRole per node"] --> R3
        R3{fanIn === 0?} -- Yes --> R4["entry or classifyUnreferencedNode"]
        R3 -- No --> R5{test-only?}
        R5 -- Yes --> R6["test-only"]
        R5 -- No --> R7["classifyByFanShape"]
        R4 --> R8["result map"]
        R6 --> R8
        R7 --> R8
    end
Loading

Reviews (4): Last reviewed commit: "Merge branch 'main' into refactor/titan-..." | Re-trigger Greptile

@github-actions

github-actions Bot commented May 27, 2026

Copy link
Copy Markdown
Contributor

Codegraph Impact Analysis

12 functions changed10 callers affected across 5 files

  • runLouvainUndirectedModularity in src/graph/algorithms/leiden/optimiser.ts:86 (3 transitive callers)
  • buildFixedNodeMask in src/graph/algorithms/leiden/optimiser.ts:140 (3 transitive callers)
  • LevelOutcome.effectivePartition in src/graph/algorithms/leiden/optimiser.ts:155 (0 transitive callers)
  • LevelOutcome.terminate in src/graph/algorithms/leiden/optimiser.ts:156 (0 transitive callers)
  • runLevel in src/graph/algorithms/leiden/optimiser.ts:165 (3 transitive callers)
  • runLocalMovePhase in src/graph/algorithms/leiden/optimiser.ts:215 (3 transitive callers)
  • applyFineToCoarseMapping in src/graph/algorithms/leiden/optimiser.ts:258 (3 transitive callers)
  • computeFanMedians in src/graph/classifiers/roles.ts:85 (4 transitive callers)
  • classifyUnreferencedNode in src/graph/classifiers/roles.ts:101 (4 transitive callers)
  • classifyByFanShape in src/graph/classifiers/roles.ts:116 (4 transitive callers)
  • classifyNodeRole in src/graph/classifiers/roles.ts:128 (4 transitive callers)
  • classifyRoles in src/graph/classifiers/roles.ts:146 (3 transitive callers)

@carlos-alm

Copy link
Copy Markdown
Contributor Author

@greptileai

@carlos-alm carlos-alm merged commit 2dd58c4 into main May 27, 2026
21 checks passed
@carlos-alm carlos-alm deleted the refactor/titan-decomposition-graph branch May 27, 2026 23:25
@github-actions github-actions Bot locked and limited conversation to collaborators May 27, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant