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,619 @@
|
|
|
1
|
+
# Research: Testing Workflow Error State Capture and Error Handling in TypeScript/JavaScript
|
|
2
|
+
|
|
3
|
+
## Executive Summary
|
|
4
|
+
|
|
5
|
+
This document compiles external best practices for testing error state capture and error handling in workflow/orchestration systems using TypeScript and JavaScript. The research was conducted in January 2026 and includes current best practices, code examples, and authoritative sources.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 1. Testing Error State in Workflow/Orchestration Systems
|
|
10
|
+
|
|
11
|
+
### Key Sources:
|
|
12
|
+
|
|
13
|
+
- **[Temporal TypeScript SDK - Failure Detection](https://docs.temporal.io/develop/typescript/failure-detection)** - Comprehensive guide on handling failures in workflows
|
|
14
|
+
- **[Temporal TypeScript SDK - Observability](https://docs.temporal.io/develop/typescript/observability)** - Workflow state observability patterns
|
|
15
|
+
- **[Workflow Orchestration: Building Complex AI Pipelines](https://medium.com/@omark.k.aly/workflow-orchestration-building-complex-ai-pipelines-c8504ab8306f)** - Error handling patterns including retry with back-off and persistent state
|
|
16
|
+
|
|
17
|
+
### Best Practices:
|
|
18
|
+
|
|
19
|
+
1. **Separate Activity Failures from Workflow Failures**
|
|
20
|
+
- Activities should never directly cause workflow failure
|
|
21
|
+
- Workflows should only fail when explicitly raising an `ApplicationFailure`
|
|
22
|
+
- This allows for proper state capture before workflow termination
|
|
23
|
+
|
|
24
|
+
2. **Use ApplicationFailure for Intentional Failures**
|
|
25
|
+
```typescript
|
|
26
|
+
// From Temporal docs
|
|
27
|
+
throw ApplicationFailure.create({
|
|
28
|
+
message: `Invalid charge amount: ${chargeAmount} (must be above zero)`,
|
|
29
|
+
type: 'InvalidChargeError',
|
|
30
|
+
nonRetryable: true
|
|
31
|
+
});
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
3. **Capture State at Failure Points**
|
|
35
|
+
- Use heartbeat details to capture activity progress
|
|
36
|
+
- Store checkpoint data for potential recovery
|
|
37
|
+
- Include context about what operations were in progress
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## 2. Testing Error Objects with Custom Properties
|
|
42
|
+
|
|
43
|
+
### Key Sources:
|
|
44
|
+
|
|
45
|
+
- **[TypeScript Error Type Handling in Try-Catch Blocks - Convex](https://www.convex.dev/typescript/best-practices/error-handling-debugging/typescript-catch-error-type)** - Comprehensive guide to custom error types
|
|
46
|
+
- **[Handling errors like a pro in TypeScript - Udacity Engineering](https://engineering.udacity.com/handling-errors-like-a-pro-in-typescript-d7a314ad4991)** - Production-tested custom error patterns
|
|
47
|
+
- **[StackOverflow: Add properties to JavaScript Error object](https://stackoverflow.com/questions/47248741/add-properties-to-javascript-error-object)** - Community best practices
|
|
48
|
+
- **[ts-custom-error npm package](https://www.npmjs.com/package/ts-custom-error)** - Library for creating custom errors
|
|
49
|
+
|
|
50
|
+
### Best Practices:
|
|
51
|
+
|
|
52
|
+
1. **Define Specific Error Types**
|
|
53
|
+
```typescript
|
|
54
|
+
// From Convex guide
|
|
55
|
+
interface NetworkError extends Error {
|
|
56
|
+
statusCode: number;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
class NetworkErrorClass extends Error {
|
|
60
|
+
statusCode: number;
|
|
61
|
+
|
|
62
|
+
constructor(message: string, statusCode: number) {
|
|
63
|
+
super(message);
|
|
64
|
+
this.statusCode = statusCode;
|
|
65
|
+
// Important: Set the prototype explicitly
|
|
66
|
+
Object.setPrototypeOf(this, NetworkErrorClass.prototype);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
2. **Use Type Guards for Safe Error Checking**
|
|
72
|
+
```typescript
|
|
73
|
+
function isNetworkError(error: unknown): error is NetworkErrorClass {
|
|
74
|
+
return error instanceof NetworkErrorClass;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
try {
|
|
78
|
+
// code that might throw
|
|
79
|
+
} catch (error: unknown) {
|
|
80
|
+
if (isNetworkError(error)) {
|
|
81
|
+
console.log(`Network error with status code ${error.statusCode}`);
|
|
82
|
+
} else {
|
|
83
|
+
console.log('Unknown error');
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
3. **Create Domain-Specific Error Base Classes**
|
|
89
|
+
```typescript
|
|
90
|
+
// From Udacity Engineering
|
|
91
|
+
abstract class ErrorBase<TName extends string> extends Error {
|
|
92
|
+
readonly name: TName;
|
|
93
|
+
readonly context?: Record<string, unknown>;
|
|
94
|
+
|
|
95
|
+
constructor(name: TName, message: string, context?: Record<string, unknown>) {
|
|
96
|
+
super(message);
|
|
97
|
+
this.name = name;
|
|
98
|
+
this.context = context;
|
|
99
|
+
Object.setPrototypeOf(this, ErrorBase.prototype);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Usage
|
|
104
|
+
class WorkflowError extends ErrorBase<'WORKFLOW_FAILED' | 'STATE_INVALID'> {
|
|
105
|
+
constructor(name, message, state?: Record<string, unknown>) {
|
|
106
|
+
super(name, message, { state });
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
4. **Test Custom Error Properties**
|
|
112
|
+
```typescript
|
|
113
|
+
describe('CustomError', () => {
|
|
114
|
+
it('should capture state in error context', () => {
|
|
115
|
+
const state = { step: 'processing', data: { id: 123 } };
|
|
116
|
+
const error = new WorkflowError('WORKFLOW_FAILED', 'Process failed', state);
|
|
117
|
+
|
|
118
|
+
expect(error.name).toBe('WORKFLOW_FAILED');
|
|
119
|
+
expect(error.context).toEqual(state);
|
|
120
|
+
expect(error.context?.step).toBe('processing');
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it('should be identifiable by type guard', () => {
|
|
124
|
+
const error = new WorkflowError('STATE_INVALID', 'Invalid state');
|
|
125
|
+
const isWorkflowError = error instanceof WorkflowError;
|
|
126
|
+
|
|
127
|
+
expect(isWorkflowError).toBe(true);
|
|
128
|
+
expect(error.name).toBe('STATE_INVALID');
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## 3. Patterns for Testing Async Error Handling in Workflows
|
|
136
|
+
|
|
137
|
+
### Key Sources:
|
|
138
|
+
|
|
139
|
+
- **[The best way to handle errors in asynchronous JavaScript](https://medium.com/@m-mdy-m/the-best-way-to-handle-errors-in-asynchronous-javascript-16ce57a877d4)** - Async error patterns
|
|
140
|
+
- **[No more Try/Catch: a better way to handle errors in TypeScript](https://dev.to/noah-00/no-more-trycatch-a-better-way-to-handle-errors-in-typescript-5hbd)** - Alternative patterns (with community discussion)
|
|
141
|
+
- **[Error Handling in Workflows - Medusa Documentation](https://docs.medusajs.com/learn/fundamentals/workflows/errors)** - Workflow-specific error handling
|
|
142
|
+
|
|
143
|
+
### Best Practices:
|
|
144
|
+
|
|
145
|
+
1. **Use Result Types for Async Operations**
|
|
146
|
+
```typescript
|
|
147
|
+
type Result<T, E = Error> =
|
|
148
|
+
| { success: true; data: T }
|
|
149
|
+
| { success: false; error: E };
|
|
150
|
+
|
|
151
|
+
async function wrapAsync<T>(
|
|
152
|
+
promise: Promise<T>
|
|
153
|
+
): Promise<Result<T>> {
|
|
154
|
+
try {
|
|
155
|
+
const data = await promise;
|
|
156
|
+
return { success: true, data };
|
|
157
|
+
} catch (error) {
|
|
158
|
+
return { success: false, error: error as Error };
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Test
|
|
163
|
+
describe('async error handling', () => {
|
|
164
|
+
it('should capture errors in Result type', async () => {
|
|
165
|
+
const failingPromise = Promise.reject(new Error('Failed'));
|
|
166
|
+
const result = await wrapAsync(failingPromise);
|
|
167
|
+
|
|
168
|
+
if (!result.success) {
|
|
169
|
+
expect(result.error.message).toBe('Failed');
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
2. **Test Async Error State Transitions**
|
|
176
|
+
```typescript
|
|
177
|
+
describe('workflow error state', () => {
|
|
178
|
+
it('should capture state when workflow fails', async () => {
|
|
179
|
+
const workflow = new Workflow();
|
|
180
|
+
|
|
181
|
+
// Start workflow
|
|
182
|
+
await workflow.start();
|
|
183
|
+
|
|
184
|
+
// Capture initial state
|
|
185
|
+
const initialState = workflow.getState();
|
|
186
|
+
|
|
187
|
+
// Trigger error
|
|
188
|
+
await expect(workflow.executeStep('failing-step'))
|
|
189
|
+
.rejects.toThrow('Step failed');
|
|
190
|
+
|
|
191
|
+
// Verify error state was captured
|
|
192
|
+
const errorState = workflow.getState();
|
|
193
|
+
expect(errorState.error).toBeDefined();
|
|
194
|
+
expect(errorState.error?.step).toBe('failing-step');
|
|
195
|
+
expect(errorState.error?.previousState).toEqual(initialState);
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
3. **Use Promise.allSettled for Parallel Operations**
|
|
201
|
+
```typescript
|
|
202
|
+
// From dev.to article comments
|
|
203
|
+
async () => {
|
|
204
|
+
const myPromise = () => new Promise((resolve, reject) => {
|
|
205
|
+
setTimeout(() => {
|
|
206
|
+
resolve('Hello, world!');
|
|
207
|
+
}, 1000);
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
const [result] = await Promise.allSettled([myPromise()]);
|
|
211
|
+
|
|
212
|
+
if (result.status === 'rejected') {
|
|
213
|
+
console.error('Error:', result.reason);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
return result.status === 'fulfilled' ? result.value : undefined;
|
|
217
|
+
};
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## 4. Testing Decorator-Based State Capture
|
|
223
|
+
|
|
224
|
+
### Key Sources:
|
|
225
|
+
|
|
226
|
+
- **[Simplify Error Handling with TypeScript Decorators](https://stordahl.dev/writing/error-handling-decorators)** - Practical decorator pattern examples
|
|
227
|
+
- **[The power of TypeScript decorators: real cases](https://medium.com/@an.chmelev/the-power-of-typescript-decorators-real-cases-decorating-class-methods-c1496fed8a7)** - Real-world decorator use cases
|
|
228
|
+
- **[valjic1/catch-decorator-ts](https://github.com/valjic1/catch-decorator-ts)** - Library for exception handling decorators
|
|
229
|
+
|
|
230
|
+
### Best Practices:
|
|
231
|
+
|
|
232
|
+
1. **Use Decorator Factories for Error Handling**
|
|
233
|
+
```typescript
|
|
234
|
+
// From stordahl.dev
|
|
235
|
+
function wrapMethodFactory<
|
|
236
|
+
This,
|
|
237
|
+
Args extends unknown[],
|
|
238
|
+
Return,
|
|
239
|
+
Fn extends (this: This, ...args: Args) => Return
|
|
240
|
+
>(callback: (error: Error) => void) {
|
|
241
|
+
return function wrapMethod(
|
|
242
|
+
target: Fn,
|
|
243
|
+
context: ClassMethodDecoratorContext<This, Fn>
|
|
244
|
+
): (this: This, ...args: Args) => unknown {
|
|
245
|
+
return function replacementMethod(this: This, ...args: Args): Return | Promise<void> | void {
|
|
246
|
+
try {
|
|
247
|
+
return target.call(this, ...args);
|
|
248
|
+
} catch (error) {
|
|
249
|
+
callback(error as Error);
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function myCallback(error: Error) {
|
|
256
|
+
console.error(error);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
class ExampleClass {
|
|
260
|
+
@wrapMethodFactory(myCallback)
|
|
261
|
+
add(a: number, b: number): number {
|
|
262
|
+
return a + b;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
2. **Decorators That Capture State**
|
|
268
|
+
```typescript
|
|
269
|
+
function withErrorStateCapture<
|
|
270
|
+
This,
|
|
271
|
+
Args extends unknown[],
|
|
272
|
+
Return,
|
|
273
|
+
Fn extends (this: This, ...args: Args) => Return
|
|
274
|
+
>(
|
|
275
|
+
target: Fn,
|
|
276
|
+
context: ClassMethodDecoratorContext<This, Fn>
|
|
277
|
+
) {
|
|
278
|
+
return function replacementMethod(this: This, ...args: Args): Return | Promise<void> | void {
|
|
279
|
+
const result = target.call(this, ...args);
|
|
280
|
+
|
|
281
|
+
// Handle both sync and async
|
|
282
|
+
if (result instanceof Promise) {
|
|
283
|
+
return result.catch((error: Error) => {
|
|
284
|
+
// Capture current state
|
|
285
|
+
const currentState = (this as any).getState();
|
|
286
|
+
|
|
287
|
+
// Augment error with state
|
|
288
|
+
(error as any).state = {
|
|
289
|
+
captured: currentState,
|
|
290
|
+
method: String(context.name),
|
|
291
|
+
timestamp: new Date().toISOString()
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
throw error;
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
return result;
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// Test decorator
|
|
303
|
+
describe('withErrorStateCapture', () => {
|
|
304
|
+
it('should capture state when method fails', async () => {
|
|
305
|
+
class TestWorkflow {
|
|
306
|
+
private state = { step: 'initial', data: {} };
|
|
307
|
+
|
|
308
|
+
getState() {
|
|
309
|
+
return { ...this.state };
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
@withErrorStateCapture
|
|
313
|
+
async failingMethod() {
|
|
314
|
+
this.state.step = 'processing';
|
|
315
|
+
throw new Error('Method failed');
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
const workflow = new TestWorkflow();
|
|
320
|
+
|
|
321
|
+
await expect(workflow.failingMethod()).rejects.toThrow('Method failed');
|
|
322
|
+
|
|
323
|
+
// Verify state was captured
|
|
324
|
+
try {
|
|
325
|
+
await workflow.failingMethod();
|
|
326
|
+
} catch (error: any) {
|
|
327
|
+
expect(error.state).toBeDefined();
|
|
328
|
+
expect(error.state.captured.step).toBe('processing');
|
|
329
|
+
expect(error.state.method).toBe('failingMethod');
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
});
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
3. **Test Decorators Independently**
|
|
336
|
+
```typescript
|
|
337
|
+
describe('error handling decorator', () => {
|
|
338
|
+
let errorCallback: jest.Mock;
|
|
339
|
+
|
|
340
|
+
beforeEach(() => {
|
|
341
|
+
errorCallback = jest.fn();
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
it('should call error callback on sync error', () => {
|
|
345
|
+
class TestClass {
|
|
346
|
+
@wrapMethodFactory(errorCallback)
|
|
347
|
+
methodThatFails() {
|
|
348
|
+
throw new Error('Sync error');
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
const instance = new TestClass();
|
|
353
|
+
instance.methodThatFails();
|
|
354
|
+
|
|
355
|
+
expect(errorCallback).toHaveBeenCalledWith(
|
|
356
|
+
expect.objectContaining({ message: 'Sync error' })
|
|
357
|
+
);
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
it('should call error callback on async error', async () => {
|
|
361
|
+
class TestClass {
|
|
362
|
+
@wrapMethodFactory(errorCallback)
|
|
363
|
+
async asyncMethodThatFails() {
|
|
364
|
+
throw new Error('Async error');
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
const instance = new TestClass();
|
|
369
|
+
await instance.asyncMethodThatFails();
|
|
370
|
+
|
|
371
|
+
expect(errorCallback).toHaveBeenCalledWith(
|
|
372
|
+
expect.objectContaining({ message: 'Async error' })
|
|
373
|
+
);
|
|
374
|
+
});
|
|
375
|
+
});
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
---
|
|
379
|
+
|
|
380
|
+
## 5. Observability and Error Metadata Capture
|
|
381
|
+
|
|
382
|
+
### Key Sources:
|
|
383
|
+
|
|
384
|
+
- **[Workflow Observability: Finding and Resolving Failures Fast](https://www.prefect.io/blog/workflow-observability-finding-and-resolving-failures-fast)** - Observability best practices for workflows
|
|
385
|
+
- **[Node.js Error Handling: Techniques & Best Practices](https://www.site24x7.com/learn/nodejs-error-handling-guide.html)** - Error context capture patterns
|
|
386
|
+
- **[Data Workflow Orchestration: Core Concepts and Practical Guide](https://www.advsyscon.com/blog/data-workflow-orchestration/)** - Real-time monitoring and logging
|
|
387
|
+
|
|
388
|
+
### Best Practices:
|
|
389
|
+
|
|
390
|
+
1. **Capture Comprehensive Error Context**
|
|
391
|
+
```typescript
|
|
392
|
+
interface ErrorContext {
|
|
393
|
+
// Basic error info
|
|
394
|
+
message: string;
|
|
395
|
+
stack?: string;
|
|
396
|
+
code?: string;
|
|
397
|
+
|
|
398
|
+
// Workflow state
|
|
399
|
+
workflowId?: string;
|
|
400
|
+
step?: string;
|
|
401
|
+
state?: Record<string, unknown>;
|
|
402
|
+
|
|
403
|
+
// Request context
|
|
404
|
+
requestId?: string;
|
|
405
|
+
userId?: string;
|
|
406
|
+
correlationId?: string;
|
|
407
|
+
|
|
408
|
+
// System state
|
|
409
|
+
timestamp: string;
|
|
410
|
+
environment: string;
|
|
411
|
+
memoryUsage?: NodeJS.MemoryUsage;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
function captureErrorContext(error: Error, additionalContext?: Partial<ErrorContext>): ErrorContext {
|
|
415
|
+
return {
|
|
416
|
+
message: error.message,
|
|
417
|
+
stack: error.stack,
|
|
418
|
+
timestamp: new Date().toISOString(),
|
|
419
|
+
environment: process.env.NODE_ENV || 'unknown',
|
|
420
|
+
memoryUsage: process.memoryUsage(),
|
|
421
|
+
...additionalContext
|
|
422
|
+
};
|
|
423
|
+
}
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
2. **Test Error Context Capture**
|
|
427
|
+
```typescript
|
|
428
|
+
describe('error context capture', () => {
|
|
429
|
+
it('should capture complete error context', () => {
|
|
430
|
+
const originalError = new Error('Test error');
|
|
431
|
+
|
|
432
|
+
const context = captureErrorContext(originalError, {
|
|
433
|
+
workflowId: 'wf-123',
|
|
434
|
+
step: 'processing',
|
|
435
|
+
state: { data: 'test' }
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
expect(context).toMatchObject({
|
|
439
|
+
message: 'Test error',
|
|
440
|
+
workflowId: 'wf-123',
|
|
441
|
+
step: 'processing',
|
|
442
|
+
state: { data: 'test' },
|
|
443
|
+
timestamp: expect.any(String),
|
|
444
|
+
environment: expect.any(String)
|
|
445
|
+
});
|
|
446
|
+
|
|
447
|
+
expect(context.stack).toBeDefined();
|
|
448
|
+
expect(context.memoryUsage).toBeDefined();
|
|
449
|
+
});
|
|
450
|
+
});
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
3. **Use Structured Logging for Errors**
|
|
454
|
+
```typescript
|
|
455
|
+
interface Logger {
|
|
456
|
+
error(message: string, meta: Record<string, unknown>): void;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
function logWorkflowError(logger: Logger, error: Error, workflowState: Record<string, unknown>) {
|
|
460
|
+
logger.error('Workflow error', {
|
|
461
|
+
error: {
|
|
462
|
+
name: error.name,
|
|
463
|
+
message: error.message,
|
|
464
|
+
stack: error.stack
|
|
465
|
+
},
|
|
466
|
+
workflow: {
|
|
467
|
+
id: workflowState.id,
|
|
468
|
+
step: workflowState.currentStep,
|
|
469
|
+
state: workflowState
|
|
470
|
+
},
|
|
471
|
+
system: {
|
|
472
|
+
timestamp: new Date().toISOString(),
|
|
473
|
+
pid: process.pid
|
|
474
|
+
}
|
|
475
|
+
});
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
// Test
|
|
479
|
+
describe('structured error logging', () => {
|
|
480
|
+
it('should log error with workflow context', () => {
|
|
481
|
+
const logger = { error: jest.fn() };
|
|
482
|
+
const error = new Error('Workflow failed');
|
|
483
|
+
const state = { id: 'wf-123', currentStep: 'step-1', data: {} };
|
|
484
|
+
|
|
485
|
+
logWorkflowError(logger, error, state);
|
|
486
|
+
|
|
487
|
+
expect(logger.error).toHaveBeenCalledWith(
|
|
488
|
+
'Workflow error',
|
|
489
|
+
expect.objectContaining({
|
|
490
|
+
error: expect.objectContaining({
|
|
491
|
+
name: 'Error',
|
|
492
|
+
message: 'Workflow failed'
|
|
493
|
+
}),
|
|
494
|
+
workflow: expect.objectContaining({
|
|
495
|
+
id: 'wf-123',
|
|
496
|
+
step: 'step-1'
|
|
497
|
+
})
|
|
498
|
+
})
|
|
499
|
+
);
|
|
500
|
+
});
|
|
501
|
+
});
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
---
|
|
505
|
+
|
|
506
|
+
## 6. Common Pitfalls to Avoid
|
|
507
|
+
|
|
508
|
+
### From Community Sources:
|
|
509
|
+
|
|
510
|
+
1. **Don't Use `any` for Error Types**
|
|
511
|
+
- Source: [Convex TypeScript Guide](https://www.convex.dev/typescript/best-practices/error-handling-debugging/typescript-catch-error-type)
|
|
512
|
+
- Use `unknown` instead and narrow with type guards
|
|
513
|
+
|
|
514
|
+
2. **Don't Ignore Error State in Tests**
|
|
515
|
+
- Tests should verify not just that an error was thrown, but what state was captured
|
|
516
|
+
- Missing state can make debugging production issues nearly impossible
|
|
517
|
+
|
|
518
|
+
3. **Don't Mix Sync and Async Error Handling**
|
|
519
|
+
- Source: [dev.to discussion](https://dev.to/noah-00/no-more-trycatch-a-better-way-to-handle-errors-in-typescript-5hbd)
|
|
520
|
+
- Be consistent in your error handling patterns
|
|
521
|
+
|
|
522
|
+
4. **Don't Forget to Set Prototype for Custom Errors**
|
|
523
|
+
- Source: Multiple sources
|
|
524
|
+
- Always use `Object.setPrototypeOf(this, CustomError.prototype)` in constructors
|
|
525
|
+
|
|
526
|
+
5. **Don't Lose Context When Re-throwing**
|
|
527
|
+
```typescript
|
|
528
|
+
// Bad
|
|
529
|
+
try {
|
|
530
|
+
await operation();
|
|
531
|
+
} catch (error) {
|
|
532
|
+
throw new Error('Operation failed'); // Loses original error
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
// Good
|
|
536
|
+
try {
|
|
537
|
+
await operation();
|
|
538
|
+
} catch (error) {
|
|
539
|
+
const newError = new Error('Operation failed');
|
|
540
|
+
(newError as any).cause = error; // Preserve original error
|
|
541
|
+
(newError as any).context = { state: currentState };
|
|
542
|
+
throw newError;
|
|
543
|
+
}
|
|
544
|
+
```
|
|
545
|
+
|
|
546
|
+
6. **Don't Test Error Messages, Test Error Types**
|
|
547
|
+
```typescript
|
|
548
|
+
// Bad - brittle
|
|
549
|
+
expect(error.message).toBe('Something went wrong');
|
|
550
|
+
|
|
551
|
+
// Good - resilient
|
|
552
|
+
expect(error).toBeInstanceOf(WorkflowError);
|
|
553
|
+
expect(error.name).toBe('WORKFLOW_FAILED');
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
---
|
|
557
|
+
|
|
558
|
+
## 7. Testing Checklist
|
|
559
|
+
|
|
560
|
+
Based on the research, here's a checklist for testing workflow error state capture:
|
|
561
|
+
|
|
562
|
+
- [ ] Error objects contain custom properties (state, context, metadata)
|
|
563
|
+
- [ ] Custom error types are properly identified (instanceof checks)
|
|
564
|
+
- [ ] Type guards correctly narrow error types
|
|
565
|
+
- [ ] Async errors are captured and typed correctly
|
|
566
|
+
- [ ] Error state is captured at failure points
|
|
567
|
+
- [ ] Decorators capture state when errors occur
|
|
568
|
+
- [ ] Error context includes workflow state (step, data, id)
|
|
569
|
+
- [ ] Error context includes system state (timestamp, environment)
|
|
570
|
+
- [ ] Stack traces are preserved
|
|
571
|
+
- [ ] Original errors are preserved when wrapping
|
|
572
|
+
- [ ] Errors are logged with structured data
|
|
573
|
+
- [ ] Tests verify error properties, not just messages
|
|
574
|
+
- [ ] Both sync and async error paths are tested
|
|
575
|
+
- [ ] Error state is serializable (for logging/transmission)
|
|
576
|
+
|
|
577
|
+
---
|
|
578
|
+
|
|
579
|
+
## 8. Recommended Testing Libraries
|
|
580
|
+
|
|
581
|
+
Based on the research:
|
|
582
|
+
|
|
583
|
+
- **Jest** - Standard testing framework with good error matching
|
|
584
|
+
- **ts-custom-error** - For creating custom errors that work well with TypeScript
|
|
585
|
+
- **fp-ts** - For Result/Either patterns if you prefer functional error handling
|
|
586
|
+
- **Temporal TypeScript SDK** - Reference implementation for workflow error handling
|
|
587
|
+
|
|
588
|
+
---
|
|
589
|
+
|
|
590
|
+
## Sources Summary
|
|
591
|
+
|
|
592
|
+
### Documentation & Guides:
|
|
593
|
+
1. [Temporal TypeScript SDK - Failure Detection](https://docs.temporal.io/develop/typescript/failure-detection)
|
|
594
|
+
2. [Temporal TypeScript SDK - Observability](https://docs.temporal.io/develop/typescript/observability)
|
|
595
|
+
3. [TypeScript Error Type Handling - Convex](https://www.convex.dev/typescript/best-practices/error-handling-debugging/typescript-catch-error-type)
|
|
596
|
+
4. [Error Handling in Workflows - Medusa](https://docs.medusajs.com/learn/fundamentals/workflows/errors)
|
|
597
|
+
|
|
598
|
+
### Articles & Blog Posts:
|
|
599
|
+
5. [Simplify Error Handling with TypeScript Decorators](https://stordahl.dev/writing/error-handling-decorators)
|
|
600
|
+
6. [Handling errors like a pro in TypeScript - Udacity](https://engineering.udacity.com/handling-errors-like-a-pro-in-typescript-d7a314ad4991)
|
|
601
|
+
7. [No more Try/Catch: a better way to handle errors - DEV.to](https://dev.to/noah-00/no-more-trycatch-a-better-way-to-handle-errors-in-typescript-5hbd)
|
|
602
|
+
8. [Workflow Orchestration: Building Complex AI Pipelines](https://medium.com/@omark.k.aly/workflow-orchestration-building-complex-ai-pipelines-c8504ab8306f)
|
|
603
|
+
9. [Workflow Observability - Prefect](https://www.prefect.io/blog/workflow-observability-finding-and-resolving-failures-fast)
|
|
604
|
+
10. [Data Workflow Orchestration Guide](https://www.advsyscon.com/blog/data-workflow-orchestration/)
|
|
605
|
+
11. [Node.js Error Handling Guide](https://www.site24x7.com/learn/nodejs-error-handling-guide.html)
|
|
606
|
+
|
|
607
|
+
### Libraries & Tools:
|
|
608
|
+
12. [ts-custom-error npm package](https://www.npmjs.com/package/ts-custom-error)
|
|
609
|
+
13. [catch-decorator-ts GitHub](https://github.com/valjic1/catch-decorator-ts)
|
|
610
|
+
14. [temporalio/samples-typescript GitHub](https://github.com/temporalio/samples-typescript)
|
|
611
|
+
15. [hotmeshio/temporal-patterns-typescript GitHub](https://github.com/hotmeshio/temporal-patterns-typescript)
|
|
612
|
+
|
|
613
|
+
### Community Discussions:
|
|
614
|
+
16. [StackOverflow: Add properties to JavaScript Error object](https://stackoverflow.com/questions/47248741/add-properties-to-javascript-error-object)
|
|
615
|
+
|
|
616
|
+
---
|
|
617
|
+
|
|
618
|
+
*Research conducted: January 11, 2026*
|
|
619
|
+
*Last updated: January 11, 2026*
|