pi-crew 0.9.51 → 0.9.53

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (611) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/README.md +216 -20
  3. package/dist/build-meta.json +2090 -1638
  4. package/dist/index.mjs +18057 -17119
  5. package/docs/actions-reference.md +431 -1
  6. package/index.ts +39 -10
  7. package/package.json +19 -9
  8. package/schema.json +41 -0
  9. package/scripts/check-bundle-size.mjs +38 -0
  10. package/scripts/test-runner.mjs +11 -1
  11. package/dist/index.mjs.map +0 -7
  12. package/docs/FEATURE_INTAKE.md +0 -126
  13. package/docs/HARNESS.md +0 -87
  14. package/docs/HARNESS_BACKLOG.md +0 -89
  15. package/docs/PROJECT_REVIEW.md +0 -270
  16. package/docs/PROJECT_REVIEW_FIXES.md +0 -342
  17. package/docs/PROJECT_REVIEW_ROUND4.md +0 -156
  18. package/docs/PROJECT_REVIEW_ROUND5.md +0 -86
  19. package/docs/REVIEW-FINDINGS-2026-06 +0 -357
  20. package/docs/REVIEW-FINDINGS-2026-07-CORE.md +0 -139
  21. package/docs/REVIEW-FINDINGS-2026-07.md +0 -125
  22. package/docs/TEST_MATRIX.md +0 -51
  23. package/docs/archive/README.md +0 -91
  24. package/docs/archive/followup-review-round3-2026-05-12.md +0 -342
  25. package/docs/archive/followup-review-round4-2026-05-13.md +0 -107
  26. package/docs/archive/pi-crew-bugs.md +0 -961
  27. package/docs/archive/pi-crew-test-final.md +0 -120
  28. package/docs/archive/pi-crew-test-results.md +0 -260
  29. package/docs/archive/pi-crew-test-round2.md +0 -136
  30. package/docs/archive/pi-crew-test-round4.md +0 -100
  31. package/docs/archive/pi-crew-test-round5.md +0 -70
  32. package/docs/archive/pi-crew-test-round6.md +0 -110
  33. package/docs/archive/pi-crew-v0.5.10-audit-fix-plan.md +0 -60
  34. package/docs/archive/pi-crew-v0.5.11-audit-fix-plan.md +0 -92
  35. package/docs/archive/pi-crew-v0.5.12-audit-fix-plan.md +0 -76
  36. package/docs/archive/pi-crew-v0.5.13-audit-fix-plan.md +0 -75
  37. package/docs/archive/pi-crew-v0.5.14-audit-fix-plan.md +0 -75
  38. package/docs/archive/pi-crew-v0.5.16-audit-fix-plan.md +0 -35
  39. package/docs/archive/pi-crew-v0.5.17-audit-fix-plan.md +0 -80
  40. package/docs/archive/pi-crew-v0.5.5-audit-fix-plan.md +0 -133
  41. package/docs/archive/pi-crew-v0.5.9-audit-fix-plan.md +0 -88
  42. package/docs/archive/pi-mono-opportunities.md +0 -969
  43. package/docs/archive/pi-mono-review.md +0 -291
  44. package/docs/archive/pi-subagent4-comparison.md +0 -261
  45. package/docs/archive/pi-subagents3-deep-analysis.md +0 -508
  46. package/docs/bugs/bug-021-notification-badge-counter-misleading.md +0 -293
  47. package/docs/bugs/bug-023-chain-windows-path-resolution.md +0 -106
  48. package/docs/bugs/bug-quota-display-truncation.md +0 -223
  49. package/docs/bugs/cross-session-notification-leakage.md +0 -82
  50. package/docs/code-review-2026-05-11.md +0 -592
  51. package/docs/coding-agent-optimization.md +0 -268
  52. package/docs/comparison-pi-subagents-vs-pi-crew.md +0 -303
  53. package/docs/decisions/0001-durable-state.md +0 -41
  54. package/docs/decisions/0002-child-process-for-async.md +0 -42
  55. package/docs/decisions/0003-depth-guard.md +0 -36
  56. package/docs/decisions/0004-execfile-over-exec.md +0 -34
  57. package/docs/decisions/0005-no-parameter-properties.md +0 -49
  58. package/docs/decisions/0006-publish-bundled-esm.md +0 -63
  59. package/docs/decisions/0007-active-run-binary-index.md +0 -54
  60. package/docs/decisions/0008-child-pi-warm-pool.md +0 -61
  61. package/docs/decisions/2026-07-21-broker-phase4-default-on.md +0 -77
  62. package/docs/decisions/2026-07-21-broker-windows-perms.md +0 -91
  63. package/docs/decisions/2026-07-22-broker-phase4-gated-on.md +0 -99
  64. package/docs/decisions/2026-07-24-oidc-trusted-publishing.md +0 -112
  65. package/docs/decisions/2026-07-26-c6-mascot-visibility-not-wired.md +0 -84
  66. package/docs/decisions/README.md +0 -26
  67. package/docs/deep-review-report.md +0 -384
  68. package/docs/distillation/cybersecurity-patterns.md +0 -294
  69. package/docs/feature-analysis-subagent4.md +0 -305
  70. package/docs/fix-plan-disabletools-exit-null.md +0 -219
  71. package/docs/fixes/BATCH_A_H1_H2.md +0 -86
  72. package/docs/fixes/bug-006-foreground-cancel-concurrent.md +0 -78
  73. package/docs/fixes/bug-007-async-notifier-stale-ctx.md +0 -112
  74. package/docs/fixes/bug-008-child-process-silent-timeout.md +0 -100
  75. package/docs/fixes/bug-009-executor-yield-limit-needs-attention.md +0 -75
  76. package/docs/fixes/bug-010-child-process-api-key-filtered.md +0 -109
  77. package/docs/fixes/bug-011-spawn-pi-enoent.md +0 -92
  78. package/docs/fixes/bug-012-essential-env-stripped.md +0 -89
  79. package/docs/fixes/bug-013-background-runner-death.md +0 -84
  80. package/docs/fixes/bug-014-infinite-retry-loop-needs-attention.md +0 -82
  81. package/docs/fixes/bug-015-background-runner-sigterm.md +0 -65
  82. package/docs/fixes/bug-017-background-runner-session-shutdown.md +0 -66
  83. package/docs/fixes/bug-017-background-runner-sigkill-double-fork.md +0 -28
  84. package/docs/fixes/bug-018-child-pi-worker-stdin-hang.md +0 -61
  85. package/docs/fixes/bug-019-phantom-runs-temp-workspace.md +0 -52
  86. package/docs/fixes/bug-020-infinite-retry-loop-needs-attention.md +0 -47
  87. package/docs/fixes/v0.9.10/locks-fix-verify.md +0 -3
  88. package/docs/fixes/v0.9.10/smoke-test.md +0 -12
  89. package/docs/followup-plan-2026-05-12.md +0 -463
  90. package/docs/followup-review-2026-05-12.md +0 -297
  91. package/docs/goals.md +0 -59
  92. package/docs/implementation-plan-top3.md +0 -333
  93. package/docs/issue-29-analysis.md +0 -189
  94. package/docs/live-mailbox-runtime.md +0 -36
  95. package/docs/migration/atomic-write-v2-migration.md +0 -299
  96. package/docs/next-upgrade-roadmap.md +0 -808
  97. package/docs/oh-my-pi-research.md +0 -509
  98. package/docs/optimization-plan-2026-07.md +0 -366
  99. package/docs/optimization-plan.md +0 -644
  100. package/docs/patterns/command-agent-skill.md +0 -71
  101. package/docs/perf/baseline-2026-05.md +0 -113
  102. package/docs/perf/final-report-2026-05.md +0 -206
  103. package/docs/perf/optimization-plan-2026-07-verified.md +0 -396
  104. package/docs/perf/performance-audit-report-2026-07.md +0 -948
  105. package/docs/perf/performance-review-2026-07.md +0 -287
  106. package/docs/perf/sprint-1-report.md +0 -71
  107. package/docs/perf/sprint-2-report.md +0 -81
  108. package/docs/perf/sprint-2.5-report.md +0 -53
  109. package/docs/perf/sprint-3-report.md +0 -36
  110. package/docs/perf/sprint-4-report.md +0 -47
  111. package/docs/perf/sprint-5-report.md +0 -51
  112. package/docs/perf/sprint-6-report.md +0 -94
  113. package/docs/perf/sprint-7-report.md +0 -74
  114. package/docs/perf/upgrade-plan-2026-05.md +0 -147
  115. package/docs/performance-optimization-execution-plan.md +0 -520
  116. package/docs/phase4-triage.md +0 -58
  117. package/docs/pi-crew-investigation-report.md +0 -411
  118. package/docs/product/README.md +0 -31
  119. package/docs/product/platform.md +0 -27
  120. package/docs/product/runtime-safety.md +0 -37
  121. package/docs/product/team-run.md +0 -39
  122. package/docs/product/team-tool.md +0 -37
  123. package/docs/runtime-analysis-child-vs-live.md +0 -171
  124. package/docs/runtime-migration-in-process-analysis.md +0 -250
  125. package/docs/skills/REFERENCE.md +0 -138
  126. package/docs/stories/README.md +0 -32
  127. package/docs/stories/US-DEPS-major-upgrade.md +0 -62
  128. package/docs/stories/backlog.md +0 -36
  129. package/docs/superpowers/plans/2026-06-09-fallow-patterns-adoption.md +0 -1270
  130. package/docs/templates/decision.md +0 -27
  131. package/docs/templates/story.md +0 -44
  132. package/docs/templates/validation-report.md +0 -32
  133. package/docs/ui-optimization-plan.md +0 -447
  134. package/src/adapters/claude-adapter.ts +0 -23
  135. package/src/adapters/codex-adapter.ts +0 -21
  136. package/src/adapters/cursor-adapter.ts +0 -17
  137. package/src/adapters/export-util.ts +0 -143
  138. package/src/adapters/index.ts +0 -15
  139. package/src/adapters/registry.ts +0 -18
  140. package/src/adapters/types.ts +0 -23
  141. package/src/agents/agent-config.ts +0 -194
  142. package/src/agents/agent-search.ts +0 -98
  143. package/src/agents/agent-serializer.ts +0 -38
  144. package/src/agents/discover-agents.ts +0 -623
  145. package/src/benchmark/benchmark-runner.ts +0 -313
  146. package/src/benchmark/feedback-loop.ts +0 -73
  147. package/src/config/config.ts +0 -1269
  148. package/src/config/defaults.ts +0 -193
  149. package/src/config/drift-detector.ts +0 -290
  150. package/src/config/markers.ts +0 -330
  151. package/src/config/resilient-parser.ts +0 -117
  152. package/src/config/role-tools.ts +0 -118
  153. package/src/config/suggestions.ts +0 -75
  154. package/src/config/types.ts +0 -278
  155. package/src/errors.ts +0 -194
  156. package/src/extension/action-suggestions.ts +0 -117
  157. package/src/extension/async-notifier.ts +0 -179
  158. package/src/extension/autonomous-policy.ts +0 -209
  159. package/src/extension/command-completions.ts +0 -120
  160. package/src/extension/context-status-injection.ts +0 -185
  161. package/src/extension/crew-autocomplete.ts +0 -131
  162. package/src/extension/crew-cleanup.ts +0 -168
  163. package/src/extension/crew-input-router.ts +0 -93
  164. package/src/extension/crew-shortcuts.ts +0 -87
  165. package/src/extension/crew-vibes/cat-frames.ts +0 -18
  166. package/src/extension/crew-vibes/config.ts +0 -195
  167. package/src/extension/crew-vibes/figures.ts +0 -101
  168. package/src/extension/crew-vibes/font-detect.ts +0 -71
  169. package/src/extension/crew-vibes/footer.ts +0 -292
  170. package/src/extension/crew-vibes/index.ts +0 -432
  171. package/src/extension/crew-vibes/provider-usage.ts +0 -396
  172. package/src/extension/crew-vibes/render.ts +0 -206
  173. package/src/extension/crew-vibes/speed.ts +0 -286
  174. package/src/extension/cross-extension-rpc.ts +0 -350
  175. package/src/extension/help.ts +0 -62
  176. package/src/extension/import-index.ts +0 -74
  177. package/src/extension/knowledge-injection.ts +0 -402
  178. package/src/extension/management.ts +0 -571
  179. package/src/extension/message-renderers.ts +0 -108
  180. package/src/extension/notification-router.ts +0 -152
  181. package/src/extension/notification-sink.ts +0 -54
  182. package/src/extension/pi-api.ts +0 -56
  183. package/src/extension/plan-orchestrate.ts +0 -302
  184. package/src/extension/project-init.ts +0 -170
  185. package/src/extension/register.ts +0 -113
  186. package/src/extension/registration/artifact-cleanup.ts +0 -20
  187. package/src/extension/registration/command-registration.ts +0 -58
  188. package/src/extension/registration/command-utils.ts +0 -58
  189. package/src/extension/registration/commands.ts +0 -1228
  190. package/src/extension/registration/compaction-guard.ts +0 -333
  191. package/src/extension/registration/context-builder.ts +0 -135
  192. package/src/extension/registration/crash-recovery-cache.ts +0 -54
  193. package/src/extension/registration/foreground-run-controller.ts +0 -238
  194. package/src/extension/registration/hook-registration.ts +0 -119
  195. package/src/extension/registration/lazy-configurers.ts +0 -124
  196. package/src/extension/registration/lifecycle-handlers.ts +0 -923
  197. package/src/extension/registration/lifecycle.ts +0 -259
  198. package/src/extension/registration/observability.ts +0 -322
  199. package/src/extension/registration/registration-types.ts +0 -158
  200. package/src/extension/registration/runtime-cleanup.ts +0 -230
  201. package/src/extension/registration/subagent-helpers.ts +0 -125
  202. package/src/extension/registration/subagent-manager-setup.ts +0 -330
  203. package/src/extension/registration/subagent-tools.ts +0 -456
  204. package/src/extension/registration/team-tool.ts +0 -220
  205. package/src/extension/registration/tool-registration.ts +0 -50
  206. package/src/extension/registration/ui.ts +0 -172
  207. package/src/extension/registration/viewers.ts +0 -121
  208. package/src/extension/registration/wire-cross-extension.ts +0 -37
  209. package/src/extension/result-watcher.ts +0 -139
  210. package/src/extension/rpc-hmac.ts +0 -256
  211. package/src/extension/run-bundle-schema.ts +0 -104
  212. package/src/extension/run-export.ts +0 -97
  213. package/src/extension/run-import.ts +0 -168
  214. package/src/extension/run-index.ts +0 -131
  215. package/src/extension/run-maintenance.ts +0 -190
  216. package/src/extension/session-summary.ts +0 -18
  217. package/src/extension/team-manager-command.ts +0 -153
  218. package/src/extension/team-onboard.ts +0 -177
  219. package/src/extension/team-recommendation.ts +0 -288
  220. package/src/extension/team-tool/anchor.ts +0 -172
  221. package/src/extension/team-tool/api.ts +0 -1244
  222. package/src/extension/team-tool/auto-summarize.ts +0 -142
  223. package/src/extension/team-tool/cache-control.ts +0 -19
  224. package/src/extension/team-tool/cancel.ts +0 -337
  225. package/src/extension/team-tool/chain-dispatch.ts +0 -95
  226. package/src/extension/team-tool/chain-executor.ts +0 -379
  227. package/src/extension/team-tool/config-patch.ts +0 -50
  228. package/src/extension/team-tool/context.ts +0 -149
  229. package/src/extension/team-tool/destructive-gate.ts +0 -52
  230. package/src/extension/team-tool/doctor.ts +0 -431
  231. package/src/extension/team-tool/explain.ts +0 -282
  232. package/src/extension/team-tool/failure-patterns.ts +0 -118
  233. package/src/extension/team-tool/goal-wrap.ts +0 -330
  234. package/src/extension/team-tool/goal.ts +0 -556
  235. package/src/extension/team-tool/handle-schedule.ts +0 -332
  236. package/src/extension/team-tool/handle-settings.ts +0 -520
  237. package/src/extension/team-tool/health-monitor.ts +0 -481
  238. package/src/extension/team-tool/inspect.ts +0 -88
  239. package/src/extension/team-tool/intent-policy.ts +0 -45
  240. package/src/extension/team-tool/lifecycle-actions.ts +0 -615
  241. package/src/extension/team-tool/orchestrate.ts +0 -98
  242. package/src/extension/team-tool/parallel-dispatch.ts +0 -183
  243. package/src/extension/team-tool/plan.ts +0 -50
  244. package/src/extension/team-tool/respond.ts +0 -150
  245. package/src/extension/team-tool/run-not-found.ts +0 -49
  246. package/src/extension/team-tool/run.ts +0 -1035
  247. package/src/extension/team-tool/status.ts +0 -260
  248. package/src/extension/team-tool/workflow-manage.ts +0 -261
  249. package/src/extension/team-tool-types.ts +0 -26
  250. package/src/extension/team-tool.ts +0 -1116
  251. package/src/extension/tool-result.ts +0 -16
  252. package/src/extension/validate-resources.ts +0 -108
  253. package/src/hooks/registry.ts +0 -200
  254. package/src/hooks/types.ts +0 -69
  255. package/src/i18n.ts +0 -212
  256. package/src/observability/correlation.ts +0 -50
  257. package/src/observability/event-bus.ts +0 -86
  258. package/src/observability/event-to-metric.ts +0 -170
  259. package/src/observability/exporters/adapter.ts +0 -27
  260. package/src/observability/exporters/otlp-exporter.ts +0 -356
  261. package/src/observability/exporters/prometheus-exporter.ts +0 -54
  262. package/src/observability/metric-registry.ts +0 -100
  263. package/src/observability/metric-retention.ts +0 -64
  264. package/src/observability/metric-sink.ts +0 -99
  265. package/src/observability/metrics-primitives.ts +0 -219
  266. package/src/plugins/plugin-define.ts +0 -6
  267. package/src/plugins/plugin-registry.ts +0 -32
  268. package/src/plugins/plugins/index.ts +0 -3
  269. package/src/plugins/plugins/nextjs.ts +0 -19
  270. package/src/plugins/plugins/vite.ts +0 -10
  271. package/src/plugins/plugins/vitest.ts +0 -9
  272. package/src/prompt/prompt-runtime.ts +0 -380
  273. package/src/runtime/adaptive-plan.ts +0 -563
  274. package/src/runtime/agent-control.ts +0 -215
  275. package/src/runtime/agent-memory.ts +0 -81
  276. package/src/runtime/agent-observability.ts +0 -122
  277. package/src/runtime/anchor-manager.ts +0 -475
  278. package/src/runtime/async-marker.ts +0 -32
  279. package/src/runtime/async-runner.ts +0 -381
  280. package/src/runtime/attention-events.ts +0 -28
  281. package/src/runtime/auto-summarize.ts +0 -344
  282. package/src/runtime/background-runner.ts +0 -837
  283. package/src/runtime/batch-barrier.ts +0 -147
  284. package/src/runtime/broker-issuer.ts +0 -37
  285. package/src/runtime/cancellation-token.ts +0 -99
  286. package/src/runtime/cancellation.ts +0 -99
  287. package/src/runtime/capability-inventory.ts +0 -137
  288. package/src/runtime/chain-parser.ts +0 -237
  289. package/src/runtime/chain-runner.ts +0 -606
  290. package/src/runtime/checkpoint.ts +0 -291
  291. package/src/runtime/child-pi-constants.ts +0 -42
  292. package/src/runtime/child-pi-kill.ts +0 -180
  293. package/src/runtime/child-pi-pool.ts +0 -68
  294. package/src/runtime/child-pi-spawn.ts +0 -287
  295. package/src/runtime/child-pi-steering.ts +0 -128
  296. package/src/runtime/child-pi-streams.ts +0 -296
  297. package/src/runtime/child-pi-transcript.ts +0 -169
  298. package/src/runtime/child-pi.ts +0 -1105
  299. package/src/runtime/coalesce-tasks.ts +0 -268
  300. package/src/runtime/code-summary.ts +0 -292
  301. package/src/runtime/command-trace.ts +0 -105
  302. package/src/runtime/compact-pipeline.ts +0 -56
  303. package/src/runtime/compact-stages/ansi-strip-stage.ts +0 -25
  304. package/src/runtime/compact-stages/blank-collapse-stage.ts +0 -31
  305. package/src/runtime/compact-stages/deduplicate-stage.ts +0 -34
  306. package/src/runtime/compact-stages/head-snap-stage.ts +0 -57
  307. package/src/runtime/compact-stages/index.ts +0 -23
  308. package/src/runtime/compact-stages/tail-capture-stage.ts +0 -77
  309. package/src/runtime/compact-stages/truncation-stage.ts +0 -74
  310. package/src/runtime/compaction-summary.ts +0 -278
  311. package/src/runtime/completion-guard.ts +0 -207
  312. package/src/runtime/concurrency.ts +0 -58
  313. package/src/runtime/crash-classification.ts +0 -229
  314. package/src/runtime/crash-recovery.ts +0 -577
  315. package/src/runtime/crew-agent-records.ts +0 -593
  316. package/src/runtime/crew-agent-runtime.ts +0 -62
  317. package/src/runtime/crew-broker-child.ts +0 -88
  318. package/src/runtime/crew-broker-client.ts +0 -673
  319. package/src/runtime/crew-broker-tokens.ts +0 -84
  320. package/src/runtime/crew-broker.ts +0 -1276
  321. package/src/runtime/crew-hooks.ts +0 -227
  322. package/src/runtime/cross-extension-rpc.ts +0 -143
  323. package/src/runtime/custom-tools/irc-tool.ts +0 -282
  324. package/src/runtime/custom-tools/submit-result-tool.ts +0 -102
  325. package/src/runtime/deadletter.ts +0 -47
  326. package/src/runtime/delivery-coordinator.ts +0 -211
  327. package/src/runtime/delta-conflict.ts +0 -348
  328. package/src/runtime/deterministic-ast.ts +0 -161
  329. package/src/runtime/diagnostic-export.ts +0 -171
  330. package/src/runtime/direct-run.ts +0 -45
  331. package/src/runtime/dwf-state-store.ts +0 -102
  332. package/src/runtime/dynamic-workflow-context.ts +0 -1016
  333. package/src/runtime/dynamic-workflow-runner.ts +0 -310
  334. package/src/runtime/effectiveness.ts +0 -90
  335. package/src/runtime/errors/crew-errors.ts +0 -162
  336. package/src/runtime/event-stream-bridge.ts +0 -98
  337. package/src/runtime/foreground-control.ts +0 -193
  338. package/src/runtime/foreground-watchdog.ts +0 -132
  339. package/src/runtime/global-worker-cap.ts +0 -96
  340. package/src/runtime/goal-achievement.ts +0 -148
  341. package/src/runtime/goal-evaluator.ts +0 -361
  342. package/src/runtime/goal-loop-runner.ts +0 -828
  343. package/src/runtime/goal-state-store.ts +0 -219
  344. package/src/runtime/green-contract.ts +0 -55
  345. package/src/runtime/group-join.ts +0 -267
  346. package/src/runtime/handoff-manager.ts +0 -598
  347. package/src/runtime/heartbeat-gradient.ts +0 -36
  348. package/src/runtime/heartbeat-watcher.ts +0 -239
  349. package/src/runtime/hidden-handoff.ts +0 -407
  350. package/src/runtime/important-line-classifier.ts +0 -140
  351. package/src/runtime/intercom-bridge.ts +0 -187
  352. package/src/runtime/iteration-hooks.ts +0 -305
  353. package/src/runtime/live-agent-control.ts +0 -136
  354. package/src/runtime/live-agent-manager.ts +0 -704
  355. package/src/runtime/live-control-realtime.ts +0 -56
  356. package/src/runtime/live-extension-bridge.ts +0 -148
  357. package/src/runtime/live-irc.ts +0 -97
  358. package/src/runtime/live-session-health.ts +0 -108
  359. package/src/runtime/live-session-runtime.ts +0 -1139
  360. package/src/runtime/loop-gates.ts +0 -128
  361. package/src/runtime/manifest-cache.ts +0 -375
  362. package/src/runtime/mcp-proxy.ts +0 -105
  363. package/src/runtime/metric-parser.ts +0 -36
  364. package/src/runtime/model-fallback.ts +0 -409
  365. package/src/runtime/model-resolver.ts +0 -126
  366. package/src/runtime/model-scope.ts +0 -158
  367. package/src/runtime/orphan-worker-registry.ts +0 -465
  368. package/src/runtime/output-validator.ts +0 -202
  369. package/src/runtime/overflow-recovery.ts +0 -206
  370. package/src/runtime/parallel-research.ts +0 -68
  371. package/src/runtime/parallel-utils.ts +0 -160
  372. package/src/runtime/parent-guard.ts +0 -134
  373. package/src/runtime/path-overlap.ts +0 -150
  374. package/src/runtime/peer-dep.ts +0 -292
  375. package/src/runtime/per-write-validator.ts +0 -181
  376. package/src/runtime/phase-progress.ts +0 -217
  377. package/src/runtime/phase-tracker.ts +0 -385
  378. package/src/runtime/pi-args.ts +0 -655
  379. package/src/runtime/pi-json-output.ts +0 -170
  380. package/src/runtime/pi-spawn.ts +0 -273
  381. package/src/runtime/pipeline-runner.ts +0 -523
  382. package/src/runtime/plan-templates.ts +0 -201
  383. package/src/runtime/policy-engine.ts +0 -115
  384. package/src/runtime/post-checks.ts +0 -142
  385. package/src/runtime/post-exit-stdio-guard.ts +0 -104
  386. package/src/runtime/process-lifecycle.ts +0 -491
  387. package/src/runtime/process-status.ts +0 -154
  388. package/src/runtime/progress-event-coalescer.ts +0 -44
  389. package/src/runtime/progress-tracker.ts +0 -124
  390. package/src/runtime/prose-compressor.ts +0 -162
  391. package/src/runtime/recovery-recipes.ts +0 -203
  392. package/src/runtime/replace.ts +0 -570
  393. package/src/runtime/resilient-edit.ts +0 -153
  394. package/src/runtime/result-extractor.ts +0 -213
  395. package/src/runtime/retry-executor.ts +0 -100
  396. package/src/runtime/retry-runner.ts +0 -336
  397. package/src/runtime/role-permission.ts +0 -59
  398. package/src/runtime/run-coalesced-task-group.ts +0 -308
  399. package/src/runtime/run-drift.ts +0 -219
  400. package/src/runtime/run-tracker.ts +0 -116
  401. package/src/runtime/runtime-policy.ts +0 -29
  402. package/src/runtime/runtime-resolver.ts +0 -172
  403. package/src/runtime/runtime-warmup.ts +0 -160
  404. package/src/runtime/scheduler.ts +0 -353
  405. package/src/runtime/semaphore.ts +0 -141
  406. package/src/runtime/sensitive-paths.ts +0 -93
  407. package/src/runtime/session-resources.ts +0 -25
  408. package/src/runtime/session-snapshot.ts +0 -59
  409. package/src/runtime/session-usage.ts +0 -79
  410. package/src/runtime/settings-store.ts +0 -155
  411. package/src/runtime/sidechain-output.ts +0 -35
  412. package/src/runtime/single-agent-compose.ts +0 -84
  413. package/src/runtime/skill-effectiveness.ts +0 -524
  414. package/src/runtime/skill-instructions.ts +0 -391
  415. package/src/runtime/stale-reconciler.ts +0 -680
  416. package/src/runtime/stream-preview.ts +0 -184
  417. package/src/runtime/streaming-output.ts +0 -50
  418. package/src/runtime/subagent-manager.ts +0 -561
  419. package/src/runtime/subprocess-tool-registry.ts +0 -70
  420. package/src/runtime/supervisor-contact.ts +0 -64
  421. package/src/runtime/task-display.ts +0 -52
  422. package/src/runtime/task-graph-scheduler.ts +0 -227
  423. package/src/runtime/task-graph.ts +0 -290
  424. package/src/runtime/task-health.ts +0 -83
  425. package/src/runtime/task-id.ts +0 -161
  426. package/src/runtime/task-output-context.ts +0 -602
  427. package/src/runtime/task-packet.ts +0 -268
  428. package/src/runtime/task-quality.ts +0 -199
  429. package/src/runtime/task-runner/capabilities.ts +0 -78
  430. package/src/runtime/task-runner/context-retrieval.ts +0 -163
  431. package/src/runtime/task-runner/live-executor.ts +0 -227
  432. package/src/runtime/task-runner/output-splitter.ts +0 -152
  433. package/src/runtime/task-runner/progress.ts +0 -157
  434. package/src/runtime/task-runner/prompt-builder.ts +0 -278
  435. package/src/runtime/task-runner/prompt-pipeline.ts +0 -88
  436. package/src/runtime/task-runner/result-utils.ts +0 -16
  437. package/src/runtime/task-runner/retrieval-orchestrator.ts +0 -310
  438. package/src/runtime/task-runner/run-projection.ts +0 -125
  439. package/src/runtime/task-runner/state-helpers.ts +0 -176
  440. package/src/runtime/task-runner/tail-read.ts +0 -34
  441. package/src/runtime/task-runner.ts +0 -1420
  442. package/src/runtime/team-runner-artifacts.ts +0 -13
  443. package/src/runtime/team-runner.ts +0 -1993
  444. package/src/runtime/tool-output-pruner.ts +0 -333
  445. package/src/runtime/tool-progress.ts +0 -278
  446. package/src/runtime/usage-tracker.ts +0 -73
  447. package/src/runtime/verification-gates.ts +0 -571
  448. package/src/runtime/verification-integrity.ts +0 -105
  449. package/src/runtime/verification-worktree.ts +0 -186
  450. package/src/runtime/worker-heartbeat.ts +0 -25
  451. package/src/runtime/worker-startup.ts +0 -83
  452. package/src/runtime/workflow-state.ts +0 -195
  453. package/src/runtime/workspace-lock.ts +0 -443
  454. package/src/runtime/workspace-tree.ts +0 -312
  455. package/src/runtime/yield-handler.ts +0 -224
  456. package/src/runtime/zombie-scanner.ts +0 -298
  457. package/src/schema/config-schema.ts +0 -327
  458. package/src/schema/team-tool-schema.ts +0 -415
  459. package/src/schema/validation-types.ts +0 -159
  460. package/src/skills/discover-skills.ts +0 -197
  461. package/src/skills/skill-templates.ts +0 -456
  462. package/src/skills/validate.ts +0 -285
  463. package/src/state/active-run-registry.ts +0 -439
  464. package/src/state/artifact-store.ts +0 -176
  465. package/src/state/atomic-write.ts +0 -903
  466. package/src/state/blob-store.ts +0 -308
  467. package/src/state/contracts.ts +0 -158
  468. package/src/state/crew-init.ts +0 -269
  469. package/src/state/decision-ledger.ts +0 -345
  470. package/src/state/event-log-rotation.ts +0 -342
  471. package/src/state/event-log.ts +0 -1311
  472. package/src/state/event-reconstructor.ts +0 -229
  473. package/src/state/gitignore-manager.ts +0 -46
  474. package/src/state/health-store.ts +0 -79
  475. package/src/state/hook-instinct-bridge.ts +0 -94
  476. package/src/state/hook-integrations.ts +0 -51
  477. package/src/state/instinct-store.ts +0 -275
  478. package/src/state/jsonl-writer.ts +0 -107
  479. package/src/state/locks.ts +0 -562
  480. package/src/state/mailbox.ts +0 -916
  481. package/src/state/observation-store.ts +0 -176
  482. package/src/state/run-cache.ts +0 -193
  483. package/src/state/run-graph.ts +0 -183
  484. package/src/state/run-metrics.ts +0 -165
  485. package/src/state/schedule.ts +0 -166
  486. package/src/state/session-state-map.ts +0 -51
  487. package/src/state/state-store.ts +0 -958
  488. package/src/state/task-claims.ts +0 -61
  489. package/src/state/tiered-eval.ts +0 -480
  490. package/src/state/types-eval.ts +0 -58
  491. package/src/state/types.ts +0 -440
  492. package/src/state/usage.ts +0 -138
  493. package/src/state/worker-atomic-writer.ts +0 -194
  494. package/src/subagents/async-entry.ts +0 -1
  495. package/src/subagents/index.ts +0 -3
  496. package/src/subagents/live/control.ts +0 -1
  497. package/src/subagents/live/manager.ts +0 -1
  498. package/src/subagents/live/realtime.ts +0 -1
  499. package/src/subagents/live/session-runtime.ts +0 -1
  500. package/src/subagents/manager.ts +0 -1
  501. package/src/subagents/spawn.ts +0 -1
  502. package/src/teams/discover-teams.ts +0 -187
  503. package/src/teams/team-config.ts +0 -27
  504. package/src/teams/team-serializer.ts +0 -38
  505. package/src/tools/safe-bash-extension.ts +0 -54
  506. package/src/tools/safe-bash.ts +0 -505
  507. package/src/types/diff.d.ts +0 -18
  508. package/src/types/new-api-types.ts +0 -35
  509. package/src/ui/agent-management-overlay.ts +0 -160
  510. package/src/ui/card-colors.ts +0 -139
  511. package/src/ui/crew-footer.ts +0 -102
  512. package/src/ui/crew-select-list.ts +0 -111
  513. package/src/ui/dashboard-panes/agents-pane.ts +0 -164
  514. package/src/ui/dashboard-panes/cancellation-pane.ts +0 -66
  515. package/src/ui/dashboard-panes/capability-pane.ts +0 -77
  516. package/src/ui/dashboard-panes/health-pane.ts +0 -31
  517. package/src/ui/dashboard-panes/mailbox-pane.ts +0 -35
  518. package/src/ui/dashboard-panes/metrics-pane.ts +0 -37
  519. package/src/ui/dashboard-panes/progress-pane.ts +0 -38
  520. package/src/ui/dashboard-panes/transcript-pane.ts +0 -10
  521. package/src/ui/deploy-bundled-themes.ts +0 -71
  522. package/src/ui/dwf-phase-display.ts +0 -151
  523. package/src/ui/dynamic-border.ts +0 -35
  524. package/src/ui/heartbeat-aggregator.ts +0 -74
  525. package/src/ui/key-utils.ts +0 -42
  526. package/src/ui/keybinding-map.ts +0 -248
  527. package/src/ui/layout-primitives.ts +0 -106
  528. package/src/ui/live-conversation-overlay.ts +0 -183
  529. package/src/ui/live-duration.ts +0 -55
  530. package/src/ui/live-run-sidebar.ts +0 -293
  531. package/src/ui/loaders.ts +0 -6
  532. package/src/ui/mascot.ts +0 -449
  533. package/src/ui/overlays/agent-picker-overlay.ts +0 -65
  534. package/src/ui/overlays/confirm-overlay.ts +0 -60
  535. package/src/ui/overlays/help-overlay.ts +0 -177
  536. package/src/ui/overlays/mailbox-compose-overlay.ts +0 -181
  537. package/src/ui/overlays/mailbox-compose-preview.ts +0 -78
  538. package/src/ui/overlays/mailbox-detail-overlay.ts +0 -154
  539. package/src/ui/pi-ui-compat.ts +0 -68
  540. package/src/ui/powerbar-publisher.ts +0 -459
  541. package/src/ui/render-coalescer.ts +0 -101
  542. package/src/ui/render-diff.ts +0 -160
  543. package/src/ui/render-scheduler.ts +0 -278
  544. package/src/ui/run-action-dispatcher.ts +0 -182
  545. package/src/ui/run-dashboard.ts +0 -904
  546. package/src/ui/run-event-bus.ts +0 -381
  547. package/src/ui/run-snapshot-cache.ts +0 -1057
  548. package/src/ui/settings-overlay.ts +0 -1067
  549. package/src/ui/shared-overlay-scheduler.ts +0 -96
  550. package/src/ui/snapshot-types.ts +0 -90
  551. package/src/ui/spinner.ts +0 -17
  552. package/src/ui/status-colors.ts +0 -143
  553. package/src/ui/syntax-highlight.ts +0 -136
  554. package/src/ui/terminal-status.ts +0 -269
  555. package/src/ui/theme-adapter.ts +0 -271
  556. package/src/ui/theme-discovery.ts +0 -199
  557. package/src/ui/tool-progress-formatter.ts +0 -93
  558. package/src/ui/tool-render.ts +0 -453
  559. package/src/ui/tool-renderers/brief-mode.ts +0 -225
  560. package/src/ui/tool-renderers/index.ts +0 -726
  561. package/src/ui/transcript-cache.ts +0 -128
  562. package/src/ui/transcript-entries.ts +0 -256
  563. package/src/ui/transcript-viewer.ts +0 -424
  564. package/src/ui/widget/index.ts +0 -391
  565. package/src/ui/widget/widget-formatters.ts +0 -182
  566. package/src/ui/widget/widget-model.ts +0 -110
  567. package/src/ui/widget/widget-renderer.ts +0 -182
  568. package/src/ui/widget/widget-types.ts +0 -36
  569. package/src/utils/bm25-search.ts +0 -235
  570. package/src/utils/completion-dedupe.ts +0 -63
  571. package/src/utils/conflict-detect.ts +0 -668
  572. package/src/utils/env-allowlist.ts +0 -30
  573. package/src/utils/env-filter.ts +0 -155
  574. package/src/utils/file-coalescer.ts +0 -98
  575. package/src/utils/fingerprint.ts +0 -180
  576. package/src/utils/frontmatter.ts +0 -70
  577. package/src/utils/fs-watch.ts +0 -37
  578. package/src/utils/gh-protocol.ts +0 -556
  579. package/src/utils/git.ts +0 -260
  580. package/src/utils/guards.ts +0 -107
  581. package/src/utils/ids.ts +0 -24
  582. package/src/utils/incremental-reader.ts +0 -220
  583. package/src/utils/internal-error.ts +0 -10
  584. package/src/utils/names.ts +0 -36
  585. package/src/utils/ndjson.ts +0 -115
  586. package/src/utils/paths.ts +0 -227
  587. package/src/utils/project-detector.ts +0 -160
  588. package/src/utils/redaction.ts +0 -347
  589. package/src/utils/resolve-shell.ts +0 -36
  590. package/src/utils/run-watcher-registry.ts +0 -152
  591. package/src/utils/safe-paths.ts +0 -383
  592. package/src/utils/scan-cache.ts +0 -144
  593. package/src/utils/session-utils.ts +0 -110
  594. package/src/utils/sleep.ts +0 -54
  595. package/src/utils/socket-path.ts +0 -127
  596. package/src/utils/sse-parser.ts +0 -129
  597. package/src/utils/task-name-generator.ts +0 -337
  598. package/src/utils/timings.ts +0 -33
  599. package/src/utils/token-counter.ts +0 -200
  600. package/src/utils/visual.ts +0 -207
  601. package/src/workflows/cost-estimator.ts +0 -34
  602. package/src/workflows/discover-workflows.ts +0 -290
  603. package/src/workflows/intermediate-store.ts +0 -166
  604. package/src/workflows/preflight-validator.ts +0 -168
  605. package/src/workflows/topology-analyzer.ts +0 -203
  606. package/src/workflows/validate-workflow.ts +0 -50
  607. package/src/workflows/workflow-config.ts +0 -70
  608. package/src/workflows/workflow-serializer.ts +0 -32
  609. package/src/worktree/branch-freshness.ts +0 -112
  610. package/src/worktree/cleanup.ts +0 -341
  611. package/src/worktree/worktree-manager.ts +0 -1200
@@ -1,948 +0,0 @@
1
- # pi-crew Performance Audit Report — 2026-07-11
2
-
3
- > **Scope**: Multi-agent orchestration runtime (task execution pipeline, memory management, I/O operations, prompt construction, concurrency patterns)
4
- > **Target**: pi-crew v0.9.x runtime (`src/runtime/`, `src/state/`, `src/utils/`)
5
- > **Status**: Analysis complete — 26 findings (6 CRITICAL/HIGH, 13 MEDIUM, 7 LOW); 6 previously-documented issues confirmed fixed; 9 new findings identified
6
- >
7
- > **Update 2026-07-11 (post-bench)**: Phase 1 shipped (NEW-M1, A1-F7, A4-F1) + NEW-C3 correctness fix shipped. **A5-C2 disproven by benchmark** (`test/bench/terminal-persist-blocking.bench.ts`): contentionRatio ≈ 0.93–0.98 across 4 runs proves NO lock contention exists between concurrent task completions (sync critical sections serialize naturally in the single-threaded event loop). The claimed 200–800ms impact does not occur. See §7 — Benchmark Findings.
8
-
9
- ---
10
-
11
- ## 1. Executive Summary
12
-
13
- ### Key Metrics
14
-
15
- | Metric | Value | Source |
16
- |--------|-------|--------|
17
- | Total findings | 26 | This audit |
18
- | CRITICAL/HIGH severity | 6 | — |
19
- | MEDIUM severity | 13 | — |
20
- | LOW severity | 7 | — |
21
- | Previously documented (confirmed fixed) | 6 | `docs/perf/performance-review-2026-07.md` |
22
- | New findings (not in prior docs) | 9 | This audit |
23
- | Files analyzed | ~45 | `src/runtime/`, `src/state/`, `src/utils/` |
24
-
25
- ### Top 5 Impact Findings
26
-
27
- | Priority | Finding | Category | Estimated Impact | Risk |
28
- |----------|---------|----------|------------------|------|
29
- | **P0** | `saveRunManifest` write-write race (NEW-C3) | Concurrency | Silent artifact loss | ✅ **FIXED** (commit a03d244) |
30
- | **P1** | `persistSingleTaskUpdate` sync lock blocks event loop (A5-C2) | Concurrency | 200–800ms/4-parallel batch | ❌ **DISPROVEN** — no contention (ratio 0.93–0.98) |
31
- | **P2** | Sync `saveRunManifest` per task completion (A1-F14) | I/O | 100–1000ms total/run | HIGH (open) |
32
- | **P3** | Stable prefix recomputed per parallel task (NEW-M1) | Prompt/I/O | 200–800ms/4-tasks | ✅ **FIXED** (commit 08d1a64) |
33
- | **P4** | Redundant skill compaction on cache hit (A4-F1) | Prompt | ~15% skill rendering waste | ✅ **FIXED** (commit 08d1a64) |
34
-
35
- ### Findings Fixed Since Prior Review
36
-
37
- Cross-referencing against `docs/perf/performance-review-2026-07.md` (F1–F21) and `docs/perf/optimization-plan-2026-07-verified.md`:
38
-
39
- | Finding | Status | Evidence |
40
- |---------|--------|----------|
41
- | **F1** — Global generation counter | ✅ FIXED | `state-store.ts:82` — `Map<string, number>` per-stateRoot |
42
- | **F9** — `rawTextEvents` unbounded | ✅ FIXED | `child-pi.ts:615` — `MAX_RAW_TEXT_EVENTS=2`, ring buffer cap |
43
- | **F12** — `finalDrainMs` hard 5000 | ✅ FIXED | `defaults.ts:8,19` — early-exit on silence |
44
- | **F15** — Discovery cache TTL 500ms | ✅ FIXED | `discover-agents.ts:502` — `DISCOVERY_CACHE_TTL_MS=5000` |
45
- | **F16** — `loadConfig()` no cache | ✅ FIXED | `config.ts:70,86–107` — 2s TTL + mtime cache |
46
- | **F17** — `discoverWorkflows` no cache | ✅ FIXED | `discover-workflows.ts:220–280` — TTL cache + dirStamp |
47
-
48
- ### Still Present (Unfixed)
49
-
50
- | Finding | Docs ID | Status |
51
- |---------|---------|--------|
52
- | Worktree `execFileSync` blocks event loop | F8 | Still present |
53
- | Mailbox delivery-state full rewrite + fsync | F6 | Still present |
54
- | Fsync data+dir unconditional (caller migration pending) | F4 | Partial — option exists |
55
- | Fsync per event (buffering incomplete) | F3 | Partial — only `task.progress` uses buffered path |
56
- | `saveRunTasksCoalesced` still has 0 call sites | F4 | Still present |
57
- | `appendEventBuffered` not wired to other event types | F3 | Still present |
58
- | `isSymlinkSafePath` ancestor walk ×2 per write | F5 | Still present |
59
-
60
- ---
61
-
62
- ## 2. Methodology and Scope
63
-
64
- ### Analysis Scope
65
-
66
- ```
67
- src/runtime/
68
- ├── task-runner/
69
- │ ├── task-runner.ts # Core task execution
70
- │ ├── prompt-builder.ts # Prompt construction
71
- │ ├── state-helpers.ts # Task state persistence
72
- │ ├── tail-read.ts # Transcript reads
73
- │ ├── progress.ts # Progress tracking
74
- │ └── path-overlap.ts # Write overlap detection
75
- ├── team-runner.ts # Orchestration loop
76
- ├── child-pi.ts # Worker spawning
77
- ├── skill-instructions.ts # Skill rendering
78
- ├── tool-output-pruner.ts # Staleness pruning
79
- ├── usage-tracker.ts # Usage tracking
80
- ├── task-graph-scheduler.ts # Task scheduling
81
- └── event-log.ts # Event append
82
-
83
- src/state/
84
- ├── state-store.ts # Manifest persistence
85
- ├── locks.ts # Run locking
86
- ├── atomic-write.ts # Safe file writes
87
- └── event-log.ts # Event logging
88
-
89
- src/utils/
90
- ├── token-counter.ts # Token estimation
91
- └── incremental-reader.ts # Efficient reads
92
-
93
- src/extension/
94
- └── knowledge-injection.ts # Knowledge fragment injection
95
- ```
96
-
97
- ### Verification Methods
98
-
99
- 1. **Source inspection**: All file:line references verified directly against source
100
- 2. **Cross-reference**: Compared against `docs/perf/performance-review-2026-07.md`, `docs/perf/optimization-plan-2026-07-verified.md`, `docs/perf/sprint-7-report.md`
101
- 3. **Current state verification**: grep/read on key files confirming fix status
102
-
103
- ### Impact Estimation Methodology
104
-
105
- | Impact Level | Criteria |
106
- |--------------|----------|
107
- | **CRITICAL** | Correctness bug (data loss, corruption, race condition) |
108
- | **HIGH** | >100ms per-run impact OR affects all runs |
109
- | **MEDIUM** | 10–100ms per-run impact OR affects most runs |
110
- | **LOW** | <10ms per-run impact OR rare case |
111
-
112
- ---
113
-
114
- ## 3. Findings by Category
115
-
116
- ### 3.1 Concurrency
117
-
118
- #### [NEW-C3] — `saveRunManifest` called without run lock (CRITICAL)
119
-
120
- **Severity**: CRITICAL
121
- **Impact**: Silent artifact loss in parallel batches; potential manifest corruption
122
- **File**: `src/runtime/task-runner.ts:1193`
123
-
124
- ```typescript
125
- // PROBLEM: Direct call without lock
126
- await writeArtifact(...); // 15 artifacts written
127
- saveRunManifest(manifest); // ← No withRunLock here!
128
- ```
129
-
130
- **Root Cause**: Task-runner writes manifest directly after `writeArtifact` calls. The team-runner's merge path at `team-runner.ts:1454` calls `saveRunManifestAsync` inside `withRunLock`. Race condition:
131
-
132
- 1. Worker A writes manifest with artifact A → Worker B writes manifest with artifact B → team-runner reads disk (stale) → team-runner overwrites both
133
-
134
- **Risk Assessment**: HIGH — correctness bug, not just perf. Could cause missing artifacts in parallel batches.
135
-
136
- **Recommendation**:
137
- - Option A: Add `withRunLock` around task-runner's manifest write
138
- - Option B: Skip per-task manifest write entirely, rely on team-runner's batch merge
139
-
140
- ---
141
-
142
- #### [NEW-C6] — Double lock acquisition in post-batch merge path
143
-
144
- > **⛔ VERDICT (2026-07-11): WONTFIX — read is NECESSARY (orphan-artifact recovery); no double lock exists.**
145
- > Two audit claims verified false: (1) **No double lock** — `saveRunManifestAsync`
146
- > and `saveRunTasksAsync` (called inside the merge's `withRunLock`) do NOT
147
- > re-acquire the lock, so there is no nested/double acquisition. (2) The disk
148
- > read is **not redundant** — it recovers **orphan artifacts** from workers that
149
- > persisted via `saveRunManifest` then threw before returning (so they're absent
150
- > from `validResults`). Those artifacts exist only on disk; skipping the read
151
- > would silently lose them. (`mergeArtifacts` dedupes by path, so the read is a
152
- > strict union, never a duplicate-counting hazard.) The read runs once per batch
153
- > (batches are minutes apart). The recommended sequence-number tagging would
154
- > **regress correctness** (lose orphan artifacts) — do not apply.
155
-
156
- **Severity**: ~~HIGH~~ → **WONTFIX (re-evaluated)**
157
- **Impact**: ~~10–50ms per merge × batch count~~ → **~15–50ms once per batch (minutes apart); defensively correct**
158
- **File**: `src/runtime/team-runner.ts:1471`
159
-
160
- ```typescript
161
- // PROBLEM: Async lock + disk read after sync locks already committed
162
- await withRunLock(runId, async () => {
163
- const manifest = await loadRunManifestById(...); // Redundant read
164
- // Merge task updates...
165
- });
166
- ```
167
-
168
- **Root Cause**: `persistSingleTaskUpdate` uses `withRunLockSync` (sync) and commits state. The async merge path re-reads from disk even though workers already persisted.
169
-
170
- **Risk Assessment**: MEDIUM — correctness is safe, but performance is wasted.
171
-
172
- **Recommendation**: Sequence-number tagging approach — each manifest write carries a monotonic sequence number. Merge skips disk read for workers with higher sequence numbers.
173
-
174
- ---
175
-
176
- #### [A5-C2] — `persistSingleTaskUpdate` sync lock blocks event loop
177
-
178
- > **⛔ VERDICT (2026-07-11): DISPROVEN — do not apply.** A dedicated benchmark
179
- > (`test/bench/terminal-persist-blocking.bench.ts`, 4 runs) measured
180
- > **contentionRatio 0.93–0.98** (≈1.0), proving there is **NO lock contention**
181
- > between concurrent task completions. The original impact estimate was based
182
- > on an incorrect concurrency model (see §7). The per-completion cost is a
183
- > single ~30ms sync block, spread over time in real runs — not a concentrated
184
- > 200–800ms block. The async conversion (11+ call sites + `checkpointTask`
185
- > ripple) would relieve contention that does not exist, at real deadlock risk.
186
-
187
- **Severity**: ~~HIGH~~ → **WONTFIX (disproven)**
188
- **Impact**: ~~200–800ms total wait time for 4-way parallel completion~~ → **~30ms p50 per completion, no inter-completion contention**
189
- **File**: `src/runtime/task-runner/state-helpers.ts:36–112`
190
-
191
- ```typescript
192
- // PROBLEM: Synchronous lock with event-loop blocking
193
- return withRunLockSync(manifest, () => {
194
- retryLoop: for (let attempt = 0; attempt < 100; attempt++) {
195
- const latest = loadRunManifestById(...); // Full state reload
196
- // ... 3x statSync mtime checks ...
197
- ```
198
-
199
- **Root Cause**: `withRunLockSync` uses `sleepSync` (`Atomics.wait`) which blocks the event loop. When 4 tasks complete simultaneously, they serialize on the lock.
200
-
201
- **Recommendation**: Convert to async `withRunLock` instead of `withRunLockSync`. The CAS loop can remain (protects against unlocked writers like `async-notifier.ts:54`).
202
-
203
- ---
204
-
205
- #### [A5-C4] — `loadRunManifestById` called inside retry loop without lock
206
-
207
- > **⛔ VERDICT (2026-07-11): WONTFIX — fully backstopped by the signal mechanism (verified end-to-end).**
208
- > Traced the cancel → retry path completely. The unlocked disk read is a
209
- > best-effort FIRST check, but two stronger guards backstop it: (1) `runTeamTask`
210
- > checks `input.signal?.aborted` at its **start** (`task-runner.ts:168`) and
211
- > returns a cancelled task **without spawning the worker**; (2) the retry loop
212
- > checks `input.signal?.aborted` (`team-runner.ts:1404`). The signal IS aborted
213
- > on user cancel — verified chain: `handleCancel` → `abortForegroundRun(runId)`
214
- > → `controller.abort()` on the EXACT controller from `startForegroundRun`
215
- > (register.ts:1413) → whose signal is passed as `executeTeamRun({signal})`
216
- > (run.ts:864). So even a 100%-stale disk read cannot produce a zombie: the
217
- > worker never runs. Background runs are killed via `killProcessPid`. The only
218
- > theoretical gap (cancel-without-signal-abort, e.g. in-process cascade) is
219
- > coordinated within the same event loop and unreachable in practice.
220
-
221
- **Severity**: ~~MEDIUM~~ → **WONTFIX (backstopped by signal.aborted)**
222
- **Impact**: ~~Low-probability zombie task~~ → **No zombie: runTeamTask:168 catches signal.aborted before worker spawn**
223
- **File**: `src/runtime/team-runner.ts:1296` (retry closure)
224
-
225
- ```typescript
226
- // PROBLEM: No lock around manifest read in retry loop
227
- const freshTask = fresh?.tasks[taskId];
228
- if (freshTask.status !== "queued" && freshTask.status !== "running") {
229
- // Task was cancelled between retry attempts
230
- ```
231
-
232
- **Recommendation**: Add `withRunLock` around retry loop, or rely on atomic-write rename safety with explicit comment.
233
-
234
- ---
235
-
236
- #### [A5-C8] — `filterReadyByWriteOverlap` greedy algorithm suboptimal
237
-
238
- **Severity**: MEDIUM
239
- **Impact**: Suboptimal task selection when enabled → unused parallelism slot
240
- **File**: `src/runtime/path-overlap.ts:76–108`
241
-
242
- ```typescript
243
- // PROBLEM: Greedy first-fit — doesn't optimize for maximum parallelism
244
- const ready = tasks.filter(t => !conflictSet.has(t.id));
245
- return ready[0]; // Always picks first non-conflicting task
246
- ```
247
-
248
- **Recommendation**: Sort by priority/conflict-count and pick tasks with fewest conflicts first. (Current behavior may be acceptable given `enabled: false` by default.)
249
-
250
- ---
251
-
252
- #### [A5-C12] — `appendEventAsync` promise chain grows unbounded
253
-
254
- **Severity**: MEDIUM
255
- **Impact**: ~150–750ms total serialization across run (150 events × 1–5ms)
256
- **File**: `src/state/event-log.ts:453–462`
257
-
258
- ```typescript
259
- // PROBLEM: Promise chain grows to 150+ deep
260
- appendEventAsync(event) {
261
- return prev.then(() => doAppend(event));
262
- }
263
- ```
264
-
265
- **Recommendation**: Batch events within a batch — collect and write in single `appendFile` call at batch end.
266
-
267
- ---
268
-
269
- #### [A1-F13] — `backpressureBytes` counter never resets on pause
270
-
271
- **Severity**: LOW
272
- **Impact**: Only affects very chatty workers (rare)
273
- **File**: `src/runtime/child-pi.ts:1149–1165`
274
-
275
- ---
276
-
277
- ### 3.2 I/O Operations
278
-
279
- #### [A1-F14] — `saveRunManifest` synchronous call on every task completion
280
-
281
- **Severity**: HIGH
282
- **Impact**: 5–50ms per write × ~20 writes per run = 100–1000ms total
283
- **File**: `src/runtime/task-runner.ts:1168`
284
-
285
- ```typescript
286
- // PROBLEM: Sync write after every task
287
- for (const artifact of artifacts) {
288
- await writeArtifact(artifact.descriptor, artifact.content);
289
- }
290
- saveRunManifest(manifest); // ← Sync, blocks event loop
291
- ```
292
-
293
- **Recommendation**: Fix NEW-C3 first, then replace with async or skip entirely (team-runner batch merge is authoritative).
294
-
295
- ---
296
-
297
- #### [NEW-M1] — Prompt stable prefix recomputed per parallel task
298
-
299
- **Severity**: MEDIUM
300
- **Impact**: ~50–200ms per task × 4 parallel = 200–800ms wasted
301
- **File**: `src/runtime/task-runner/prompt-builder.ts:123–168`
302
-
303
- ```typescript
304
- // PROBLEM: Stable prefix computed independently for each task
305
- async function renderTaskPrompt(task) {
306
- const stablePrefix = await computeStablePrefix(task); // Identical for all 4 parallel tasks
307
- const dynamicSuffix = buildDynamicSuffix(task);
308
- return stablePrefix + dynamicSuffix;
309
- }
310
- ```
311
-
312
- **Root Cause**: In a 4-way parallel batch, all 4 tasks get identical stable prefixes (workspace tree + retrieval + knowledge + skills) computed independently.
313
-
314
- **Recommendation**: Pre-compute stable prefix once per (cwd, role, runId) in team-runner batch loop. `renderTaskPrompt` already separates stablePrefix from dynamicSuffix.
315
-
316
- ---
317
-
318
- #### [NEW-M2] — Skill cache stat on every cache hit
319
-
320
- > **⛔ VERDICT (2026-07-11): WONTFIX — dirStamp is unsafe for content freshness; stat is cheap & correct.**
321
- > The recommended `dirStamp` (parent-directory mtime) optimization is **incorrect**
322
- > for skill *content* freshness: directory mtime changes only on add/remove/rename,
323
- > **not on in-place edits** of a `SKILL.md`. Using it would serve stale skill
324
- > content after an edit — a correctness bug. The current per-file `statSync`
325
- > correctly catches both add/remove and content edits. Actual cost is ~0.3ms per
326
- > stat × ~5 skills × ~4 tasks ≈ ~6ms/batch (stat is far cheaper than the
327
- > 10–80ms estimate, which assumed read+parse cost). Trading correctness for
328
- > negligible speed is not justified.
329
-
330
- **Severity**: ~~MEDIUM~~ → **WONTFIX (re-evaluated; recommended fix is incorrect)**
331
- **Impact**: ~~10–80ms total~~ → **~6ms/batch; stat is ~0.3ms, not read-cost**
332
- **File**: `src/runtime/skill-instructions.ts:155` (`cachedSkillFresh`)
333
-
334
- ```typescript
335
- // PROBLEM: fs.statSync on every cache hit
336
- readSkillMarkdown(skillPath: string): CachedSkillMarkdown {
337
- const cached = skillCache.get(skillPath);
338
- if (cached) {
339
- fs.statSync(skillPath); // ← Redundant stat for freshness
340
- return cached;
341
- }
342
- ```
343
-
344
- **Recommendation**: Use `dirStamp` pattern (like `discover-workflows.ts:222`) — check parent directory mtime instead of each skill file.
345
-
346
- ---
347
-
348
- #### [A1-F5] — `tailReadWithLineSnap` double stat+read per transcript read
349
-
350
- **Severity**: MEDIUM
351
- **Impact**: ~20–80ms per task
352
- **File**: `src/runtime/task-runner/tail-read.ts:11–12`
353
-
354
- ```typescript
355
- // PROBLEM: 2–4 syscalls per call
356
- const stats = fs.statSync(path);
357
- const content = stats.size > 0 ? fs.readFileSync(path, "utf-8") : "";
358
- ```
359
-
360
- **Recommendation**: Use `fs.promises.open` + `fileHandle.stat()` + `fileHandle.read()` to avoid stat+open double-call.
361
-
362
- ---
363
-
364
- #### [A1-F9] — Redundant `fs.mkdirSync` inside model-attempt loop
365
-
366
- **Severity**: LOW
367
- **Impact**: ~0.3ms per task
368
- **File**: `src/runtime/task-runner.ts:411–413`
369
-
370
- **Recommendation**: Hoist `mkdirSync` outside the loop.
371
-
372
- ---
373
-
374
- #### [A1-F12] — Pretty-print JSON in metadata artifacts
375
-
376
- **Severity**: LOW
377
- **Impact**: ~30–50% larger artifact files
378
- **File**: `src/runtime/task-runner.ts:1126–1165`
379
-
380
- **Recommendation**: Use compact JSON for metadata artifacts; keep pretty-print for human-readable manifests only.
381
-
382
- ---
383
-
384
- ### 3.3 Prompt Construction
385
-
386
- #### [A4-F1] — Redundant skill content compaction on cache hit
387
-
388
- **Severity**: HIGH
389
- **Impact**: ~15% of skill rendering time wasted; ~50ms per task for 5 skills
390
- **File**: `src/runtime/skill-instructions.ts:216–230`
391
-
392
- ```typescript
393
- // PROBLEM: Compaction runs even when cache is hit
394
- async function renderSkillInstructions(task) {
395
- const cached = skillCache.get(skillKey);
396
- if (cached) {
397
- const compacted = compactSkillContent(cached.raw); // ← Redundant!
398
- return compacted;
399
- }
400
- ```
401
-
402
- **Recommendation**: Cache the compacted content in `CachedSkillMarkdown` structure: `{ raw, compacted }`. Use `compacted` on cache hit.
403
-
404
- ---
405
-
406
- #### [A4-F3] — Token estimation inaccuracy for code-heavy content
407
-
408
- **Severity**: MEDIUM
409
- **Impact**: 10–15% error → under/over-truncation → wasted context or missing content
410
- **File**: `src/utils/token-counter.ts:49–80`
411
-
412
- ```typescript
413
- // PROBLEM: Underestimates tokens for code
414
- estimateTokens(text: string): number {
415
- const alpha = text.replace(/[^a-zA-Z]/g, "").length;
416
- const punct = text.replace(/[a-zA-Z\s]/g, "").length;
417
- return Math.ceil(alpha / 4) + punct;
418
- }
419
- ```
420
-
421
- **Recommendation**: Use code-aware estimation — code fences as `length * 0.3`, prose as `word_count * 1.3`. Benchmark against `tiktoken` or actual model tokenizer.
422
-
423
- ---
424
-
425
- #### [A4-F4] — Staleness index rebuilds O(N) per pruning call
426
-
427
- **Severity**: MEDIUM
428
- **Impact**: O(N) where N = tool results count. In runs with 200+ results, rebuilding on every pruning call adds up.
429
- **File**: `src/runtime/tool-output-pruner.ts:182–220`
430
-
431
- ```typescript
432
- // PROBLEM: Full rebuild on every call
433
- function pruneToolOutputs(context) {
434
- const index = buildStalenessIndex(context.results); // O(N) every time
435
- // ...
436
- }
437
- ```
438
-
439
- **Recommendation**: Maintain staleness index incrementally; only rebuild from scratch if index becomes inconsistent.
440
-
441
- ---
442
-
443
- #### [A4-F2] — Knowledge section parsing overhead per query
444
-
445
- **Severity**: LOW
446
- **Impact**: ~2–5ms per worker × N workers
447
- **File**: `src/extension/knowledge-injection.ts:114–150`
448
-
449
- **Recommendation**: Cache parsed sections by (mtimeMs, size).
450
-
451
- ---
452
-
453
- ### 3.4 Memory Management
454
-
455
- #### [A1-F7] — `collectedJsonEvents` accumulated but unused for child-process workers
456
-
457
- **Severity**: MEDIUM
458
- **Impact**: ~10KB memory waste per task + allocation/trim cycle
459
- **File**: `src/runtime/task-runner.ts:296, 506–509, 879–882`
460
-
461
- ```typescript
462
- // PROBLEM: Array built up for 100% of child-process tasks, never read
463
- const collectedJsonEvents: ParsedEvent[] = [];
464
-
465
- async function processChildOutput() {
466
- // ...
467
- collectedJsonEvents.push(event); // Accumulates
468
- if (collectedJsonEvents.length > MAX_COLLECTED) {
469
- collectedJsonEvents.splice(0, collectedJsonEvents.length - MAX_COLLECTED);
470
- }
471
- }
472
-
473
- // Only consumed when yieldEnabled === true (live-session only)
474
- if (yieldEnabled) {
475
- yield detection uses collectedJsonEvents; // Never reached for child-process
476
- }
477
- ```
478
-
479
- **Recommendation**: Guard `collectedJsonEvents` accumulation behind `yieldEnabled` check. Only allocate when `yieldEnabled === true`.
480
-
481
- ---
482
-
483
- #### [A2-F1] — `taskUsageMap` global Map lacks auto-cleanup
484
-
485
- > **✅ VERDICT (2026-07-11): leak claim wrong, but quality fix applied.**
486
- > Scrutinized the lifecycle: `trackTaskUsage` is called **only** in the
487
- > live-session path (`live-session-runtime.ts:829`), never for child-process
488
- > workers. `cleanupUsage()` ran in **both** the success path and the error
489
- > path, clearing every task in `input.tasks`. For live-session runs
490
- > `input.task.id ∈ input.tasks`, so entries were reclaimed; hard crashes
491
- > reclaim the Map via GC. So the original 'stale entries accumulate' leak claim
492
- > was **inaccurate**. **However**, cleanup was duplicated outside the `finally`
493
- > block — a future throw could skip both copies. Applied a quality fix
494
- > (commit e1273ab): consolidated `cleanupUsage()` into `finally` so cleanup is
495
- > guaranteed on every exit path (DRY + robustness, consistent with
496
- > `clearStablePrefixCache`). Verified safe: nothing in team-runner reads usage
497
- > after the run resolves, and the TUI widget reads live usage only while a task
498
- > is running.
499
-
500
- **Severity**: ~~MEDIUM~~ → **quality fix applied (leak disproven; cleanup hardened)**
501
- **Impact**: ~~Stale entries accumulate~~ → **no real leak; cleanup now guaranteed on all exit paths**
502
- **File**: `src/runtime/usage-tracker.ts:38` + `team-runner.ts` (consolidated into `finally`)
503
-
504
- ```typescript
505
- // PROBLEM: No TTL-based eviction
506
- const taskUsageMap = new Map<string, TaskUsage>();
507
-
508
- clearTrackedTaskUsage() { // Clears ALL, not just stale
509
- taskUsageMap.clear();
510
- }
511
- ```
512
-
513
- **Recommendation**: Add TTL-based eviction similar to `activeChildProcesses` cleanup pattern in `child-pi.ts:33–42`.
514
-
515
- ---
516
-
517
- #### [A1-F2] — `compactChildPiEvent` creates new objects per stdout line
518
-
519
- **Severity**: LOW
520
- **Impact**: ~250–500ms per task (GC pressure)
521
- **File**: `src/runtime/child-pi.ts:522–580, 583–602, 680–705`
522
-
523
- ```typescript
524
- // PROBLEM: JSON.parse → deep clone → JSON.stringify for every line
525
- for (const line of lines) {
526
- const parsed = JSON.parse(line);
527
- const compacted = compactChildPiEvent(parsed); // Deep clone
528
- compactedLines.push(JSON.stringify(compacted));
529
- }
530
- ```
531
-
532
- **Recommendation**: Skip `compactChildPiEvent` for events under 500 bytes — clone+stringify overhead is disproportionate for small events.
533
-
534
- ---
535
-
536
- #### [A1-F11] — Array copies per event in progress tracking
537
-
538
- **Severity**: LOW
539
- **Impact**: ~20ms per task (allocation pressure)
540
- **File**: `src/runtime/task-runner/progress.ts:107–109`
541
-
542
- ```typescript
543
- // PROBLEM: Array slice creates copy on every event
544
- recentTools: state.recentTools.slice(-10),
545
- recentOutput: state.recentOutput.slice(-5),
546
- ```
547
-
548
- **Recommendation**: Use ring buffer instead of array-slice.
549
-
550
- ---
551
-
552
- ### 3.5 Algorithm / Task Execution
553
-
554
- #### [A1-F3] — `taskGraphSnapshot` multi-pass O(N) → single-pass bucket collection
555
-
556
- **Severity**: MEDIUM
557
- **Impact**: 7 passes (1 map + 6 filters) over task array per scheduling cycle
558
- **File**: `src/runtime/task-graph-scheduler.ts:130–158`
559
-
560
- ```typescript
561
- // PROBLEM: 7 separate passes over tasks
562
- const all = taskArray.map(t => categorize(t)); // Pass 1
563
- const ready = all.filter(t => t.status === "pending"); // Pass 2
564
- const blocked = all.filter(t => isBlocked(t)); // Pass 3
565
- const running = all.filter(t => t.status === "running"); // Pass 4
566
- const done = all.filter(t => isTerminal(t) && !t.failed);// Pass 5
567
- const failed = all.filter(t => isTerminal(t) && t.failed);// Pass 6
568
- const cancelled = all.filter(t => t.status === "cancelled"); // Pass 7
569
- ```
570
-
571
- **Recommendation**: Single O(N) iteration collecting into ready/blocked/running/done/failed/cancelled buckets.
572
-
573
- ---
574
-
575
- #### [A5-C1] — Batch-level serialization: no inter-batch overlap
576
-
577
- **Severity**: MEDIUM
578
- **Impact**: 5–10 minutes per run in DAGs with heterogeneous wave times
579
- **File**: `src/runtime/team-runner.ts:922–1640`
580
-
581
- **Root Cause**: Tasks complete in waves. Wave N+1 doesn't start until ALL Wave N tasks complete, even if Wave N+1 tasks' dependencies were satisfied earlier.
582
-
583
- **Recommendation**: Streaming/continuous dispatch — start Wave N+1 tasks as soon as their specific dependencies complete. (Phase 3 per optimization-plan.)
584
-
585
- ---
586
-
587
- #### [A2-F2] — `MAX_TRACKED_STATES=5000` cap behavior
588
-
589
- **Severity**: LOW
590
- **Impact**: Bounded; acceptable
591
- **File**: `src/runtime/overflow-recovery.ts:34`
592
-
593
- ---
594
-
595
- #### [A1-F15] — `isFinalAssistantEvent` per event check
596
-
597
- **Severity**: LOW
598
- **Impact**: Negligible
599
- **File**: `src/runtime/child-pi.ts:515`
600
-
601
- ---
602
-
603
- ---
604
-
605
- ## 4. Recommendations — Prioritized by Impact/Risk
606
-
607
- ### Immediate (Low Risk, High Impact)
608
-
609
- | # | Finding | Action | Files | Impact |
610
- |---|---------|--------|-------|--------|
611
- | 1 | **NEW-M1** | Pre-compute stable prefix once per (cwd, role, runId) | `prompt-builder.ts`, `team-runner.ts` | 200–800ms/4-tasks |
612
- | 2 | **A1-F7** | Guard `collectedJsonEvents` behind `yieldEnabled` | `task-runner.ts:296` | ~10KB/task |
613
- | 3 | **A4-F1** | Cache compacted skill content as `{ raw, compacted }` | `skill-instructions.ts` | ~15% skill rendering |
614
- | 4 | **A4-F2** | Verify knowledge section cache covers all callers | `knowledge-injection.ts` | 2–5ms/worker |
615
-
616
- ### Short-Term (Medium Risk, High Impact)
617
-
618
- | # | Finding | Action | Files | Impact |
619
- |---|---------|--------|-------|--------|
620
- | 5 | **NEW-C3** | Add `withRunLock` around task-runner manifest write | `task-runner.ts:1193` | Correctness |
621
- | 6 | **A5-C2** | Convert `persistSingleTaskUpdate` to async lock | `state-helpers.ts:36` | 200–800ms/batch |
622
- | 7 | **A4-F3** | Code-aware token estimation | `token-counter.ts:49` | 10–15% accuracy |
623
-
624
- ### Medium-Term (Correctness-Sensitive)
625
-
626
- | # | Finding | Action | Files | Impact |
627
- |---|---------|--------|-------|--------|
628
- | 8 | **NEW-M2** | Use dirStamp for skill cache freshness | `skill-instructions.ts:128` | 10–80ms/batch |
629
- | 9 | **A1-F5** | Async transcript reads with `fs.promises.open` | `tail-read.ts:11` | ~20ms/task |
630
- | 10 | **A5-C4** | Add lock around retry loop manifest read | `team-runner.ts:1254` | Correctness |
631
-
632
- ### Long-Term / Architectural (High Risk, High Reward)
633
-
634
- | # | Finding | Action | Phase | Impact |
635
- |---|---------|--------|-------|--------|
636
- | 11 | **A5-C1** | Streaming dispatch (inter-batch overlap) | Phase 3 | 5–10 min/run |
637
- | 12 | **A5-C12** | Batched event appends | Phase 2 | 150–750ms/run |
638
-
639
- ---
640
-
641
- ## 5. Implementation Roadmap
642
-
643
- ### Phase 0: Baseline Measurement (Bench-First)
644
-
645
- **Before any changes**, establish baselines for the high-impact findings:
646
-
647
- ```bash
648
- # Run existing benchmarks
649
- npm run bench
650
-
651
- # Add new benchmarks for critical paths
652
- npm run bench:persist-single-task # A5-C2
653
- npm run bench:prompt-stable-prefix # NEW-M1
654
- npm run bench:skill-render # A4-F1
655
- ```
656
-
657
- **Target**: Capture p50/p95 before and after each fix. Only proceed if improvement ≥15%.
658
-
659
- ---
660
-
661
- ### Phase 1: Quick Wins (1–2 days)
662
-
663
- #### 1.1 Fix `collectedJsonEvents` waste (A1-F7)
664
- ```typescript
665
- // task-runner.ts
666
- const collectedJsonEvents: ParsedEvent[] | undefined = yieldEnabled ? [] : undefined;
667
-
668
- // When accumulating:
669
- if (collectedJsonEvents) {
670
- collectedJsonEvents.push(event);
671
- if (collectedJsonEvents.length > MAX_COLLECTED) {
672
- collectedJsonEvents.splice(0, collectedJsonEvents.length - MAX_COLLECTED);
673
- }
674
- }
675
- ```
676
-
677
- #### 1.2 Cache compacted skill content (A4-F1)
678
- ```typescript
679
- // skill-instructions.ts
680
- interface CachedSkillMarkdown {
681
- raw: string;
682
- compacted: string; // Add this
683
- mtimeMs: number;
684
- size: number;
685
- }
686
- ```
687
-
688
- #### 1.3 Stable prefix memoization (NEW-M1)
689
- ```typescript
690
- // team-runner.ts — batch loop
691
- const stablePrefixCache = new Map<string, string>();
692
-
693
- // Before spawning batch
694
- for (const task of batch) {
695
- const key = `${task.cwd}|${task.agent.role}|${runId}`;
696
- if (!stablePrefixCache.has(key)) {
697
- stablePrefixCache.set(key, await computeStablePrefix(task));
698
- }
699
- task.stablePrefix = stablePrefixCache.get(key);
700
- }
701
- ```
702
-
703
- ---
704
-
705
- ### Phase 2: Correctness + Performance (3–5 days)
706
-
707
- #### 2.1 Fix `saveRunManifest` lock race (NEW-C3)
708
- ```typescript
709
- // task-runner.ts:1193
710
- await withRunLock(runId, () => saveRunManifestAsync(manifest));
711
- ```
712
-
713
- #### 2.2 Convert `persistSingleTaskUpdate` to async (A5-C2)
714
- ```typescript
715
- // state-helpers.ts
716
- export async function persistSingleTaskUpdateAsync(
717
- manifest: TeamRunManifest,
718
- taskId: string,
719
- update: Partial<TeamTaskState>
720
- ): Promise<void> {
721
- await withRunLock(manifest.runId, async () => {
722
- // Async read + write, single stat on hit
723
- });
724
- }
725
- ```
726
-
727
- #### 2.3 Skill cache dirStamp (NEW-M2)
728
- ```typescript
729
- // skill-instructions.ts
730
- function dirStamp(skillDir: string): string {
731
- try { return fs.statSync(skillDir).mtimeMs.toString(); }
732
- catch { return "0"; }
733
- }
734
- ```
735
-
736
- ---
737
-
738
- ### Phase 3: Architectural (1–2 weeks)
739
-
740
- #### 3.1 Streaming dispatch (A5-C1)
741
- Replace batch loop with continuous dispatch that starts Wave N+1 tasks as soon as their specific dependencies complete.
742
-
743
- #### 3.2 Batched event appends (A5-C12)
744
- Collect events during batch, write once at batch end using `appendFile` batch.
745
-
746
- ---
747
-
748
- ## 6. Validation Strategy
749
-
750
- ### Unit Tests
751
-
752
- | Finding | Test Coverage |
753
- |---------|---------------|
754
- | NEW-C3 | Test that parallel artifact writes don't lose data |
755
- | A5-C2 | Test async lock doesn't deadlock with sync paths |
756
- | A1-F7 | Test `collectedJsonEvents` is `undefined` for child-process |
757
- | A4-F1 | Test compacted content cached correctly |
758
- | NEW-M1 | Test stable prefix identical across parallel tasks |
759
-
760
- ### Integration Tests
761
-
762
- ```bash
763
- # Run full test suite
764
- npm test
765
-
766
- # Run with concurrency
767
- npm run test:parallel
768
-
769
- # Run benchmarks
770
- npm run bench
771
- npm run bench:check # Compare against baseline
772
- ```
773
-
774
- ### Benchmark Metrics
775
-
776
- | Metric | Tool | Baseline | Target |
777
- |--------|------|----------|--------|
778
- | Task completion latency | `bench:persist-single-task` | TBD | <15% improvement |
779
- | Skill rendering time | `bench:skill-render` | TBD | <15% improvement |
780
- | Stable prefix computation | `bench:prompt-stable-prefix` | TBD | <15% improvement |
781
- | Memory per task | `bench:memory` | TBD | <10KB reduction |
782
- | I/O per task | `bench:io` | TBD | <20% reduction |
783
-
784
- ### Performance Regression Guards
785
-
786
- ```bash
787
- # CI: Fail if benchmarks regress >15%
788
- npm run bench:check
789
-
790
- # Pre-commit: Run fast unit tests
791
- npm test
792
- ```
793
-
794
- ---
795
-
796
- ## Appendix A: Findings Summary Table
797
-
798
- | ID | Severity | Category | Finding | Impact | Status | File:Line |
799
- |----|----------|----------|---------|--------|--------|-----------|
800
- | NEW-C3 | **CRITICAL** | Concurrency | `saveRunManifest` no lock — write-write race | Silent artifact loss | **NEW** | task-runner.ts:1193 |
801
- | NEW-C6 | **HIGH** | Concurrency | Double lock + redundant disk read in merge | 10–50ms × batches | **NEW** | team-runner.ts:1450 |
802
- | A5-C2 | **HIGH** | Concurrency | `persistSingleTaskUpdate` sync lock blocks event loop | 200–800ms/4-parallel | **NEW** | state-helpers.ts:36 |
803
- | A4-F1 | **HIGH** | Prompt | Redundant skill compaction on cache hit | ~15% waste | **NEW** | skill-instructions.ts:216 |
804
- | A1-F14 | **HIGH** | I/O | Sync `saveRunManifest` on every task completion | 100–1000ms/run | **NEW** | task-runner.ts:1168 |
805
- | NEW-M1 | MEDIUM | I/O/Prompt | Stable prefix recomputed per parallel task | 200–800ms/4-tasks | **NEW** | prompt-builder.ts:123 |
806
- | NEW-M2 | MEDIUM | I/O | Skill cache stat on every cache hit | 10–80ms/4-tasks | **NEW** | skill-instructions.ts:128 |
807
- | A4-F3 | MEDIUM | Prompt | Token estimation 10–15% error for code | Context waste | **NEW** | token-counter.ts:49 |
808
- | A4-F4 | MEDIUM | Algorithm | Staleness index rebuilds O(N) per pruning | O(N) per call | **NEW** | tool-output-pruner.ts:182 |
809
- | A1-F3 | MEDIUM | Algorithm | taskGraphSnapshot 7 passes → 1 pass | 0.1–0.5ms/cycle | **NEW** | task-graph-scheduler.ts:130 |
810
- | A1-F5 | MEDIUM | I/O | tailReadWithLineSnap double stat+read | ~20ms/task | **NEW** | tail-read.ts:11 |
811
- | A1-F7 | MEDIUM | Memory | collectedJsonEvents unused for child-process | 10KB/task waste | **NEW** | task-runner.ts:296 |
812
- | A5-C4 | MEDIUM | Concurrency | loadRunManifestById retry without lock | Low-prob zombie | **NEW** | team-runner.ts:1254 |
813
- | A5-C8 | MEDIUM | Algorithm | Greedy write-overlap filter suboptimal | Unused slot | **NEW** | path-overlap.ts:76 |
814
- | A5-C12 | MEDIUM | I/O | appendEventAsync promise chain unbounded | 150–750ms/run | **NEW** | event-log.ts:453 |
815
- | A2-F1 | MEDIUM | Memory | taskUsageMap no auto-cleanup | Unbounded growth | **NEW** | usage-tracker.ts:38 |
816
- | A5-C1 | MEDIUM | Architecture | Batch serialization — no inter-batch overlap | 5–10 min/run | **NEW** | team-runner.ts:922 |
817
- | A1-F2 | LOW | GC | compactChildPiEvent object churn per line | 250–500ms/task | **NEW** | child-pi.ts:522 |
818
- | A4-F2 | LOW | Prompt | Knowledge section parsing per query | 2–5ms/worker | **NEW** | knowledge-injection.ts:114 |
819
- | A1-F9 | LOW | I/O | Redundant mkdirSync in attempt loop | 0.3ms/task | **NEW** | task-runner.ts:411 |
820
- | A1-F11 | LOW | Memory | Array copies per event in progress | 20ms/task | **NEW** | progress.ts:107 |
821
- | A1-F12 | LOW | I/O | Pretty-print JSON in metadata artifacts | 30–50% size | **NEW** | task-runner.ts:1126 |
822
- | A1-F13 | LOW | Concurrency | backpressureBytes counter never resets | Minor | **NEW** | child-pi.ts:1149 |
823
- | A1-F15 | LOW | CPU | isFinalAssistantEvent per event | Negligible | **NEW** | child-pi.ts:515 |
824
- | A2-F2 | LOW | Memory | MAX_TRACKED_STATES=5000 cap | Bounded | **NEW** | overflow-recovery.ts:34 |
825
-
826
- ---
827
-
828
- ## Appendix B: Cross-Reference with Prior Documentation
829
-
830
- ### vs. `performance-review-2026-07.md`
831
-
832
- | Docs Finding | Audit Status | Notes |
833
- |--------------|--------------|-------|
834
- | F1 — Global generation counter | ✅ FIXED | `state-store.ts:82` |
835
- | F2 — persistSingleTaskUpdate sync | ⚠️ PARTIAL | Phase 2 plan exists |
836
- | F3 — fsync per event | ⚠️ PARTIAL | `task.progress` only |
837
- | F4 — tasks.json full rewrite | ⚠️ PARTIAL | Option exists, not migrated |
838
- | F5 — symlink check no cache | ⚠️ PRESENT | No caching yet |
839
- | F6 — mailbox full rewrite | ⚠️ PRESENT | High-risk refactor |
840
- | F8 — execFileSync blocking | ⚠️ PRESENT | All sync worktree ops |
841
- | F9 — rawTextEvents unbounded | ✅ FIXED | Ring buffer cap |
842
- | F12 — finalDrainMs hard | ✅ FIXED | Early-exit on silence |
843
- | F15 — discovery cache TTL | ✅ FIXED | 5000ms |
844
- | F16 — config no cache | ✅ FIXED | 2s TTL + mtime |
845
- | F17 — discoverWorkflows no cache | ✅ FIXED | TTL + dirStamp |
846
-
847
- ### vs. `optimization-plan-2026-07-verified.md`
848
-
849
- | Plan Phase | Item | Audit Status |
850
- |------------|------|--------------|
851
- | Phase 1 | F17 cache discoverWorkflows | ✅ DONE |
852
- | Phase 1 | F15 TTL discovery | ✅ DONE |
853
- | Phase 1 | F4 durability best-effort | ⚠️ PARTIAL |
854
- | Phase 1 | F9 ring buffer | ✅ DONE |
855
- | Phase 2 | F2 stat consolidation | ⚠️ PENDING |
856
- | Phase 2 | F3a fsync terminal only | ⚠️ PENDING |
857
- | Phase 2 | F5 symlink cache | ⚠️ PENDING |
858
- | Phase 2 | F1 generation per-stateRoot | ✅ DONE |
859
- | Phase 3 | F12 early-exit-on-silence | ✅ DONE |
860
- | Phase 3 | F3b buffering deadlock | ⚠️ REVERTED |
861
- | Phase 3 | F6 mailbox append-only | ⚠️ PENDING |
862
- | Phase 3 | In-memory task state | ⚠️ PENDING |
863
-
864
- ---
865
-
866
- *Report generated: 2026-07-11*
867
- *Source data: adaptive-01 through adaptive-05 exploration artifacts + existing `docs/perf/` documentation*
868
-
869
- ---
870
-
871
- ## 7. Benchmark Findings (2026-07-11, post-bench)
872
-
873
- A new benchmark `test/bench/terminal-persist-blocking.bench.ts` was added to
874
- empirically answer the A5-C2 question: *does `persistSingleTaskUpdate`'s sync
875
- run lock block the event loop 200–800ms during 4-way parallel completion?*
876
-
877
- ### Method
878
-
879
- Measures the **real persist path** (not just the atomic-write primitive) in
880
- four scenarios, with `monitorEventLoopDelay` capturing true event-loop lag:
881
-
882
- 1. **serialPersist** — full `persistSingleTaskUpdate` (lock + load + CAS + write), isolated.
883
- 2. **saveManifestLarge** — `saveRunManifest` with 60 artifact descriptors (terminal size).
884
- 3. **singleTerminalBlock** — ONE full terminal block (saveManifest + persist) = the actual
885
- per-completion cost. In real runs completions are spread over minutes, so each runs
886
- exactly one such block.
887
- 4. **spacedBurst** — 4 completions spaced by 15ms setTimeout gaps (so the event loop turns
888
- over between blocks), under `monitorEventLoopDelay`.
889
-
890
- ### Results (captured in `test/bench/results.json`)
891
-
892
- | Metric | p50 | p95 | max |
893
- |--------|-----|-----|-----|
894
- | serialPersist (ms) | 15.17 | 19.28 | 42.96 |
895
- | saveManifestLarge (ms) | 13.99 | 22.18 | 38.94 |
896
- | **singleTerminalBlock (ms)** | **30.28** | **32.83** | **38.92** |
897
- | spacedBurstPerCall (ms) | 28.20 | 34.72 | 68.81 |
898
- | eventLoopDelay (ms) | 1.09 | 29.69 | 210.11 |
899
- | **contentionRatio** | **0.93** | — | — |
900
-
901
- **contentionRatio was 0.93 / 0.98 / 0.96 / 0.98 across four independent runs** —
902
- consistently ≈ 1.0.
903
-
904
- ### Verdict: A5-C2 disproven
905
-
906
- - **contentionRatio ≈ 1.0** means a completion's per-call latency under a 4-way
907
- burst is **statistically identical** to a single isolated block. There is
908
- **no lock contention** to relieve. The audit's premise ("4 tasks serialize
909
- on the lock → `sleepSync` blocks 200–800ms") does not hold.
910
-
911
- - **Why**: JavaScript is single-threaded. `withRunLockSync`'s critical section
912
- is fully synchronous, so concurrent `mapConcurrent` completions **cannot
913
- overlap** — worker A's persist runs atomically to completion, then worker B's
914
- runs. By the time B runs, A has released the lock (re-entrance map cleared),
915
- so B acquires fresh via `O_EXCL` on the first try — `sleepSync`/`Atomics.wait`
916
- **never triggers** for same-process workers. It only triggers under genuine
917
- *cross-process* contention (a separate OS process holding the lock file),
918
- which doesn't happen for in-process task completion.
919
-
920
- - **Real per-completion cost**: ~30ms p50 (one sync block). Real runs spread
921
- completions over minutes, so this is ~30ms of event-loop blocking per
922
- completion — acceptable for a CLI tool (no sub-16ms interactive frame budget
923
- during that moment). The `eventLoopDelay` max of ~210ms is an occasional
924
- fsync/GC outlier, **not** lock contention — and is the same fsync-cost issue
925
- already tracked as F3/F4 in the prior review.
926
-
927
- - **Why the async conversion wouldn't help even if applied**: `persistSingleTaskUpdate`'s
928
- body is fully synchronous I/O (`loadRunManifestById`, `saveRunTasksCoalesced`,
929
- `statSync`). Converting only the lock to async leaves the body I/O synchronous,
930
- so event-loop blocking from the I/O persists regardless. Removing it would
931
- require converting the entire persist path to async I/O — a much larger,
932
- higher-risk refactor — for ~30ms of infrequent blocking that doesn't matter
933
- in practice.
934
-
935
- ### Recommendation
936
-
937
- **Do not implement A5-C2 as specified.** The 11+ call-site + `checkpointTask`
938
- ripple (with deadlock risk) buys nothing measurable. If event-loop blocking
939
- from the persist path ever becomes a real problem (e.g. a highly concurrent
940
- interactive TUI), the correct target is **async I/O throughout
941
- `persistSingleTaskUpdate`** + a benchmark proving the win — not the lock
942
- conversion.
943
-
944
- ### What this benchmark is now good for
945
-
946
- `terminal-persist-blocking.bench.ts` is a durable regression guard: any future
947
- change to the persist/lock path can be re-benched to confirm `contentionRatio`
948
- stays ≈1.0 and `singleTerminalBlock` doesn't regress.