Issue 2 — P2 (Code Smell)
Title: [REFACTOR] Split CodeAnalyzer into focused extractors
Labels: refactor, technical-debt
Body:
Problem
Services/CodeAnalyzer.cs is 689 lines and mixes multiple concerns:
Roslyn parsing
ASP.NET pattern detection (Controller / Service / Middleware)
Route prefix + HTTP method extraction
Call-graph extraction
XML documentation extraction
A stateful cache (_qualifiedNameToChunkId)
The stateful cache is the only mutable state in the whole project. In watch mode (--mode watch) with parallel file updates, this is a potential race condition (it is a plain Dictionary, not ConcurrentDictionary).
It is also hard to unit-test the individual sub-steps because they're all fused into one big class.
Proposed Solution
Split into focused components:
RoslynSyntaxAnalyzer — pure parsing, returns AST-derived data structures
AspNetMetadataExtractor — detects Controller / Service / Middleware patterns and route prefixes
CallGraphExtractor — extracts method call targets
CodeChunkBuilder (or rename CodeAnalyzer to this) — orchestrates the three above
The qualified-name cache should either:
Move to a ConcurrentDictionary, or
Be removed entirely if it's not actually used downstream (need to check)
Expected outcome: smaller, single-responsibility classes that can be unit-tested in isolation, and watch mode becomes race-safe.
Estimated scope: ~400 LOC refactor, 6–10 new unit tests for the extractors, regression test for watch-mode parallel updates.
Issue 2 — P2 (Code Smell)
Title: [REFACTOR] Split CodeAnalyzer into focused extractors
Labels: refactor, technical-debt
Body:
Problem
Services/CodeAnalyzer.cs is 689 lines and mixes multiple concerns:
Roslyn parsing
ASP.NET pattern detection (Controller / Service / Middleware)
Route prefix + HTTP method extraction
Call-graph extraction
XML documentation extraction
A stateful cache (_qualifiedNameToChunkId)
The stateful cache is the only mutable state in the whole project. In watch mode (--mode watch) with parallel file updates, this is a potential race condition (it is a plain Dictionary, not ConcurrentDictionary).
It is also hard to unit-test the individual sub-steps because they're all fused into one big class.
Proposed Solution
Split into focused components:
RoslynSyntaxAnalyzer — pure parsing, returns AST-derived data structures
AspNetMetadataExtractor — detects Controller / Service / Middleware patterns and route prefixes
CallGraphExtractor — extracts method call targets
CodeChunkBuilder (or rename CodeAnalyzer to this) — orchestrates the three above
The qualified-name cache should either:
Move to a ConcurrentDictionary, or
Be removed entirely if it's not actually used downstream (need to check)
Expected outcome: smaller, single-responsibility classes that can be unit-tested in isolation, and watch mode becomes race-safe.
Estimated scope: ~400 LOC refactor, 6–10 new unit tests for the extractors, regression test for watch-mode parallel updates.