fix(build): turbo runner now actually reports per-task accounting (#830)#833
Merged
horza-bora merged 1 commit intomainfrom Apr 26, 2026
Merged
fix(build): turbo runner now actually reports per-task accounting (#830)#833horza-bora merged 1 commit intomainfrom
horza-bora merged 1 commit intomainfrom
Conversation
…sk accounting (#830) Turbo 2.x emits per-task status lines as "<pkg>:<task>: cache hit/miss/bypass ..." (colon separator, no trailing duration in parens). The parser was hard-coded to match the legacy "<pkg>#<task>:" form with a mandatory "(duration)" suffix, so every task line was silently dropped — leaving "tasks: []", "passed: 0", "failed: 0", "cached: 0" while "totalTasks" came from the "Tasks: N successful, M total" summary line. Changes: - TURBO_TASK_RE now accepts both ":" and "#" between package and task name and treats the trailing "(duration)" as optional. - New TURBO_ERROR_LINE_RE / TURBO_FAILED_LIST_RE patterns parse turbo 2.x's failure summary lines (" ERROR pkg#task: ... exited (N)" and "Failed: pkg#task"). - Failure information always wins over an earlier "cache bypass" pass line for the same task via a small upsert helper. - When the "Tasks: N successful, M total" summary line is present we trust it as ground truth for totalTasks/passed/failed (failed = M - N), preserving the "passed + failed === totalTasks" invariant even if per-task lines drift in future turbo releases. Adds 5 regression tests covering modern turbo 2.x output: cache bypass on force, cache hit, cache miss, ERROR+Failed failure summaries, and an invariant check across all fixtures.
horza-bora
approved these changes
Apr 26, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes #830.
mcp__pare-build__turbowas returning{success: true, totalTasks: 1, passed: 0, failed: 0, cached: 0, tasks: []}on every modern (turbo 2.x) run — claiming success while reporting zero per-task data.Root cause
Turbo 2.x emits per-task status lines as
<pkg>:<task>: cache hit/miss/bypass ...(colon separator, no trailing(duration)). The parser regexTURBO_TASK_REwas hard-coded to^(.+?)#(\S+):\s+cache\s+(hit|miss|bypass)(?:,\s+\w+[^(]*)?\(([^)]+)\)— requiring#between package and task and a mandatory(duration)suffix. Every per-task line silently failed to match, sotasks: []whiletotalTaskscame from theTasks: N successful, M totalsummary line. Failure parsing was broken in the same way.The 1.9s duration mentioned in the issue is turbo actually running — turbo just refused to print extra accounting because the run completed in milliseconds; the parse failure happened on the legitimate output.
Fix
packages/server-build/src/lib/parsers.ts:TURBO_TASK_REnow accepts both:and#between package and task, and treats the trailing(duration)as optional.TURBO_ERROR_LINE_RE/TURBO_FAILED_LIST_REpatterns parse turbo 2.x's failure summary lines (ERROR pkg#task: ... exited (N)andFailed: pkg#task).cache bypass"pass" classification.Tasks: N successful, M totalsummary line is present, it is trusted as ground truth fortotalTasks/passed/failed(failed = M − N) — preserving thepassed + failed === totalTasksinvariant even if per-task lines drift in a future turbo release.Before / after
Manual repro against the captured turbo 2.9.6 output for
--filter @paretools/shared --force:Before:
{ "success": true, "duration": 1.3, "tasks": [], "totalTasks": 1, "passed": 0, "failed": 0, "cached": 0 }After:
{ "success": true, "duration": 1.3, "tasks": [ { "package": "@paretools/shared", "task": "build", "status": "pass", "cache": "miss" } ], "totalTasks": 1, "passed": 1, "failed": 0, "cached": 0 }Failure case (deliberate broken TS file under
--force):{ "success": false, "duration": 1.4, "tasks": [ { "package": "@paretools/shared", "task": "build", "status": "fail", "cache": "miss" } ], "totalTasks": 1, "passed": 0, "failed": 1, "cached": 0 }Test plan
#fixtures)cache bypasson--forcecache hit(replaying logs)cache miss(no inline duration)ERROR+Failed:linespassed + failed === totalTasks@paretools/buildsuite green (262/262)pnpm format:checkclean on touched filesturbo 2.9.6output via the rebuilt parser confirms correct accountingChangeset
patchto@paretools/build.