groundswell 0.0.2 → 1.0.0

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 (554) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +26 -9
  3. package/dist/cache/cache-key.d.ts +86 -0
  4. package/dist/cache/cache-key.d.ts.map +1 -0
  5. package/dist/cache/cache-key.js +204 -0
  6. package/dist/cache/cache-key.js.map +1 -0
  7. package/dist/cache/cache.d.ts +104 -0
  8. package/dist/cache/cache.d.ts.map +1 -0
  9. package/dist/cache/cache.js +179 -0
  10. package/dist/cache/cache.js.map +1 -0
  11. package/{src/cache/index.ts → dist/cache/index.d.ts} +1 -1
  12. package/dist/cache/index.d.ts.map +1 -0
  13. package/dist/cache/index.js +6 -0
  14. package/dist/cache/index.js.map +1 -0
  15. package/dist/core/agent.d.ts +203 -0
  16. package/dist/core/agent.d.ts.map +1 -0
  17. package/dist/core/agent.js +833 -0
  18. package/dist/core/agent.js.map +1 -0
  19. package/{src/core/context.ts → dist/core/context.d.ts} +16 -67
  20. package/dist/core/context.d.ts.map +1 -0
  21. package/dist/core/context.js +80 -0
  22. package/dist/core/context.js.map +1 -0
  23. package/dist/core/event-tree.d.ts +72 -0
  24. package/dist/core/event-tree.d.ts.map +1 -0
  25. package/dist/core/event-tree.js +211 -0
  26. package/dist/core/event-tree.js.map +1 -0
  27. package/{src/core/factory.ts → dist/core/factory.d.ts} +6 -27
  28. package/dist/core/factory.d.ts.map +1 -0
  29. package/dist/core/factory.js +110 -0
  30. package/dist/core/factory.js.map +1 -0
  31. package/{src/core/index.ts → dist/core/index.d.ts} +2 -10
  32. package/dist/core/index.d.ts.map +1 -0
  33. package/dist/core/index.js +9 -0
  34. package/dist/core/index.js.map +1 -0
  35. package/dist/core/logger.d.ts +50 -0
  36. package/dist/core/logger.d.ts.map +1 -0
  37. package/dist/core/logger.js +91 -0
  38. package/dist/core/logger.js.map +1 -0
  39. package/dist/core/mcp-handler.d.ts +127 -0
  40. package/dist/core/mcp-handler.d.ts.map +1 -0
  41. package/dist/core/mcp-handler.js +323 -0
  42. package/dist/core/mcp-handler.js.map +1 -0
  43. package/dist/core/prompt.d.ts +80 -0
  44. package/dist/core/prompt.d.ts.map +1 -0
  45. package/dist/core/prompt.js +120 -0
  46. package/dist/core/prompt.js.map +1 -0
  47. package/dist/core/workflow-context.d.ts +61 -0
  48. package/dist/core/workflow-context.d.ts.map +1 -0
  49. package/dist/core/workflow-context.js +358 -0
  50. package/dist/core/workflow-context.js.map +1 -0
  51. package/dist/core/workflow.d.ts +543 -0
  52. package/dist/core/workflow.d.ts.map +1 -0
  53. package/dist/core/workflow.js +986 -0
  54. package/dist/core/workflow.js.map +1 -0
  55. package/dist/debugger/event-replayer.d.ts +422 -0
  56. package/dist/debugger/event-replayer.d.ts.map +1 -0
  57. package/dist/debugger/event-replayer.js +639 -0
  58. package/dist/debugger/event-replayer.js.map +1 -0
  59. package/dist/debugger/index.d.ts +2 -0
  60. package/dist/debugger/index.d.ts.map +1 -0
  61. package/{src/debugger/index.ts → dist/debugger/index.js} +1 -0
  62. package/dist/debugger/index.js.map +1 -0
  63. package/dist/debugger/tree-debugger.d.ts +240 -0
  64. package/dist/debugger/tree-debugger.d.ts.map +1 -0
  65. package/dist/debugger/tree-debugger.js +620 -0
  66. package/dist/debugger/tree-debugger.js.map +1 -0
  67. package/dist/decorators/index.d.ts +4 -0
  68. package/dist/decorators/index.d.ts.map +1 -0
  69. package/{src/decorators/index.ts → dist/decorators/index.js} +1 -0
  70. package/dist/decorators/index.js.map +1 -0
  71. package/dist/decorators/observed-state.d.ts +32 -0
  72. package/dist/decorators/observed-state.d.ts.map +1 -0
  73. package/dist/decorators/observed-state.js +79 -0
  74. package/dist/decorators/observed-state.js.map +1 -0
  75. package/dist/decorators/step.d.ts +15 -0
  76. package/dist/decorators/step.d.ts.map +1 -0
  77. package/dist/decorators/step.js +192 -0
  78. package/dist/decorators/step.js.map +1 -0
  79. package/dist/decorators/task.d.ts +50 -0
  80. package/dist/decorators/task.d.ts.map +1 -0
  81. package/dist/decorators/task.js +118 -0
  82. package/dist/decorators/task.js.map +1 -0
  83. package/dist/examples/index.d.ts +3 -0
  84. package/dist/examples/index.d.ts.map +1 -0
  85. package/{src/examples/index.ts → dist/examples/index.js} +1 -0
  86. package/dist/examples/index.js.map +1 -0
  87. package/dist/examples/tdd-orchestrator.d.ts +15 -0
  88. package/dist/examples/tdd-orchestrator.d.ts.map +1 -0
  89. package/dist/examples/tdd-orchestrator.js +121 -0
  90. package/dist/examples/tdd-orchestrator.js.map +1 -0
  91. package/dist/examples/test-cycle-workflow.d.ts +14 -0
  92. package/dist/examples/test-cycle-workflow.d.ts.map +1 -0
  93. package/dist/examples/test-cycle-workflow.js +116 -0
  94. package/dist/examples/test-cycle-workflow.js.map +1 -0
  95. package/dist/harnesses/claude-code-harness.d.ts +391 -0
  96. package/dist/harnesses/claude-code-harness.d.ts.map +1 -0
  97. package/dist/harnesses/claude-code-harness.js +1076 -0
  98. package/dist/harnesses/claude-code-harness.js.map +1 -0
  99. package/dist/harnesses/harness-registry.d.ts +440 -0
  100. package/dist/harnesses/harness-registry.d.ts.map +1 -0
  101. package/dist/harnesses/harness-registry.js +543 -0
  102. package/dist/harnesses/harness-registry.js.map +1 -0
  103. package/dist/harnesses/index.d.ts +12 -0
  104. package/dist/harnesses/index.d.ts.map +1 -0
  105. package/dist/harnesses/index.js +11 -0
  106. package/dist/harnesses/index.js.map +1 -0
  107. package/dist/harnesses/pi-harness.d.ts +219 -0
  108. package/dist/harnesses/pi-harness.d.ts.map +1 -0
  109. package/dist/harnesses/pi-harness.js +676 -0
  110. package/dist/harnesses/pi-harness.js.map +1 -0
  111. package/dist/harnesses/pi-schema-converter.d.ts +24 -0
  112. package/dist/harnesses/pi-schema-converter.d.ts.map +1 -0
  113. package/dist/harnesses/pi-schema-converter.js +81 -0
  114. package/dist/harnesses/pi-schema-converter.js.map +1 -0
  115. package/dist/harnesses/register-defaults.d.ts +24 -0
  116. package/dist/harnesses/register-defaults.d.ts.map +1 -0
  117. package/dist/harnesses/register-defaults.js +40 -0
  118. package/dist/harnesses/register-defaults.js.map +1 -0
  119. package/dist/harnesses/session-store.d.ts +201 -0
  120. package/dist/harnesses/session-store.d.ts.map +1 -0
  121. package/dist/harnesses/session-store.js +254 -0
  122. package/dist/harnesses/session-store.js.map +1 -0
  123. package/dist/index.d.ts +37 -0
  124. package/dist/index.d.ts.map +1 -0
  125. package/dist/index.js +57 -0
  126. package/dist/index.js.map +1 -0
  127. package/dist/reflection/index.d.ts +5 -0
  128. package/dist/reflection/index.d.ts.map +1 -0
  129. package/{src/reflection/index.ts → dist/reflection/index.js} +1 -1
  130. package/dist/reflection/index.js.map +1 -0
  131. package/dist/reflection/reflection.d.ts +84 -0
  132. package/dist/reflection/reflection.d.ts.map +1 -0
  133. package/dist/reflection/reflection.js +344 -0
  134. package/dist/reflection/reflection.js.map +1 -0
  135. package/dist/tools/index.d.ts +6 -0
  136. package/dist/tools/index.d.ts.map +1 -0
  137. package/dist/tools/index.js +11 -0
  138. package/dist/tools/index.js.map +1 -0
  139. package/dist/tools/introspection.d.ts +165 -0
  140. package/dist/tools/introspection.d.ts.map +1 -0
  141. package/dist/tools/introspection.js +324 -0
  142. package/dist/tools/introspection.js.map +1 -0
  143. package/dist/types/agent.d.ts +1317 -0
  144. package/dist/types/agent.d.ts.map +1 -0
  145. package/dist/types/agent.js +423 -0
  146. package/dist/types/agent.js.map +1 -0
  147. package/dist/types/decorators.d.ts +40 -0
  148. package/dist/types/decorators.d.ts.map +1 -0
  149. package/dist/types/decorators.js +2 -0
  150. package/dist/types/decorators.js.map +1 -0
  151. package/dist/types/error-strategy.d.ts +13 -0
  152. package/dist/types/error-strategy.d.ts.map +1 -0
  153. package/dist/types/error-strategy.js +2 -0
  154. package/dist/types/error-strategy.js.map +1 -0
  155. package/dist/types/error.d.ts +20 -0
  156. package/dist/types/error.d.ts.map +1 -0
  157. package/dist/types/error.js +2 -0
  158. package/dist/types/error.js.map +1 -0
  159. package/dist/types/events.d.ts +113 -0
  160. package/dist/types/events.d.ts.map +1 -0
  161. package/dist/types/events.js +2 -0
  162. package/dist/types/events.js.map +1 -0
  163. package/dist/types/harnesses.d.ts +474 -0
  164. package/dist/types/harnesses.d.ts.map +1 -0
  165. package/dist/types/harnesses.js +2 -0
  166. package/dist/types/harnesses.js.map +1 -0
  167. package/dist/types/index.d.ts +23 -0
  168. package/dist/types/index.d.ts.map +1 -0
  169. package/dist/types/index.js +8 -0
  170. package/dist/types/index.js.map +1 -0
  171. package/dist/types/logging.d.ts +24 -0
  172. package/dist/types/logging.d.ts.map +1 -0
  173. package/dist/types/logging.js +2 -0
  174. package/dist/types/logging.js.map +1 -0
  175. package/dist/types/observer.d.ts +18 -0
  176. package/dist/types/observer.d.ts.map +1 -0
  177. package/dist/types/observer.js +2 -0
  178. package/dist/types/observer.js.map +1 -0
  179. package/dist/types/prompt.d.ts +31 -0
  180. package/dist/types/prompt.d.ts.map +1 -0
  181. package/dist/types/prompt.js +6 -0
  182. package/dist/types/prompt.js.map +1 -0
  183. package/dist/types/providers.d.ts +691 -0
  184. package/dist/types/providers.d.ts.map +1 -0
  185. package/dist/types/providers.js +14 -0
  186. package/dist/types/providers.js.map +1 -0
  187. package/dist/types/reflection.d.ts +96 -0
  188. package/dist/types/reflection.d.ts.map +1 -0
  189. package/dist/types/reflection.js +24 -0
  190. package/dist/types/reflection.js.map +1 -0
  191. package/dist/types/restart.d.ts +132 -0
  192. package/dist/types/restart.d.ts.map +1 -0
  193. package/dist/types/restart.js +2 -0
  194. package/dist/types/restart.js.map +1 -0
  195. package/dist/types/sdk-primitives.d.ts +118 -0
  196. package/dist/types/sdk-primitives.d.ts.map +1 -0
  197. package/dist/types/sdk-primitives.js +6 -0
  198. package/dist/types/sdk-primitives.js.map +1 -0
  199. package/{src/types/snapshot.ts → dist/types/snapshot.d.ts} +5 -5
  200. package/dist/types/snapshot.d.ts.map +1 -0
  201. package/dist/types/snapshot.js +2 -0
  202. package/dist/types/snapshot.js.map +1 -0
  203. package/dist/types/streaming.d.ts +194 -0
  204. package/dist/types/streaming.d.ts.map +1 -0
  205. package/dist/types/streaming.js +67 -0
  206. package/dist/types/streaming.js.map +1 -0
  207. package/dist/types/workflow-context.d.ts +275 -0
  208. package/dist/types/workflow-context.d.ts.map +1 -0
  209. package/dist/types/workflow-context.js +8 -0
  210. package/dist/types/workflow-context.js.map +1 -0
  211. package/dist/types/workflow.d.ts +30 -0
  212. package/dist/types/workflow.d.ts.map +1 -0
  213. package/dist/types/workflow.js +2 -0
  214. package/dist/types/workflow.js.map +1 -0
  215. package/dist/utils/agent-validation.d.ts +88 -0
  216. package/dist/utils/agent-validation.d.ts.map +1 -0
  217. package/dist/utils/agent-validation.js +87 -0
  218. package/dist/utils/agent-validation.js.map +1 -0
  219. package/dist/utils/delay.d.ts +7 -0
  220. package/dist/utils/delay.d.ts.map +1 -0
  221. package/dist/utils/delay.js +9 -0
  222. package/dist/utils/delay.js.map +1 -0
  223. package/dist/utils/harness-config.d.ts +180 -0
  224. package/dist/utils/harness-config.d.ts.map +1 -0
  225. package/dist/utils/harness-config.js +311 -0
  226. package/dist/utils/harness-config.js.map +1 -0
  227. package/dist/utils/id.d.ts +6 -0
  228. package/dist/utils/id.d.ts.map +1 -0
  229. package/dist/utils/id.js +12 -0
  230. package/dist/utils/id.js.map +1 -0
  231. package/dist/utils/index.d.ts +13 -0
  232. package/dist/utils/index.d.ts.map +1 -0
  233. package/dist/utils/index.js +11 -0
  234. package/dist/utils/index.js.map +1 -0
  235. package/dist/utils/model-spec.d.ts +110 -0
  236. package/dist/utils/model-spec.d.ts.map +1 -0
  237. package/dist/utils/model-spec.js +149 -0
  238. package/dist/utils/model-spec.js.map +1 -0
  239. package/dist/utils/observable.d.ts +54 -0
  240. package/dist/utils/observable.d.ts.map +1 -0
  241. package/dist/utils/observable.js +82 -0
  242. package/dist/utils/observable.js.map +1 -0
  243. package/dist/utils/provider-config.d.ts +10 -0
  244. package/dist/utils/provider-config.d.ts.map +1 -0
  245. package/dist/utils/provider-config.js +10 -0
  246. package/dist/utils/provider-config.js.map +1 -0
  247. package/dist/utils/restart-analysis.d.ts +202 -0
  248. package/dist/utils/restart-analysis.d.ts.map +1 -0
  249. package/dist/utils/restart-analysis.js +426 -0
  250. package/dist/utils/restart-analysis.js.map +1 -0
  251. package/dist/utils/session-serialization.d.ts +118 -0
  252. package/dist/utils/session-serialization.d.ts.map +1 -0
  253. package/dist/utils/session-serialization.js +217 -0
  254. package/dist/utils/session-serialization.js.map +1 -0
  255. package/dist/utils/workflow-error-utils.d.ts +22 -0
  256. package/dist/utils/workflow-error-utils.d.ts.map +1 -0
  257. package/dist/utils/workflow-error-utils.js +45 -0
  258. package/dist/utils/workflow-error-utils.js.map +1 -0
  259. package/package.json +34 -5
  260. package/.claude/commands/subtask-planning/prp-base-create.md +0 -120
  261. package/.claude/commands/subtask-planning/prp-base-execute.md +0 -65
  262. package/.claude/commands/task-breakdown.md +0 -94
  263. package/.claude/settings.local.json +0 -9
  264. package/.claude/system_prompts/task-breakdown.md +0 -101
  265. package/CHANGELOG.md +0 -188
  266. package/PRD.md +0 -543
  267. package/PRPs/001-hierarchical-workflow-engine.md +0 -2438
  268. package/PRPs/PRDs/002-agent-prompt.md +0 -390
  269. package/PRPs/PRDs/003-agent-prompt.md +0 -943
  270. package/PRPs/PRDs/004-agent-prompt.md +0 -1136
  271. package/PRPs/PRDs/tasks-001.json +0 -492
  272. package/PRPs/README.md +0 -83
  273. package/PRPs/templates/prp_base.md +0 -222
  274. package/docs/agent.md +0 -422
  275. package/docs/prompt.md +0 -419
  276. package/docs/workflow.md +0 -600
  277. package/examples/README.md +0 -258
  278. package/examples/examples/01-basic-workflow.ts +0 -100
  279. package/examples/examples/02-decorator-options.ts +0 -217
  280. package/examples/examples/03-parent-child.ts +0 -241
  281. package/examples/examples/04-observers-debugger.ts +0 -340
  282. package/examples/examples/05-error-handling.ts +0 -387
  283. package/examples/examples/06-concurrent-tasks.ts +0 -352
  284. package/examples/examples/07-agent-loops.ts +0 -432
  285. package/examples/examples/08-sdk-features.ts +0 -667
  286. package/examples/examples/09-reflection.ts +0 -573
  287. package/examples/examples/10-introspection.ts +0 -550
  288. package/examples/examples/11-reparenting-workflows.ts +0 -269
  289. package/examples/index.ts +0 -147
  290. package/examples/utils/helpers.ts +0 -57
  291. package/package-lock.json +0 -2398
  292. package/plan/001_d3bb02af4886/TEST_RESULTS.md +0 -259
  293. package/plan/001_d3bb02af4886/backlog.json +0 -867
  294. package/plan/001_d3bb02af4886/bug_fix_tasks.json +0 -484
  295. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M1T1S1/PRP.md +0 -488
  296. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M1T1S2/PRP.md +0 -581
  297. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M1T1S3/PRP.md +0 -687
  298. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T1S1/PRP.md +0 -492
  299. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T1S3/PRP.md +0 -932
  300. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T1S3/research/concurrent_error_testing_patterns.md +0 -1109
  301. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T1S3/research/vitest_concurrent_testing.md +0 -802
  302. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T1S3/research/workflow_engine_test_references.md +0 -603
  303. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T2S1/PRP.md +0 -564
  304. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T2S3/PRP.md +0 -518
  305. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T2S4/PRP.md +0 -1252
  306. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T3S1/PRP.md +0 -364
  307. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T3S1/research/CODEBASE_INVENTORY.md +0 -114
  308. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T3S1/research/DECORATOR_DOCUMENTATION_PATTERNS.md +0 -205
  309. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T3S1/research/PRD_LOCATION_ANALYSIS.md +0 -199
  310. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T3S1/research/ULTRATHINK_PRP_PLAN.md +0 -134
  311. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T1S1/PRP.md +0 -495
  312. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T1S1/research/console_error_inventory.md +0 -435
  313. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T1S2/PRP.md +0 -506
  314. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T1S3/PRP.md +0 -612
  315. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T2S2/PRP.md +0 -558
  316. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T2S2/research/external_research.md +0 -788
  317. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T3S2/PRP.md +0 -460
  318. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T3S3/PRP.md +0 -454
  319. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T4S1/PRP.md +0 -520
  320. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T4S1/RECOMMENDATION.md +0 -417
  321. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T4S1/research/external_workflow_engines_research.md +0 -760
  322. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T4S1/research/security_implications_analysis.md +0 -245
  323. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T4S2/PRP.md +0 -792
  324. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S1/PRP.md +0 -535
  325. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S1/TEST_EXECUTION_REPORT.md +0 -190
  326. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S2/PRP.md +0 -654
  327. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S2/TEST_FIX_REPORT.md +0 -227
  328. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S2/research/KEY_FINDINGS.md +0 -345
  329. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S2/research/QUICK_REFERENCE.md +0 -193
  330. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S2/research/test_maintenance_research.md +0 -1323
  331. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T3S1/BREAKING_CHANGES_AUDIT.md +0 -1011
  332. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T3S1/PRP.md +0 -927
  333. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T3S2/PRP.md +0 -505
  334. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/architecture/logger_child_signature_analysis.md +0 -401
  335. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S3/child_implementation_research.md +0 -142
  336. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S3/test_patterns_research.md +0 -112
  337. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S3/vitest_patterns_research.md +0 -159
  338. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S4/PRP.md +0 -549
  339. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S4/VERIFICATION_REPORT.md +0 -368
  340. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S4/edge_case_analysis.md +0 -172
  341. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S4/usage_inventory.md +0 -175
  342. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T1S2/PRP.md +0 -696
  343. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T1S4/PRP.md +0 -860
  344. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/PRP.md +0 -1066
  345. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/01-testing-aggregated-errors.md +0 -1103
  346. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/01_typescript_error_aggregation_patterns.md +0 -789
  347. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/02-error-merge-strategy-testing-guide.md +0 -1098
  348. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/02_aggregate_error_patterns.md +0 -1037
  349. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/03-promise-allsettled-testing-patterns.md +0 -916
  350. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/03_error_merging_strategies.md +0 -1045
  351. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/04_github_stackoverflow_examples.md +0 -890
  352. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/05_comprehensive_summary.md +0 -822
  353. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/INDEX.md +0 -668
  354. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/QUICK_REFERENCE.md +0 -706
  355. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/README.md +0 -265
  356. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/RESEARCH_REPORT.md +0 -655
  357. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S4/research/vitest_testing_patterns.md +0 -1103
  358. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T3S2/PRP.md +0 -426
  359. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T1S2/PRP.md +0 -506
  360. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T1S2/research/QUICK_REFERENCE.md +0 -114
  361. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T1S2/research/RESEARCH_SUMMARY.md +0 -316
  362. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T1S2/research/vitest_observer_error_logging_best_practices.md +0 -754
  363. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T1S3/PRP.md +0 -612
  364. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T2S1/PRP.md +0 -719
  365. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T2S1/README.md +0 -215
  366. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T2S1/analysis.md +0 -765
  367. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T2S3/PRP.md +0 -718
  368. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T3S1/DECISION.md +0 -149
  369. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T3S1/PRP.md +0 -470
  370. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T3S1/research/ULTRATHINK_PLAN.md +0 -332
  371. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T3S1/research/codebase_workflow_name_analysis.md +0 -167
  372. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T3S1/research/external_best_practices.md +0 -265
  373. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T3S1/research/validation_patterns.md +0 -273
  374. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T4S1/workflow_engine_ancestry_api_research.md +0 -760
  375. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T4S3-PRP.md +0 -434
  376. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M4T2S1/PRP.md +0 -717
  377. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M4T2S2/PRP.md +0 -472
  378. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M4T2S2/VALIDATION_REPORT.md +0 -125
  379. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M4T2S2/research/ULTRATHINK_PRP_PLAN.md +0 -301
  380. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/error-logging-best-practices.md +0 -1170
  381. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/research_typescript_partial_and_overloads.md +0 -940
  382. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/vitest-quick-reference.md +0 -151
  383. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/vitest-research.md +0 -650
  384. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/prd_snapshot.md +0 -259
  385. package/plan/001_d3bb02af4886/bugfix/P1M1T1S1/PRP.md +0 -457
  386. package/plan/001_d3bb02af4886/bugfix/RESEARCH_SUMMARY.md +0 -346
  387. package/plan/001_d3bb02af4886/bugfix/architecture/codebase_structure.md +0 -311
  388. package/plan/001_d3bb02af4886/bugfix/architecture/concurrent_execution_best_practices.md +0 -1565
  389. package/plan/001_d3bb02af4886/bugfix/architecture/error_handling_patterns.md +0 -288
  390. package/plan/001_d3bb02af4886/bugfix/architecture/promise_all_analysis.md +0 -741
  391. package/plan/001_d3bb02af4886/docs/PRP/P1M1T1S4-functional-workflow-error-state-capture-test.md +0 -652
  392. package/plan/001_d3bb02af4886/docs/PRP/P1P2-PRP.md +0 -527
  393. package/plan/001_d3bb02af4886/docs/PRP/P3P4-PRP.md +0 -1388
  394. package/plan/001_d3bb02af4886/docs/PRP/P4P5-PRP.md +0 -1136
  395. package/plan/001_d3bb02af4886/docs/PRP/PRP.md +0 -527
  396. package/plan/001_d3bb02af4886/docs/PRP/bugfix/P1M1T2S1-PRP.md +0 -415
  397. package/plan/001_d3bb02af4886/docs/PRP/bugfix/P1M1T2S2-PRP.md +0 -378
  398. package/plan/001_d3bb02af4886/docs/PRP/bugfix/P1M1T2S4-PRP.md +0 -713
  399. package/plan/001_d3bb02af4886/docs/PRP/bugfix/P1M2T1S4-PRP.md +0 -370
  400. package/plan/001_d3bb02af4886/docs/PRP_P1M3T1S3.md +0 -499
  401. package/plan/001_d3bb02af4886/docs/TEST_RESULTS.md +0 -230
  402. package/plan/001_d3bb02af4886/docs/architecture/external_deps.md +0 -358
  403. package/plan/001_d3bb02af4886/docs/architecture/system_context.md +0 -242
  404. package/plan/001_d3bb02af4886/docs/bugfix/ANALYSIS_PRD_VS_IMPLEMENTATION.md +0 -1134
  405. package/plan/001_d3bb02af4886/docs/bugfix/GAP_ANALYSIS_SUMMARY.md +0 -179
  406. package/plan/001_d3bb02af4886/docs/bugfix/P1M4T2S1/PRP.md +0 -629
  407. package/plan/001_d3bb02af4886/docs/bugfix/P1M4T2S1/validation-report.md +0 -214
  408. package/plan/001_d3bb02af4886/docs/bugfix/PRP_P1M4T2S3.md +0 -629
  409. package/plan/001_d3bb02af4886/docs/bugfix/bugfix_PRP.md +0 -529
  410. package/plan/001_d3bb02af4886/docs/bugfix/bugfix_QUICK_REFERENCE.md +0 -142
  411. package/plan/001_d3bb02af4886/docs/bugfix/bugfix_README.md +0 -304
  412. package/plan/001_d3bb02af4886/docs/bugfix/bugfix_TEST_RESULTS.md +0 -558
  413. package/plan/001_d3bb02af4886/docs/bugfix/bugfix_VALIDATION_SUMMARY.md +0 -256
  414. package/plan/001_d3bb02af4886/docs/bugfix/system_context.md +0 -346
  415. package/plan/001_d3bb02af4886/docs/bugfix-architecture/bug_analysis.md +0 -415
  416. package/plan/001_d3bb02af4886/docs/bugfix-architecture/implementation_patterns.md +0 -489
  417. package/plan/001_d3bb02af4886/docs/bugfix-architecture/system_context.md +0 -218
  418. package/plan/001_d3bb02af4886/docs/bugfix_INITIATION_SUMMARY.md +0 -380
  419. package/plan/001_d3bb02af4886/docs/research/CYCLE_DETECTION_PATTERNS.md +0 -1923
  420. package/plan/001_d3bb02af4886/docs/research/CYCLE_DETECTION_QUICK_REF.md +0 -319
  421. package/plan/001_d3bb02af4886/docs/research/P1M1T2S1/codebase-context.md +0 -115
  422. package/plan/001_d3bb02af4886/docs/research/P1M1T2S1/cycle-detection-algorithms.md +0 -134
  423. package/plan/001_d3bb02af4886/docs/research/P1M1T2S1/test-patterns.md +0 -153
  424. package/plan/001_d3bb02af4886/docs/research/P1M1T2S1/workflow-class.md +0 -132
  425. package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/DECORATOR_DOCUMENTATION_BEST_PRACTICES.md +0 -716
  426. package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/DECORATOR_DOCUMENTATION_QUICK_REF.md +0 -186
  427. package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/GROUNDSWELL_DECORATOR_EXAMPLES.md +0 -604
  428. package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/INDEX.md +0 -213
  429. package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/codebase_structure.md +0 -30
  430. package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/existing_test_pattern.md +0 -56
  431. package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/getRootObservers_implementation.md +0 -53
  432. package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/test_conventions.md +0 -49
  433. package/plan/001_d3bb02af4886/docs/research/P1M3T1S4/PRP.md +0 -958
  434. package/plan/001_d3bb02af4886/docs/research/P1M3T1S4/QUICK_REFERENCE.md +0 -339
  435. package/plan/001_d3bb02af4886/docs/research/P1M3T1S4/README.md +0 -305
  436. package/plan/001_d3bb02af4886/docs/research/P1M3T1S4/SUMMARY.md +0 -433
  437. package/plan/001_d3bb02af4886/docs/research/P1M3T1S4/bidirectional-tree-consistency-testing.md +0 -1574
  438. package/plan/001_d3bb02af4886/docs/research/P1M3T1S4/test-pattern-examples.md +0 -1014
  439. package/plan/001_d3bb02af4886/docs/research/P1P2/LRU_CACHE_BEST_PRACTICES.md +0 -1929
  440. package/plan/001_d3bb02af4886/docs/research/P1P2/LRU_CACHE_CODE_PATTERNS.md +0 -857
  441. package/plan/001_d3bb02af4886/docs/research/P1P2/LRU_CACHE_INTEGRATION_GUIDE.md +0 -738
  442. package/plan/001_d3bb02af4886/docs/research/P1P2/LRU_CACHE_RESEARCH_INDEX.md +0 -424
  443. package/plan/001_d3bb02af4886/docs/research/P1P2/REFLECTION_INDEX.md +0 -291
  444. package/plan/001_d3bb02af4886/docs/research/P1P2/REFLECTION_RESEARCH_REPORT.md +0 -1342
  445. package/plan/001_d3bb02af4886/docs/research/P1P2/RESEARCH_SUMMARY.md +0 -342
  446. package/plan/001_d3bb02af4886/docs/research/P1P2/anthropic-sdk.md +0 -174
  447. package/plan/001_d3bb02af4886/docs/research/P1P2/async-local-storage.md +0 -200
  448. package/plan/001_d3bb02af4886/docs/research/P1P2/reflection-code-patterns.md +0 -1205
  449. package/plan/001_d3bb02af4886/docs/research/P1P2/reflection-decision-matrix.md +0 -421
  450. package/plan/001_d3bb02af4886/docs/research/P1P2/reflection-implementation-guide.md +0 -1341
  451. package/plan/001_d3bb02af4886/docs/research/P1P2/reflection-integration-guide.md +0 -834
  452. package/plan/001_d3bb02af4886/docs/research/P1P2/reflection-patterns.md +0 -1468
  453. package/plan/001_d3bb02af4886/docs/research/P1P2/reflection-quick-reference.md +0 -558
  454. package/plan/001_d3bb02af4886/docs/research/P1P2/zod-schema.md +0 -152
  455. package/plan/001_d3bb02af4886/docs/research/P3P4/caching-lru.md +0 -116
  456. package/plan/001_d3bb02af4886/docs/research/P3P4/introspection-tools.md +0 -177
  457. package/plan/001_d3bb02af4886/docs/research/P3P4/reflection-patterns.md +0 -117
  458. package/plan/001_d3bb02af4886/docs/research/P4P5/RESEARCH_SUMMARY.md +0 -151
  459. package/plan/001_d3bb02af4886/docs/research/PROMISE_ALLSETTLED_QUICK_REF.md +0 -376
  460. package/plan/001_d3bb02af4886/docs/research/PROMISE_ALLSETTLED_RESEARCH.md +0 -1507
  461. package/plan/001_d3bb02af4886/docs/research/bugfix_typescript_patterns.md +0 -949
  462. package/plan/001_d3bb02af4886/docs/research/error-testing-research.md +0 -619
  463. package/plan/001_d3bb02af4886/docs/research/error_handling_patterns.md +0 -723
  464. package/plan/001_d3bb02af4886/docs/research/general/INTROSPECTION_RESEARCH_SUMMARY.md +0 -378
  465. package/plan/001_d3bb02af4886/docs/research/general/README-INTROSPECTION.md +0 -352
  466. package/plan/001_d3bb02af4886/docs/research/general/agent-introspection-patterns.md +0 -1085
  467. package/plan/001_d3bb02af4886/docs/research/general/introspection-security-guide.md +0 -984
  468. package/plan/001_d3bb02af4886/docs/research/general/introspection-tool-examples.md +0 -875
  469. package/plan/001_d3bb02af4886/docs/research/incremental-tree-map-updates/PRP_TEMPLATE.md +0 -460
  470. package/plan/001_d3bb02af4886/docs/research/incremental-tree-map-updates/QUICK_REFERENCE.md +0 -324
  471. package/plan/001_d3bb02af4886/docs/research/incremental-tree-map-updates/README.md +0 -175
  472. package/plan/001_d3bb02af4886/docs/research/incremental-tree-map-updates/RESEARCH_REPORT.md +0 -499
  473. package/plan/001_d3bb02af4886/docs/research/incremental-tree-map-updates/SUMMARY.md +0 -163
  474. package/plan/001_d3bb02af4886/prd_snapshot.md +0 -543
  475. package/plan/bugfix/BUG_FIX_SUMMARY.md +0 -961
  476. package/scripts/generate-llms-full.ts +0 -206
  477. package/src/__tests__/adversarial/attachChild-performance.test.ts +0 -216
  478. package/src/__tests__/adversarial/circular-reference.test.ts +0 -101
  479. package/src/__tests__/adversarial/complex-circular-reference.test.ts +0 -139
  480. package/src/__tests__/adversarial/concurrent-task-failures.test.ts +0 -571
  481. package/src/__tests__/adversarial/deep-analysis.test.ts +0 -729
  482. package/src/__tests__/adversarial/deep-hierarchy-stress.test.ts +0 -213
  483. package/src/__tests__/adversarial/e2e-prd-validation.test.ts +0 -448
  484. package/src/__tests__/adversarial/edge-case.test.ts +0 -703
  485. package/src/__tests__/adversarial/error-merge-strategy.test.ts +0 -760
  486. package/src/__tests__/adversarial/incremental-performance.test.ts +0 -140
  487. package/src/__tests__/adversarial/node-map-update-benchmarks.test.ts +0 -457
  488. package/src/__tests__/adversarial/observer-propagation.test.ts +0 -487
  489. package/src/__tests__/adversarial/parent-validation.test.ts +0 -143
  490. package/src/__tests__/adversarial/prd-12-2-compliance.test.ts +0 -611
  491. package/src/__tests__/adversarial/prd-compliance.test.ts +0 -731
  492. package/src/__tests__/compatibility/backward-compatibility.test.ts +0 -1572
  493. package/src/__tests__/helpers/index.ts +0 -18
  494. package/src/__tests__/helpers/tree-verification.ts +0 -257
  495. package/src/__tests__/integration/agent-workflow.test.ts +0 -256
  496. package/src/__tests__/integration/bidirectional-consistency.test.ts +0 -847
  497. package/src/__tests__/integration/observer-logging.test.ts +0 -643
  498. package/src/__tests__/integration/tree-mirroring.test.ts +0 -151
  499. package/src/__tests__/integration/workflow-reparenting.test.ts +0 -303
  500. package/src/__tests__/unit/agent.test.ts +0 -169
  501. package/src/__tests__/unit/cache-key.test.ts +0 -182
  502. package/src/__tests__/unit/cache.test.ts +0 -172
  503. package/src/__tests__/unit/context.test.ts +0 -217
  504. package/src/__tests__/unit/decorators.test.ts +0 -100
  505. package/src/__tests__/unit/introspection-tools.test.ts +0 -277
  506. package/src/__tests__/unit/logger.test.ts +0 -293
  507. package/src/__tests__/unit/observable.test.ts +0 -321
  508. package/src/__tests__/unit/prompt.test.ts +0 -135
  509. package/src/__tests__/unit/reflection.test.ts +0 -210
  510. package/src/__tests__/unit/tree-debugger-incremental.test.ts +0 -170
  511. package/src/__tests__/unit/tree-debugger.test.ts +0 -85
  512. package/src/__tests__/unit/utils/workflow-error-utils.test.ts +0 -209
  513. package/src/__tests__/unit/workflow-detachChild.test.ts +0 -100
  514. package/src/__tests__/unit/workflow-emitEvent-childDetached.test.ts +0 -153
  515. package/src/__tests__/unit/workflow-isDescendantOf.test.ts +0 -180
  516. package/src/__tests__/unit/workflow.test.ts +0 -357
  517. package/src/cache/cache-key.ts +0 -244
  518. package/src/cache/cache.ts +0 -236
  519. package/src/core/agent.ts +0 -593
  520. package/src/core/event-tree.ts +0 -260
  521. package/src/core/logger.ts +0 -112
  522. package/src/core/mcp-handler.ts +0 -184
  523. package/src/core/prompt.ts +0 -150
  524. package/src/core/workflow-context.ts +0 -351
  525. package/src/core/workflow.ts +0 -540
  526. package/src/debugger/tree-debugger.ts +0 -255
  527. package/src/decorators/observed-state.ts +0 -95
  528. package/src/decorators/step.ts +0 -139
  529. package/src/decorators/task.ts +0 -159
  530. package/src/examples/tdd-orchestrator.ts +0 -65
  531. package/src/examples/test-cycle-workflow.ts +0 -64
  532. package/src/index.ts +0 -142
  533. package/src/reflection/reflection.ts +0 -407
  534. package/src/tools/index.ts +0 -36
  535. package/src/tools/introspection.ts +0 -464
  536. package/src/types/agent.ts +0 -90
  537. package/src/types/decorators.ts +0 -32
  538. package/src/types/error-strategy.ts +0 -13
  539. package/src/types/error.ts +0 -20
  540. package/src/types/events.ts +0 -75
  541. package/src/types/index.ts +0 -55
  542. package/src/types/logging.ts +0 -24
  543. package/src/types/observer.ts +0 -18
  544. package/src/types/prompt.ts +0 -40
  545. package/src/types/reflection.ts +0 -117
  546. package/src/types/sdk-primitives.ts +0 -128
  547. package/src/types/workflow-context.ts +0 -163
  548. package/src/types/workflow.ts +0 -37
  549. package/src/utils/id.ts +0 -11
  550. package/src/utils/index.ts +0 -4
  551. package/src/utils/observable.ts +0 -106
  552. package/src/utils/workflow-error-utils.ts +0 -56
  553. package/tsconfig.json +0 -22
  554. package/vitest.config.ts +0 -16
@@ -1,1565 +0,0 @@
1
- # Concurrent Workflow Execution and Error Handling: Best Practices Research
2
-
3
- **Author**: Research Specialist
4
- **Date**: 2026-01-12
5
- **Status**: Comprehensive Research Report
6
- **Target**: Groundswell Hierarchical Workflow Engine
7
-
8
- ---
9
-
10
- ## Executive Summary
11
-
12
- This document provides comprehensive research findings on concurrent workflow execution and error handling patterns, with specific recommendations for the Groundswell workflow engine. The research covers Promise.all vs Promise.allSettled trade-offs, production-grade workflow engine patterns, error aggregation strategies, and fail-fast vs complete-all strategies.
13
-
14
- **Key Finding**: The current implementation uses `Promise.all()` in the @Task decorator with `concurrent: true`, which implements a fail-fast strategy. Based on PRD requirements and production patterns, this report recommends adding support for `Promise.allSettled()` to enable "complete all" error handling with proper error aggregation.
15
-
16
- ---
17
-
18
- ## Table of Contents
19
-
20
- 1. [Promise.all vs Promise.allSettled: Technical Comparison](#1-promiseall-vs-promiseallsettled-technical-comparison)
21
- 2. [Production Workflow Engine Patterns](#2-production-workflow-engine-patterns)
22
- 3. [Error Aggregation Strategies](#3-error-aggregation-strategies)
23
- 4. [Fail-Fast vs Complete-All Decision Framework](#4-fail-fast-vs-complete-all-decision-framework)
24
- 5. [Groundswell-Specific Recommendations](#5-groundswell-specific-recommendations)
25
- 6. [Implementation Roadmap](#6-implementation-roadmap)
26
- 7. [Appendix: Code Examples](#7-appendix-code-examples)
27
-
28
- ---
29
-
30
- ## 1. Promise.all vs Promise.allSettled: Technical Comparison
31
-
32
- ### 1.1 Behavioral Differences
33
-
34
- #### Promise.all (Fail-Fast Strategy)
35
-
36
- ```typescript
37
- // Current Groundswell Implementation (src/decorators/task.ts:112)
38
- await Promise.all(runnable.map((w) => w.run()));
39
-
40
- // Behavior:
41
- // - Rejects IMMEDIATELY when ANY promise rejects
42
- // - Does NOT wait for other promises to complete
43
- // - Returns array of resolved values when ALL fulfill
44
- // - Use case: All operations must succeed, fast-fail desired
45
- ```
46
-
47
- **Characteristics:**
48
- - **Performance**: Faster failure detection (stops at first error)
49
- - **Resource Usage**: Wastes resources from in-flight operations
50
- - **Error Visibility**: Only shows first error (hides concurrent failures)
51
- - **Debugging**: Difficult to understand full scope of failures
52
-
53
- **Example:**
54
- ```typescript
55
- const results = await Promise.all([
56
- task1(), // completes in 100ms
57
- task2(), // completes in 200ms
58
- task3(), // FAILS in 50ms
59
- ]);
60
- // Execution stops at 50ms, results from task1/task2 lost
61
- // Only error from task3 is visible
62
- ```
63
-
64
- #### Promise.allSettled (Complete-All Strategy)
65
-
66
- ```typescript
67
- // Recommended Enhancement for Groundswell
68
- const results = await Promise.allSettled(
69
- runnable.map((w) => w.run())
70
- );
71
-
72
- // Behavior:
73
- // - Waits for ALL promises to settle (fulfilled OR rejected)
74
- // - Returns array of status objects with reason/value
75
- // - Never rejects (always fulfills)
76
- // - Use case: Need all results regardless of individual failures
77
- ```
78
-
79
- **Characteristics:**
80
- - **Performance**: Slower failure detection (waits for all operations)
81
- - **Resource Usage**: Completes all work (no waste)
82
- - **Error Visibility**: Shows ALL errors (complete picture)
83
- - **Debugging**: Easy to understand scope and patterns of failures
84
-
85
- **Example:**
86
- ```typescript
87
- const results = await Promise.allSettled([
88
- task1(), // completes in 100ms, fulfills
89
- task2(), // completes in 200ms, fulfills
90
- task3(), // FAILS in 50ms, rejects
91
- ]);
92
- // Execution completes at 200ms (waits for slowest)
93
- // All three results available:
94
- // [
95
- // { status: 'fulfilled', value: 'task1-result' },
96
- // { status: 'fulfilled', value: 'task2-result' },
97
- // { status: 'rejected', reason: Error('task3 failed') }
98
- // ]
99
- ```
100
-
101
- ### 1.2 Performance Comparison
102
-
103
- | Metric | Promise.all | Promise.allSettled |
104
- |--------|-------------|-------------------|
105
- | **Time to First Error** | Immediate (min time) | Waits for all (max time) |
106
- | **Time to Complete All** | N/A (fails early) | Max of all operations |
107
- | **Resource Efficiency** | Low (wastes in-flight work) | High (completes all work) |
108
- | **Error Completeness** | First error only | All errors |
109
- | **Partial Results** | Lost | Preserved |
110
- | **Backpressure** | Poor (can't throttle) | Better (can process as they settle) |
111
-
112
- ### 1.3 When to Use Each Strategy
113
-
114
- #### Use Promise.all When:
115
-
116
- 1. **All Operations Are Critical**: Partial success is meaningless
117
- ```typescript
118
- // Financial transaction - all parts must succeed
119
- await Promise.all([
120
- validateAccount(),
121
- holdFunds(),
122
- processTransfer(),
123
- confirmReceipt(),
124
- ]);
125
- // If any fails, entire transaction should fail
126
- ```
127
-
128
- 2. **Fast Failure Saves Resources**: Stopping early prevents waste
129
- ```typescript
130
- // Batch API calls with early validation
131
- const isValid = await validateBatch(items);
132
- if (!isValid) {
133
- return; // Don't process if validation fails
134
- }
135
- await Promise.all(items.map(processItem));
136
- ```
137
-
138
- 3. **Dependent Operations**: Subsequent steps depend on all succeeding
139
- ```typescript
140
- const [config, schema] = await Promise.all([
141
- fetchConfig(),
142
- fetchSchema(),
143
- ]);
144
- // Both needed for next step
145
- validateData(config, schema);
146
- ```
147
-
148
- 4. **Error Cascading Acceptable**: First error is representative
149
- ```typescript
150
- // Homogeneous operations (same type of task)
151
- await Promise.all(
152
- servers.map(s => s.ping())
153
- );
154
- // If any server is down, treat all as down
155
- ```
156
-
157
- #### Use Promise.allSettled When:
158
-
159
- 1. **Partial Success Has Value**: Some results better than none
160
- ```typescript
161
- // Bulk data synchronization
162
- const results = await Promise.allSettled(
163
- records.map(r => syncRecord(r))
164
- );
165
- const succeeded = results.filter(r => r.status === 'fulfilled');
166
- const failed = results.filter(r => r.status === 'rejected');
167
- // Process succeeded, retry failed
168
- ```
169
-
170
- 2. **Independent Operations**: Tasks don't depend on each other
171
- ```typescript
172
- // Parallel notifications
173
- await Promise.allSettled([
174
- sendEmail(user),
175
- sendSlack(user),
176
- sendSMS(user),
177
- ]);
178
- // Try all channels, log failures, continue
179
- ```
180
-
181
- 3. **Error Aggregation Needed**: Need to see all failures
182
- ```typescript
183
- // Batch validation with comprehensive error reporting
184
- const validations = await Promise.allSettled(
185
- fields.map(f => validateField(f))
186
- );
187
- const errors = validations
188
- .filter(v => v.status === 'rejected')
189
- .map(v => v.reason);
190
- // Return all validation errors to user
191
- ```
192
-
193
- 4. **Idempotent or Retryable Operations**: Can handle/ignore failures
194
- ```typescript
195
- // Cache warming
196
- await Promise.allSettled(
197
- keys.map(k => cache.set(k, fetchValue(k)))
198
- );
199
- // Populate as much as possible, retry misses later
200
- ```
201
-
202
- ### 1.4 Recommendations for Groundswell
203
-
204
- **Current State Analysis:**
205
- - File: `/home/dustin/projects/groundswell/src/decorators/task.ts`
206
- - Line 112: Uses `Promise.all()` for concurrent execution
207
- - Behavior: Fail-fast (stops at first child workflow error)
208
-
209
- **Issue**: This prevents partial success scenarios and hides concurrent errors.
210
-
211
- **Recommendation**: Support both strategies via configuration:
212
-
213
- ```typescript
214
- export interface TaskOptions {
215
- name?: string;
216
- concurrent?: boolean;
217
-
218
- // NEW: Add error handling strategy
219
- errorStrategy?: 'fail-fast' | 'complete-all';
220
-
221
- // NEW: Enable error aggregation
222
- mergeErrors?: boolean;
223
- }
224
- ```
225
-
226
- ---
227
-
228
- ## 2. Production Workflow Engine Patterns
229
-
230
- ### 2.1 Temporal.io: Child Workflow Error Handling
231
-
232
- **Pattern**: Temporal uses a "parent close policy" to determine child behavior on parent failure.
233
-
234
- **Key Concepts**:
235
- 1. **Parent Close Policy**: What happens to children when parent completes
236
- 2. **Cancellation Scopes**: Groups of activities that cancel together
237
- 3. **Activity Retry Policies**: Automatic retries with exponential backoff
238
-
239
- **Temporal's Approach**:
240
- ```typescript
241
- // Temporal-style child workflow execution
242
- const childHandle = await workflow.executeChild(childWorkflow, {
243
- taskQueue: 'my-task-queue',
244
- retryPolicy: {
245
- initialInterval: '1 second',
246
- backoffCoefficient: 2,
247
- maximumAttempts: 5,
248
- nonRetryableErrorTypes: ['PermanentError'],
249
- },
250
- });
251
-
252
- // Children continue by default when parent completes
253
- // Can be overridden with:
254
- const options = {
255
- parentClosePolicy: ParentClosePolicy.PARENT_CLOSE_POLICY_ABANDON,
256
- // or REQUEST_CANCEL, TERMINATE
257
- };
258
- ```
259
-
260
- **Lessons for Groundswell**:
261
- 1. **Configurable Child Behavior**: Allow parent to specify what happens on error
262
- 2. **Retry Policies**: Built-in retry with exponential backoff
263
- 3. **Error Categorization**: Distinguish retryable vs non-retryable errors
264
- 4. **Cancellation Propagation**: Controlled cascading of failures
265
-
266
- ### 2.2 AWS Step Functions: Error Handling
267
-
268
- **Pattern**: Step Functions uses catch/cascade patterns with automatic retries.
269
-
270
- **Key Concepts**:
271
- 1. **Retry Blocks**: Automatic retry with backoff
272
- 2. **Catch Blocks**: Error handling and fallback
273
- 3. **Parallel States**: Branch and merge with error aggregation
274
-
275
- **Step Functions Approach**:
276
- ```json
277
- {
278
- "Type": "Parallel",
279
- "Branches": [
280
- {
281
- "StartAt": "ProcessA",
282
- "States": {
283
- "ProcessA": {
284
- "Type": "Task",
285
- "Retry": [
286
- {
287
- "ErrorEquals": ["States.TaskFailed"],
288
- "IntervalSeconds": 1,
289
- "MaxAttempts": 3,
290
- "BackoffRate": 2.0
291
- }
292
- ],
293
- "Catch": [
294
- {
295
- "ErrorEquals": ["States.ALL"],
296
- "ResultPath": "$.error",
297
- "Next": "FallbackA"
298
- }
299
- ]
300
- }
301
- }
302
- }
303
- ]
304
- }
305
- ```
306
-
307
- **Lessons for Groundswell**:
308
- 1. **Declarative Retry**: Configuration-driven retry logic
309
- 2. **Error Categories**: Different handling for different error types
310
- 3. **Fallback States**: Degraded but functional behavior on failure
311
- 4. **Parallel Error Aggregation**: Collect errors from all branches
312
-
313
- ### 2.3 Cadence Workflow: Error Propagation
314
-
315
- **Pattern**: Cadence uses exception-based error propagation with child workflow isolation.
316
-
317
- **Key Concepts**:
318
- 1. **Workflow Exceptions**: Errors propagate up the tree
319
- 2. **Child Workflow Isolation**: Child errors don't crash parent unless thrown
320
- 3. **Timeout Handling**: Distinction between timeout and failure
321
-
322
- **Cadence Approach**:
323
- ```go
324
- // Cadence-style child workflow
325
- childFuture, _ := workflow.ExecuteChildWorkflow(ctx, childWorkflow, input)
326
-
327
- var result string
328
- if err := childFuture.Get(ctx, &result); err != nil {
329
- // Child failed, but parent can handle
330
- if activities.IsTimeoutError(err) {
331
- // Handle timeout specifically
332
- } else if activities.IsCanceledError(err) {
333
- // Handle cancellation
334
- } else {
335
- // Handle other errors
336
- }
337
- // Parent continues
338
- }
339
- ```
340
-
341
- **Lessons for Groundswell**:
342
- 1. **Non-Blocking Errors**: Parent can handle child failures
343
- 2. **Error Type Discrimination**: Different error types handled differently
344
- 3. **Explicit Error Handling**: Parent must explicitly handle child errors
345
- 4. **Timeout as First-Class Concept**: Distinguish timeout from failure
346
-
347
- ### 2.4 Apache Airflow: Task Failure Handling
348
-
349
- **Pattern**: Airflow uses DAG-based execution with trigger rules controlling downstream behavior.
350
-
351
- **Key Concepts**:
352
- 1. **Trigger Rules**: Determine when tasks run based on upstream state
353
- 2. **Task Instances**: Individual executions with state tracking
354
- 3. **Retries**: Configurable per task
355
- 4. **Failure Handlers**: Callbacks on task failure
356
-
357
- **Airflow Approach**:
358
- ```python
359
- # Airflow-style DAG with trigger rules
360
- task1 = PythonOperator(
361
- task_id='task1',
362
- python_callable=process_data,
363
- retries=3,
364
- retry_delay=timedelta(seconds=60),
365
- on_failure_callback=notify_failure,
366
- )
367
-
368
- task2 = PythonOperator(
369
- task_id='task2',
370
- python_callable=process_more_data,
371
- trigger_rule=TriggerRule.ONE_SUCCESS, # Run if ANY upstream succeeded
372
- depends_on_past=False,
373
- )
374
-
375
- task3 = PythonOperator(
376
- task_id='task3',
377
- python_callable=finalize,
378
- trigger_rule=TriggerRule.ALL_DONE, # Run after ALL upstream complete (success or fail)
379
- )
380
- ```
381
-
382
- **Lessons for Groundswell**:
383
- 1. **Flexible Trigger Rules**: Control downstream execution based on upstream state
384
- 2. **Per-Task Retry Configuration**: Fine-grained retry control
385
- 3. **Failure Callbacks**: Reactive error handling
386
- 4. **Completion-Based Triggers**: "ALL_DONE" = Promise.allSettled pattern
387
-
388
- ### 2.5 Cross-Cutting Patterns Summary
389
-
390
- | Pattern | Temporal | Step Functions | Cadence | Airflow | Groundswell |
391
- |---------|----------|----------------|---------|---------|-------------|
392
- | **Child Isolation** | ✓ | ✓ | ✓ | ✓ | ⚠️ Partial |
393
- | **Error Aggregation** | ✗ | ✓ (Parallel) | ⚠️ Manual | ✓ (Trigger rules) | ✗ |
394
- | **Automatic Retry** | ✓ | ✓ | ✓ | ✓ | ✗ |
395
- | **Fail-Fast** | Default | Configurable | Default | Configurable | Default |
396
- | **Complete-All** | ✗ | ✓ (Parallel) | ⚠️ Manual | ✓ (ALL_DONE) | ✗ |
397
- | **Fallback States** | ✗ | ✓ (Catch) | ⚠️ Manual | ✓ (On failure) | ✗ |
398
- | **Cancellation Propagation** | ✓ | ✓ | ✓ | ✓ | ⚠️ Unimplemented |
399
-
400
- ---
401
-
402
- ## 3. Error Aggregation Strategies
403
-
404
- ### 3.1 Strategy 1: First Error Wins (Current Groundswell)
405
-
406
- **Description**: Return immediately on first error, hiding concurrent failures.
407
-
408
- **Implementation**:
409
- ```typescript
410
- // Current implementation (src/decorators/task.ts:112)
411
- await Promise.all(runnable.map((w) => w.run()));
412
- ```
413
-
414
- **Pros**:
415
- - Simple implementation
416
- - Fast failure detection
417
- - Low memory overhead
418
- - Familiar pattern (Promise.all)
419
-
420
- **Cons**:
421
- - Hides concurrent errors
422
- - Loses partial results
423
- - Difficult debugging
424
- - No error context
425
-
426
- **Use Case**: Critical workflows where partial success is meaningless.
427
-
428
- ### 3.2 Strategy 2: Collect All Errors (Recommended)
429
-
430
- **Description**: Wait for all operations to complete, collect all errors.
431
-
432
- **Implementation**:
433
- ```typescript
434
- // Promise.allSettled with error aggregation
435
- const results = await Promise.allSettled(
436
- runnable.map((w) => w.run())
437
- );
438
-
439
- const errors = results
440
- .filter((r) => r.status === 'rejected')
441
- .map((r, idx) => ({
442
- workflow: runnable[idx],
443
- error: r.status === 'rejected' ? r.reason : undefined,
444
- }));
445
-
446
- if (errors.length > 0) {
447
- throw new AggregateError(
448
- errors.map(e => e.error),
449
- `${errors.length} child workflows failed`
450
- );
451
- }
452
- ```
453
-
454
- **Pros**:
455
- - Complete error visibility
456
- - Preserves partial results
457
- - Better debugging
458
- - Error pattern analysis
459
-
460
- **Cons**:
461
- - Higher memory usage
462
- - Slower failure detection
463
- - More complex error handling
464
- - Need AggregateError polyfill for older Node versions
465
-
466
- **Use Case**: Independent operations where understanding all failures is important.
467
-
468
- ### 3.3 Strategy 3: Hierarchical Error Merging
469
-
470
- **Description**: Merge errors with workflow hierarchy context.
471
-
472
- **Implementation**:
473
- ```typescript
474
- class WorkflowAggregateError extends Error {
475
- constructor(
476
- message: string,
477
- public errors: WorkflowError[],
478
- public workflowId: string,
479
- public workflowName: string,
480
- public parent?: WorkflowAggregateError
481
- ) {
482
- super(message);
483
- this.name = 'WorkflowAggregateError';
484
- }
485
-
486
- // Pretty-print error hierarchy
487
- toString(): string {
488
- let output = `${this.workflowName}: ${this.message}\n`;
489
- for (const error of this.errors) {
490
- output += ` - ${error.workflowId}: ${error.message}\n`;
491
- }
492
- if (this.parent) {
493
- output += `\nCaused by:\n${this.parent.toString()}`;
494
- }
495
- return output;
496
- }
497
-
498
- // Get error statistics
499
- getStats() {
500
- return {
501
- totalErrors: this.errors.length,
502
- byWorkflow: groupErrorsByWorkflow(this.errors),
503
- byErrorType: groupErrorsByType(this.errors),
504
- };
505
- }
506
- }
507
- ```
508
-
509
- **Pros**:
510
- - Maintains workflow context
511
- - Hierarchical error visualization
512
- - Rich error metadata
513
- - Statistical analysis
514
-
515
- **Cons**:
516
- - Complex implementation
517
- - Higher memory overhead
518
- - Steeper learning curve
519
-
520
- **Use Case**: Complex workflow trees needing comprehensive error reporting.
521
-
522
- ### 3.4 Strategy 4: Error Rate Thresholding
523
-
524
- **Description**: Allow some failures, only throw if error rate exceeds threshold.
525
-
526
- **Implementation**:
527
- ```typescript
528
- interface ErrorThresholdStrategy {
529
- enabled: boolean;
530
- maxErrorRate: number; // 0.0 to 1.0
531
- minAbsoluteErrors: number; // Throw if >= this many errors
532
- }
533
-
534
- async function executeWithThreshold(
535
- workflows: Workflow[],
536
- strategy: ErrorThresholdStrategy
537
- ) {
538
- const results = await Promise.allSettled(
539
- workflows.map((w) => w.run())
540
- );
541
-
542
- const failures = results.filter((r) => r.status === 'rejected');
543
- const errorRate = failures.length / results.length;
544
-
545
- const shouldThrow =
546
- failures.length >= strategy.minAbsoluteErrors ||
547
- errorRate > strategy.maxErrorRate;
548
-
549
- if (shouldThrow) {
550
- throw new WorkflowAggregateError(
551
- `${failures.length}/${results.length} workflows failed (${(errorRate * 100).toFixed(1)}%)`,
552
- failures.map(f => f.reason),
553
- // ... context
554
- );
555
- }
556
-
557
- return results;
558
- }
559
- ```
560
-
561
- **Pros**:
562
- - Graceful degradation
563
- - Configurable tolerance
564
- - Good for bulk operations
565
- - Prevents single failures from stopping everything
566
-
567
- **Cons**:
568
- - May hide systematic issues
569
- - Requires threshold tuning
570
- - Ambiguous success criteria
571
-
572
- **Use Case**: High-volume operations where some failures are acceptable (e.g., bulk notifications, cache warming).
573
-
574
- ### 3.5 Error Aggregation Best Practices
575
-
576
- #### DO:
577
- 1. **Preserve Workflow Context**: Include workflow ID, name, and path in errors
578
- 2. **Maintain Error Order**: Keep errors in execution order for debugging
579
- 3. **Include Error Metadata**: Timestamps, retry counts, state snapshots
580
- 4. **Provide Statistics**: Error counts, rates, patterns
581
- 5. **Support Error Inspection**: Allow programmatic error analysis
582
-
583
- #### DON'T:
584
- 1. **Lose Stack Traces**: Always preserve original stack traces
585
- 2. **Swallow Errors**: Always report or log errors
586
- 3. **Create Excessive Depth**: Limit error nesting to prevent stack overflow
587
- 4. **Duplicate Errors**: Deduplicate identical errors
588
- 5. **Include Sensitive Data**: Redact passwords, tokens, PII from errors
589
-
590
- ### 3.6 Groundswell Implementation Recommendation
591
-
592
- **Current State**:
593
- - Type: `/home/dustin/projects/groundswell/src/types/error-strategy.ts`
594
- - Status: Defined but not implemented
595
- - Interface: `ErrorMergeStrategy` exists but unused
596
-
597
- **Recommendation**:
598
-
599
- ```typescript
600
- // Enhanced error strategy interface
601
- export interface ErrorStrategy {
602
- type: 'fail-fast' | 'complete-all' | 'threshold';
603
- threshold?: number; // For 'threshold' type
604
- mergeErrors?: boolean; // Always merge errors in 'complete-all' mode
605
- }
606
-
607
- // Implementation in @Task decorator
608
- if (opts.concurrent && Array.isArray(result)) {
609
- const runnable = workflows.filter(/* ... */);
610
-
611
- if (runnable.length > 0) {
612
- const errorStrategy = opts.errorStrategy || 'fail-fast';
613
-
614
- if (errorStrategy === 'fail-fast') {
615
- // Current behavior: Promise.all
616
- await Promise.all(runnable.map((w) => w.run()));
617
- } else {
618
- // New behavior: Promise.allSettled with aggregation
619
- const results = await Promise.allSettled(
620
- runnable.map((w) => w.run())
621
- );
622
-
623
- const errors = results
624
- .filter((r) => r.status === 'rejected')
625
- .map((r) => r.reason);
626
-
627
- if (errors.length > 0) {
628
- throw new WorkflowAggregateError(
629
- `${errors.length} child workflows failed`,
630
- errors,
631
- wf.id,
632
- taskName
633
- );
634
- }
635
- }
636
- }
637
- }
638
- ```
639
-
640
- ---
641
-
642
- ## 4. Fail-Fast vs Complete-All Decision Framework
643
-
644
- ### 4.1 Decision Tree
645
-
646
- ```
647
- Start Concurrent Tasks
648
- |
649
- Are tasks independent?
650
- / \
651
- No Yes
652
- | |
653
- Use Promise.all Is partial success
654
- (Fail-Fast) valuable?
655
- / \
656
- No Yes
657
- | |
658
- Use Promise.all Need complete
659
- (Fail-Fast) error picture?
660
- / \
661
- No Yes
662
- | |
663
- Use Promise Use Promise
664
- .allSettled .allSettled
665
- (simple) (aggregate)
666
- ```
667
-
668
- ### 4.2 Heuristics for Choosing Strategy
669
-
670
- #### Use Fail-Fast (Promise.all) When:
671
-
672
- 1. **Strong Coupling**: Tasks are logically dependent
673
- - Example: Multi-step transaction where all steps must succeed
674
- - Pattern: `validate → hold → transfer → confirm`
675
-
676
- 2. **Fast Failure Saves Money**: Early termination prevents waste
677
- - Example: Paid API calls with rate limits
678
- - Pattern: Stop if quota exceeded or auth fails
679
-
680
- 3. **First Error Is Representative**: Errors are correlated
681
- - Example: All tasks use same resource (database, API)
682
- - Pattern: If one fails, all would fail
683
-
684
- 4. **User Experience Requires Speed**: Fast feedback is critical
685
- - Example: Form validation before submission
686
- - Pattern: Show first error immediately
687
-
688
- #### Use Complete-All (Promise.allSettled) When:
689
-
690
- 1. **Independent Tasks**: No dependencies between operations
691
- - Example: Sending notifications via multiple channels
692
- - Pattern: Email, SMS, Slack - try all, report failures
693
-
694
- 2. **Partial Success Has Value**: Some results better than none
695
- - Example: Bulk data synchronization
696
- - Pattern: Sync what succeeds, retry failures
697
-
698
- 3. **Error Analysis Required**: Need to see all failures
699
- - Example: Batch processing with quality control
700
- - Pattern: Analyze error patterns, adjust strategy
701
-
702
- 4. **Idempotent Operations**: Can safely retry failures
703
- - Example: Cache warming, data replication
704
- - Pattern: Populate cache, retry misses later
705
-
706
- ### 4.3 Strategy Selection Matrix
707
-
708
- | Scenario | Fail-Fast | Complete-All | Rationale |
709
- |----------|-----------|--------------|-----------|
710
- | **Financial Transaction** | ✓ | ✗ | All-or-nothing, can't have partial money movement |
711
- | **Bulk Notifications** | ✗ | ✓ | Try all channels, log failures |
712
- | **Data Validation** | ✓ | ✗ | Fast feedback, first error representative |
713
- | **Batch Processing** | ✗ | ✓ | Process what you can, retry failures |
714
- | **Cache Warming** | ✗ | ✓ | Populate as much as possible |
715
- | **API Rate Limiting** | ✓ | ✗ | Stop immediately to avoid waste |
716
- | **Multi-Region Deployment** | ✗ | ✓ | Deploy to available regions, log failures |
717
- | **Form Submission** | ✓ | ✗ | User needs immediate feedback |
718
- | **Data Replication** | ✗ | ✓ | Replicate to available nodes |
719
- | **Paid API Calls** | ✓ | ✗ | Save money on failed requests |
720
-
721
- ### 4.4 Hybrid Strategy: Adaptive Error Handling
722
-
723
- **Concept**: Start with complete-all, switch to fail-fast if error rate exceeds threshold.
724
-
725
- **Implementation**:
726
- ```typescript
727
- async function adaptiveExecute(
728
- workflows: Workflow[],
729
- options: {
730
- initialStrategy: 'fail-fast' | 'complete-all';
731
- errorRateThreshold: number; // Switch to fail-fast if exceeded
732
- minSampleSize: number; // Don't switch until this many tasks
733
- }
734
- ) {
735
- let strategy = options.initialStrategy;
736
- let completed = 0;
737
- let errors = 0;
738
-
739
- const results = await Promise.allSettled(
740
- workflows.map(async (workflow) => {
741
- try {
742
- const result = await workflow.run();
743
- completed++;
744
- errors++;
745
-
746
- // Check if we should switch to fail-fast
747
- if (
748
- strategy === 'complete-all' &&
749
- completed >= options.minSampleSize
750
- ) {
751
- const errorRate = errors / completed;
752
- if (errorRate > options.errorRateThreshold) {
753
- // Switch to fail-fast
754
- throw new Error(`Error rate ${(errorRate * 100).toFixed(1)}% exceeds threshold, switching to fail-fast`);
755
- }
756
- }
757
-
758
- return { status: 'fulfilled', value: result };
759
- } catch (error) {
760
- return { status: 'rejected', reason: error };
761
- }
762
- })
763
- );
764
-
765
- return results;
766
- }
767
- ```
768
-
769
- **Use Case**: High-volume operations where most tasks succeed, but rapid failure indicates systemic issues.
770
-
771
- ### 4.5 Groundswell Decision Framework
772
-
773
- **Question**: Should Groundswell use fail-fast or complete-all by default?
774
-
775
- **Analysis**:
776
-
777
- **Arguments for Fail-Fast (Current)**:
778
- - Workflow engines traditionally emphasize correctness over partial success
779
- - Parent workflows often need to know immediately if children fail
780
- - Simpler mental model for developers
781
- - Lower memory overhead
782
- - Already implemented
783
-
784
- **Arguments for Complete-All (Recommended)**:
785
- - Observability is a core feature (PRD emphasis on logging and debugging)
786
- - Child workflows are often independent (parallel processing pattern)
787
- - "Complete all" provides better error visibility
788
- - Aligns with production patterns (Airflow, Step Functions)
789
- - Enables graceful degradation patterns
790
- - More flexible (can opt-in to fail-fast)
791
-
792
- **Recommendation**: **Default to complete-all with opt-in fail-fast**
793
-
794
- **Rationale**:
795
- 1. Observability First: Groundswell's value prop is debugging and observability
796
- 2. Independent by Default: @Task creates independent child workflows
797
- 3. Error Visibility: Complete-all provides comprehensive error information
798
- 4. Production Patterns: Aligns with Airflow and Step Functions
799
- 5. Flexibility: Developers can opt-in to fail-fast when needed
800
-
801
- ---
802
-
803
- ## 5. Groundswell-Specific Recommendations
804
-
805
- ### 5.1 Current Implementation Analysis
806
-
807
- **File**: `/home/dustin/projects/groundswell/src/decorators/task.ts`
808
-
809
- **Current Behavior (Line 104-114)**:
810
- ```typescript
811
- // If concurrent option is set and we have multiple workflows, run them in parallel
812
- if (opts.concurrent && Array.isArray(result)) {
813
- const runnable = workflows.filter(
814
- (w): w is WorkflowClass =>
815
- w && typeof w === 'object' && 'run' in w && typeof w.run === 'function'
816
- );
817
-
818
- if (runnable.length > 0) {
819
- await Promise.all(runnable.map((w) => w.run()));
820
- }
821
- }
822
- ```
823
-
824
- **Characteristics**:
825
- - Strategy: Fail-fast (Promise.all)
826
- - Error Handling: First error wins
827
- - Partial Results: Lost
828
- - Error Aggregation: None
829
- - Configuration: None (hardcoded)
830
-
831
- **Issues**:
832
- 1. No error aggregation: Only first error is visible
833
- 2. No flexibility: Can't choose strategy
834
- 3. No observability: Loses error information
835
- 4. No graceful degradation: All-or-nothing approach
836
-
837
- ### 5.2 Recommended Enhancement
838
-
839
- #### Phase 1: Add Error Strategy Option
840
-
841
- **Changes to `/home/dustin/projects/groundswell/src/types/decorators.ts`**:
842
-
843
- ```typescript
844
- export interface TaskOptions {
845
- name?: string;
846
- concurrent?: boolean;
847
-
848
- // NEW: Error handling strategy
849
- errorStrategy?: 'fail-fast' | 'complete-all';
850
-
851
- // NEW: Error aggregation (only for 'complete-all')
852
- mergeErrors?: boolean;
853
- }
854
- ```
855
-
856
- **Changes to `/home/dustin/projects/groundswell/src/decorators/task.ts`**:
857
-
858
- ```typescript
859
- // If concurrent option is set and we have multiple workflows, run them in parallel
860
- if (opts.concurrent && Array.isArray(result)) {
861
- const runnable = workflows.filter(
862
- (w): w is WorkflowClass =>
863
- w && typeof w === 'object' && 'run' in w && typeof w.run === 'function'
864
- );
865
-
866
- if (runnable.length > 0) {
867
- const strategy = opts.errorStrategy || 'fail-fast';
868
-
869
- if (strategy === 'fail-fast') {
870
- // Current behavior: Promise.all (fail-fast)
871
- await Promise.all(runnable.map((w) => w.run()));
872
- } else {
873
- // New behavior: Promise.allSettled (complete-all)
874
- const settledResults = await Promise.allSettled(
875
- runnable.map((w) => w.run())
876
- );
877
-
878
- // Collect errors
879
- const errors = settledResults
880
- .map((result, idx) => ({ result, workflow: runnable[idx] }))
881
- .filter(({ result }) => result.status === 'rejected')
882
- .map(({ result, workflow }) => ({
883
- workflowId: workflow.id,
884
- workflowName: workflow.constructor.name,
885
- error: result.status === 'rejected' ? result.reason : undefined,
886
- }));
887
-
888
- // Throw if there were errors
889
- if (errors.length > 0) {
890
- // Create aggregate error with all failures
891
- const aggregateError = new Error(
892
- `${errors.length} child workflow(s) failed in task '${taskName}'`
893
- ) as any;
894
-
895
- aggregateError.name = 'WorkflowAggregateError';
896
- aggregateError.errors = errors;
897
- aggregateError.taskName = taskName;
898
- aggregateError.workflowId = wf.id;
899
- aggregateError.totalChildren = runnable.length;
900
- aggregateError.failedChildren = errors.length;
901
-
902
- throw aggregateError;
903
- }
904
- }
905
- }
906
- }
907
- ```
908
-
909
- #### Phase 2: Implement AggregateError Type
910
-
911
- **New file**: `/home/dustin/projects/groundswell/src/types/aggregate-error.ts`
912
-
913
- ```typescript
914
- import type { WorkflowError } from './error.js';
915
-
916
- /**
917
- * Aggregate error containing multiple child workflow errors
918
- */
919
- export interface WorkflowAggregateError extends Error {
920
- name: 'WorkflowAggregateError';
921
- message: string;
922
- errors: Array<{
923
- workflowId: string;
924
- workflowName: string;
925
- error: unknown;
926
- }>;
927
- taskName: string;
928
- workflowId: string;
929
- totalChildren: number;
930
- failedChildren: number;
931
- }
932
-
933
- /**
934
- * Type guard for WorkflowAggregateError
935
- */
936
- export function isWorkflowAggregateError(
937
- error: unknown
938
- ): error is WorkflowAggregateError {
939
- return (
940
- error instanceof Error &&
941
- (error as any).name === 'WorkflowAggregateError' &&
942
- 'errors' in error &&
943
- 'totalChildren' in error &&
944
- 'failedChildren' in error
945
- );
946
- }
947
-
948
- /**
949
- * Create a workflow aggregate error
950
- */
951
- export function createAggregateError(
952
- errors: Array<{ workflowId: string; workflowName: string; error: unknown }>,
953
- taskName: string,
954
- parentWorkflowId: string
955
- ): WorkflowAggregateError {
956
- const error = new Error(
957
- `${errors.length} child workflow(s) failed in task '${taskName}'`
958
- ) as WorkflowAggregateError;
959
-
960
- error.name = 'WorkflowAggregateError';
961
- error.errors = errors;
962
- error.taskName = taskName;
963
- error.workflowId = parentWorkflowId;
964
- error.totalChildren = errors.length; // Will be updated by caller
965
- error.failedChildren = errors.length;
966
-
967
- return error;
968
- }
969
- ```
970
-
971
- #### Phase 3: Update Error Handling Documentation
972
-
973
- **File**: `/home/dustin/projects/groundswell/docs/workflow.md`
974
-
975
- **Add section**:
976
-
977
- ```markdown
978
- ## Error Handling in Concurrent Tasks
979
-
980
- ### Fail-Fast Strategy (Default)
981
-
982
- When `concurrent: true` is used without specifying `errorStrategy`, the workflow uses a fail-fast approach:
983
-
984
- ```typescript
985
- class ParentWorkflow extends Workflow {
986
- @Task({ concurrent: true })
987
- async createChildren(): Promise<ChildWorkflow[]> {
988
- return [
989
- new ChildWorkflow('child1', this),
990
- new ChildWorkflow('child2', this),
991
- new ChildWorkflow('child3', this),
992
- ];
993
- }
994
-
995
- async run() {
996
- try {
997
- await this.createChildren();
998
- } catch (error) {
999
- // Throws immediately when first child fails
1000
- console.error('First child failed:', error.message);
1001
- }
1002
- }
1003
- }
1004
- ```
1005
-
1006
- ### Complete-All Strategy
1007
-
1008
- To wait for all children to complete and collect all errors:
1009
-
1010
- ```typescript
1011
- class ParentWorkflow extends Workflow {
1012
- @Task({
1013
- concurrent: true,
1014
- errorStrategy: 'complete-all', // Wait for all children
1015
- })
1016
- async createChildren(): Promise<ChildWorkflow[]> {
1017
- return [
1018
- new ChildWorkflow('child1', this),
1019
- new ChildWorkflow('child2', this),
1020
- new ChildWorkflow('child3', this),
1021
- ];
1022
- }
1023
-
1024
- async run() {
1025
- try {
1026
- await this.createChildren();
1027
- } catch (error) {
1028
- if (isWorkflowAggregateError(error)) {
1029
- console.error(`${error.failedChildren}/${error.totalChildren} children failed:`);
1030
-
1031
- for (const failure of error.errors) {
1032
- console.error(` - ${failure.workflowName}: ${failure.error?.message}`);
1033
- }
1034
- }
1035
- }
1036
- }
1037
- }
1038
- ```
1039
-
1040
- ### Choosing the Right Strategy
1041
-
1042
- **Use Fail-Fast When:**
1043
- - Child workflows are dependent on each other
1044
- - Partial success is not meaningful
1045
- - You need immediate feedback on errors
1046
- - Resource conservation is important
1047
-
1048
- **Use Complete-All When:**
1049
- - Child workflows are independent
1050
- - Partial results have value
1051
- - You need comprehensive error reporting
1052
- - Observability is a priority
1053
- ```
1054
-
1055
- ### 5.3 Backward Compatibility
1056
-
1057
- **Recommendation**: Keep current behavior (fail-fast) as default to maintain backward compatibility.
1058
-
1059
- **Rationale**:
1060
- 1. Existing code won't break
1061
- 2. Opt-in to new behavior via `errorStrategy: 'complete-all'`
1062
- 3. Gradual migration path
1063
- 4. Safe default (fail-fast is more conservative)
1064
-
1065
- **Future Enhancement**: Consider changing default to `complete-all` in a major version (2.0).
1066
-
1067
- ### 5.4 Testing Recommendations
1068
-
1069
- **Add tests to** `/home/dustin/projects/groundswell/src/__tests__/adversarial/edge-case.test.ts`:
1070
-
1071
- ```typescript
1072
- describe('Concurrent Error Handling', () => {
1073
- it('should use fail-fast strategy by default', async () => {
1074
- // Test that current behavior is maintained
1075
- });
1076
-
1077
- it('should use complete-all strategy when specified', async () => {
1078
- // Test new behavior with errorStrategy: 'complete-all'
1079
- });
1080
-
1081
- it('should aggregate all errors in complete-all mode', async () => {
1082
- // Test that all errors are collected
1083
- });
1084
-
1085
- it('should preserve error context in aggregate error', async () => {
1086
- // Test that workflow ID, name, etc. are preserved
1087
- });
1088
-
1089
- it('should throw WorkflowAggregateError in complete-all mode', async () => {
1090
- // Test error type and structure
1091
- });
1092
-
1093
- it('should handle partial success in complete-all mode', async () => {
1094
- // Test that some successes + some failures works correctly
1095
- });
1096
- });
1097
- ```
1098
-
1099
- ---
1100
-
1101
- ## 6. Implementation Roadmap
1102
-
1103
- ### Phase 1: Core Implementation (Week 1)
1104
-
1105
- **Tasks**:
1106
- 1. Add `errorStrategy` option to `TaskOptions` interface
1107
- 2. Implement `Promise.allSettled` logic in @Task decorator
1108
- 3. Create `WorkflowAggregateError` type and factory
1109
- 4. Add error collection and aggregation logic
1110
- 5. Update JSDoc comments
1111
-
1112
- **Deliverables**:
1113
- - Enhanced `/home/dustin/projects/groundswell/src/types/decorators.ts`
1114
- - Updated `/home/dustin/projects/groundswell/src/decorators/task.ts`
1115
- - New `/home/dustin/projects/groundswell/src/types/aggregate-error.ts`
1116
-
1117
- **Success Criteria**:
1118
- - TypeScript compiles without errors
1119
- - Existing tests pass (backward compatibility)
1120
- - New behavior accessible via `errorStrategy: 'complete-all'`
1121
-
1122
- ### Phase 2: Testing (Week 1-2)
1123
-
1124
- **Tasks**:
1125
- 1. Add unit tests for error aggregation
1126
- 2. Add integration tests for complete-all strategy
1127
- 3. Add edge case tests (mixed success/failure)
1128
- 4. Add performance tests (compare fail-fast vs complete-all)
1129
- 5. Update example workflows
1130
-
1131
- **Deliverables**:
1132
- - New tests in `/home/dustin/projects/groundswell/src/__tests__/adversarial/edge-case.test.ts`
1133
- - Updated `/home/dustin/projects/groundswell/examples/examples/06-concurrent-tasks.ts`
1134
-
1135
- **Success Criteria**:
1136
- - All tests pass (including new tests)
1137
- - Test coverage > 90% for new code
1138
- - Examples demonstrate both strategies
1139
-
1140
- ### Phase 3: Documentation (Week 2)
1141
-
1142
- **Tasks**:
1143
- 1. Update `/home/dustin/projects/groundswell/docs/workflow.md`
1144
- 2. Add error handling guide
1145
- 3. Update API reference
1146
- 4. Create migration guide
1147
- 5. Add best practices document
1148
-
1149
- **Deliverables**:
1150
- - Updated documentation
1151
- - New error handling guide
1152
- - Migration guide from fail-fast to complete-all
1153
- - Best practices document
1154
-
1155
- **Success Criteria**:
1156
- - All APIs documented
1157
- - Examples cover both strategies
1158
- - Migration path is clear
1159
-
1160
- ### Phase 4: Validation (Week 2)
1161
-
1162
- **Tasks**:
1163
- 1. Manual testing with real workflows
1164
- 2. Performance benchmarking
1165
- 3. Memory profiling
1166
- 4. Error scenario testing
1167
- 5. User acceptance testing
1168
-
1169
- **Deliverables**:
1170
- - Performance benchmarks
1171
- - Memory profiles
1172
- - Test results report
1173
- - Bug fixes (if any)
1174
-
1175
- **Success Criteria**:
1176
- - Performance acceptable (< 10% overhead)
1177
- - No memory leaks
1178
- - All error scenarios handled correctly
1179
- - Users can use both strategies effectively
1180
-
1181
- ---
1182
-
1183
- ## 7. Appendix: Code Examples
1184
-
1185
- ### 7.1 Complete Example: Fail-Fast vs Complete-All
1186
-
1187
- ```typescript
1188
- import { Workflow, Task, Step } from 'groundswell';
1189
-
1190
- // Child workflow that may fail
1191
- class DataProcessor extends Workflow {
1192
- constructor(
1193
- public id: string,
1194
- public shouldFail: boolean = false,
1195
- parent?: Workflow
1196
- ) {
1197
- super(id, parent);
1198
- }
1199
-
1200
- @Step()
1201
- async process(): Promise<string> {
1202
- if (this.shouldFail) {
1203
- throw new Error(`Processing failed in ${this.id}`);
1204
- }
1205
- return `Processed by ${this.id}`;
1206
- }
1207
-
1208
- async run(): Promise<string> {
1209
- this.setStatus('running');
1210
- const result = await this.process();
1211
- this.setStatus('completed');
1212
- return result;
1213
- }
1214
- }
1215
-
1216
- // Parent workflow using fail-fast (default)
1217
- class FailFastParent extends Workflow {
1218
- @Task({ concurrent: true })
1219
- async spawnProcessors(): Promise<DataProcessor[]> {
1220
- return [
1221
- new DataProcessor('processor-1', false, this),
1222
- new DataProcessor('processor-2', true, this), // This will fail
1223
- new DataProcessor('processor-3', false, this),
1224
- ];
1225
- }
1226
-
1227
- async run(): Promise<void> {
1228
- this.setStatus('running');
1229
-
1230
- try {
1231
- await this.spawnProcessors();
1232
- console.log('All processors completed successfully');
1233
- } catch (error) {
1234
- console.error('Fail-fast: Stopped at first error');
1235
- console.error('Error:', error.message);
1236
- // processor-3 never runs
1237
- // Only processor-2's error is visible
1238
- }
1239
-
1240
- this.setStatus('completed');
1241
- }
1242
- }
1243
-
1244
- // Parent workflow using complete-all
1245
- class CompleteAllParent extends Workflow {
1246
- @Task({
1247
- concurrent: true,
1248
- errorStrategy: 'complete-all', // NEW: Wait for all
1249
- })
1250
- async spawnProcessors(): Promise<DataProcessor[]> {
1251
- return [
1252
- new DataProcessor('processor-1', false, this),
1253
- new DataProcessor('processor-2', true, this), // This will fail
1254
- new DataProcessor('processor-3', false, this),
1255
- ];
1256
- }
1257
-
1258
- async run(): Promise<void> {
1259
- this.setStatus('running');
1260
-
1261
- try {
1262
- await this.spawnProcessors();
1263
- console.log('All processors completed successfully');
1264
- } catch (error) {
1265
- if (error.name === 'WorkflowAggregateError') {
1266
- console.error('Complete-all: All processors completed');
1267
- console.error(`${error.failedChildren}/${error.totalChildren} failed:`);
1268
-
1269
- for (const failure of error.errors) {
1270
- console.error(` - ${failure.workflowName}: ${failure.error?.message}`);
1271
- }
1272
-
1273
- // processor-1 and processor-3 completed successfully
1274
- // processor-2's error is visible
1275
- // All errors are aggregated
1276
- }
1277
- }
1278
-
1279
- this.setStatus('completed');
1280
- }
1281
- }
1282
- ```
1283
-
1284
- ### 7.2 Error Aggregation Implementation
1285
-
1286
- ```typescript
1287
- /**
1288
- * Aggregate multiple workflow errors into a single error
1289
- */
1290
- class WorkflowAggregateError extends Error {
1291
- constructor(
1292
- message: string,
1293
- public errors: Array<{
1294
- workflowId: string;
1295
- workflowName: string;
1296
- error: unknown;
1297
- }>,
1298
- public taskName: string,
1299
- public workflowId: string,
1300
- public totalChildren: number,
1301
- public failedChildren: number
1302
- ) {
1303
- super(message);
1304
- this.name = 'WorkflowAggregateError';
1305
- }
1306
-
1307
- /**
1308
- * Pretty-print the aggregate error
1309
- */
1310
- toString(): string {
1311
- let output = `${this.taskName}: ${this.message}\n`;
1312
- output += ` Total: ${this.totalChildren}, Failed: ${this.failedChildren}\n`;
1313
- output += ` Success Rate: ${((1 - this.failedChildren / this.totalChildren) * 100).toFixed(1)}%\n`;
1314
-
1315
- for (const failure of this.errors) {
1316
- output += ` - ${failure.workflowName} (${failure.workflowId}):\n`;
1317
- output += ` ${failure.error?.message || 'Unknown error'}\n`;
1318
- }
1319
-
1320
- return output;
1321
- }
1322
-
1323
- /**
1324
- * Get error statistics
1325
- */
1326
- getStats() {
1327
- const errorsByType = new Map<string, number>();
1328
- const errorsByWorkflow = new Map<string, number>();
1329
-
1330
- for (const failure of this.errors) {
1331
- const errorType = failure.error?.constructor.name || 'Unknown';
1332
- errorsByType.set(errorType, (errorsByType.get(errorType) || 0) + 1);
1333
- errorsByWorkflow.set(
1334
- failure.workflowName,
1335
- (errorsByWorkflow.get(failure.workflowName) || 0) + 1
1336
- );
1337
- }
1338
-
1339
- return {
1340
- totalErrors: this.errors.length,
1341
- totalChildren: this.totalChildren,
1342
- failedChildren: this.failedChildren,
1343
- successRate: (1 - this.failedChildren / this.totalChildren) * 100,
1344
- errorsByType: Object.fromEntries(errorsByType),
1345
- errorsByWorkflow: Object.fromEntries(errorsByWorkflow),
1346
- };
1347
- }
1348
- }
1349
- ```
1350
-
1351
- ### 7.3 Usage in Production
1352
-
1353
- ```typescript
1354
- // Real-world example: Bulk data synchronization
1355
- class DataSyncWorkflow extends Workflow {
1356
- @ObservedState()
1357
- recordsProcessed = 0;
1358
-
1359
- @ObservedState()
1360
- recordsFailed = 0;
1361
-
1362
- @ObservedState()
1363
- syncStartTime = 0;
1364
-
1365
- @Task({
1366
- concurrent: true,
1367
- errorStrategy: 'complete-all', // Try all records
1368
- })
1369
- async syncRecords(records: Record[]): Promise<RecordSyncWorkflow[]> {
1370
- return records.map(
1371
- (record) => new RecordSyncWorkflow(record, this)
1372
- );
1373
- }
1374
-
1375
- @Step({ snapshotState: true })
1376
- async aggregateResults(results: PromiseSettledResult<unknown>[]): Promise<void> {
1377
- const succeeded = results.filter((r) => r.status === 'fulfilled');
1378
- const failed = results.filter((r) => r.status === 'rejected');
1379
-
1380
- this.recordsProcessed = succeeded.length;
1381
- this.recordsFailed = failed.length;
1382
-
1383
- this.logger.info(`Sync complete: ${succeeded.length} succeeded, ${failed.length} failed`);
1384
-
1385
- if (failed.length > 0) {
1386
- this.logger.warn(`${failed.length} records failed to sync, will retry`);
1387
- }
1388
- }
1389
-
1390
- async run(records: Record[]): Promise<SyncResults> {
1391
- this.setStatus('running');
1392
- this.syncStartTime = Date.now();
1393
-
1394
- try {
1395
- await this.syncRecords(records);
1396
-
1397
- // Continue despite partial failures
1398
- return {
1399
- total: records.length,
1400
- succeeded: this.recordsProcessed,
1401
- failed: this.recordsFailed,
1402
- duration: Date.now() - this.syncStartTime,
1403
- };
1404
- } catch (error) {
1405
- if (error.name === 'WorkflowAggregateError') {
1406
- // Log all failures but don't fail the workflow
1407
- this.logger.warn(`Partial sync complete: ${error.failedChildren}/${error.totalChildren} failed`);
1408
-
1409
- return {
1410
- total: records.length,
1411
- succeeded: error.totalChildren - error.failedChildren,
1412
- failed: error.failedChildren,
1413
- duration: Date.now() - this.syncStartTime,
1414
- errors: error.errors,
1415
- };
1416
- }
1417
- throw error;
1418
- } finally {
1419
- this.setStatus('completed');
1420
- }
1421
- }
1422
- }
1423
- ```
1424
-
1425
- ---
1426
-
1427
- ## 8. Conclusion
1428
-
1429
- ### 8.1 Summary of Findings
1430
-
1431
- 1. **Promise.all vs Promise.allSettled**:
1432
- - Promise.all (fail-fast): Fast, simple, but loses error information
1433
- - Promise.allSettled (complete-all): Slower, more complex, but provides complete error visibility
1434
- - **Recommendation**: Support both strategies via configuration
1435
-
1436
- 2. **Production Workflow Engines**:
1437
- - Temporal: Parent close policies, configurable cancellation
1438
- - Step Functions: Parallel states with error aggregation
1439
- - Cadence: Exception-based error propagation
1440
- - Airflow: Trigger rules for flexible execution
1441
- - **Gap**: Groundswell lacks error aggregation and flexible error strategies
1442
-
1443
- 3. **Error Aggregation Strategies**:
1444
- - First error wins: Simple but limited (current implementation)
1445
- - Collect all errors: Comprehensive error visibility (recommended)
1446
- - Hierarchical merging: Maintains workflow context
1447
- - Threshold-based: Graceful degradation
1448
- - **Recommendation**: Implement collect-all with hierarchical context
1449
-
1450
- 4. **Fail-Fast vs Complete-All**:
1451
- - Fail-fast: Critical workflows, dependent tasks, fast feedback
1452
- - Complete-all: Independent tasks, partial success, observability
1453
- - **Recommendation**: Default to complete-all for Groundswell (observability-first design)
1454
-
1455
- ### 8.2 Recommendations for Groundswell
1456
-
1457
- **Priority 1 (Immediate)**:
1458
- 1. Add `errorStrategy` option to `TaskOptions`
1459
- 2. Implement `Promise.allSettled` path in @Task decorator
1460
- 3. Create `WorkflowAggregateError` type
1461
- 4. Maintain backward compatibility (fail-fast as default)
1462
-
1463
- **Priority 2 (Short-term)**:
1464
- 1. Add comprehensive error aggregation
1465
- 2. Include workflow context in errors
1466
- 3. Add error statistics and pretty-printing
1467
- 4. Update documentation and examples
1468
-
1469
- **Priority 3 (Long-term)**:
1470
- 1. Consider changing default to complete-all in v2.0
1471
- 2. Add retry policies per child workflow
1472
- 3. Implement threshold-based error handling
1473
- 4. Add error rate monitoring and alerting
1474
-
1475
- ### 8.3 Impact Assessment
1476
-
1477
- **Benefits**:
1478
- - Better observability: See all errors, not just first
1479
- - Graceful degradation: Partial success scenarios
1480
- - Production-ready: Aligns with industry patterns
1481
- - Debugging: Comprehensive error information
1482
- - Flexibility: Developers choose strategy per task
1483
-
1484
- **Costs**:
1485
- - Complexity: More configuration options
1486
- - Memory: Storing all errors (mitigated by error limiting)
1487
- - Performance: Waiting for all tasks to complete (mitigated by configurable strategy)
1488
- - Learning curve: Developers need to understand both strategies
1489
-
1490
- **Risk Mitigation**:
1491
- - Backward compatibility: Default to fail-fast
1492
- - Gradual migration: Opt-in to complete-all
1493
- - Documentation: Clear examples and best practices
1494
- - Testing: Comprehensive test coverage
1495
-
1496
- ---
1497
-
1498
- ## References
1499
-
1500
- ### Production Documentation
1501
-
1502
- 1. **Temporal.io**: Child Workflows and Error Handling
1503
- - https://docs.temporal.io/develop/typescript/child-workflows
1504
- - Key concepts: Parent close policy, cancellation scopes, retry policies
1505
-
1506
- 2. **AWS Step Functions**: Error Handling
1507
- - https://docs.aws.amazon.com/step-functions/latest/dg/concepts-error-handling.html
1508
- - Key concepts: Retry blocks, catch blocks, parallel state error aggregation
1509
-
1510
- 3. **Cadence Workflow**: Execution Patterns
1511
- - https://cadenceworkflow.io/docs/concepts/execution/
1512
- - Key concepts: Exception-based error propagation, child workflow isolation
1513
-
1514
- 4. **Apache Airflow**: Task Instances and Trigger Rules
1515
- - https://airflow.apache.org/docs/apache-airflow/stable/core-concepts/dags.html
1516
- - Key concepts: Trigger rules, task dependencies, failure handlers
1517
-
1518
- ### JavaScript/TypeScript Documentation
1519
-
1520
- 5. **MDN: Promise.all()**
1521
- - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
1522
- - Fail-fast behavior, rejection handling
1523
-
1524
- 6. **MDN: Promise.allSettled()**
1525
- - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled
1526
- - Complete-all behavior, status objects
1527
-
1528
- 7. **Node.js: Asynchronous Work**
1529
- - https://nodejs.dev/en/learn/asynchronous-work/
1530
- - Async/await patterns, error handling
1531
-
1532
- ### Groundswell Codebase
1533
-
1534
- 8. **@Task Decorator Implementation**
1535
- - `/home/dustin/projects/groundswell/src/decorators/task.ts`
1536
- - Current fail-fast implementation
1537
-
1538
- 9. **Error Strategy Types**
1539
- - `/home/dustin/projects/groundswell/src/types/error-strategy.ts`
1540
- - Defined but not implemented
1541
-
1542
- 10. **Workflow Documentation**
1543
- - `/home/dustin/projects/groundswell/docs/workflow.md`
1544
- - Current error handling patterns
1545
-
1546
- 11. **Concurrent Tasks Example**
1547
- - `/home/dustin/projects/groundswell/examples/examples/06-concurrent-tasks.ts`
1548
- - Real-world usage examples
1549
-
1550
- ### Research Context
1551
-
1552
- 12. **Error Handling Best Practices Research**
1553
- - `/home/dustin/projects/groundswell/plan/docs/research/error_handling_patterns.md`
1554
- - TypeScript error handling patterns, state capture
1555
-
1556
- 13. **PRD: Hierarchical Workflow Engine**
1557
- - `/home/dustin/projects/groundswell/PRPs/001-hierarchical-workflow-engine.md`
1558
- - Requirements for observability and error handling
1559
-
1560
- ---
1561
-
1562
- **Document Version**: 1.0
1563
- **Last Updated**: 2026-01-12
1564
- **Status**: Ready for Implementation
1565
- **Next Review**: After Phase 1 Implementation