Title#
Fix token usage recording in InvocationResultListener
Problem#
Token usage metrics went dark after the fire-and-forget refactor (e392b51). InvocationResultListener was processing phase results without calling TokenUsageService.record(), leaving all /api/cc/metrics/token-usage/* endpoints returning zeros.
Task / Link#
Closes #495
Changes#
- Add
TokenUsageModuletoInvokeModuleimports soTokenUsageServiceis available for injection - Inject
TokenUsageServicevia lazyModuleRef.get()inInvocationResultListener.onModuleInit() - Add
parseUsageFromStdout()to extract token counts and cost from Claude CLI JSONL output (resultevent for aggregates,assistantmessages for model name) - Call
tokenUsage.record(taskId, phase, usage)after the duplicate-delivery guard (fire-and-forget) - Add unit tests asserting
record()is called with correct args when usage is present, and skipped when absent
Notes#
- Usage recording is placed after the duplicate-delivery guard to avoid double-counting replayed jobs
- Model name is read from the first
assistantmessage in the JSONL stream; defaults to"unknown"if absent record()is fire-and-forget (void) — failures are silent and do not affect pipeline advancement
Testing#
- Unit tests:
invocation-result.listener.spec.ts— 2 new tests, all 790 suite tests pass - Lint: zero errors/warnings