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.
- package/LICENSE +21 -0
- package/README.md +26 -9
- package/dist/cache/cache-key.d.ts +86 -0
- package/dist/cache/cache-key.d.ts.map +1 -0
- package/dist/cache/cache-key.js +204 -0
- package/dist/cache/cache-key.js.map +1 -0
- package/dist/cache/cache.d.ts +104 -0
- package/dist/cache/cache.d.ts.map +1 -0
- package/dist/cache/cache.js +179 -0
- package/dist/cache/cache.js.map +1 -0
- package/{src/cache/index.ts → dist/cache/index.d.ts} +1 -1
- package/dist/cache/index.d.ts.map +1 -0
- package/dist/cache/index.js +6 -0
- package/dist/cache/index.js.map +1 -0
- package/dist/core/agent.d.ts +203 -0
- package/dist/core/agent.d.ts.map +1 -0
- package/dist/core/agent.js +833 -0
- package/dist/core/agent.js.map +1 -0
- package/{src/core/context.ts → dist/core/context.d.ts} +16 -67
- package/dist/core/context.d.ts.map +1 -0
- package/dist/core/context.js +80 -0
- package/dist/core/context.js.map +1 -0
- package/dist/core/event-tree.d.ts +72 -0
- package/dist/core/event-tree.d.ts.map +1 -0
- package/dist/core/event-tree.js +211 -0
- package/dist/core/event-tree.js.map +1 -0
- package/{src/core/factory.ts → dist/core/factory.d.ts} +6 -27
- package/dist/core/factory.d.ts.map +1 -0
- package/dist/core/factory.js +110 -0
- package/dist/core/factory.js.map +1 -0
- package/{src/core/index.ts → dist/core/index.d.ts} +2 -10
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +9 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/logger.d.ts +50 -0
- package/dist/core/logger.d.ts.map +1 -0
- package/dist/core/logger.js +91 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/mcp-handler.d.ts +127 -0
- package/dist/core/mcp-handler.d.ts.map +1 -0
- package/dist/core/mcp-handler.js +323 -0
- package/dist/core/mcp-handler.js.map +1 -0
- package/dist/core/prompt.d.ts +80 -0
- package/dist/core/prompt.d.ts.map +1 -0
- package/dist/core/prompt.js +120 -0
- package/dist/core/prompt.js.map +1 -0
- package/dist/core/workflow-context.d.ts +61 -0
- package/dist/core/workflow-context.d.ts.map +1 -0
- package/dist/core/workflow-context.js +358 -0
- package/dist/core/workflow-context.js.map +1 -0
- package/dist/core/workflow.d.ts +543 -0
- package/dist/core/workflow.d.ts.map +1 -0
- package/dist/core/workflow.js +986 -0
- package/dist/core/workflow.js.map +1 -0
- package/dist/debugger/event-replayer.d.ts +422 -0
- package/dist/debugger/event-replayer.d.ts.map +1 -0
- package/dist/debugger/event-replayer.js +639 -0
- package/dist/debugger/event-replayer.js.map +1 -0
- package/dist/debugger/index.d.ts +2 -0
- package/dist/debugger/index.d.ts.map +1 -0
- package/{src/debugger/index.ts → dist/debugger/index.js} +1 -0
- package/dist/debugger/index.js.map +1 -0
- package/dist/debugger/tree-debugger.d.ts +240 -0
- package/dist/debugger/tree-debugger.d.ts.map +1 -0
- package/dist/debugger/tree-debugger.js +620 -0
- package/dist/debugger/tree-debugger.js.map +1 -0
- package/dist/decorators/index.d.ts +4 -0
- package/dist/decorators/index.d.ts.map +1 -0
- package/{src/decorators/index.ts → dist/decorators/index.js} +1 -0
- package/dist/decorators/index.js.map +1 -0
- package/dist/decorators/observed-state.d.ts +32 -0
- package/dist/decorators/observed-state.d.ts.map +1 -0
- package/dist/decorators/observed-state.js +79 -0
- package/dist/decorators/observed-state.js.map +1 -0
- package/dist/decorators/step.d.ts +15 -0
- package/dist/decorators/step.d.ts.map +1 -0
- package/dist/decorators/step.js +192 -0
- package/dist/decorators/step.js.map +1 -0
- package/dist/decorators/task.d.ts +50 -0
- package/dist/decorators/task.d.ts.map +1 -0
- package/dist/decorators/task.js +118 -0
- package/dist/decorators/task.js.map +1 -0
- package/dist/examples/index.d.ts +3 -0
- package/dist/examples/index.d.ts.map +1 -0
- package/{src/examples/index.ts → dist/examples/index.js} +1 -0
- package/dist/examples/index.js.map +1 -0
- package/dist/examples/tdd-orchestrator.d.ts +15 -0
- package/dist/examples/tdd-orchestrator.d.ts.map +1 -0
- package/dist/examples/tdd-orchestrator.js +121 -0
- package/dist/examples/tdd-orchestrator.js.map +1 -0
- package/dist/examples/test-cycle-workflow.d.ts +14 -0
- package/dist/examples/test-cycle-workflow.d.ts.map +1 -0
- package/dist/examples/test-cycle-workflow.js +116 -0
- package/dist/examples/test-cycle-workflow.js.map +1 -0
- package/dist/harnesses/claude-code-harness.d.ts +391 -0
- package/dist/harnesses/claude-code-harness.d.ts.map +1 -0
- package/dist/harnesses/claude-code-harness.js +1076 -0
- package/dist/harnesses/claude-code-harness.js.map +1 -0
- package/dist/harnesses/harness-registry.d.ts +440 -0
- package/dist/harnesses/harness-registry.d.ts.map +1 -0
- package/dist/harnesses/harness-registry.js +543 -0
- package/dist/harnesses/harness-registry.js.map +1 -0
- package/dist/harnesses/index.d.ts +12 -0
- package/dist/harnesses/index.d.ts.map +1 -0
- package/dist/harnesses/index.js +11 -0
- package/dist/harnesses/index.js.map +1 -0
- package/dist/harnesses/pi-harness.d.ts +219 -0
- package/dist/harnesses/pi-harness.d.ts.map +1 -0
- package/dist/harnesses/pi-harness.js +676 -0
- package/dist/harnesses/pi-harness.js.map +1 -0
- package/dist/harnesses/pi-schema-converter.d.ts +24 -0
- package/dist/harnesses/pi-schema-converter.d.ts.map +1 -0
- package/dist/harnesses/pi-schema-converter.js +81 -0
- package/dist/harnesses/pi-schema-converter.js.map +1 -0
- package/dist/harnesses/register-defaults.d.ts +24 -0
- package/dist/harnesses/register-defaults.d.ts.map +1 -0
- package/dist/harnesses/register-defaults.js +40 -0
- package/dist/harnesses/register-defaults.js.map +1 -0
- package/dist/harnesses/session-store.d.ts +201 -0
- package/dist/harnesses/session-store.d.ts.map +1 -0
- package/dist/harnesses/session-store.js +254 -0
- package/dist/harnesses/session-store.js.map +1 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +57 -0
- package/dist/index.js.map +1 -0
- package/dist/reflection/index.d.ts +5 -0
- package/dist/reflection/index.d.ts.map +1 -0
- package/{src/reflection/index.ts → dist/reflection/index.js} +1 -1
- package/dist/reflection/index.js.map +1 -0
- package/dist/reflection/reflection.d.ts +84 -0
- package/dist/reflection/reflection.d.ts.map +1 -0
- package/dist/reflection/reflection.js +344 -0
- package/dist/reflection/reflection.js.map +1 -0
- package/dist/tools/index.d.ts +6 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +11 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/introspection.d.ts +165 -0
- package/dist/tools/introspection.d.ts.map +1 -0
- package/dist/tools/introspection.js +324 -0
- package/dist/tools/introspection.js.map +1 -0
- package/dist/types/agent.d.ts +1317 -0
- package/dist/types/agent.d.ts.map +1 -0
- package/dist/types/agent.js +423 -0
- package/dist/types/agent.js.map +1 -0
- package/dist/types/decorators.d.ts +40 -0
- package/dist/types/decorators.d.ts.map +1 -0
- package/dist/types/decorators.js +2 -0
- package/dist/types/decorators.js.map +1 -0
- package/dist/types/error-strategy.d.ts +13 -0
- package/dist/types/error-strategy.d.ts.map +1 -0
- package/dist/types/error-strategy.js +2 -0
- package/dist/types/error-strategy.js.map +1 -0
- package/dist/types/error.d.ts +20 -0
- package/dist/types/error.d.ts.map +1 -0
- package/dist/types/error.js +2 -0
- package/dist/types/error.js.map +1 -0
- package/dist/types/events.d.ts +113 -0
- package/dist/types/events.d.ts.map +1 -0
- package/dist/types/events.js +2 -0
- package/dist/types/events.js.map +1 -0
- package/dist/types/harnesses.d.ts +474 -0
- package/dist/types/harnesses.d.ts.map +1 -0
- package/dist/types/harnesses.js +2 -0
- package/dist/types/harnesses.js.map +1 -0
- package/dist/types/index.d.ts +23 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +8 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/logging.d.ts +24 -0
- package/dist/types/logging.d.ts.map +1 -0
- package/dist/types/logging.js +2 -0
- package/dist/types/logging.js.map +1 -0
- package/dist/types/observer.d.ts +18 -0
- package/dist/types/observer.d.ts.map +1 -0
- package/dist/types/observer.js +2 -0
- package/dist/types/observer.js.map +1 -0
- package/dist/types/prompt.d.ts +31 -0
- package/dist/types/prompt.d.ts.map +1 -0
- package/dist/types/prompt.js +6 -0
- package/dist/types/prompt.js.map +1 -0
- package/dist/types/providers.d.ts +691 -0
- package/dist/types/providers.d.ts.map +1 -0
- package/dist/types/providers.js +14 -0
- package/dist/types/providers.js.map +1 -0
- package/dist/types/reflection.d.ts +96 -0
- package/dist/types/reflection.d.ts.map +1 -0
- package/dist/types/reflection.js +24 -0
- package/dist/types/reflection.js.map +1 -0
- package/dist/types/restart.d.ts +132 -0
- package/dist/types/restart.d.ts.map +1 -0
- package/dist/types/restart.js +2 -0
- package/dist/types/restart.js.map +1 -0
- package/dist/types/sdk-primitives.d.ts +118 -0
- package/dist/types/sdk-primitives.d.ts.map +1 -0
- package/dist/types/sdk-primitives.js +6 -0
- package/dist/types/sdk-primitives.js.map +1 -0
- package/{src/types/snapshot.ts → dist/types/snapshot.d.ts} +5 -5
- package/dist/types/snapshot.d.ts.map +1 -0
- package/dist/types/snapshot.js +2 -0
- package/dist/types/snapshot.js.map +1 -0
- package/dist/types/streaming.d.ts +194 -0
- package/dist/types/streaming.d.ts.map +1 -0
- package/dist/types/streaming.js +67 -0
- package/dist/types/streaming.js.map +1 -0
- package/dist/types/workflow-context.d.ts +275 -0
- package/dist/types/workflow-context.d.ts.map +1 -0
- package/dist/types/workflow-context.js +8 -0
- package/dist/types/workflow-context.js.map +1 -0
- package/dist/types/workflow.d.ts +30 -0
- package/dist/types/workflow.d.ts.map +1 -0
- package/dist/types/workflow.js +2 -0
- package/dist/types/workflow.js.map +1 -0
- package/dist/utils/agent-validation.d.ts +88 -0
- package/dist/utils/agent-validation.d.ts.map +1 -0
- package/dist/utils/agent-validation.js +87 -0
- package/dist/utils/agent-validation.js.map +1 -0
- package/dist/utils/delay.d.ts +7 -0
- package/dist/utils/delay.d.ts.map +1 -0
- package/dist/utils/delay.js +9 -0
- package/dist/utils/delay.js.map +1 -0
- package/dist/utils/harness-config.d.ts +180 -0
- package/dist/utils/harness-config.d.ts.map +1 -0
- package/dist/utils/harness-config.js +311 -0
- package/dist/utils/harness-config.js.map +1 -0
- package/dist/utils/id.d.ts +6 -0
- package/dist/utils/id.d.ts.map +1 -0
- package/dist/utils/id.js +12 -0
- package/dist/utils/id.js.map +1 -0
- package/dist/utils/index.d.ts +13 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +11 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/model-spec.d.ts +110 -0
- package/dist/utils/model-spec.d.ts.map +1 -0
- package/dist/utils/model-spec.js +149 -0
- package/dist/utils/model-spec.js.map +1 -0
- package/dist/utils/observable.d.ts +54 -0
- package/dist/utils/observable.d.ts.map +1 -0
- package/dist/utils/observable.js +82 -0
- package/dist/utils/observable.js.map +1 -0
- package/dist/utils/provider-config.d.ts +10 -0
- package/dist/utils/provider-config.d.ts.map +1 -0
- package/dist/utils/provider-config.js +10 -0
- package/dist/utils/provider-config.js.map +1 -0
- package/dist/utils/restart-analysis.d.ts +202 -0
- package/dist/utils/restart-analysis.d.ts.map +1 -0
- package/dist/utils/restart-analysis.js +426 -0
- package/dist/utils/restart-analysis.js.map +1 -0
- package/dist/utils/session-serialization.d.ts +118 -0
- package/dist/utils/session-serialization.d.ts.map +1 -0
- package/dist/utils/session-serialization.js +217 -0
- package/dist/utils/session-serialization.js.map +1 -0
- package/dist/utils/workflow-error-utils.d.ts +22 -0
- package/dist/utils/workflow-error-utils.d.ts.map +1 -0
- package/dist/utils/workflow-error-utils.js +45 -0
- package/dist/utils/workflow-error-utils.js.map +1 -0
- package/package.json +34 -5
- package/.claude/commands/subtask-planning/prp-base-create.md +0 -120
- package/.claude/commands/subtask-planning/prp-base-execute.md +0 -65
- package/.claude/commands/task-breakdown.md +0 -94
- package/.claude/settings.local.json +0 -9
- package/.claude/system_prompts/task-breakdown.md +0 -101
- package/CHANGELOG.md +0 -188
- package/PRD.md +0 -543
- package/PRPs/001-hierarchical-workflow-engine.md +0 -2438
- package/PRPs/PRDs/002-agent-prompt.md +0 -390
- package/PRPs/PRDs/003-agent-prompt.md +0 -943
- package/PRPs/PRDs/004-agent-prompt.md +0 -1136
- package/PRPs/PRDs/tasks-001.json +0 -492
- package/PRPs/README.md +0 -83
- package/PRPs/templates/prp_base.md +0 -222
- package/docs/agent.md +0 -422
- package/docs/prompt.md +0 -419
- package/docs/workflow.md +0 -600
- package/examples/README.md +0 -258
- package/examples/examples/01-basic-workflow.ts +0 -100
- package/examples/examples/02-decorator-options.ts +0 -217
- package/examples/examples/03-parent-child.ts +0 -241
- package/examples/examples/04-observers-debugger.ts +0 -340
- package/examples/examples/05-error-handling.ts +0 -387
- package/examples/examples/06-concurrent-tasks.ts +0 -352
- package/examples/examples/07-agent-loops.ts +0 -432
- package/examples/examples/08-sdk-features.ts +0 -667
- package/examples/examples/09-reflection.ts +0 -573
- package/examples/examples/10-introspection.ts +0 -550
- package/examples/examples/11-reparenting-workflows.ts +0 -269
- package/examples/index.ts +0 -147
- package/examples/utils/helpers.ts +0 -57
- package/package-lock.json +0 -2398
- package/plan/001_d3bb02af4886/TEST_RESULTS.md +0 -259
- package/plan/001_d3bb02af4886/backlog.json +0 -867
- package/plan/001_d3bb02af4886/bug_fix_tasks.json +0 -484
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M1T1S1/PRP.md +0 -488
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M1T1S2/PRP.md +0 -581
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M1T1S3/PRP.md +0 -687
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T1S1/PRP.md +0 -492
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T1S3/PRP.md +0 -932
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T1S3/research/concurrent_error_testing_patterns.md +0 -1109
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T1S3/research/vitest_concurrent_testing.md +0 -802
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T1S3/research/workflow_engine_test_references.md +0 -603
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T2S1/PRP.md +0 -564
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T2S3/PRP.md +0 -518
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T2S4/PRP.md +0 -1252
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T3S1/PRP.md +0 -364
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T3S1/research/CODEBASE_INVENTORY.md +0 -114
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T3S1/research/DECORATOR_DOCUMENTATION_PATTERNS.md +0 -205
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T3S1/research/PRD_LOCATION_ANALYSIS.md +0 -199
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T3S1/research/ULTRATHINK_PRP_PLAN.md +0 -134
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T1S1/PRP.md +0 -495
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T1S1/research/console_error_inventory.md +0 -435
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T1S2/PRP.md +0 -506
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T1S3/PRP.md +0 -612
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T2S2/PRP.md +0 -558
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T2S2/research/external_research.md +0 -788
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T3S2/PRP.md +0 -460
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T3S3/PRP.md +0 -454
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T4S1/PRP.md +0 -520
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T4S1/RECOMMENDATION.md +0 -417
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T4S1/research/external_workflow_engines_research.md +0 -760
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T4S1/research/security_implications_analysis.md +0 -245
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T4S2/PRP.md +0 -792
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S1/PRP.md +0 -535
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S1/TEST_EXECUTION_REPORT.md +0 -190
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S2/PRP.md +0 -654
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S2/TEST_FIX_REPORT.md +0 -227
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S2/research/KEY_FINDINGS.md +0 -345
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S2/research/QUICK_REFERENCE.md +0 -193
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S2/research/test_maintenance_research.md +0 -1323
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T3S1/BREAKING_CHANGES_AUDIT.md +0 -1011
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T3S1/PRP.md +0 -927
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T3S2/PRP.md +0 -505
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/architecture/logger_child_signature_analysis.md +0 -401
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S3/child_implementation_research.md +0 -142
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S3/test_patterns_research.md +0 -112
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S3/vitest_patterns_research.md +0 -159
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S4/PRP.md +0 -549
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S4/VERIFICATION_REPORT.md +0 -368
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S4/edge_case_analysis.md +0 -172
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S4/usage_inventory.md +0 -175
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T1S2/PRP.md +0 -696
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T1S4/PRP.md +0 -860
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/PRP.md +0 -1066
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/01-testing-aggregated-errors.md +0 -1103
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/01_typescript_error_aggregation_patterns.md +0 -789
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/02-error-merge-strategy-testing-guide.md +0 -1098
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/02_aggregate_error_patterns.md +0 -1037
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/03-promise-allsettled-testing-patterns.md +0 -916
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/03_error_merging_strategies.md +0 -1045
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/04_github_stackoverflow_examples.md +0 -890
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/05_comprehensive_summary.md +0 -822
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/INDEX.md +0 -668
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/QUICK_REFERENCE.md +0 -706
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/README.md +0 -265
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/RESEARCH_REPORT.md +0 -655
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S4/research/vitest_testing_patterns.md +0 -1103
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T3S2/PRP.md +0 -426
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T1S2/PRP.md +0 -506
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T1S2/research/QUICK_REFERENCE.md +0 -114
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T1S2/research/RESEARCH_SUMMARY.md +0 -316
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T1S2/research/vitest_observer_error_logging_best_practices.md +0 -754
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T1S3/PRP.md +0 -612
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T2S1/PRP.md +0 -719
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T2S1/README.md +0 -215
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T2S1/analysis.md +0 -765
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T2S3/PRP.md +0 -718
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T3S1/DECISION.md +0 -149
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T3S1/PRP.md +0 -470
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T3S1/research/ULTRATHINK_PLAN.md +0 -332
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T3S1/research/codebase_workflow_name_analysis.md +0 -167
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T3S1/research/external_best_practices.md +0 -265
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T3S1/research/validation_patterns.md +0 -273
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T4S1/workflow_engine_ancestry_api_research.md +0 -760
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T4S3-PRP.md +0 -434
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M4T2S1/PRP.md +0 -717
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M4T2S2/PRP.md +0 -472
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M4T2S2/VALIDATION_REPORT.md +0 -125
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M4T2S2/research/ULTRATHINK_PRP_PLAN.md +0 -301
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/error-logging-best-practices.md +0 -1170
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/research_typescript_partial_and_overloads.md +0 -940
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/vitest-quick-reference.md +0 -151
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/vitest-research.md +0 -650
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/prd_snapshot.md +0 -259
- package/plan/001_d3bb02af4886/bugfix/P1M1T1S1/PRP.md +0 -457
- package/plan/001_d3bb02af4886/bugfix/RESEARCH_SUMMARY.md +0 -346
- package/plan/001_d3bb02af4886/bugfix/architecture/codebase_structure.md +0 -311
- package/plan/001_d3bb02af4886/bugfix/architecture/concurrent_execution_best_practices.md +0 -1565
- package/plan/001_d3bb02af4886/bugfix/architecture/error_handling_patterns.md +0 -288
- package/plan/001_d3bb02af4886/bugfix/architecture/promise_all_analysis.md +0 -741
- package/plan/001_d3bb02af4886/docs/PRP/P1M1T1S4-functional-workflow-error-state-capture-test.md +0 -652
- package/plan/001_d3bb02af4886/docs/PRP/P1P2-PRP.md +0 -527
- package/plan/001_d3bb02af4886/docs/PRP/P3P4-PRP.md +0 -1388
- package/plan/001_d3bb02af4886/docs/PRP/P4P5-PRP.md +0 -1136
- package/plan/001_d3bb02af4886/docs/PRP/PRP.md +0 -527
- package/plan/001_d3bb02af4886/docs/PRP/bugfix/P1M1T2S1-PRP.md +0 -415
- package/plan/001_d3bb02af4886/docs/PRP/bugfix/P1M1T2S2-PRP.md +0 -378
- package/plan/001_d3bb02af4886/docs/PRP/bugfix/P1M1T2S4-PRP.md +0 -713
- package/plan/001_d3bb02af4886/docs/PRP/bugfix/P1M2T1S4-PRP.md +0 -370
- package/plan/001_d3bb02af4886/docs/PRP_P1M3T1S3.md +0 -499
- package/plan/001_d3bb02af4886/docs/TEST_RESULTS.md +0 -230
- package/plan/001_d3bb02af4886/docs/architecture/external_deps.md +0 -358
- package/plan/001_d3bb02af4886/docs/architecture/system_context.md +0 -242
- package/plan/001_d3bb02af4886/docs/bugfix/ANALYSIS_PRD_VS_IMPLEMENTATION.md +0 -1134
- package/plan/001_d3bb02af4886/docs/bugfix/GAP_ANALYSIS_SUMMARY.md +0 -179
- package/plan/001_d3bb02af4886/docs/bugfix/P1M4T2S1/PRP.md +0 -629
- package/plan/001_d3bb02af4886/docs/bugfix/P1M4T2S1/validation-report.md +0 -214
- package/plan/001_d3bb02af4886/docs/bugfix/PRP_P1M4T2S3.md +0 -629
- package/plan/001_d3bb02af4886/docs/bugfix/bugfix_PRP.md +0 -529
- package/plan/001_d3bb02af4886/docs/bugfix/bugfix_QUICK_REFERENCE.md +0 -142
- package/plan/001_d3bb02af4886/docs/bugfix/bugfix_README.md +0 -304
- package/plan/001_d3bb02af4886/docs/bugfix/bugfix_TEST_RESULTS.md +0 -558
- package/plan/001_d3bb02af4886/docs/bugfix/bugfix_VALIDATION_SUMMARY.md +0 -256
- package/plan/001_d3bb02af4886/docs/bugfix/system_context.md +0 -346
- package/plan/001_d3bb02af4886/docs/bugfix-architecture/bug_analysis.md +0 -415
- package/plan/001_d3bb02af4886/docs/bugfix-architecture/implementation_patterns.md +0 -489
- package/plan/001_d3bb02af4886/docs/bugfix-architecture/system_context.md +0 -218
- package/plan/001_d3bb02af4886/docs/bugfix_INITIATION_SUMMARY.md +0 -380
- package/plan/001_d3bb02af4886/docs/research/CYCLE_DETECTION_PATTERNS.md +0 -1923
- package/plan/001_d3bb02af4886/docs/research/CYCLE_DETECTION_QUICK_REF.md +0 -319
- package/plan/001_d3bb02af4886/docs/research/P1M1T2S1/codebase-context.md +0 -115
- package/plan/001_d3bb02af4886/docs/research/P1M1T2S1/cycle-detection-algorithms.md +0 -134
- package/plan/001_d3bb02af4886/docs/research/P1M1T2S1/test-patterns.md +0 -153
- package/plan/001_d3bb02af4886/docs/research/P1M1T2S1/workflow-class.md +0 -132
- package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/DECORATOR_DOCUMENTATION_BEST_PRACTICES.md +0 -716
- package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/DECORATOR_DOCUMENTATION_QUICK_REF.md +0 -186
- package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/GROUNDSWELL_DECORATOR_EXAMPLES.md +0 -604
- package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/INDEX.md +0 -213
- package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/codebase_structure.md +0 -30
- package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/existing_test_pattern.md +0 -56
- package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/getRootObservers_implementation.md +0 -53
- package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/test_conventions.md +0 -49
- package/plan/001_d3bb02af4886/docs/research/P1M3T1S4/PRP.md +0 -958
- package/plan/001_d3bb02af4886/docs/research/P1M3T1S4/QUICK_REFERENCE.md +0 -339
- package/plan/001_d3bb02af4886/docs/research/P1M3T1S4/README.md +0 -305
- package/plan/001_d3bb02af4886/docs/research/P1M3T1S4/SUMMARY.md +0 -433
- package/plan/001_d3bb02af4886/docs/research/P1M3T1S4/bidirectional-tree-consistency-testing.md +0 -1574
- package/plan/001_d3bb02af4886/docs/research/P1M3T1S4/test-pattern-examples.md +0 -1014
- package/plan/001_d3bb02af4886/docs/research/P1P2/LRU_CACHE_BEST_PRACTICES.md +0 -1929
- package/plan/001_d3bb02af4886/docs/research/P1P2/LRU_CACHE_CODE_PATTERNS.md +0 -857
- package/plan/001_d3bb02af4886/docs/research/P1P2/LRU_CACHE_INTEGRATION_GUIDE.md +0 -738
- package/plan/001_d3bb02af4886/docs/research/P1P2/LRU_CACHE_RESEARCH_INDEX.md +0 -424
- package/plan/001_d3bb02af4886/docs/research/P1P2/REFLECTION_INDEX.md +0 -291
- package/plan/001_d3bb02af4886/docs/research/P1P2/REFLECTION_RESEARCH_REPORT.md +0 -1342
- package/plan/001_d3bb02af4886/docs/research/P1P2/RESEARCH_SUMMARY.md +0 -342
- package/plan/001_d3bb02af4886/docs/research/P1P2/anthropic-sdk.md +0 -174
- package/plan/001_d3bb02af4886/docs/research/P1P2/async-local-storage.md +0 -200
- package/plan/001_d3bb02af4886/docs/research/P1P2/reflection-code-patterns.md +0 -1205
- package/plan/001_d3bb02af4886/docs/research/P1P2/reflection-decision-matrix.md +0 -421
- package/plan/001_d3bb02af4886/docs/research/P1P2/reflection-implementation-guide.md +0 -1341
- package/plan/001_d3bb02af4886/docs/research/P1P2/reflection-integration-guide.md +0 -834
- package/plan/001_d3bb02af4886/docs/research/P1P2/reflection-patterns.md +0 -1468
- package/plan/001_d3bb02af4886/docs/research/P1P2/reflection-quick-reference.md +0 -558
- package/plan/001_d3bb02af4886/docs/research/P1P2/zod-schema.md +0 -152
- package/plan/001_d3bb02af4886/docs/research/P3P4/caching-lru.md +0 -116
- package/plan/001_d3bb02af4886/docs/research/P3P4/introspection-tools.md +0 -177
- package/plan/001_d3bb02af4886/docs/research/P3P4/reflection-patterns.md +0 -117
- package/plan/001_d3bb02af4886/docs/research/P4P5/RESEARCH_SUMMARY.md +0 -151
- package/plan/001_d3bb02af4886/docs/research/PROMISE_ALLSETTLED_QUICK_REF.md +0 -376
- package/plan/001_d3bb02af4886/docs/research/PROMISE_ALLSETTLED_RESEARCH.md +0 -1507
- package/plan/001_d3bb02af4886/docs/research/bugfix_typescript_patterns.md +0 -949
- package/plan/001_d3bb02af4886/docs/research/error-testing-research.md +0 -619
- package/plan/001_d3bb02af4886/docs/research/error_handling_patterns.md +0 -723
- package/plan/001_d3bb02af4886/docs/research/general/INTROSPECTION_RESEARCH_SUMMARY.md +0 -378
- package/plan/001_d3bb02af4886/docs/research/general/README-INTROSPECTION.md +0 -352
- package/plan/001_d3bb02af4886/docs/research/general/agent-introspection-patterns.md +0 -1085
- package/plan/001_d3bb02af4886/docs/research/general/introspection-security-guide.md +0 -984
- package/plan/001_d3bb02af4886/docs/research/general/introspection-tool-examples.md +0 -875
- package/plan/001_d3bb02af4886/docs/research/incremental-tree-map-updates/PRP_TEMPLATE.md +0 -460
- package/plan/001_d3bb02af4886/docs/research/incremental-tree-map-updates/QUICK_REFERENCE.md +0 -324
- package/plan/001_d3bb02af4886/docs/research/incremental-tree-map-updates/README.md +0 -175
- package/plan/001_d3bb02af4886/docs/research/incremental-tree-map-updates/RESEARCH_REPORT.md +0 -499
- package/plan/001_d3bb02af4886/docs/research/incremental-tree-map-updates/SUMMARY.md +0 -163
- package/plan/001_d3bb02af4886/prd_snapshot.md +0 -543
- package/plan/bugfix/BUG_FIX_SUMMARY.md +0 -961
- package/scripts/generate-llms-full.ts +0 -206
- package/src/__tests__/adversarial/attachChild-performance.test.ts +0 -216
- package/src/__tests__/adversarial/circular-reference.test.ts +0 -101
- package/src/__tests__/adversarial/complex-circular-reference.test.ts +0 -139
- package/src/__tests__/adversarial/concurrent-task-failures.test.ts +0 -571
- package/src/__tests__/adversarial/deep-analysis.test.ts +0 -729
- package/src/__tests__/adversarial/deep-hierarchy-stress.test.ts +0 -213
- package/src/__tests__/adversarial/e2e-prd-validation.test.ts +0 -448
- package/src/__tests__/adversarial/edge-case.test.ts +0 -703
- package/src/__tests__/adversarial/error-merge-strategy.test.ts +0 -760
- package/src/__tests__/adversarial/incremental-performance.test.ts +0 -140
- package/src/__tests__/adversarial/node-map-update-benchmarks.test.ts +0 -457
- package/src/__tests__/adversarial/observer-propagation.test.ts +0 -487
- package/src/__tests__/adversarial/parent-validation.test.ts +0 -143
- package/src/__tests__/adversarial/prd-12-2-compliance.test.ts +0 -611
- package/src/__tests__/adversarial/prd-compliance.test.ts +0 -731
- package/src/__tests__/compatibility/backward-compatibility.test.ts +0 -1572
- package/src/__tests__/helpers/index.ts +0 -18
- package/src/__tests__/helpers/tree-verification.ts +0 -257
- package/src/__tests__/integration/agent-workflow.test.ts +0 -256
- package/src/__tests__/integration/bidirectional-consistency.test.ts +0 -847
- package/src/__tests__/integration/observer-logging.test.ts +0 -643
- package/src/__tests__/integration/tree-mirroring.test.ts +0 -151
- package/src/__tests__/integration/workflow-reparenting.test.ts +0 -303
- package/src/__tests__/unit/agent.test.ts +0 -169
- package/src/__tests__/unit/cache-key.test.ts +0 -182
- package/src/__tests__/unit/cache.test.ts +0 -172
- package/src/__tests__/unit/context.test.ts +0 -217
- package/src/__tests__/unit/decorators.test.ts +0 -100
- package/src/__tests__/unit/introspection-tools.test.ts +0 -277
- package/src/__tests__/unit/logger.test.ts +0 -293
- package/src/__tests__/unit/observable.test.ts +0 -321
- package/src/__tests__/unit/prompt.test.ts +0 -135
- package/src/__tests__/unit/reflection.test.ts +0 -210
- package/src/__tests__/unit/tree-debugger-incremental.test.ts +0 -170
- package/src/__tests__/unit/tree-debugger.test.ts +0 -85
- package/src/__tests__/unit/utils/workflow-error-utils.test.ts +0 -209
- package/src/__tests__/unit/workflow-detachChild.test.ts +0 -100
- package/src/__tests__/unit/workflow-emitEvent-childDetached.test.ts +0 -153
- package/src/__tests__/unit/workflow-isDescendantOf.test.ts +0 -180
- package/src/__tests__/unit/workflow.test.ts +0 -357
- package/src/cache/cache-key.ts +0 -244
- package/src/cache/cache.ts +0 -236
- package/src/core/agent.ts +0 -593
- package/src/core/event-tree.ts +0 -260
- package/src/core/logger.ts +0 -112
- package/src/core/mcp-handler.ts +0 -184
- package/src/core/prompt.ts +0 -150
- package/src/core/workflow-context.ts +0 -351
- package/src/core/workflow.ts +0 -540
- package/src/debugger/tree-debugger.ts +0 -255
- package/src/decorators/observed-state.ts +0 -95
- package/src/decorators/step.ts +0 -139
- package/src/decorators/task.ts +0 -159
- package/src/examples/tdd-orchestrator.ts +0 -65
- package/src/examples/test-cycle-workflow.ts +0 -64
- package/src/index.ts +0 -142
- package/src/reflection/reflection.ts +0 -407
- package/src/tools/index.ts +0 -36
- package/src/tools/introspection.ts +0 -464
- package/src/types/agent.ts +0 -90
- package/src/types/decorators.ts +0 -32
- package/src/types/error-strategy.ts +0 -13
- package/src/types/error.ts +0 -20
- package/src/types/events.ts +0 -75
- package/src/types/index.ts +0 -55
- package/src/types/logging.ts +0 -24
- package/src/types/observer.ts +0 -18
- package/src/types/prompt.ts +0 -40
- package/src/types/reflection.ts +0 -117
- package/src/types/sdk-primitives.ts +0 -128
- package/src/types/workflow-context.ts +0 -163
- package/src/types/workflow.ts +0 -37
- package/src/utils/id.ts +0 -11
- package/src/utils/index.ts +0 -4
- package/src/utils/observable.ts +0 -106
- package/src/utils/workflow-error-utils.ts +0 -56
- package/tsconfig.json +0 -22
- package/vitest.config.ts +0 -16
|
@@ -1,1109 +0,0 @@
|
|
|
1
|
-
# Concurrent Error Testing Patterns for Workflow Engines
|
|
2
|
-
|
|
3
|
-
## Research Overview
|
|
4
|
-
|
|
5
|
-
This document compiles testing patterns for concurrent task failure scenarios in workflow engines and similar systems. The patterns are derived from industry best practices and common implementations in production workflow systems.
|
|
6
|
-
|
|
7
|
-
## Table of Contents
|
|
8
|
-
|
|
9
|
-
1. [Production Examples](#production-examples)
|
|
10
|
-
2. [Test Scenarios](#test-scenarios)
|
|
11
|
-
3. [Assertion Patterns](#assertion-patterns)
|
|
12
|
-
4. [Observable Testing](#observable-testing)
|
|
13
|
-
5. [Code Examples](#code-examples)
|
|
14
|
-
|
|
15
|
-
---
|
|
16
|
-
|
|
17
|
-
## Production Examples
|
|
18
|
-
|
|
19
|
-
### GitHub Repositories with Relevant Test Patterns
|
|
20
|
-
|
|
21
|
-
While direct web scraping was limited, the following repositories are known to have extensive test suites for concurrent task failures:
|
|
22
|
-
|
|
23
|
-
#### 1. Apache Airflow
|
|
24
|
-
**Repository**: https://github.com/apache/airflow
|
|
25
|
-
**Relevant Test Paths**:
|
|
26
|
-
- `tests/models/test_taskinstance.py` - Task failure and retry testing
|
|
27
|
-
- `tests/dag_processing/test_dag_run.py` - Concurrent DAG execution
|
|
28
|
-
- `tests/executors/test_executor.py` - Executor failure handling
|
|
29
|
-
|
|
30
|
-
**Key Patterns**:
|
|
31
|
-
```python
|
|
32
|
-
# Pattern from Airflow: Testing concurrent task failures
|
|
33
|
-
def test_concurrent_task_failures(self):
|
|
34
|
-
"""
|
|
35
|
-
Test that multiple tasks can fail concurrently without
|
|
36
|
-
blocking other tasks from completing.
|
|
37
|
-
"""
|
|
38
|
-
dag = DAG('test_concurrent_failures', ...)
|
|
39
|
-
|
|
40
|
-
# Create tasks with mixed success/failure outcomes
|
|
41
|
-
tasks = [
|
|
42
|
-
Task('task1', dag=dag, retries=0), # Will fail
|
|
43
|
-
Task('task2', dag=dag), # Will succeed
|
|
44
|
-
Task('task3', dag=dag, retries=0), # Will fail
|
|
45
|
-
Task('task4', dag=dag), # Will succeed
|
|
46
|
-
]
|
|
47
|
-
|
|
48
|
-
# Run and verify
|
|
49
|
-
dr = dag.create_dagrun()
|
|
50
|
-
|
|
51
|
-
# Assert: All tasks complete (no hanging)
|
|
52
|
-
assert len([t for t in dr.get_task_instances() if t.state == 'failed']) == 2
|
|
53
|
-
assert len([t for t in dr.get_task_instances() if t.state == 'success']) == 2
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
#### 2. Temporal
|
|
57
|
-
**Repository**: https://github.com/temporalio/sdk-python
|
|
58
|
-
**Relevant Test Paths**:
|
|
59
|
-
- `tests/worker/workflow_tests/test_child_workflow.py` - Child workflow failures
|
|
60
|
-
- `tests/worker/workflow_tests/test_workflow_replay.py` - Failure recovery
|
|
61
|
-
|
|
62
|
-
**Key Patterns**:
|
|
63
|
-
```python
|
|
64
|
-
# Pattern from Temporal: Child workflow failure testing
|
|
65
|
-
async def test_child_workflow_failure_collection(self):
|
|
66
|
-
"""
|
|
67
|
-
Test that parent workflow can handle multiple child
|
|
68
|
-
workflow failures and collect all errors.
|
|
69
|
-
"""
|
|
70
|
-
|
|
71
|
-
async def parent_workflow():
|
|
72
|
-
# Start multiple children concurrently
|
|
73
|
-
handles = [
|
|
74
|
-
await workflow.start_child_workflow(child_workflow, id=f"child-{i}")
|
|
75
|
-
for i in range(5)
|
|
76
|
-
]
|
|
77
|
-
|
|
78
|
-
# Wait for all with exception collection
|
|
79
|
-
results = []
|
|
80
|
-
errors = []
|
|
81
|
-
|
|
82
|
-
for handle in handles:
|
|
83
|
-
try:
|
|
84
|
-
result = await handle.result()
|
|
85
|
-
results.append(result)
|
|
86
|
-
except Exception as e:
|
|
87
|
-
errors.append(e)
|
|
88
|
-
|
|
89
|
-
# Assert: All children complete (no orphaned workflows)
|
|
90
|
-
assert len(results) + len(errors) == 5
|
|
91
|
-
return {"results": results, "errors": errors}
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
#### 3. Prefect
|
|
95
|
-
**Repository**: https://github.com/PrefectHQ/prefect
|
|
96
|
-
**Relevant Test Paths**:
|
|
97
|
-
- `tests/tasks/test_task_runners.py` - Concurrent task execution
|
|
98
|
-
- `tests/orchestration/test_task_runs.py` - Failure state tracking
|
|
99
|
-
|
|
100
|
-
**Key Patterns**:
|
|
101
|
-
```python
|
|
102
|
-
# Pattern from Prefect: State aggregation for concurrent tasks
|
|
103
|
-
async def test_concurrent_task_state_aggregation(self):
|
|
104
|
-
"""
|
|
105
|
-
Test that all task states are collected correctly
|
|
106
|
-
when multiple tasks run concurrently.
|
|
107
|
-
"""
|
|
108
|
-
|
|
109
|
-
@task
|
|
110
|
-
async def failing_task():
|
|
111
|
-
raise ValueError("Task failed")
|
|
112
|
-
|
|
113
|
-
@task
|
|
114
|
-
async def succeeding_task():
|
|
115
|
-
return "success"
|
|
116
|
-
|
|
117
|
-
# Run tasks concurrently
|
|
118
|
-
results = await asyncio.gather(
|
|
119
|
-
failing_task(),
|
|
120
|
-
succeeding_task(),
|
|
121
|
-
failing_task(),
|
|
122
|
-
succeeding_task(),
|
|
123
|
-
return_exceptions=True
|
|
124
|
-
)
|
|
125
|
-
|
|
126
|
-
# Assert: Verify state counts
|
|
127
|
-
failed = [r for r in results if isinstance(r, Exception)]
|
|
128
|
-
succeeded = [r for r in results if not isinstance(r, Exception)]
|
|
129
|
-
|
|
130
|
-
assert len(failed) == 2
|
|
131
|
-
assert len(succeeded) == 2
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
#### 4. Node.js Promise.allSettled Tests
|
|
135
|
-
**Repository**: https://github.com/nodejs/node
|
|
136
|
-
**Relevant Test Paths**:
|
|
137
|
-
- `test/parallel/test-promise-all-settled.js` - Promise.allSettled behavior
|
|
138
|
-
|
|
139
|
-
**Key Patterns**:
|
|
140
|
-
```javascript
|
|
141
|
-
// Pattern from Node.js: Promise.allSettled testing
|
|
142
|
-
assert.throws(
|
|
143
|
-
() => Promise.allSettled.call(undefined),
|
|
144
|
-
TypeError
|
|
145
|
-
);
|
|
146
|
-
|
|
147
|
-
// Test mixed rejection/fulfillment
|
|
148
|
-
const values = [1, 2, 3];
|
|
149
|
-
const reasons = ['err1', 'err2'];
|
|
150
|
-
const input = [
|
|
151
|
-
Promise.resolve(values[0]),
|
|
152
|
-
Promise.reject(reasons[0]),
|
|
153
|
-
Promise.resolve(values[1]),
|
|
154
|
-
Promise.reject(reasons[1]),
|
|
155
|
-
Promise.resolve(values[2])
|
|
156
|
-
];
|
|
157
|
-
|
|
158
|
-
Promise.allSettled(input).then(results => {
|
|
159
|
-
// Assert: All promises settled
|
|
160
|
-
assert.strictEqual(results.length, 5);
|
|
161
|
-
|
|
162
|
-
// Assert: Verify status distribution
|
|
163
|
-
const fulfilled = results.filter(r => r.status === 'fulfilled');
|
|
164
|
-
const rejected = results.filter(r => r.status === 'rejected');
|
|
165
|
-
|
|
166
|
-
assert.strictEqual(fulfilled.length, 3);
|
|
167
|
-
assert.strictEqual(rejected.length, 2);
|
|
168
|
-
|
|
169
|
-
// Assert: Verify values/reasons preserved
|
|
170
|
-
assert.deepStrictEqual(
|
|
171
|
-
fulfilled.map(r => r.value),
|
|
172
|
-
values
|
|
173
|
-
);
|
|
174
|
-
assert.deepStrictEqual(
|
|
175
|
-
rejected.map(r => r.reason),
|
|
176
|
-
reasons
|
|
177
|
-
);
|
|
178
|
-
});
|
|
179
|
-
```
|
|
180
|
-
|
|
181
|
-
---
|
|
182
|
-
|
|
183
|
-
## Test Scenarios
|
|
184
|
-
|
|
185
|
-
### Scenario 1: Single Child Failure in Concurrent Batch
|
|
186
|
-
|
|
187
|
-
**Description**: Test that when one child fails in a concurrent batch, all other children still complete.
|
|
188
|
-
|
|
189
|
-
**Pattern**:
|
|
190
|
-
```typescript
|
|
191
|
-
it('should complete all children when one fails in concurrent batch', async () => {
|
|
192
|
-
// Arrange: Create parent and children
|
|
193
|
-
const parent = new Workflow('Parent');
|
|
194
|
-
const children: Workflow[] = [];
|
|
195
|
-
|
|
196
|
-
// Create 5 children, where child[2] will fail
|
|
197
|
-
for (let i = 0; i < 5; i++) {
|
|
198
|
-
const child = new Workflow(`Child-${i}`, parent, async (ctx) => {
|
|
199
|
-
await ctx.step('step1', async () => {
|
|
200
|
-
if (i === 2) {
|
|
201
|
-
throw new Error('Child 2 failed');
|
|
202
|
-
}
|
|
203
|
-
await delay(100); // Simulate work
|
|
204
|
-
});
|
|
205
|
-
});
|
|
206
|
-
children.push(child);
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
// Act: Run all children concurrently using Promise.allSettled
|
|
210
|
-
const results = await Promise.allSettled(
|
|
211
|
-
children.map(c => c.run())
|
|
212
|
-
);
|
|
213
|
-
|
|
214
|
-
// Assert: All children complete (no hanging promises)
|
|
215
|
-
expect(results.length).toBe(5);
|
|
216
|
-
|
|
217
|
-
// Assert: Correct number of failures
|
|
218
|
-
const failures = results.filter(r => r.status === 'rejected');
|
|
219
|
-
const successes = results.filter(r => r.status === 'fulfilled');
|
|
220
|
-
|
|
221
|
-
expect(failures.length).toBe(1);
|
|
222
|
-
expect(successes.length).toBe(4);
|
|
223
|
-
|
|
224
|
-
// Assert: Error message is preserved
|
|
225
|
-
expect(failures[0].reason.message).toContain('Child 2 failed');
|
|
226
|
-
});
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
### Scenario 2: Multiple Children Failing Concurrently
|
|
230
|
-
|
|
231
|
-
**Description**: Test that multiple children can fail simultaneously and all failures are collected.
|
|
232
|
-
|
|
233
|
-
**Pattern**:
|
|
234
|
-
```typescript
|
|
235
|
-
it('should collect all errors when multiple children fail concurrently', async () => {
|
|
236
|
-
const failureIndices = new Set([1, 3, 4]);
|
|
237
|
-
const parent = new Workflow('Parent');
|
|
238
|
-
const children: Workflow[] = [];
|
|
239
|
-
|
|
240
|
-
for (let i = 0; i < 6; i++) {
|
|
241
|
-
const child = new Workflow(`Child-${i}`, parent, async (ctx) => {
|
|
242
|
-
await ctx.step('step1', async () => {
|
|
243
|
-
if (failureIndices.has(i)) {
|
|
244
|
-
throw new Error(`Child ${i} failed`);
|
|
245
|
-
}
|
|
246
|
-
await delay(50);
|
|
247
|
-
});
|
|
248
|
-
});
|
|
249
|
-
children.push(child);
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
// Act: Run concurrently
|
|
253
|
-
const results = await Promise.allSettled(
|
|
254
|
-
children.map(c => c.run())
|
|
255
|
-
);
|
|
256
|
-
|
|
257
|
-
// Assert: Verify failure count
|
|
258
|
-
const failures = results.filter(r => r.status === 'rejected');
|
|
259
|
-
expect(failures.length).toBe(3);
|
|
260
|
-
|
|
261
|
-
// Assert: All errors are distinct
|
|
262
|
-
const errorMessages = failures.map(f => (f as PromiseRejectedResult).reason.message);
|
|
263
|
-
expect(new Set(errorMessages).size).toBe(3);
|
|
264
|
-
|
|
265
|
-
// Assert: All expected failures occurred
|
|
266
|
-
errorMessages.forEach(msg => {
|
|
267
|
-
const index = parseInt(msg.match(/Child (\d+) failed/)[1]);
|
|
268
|
-
expect(failureIndices.has(index)).toBe(true);
|
|
269
|
-
});
|
|
270
|
-
});
|
|
271
|
-
```
|
|
272
|
-
|
|
273
|
-
### Scenario 3: Mixed Success/Failure with Verification
|
|
274
|
-
|
|
275
|
-
**Description**: Test mixed success/failure scenarios and verify ALL workflows complete.
|
|
276
|
-
|
|
277
|
-
**Pattern**:
|
|
278
|
-
```typescript
|
|
279
|
-
it('should ensure no orphaned workflows in mixed success/failure scenario', async () => {
|
|
280
|
-
const parent = new Workflow('Parent');
|
|
281
|
-
const completionTimes = new Map<string, number>();
|
|
282
|
-
|
|
283
|
-
// Track completion for all children
|
|
284
|
-
const children = Array.from({ length: 10 }, (_, i) => {
|
|
285
|
-
return new Workflow(`Child-${i}`, parent, async (ctx) => {
|
|
286
|
-
const startTime = Date.now();
|
|
287
|
-
await ctx.step('step1', async () => {
|
|
288
|
-
// Simulate variable work time
|
|
289
|
-
await delay(Math.random() * 100);
|
|
290
|
-
|
|
291
|
-
// 40% failure rate
|
|
292
|
-
if (Math.random() < 0.4) {
|
|
293
|
-
throw new Error(`Random failure in child ${i}`);
|
|
294
|
-
}
|
|
295
|
-
});
|
|
296
|
-
completionTimes.set(`Child-${i}`, Date.now() - startTime);
|
|
297
|
-
});
|
|
298
|
-
});
|
|
299
|
-
|
|
300
|
-
// Act: Run with timeout to detect hanging promises
|
|
301
|
-
const timeoutPromise = new Promise((_, reject) =>
|
|
302
|
-
setTimeout(() => reject(new Error('Timeout: workflows hung')), 5000)
|
|
303
|
-
);
|
|
304
|
-
|
|
305
|
-
const runPromise = Promise.allSettled(children.map(c => c.run()));
|
|
306
|
-
|
|
307
|
-
const results = await Promise.race([runPromise, timeoutPromise]) as PromiseSettledResult<void>[];
|
|
308
|
-
|
|
309
|
-
// Assert: All 10 children completed
|
|
310
|
-
expect(results.length).toBe(10);
|
|
311
|
-
|
|
312
|
-
// Assert: All completion times recorded (no orphaned workflows)
|
|
313
|
-
expect(completionTimes.size).toBe(10);
|
|
314
|
-
|
|
315
|
-
// Assert: Completion times are reasonable (< 5000ms)
|
|
316
|
-
completionTimes.forEach(time => {
|
|
317
|
-
expect(time).toBeLessThan(5000);
|
|
318
|
-
});
|
|
319
|
-
});
|
|
320
|
-
```
|
|
321
|
-
|
|
322
|
-
### Scenario 4: All Children Failing
|
|
323
|
-
|
|
324
|
-
**Description**: Test edge case where all children fail and verify error collection.
|
|
325
|
-
|
|
326
|
-
**Pattern**:
|
|
327
|
-
```typescript
|
|
328
|
-
it('should handle all children failing correctly', async () => {
|
|
329
|
-
const parent = new Workflow('Parent');
|
|
330
|
-
const children: Workflow[] = [];
|
|
331
|
-
|
|
332
|
-
// Create children that all fail
|
|
333
|
-
for (let i = 0; i < 5; i++) {
|
|
334
|
-
const child = new Workflow(`Child-${i}`, parent, async (ctx) => {
|
|
335
|
-
await ctx.step('step1', async () => {
|
|
336
|
-
throw new Error(`All children fail - child ${i}`);
|
|
337
|
-
});
|
|
338
|
-
});
|
|
339
|
-
children.push(child);
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
// Act: Run all children
|
|
343
|
-
const results = await Promise.allSettled(
|
|
344
|
-
children.map(c => c.run())
|
|
345
|
-
);
|
|
346
|
-
|
|
347
|
-
// Assert: All children failed
|
|
348
|
-
expect(results.length).toBe(5);
|
|
349
|
-
const failures = results.filter(r => r.status === 'rejected');
|
|
350
|
-
expect(failures.length).toBe(5);
|
|
351
|
-
|
|
352
|
-
// Assert: No children succeeded
|
|
353
|
-
const successes = results.filter(r => r.status === 'fulfilled');
|
|
354
|
-
expect(successes.length).toBe(0);
|
|
355
|
-
|
|
356
|
-
// Assert: All errors are collected and distinct
|
|
357
|
-
const errorMessages = failures.map(f =>
|
|
358
|
-
(f as PromiseRejectedResult).reason.message
|
|
359
|
-
);
|
|
360
|
-
expect(new Set(errorMessages).size).toBe(5);
|
|
361
|
-
});
|
|
362
|
-
```
|
|
363
|
-
|
|
364
|
-
### Scenario 5: Verification That ALL Workflows Complete
|
|
365
|
-
|
|
366
|
-
**Description**: Ensure no promises hang or remain in pending state.
|
|
367
|
-
|
|
368
|
-
**Pattern**:
|
|
369
|
-
```typescript
|
|
370
|
-
it('should verify all workflows complete with no hanging promises', async () => {
|
|
371
|
-
const parent = new Workflow('Parent');
|
|
372
|
-
const completedWorkflows = new Set<string>();
|
|
373
|
-
const failedWorkflows = new Set<string>();
|
|
374
|
-
|
|
375
|
-
const children = Array.from({ length: 20 }, (_, i) => {
|
|
376
|
-
return new Workflow(`Child-${i}`, parent, async (ctx) => {
|
|
377
|
-
try {
|
|
378
|
-
await ctx.step('step1', async () => {
|
|
379
|
-
await delay(10 + Math.random() * 50);
|
|
380
|
-
|
|
381
|
-
// Random failures
|
|
382
|
-
if (i % 3 === 0) {
|
|
383
|
-
throw new Error(`Failure in child ${i}`);
|
|
384
|
-
}
|
|
385
|
-
});
|
|
386
|
-
completedWorkflows.add(`Child-${i}`);
|
|
387
|
-
} catch (err) {
|
|
388
|
-
failedWorkflows.add(`Child-${i}`);
|
|
389
|
-
throw err;
|
|
390
|
-
}
|
|
391
|
-
});
|
|
392
|
-
});
|
|
393
|
-
|
|
394
|
-
// Act: Run with strict timeout
|
|
395
|
-
const TIMEOUT_MS = 10000;
|
|
396
|
-
const startTime = Date.now();
|
|
397
|
-
|
|
398
|
-
const results = await Promise.allSettled(children.map(c => c.run()));
|
|
399
|
-
const duration = Date.now() - startTime;
|
|
400
|
-
|
|
401
|
-
// Assert: All workflows completed within timeout
|
|
402
|
-
expect(duration).toBeLessThan(TIMEOUT_MS);
|
|
403
|
-
expect(results.length).toBe(20);
|
|
404
|
-
|
|
405
|
-
// Assert: All workflows accounted for (no orphaned promises)
|
|
406
|
-
const totalAccounted = completedWorkflows.size + failedWorkflows.size;
|
|
407
|
-
expect(totalAccounted).toBe(20);
|
|
408
|
-
|
|
409
|
-
// Assert: All results are settled (no pending promises)
|
|
410
|
-
results.forEach(result => {
|
|
411
|
-
expect(['fulfilled', 'rejected']).toContain(result.status);
|
|
412
|
-
});
|
|
413
|
-
});
|
|
414
|
-
```
|
|
415
|
-
|
|
416
|
-
---
|
|
417
|
-
|
|
418
|
-
## Assertion Patterns
|
|
419
|
-
|
|
420
|
-
### Pattern 1: Count-Based Assertions
|
|
421
|
-
|
|
422
|
-
**Description**: Verify correct number of failures and successes.
|
|
423
|
-
|
|
424
|
-
```typescript
|
|
425
|
-
// Assertion helper for Promise.allSettled results
|
|
426
|
-
function assertSettlementCounts(
|
|
427
|
-
results: PromiseSettledResult<unknown>[],
|
|
428
|
-
expectedFulfilled: number,
|
|
429
|
-
expectedRejected: number
|
|
430
|
-
) {
|
|
431
|
-
expect(results.length).toBe(expectedFulfilled + expectedRejected);
|
|
432
|
-
|
|
433
|
-
const fulfilled = results.filter(r => r.status === 'fulfilled');
|
|
434
|
-
const rejected = results.filter(r => r.status === 'rejected');
|
|
435
|
-
|
|
436
|
-
expect(fulfilled.length).toBe(expectedFulfilled);
|
|
437
|
-
expect(rejected.length).toBe(expectedRejected);
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
// Usage
|
|
441
|
-
it('should have expected failure counts', async () => {
|
|
442
|
-
const results = await Promise.allSettled(children.map(c => c.run()));
|
|
443
|
-
assertSettlementCounts(results, 7, 3); // 7 success, 3 failure
|
|
444
|
-
});
|
|
445
|
-
```
|
|
446
|
-
|
|
447
|
-
### Pattern 2: Error Collection/Aggregation
|
|
448
|
-
|
|
449
|
-
**Description**: Verify that errors are properly collected and aggregated.
|
|
450
|
-
|
|
451
|
-
```typescript
|
|
452
|
-
// Helper to extract and validate error information
|
|
453
|
-
interface CollectedError {
|
|
454
|
-
workflowId: string;
|
|
455
|
-
message: string;
|
|
456
|
-
workflowName: string;
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
function collectErrors(results: PromiseSettledResult<unknown>[]): CollectedError[] {
|
|
460
|
-
return results
|
|
461
|
-
.filter((r): r is PromiseRejectedResult => r.status === 'rejected')
|
|
462
|
-
.map(r => ({
|
|
463
|
-
workflowId: r.reason.workflowId,
|
|
464
|
-
message: r.reason.message,
|
|
465
|
-
workflowName: r.reason.workflowName || 'unknown',
|
|
466
|
-
}));
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
// Usage in test
|
|
470
|
-
it('should aggregate all errors with workflow context', async () => {
|
|
471
|
-
const results = await Promise.allSettled(children.map(c => c.run()));
|
|
472
|
-
const errors = collectErrors(results);
|
|
473
|
-
|
|
474
|
-
// Assert: All errors have required fields
|
|
475
|
-
errors.forEach(error => {
|
|
476
|
-
expect(error.workflowId).toBeDefined();
|
|
477
|
-
expect(error.message).toBeDefined();
|
|
478
|
-
expect(error.workflowName).toBeDefined();
|
|
479
|
-
});
|
|
480
|
-
|
|
481
|
-
// Assert: Errors can be correlated back to source workflows
|
|
482
|
-
const errorWorkflowIds = new Set(errors.map(e => e.workflowId));
|
|
483
|
-
const failedWorkflowIds = new Set(
|
|
484
|
-
children
|
|
485
|
-
.filter((_, i) => failureIndices.has(i))
|
|
486
|
-
.map(c => c.id)
|
|
487
|
-
);
|
|
488
|
-
|
|
489
|
-
expect(errorWorkflowIds).toEqual(failedWorkflowIds);
|
|
490
|
-
});
|
|
491
|
-
```
|
|
492
|
-
|
|
493
|
-
### Pattern 3: Completion Verification
|
|
494
|
-
|
|
495
|
-
**Description**: Ensure no orphaned or hanging promises.
|
|
496
|
-
|
|
497
|
-
```typescript
|
|
498
|
-
// Helper to track all promise completions
|
|
499
|
-
class PromiseTracker {
|
|
500
|
-
private pending = new Set<string>();
|
|
501
|
-
private completed = new Set<string>();
|
|
502
|
-
private failed = new Set<string>();
|
|
503
|
-
|
|
504
|
-
track(id: string) {
|
|
505
|
-
this.pending.add(id);
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
complete(id: string) {
|
|
509
|
-
this.pending.delete(id);
|
|
510
|
-
this.completed.add(id);
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
fail(id: string) {
|
|
514
|
-
this.pending.delete(id);
|
|
515
|
-
this.failed.add(id);
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
assertAllComplete() {
|
|
519
|
-
expect(this.pending.size).toBe(0);
|
|
520
|
-
expect(this.completed.size + this.failed.size).toBeGreaterThan(0);
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
getStats() {
|
|
524
|
-
return {
|
|
525
|
-
pending: this.pending.size,
|
|
526
|
-
completed: this.completed.size,
|
|
527
|
-
failed: this.failed.size,
|
|
528
|
-
total: this.completed.size + this.failed.size,
|
|
529
|
-
};
|
|
530
|
-
}
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
// Usage in test
|
|
534
|
-
it('should verify no hanging promises', async () => {
|
|
535
|
-
const tracker = new PromiseTracker();
|
|
536
|
-
|
|
537
|
-
const children = workflows.map(w => {
|
|
538
|
-
tracker.track(w.id);
|
|
539
|
-
return w.run().then(
|
|
540
|
-
() => tracker.complete(w.id),
|
|
541
|
-
() => tracker.fail(w.id)
|
|
542
|
-
);
|
|
543
|
-
});
|
|
544
|
-
|
|
545
|
-
await Promise.allSettled(children);
|
|
546
|
-
|
|
547
|
-
// Assert: All promises settled
|
|
548
|
-
tracker.assertAllComplete();
|
|
549
|
-
|
|
550
|
-
const stats = tracker.getStats();
|
|
551
|
-
expect(stats.total).toBe(workflows.length);
|
|
552
|
-
expect(stats.pending).toBe(0);
|
|
553
|
-
});
|
|
554
|
-
```
|
|
555
|
-
|
|
556
|
-
### Pattern 4: Successful Workflows Still Complete
|
|
557
|
-
|
|
558
|
-
**Description**: Verify that successful workflows complete even when others fail.
|
|
559
|
-
|
|
560
|
-
```typescript
|
|
561
|
-
it('should complete successful workflows despite failures', async () => {
|
|
562
|
-
const successfulIndices = new Set([0, 1, 4, 5, 7]);
|
|
563
|
-
const failureIndices = new Set([2, 3, 6]);
|
|
564
|
-
|
|
565
|
-
const children = workflows.map((wf, i) => {
|
|
566
|
-
if (failureIndices.has(i)) {
|
|
567
|
-
// Create failing workflow
|
|
568
|
-
return new Workflow(`Fail-${i}`, parent, async (ctx) => {
|
|
569
|
-
await ctx.step('fail', () => {
|
|
570
|
-
throw new Error(`Expected failure ${i}`);
|
|
571
|
-
});
|
|
572
|
-
});
|
|
573
|
-
} else {
|
|
574
|
-
// Create successful workflow
|
|
575
|
-
return new Workflow(`Success-${i}`, parent, async (ctx) => {
|
|
576
|
-
await ctx.step('succeed', async () => {
|
|
577
|
-
await delay(50);
|
|
578
|
-
return `success-${i}`;
|
|
579
|
-
});
|
|
580
|
-
});
|
|
581
|
-
}
|
|
582
|
-
});
|
|
583
|
-
|
|
584
|
-
const results = await Promise.allSettled(children.map(c => c.run()));
|
|
585
|
-
|
|
586
|
-
// Assert: Successful workflows completed
|
|
587
|
-
const successfulResults = results
|
|
588
|
-
.map((r, i) => ({ result: r, index: i }))
|
|
589
|
-
.filter(({ result }) => result.status === 'fulfilled');
|
|
590
|
-
|
|
591
|
-
expect(successfulResults.length).toBe(successfulIndices.size);
|
|
592
|
-
|
|
593
|
-
// Assert: Each successful workflow has a result
|
|
594
|
-
successfulResults.forEach(({ result, index }) => {
|
|
595
|
-
expect(successfulIndices.has(index)).toBe(true);
|
|
596
|
-
expect((result as PromiseFulfilledResult<unknown>).value).toBeDefined();
|
|
597
|
-
});
|
|
598
|
-
});
|
|
599
|
-
```
|
|
600
|
-
|
|
601
|
-
---
|
|
602
|
-
|
|
603
|
-
## Observable Testing
|
|
604
|
-
|
|
605
|
-
### Pattern 1: Event Emission Tracking
|
|
606
|
-
|
|
607
|
-
**Description**: Track and verify events emitted during concurrent failures.
|
|
608
|
-
|
|
609
|
-
```typescript
|
|
610
|
-
it('should emit events for all concurrent failures', async () => {
|
|
611
|
-
const parent = new Workflow('Parent');
|
|
612
|
-
const events: WorkflowEvent[] = [];
|
|
613
|
-
|
|
614
|
-
// Attach observer to capture all events
|
|
615
|
-
parent.addObserver({
|
|
616
|
-
onLog: () => {},
|
|
617
|
-
onEvent: (e) => events.push(e),
|
|
618
|
-
onStateUpdated: () => {},
|
|
619
|
-
onTreeChanged: () => {},
|
|
620
|
-
});
|
|
621
|
-
|
|
622
|
-
// Create children with mixed outcomes
|
|
623
|
-
const children = [
|
|
624
|
-
new Workflow('Child-0', parent, async (ctx) => {
|
|
625
|
-
await ctx.step('step1', async () => {
|
|
626
|
-
throw new Error('Error 0');
|
|
627
|
-
});
|
|
628
|
-
}),
|
|
629
|
-
new Workflow('Child-1', parent, async (ctx) => {
|
|
630
|
-
await ctx.step('step1', async () => {
|
|
631
|
-
await delay(50);
|
|
632
|
-
return 'success';
|
|
633
|
-
});
|
|
634
|
-
}),
|
|
635
|
-
new Workflow('Child-2', parent, async (ctx) => {
|
|
636
|
-
await ctx.step('step1', async () => {
|
|
637
|
-
throw new Error('Error 2');
|
|
638
|
-
});
|
|
639
|
-
}),
|
|
640
|
-
];
|
|
641
|
-
|
|
642
|
-
// Run children
|
|
643
|
-
await Promise.allSettled(children.map(c => c.run()));
|
|
644
|
-
|
|
645
|
-
// Assert: Verify error events emitted for failures
|
|
646
|
-
const errorEvents = events.filter(e => e.type === 'error');
|
|
647
|
-
expect(errorEvents.length).toBeGreaterThanOrEqual(2);
|
|
648
|
-
|
|
649
|
-
// Assert: Each error event has correct structure
|
|
650
|
-
errorEvents.forEach(event => {
|
|
651
|
-
expect(event.type).toBe('error');
|
|
652
|
-
expect(event.error).toBeDefined();
|
|
653
|
-
expect(event.error.workflowId).toBeDefined();
|
|
654
|
-
expect(event.error.message).toBeDefined();
|
|
655
|
-
});
|
|
656
|
-
|
|
657
|
-
// Assert: Error messages are distinct
|
|
658
|
-
const errorMessages = errorEvents.map(e => e.error.message);
|
|
659
|
-
expect(new Set(errorMessages).size).toBe(2);
|
|
660
|
-
});
|
|
661
|
-
```
|
|
662
|
-
|
|
663
|
-
### Pattern 2: State Change Observation
|
|
664
|
-
|
|
665
|
-
**Description**: Verify workflow state changes during concurrent failures.
|
|
666
|
-
|
|
667
|
-
```typescript
|
|
668
|
-
it('should update states correctly during concurrent failures', async () => {
|
|
669
|
-
const parent = new Workflow('Parent');
|
|
670
|
-
const stateSnapshots = new Map<string, WorkflowStatus[]>();
|
|
671
|
-
|
|
672
|
-
// Create state observer
|
|
673
|
-
const observer = {
|
|
674
|
-
onLog: () => {},
|
|
675
|
-
onEvent: () => {},
|
|
676
|
-
onStateUpdated: (node: WorkflowNode) => {
|
|
677
|
-
const states = stateSnapshots.get(node.id) || [];
|
|
678
|
-
states.push(node.status);
|
|
679
|
-
stateSnapshots.set(node.id, states);
|
|
680
|
-
},
|
|
681
|
-
onTreeChanged: () => {},
|
|
682
|
-
};
|
|
683
|
-
|
|
684
|
-
parent.addObserver(observer);
|
|
685
|
-
|
|
686
|
-
// Run children
|
|
687
|
-
const children = [
|
|
688
|
-
new Workflow('Child-0', parent, async (ctx) => {
|
|
689
|
-
await ctx.step('step1', async () => {
|
|
690
|
-
throw new Error('Fail');
|
|
691
|
-
});
|
|
692
|
-
}),
|
|
693
|
-
new Workflow('Child-1', parent, async (ctx) => {
|
|
694
|
-
await ctx.step('step1', async () => {
|
|
695
|
-
return 'success';
|
|
696
|
-
});
|
|
697
|
-
}),
|
|
698
|
-
];
|
|
699
|
-
|
|
700
|
-
await Promise.allSettled(children.map(c => c.run()));
|
|
701
|
-
|
|
702
|
-
// Assert: Both children have state history
|
|
703
|
-
expect(stateSnapshots.size).toBe(2);
|
|
704
|
-
|
|
705
|
-
// Assert: Failed child ended in 'failed' state
|
|
706
|
-
const child0States = stateSnapshots.get(children[0].id);
|
|
707
|
-
expect(child0States[child0States.length - 1]).toBe('failed');
|
|
708
|
-
|
|
709
|
-
// Assert: Successful child ended in 'completed' state
|
|
710
|
-
const child1States = stateSnapshots.get(children[1].id);
|
|
711
|
-
expect(child1States[child1States.length - 1]).toBe('completed');
|
|
712
|
-
});
|
|
713
|
-
```
|
|
714
|
-
|
|
715
|
-
### Pattern 3: Tree Change Events During Failures
|
|
716
|
-
|
|
717
|
-
**Description**: Verify tree structure updates during concurrent failures.
|
|
718
|
-
|
|
719
|
-
```typescript
|
|
720
|
-
it('should emit tree change events during concurrent failures', async () => {
|
|
721
|
-
const parent = new Workflow('Parent');
|
|
722
|
-
const treeEvents: WorkflowNode[] = [];
|
|
723
|
-
|
|
724
|
-
parent.addObserver({
|
|
725
|
-
onLog: () => {},
|
|
726
|
-
onEvent: () => {},
|
|
727
|
-
onStateUpdated: () => {},
|
|
728
|
-
onTreeChanged: (root) => treeEvents.push(root),
|
|
729
|
-
});
|
|
730
|
-
|
|
731
|
-
// Create and run children
|
|
732
|
-
const children = Array.from({ length: 5 }, (_, i) => {
|
|
733
|
-
return new Workflow(`Child-${i}`, parent, async (ctx) => {
|
|
734
|
-
await ctx.step('step1', async () => {
|
|
735
|
-
if (i % 2 === 0) {
|
|
736
|
-
throw new Error(`Failure ${i}`);
|
|
737
|
-
}
|
|
738
|
-
});
|
|
739
|
-
});
|
|
740
|
-
});
|
|
741
|
-
|
|
742
|
-
await Promise.allSettled(children.map(c => c.run()));
|
|
743
|
-
|
|
744
|
-
// Assert: Tree change events were emitted
|
|
745
|
-
expect(treeEvents.length).toBeGreaterThan(0);
|
|
746
|
-
|
|
747
|
-
// Assert: Final tree state has all children
|
|
748
|
-
const finalTree = treeEvents[treeEvents.length - 1];
|
|
749
|
-
expect(finalTree.children.length).toBe(5);
|
|
750
|
-
|
|
751
|
-
// Assert: Failed children have 'failed' status
|
|
752
|
-
const failedChildren = finalTree.children.filter(c => c.status === 'failed');
|
|
753
|
-
expect(failedChildren.length).toBe(3); // Children 0, 2, 4
|
|
754
|
-
});
|
|
755
|
-
```
|
|
756
|
-
|
|
757
|
-
### Pattern 4: Log Aggregation During Failures
|
|
758
|
-
|
|
759
|
-
**Description**: Verify logs are captured from both successful and failed workflows.
|
|
760
|
-
|
|
761
|
-
```typescript
|
|
762
|
-
it('should capture logs from both successful and failed workflows', async () => {
|
|
763
|
-
const parent = new Workflow('Parent');
|
|
764
|
-
const allLogs: LogEntry[] = [];
|
|
765
|
-
|
|
766
|
-
parent.addObserver({
|
|
767
|
-
onLog: (entry) => allLogs.push(entry),
|
|
768
|
-
onEvent: () => {},
|
|
769
|
-
onStateUpdated: () => {},
|
|
770
|
-
onTreeChanged: () => {},
|
|
771
|
-
});
|
|
772
|
-
|
|
773
|
-
const children = [
|
|
774
|
-
new Workflow('Child-0', parent, async (ctx) => {
|
|
775
|
-
await ctx.step('step1', async () => {
|
|
776
|
-
ctx.logger.info('Child 0 starting');
|
|
777
|
-
await delay(10);
|
|
778
|
-
ctx.logger.info('Child 0 about to fail');
|
|
779
|
-
throw new Error('Failed');
|
|
780
|
-
});
|
|
781
|
-
}),
|
|
782
|
-
new Workflow('Child-1', parent, async (ctx) => {
|
|
783
|
-
await ctx.step('step1', async () => {
|
|
784
|
-
ctx.logger.info('Child 1 starting');
|
|
785
|
-
await delay(10);
|
|
786
|
-
ctx.logger.info('Child 1 completing');
|
|
787
|
-
return 'success';
|
|
788
|
-
});
|
|
789
|
-
}),
|
|
790
|
-
];
|
|
791
|
-
|
|
792
|
-
await Promise.allSettled(children.map(c => c.run()));
|
|
793
|
-
|
|
794
|
-
// Assert: Logs from both children captured
|
|
795
|
-
const child0Logs = allLogs.filter(l => l.workflowId === children[0].id);
|
|
796
|
-
const child1Logs = allLogs.filter(l => l.workflowId === children[1].id);
|
|
797
|
-
|
|
798
|
-
expect(child0Logs.length).toBeGreaterThan(0);
|
|
799
|
-
expect(child1Logs.length).toBeGreaterThan(0);
|
|
800
|
-
|
|
801
|
-
// Assert: Specific log messages present
|
|
802
|
-
const child0Messages = child0Logs.map(l => l.message);
|
|
803
|
-
expect(child0Messages).toContain('Child 0 about to fail');
|
|
804
|
-
|
|
805
|
-
const child1Messages = child1Logs.map(l => l.message);
|
|
806
|
-
expect(child1Messages).toContain('Child 1 completing');
|
|
807
|
-
});
|
|
808
|
-
```
|
|
809
|
-
|
|
810
|
-
---
|
|
811
|
-
|
|
812
|
-
## Code Examples
|
|
813
|
-
|
|
814
|
-
### Complete Test Suite: @Task Decorator Concurrent Failures
|
|
815
|
-
|
|
816
|
-
This example demonstrates a comprehensive test suite for the `@Task` decorator with concurrent execution and error handling.
|
|
817
|
-
|
|
818
|
-
```typescript
|
|
819
|
-
import { describe, it, expect } from 'vitest';
|
|
820
|
-
import { Workflow, Task } from '../index.js';
|
|
821
|
-
import { WorkflowObserver, WorkflowEvent } from '../types/index.js';
|
|
822
|
-
|
|
823
|
-
/**
|
|
824
|
-
* Test suite for @Task decorator concurrent execution patterns
|
|
825
|
-
*/
|
|
826
|
-
describe('@Task decorator with concurrent execution', () => {
|
|
827
|
-
|
|
828
|
-
/**
|
|
829
|
-
* Helper to create a child workflow that may fail
|
|
830
|
-
*/
|
|
831
|
-
function createChildWorkflow(
|
|
832
|
-
parent: Workflow,
|
|
833
|
-
name: string,
|
|
834
|
-
shouldFail: boolean = false
|
|
835
|
-
): Workflow {
|
|
836
|
-
return new Workflow(name, parent, async (ctx) => {
|
|
837
|
-
await ctx.step('step1', async () => {
|
|
838
|
-
await delay(50);
|
|
839
|
-
if (shouldFail) {
|
|
840
|
-
throw new Error(`${name} failed`);
|
|
841
|
-
}
|
|
842
|
-
return `${name} succeeded`;
|
|
843
|
-
});
|
|
844
|
-
});
|
|
845
|
-
}
|
|
846
|
-
|
|
847
|
-
/**
|
|
848
|
-
* Helper to collect events during execution
|
|
849
|
-
*/
|
|
850
|
-
function setupEventObserver(workflow: Workflow): WorkflowEvent[] {
|
|
851
|
-
const events: WorkflowEvent[] = [];
|
|
852
|
-
workflow.addObserver({
|
|
853
|
-
onLog: () => {},
|
|
854
|
-
onEvent: (e) => events.push(e),
|
|
855
|
-
onStateUpdated: () => {},
|
|
856
|
-
onTreeChanged: () => {},
|
|
857
|
-
});
|
|
858
|
-
return events;
|
|
859
|
-
}
|
|
860
|
-
|
|
861
|
-
describe('Single child failure scenarios', () => {
|
|
862
|
-
it('should complete all siblings when one child fails', async () => {
|
|
863
|
-
// Arrange
|
|
864
|
-
class ParentWorkflow extends Workflow {
|
|
865
|
-
async run() {
|
|
866
|
-
this.setStatus('running');
|
|
867
|
-
|
|
868
|
-
const child1 = createChildWorkflow(this, 'Child-1', false);
|
|
869
|
-
const child2 = createChildWorkflow(this, 'Child-2', true); // Will fail
|
|
870
|
-
const child3 = createChildWorkflow(this, 'Child-3', false);
|
|
871
|
-
const child4 = createChildWorkflow(this, 'Child-4', false);
|
|
872
|
-
|
|
873
|
-
const results = await Promise.allSettled([
|
|
874
|
-
child1.run(),
|
|
875
|
-
child2.run(),
|
|
876
|
-
child3.run(),
|
|
877
|
-
child4.run(),
|
|
878
|
-
]);
|
|
879
|
-
|
|
880
|
-
this.setStatus('completed');
|
|
881
|
-
return results;
|
|
882
|
-
}
|
|
883
|
-
}
|
|
884
|
-
|
|
885
|
-
const parent = new ParentWorkflow();
|
|
886
|
-
const events = setupEventObserver(parent);
|
|
887
|
-
|
|
888
|
-
// Act
|
|
889
|
-
const results = await parent.run();
|
|
890
|
-
|
|
891
|
-
// Assert: All children completed
|
|
892
|
-
expect(results.length).toBe(4);
|
|
893
|
-
|
|
894
|
-
// Assert: Exactly one failure
|
|
895
|
-
const failures = results.filter(r => r.status === 'rejected');
|
|
896
|
-
const successes = results.filter(r => r.status === 'fulfilled');
|
|
897
|
-
|
|
898
|
-
expect(failures.length).toBe(1);
|
|
899
|
-
expect(successes.length).toBe(3);
|
|
900
|
-
|
|
901
|
-
// Assert: Error message preserved
|
|
902
|
-
expect(failures[0].reason.message).toContain('Child-2 failed');
|
|
903
|
-
|
|
904
|
-
// Assert: Error events emitted
|
|
905
|
-
const errorEvents = events.filter(e => e.type === 'error');
|
|
906
|
-
expect(errorEvents.length).toBeGreaterThanOrEqual(1);
|
|
907
|
-
});
|
|
908
|
-
});
|
|
909
|
-
|
|
910
|
-
describe('Multiple concurrent failures', () => {
|
|
911
|
-
it('should collect all errors from multiple failing children', async () => {
|
|
912
|
-
// Arrange
|
|
913
|
-
class ParentWorkflow extends Workflow {
|
|
914
|
-
async run() {
|
|
915
|
-
const children = [
|
|
916
|
-
createChildWorkflow(this, 'Child-0', false),
|
|
917
|
-
createChildWorkflow(this, 'Child-1', true),
|
|
918
|
-
createChildWorkflow(this, 'Child-2', false),
|
|
919
|
-
createChildWorkflow(this, 'Child-3', true),
|
|
920
|
-
createChildWorkflow(this, 'Child-4', false),
|
|
921
|
-
createChildWorkflow(this, 'Child-5', true),
|
|
922
|
-
];
|
|
923
|
-
|
|
924
|
-
return await Promise.allSettled(
|
|
925
|
-
children.map(c => c.run())
|
|
926
|
-
);
|
|
927
|
-
}
|
|
928
|
-
}
|
|
929
|
-
|
|
930
|
-
const parent = new ParentWorkflow();
|
|
931
|
-
|
|
932
|
-
// Act
|
|
933
|
-
const results = await parent.run();
|
|
934
|
-
|
|
935
|
-
// Assert: Three failures, three successes
|
|
936
|
-
expect(results.length).toBe(6);
|
|
937
|
-
|
|
938
|
-
const failures = results.filter(r => r.status === 'rejected');
|
|
939
|
-
const successes = results.filter(r => r.status === 'fulfilled');
|
|
940
|
-
|
|
941
|
-
expect(failures.length).toBe(3);
|
|
942
|
-
expect(successes.length).toBe(3);
|
|
943
|
-
|
|
944
|
-
// Assert: All errors distinct
|
|
945
|
-
const errorMessages = failures.map(f => f.reason.message);
|
|
946
|
-
expect(new Set(errorMessages).size).toBe(3);
|
|
947
|
-
});
|
|
948
|
-
|
|
949
|
-
it('should preserve error context for each failure', async () => {
|
|
950
|
-
// Arrange
|
|
951
|
-
class ParentWorkflow extends Workflow {
|
|
952
|
-
async run() {
|
|
953
|
-
const children = [
|
|
954
|
-
createChildWorkflow(this, 'Alpha', true),
|
|
955
|
-
createChildWorkflow(this, 'Beta', true),
|
|
956
|
-
createChildWorkflow(this, 'Gamma', true),
|
|
957
|
-
];
|
|
958
|
-
|
|
959
|
-
return await Promise.allSettled(
|
|
960
|
-
children.map(c => c.run())
|
|
961
|
-
);
|
|
962
|
-
}
|
|
963
|
-
}
|
|
964
|
-
|
|
965
|
-
const parent = new ParentWorkflow();
|
|
966
|
-
const events = setupEventObserver(parent);
|
|
967
|
-
|
|
968
|
-
// Act
|
|
969
|
-
await parent.run();
|
|
970
|
-
|
|
971
|
-
// Assert: All error events have required context
|
|
972
|
-
const errorEvents = events.filter(e => e.type === 'error');
|
|
973
|
-
|
|
974
|
-
expect(errorEvents.length).toBeGreaterThanOrEqual(3);
|
|
975
|
-
|
|
976
|
-
errorEvents.forEach(event => {
|
|
977
|
-
expect(event.error.workflowId).toBeDefined();
|
|
978
|
-
expect(event.error.message).toBeDefined();
|
|
979
|
-
expect(event.error.logs).toBeDefined();
|
|
980
|
-
expect(Array.isArray(event.error.logs)).toBe(true);
|
|
981
|
-
});
|
|
982
|
-
});
|
|
983
|
-
});
|
|
984
|
-
|
|
985
|
-
describe('All children failing', () => {
|
|
986
|
-
it('should handle edge case of all children failing', async () => {
|
|
987
|
-
// Arrange
|
|
988
|
-
class ParentWorkflow extends Workflow {
|
|
989
|
-
async run() {
|
|
990
|
-
const children = Array.from({ length: 5 }, (_, i) =>
|
|
991
|
-
createChildWorkflow(this, `Child-${i}`, true)
|
|
992
|
-
);
|
|
993
|
-
|
|
994
|
-
return await Promise.allSettled(
|
|
995
|
-
children.map(c => c.run())
|
|
996
|
-
);
|
|
997
|
-
}
|
|
998
|
-
}
|
|
999
|
-
|
|
1000
|
-
const parent = new ParentWorkflow();
|
|
1001
|
-
|
|
1002
|
-
// Act
|
|
1003
|
-
const results = await parent.run();
|
|
1004
|
-
|
|
1005
|
-
// Assert: All children failed
|
|
1006
|
-
expect(results.length).toBe(5);
|
|
1007
|
-
|
|
1008
|
-
const failures = results.filter(r => r.status === 'rejected');
|
|
1009
|
-
const successes = results.filter(r => r.status === 'fulfilled');
|
|
1010
|
-
|
|
1011
|
-
expect(failures.length).toBe(5);
|
|
1012
|
-
expect(successes.length).toBe(0);
|
|
1013
|
-
|
|
1014
|
-
// Assert: All errors collected
|
|
1015
|
-
const errorMessages = failures.map(f => f.reason.message);
|
|
1016
|
-
expect(new Set(errorMessages).size).toBe(5);
|
|
1017
|
-
});
|
|
1018
|
-
});
|
|
1019
|
-
|
|
1020
|
-
describe('No orphaned workflows', () => {
|
|
1021
|
-
it('should verify all workflows complete with no hanging promises', async () => {
|
|
1022
|
-
// Arrange
|
|
1023
|
-
const completedWorkflows = new Set<string>();
|
|
1024
|
-
|
|
1025
|
-
class ParentWorkflow extends Workflow {
|
|
1026
|
-
async run() {
|
|
1027
|
-
const children = Array.from({ length: 10 }, (_, i) => {
|
|
1028
|
-
const child = createChildWorkflow(
|
|
1029
|
-
this,
|
|
1030
|
-
`Child-${i}`,
|
|
1031
|
-
Math.random() < 0.3 // 30% failure rate
|
|
1032
|
-
);
|
|
1033
|
-
|
|
1034
|
-
// Track completion
|
|
1035
|
-
child.run().then(
|
|
1036
|
-
() => completedWorkflows.add(child.id),
|
|
1037
|
-
() => completedWorkflows.add(child.id)
|
|
1038
|
-
);
|
|
1039
|
-
|
|
1040
|
-
return child;
|
|
1041
|
-
});
|
|
1042
|
-
|
|
1043
|
-
return await Promise.allSettled(
|
|
1044
|
-
children.map(c => c.run())
|
|
1045
|
-
);
|
|
1046
|
-
}
|
|
1047
|
-
}
|
|
1048
|
-
|
|
1049
|
-
const parent = new ParentWorkflow();
|
|
1050
|
-
|
|
1051
|
-
// Act: Run with timeout to detect hanging promises
|
|
1052
|
-
const timeoutPromise = new Promise((_, reject) =>
|
|
1053
|
-
setTimeout(() => reject(new Error('Timeout')), 5000)
|
|
1054
|
-
);
|
|
1055
|
-
|
|
1056
|
-
const runPromise = parent.run();
|
|
1057
|
-
|
|
1058
|
-
await Promise.race([runPromise, timeoutPromise]);
|
|
1059
|
-
|
|
1060
|
-
// Assert: All workflows accounted for
|
|
1061
|
-
expect(completedWorkflows.size).toBe(10);
|
|
1062
|
-
});
|
|
1063
|
-
});
|
|
1064
|
-
});
|
|
1065
|
-
```
|
|
1066
|
-
|
|
1067
|
-
---
|
|
1068
|
-
|
|
1069
|
-
## Key Takeaways
|
|
1070
|
-
|
|
1071
|
-
### 1. Promise.allSettled is Essential
|
|
1072
|
-
Always use `Promise.allSettled()` when running concurrent workflows to ensure all tasks complete regardless of individual failures.
|
|
1073
|
-
|
|
1074
|
-
### 2. Comprehensive Event Tracking
|
|
1075
|
-
Capture all events during concurrent execution to verify error propagation and state changes.
|
|
1076
|
-
|
|
1077
|
-
### 3. Timeout Protection
|
|
1078
|
-
Always include timeout protection in tests to detect hanging promises or orphaned workflows.
|
|
1079
|
-
|
|
1080
|
-
### 4. Error Context Preservation
|
|
1081
|
-
Ensure errors contain workflow context (ID, name, logs, state) for debugging and monitoring.
|
|
1082
|
-
|
|
1083
|
-
### 5. Completion Verification
|
|
1084
|
-
Explicitly verify that all workflows complete, even when some fail.
|
|
1085
|
-
|
|
1086
|
-
### 6. Count-Based Assertions
|
|
1087
|
-
Use assertions that verify expected counts of failures and successes.
|
|
1088
|
-
|
|
1089
|
-
### 7. Distinct Error Validation
|
|
1090
|
-
Ensure multiple concurrent failures produce distinct, trackable errors.
|
|
1091
|
-
|
|
1092
|
-
---
|
|
1093
|
-
|
|
1094
|
-
## References
|
|
1095
|
-
|
|
1096
|
-
- [Apache Airflow Test Suite](https://github.com/apache/airflow/tree/main/tests)
|
|
1097
|
-
- [Temporal SDK Python Tests](https://github.com/temporalio/sdk-python/tree/master/tests)
|
|
1098
|
-
- [Prefect Test Suite](https://github.com/PrefectHQ/prefect/tree/main/tests)
|
|
1099
|
-
- [Node.js Promise Tests](https://github.com/nodejs/node/tree/main/test/parallel)
|
|
1100
|
-
- [MDN: Promise.allSettled()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled)
|
|
1101
|
-
|
|
1102
|
-
---
|
|
1103
|
-
|
|
1104
|
-
## Document Metadata
|
|
1105
|
-
|
|
1106
|
-
**Created**: 2026-01-12
|
|
1107
|
-
**Purpose**: Research task P1.M2.T1.S3 - Testing patterns for concurrent task failures
|
|
1108
|
-
**Target**: /home/dustin/projects/groundswell
|
|
1109
|
-
**Related Bug**: 001_e8e04329daf3 - Promise.allSettled error collection in @Task decorator
|