groundswell 0.0.1 → 0.0.2
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/.claude/commands/subtask-planning/prp-base-create.md +120 -0
- package/.claude/commands/subtask-planning/prp-base-execute.md +65 -0
- package/.claude/commands/task-breakdown.md +94 -0
- package/.claude/system_prompts/task-breakdown.md +1 -0
- package/CHANGELOG.md +188 -0
- package/PRD.md +543 -0
- package/README.md +99 -5
- package/examples/README.md +15 -1
- package/examples/examples/11-reparenting-workflows.ts +269 -0
- package/examples/index.ts +4 -0
- package/package-lock.json +2398 -0
- package/package.json +3 -1
- package/plan/001_d3bb02af4886/TEST_RESULTS.md +259 -0
- package/plan/001_d3bb02af4886/bug_fix_tasks.json +484 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M1T1S1/PRP.md +488 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M1T1S2/PRP.md +581 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M1T1S3/PRP.md +687 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T1S1/PRP.md +492 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T1S3/PRP.md +932 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T1S3/research/concurrent_error_testing_patterns.md +1109 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T1S3/research/vitest_concurrent_testing.md +802 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T1S3/research/workflow_engine_test_references.md +603 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T2S1/PRP.md +564 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T2S3/PRP.md +518 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T2S4/PRP.md +1252 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T3S1/PRP.md +364 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T3S1/research/CODEBASE_INVENTORY.md +114 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T3S1/research/DECORATOR_DOCUMENTATION_PATTERNS.md +205 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T3S1/research/PRD_LOCATION_ANALYSIS.md +199 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T3S1/research/ULTRATHINK_PRP_PLAN.md +134 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T1S1/PRP.md +495 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T1S1/research/console_error_inventory.md +435 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T1S2/PRP.md +506 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T1S3/PRP.md +612 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T2S2/PRP.md +558 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T2S2/research/external_research.md +788 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T3S2/PRP.md +460 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T3S3/PRP.md +454 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T4S1/PRP.md +520 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T4S1/RECOMMENDATION.md +417 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T4S1/research/external_workflow_engines_research.md +760 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T4S1/research/security_implications_analysis.md +245 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T4S2/PRP.md +792 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S1/PRP.md +535 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S1/TEST_EXECUTION_REPORT.md +190 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S2/PRP.md +654 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S2/TEST_FIX_REPORT.md +227 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S2/research/KEY_FINDINGS.md +345 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S2/research/QUICK_REFERENCE.md +193 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S2/research/test_maintenance_research.md +1323 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T3S1/BREAKING_CHANGES_AUDIT.md +1011 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T3S1/PRP.md +927 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T3S2/PRP.md +505 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/architecture/logger_child_signature_analysis.md +401 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S3/child_implementation_research.md +142 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S3/test_patterns_research.md +112 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S3/vitest_patterns_research.md +159 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S4/PRP.md +549 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S4/VERIFICATION_REPORT.md +368 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S4/edge_case_analysis.md +172 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S4/usage_inventory.md +175 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T1S2/PRP.md +696 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T1S4/PRP.md +860 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/PRP.md +1066 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/01-testing-aggregated-errors.md +1103 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/01_typescript_error_aggregation_patterns.md +789 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/02-error-merge-strategy-testing-guide.md +1098 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/02_aggregate_error_patterns.md +1037 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/03-promise-allsettled-testing-patterns.md +916 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/03_error_merging_strategies.md +1045 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/04_github_stackoverflow_examples.md +890 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/05_comprehensive_summary.md +822 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/INDEX.md +668 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/QUICK_REFERENCE.md +706 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/README.md +265 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/RESEARCH_REPORT.md +655 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S4/research/vitest_testing_patterns.md +1103 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T3S2/PRP.md +426 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T1S2/PRP.md +506 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T1S2/research/QUICK_REFERENCE.md +114 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T1S2/research/RESEARCH_SUMMARY.md +316 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T1S2/research/vitest_observer_error_logging_best_practices.md +754 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T1S3/PRP.md +612 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T2S1/PRP.md +719 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T2S1/README.md +215 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T2S1/analysis.md +765 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T2S3/PRP.md +718 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T3S1/DECISION.md +149 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T3S1/PRP.md +470 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T3S1/research/ULTRATHINK_PLAN.md +332 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T3S1/research/codebase_workflow_name_analysis.md +167 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T3S1/research/external_best_practices.md +265 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T3S1/research/validation_patterns.md +273 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T4S1/workflow_engine_ancestry_api_research.md +760 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T4S3-PRP.md +434 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M4T2S1/PRP.md +717 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M4T2S2/PRP.md +472 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M4T2S2/VALIDATION_REPORT.md +125 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M4T2S2/research/ULTRATHINK_PRP_PLAN.md +301 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/error-logging-best-practices.md +1170 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/research_typescript_partial_and_overloads.md +940 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/vitest-quick-reference.md +151 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/vitest-research.md +650 -0
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/prd_snapshot.md +259 -0
- package/plan/001_d3bb02af4886/bugfix/P1M1T1S1/PRP.md +457 -0
- package/plan/001_d3bb02af4886/bugfix/RESEARCH_SUMMARY.md +346 -0
- package/plan/001_d3bb02af4886/bugfix/architecture/codebase_structure.md +311 -0
- package/plan/001_d3bb02af4886/bugfix/architecture/concurrent_execution_best_practices.md +1565 -0
- package/plan/001_d3bb02af4886/bugfix/architecture/error_handling_patterns.md +288 -0
- package/plan/001_d3bb02af4886/bugfix/architecture/promise_all_analysis.md +741 -0
- package/plan/001_d3bb02af4886/docs/PRP/P1M1T1S4-functional-workflow-error-state-capture-test.md +652 -0
- package/plan/001_d3bb02af4886/docs/PRP/PRP.md +527 -0
- package/plan/001_d3bb02af4886/docs/PRP/bugfix/P1M1T2S1-PRP.md +415 -0
- package/plan/001_d3bb02af4886/docs/PRP/bugfix/P1M1T2S2-PRP.md +378 -0
- package/plan/001_d3bb02af4886/docs/PRP/bugfix/P1M1T2S4-PRP.md +713 -0
- package/plan/001_d3bb02af4886/docs/PRP/bugfix/P1M2T1S4-PRP.md +370 -0
- package/plan/001_d3bb02af4886/docs/PRP_P1M3T1S3.md +499 -0
- package/plan/001_d3bb02af4886/docs/TEST_RESULTS.md +230 -0
- package/plan/001_d3bb02af4886/docs/bugfix/ANALYSIS_PRD_VS_IMPLEMENTATION.md +1134 -0
- package/plan/001_d3bb02af4886/docs/bugfix/GAP_ANALYSIS_SUMMARY.md +179 -0
- package/plan/001_d3bb02af4886/docs/bugfix/P1M4T2S1/PRP.md +629 -0
- package/plan/001_d3bb02af4886/docs/bugfix/P1M4T2S1/validation-report.md +214 -0
- package/plan/001_d3bb02af4886/docs/bugfix/PRP_P1M4T2S3.md +629 -0
- package/plan/001_d3bb02af4886/docs/bugfix/bugfix_PRP.md +529 -0
- package/plan/001_d3bb02af4886/docs/bugfix/bugfix_QUICK_REFERENCE.md +142 -0
- package/plan/001_d3bb02af4886/docs/bugfix/bugfix_README.md +304 -0
- package/plan/001_d3bb02af4886/docs/bugfix/bugfix_TEST_RESULTS.md +558 -0
- package/plan/001_d3bb02af4886/docs/bugfix/bugfix_VALIDATION_SUMMARY.md +256 -0
- package/plan/001_d3bb02af4886/docs/bugfix/system_context.md +346 -0
- package/plan/001_d3bb02af4886/docs/bugfix-architecture/bug_analysis.md +415 -0
- package/plan/001_d3bb02af4886/docs/bugfix-architecture/implementation_patterns.md +489 -0
- package/plan/001_d3bb02af4886/docs/bugfix-architecture/system_context.md +218 -0
- package/plan/001_d3bb02af4886/docs/bugfix_INITIATION_SUMMARY.md +380 -0
- package/plan/001_d3bb02af4886/docs/research/CYCLE_DETECTION_PATTERNS.md +1923 -0
- package/plan/001_d3bb02af4886/docs/research/CYCLE_DETECTION_QUICK_REF.md +319 -0
- package/plan/001_d3bb02af4886/docs/research/P1M1T2S1/codebase-context.md +115 -0
- package/plan/001_d3bb02af4886/docs/research/P1M1T2S1/cycle-detection-algorithms.md +134 -0
- package/plan/001_d3bb02af4886/docs/research/P1M1T2S1/test-patterns.md +153 -0
- package/plan/001_d3bb02af4886/docs/research/P1M1T2S1/workflow-class.md +132 -0
- package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/DECORATOR_DOCUMENTATION_BEST_PRACTICES.md +716 -0
- package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/DECORATOR_DOCUMENTATION_QUICK_REF.md +186 -0
- package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/GROUNDSWELL_DECORATOR_EXAMPLES.md +604 -0
- package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/INDEX.md +213 -0
- package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/codebase_structure.md +30 -0
- package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/existing_test_pattern.md +56 -0
- package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/getRootObservers_implementation.md +53 -0
- package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/test_conventions.md +49 -0
- package/plan/001_d3bb02af4886/docs/research/P1M3T1S4/PRP.md +958 -0
- package/plan/001_d3bb02af4886/docs/research/P1M3T1S4/QUICK_REFERENCE.md +339 -0
- package/plan/001_d3bb02af4886/docs/research/P1M3T1S4/README.md +305 -0
- package/plan/001_d3bb02af4886/docs/research/P1M3T1S4/SUMMARY.md +433 -0
- package/plan/001_d3bb02af4886/docs/research/P1M3T1S4/bidirectional-tree-consistency-testing.md +1574 -0
- package/plan/001_d3bb02af4886/docs/research/P1M3T1S4/test-pattern-examples.md +1014 -0
- package/plan/001_d3bb02af4886/docs/research/PROMISE_ALLSETTLED_QUICK_REF.md +376 -0
- package/plan/001_d3bb02af4886/docs/research/PROMISE_ALLSETTLED_RESEARCH.md +1507 -0
- package/plan/001_d3bb02af4886/docs/research/bugfix_typescript_patterns.md +949 -0
- package/plan/001_d3bb02af4886/docs/research/error-testing-research.md +619 -0
- package/plan/001_d3bb02af4886/docs/research/error_handling_patterns.md +723 -0
- package/plan/{research → 001_d3bb02af4886/docs/research/general}/introspection-security-guide.md +56 -0
- package/plan/001_d3bb02af4886/docs/research/incremental-tree-map-updates/PRP_TEMPLATE.md +460 -0
- package/plan/001_d3bb02af4886/docs/research/incremental-tree-map-updates/QUICK_REFERENCE.md +324 -0
- package/plan/001_d3bb02af4886/docs/research/incremental-tree-map-updates/README.md +175 -0
- package/plan/001_d3bb02af4886/docs/research/incremental-tree-map-updates/RESEARCH_REPORT.md +499 -0
- package/plan/001_d3bb02af4886/docs/research/incremental-tree-map-updates/SUMMARY.md +163 -0
- package/plan/bugfix/BUG_FIX_SUMMARY.md +961 -0
- package/src/__tests__/adversarial/attachChild-performance.test.ts +216 -0
- package/src/__tests__/adversarial/circular-reference.test.ts +101 -0
- package/src/__tests__/adversarial/complex-circular-reference.test.ts +139 -0
- package/src/__tests__/adversarial/concurrent-task-failures.test.ts +571 -0
- package/src/__tests__/adversarial/deep-analysis.test.ts +729 -0
- package/src/__tests__/adversarial/deep-hierarchy-stress.test.ts +213 -0
- package/src/__tests__/adversarial/e2e-prd-validation.test.ts +448 -0
- package/src/__tests__/adversarial/edge-case.test.ts +703 -0
- package/src/__tests__/adversarial/error-merge-strategy.test.ts +760 -0
- package/src/__tests__/adversarial/incremental-performance.test.ts +140 -0
- package/src/__tests__/adversarial/node-map-update-benchmarks.test.ts +457 -0
- package/src/__tests__/adversarial/observer-propagation.test.ts +487 -0
- package/src/__tests__/adversarial/parent-validation.test.ts +143 -0
- package/src/__tests__/adversarial/prd-12-2-compliance.test.ts +611 -0
- package/src/__tests__/adversarial/prd-compliance.test.ts +731 -0
- package/src/__tests__/compatibility/backward-compatibility.test.ts +1572 -0
- package/src/__tests__/helpers/index.ts +18 -0
- package/src/__tests__/helpers/tree-verification.ts +257 -0
- package/src/__tests__/integration/bidirectional-consistency.test.ts +847 -0
- package/src/__tests__/integration/observer-logging.test.ts +643 -0
- package/src/__tests__/integration/tree-mirroring.test.ts +37 -0
- package/src/__tests__/integration/workflow-reparenting.test.ts +303 -0
- package/src/__tests__/unit/context.test.ts +79 -0
- package/src/__tests__/unit/logger.test.ts +293 -0
- package/src/__tests__/unit/observable.test.ts +321 -0
- package/src/__tests__/unit/tree-debugger-incremental.test.ts +170 -0
- package/src/__tests__/unit/utils/workflow-error-utils.test.ts +209 -0
- package/src/__tests__/unit/workflow-detachChild.test.ts +100 -0
- package/src/__tests__/unit/workflow-emitEvent-childDetached.test.ts +153 -0
- package/src/__tests__/unit/workflow-isDescendantOf.test.ts +180 -0
- package/src/__tests__/unit/workflow.test.ts +277 -1
- package/src/core/agent.ts +21 -1
- package/src/core/logger.ts +27 -2
- package/src/core/workflow-context.ts +6 -4
- package/src/core/workflow.ts +252 -14
- package/src/debugger/tree-debugger.ts +52 -7
- package/src/decorators/task.ts +65 -2
- package/src/index.ts +4 -2
- package/src/types/decorators.ts +8 -1
- package/src/types/events.ts +1 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/observable.ts +32 -3
- package/src/utils/workflow-error-utils.ts +56 -0
- package/tsconfig.json +1 -1
- package/llms_full.txt +0 -5890
- package/tasks.json +0 -0
- /package/plan/{backlog.json → 001_d3bb02af4886/backlog.json} +0 -0
- /package/plan/{P1P2/PRP.md → 001_d3bb02af4886/docs/PRP/P1P2-PRP.md} +0 -0
- /package/plan/{P3P4/PRP.md → 001_d3bb02af4886/docs/PRP/P3P4-PRP.md} +0 -0
- /package/plan/{P4P5/PRP.md → 001_d3bb02af4886/docs/PRP/P4P5-PRP.md} +0 -0
- /package/plan/{architecture → 001_d3bb02af4886/docs/architecture}/external_deps.md +0 -0
- /package/plan/{architecture → 001_d3bb02af4886/docs/architecture}/system_context.md +0 -0
- /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/LRU_CACHE_BEST_PRACTICES.md +0 -0
- /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/LRU_CACHE_CODE_PATTERNS.md +0 -0
- /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/LRU_CACHE_INTEGRATION_GUIDE.md +0 -0
- /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/LRU_CACHE_RESEARCH_INDEX.md +0 -0
- /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/REFLECTION_INDEX.md +0 -0
- /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/REFLECTION_RESEARCH_REPORT.md +0 -0
- /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/RESEARCH_SUMMARY.md +0 -0
- /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/anthropic-sdk.md +0 -0
- /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/async-local-storage.md +0 -0
- /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/reflection-code-patterns.md +0 -0
- /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/reflection-decision-matrix.md +0 -0
- /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/reflection-implementation-guide.md +0 -0
- /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/reflection-integration-guide.md +0 -0
- /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/reflection-patterns.md +0 -0
- /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/reflection-quick-reference.md +0 -0
- /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/zod-schema.md +0 -0
- /package/plan/{P3P4/research → 001_d3bb02af4886/docs/research/P3P4}/caching-lru.md +0 -0
- /package/plan/{P3P4/research → 001_d3bb02af4886/docs/research/P3P4}/introspection-tools.md +0 -0
- /package/plan/{P3P4/research → 001_d3bb02af4886/docs/research/P3P4}/reflection-patterns.md +0 -0
- /package/plan/{P4P5/research → 001_d3bb02af4886/docs/research/P4P5}/RESEARCH_SUMMARY.md +0 -0
- /package/plan/{research → 001_d3bb02af4886/docs/research/general}/INTROSPECTION_RESEARCH_SUMMARY.md +0 -0
- /package/plan/{research → 001_d3bb02af4886/docs/research/general}/README-INTROSPECTION.md +0 -0
- /package/plan/{research → 001_d3bb02af4886/docs/research/general}/agent-introspection-patterns.md +0 -0
- /package/plan/{research → 001_d3bb02af4886/docs/research/general}/introspection-tool-examples.md +0 -0
- /package/{PRPs/PRDs/001-hierarchical-workflow-engine.md → plan/001_d3bb02af4886/prd_snapshot.md} +0 -0
|
@@ -0,0 +1,696 @@
|
|
|
1
|
+
# PRP: P1.M2.T1.S2 - Implement Promise.allSettled with Error Collection
|
|
2
|
+
|
|
3
|
+
**Document Version:** 1.0
|
|
4
|
+
**Creation Date:** 2026-01-12
|
|
5
|
+
**Target:** Subtask P1.M2.T1.S2 - Replace Promise.all with Promise.allSettled in @Task decorator
|
|
6
|
+
**Primary File:** `src/decorators/task.ts` (line 112)
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Goal
|
|
11
|
+
|
|
12
|
+
**Feature Goal**: Replace `Promise.all()` with `Promise.allSettled()` in the @Task decorator's concurrent execution path (src/decorators/task.ts:112) to enable collection of all concurrent workflow errors while maintaining backward compatibility by throwing the first error when no error merge strategy is configured.
|
|
13
|
+
|
|
14
|
+
**Deliverable**: Updated @Task decorator that:
|
|
15
|
+
1. Uses `Promise.allSettled()` instead of `Promise.all()` for concurrent task execution
|
|
16
|
+
2. Collects all `PromiseRejectedResult` errors from concurrent workflows
|
|
17
|
+
3. Maintains backward compatibility by throwing the first error (fail-fast behavior) when no error merge strategy is configured
|
|
18
|
+
4. Preserves all existing event emissions and workflow attachment behaviors
|
|
19
|
+
|
|
20
|
+
**Success Definition**:
|
|
21
|
+
- Line 112 in `src/decorators/task.ts` uses `Promise.allSettled()` instead of `Promise.all()`
|
|
22
|
+
- Errors from all failed concurrent workflows are collected into an array
|
|
23
|
+
- Backward compatibility is maintained: first error is thrown by default (no behavior change for existing code)
|
|
24
|
+
- All existing tests continue to pass without modification
|
|
25
|
+
- The change enables P1.M2.T2 (ErrorMergeStrategy implementation) in future work
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## All Needed Context
|
|
30
|
+
|
|
31
|
+
### Context Completeness Check
|
|
32
|
+
|
|
33
|
+
**"No Prior Knowledge" Test**: If someone knew nothing about this codebase, would they have everything needed to implement this successfully?
|
|
34
|
+
|
|
35
|
+
**Answer**: YES - This PRP provides:
|
|
36
|
+
- Exact file location with line number (src/decorators/task.ts:112)
|
|
37
|
+
- Complete current implementation code snippet
|
|
38
|
+
- Required code changes with before/after comparison
|
|
39
|
+
- Type definitions for all interfaces used
|
|
40
|
+
- Error handling patterns to follow
|
|
41
|
+
- Test patterns for validation
|
|
42
|
+
- External research documentation with URLs
|
|
43
|
+
|
|
44
|
+
### Documentation & References
|
|
45
|
+
|
|
46
|
+
```yaml
|
|
47
|
+
# MUST READ - Current Implementation
|
|
48
|
+
- file: src/decorators/task.ts
|
|
49
|
+
lines: 104-114
|
|
50
|
+
why: Contains the Promise.all implementation that must be replaced
|
|
51
|
+
pattern: Concurrent workflow execution with runnable filtering
|
|
52
|
+
gotcha: Promise.all fails fast on first error; Promise.allSettled never rejects
|
|
53
|
+
|
|
54
|
+
- file: src/decorators/task.ts
|
|
55
|
+
lines: 1-129 (full file)
|
|
56
|
+
why: Complete @Task decorator context including child attachment logic
|
|
57
|
+
pattern: Task decorator wrapper function with event emission
|
|
58
|
+
|
|
59
|
+
- file: plan/001_d3bb02af4886/bugfix/architecture/promise_all_analysis.md
|
|
60
|
+
why: S1 analysis document with complete Promise.all implementation details
|
|
61
|
+
section: "5. Promise.allSettled Migration Requirements"
|
|
62
|
+
critical: Contains exact migration requirements and code changes needed
|
|
63
|
+
|
|
64
|
+
- file: plan/001_d3bb02af4886/bugfix/architecture/concurrent_execution_best_practices.md
|
|
65
|
+
why: Internal guidance on Promise.allSettled usage patterns
|
|
66
|
+
section: "Recommended Error Collection Patterns"
|
|
67
|
+
critical: Specifies using Promise.allSettled for complete-all error strategy
|
|
68
|
+
|
|
69
|
+
# TYPE DEFINITIONS - Required for implementation
|
|
70
|
+
- file: src/types/error-strategy.ts
|
|
71
|
+
why: Defines ErrorMergeStrategy interface (future use in P1.M2.T2)
|
|
72
|
+
pattern: Interface with enabled, maxMergeDepth, and combine() function
|
|
73
|
+
note: NOT used in this task - collected errors stored in array for future use
|
|
74
|
+
|
|
75
|
+
- file: src/types/decorators.ts
|
|
76
|
+
why: Defines TaskOptions interface for @Task decorator configuration
|
|
77
|
+
pattern: Options interface with name and concurrent properties
|
|
78
|
+
|
|
79
|
+
- file: src/types/error.ts
|
|
80
|
+
why: Defines WorkflowError interface structure for error handling
|
|
81
|
+
pattern: Interface with message, original, workflowId, stack, state, logs
|
|
82
|
+
|
|
83
|
+
- file: src/types/events.ts
|
|
84
|
+
why: Defines WorkflowEvent type including error events
|
|
85
|
+
pattern: Union type with { type: 'error', node, error }
|
|
86
|
+
|
|
87
|
+
# EXTERNAL RESEARCH - Promise.allSettled best practices
|
|
88
|
+
- url: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled
|
|
89
|
+
why: Official documentation for Promise.allSettled() method
|
|
90
|
+
section: #description
|
|
91
|
+
critical: Promise.allSettled NEVER rejects - always resolves with status array
|
|
92
|
+
|
|
93
|
+
- url: https://www.typescriptlang.org/docs/handbook/2/types-from-types.html#promise-types
|
|
94
|
+
why: TypeScript Promise types including PromiseSettledResult
|
|
95
|
+
section: Promise Types
|
|
96
|
+
critical: Type guards required for discriminated unions
|
|
97
|
+
|
|
98
|
+
- docfile: plan/001_d3bb02af4886/docs/research/PROMISE_ALLSETTLED_RESEARCH.md
|
|
99
|
+
why: Comprehensive Promise.allSettled implementation patterns
|
|
100
|
+
section: "2. Promise.allSettled() Error Collection Patterns"
|
|
101
|
+
critical: Type guard patterns, error filtering, aggregation examples
|
|
102
|
+
|
|
103
|
+
- docfile: plan/001_d3bb02af4886/docs/research/PROMISE_ALLSETTLED_QUICK_REF.md
|
|
104
|
+
why: Quick reference for Promise.allSettled implementation
|
|
105
|
+
section: "Groundswell Implementation"
|
|
106
|
+
critical: Specific code examples for this codebase
|
|
107
|
+
|
|
108
|
+
# TEST PATTERNS - Follow for validation
|
|
109
|
+
- file: src/__tests__/adversarial/edge-case.test.ts
|
|
110
|
+
lines: 366-430
|
|
111
|
+
why: Contains concurrent task execution tests with mixed success/failure
|
|
112
|
+
pattern: Testing concurrent workflows with errors
|
|
113
|
+
|
|
114
|
+
- file: src/__tests__/adversarial/prd-compliance.test.ts
|
|
115
|
+
lines: 421-460
|
|
116
|
+
why: Tests concurrent execution with multiple child workflows
|
|
117
|
+
pattern: Execution order tracking for verifying concurrency
|
|
118
|
+
|
|
119
|
+
- file: vitest.config.ts
|
|
120
|
+
why: Test runner configuration
|
|
121
|
+
command: npm test or npm run test:watch
|
|
122
|
+
|
|
123
|
+
# STEP DECORATOR - Error wrapping context
|
|
124
|
+
- file: src/decorators/step.ts
|
|
125
|
+
lines: 109-134
|
|
126
|
+
why: Shows how WorkflowError objects are created and error events emitted
|
|
127
|
+
pattern: Error capture with getObservedState(), event emission
|
|
128
|
+
critical: Each failing workflow already emits error event - don't duplicate
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Current Codebase Tree
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
/home/dustin/projects/groundswell
|
|
135
|
+
├── src/
|
|
136
|
+
│ ├── decorators/
|
|
137
|
+
│ │ ├── index.ts # Exports Task decorator
|
|
138
|
+
│ │ ├── step.ts # @Step decorator with error wrapping (lines 109-134)
|
|
139
|
+
│ │ └── task.ts # PRIMARY: Promise.all at line 112 - TARGET FILE
|
|
140
|
+
│ ├── types/
|
|
141
|
+
│ │ ├── index.ts # Re-exports all types
|
|
142
|
+
│ │ ├── decorators.ts # TaskOptions interface
|
|
143
|
+
│ │ ├── error-strategy.ts # ErrorMergeStrategy interface (unused in this task)
|
|
144
|
+
│ │ ├── error.ts # WorkflowError interface
|
|
145
|
+
│ │ └── events.ts # WorkflowEvent union type
|
|
146
|
+
│ ├── utils/
|
|
147
|
+
│ │ ├── id.ts # ID generation utilities
|
|
148
|
+
│ │ ├── index.ts # Exports utils
|
|
149
|
+
│ │ └── observable.ts # Observable utilities
|
|
150
|
+
│ └── __tests__/
|
|
151
|
+
│ ├── adversarial/
|
|
152
|
+
│ │ ├── edge-case.test.ts # Concurrent error tests (lines 366-430)
|
|
153
|
+
│ │ ├── prd-compliance.test.ts # Concurrent execution tests (lines 421-460)
|
|
154
|
+
│ │ └── deep-analysis.test.ts # Promise.all usage in tests
|
|
155
|
+
│ └── unit/
|
|
156
|
+
│ └── decorators.test.ts # General decorator tests
|
|
157
|
+
├── plan/
|
|
158
|
+
│ └── 001_d3bb02af4886/
|
|
159
|
+
│ ├── bugfix/
|
|
160
|
+
│ │ ├── 001_e8e04329daf3/
|
|
161
|
+
│ │ │ ├── P1M2T1S1/
|
|
162
|
+
│ │ │ │ └── PRP.md # S1 analysis PRP (completed)
|
|
163
|
+
│ │ │ └── P1M2T1S2/
|
|
164
|
+
│ │ │ └── PRP.md # THIS FILE
|
|
165
|
+
│ │ └── architecture/
|
|
166
|
+
│ │ ├── promise_all_analysis.md # S1 analysis output
|
|
167
|
+
│ │ ├── concurrent_execution_best_practices.md
|
|
168
|
+
│ │ └── error_handling_patterns.md
|
|
169
|
+
│ └── docs/
|
|
170
|
+
│ └── research/
|
|
171
|
+
│ ├── PROMISE_ALLSETTLED_RESEARCH.md
|
|
172
|
+
│ └── PROMISE_ALLSETTLED_QUICK_REF.md
|
|
173
|
+
└── vitest.config.ts # Test configuration
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### Desired Codebase Tree (Changes for This Task)
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
# MODIFIED FILES:
|
|
180
|
+
src/decorators/task.ts # Replace Promise.all with Promise.allSettled at line 112
|
|
181
|
+
|
|
182
|
+
# NO NEW FILES for this task
|
|
183
|
+
# Type utilities will be added in P1.M2.T2.S1 (ErrorMergeStrategy support)
|
|
184
|
+
# This task only replaces Promise.all with Promise.allSettled
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Known Gotchas of Our Codebase & Library Quirks
|
|
188
|
+
|
|
189
|
+
```typescript
|
|
190
|
+
// CRITICAL GOTCHA #1: Promise.allSettled NEVER rejects
|
|
191
|
+
// Unlike Promise.all which rejects on first error, Promise.allSettled ALWAYS resolves
|
|
192
|
+
// You MUST manually check for errors in the results array
|
|
193
|
+
// BAD: try { await Promise.allSettled(...) } catch (e) { /* NEVER EXECUTES */ }
|
|
194
|
+
// GOOD: const results = await Promise.allSettled(...);
|
|
195
|
+
// const errors = results.filter(r => r.status === 'rejected');
|
|
196
|
+
// if (errors.length > 0) throw errors[0].reason;
|
|
197
|
+
|
|
198
|
+
// CRITICAL GOTCHA #2: Type guards REQUIRED for TypeScript
|
|
199
|
+
// PromiseSettledResult is a discriminated union
|
|
200
|
+
// BAD: results.forEach(r => { if (r.status === 'fulfilled') console.log(r.value); });
|
|
201
|
+
// TypeScript error: Property 'value' does not exist on type 'PromiseSettledResult<unknown>'
|
|
202
|
+
// GOOD: const isFulfilled = <T>(r: PromiseSettledResult<T>): r is PromiseFulfilledResult<T> =>
|
|
203
|
+
// r.status === 'fulfilled';
|
|
204
|
+
// results.filter(isFulfilled).forEach(r => console.log(r.value));
|
|
205
|
+
|
|
206
|
+
// CRITICAL GOTCHA #3: Child attachment happens BEFORE concurrent execution
|
|
207
|
+
// Lines 91-102: children are attached before Promise.allSettled runs
|
|
208
|
+
// Parent-child relationships exist regardless of execution success
|
|
209
|
+
// Failed workflows remain attached to parent
|
|
210
|
+
|
|
211
|
+
// CRITICAL GOTCHA #4: Error events already emitted by @Step decorator
|
|
212
|
+
// src/decorators/step.ts:126-130 emits error events for each failed workflow
|
|
213
|
+
// DO NOT emit additional error events in @Task decorator
|
|
214
|
+
// Observers already see individual workflow errors
|
|
215
|
+
|
|
216
|
+
// CRITICAL GOTCHA #5: WorkflowError.original is `unknown`, not `Error`
|
|
217
|
+
// When collecting errors, don't assume Error interface
|
|
218
|
+
// BAD: errors.forEach(e => console.log(e.original.stack));
|
|
219
|
+
// GOOD: if (error.original instanceof Error) console.log(error.original.stack);
|
|
220
|
+
|
|
221
|
+
// CRITICAL GOTCHA #6: Backward compatibility REQUIRED
|
|
222
|
+
// Default behavior must remain fail-fast (throw first error)
|
|
223
|
+
// Only collect errors for future P1.M2.T2 (ErrorMergeStrategy) use
|
|
224
|
+
// DO NOT change behavior of existing code
|
|
225
|
+
|
|
226
|
+
// CRITICAL GOTCHA #7: Runnable filter uses type guard pattern
|
|
227
|
+
// The filter (w): w is WorkflowClass narrows type in filter callback
|
|
228
|
+
// After filtering, runnable items have run() method guaranteed
|
|
229
|
+
|
|
230
|
+
// CRITICAL GOTCHA #8: No duplicate prevention in runnable filter
|
|
231
|
+
// Same workflow instance could appear twice if returned twice
|
|
232
|
+
// Not our concern - user code responsibility
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
## Implementation Blueprint
|
|
238
|
+
|
|
239
|
+
### Data Models and Structure
|
|
240
|
+
|
|
241
|
+
**No new data models for this task** - this task only replaces Promise.all with Promise.allSettled.
|
|
242
|
+
|
|
243
|
+
**Type guards needed (inline in task.ts for now, extracted to utils in P1.M2.T2.S1):**
|
|
244
|
+
|
|
245
|
+
```typescript
|
|
246
|
+
// Type guard for PromiseRejectedResult
|
|
247
|
+
const isRejected = (result: PromiseSettledResult<unknown>): result is PromiseRejectedResult =>
|
|
248
|
+
result.status === 'rejected';
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
**Note:** Full utility file `src/utils/promise-utils.ts` will be created in P1.M2.T2.S1 when implementing ErrorMergeStrategy support.
|
|
252
|
+
|
|
253
|
+
### Implementation Tasks (ordered by dependencies)
|
|
254
|
+
|
|
255
|
+
```yaml
|
|
256
|
+
Task 1: MODIFY src/decorators/task.ts - Import type for Promise.allSettled
|
|
257
|
+
- ADD: No new imports needed - Promise.allSettled is built-in
|
|
258
|
+
- UNDERSTAND: PromiseSettledResult<T>, PromiseFulfilledResult<T>, PromiseRejectedResult are global types
|
|
259
|
+
- DEPENDENCIES: None
|
|
260
|
+
|
|
261
|
+
Task 2: MODIFY src/decorators/task.ts - Replace Promise.all with Promise.allSettled (lines 111-113)
|
|
262
|
+
- CURRENT CODE:
|
|
263
|
+
await Promise.all(runnable.map((w) => w.run()));
|
|
264
|
+
|
|
265
|
+
- REPLACE WITH:
|
|
266
|
+
const results = await Promise.allSettled(runnable.map((w) => w.run()));
|
|
267
|
+
|
|
268
|
+
- DEPENDENCIES: Task 1
|
|
269
|
+
|
|
270
|
+
Task 3: MODIFY src/decorators/task.ts - Add error collection after Promise.allSettled (after line 112)
|
|
271
|
+
- ADD: Filter for rejected results
|
|
272
|
+
- ADD: Extract error reasons from rejected promises
|
|
273
|
+
- ADD: Throw first error for backward compatibility
|
|
274
|
+
|
|
275
|
+
- IMPLEMENTATION:
|
|
276
|
+
// Filter for rejected results
|
|
277
|
+
const rejected = results.filter(
|
|
278
|
+
(r): r is PromiseRejectedResult => r.status === 'rejected'
|
|
279
|
+
);
|
|
280
|
+
|
|
281
|
+
// Throw first error for backward compatibility (fail-fast behavior)
|
|
282
|
+
if (rejected.length > 0) {
|
|
283
|
+
throw rejected[0].reason;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
- DEPENDENCIES: Task 2
|
|
287
|
+
|
|
288
|
+
Task 4: VERIFY existing tests still pass
|
|
289
|
+
- RUN: npm test
|
|
290
|
+
- VERIFY: All existing tests pass without modification
|
|
291
|
+
- VERIFY: Backward compatibility maintained (first error thrown)
|
|
292
|
+
- DEPENDENCIES: Task 3
|
|
293
|
+
|
|
294
|
+
Task 5: RUN specific concurrent execution tests
|
|
295
|
+
- RUN: npm test -- src/__tests__/adversarial/edge-case.test.ts
|
|
296
|
+
- RUN: npm test -- src/__tests__/adversarial/prd-compliance.test.ts
|
|
297
|
+
- VERIFY: Concurrent execution tests still pass
|
|
298
|
+
- DEPENDENCIES: Task 4
|
|
299
|
+
|
|
300
|
+
Task 6: (OPTIONAL) Add inline comment for future P1.M2.T2 enhancement
|
|
301
|
+
- ADD: Comment indicating collected errors are available for future aggregation
|
|
302
|
+
- FORMAT: // P1.M2.T2: Collected errors available for ErrorMergeStrategy implementation
|
|
303
|
+
- DEPENDENCIES: Task 3
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
### Implementation Patterns & Key Details
|
|
307
|
+
|
|
308
|
+
```typescript
|
|
309
|
+
// ============================================
|
|
310
|
+
// PATTERN 1: Promise.allSettled with Error Collection
|
|
311
|
+
// Location: src/decorators/task.ts lines 111-120
|
|
312
|
+
// ============================================
|
|
313
|
+
|
|
314
|
+
// BEFORE (current):
|
|
315
|
+
if (runnable.length > 0) {
|
|
316
|
+
await Promise.all(runnable.map((w) => w.run()));
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// AFTER (target):
|
|
320
|
+
if (runnable.length > 0) {
|
|
321
|
+
// Use Promise.allSettled to collect all results (success and failure)
|
|
322
|
+
const results = await Promise.allSettled(runnable.map((w) => w.run()));
|
|
323
|
+
|
|
324
|
+
// Filter for rejected promises
|
|
325
|
+
const rejected = results.filter(
|
|
326
|
+
(r): r is PromiseRejectedResult => r.status === 'rejected'
|
|
327
|
+
);
|
|
328
|
+
|
|
329
|
+
// Throw first error for backward compatibility (fail-fast behavior)
|
|
330
|
+
// P1.M2.T2: All collected errors available via rejected array for ErrorMergeStrategy
|
|
331
|
+
if (rejected.length > 0) {
|
|
332
|
+
throw rejected[0].reason;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// KEY INSIGHTS:
|
|
337
|
+
// - Promise.allSettled returns PromiseSettledResult<unknown>[] (never rejects)
|
|
338
|
+
// - Type guard (r): r is PromiseRejectedResult narrows type for filter
|
|
339
|
+
// - Throwing first reason maintains exact same behavior as Promise.all
|
|
340
|
+
// - rejected array preserved for future P1.M2.T2 error aggregation
|
|
341
|
+
// - No other behavior changes: events already emitted, children already attached
|
|
342
|
+
|
|
343
|
+
// ============================================
|
|
344
|
+
// PATTERN 2: Type Guard for PromiseRejectedResult
|
|
345
|
+
// Location: src/decorators/task.ts inline (extracted to utils in P1.M2.T2)
|
|
346
|
+
// ============================================
|
|
347
|
+
|
|
348
|
+
// Inline type guard (used in this task):
|
|
349
|
+
const rejected = results.filter(
|
|
350
|
+
(r): r is PromiseRejectedResult => r.status === 'rejected'
|
|
351
|
+
);
|
|
352
|
+
|
|
353
|
+
// Type predicate syntax: (r): r is PromiseRejectedResult
|
|
354
|
+
// - Tells TypeScript that filtered results are always PromiseRejectedResult
|
|
355
|
+
// - Enables accessing .reason property without type error
|
|
356
|
+
// - Equivalent to explicit type guard function:
|
|
357
|
+
// const isRejected = (r: PromiseSettledResult<unknown>): r is PromiseRejectedResult =>
|
|
358
|
+
// r.status === 'rejected';
|
|
359
|
+
|
|
360
|
+
// ============================================
|
|
361
|
+
// PATTERN 3: Backward Compatibility Strategy
|
|
362
|
+
// Location: src/decorators/task.ts after Promise.allSettled
|
|
363
|
+
// ============================================
|
|
364
|
+
|
|
365
|
+
// CRITICAL: Must maintain exact same error propagation behavior
|
|
366
|
+
// Promise.all behavior: Rejects with first error reason
|
|
367
|
+
// Our implementation: Throw first rejected reason
|
|
368
|
+
|
|
369
|
+
if (rejected.length > 0) {
|
|
370
|
+
throw rejected[0].reason; // First error wins (same as Promise.all)
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// WHY THIS WORKS:
|
|
374
|
+
// - Promise.all: first rejection causes immediate reject, reason is the error
|
|
375
|
+
// - Our code: await allSettled completes, then throw first reason
|
|
376
|
+
// - Result: Parent receives same error, same timing (approximately)
|
|
377
|
+
// - Difference: All workflows complete instead of being "orphaned"
|
|
378
|
+
// - This is actually BETTER behavior (no zombie workflows)
|
|
379
|
+
|
|
380
|
+
// ============================================
|
|
381
|
+
// PATTERN 4: Error Context (Already Captured)
|
|
382
|
+
// Location: src/decorators/step.ts lines 109-134
|
|
383
|
+
// ============================================
|
|
384
|
+
|
|
385
|
+
// NOTE: Error wrapping already happens in @Step decorator
|
|
386
|
+
// Each workflow that throws has error already wrapped in WorkflowError
|
|
387
|
+
|
|
388
|
+
// In @Step decorator (step.ts:126-130):
|
|
389
|
+
wf.emitEvent({
|
|
390
|
+
type: 'error',
|
|
391
|
+
node: wf.node,
|
|
392
|
+
error: workflowError, // WorkflowError with full context
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
// IMPLICATION FOR @Task:
|
|
396
|
+
// - rejected[0].reason is already a WorkflowError object
|
|
397
|
+
// - Contains: message, original, workflowId, stack, state, logs
|
|
398
|
+
// - No need to wrap or transform errors
|
|
399
|
+
// - Error events already emitted to observers
|
|
400
|
+
// - Just throw the first WorkflowError as-is
|
|
401
|
+
|
|
402
|
+
// ============================================
|
|
403
|
+
// PATTERN 5: PromiseSettledResult Type Structure
|
|
404
|
+
// Built-in TypeScript types
|
|
405
|
+
// ============================================
|
|
406
|
+
|
|
407
|
+
// PromiseFulfilledResult<T>:
|
|
408
|
+
interface PromiseFulfilledResult<T> {
|
|
409
|
+
status: 'fulfilled';
|
|
410
|
+
value: T;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// PromiseRejectedResult:
|
|
414
|
+
interface PromiseRejectedResult {
|
|
415
|
+
status: 'rejected';
|
|
416
|
+
reason: unknown; // The error/rejection reason
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// PromiseSettledResult<T> (union type):
|
|
420
|
+
type PromiseSettledResult<T> = PromiseFulfilledResult<T> | PromiseRejectedResult;
|
|
421
|
+
|
|
422
|
+
// DISCRIMINATED UNION:
|
|
423
|
+
// - Check .status property to narrow type
|
|
424
|
+
// - 'fulfilled' -> has .value property
|
|
425
|
+
// - 'rejected' -> has .reason property
|
|
426
|
+
// - Type guards required for TypeScript to understand this
|
|
427
|
+
|
|
428
|
+
// Example: Accessing properties safely
|
|
429
|
+
results.forEach(result => {
|
|
430
|
+
if (result.status === 'fulfilled') {
|
|
431
|
+
console.log(result.value); // OK: TypeScript knows this is fulfilled
|
|
432
|
+
} else {
|
|
433
|
+
console.log(result.reason); // OK: TypeScript knows this is rejected
|
|
434
|
+
}
|
|
435
|
+
});
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
### Integration Points
|
|
439
|
+
|
|
440
|
+
```yaml
|
|
441
|
+
# No integration point changes for this task
|
|
442
|
+
# Promise.allSettled is a drop-in replacement for Promise.all
|
|
443
|
+
# No API changes, no type changes, no configuration changes
|
|
444
|
+
|
|
445
|
+
FUTURE_INTEGRATIONS (P1.M2.T2 - ErrorMergeStrategy):
|
|
446
|
+
- modify: src/types/decorators.ts
|
|
447
|
+
add: errorMergeStrategy?: ErrorMergeStrategy
|
|
448
|
+
|
|
449
|
+
- modify: src/decorators/task.ts
|
|
450
|
+
use: rejected array from this task for error aggregation
|
|
451
|
+
pattern: if (opts.errorMergeStrategy?.enabled) { /* aggregate */ }
|
|
452
|
+
|
|
453
|
+
- create: src/utils/promise-utils.ts
|
|
454
|
+
add: Type guard functions isFulfilled, isRejected, isWorkflowError
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
---
|
|
458
|
+
|
|
459
|
+
## Validation Loop
|
|
460
|
+
|
|
461
|
+
### Level 1: Syntax & Style (Immediate Feedback)
|
|
462
|
+
|
|
463
|
+
```bash
|
|
464
|
+
# After modifying src/decorators/task.ts, run these checks
|
|
465
|
+
|
|
466
|
+
# TypeScript type checking
|
|
467
|
+
npx tsc --noEmit src/decorators/task.ts
|
|
468
|
+
|
|
469
|
+
# Run full type check on project
|
|
470
|
+
npm run type-check # or equivalent command
|
|
471
|
+
|
|
472
|
+
# Expected: Zero type errors
|
|
473
|
+
# Common error to fix: TypeScript complaining about .reason access
|
|
474
|
+
# Solution: Ensure type guard (r): r is PromiseRejectedResult is correct
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
### Level 2: Unit Tests (Component Validation)
|
|
478
|
+
|
|
479
|
+
```bash
|
|
480
|
+
# Run all existing tests to verify backward compatibility
|
|
481
|
+
npm test
|
|
482
|
+
|
|
483
|
+
# Run specific concurrent execution tests
|
|
484
|
+
npm test -- src/__tests__/adversarial/edge-case.test.ts
|
|
485
|
+
npm test -- src/__tests__/adversarial/prd-compliance.test.ts
|
|
486
|
+
|
|
487
|
+
# Run decorator-specific tests
|
|
488
|
+
npm test -- src/__tests__/unit/decorators.test.ts
|
|
489
|
+
|
|
490
|
+
# Expected: All tests pass without modification
|
|
491
|
+
# If tests fail, debug - should maintain exact same behavior
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
### Level 3: Integration Testing (System Validation)
|
|
495
|
+
|
|
496
|
+
```bash
|
|
497
|
+
# Create quick manual test to verify Promise.allSettled behavior
|
|
498
|
+
cat > test_concurrent_errors.js << 'EOF'
|
|
499
|
+
// Quick manual test for concurrent error collection
|
|
500
|
+
import { Workflow, Task, Step } from './src/index.js';
|
|
501
|
+
|
|
502
|
+
class FailingWorkflow extends Workflow {
|
|
503
|
+
@Step()
|
|
504
|
+
async run() {
|
|
505
|
+
throw new Error(`Intentional failure in ${this.node.name}`);
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
class SuccessWorkflow extends Workflow {
|
|
510
|
+
@Step()
|
|
511
|
+
async run() {
|
|
512
|
+
return `Success from ${this.node.name}`;
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
class ParentWorkflow extends Workflow {
|
|
517
|
+
@Task({ concurrent: true })
|
|
518
|
+
async spawnMixed() {
|
|
519
|
+
return [
|
|
520
|
+
new SuccessWorkflow('Good1', this),
|
|
521
|
+
new FailingWorkflow('Bad1', this),
|
|
522
|
+
new SuccessWorkflow('Good2', this),
|
|
523
|
+
new FailingWorkflow('Bad2', this),
|
|
524
|
+
];
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
async run() {
|
|
528
|
+
return this.spawnMixed();
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
async function test() {
|
|
533
|
+
const workflow = new ParentWorkflow('TestParent');
|
|
534
|
+
try {
|
|
535
|
+
await workflow.run();
|
|
536
|
+
} catch (error) {
|
|
537
|
+
console.log('Caught error (expected):', error.message);
|
|
538
|
+
console.log('Error workflowId:', error.workflowId);
|
|
539
|
+
console.log('Children attached:', workflow.children.length);
|
|
540
|
+
|
|
541
|
+
// Verify: All workflows completed and attached
|
|
542
|
+
// Verify: First error thrown (Bad1 or Bad2, non-deterministic which)
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
test();
|
|
547
|
+
EOF
|
|
548
|
+
|
|
549
|
+
node test_concurrent_errors.js
|
|
550
|
+
|
|
551
|
+
# Expected behavior:
|
|
552
|
+
# - All 4 child workflows complete execution
|
|
553
|
+
# - All 4 children attached to parent
|
|
554
|
+
# - First error thrown (either Bad1 or Bad2)
|
|
555
|
+
# - Error is WorkflowError with full context
|
|
556
|
+
|
|
557
|
+
# Clean up test file
|
|
558
|
+
rm test_concurrent_errors.js
|
|
559
|
+
```
|
|
560
|
+
|
|
561
|
+
### Level 4: Manual Code Review
|
|
562
|
+
|
|
563
|
+
```bash
|
|
564
|
+
# Review the changes made to src/decorators/task.ts
|
|
565
|
+
|
|
566
|
+
# Key verification points:
|
|
567
|
+
grep -A 10 "Promise.allSettled" src/decorators/task.ts
|
|
568
|
+
|
|
569
|
+
# Should show:
|
|
570
|
+
# 1. Promise.allSettled replaces Promise.all
|
|
571
|
+
# 2. Results filtered for 'rejected' status
|
|
572
|
+
# 3. First error thrown for backward compatibility
|
|
573
|
+
|
|
574
|
+
# Verify no other changes
|
|
575
|
+
git diff src/decorators/task.ts
|
|
576
|
+
|
|
577
|
+
# Expected: Only lines 111-120 changed, no other modifications
|
|
578
|
+
```
|
|
579
|
+
|
|
580
|
+
---
|
|
581
|
+
|
|
582
|
+
## Final Validation Checklist
|
|
583
|
+
|
|
584
|
+
### Technical Validation
|
|
585
|
+
|
|
586
|
+
- [ ] Promise.all replaced with Promise.allSettled at line 112
|
|
587
|
+
- [ ] Error collection filters for PromiseRejectedResult
|
|
588
|
+
- [ ] Type guard (r): r is PromiseRejectedResult used correctly
|
|
589
|
+
- [ ] First error thrown for backward compatibility
|
|
590
|
+
- [ ] No type errors: `npm run type-check` passes
|
|
591
|
+
- [ ] All existing tests pass: `npm test` passes
|
|
592
|
+
- [ ] Concurrent execution tests pass: edge-case.test.ts, prd-compliance.test.ts
|
|
593
|
+
|
|
594
|
+
### Backward Compatibility Validation
|
|
595
|
+
|
|
596
|
+
- [ ] First error thrown maintains fail-fast behavior
|
|
597
|
+
- [ ] Error is same WorkflowError object (no wrapping/transformation)
|
|
598
|
+
- [ ] Error events still emitted by @Step decorator (no duplication)
|
|
599
|
+
- [ ] Child attachment happens before execution (unchanged)
|
|
600
|
+
- [ ] Task start/end events still emitted (unchanged)
|
|
601
|
+
- [ ] No changes to TaskOptions interface (no new options yet)
|
|
602
|
+
|
|
603
|
+
### Code Quality Validation
|
|
604
|
+
|
|
605
|
+
- [ ] Follows existing code patterns (indentation, naming, style)
|
|
606
|
+
- [ ] Inline comment added for future P1.M2.T2 enhancement
|
|
607
|
+
- [ ] No unused variables or dead code
|
|
608
|
+
- [ ] No console.log or debug statements left in
|
|
609
|
+
- [ ] Error handling is specific (throwing exact error, not new wrapper)
|
|
610
|
+
|
|
611
|
+
### Documentation & Future-Proofing
|
|
612
|
+
|
|
613
|
+
- [ ] Comment indicates rejected array available for P1.M2.T2
|
|
614
|
+
- [ ] No breaking changes to public API
|
|
615
|
+
- [ ] Code is self-documenting with clear variable names
|
|
616
|
+
- [ ] Type guards are clear and correct
|
|
617
|
+
|
|
618
|
+
---
|
|
619
|
+
|
|
620
|
+
## Anti-Patterns to Avoid
|
|
621
|
+
|
|
622
|
+
- ❌ **Don't add try-catch around Promise.allSettled** - It never rejects, catching won't work
|
|
623
|
+
- ❌ **Don't skip the type guard** - TypeScript won't know .reason exists without type predicate
|
|
624
|
+
- ❌ **Don't wrap the error** - Throw rejected[0].reason as-is, it's already WorkflowError
|
|
625
|
+
- ❌ **Don't emit error events** - @Step decorator already emits them, don't duplicate
|
|
626
|
+
- ❌ **Don't change TaskOptions** - That's P1.M2.T2, this task is internal change only
|
|
627
|
+
- ❌ **Don't throw AggregateError** - Maintain fail-fast by throwing first error
|
|
628
|
+
- ❌ **Don't access .value or .reason without type check** - Use type guard first
|
|
629
|
+
- ❌ **Don't assume Error interface** - rejected[0].reason is WorkflowError (check with instanceof if needed)
|
|
630
|
+
- ❌ **Don't create new files** - This task only modifies existing task.ts
|
|
631
|
+
- ❌ **Don't write new tests** - Existing tests should pass, new tests in P1.M2.T1.S3
|
|
632
|
+
|
|
633
|
+
---
|
|
634
|
+
|
|
635
|
+
## Success Metrics
|
|
636
|
+
|
|
637
|
+
**Confidence Score**: 10/10 for one-pass implementation success
|
|
638
|
+
|
|
639
|
+
**Definition of Done**:
|
|
640
|
+
1. src/decorators/task.ts line 112 uses Promise.allSettled instead of Promise.all
|
|
641
|
+
2. Errors from all failed concurrent workflows are collected (via rejected array)
|
|
642
|
+
3. Backward compatibility maintained: first error still thrown
|
|
643
|
+
4. All existing tests pass without modification
|
|
644
|
+
5. Zero TypeScript type errors
|
|
645
|
+
6. No changes to public API or TaskOptions interface
|
|
646
|
+
|
|
647
|
+
**Validation**: The implementation enables P1.M2.T2 (ErrorMergeStrategy) by providing collected errors while maintaining complete backward compatibility with existing code.
|
|
648
|
+
|
|
649
|
+
---
|
|
650
|
+
|
|
651
|
+
## Appendix: Complete Code Change Reference
|
|
652
|
+
|
|
653
|
+
### Exact Change Required (src/decorators/task.ts)
|
|
654
|
+
|
|
655
|
+
**Lines 111-113 (BEFORE):**
|
|
656
|
+
```typescript
|
|
657
|
+
if (runnable.length > 0) {
|
|
658
|
+
await Promise.all(runnable.map((w) => w.run()));
|
|
659
|
+
}
|
|
660
|
+
```
|
|
661
|
+
|
|
662
|
+
**Lines 111-120 (AFTER):**
|
|
663
|
+
```typescript
|
|
664
|
+
if (runnable.length > 0) {
|
|
665
|
+
const results = await Promise.allSettled(runnable.map((w) => w.run()));
|
|
666
|
+
|
|
667
|
+
const rejected = results.filter(
|
|
668
|
+
(r): r is PromiseRejectedResult => r.status === 'rejected'
|
|
669
|
+
);
|
|
670
|
+
|
|
671
|
+
if (rejected.length > 0) {
|
|
672
|
+
throw rejected[0].reason;
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
```
|
|
676
|
+
|
|
677
|
+
**Diff:**
|
|
678
|
+
```diff
|
|
679
|
+
if (runnable.length > 0) {
|
|
680
|
+
- await Promise.all(runnable.map((w) => w.run()));
|
|
681
|
+
+ const results = await Promise.allSettled(runnable.map((w) => w.run()));
|
|
682
|
+
+
|
|
683
|
+
+ const rejected = results.filter(
|
|
684
|
+
+ (r): r is PromiseRejectedResult => r.status === 'rejected'
|
|
685
|
+
+ );
|
|
686
|
+
+
|
|
687
|
+
+ if (rejected.length > 0) {
|
|
688
|
+
+ throw rejected[0].reason;
|
|
689
|
+
+ }
|
|
690
|
+
}
|
|
691
|
+
```
|
|
692
|
+
|
|
693
|
+
---
|
|
694
|
+
|
|
695
|
+
**PRP Status**: ✅ Complete - Ready for Implementation
|
|
696
|
+
**Next Task**: P1.M2.T1.S3 - Add tests for concurrent task failure scenarios
|