AI Agents SDE Task Viewer
      • Context
      • Plan
      • Prd
  1. Home
  2. AgentSDE
  3. agent-core
  4. gh-352
  5. plan
  6. plan.md
plan.md(3.4 KB)· Apr 8, 2026· 2 min read
  • Summary
  • Files
  • Steps
  • Verification
  • Risks

Plan: Migrate InternalAdapterService from SignalResult to PhaseResult#

Summary#

Replace the SignalKind string union and handleSignal(taskId, phase, signal: SignalKind, output?) signature with handleSignal(taskId, phase, result: PhaseResult) so the internal adapter consumes the normalized PhaseResult type directly — eliminating the lossy toSignalKind() conversion in PhaseRouterService and removing all SignalKind/SignalParser references from the internal-adapter module.

Files#

FileActionDescription
src/internal-adapter/internal-adapter.service.tsmodifyRemove SignalKind type, update handleSignal to accept PhaseResult, dispatch on result.status/result.blockedType, read result.reason/result.retryAfter/result.conflictMetadata
src/internal-adapter/internal-adapter.module.tsinspectVerify no SignalParser provider — currently clean, no change needed
src/internal-adapter/internal-adapter.service.spec.tsmodifyRewrite all handleSignal calls to pass PhaseResult objects instead of SignalKind strings
src/phase-router/phase-router.service.tsmodifyRemove toSignalKind() method, pass SignalResult→PhaseResult mapping directly to handleSignal, update all call sites

Steps#

  1. Import PhaseResult and update handleSignal signature in internal-adapter.service.ts — remove SignalKind type export, import PhaseResult from #346's type location, change signature to handleSignal(taskId: number, phase: string, result: PhaseResult).
  2. Rewrite dispatch logic in handleSignal — switch on result.status (complete, skip, blocked) with result.blockedType sub-dispatch (transient, persistent, conflict). Pass result.reason to handlers instead of the old output parameter. Add fallback: unrecognized result.status logs a warning and is treated as blocked:transient.
  3. Update handler methods — handleComplete/handleSkip/handleTransientBlock/handlePersistentBlock/handleConflictBlock to read fields from PhaseResult (reason, retryAfter, conflictMetadata) instead of the generic output string.
  4. Update PhaseRouterService call sites — remove toSignalKind() private method, construct PhaseResult from the existing SignalResult fields, pass it to handleSignal. Update the 3 direct handleSignal calls (review_approved, worktree failure, post-invocation).
  5. Update all unit tests in internal-adapter.service.spec.ts — replace every handleSignal(id, phase, 'COMPLETE', output) call with handleSignal(id, phase, { status: 'complete', reason: '...' }) PhaseResult objects. Add a test for unrecognized status → blocked:transient fallback.

Verification#

  • tsc --noEmit passes with no SignalKind or SignalParser imports in src/internal-adapter/
  • npm run test — all existing dispatch behavior preserved, new unrecognized-status test passes
  • npm run lint — zero warnings

Risks#

  • Blocked by #346 — PhaseResult type must exist before implementation starts. If #346's PhaseResult shape differs from what the issue describes (status/blockedType/reason/retryAfter/conflictMetadata), the dispatch mapping will need adjustment.
  • Parallel merge with #351 — #351 modifies PhaseRouterService caller side. Merge order matters; coordinate to avoid a broken intermediate state where handleSignal expects PhaseResult but callers still pass SignalKind.
ContextPrd