src/orchestrator/tally.ts — shared outcome tally
Purpose
Section titled “Purpose”Both the end-of-run terminal summary (summary.ts:formatRunSummary)
and the --summarize JSON writer (run-artifacts.ts:writeRunSummary)
need the same per-run counts. Centralising them prevents drift between
the two surfaces.
Public surface
Section titled “Public surface”export interface Tally { successful: number failed: number skipped: number cachedLocal: number cachedRemote: number /** Group tasks are excluded from `total`. */ total: number}
export function tallyOutcomes(outcomes: readonly TaskOutcome[]): Tally- Group tasks (
isGroupTask(node)true) are skipped — they aren’t real work; counting them in “N total” would mislead the user. success→ +successful.cache-hit→ +successful, +cachedLocal.cache-hit-remote→ +successful, +cachedRemote.failed→ +failed.skipped→ +skipped.
The implementation is intentionally simple — one loop, one counter record. Adding a new outcome status means adding one branch here and the two consumer files automatically stay in sync.
Why this lives in orchestrator/ and not graph/
Section titled “Why this lives in orchestrator/ and not graph/”TaskOutcome (and the scheduler that produces it) live in graph/,
but the tally is a presentation-layer concern — it’s consumed by the
two run-summary writers. Keeping it under orchestrator/ keeps the
graph layer scheduler-only.
Covered transitively by tests/summary.test.ts (formatRunSummary
exercises every status branch + group-task exclusion) and
tests/run-artifacts.test.ts (the summary block in --summarize
JSON has full per-status coverage including group exclusion).