Plan: Migrate PhaseRouterService to LLMProvider#
Summary#
Replace direct ClaudeInvocationService injection in PhaseRouterService with the LLMProvider interface from #346. This removes signal parsing, metadata extraction, and skill mapping from the phase router, making it a pure orchestrator that consumes PhaseResult directly.
Files#
| File | Action | Description |
|---|---|---|
src/phase-router/phase-router.service.ts | modify | Swap ClaudeInvocationService → @Inject(LLM_PROVIDER) LLMProvider; replace SignalResult with PhaseResult; remove toSignalKind() conversion and PR metadata extraction |
src/phase-router/phase-router.module.ts | modify | Import LLMModule instead of InvokeModule |
src/phase-router/phase-router.service.spec.ts | modify | Replace ClaudeInvocationService mock with LLMProvider mock returning PhaseResult |
Steps#
- Update module imports — In
phase-router.module.ts: replaceInvokeModuleimport withLLMModule, removeInvokeModuleimport statement. - Swap injection in service — In
phase-router.service.tsconstructor: replaceClaudeInvocationServicewith@Inject(LLM_PROVIDER) private readonly llm: LLMProvider. Remove imports forClaudeInvocationService,SignalResult,SignalParser. - Refactor
executePhase()— Replacethis.claude.invoke()withthis.llm.invoke(). UsePhaseResultfields directly:result.signalfor signal kind,result.prNumber/result.prBranchfor PR metadata,result.conflictMetadatafor conflict data. RemovetoSignalKind()method entirely. - Remove
PHASE_TO_SKILLreference — Verify no local skill mapping exists in phase-router (currently inClaudeInvocationService— confirm no duplication). - Update
validateCompoundScope()— Change parameter type fromSignalResulttoPhaseResult. Update metadata access to usePhaseResultfield names instead ofresult.metadata?.['prNumber']. - Update test file — Replace
ClaudeInvocationServicemock withLLM_PROVIDERtoken mock. UpdatecompleteResult(),blockedResult(),skipResult()helpers to returnPhaseResultobjects. Update all test assertions referencingSignalResultfields.
Verification#
npx tsc --noEmitpasses with no type errorsnpm run test— all phase-router specs pass withLLMProvidermocknpm run lint— zero warnings
Risks#
- #346 not merged yet:
LLMProvider,PhaseResult,LLMModule, andClaudeCLIProviderdo not exist onrc/multi-tenantyet. Implementation is blocked until #346 lands. PhaseResultfield contract: IfPhaseResultuses different field names than assumed (e.g.signalvstype), the mapping in step 3 must adapt to the actual interface.