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.
Files changed (242) hide show
  1. package/.claude/commands/subtask-planning/prp-base-create.md +120 -0
  2. package/.claude/commands/subtask-planning/prp-base-execute.md +65 -0
  3. package/.claude/commands/task-breakdown.md +94 -0
  4. package/.claude/system_prompts/task-breakdown.md +1 -0
  5. package/CHANGELOG.md +188 -0
  6. package/PRD.md +543 -0
  7. package/README.md +99 -5
  8. package/examples/README.md +15 -1
  9. package/examples/examples/11-reparenting-workflows.ts +269 -0
  10. package/examples/index.ts +4 -0
  11. package/package-lock.json +2398 -0
  12. package/package.json +3 -1
  13. package/plan/001_d3bb02af4886/TEST_RESULTS.md +259 -0
  14. package/plan/001_d3bb02af4886/bug_fix_tasks.json +484 -0
  15. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M1T1S1/PRP.md +488 -0
  16. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M1T1S2/PRP.md +581 -0
  17. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M1T1S3/PRP.md +687 -0
  18. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T1S1/PRP.md +492 -0
  19. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T1S3/PRP.md +932 -0
  20. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T1S3/research/concurrent_error_testing_patterns.md +1109 -0
  21. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T1S3/research/vitest_concurrent_testing.md +802 -0
  22. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T1S3/research/workflow_engine_test_references.md +603 -0
  23. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T2S1/PRP.md +564 -0
  24. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T2S3/PRP.md +518 -0
  25. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T2S4/PRP.md +1252 -0
  26. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T3S1/PRP.md +364 -0
  27. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T3S1/research/CODEBASE_INVENTORY.md +114 -0
  28. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T3S1/research/DECORATOR_DOCUMENTATION_PATTERNS.md +205 -0
  29. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T3S1/research/PRD_LOCATION_ANALYSIS.md +199 -0
  30. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T3S1/research/ULTRATHINK_PRP_PLAN.md +134 -0
  31. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T1S1/PRP.md +495 -0
  32. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T1S1/research/console_error_inventory.md +435 -0
  33. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T1S2/PRP.md +506 -0
  34. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T1S3/PRP.md +612 -0
  35. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T2S2/PRP.md +558 -0
  36. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T2S2/research/external_research.md +788 -0
  37. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T3S2/PRP.md +460 -0
  38. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T3S3/PRP.md +454 -0
  39. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T4S1/PRP.md +520 -0
  40. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T4S1/RECOMMENDATION.md +417 -0
  41. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T4S1/research/external_workflow_engines_research.md +760 -0
  42. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T4S1/research/security_implications_analysis.md +245 -0
  43. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T4S2/PRP.md +792 -0
  44. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S1/PRP.md +535 -0
  45. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S1/TEST_EXECUTION_REPORT.md +190 -0
  46. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S2/PRP.md +654 -0
  47. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S2/TEST_FIX_REPORT.md +227 -0
  48. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S2/research/KEY_FINDINGS.md +345 -0
  49. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S2/research/QUICK_REFERENCE.md +193 -0
  50. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S2/research/test_maintenance_research.md +1323 -0
  51. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T3S1/BREAKING_CHANGES_AUDIT.md +1011 -0
  52. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T3S1/PRP.md +927 -0
  53. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T3S2/PRP.md +505 -0
  54. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/architecture/logger_child_signature_analysis.md +401 -0
  55. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S3/child_implementation_research.md +142 -0
  56. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S3/test_patterns_research.md +112 -0
  57. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S3/vitest_patterns_research.md +159 -0
  58. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S4/PRP.md +549 -0
  59. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S4/VERIFICATION_REPORT.md +368 -0
  60. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S4/edge_case_analysis.md +172 -0
  61. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S4/usage_inventory.md +175 -0
  62. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T1S2/PRP.md +696 -0
  63. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T1S4/PRP.md +860 -0
  64. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/PRP.md +1066 -0
  65. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/01-testing-aggregated-errors.md +1103 -0
  66. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/01_typescript_error_aggregation_patterns.md +789 -0
  67. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/02-error-merge-strategy-testing-guide.md +1098 -0
  68. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/02_aggregate_error_patterns.md +1037 -0
  69. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/03-promise-allsettled-testing-patterns.md +916 -0
  70. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/03_error_merging_strategies.md +1045 -0
  71. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/04_github_stackoverflow_examples.md +890 -0
  72. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/05_comprehensive_summary.md +822 -0
  73. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/INDEX.md +668 -0
  74. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/QUICK_REFERENCE.md +706 -0
  75. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/README.md +265 -0
  76. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/RESEARCH_REPORT.md +655 -0
  77. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S4/research/vitest_testing_patterns.md +1103 -0
  78. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T3S2/PRP.md +426 -0
  79. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T1S2/PRP.md +506 -0
  80. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T1S2/research/QUICK_REFERENCE.md +114 -0
  81. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T1S2/research/RESEARCH_SUMMARY.md +316 -0
  82. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T1S2/research/vitest_observer_error_logging_best_practices.md +754 -0
  83. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T1S3/PRP.md +612 -0
  84. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T2S1/PRP.md +719 -0
  85. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T2S1/README.md +215 -0
  86. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T2S1/analysis.md +765 -0
  87. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T2S3/PRP.md +718 -0
  88. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T3S1/DECISION.md +149 -0
  89. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T3S1/PRP.md +470 -0
  90. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T3S1/research/ULTRATHINK_PLAN.md +332 -0
  91. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T3S1/research/codebase_workflow_name_analysis.md +167 -0
  92. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T3S1/research/external_best_practices.md +265 -0
  93. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T3S1/research/validation_patterns.md +273 -0
  94. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T4S1/workflow_engine_ancestry_api_research.md +760 -0
  95. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T4S3-PRP.md +434 -0
  96. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M4T2S1/PRP.md +717 -0
  97. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M4T2S2/PRP.md +472 -0
  98. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M4T2S2/VALIDATION_REPORT.md +125 -0
  99. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M4T2S2/research/ULTRATHINK_PRP_PLAN.md +301 -0
  100. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/error-logging-best-practices.md +1170 -0
  101. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/research_typescript_partial_and_overloads.md +940 -0
  102. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/vitest-quick-reference.md +151 -0
  103. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/vitest-research.md +650 -0
  104. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/prd_snapshot.md +259 -0
  105. package/plan/001_d3bb02af4886/bugfix/P1M1T1S1/PRP.md +457 -0
  106. package/plan/001_d3bb02af4886/bugfix/RESEARCH_SUMMARY.md +346 -0
  107. package/plan/001_d3bb02af4886/bugfix/architecture/codebase_structure.md +311 -0
  108. package/plan/001_d3bb02af4886/bugfix/architecture/concurrent_execution_best_practices.md +1565 -0
  109. package/plan/001_d3bb02af4886/bugfix/architecture/error_handling_patterns.md +288 -0
  110. package/plan/001_d3bb02af4886/bugfix/architecture/promise_all_analysis.md +741 -0
  111. package/plan/001_d3bb02af4886/docs/PRP/P1M1T1S4-functional-workflow-error-state-capture-test.md +652 -0
  112. package/plan/001_d3bb02af4886/docs/PRP/PRP.md +527 -0
  113. package/plan/001_d3bb02af4886/docs/PRP/bugfix/P1M1T2S1-PRP.md +415 -0
  114. package/plan/001_d3bb02af4886/docs/PRP/bugfix/P1M1T2S2-PRP.md +378 -0
  115. package/plan/001_d3bb02af4886/docs/PRP/bugfix/P1M1T2S4-PRP.md +713 -0
  116. package/plan/001_d3bb02af4886/docs/PRP/bugfix/P1M2T1S4-PRP.md +370 -0
  117. package/plan/001_d3bb02af4886/docs/PRP_P1M3T1S3.md +499 -0
  118. package/plan/001_d3bb02af4886/docs/TEST_RESULTS.md +230 -0
  119. package/plan/001_d3bb02af4886/docs/bugfix/ANALYSIS_PRD_VS_IMPLEMENTATION.md +1134 -0
  120. package/plan/001_d3bb02af4886/docs/bugfix/GAP_ANALYSIS_SUMMARY.md +179 -0
  121. package/plan/001_d3bb02af4886/docs/bugfix/P1M4T2S1/PRP.md +629 -0
  122. package/plan/001_d3bb02af4886/docs/bugfix/P1M4T2S1/validation-report.md +214 -0
  123. package/plan/001_d3bb02af4886/docs/bugfix/PRP_P1M4T2S3.md +629 -0
  124. package/plan/001_d3bb02af4886/docs/bugfix/bugfix_PRP.md +529 -0
  125. package/plan/001_d3bb02af4886/docs/bugfix/bugfix_QUICK_REFERENCE.md +142 -0
  126. package/plan/001_d3bb02af4886/docs/bugfix/bugfix_README.md +304 -0
  127. package/plan/001_d3bb02af4886/docs/bugfix/bugfix_TEST_RESULTS.md +558 -0
  128. package/plan/001_d3bb02af4886/docs/bugfix/bugfix_VALIDATION_SUMMARY.md +256 -0
  129. package/plan/001_d3bb02af4886/docs/bugfix/system_context.md +346 -0
  130. package/plan/001_d3bb02af4886/docs/bugfix-architecture/bug_analysis.md +415 -0
  131. package/plan/001_d3bb02af4886/docs/bugfix-architecture/implementation_patterns.md +489 -0
  132. package/plan/001_d3bb02af4886/docs/bugfix-architecture/system_context.md +218 -0
  133. package/plan/001_d3bb02af4886/docs/bugfix_INITIATION_SUMMARY.md +380 -0
  134. package/plan/001_d3bb02af4886/docs/research/CYCLE_DETECTION_PATTERNS.md +1923 -0
  135. package/plan/001_d3bb02af4886/docs/research/CYCLE_DETECTION_QUICK_REF.md +319 -0
  136. package/plan/001_d3bb02af4886/docs/research/P1M1T2S1/codebase-context.md +115 -0
  137. package/plan/001_d3bb02af4886/docs/research/P1M1T2S1/cycle-detection-algorithms.md +134 -0
  138. package/plan/001_d3bb02af4886/docs/research/P1M1T2S1/test-patterns.md +153 -0
  139. package/plan/001_d3bb02af4886/docs/research/P1M1T2S1/workflow-class.md +132 -0
  140. package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/DECORATOR_DOCUMENTATION_BEST_PRACTICES.md +716 -0
  141. package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/DECORATOR_DOCUMENTATION_QUICK_REF.md +186 -0
  142. package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/GROUNDSWELL_DECORATOR_EXAMPLES.md +604 -0
  143. package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/INDEX.md +213 -0
  144. package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/codebase_structure.md +30 -0
  145. package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/existing_test_pattern.md +56 -0
  146. package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/getRootObservers_implementation.md +53 -0
  147. package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/test_conventions.md +49 -0
  148. package/plan/001_d3bb02af4886/docs/research/P1M3T1S4/PRP.md +958 -0
  149. package/plan/001_d3bb02af4886/docs/research/P1M3T1S4/QUICK_REFERENCE.md +339 -0
  150. package/plan/001_d3bb02af4886/docs/research/P1M3T1S4/README.md +305 -0
  151. package/plan/001_d3bb02af4886/docs/research/P1M3T1S4/SUMMARY.md +433 -0
  152. package/plan/001_d3bb02af4886/docs/research/P1M3T1S4/bidirectional-tree-consistency-testing.md +1574 -0
  153. package/plan/001_d3bb02af4886/docs/research/P1M3T1S4/test-pattern-examples.md +1014 -0
  154. package/plan/001_d3bb02af4886/docs/research/PROMISE_ALLSETTLED_QUICK_REF.md +376 -0
  155. package/plan/001_d3bb02af4886/docs/research/PROMISE_ALLSETTLED_RESEARCH.md +1507 -0
  156. package/plan/001_d3bb02af4886/docs/research/bugfix_typescript_patterns.md +949 -0
  157. package/plan/001_d3bb02af4886/docs/research/error-testing-research.md +619 -0
  158. package/plan/001_d3bb02af4886/docs/research/error_handling_patterns.md +723 -0
  159. package/plan/{research → 001_d3bb02af4886/docs/research/general}/introspection-security-guide.md +56 -0
  160. package/plan/001_d3bb02af4886/docs/research/incremental-tree-map-updates/PRP_TEMPLATE.md +460 -0
  161. package/plan/001_d3bb02af4886/docs/research/incremental-tree-map-updates/QUICK_REFERENCE.md +324 -0
  162. package/plan/001_d3bb02af4886/docs/research/incremental-tree-map-updates/README.md +175 -0
  163. package/plan/001_d3bb02af4886/docs/research/incremental-tree-map-updates/RESEARCH_REPORT.md +499 -0
  164. package/plan/001_d3bb02af4886/docs/research/incremental-tree-map-updates/SUMMARY.md +163 -0
  165. package/plan/bugfix/BUG_FIX_SUMMARY.md +961 -0
  166. package/src/__tests__/adversarial/attachChild-performance.test.ts +216 -0
  167. package/src/__tests__/adversarial/circular-reference.test.ts +101 -0
  168. package/src/__tests__/adversarial/complex-circular-reference.test.ts +139 -0
  169. package/src/__tests__/adversarial/concurrent-task-failures.test.ts +571 -0
  170. package/src/__tests__/adversarial/deep-analysis.test.ts +729 -0
  171. package/src/__tests__/adversarial/deep-hierarchy-stress.test.ts +213 -0
  172. package/src/__tests__/adversarial/e2e-prd-validation.test.ts +448 -0
  173. package/src/__tests__/adversarial/edge-case.test.ts +703 -0
  174. package/src/__tests__/adversarial/error-merge-strategy.test.ts +760 -0
  175. package/src/__tests__/adversarial/incremental-performance.test.ts +140 -0
  176. package/src/__tests__/adversarial/node-map-update-benchmarks.test.ts +457 -0
  177. package/src/__tests__/adversarial/observer-propagation.test.ts +487 -0
  178. package/src/__tests__/adversarial/parent-validation.test.ts +143 -0
  179. package/src/__tests__/adversarial/prd-12-2-compliance.test.ts +611 -0
  180. package/src/__tests__/adversarial/prd-compliance.test.ts +731 -0
  181. package/src/__tests__/compatibility/backward-compatibility.test.ts +1572 -0
  182. package/src/__tests__/helpers/index.ts +18 -0
  183. package/src/__tests__/helpers/tree-verification.ts +257 -0
  184. package/src/__tests__/integration/bidirectional-consistency.test.ts +847 -0
  185. package/src/__tests__/integration/observer-logging.test.ts +643 -0
  186. package/src/__tests__/integration/tree-mirroring.test.ts +37 -0
  187. package/src/__tests__/integration/workflow-reparenting.test.ts +303 -0
  188. package/src/__tests__/unit/context.test.ts +79 -0
  189. package/src/__tests__/unit/logger.test.ts +293 -0
  190. package/src/__tests__/unit/observable.test.ts +321 -0
  191. package/src/__tests__/unit/tree-debugger-incremental.test.ts +170 -0
  192. package/src/__tests__/unit/utils/workflow-error-utils.test.ts +209 -0
  193. package/src/__tests__/unit/workflow-detachChild.test.ts +100 -0
  194. package/src/__tests__/unit/workflow-emitEvent-childDetached.test.ts +153 -0
  195. package/src/__tests__/unit/workflow-isDescendantOf.test.ts +180 -0
  196. package/src/__tests__/unit/workflow.test.ts +277 -1
  197. package/src/core/agent.ts +21 -1
  198. package/src/core/logger.ts +27 -2
  199. package/src/core/workflow-context.ts +6 -4
  200. package/src/core/workflow.ts +252 -14
  201. package/src/debugger/tree-debugger.ts +52 -7
  202. package/src/decorators/task.ts +65 -2
  203. package/src/index.ts +4 -2
  204. package/src/types/decorators.ts +8 -1
  205. package/src/types/events.ts +1 -0
  206. package/src/utils/index.ts +1 -0
  207. package/src/utils/observable.ts +32 -3
  208. package/src/utils/workflow-error-utils.ts +56 -0
  209. package/tsconfig.json +1 -1
  210. package/llms_full.txt +0 -5890
  211. package/tasks.json +0 -0
  212. /package/plan/{backlog.json → 001_d3bb02af4886/backlog.json} +0 -0
  213. /package/plan/{P1P2/PRP.md → 001_d3bb02af4886/docs/PRP/P1P2-PRP.md} +0 -0
  214. /package/plan/{P3P4/PRP.md → 001_d3bb02af4886/docs/PRP/P3P4-PRP.md} +0 -0
  215. /package/plan/{P4P5/PRP.md → 001_d3bb02af4886/docs/PRP/P4P5-PRP.md} +0 -0
  216. /package/plan/{architecture → 001_d3bb02af4886/docs/architecture}/external_deps.md +0 -0
  217. /package/plan/{architecture → 001_d3bb02af4886/docs/architecture}/system_context.md +0 -0
  218. /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/LRU_CACHE_BEST_PRACTICES.md +0 -0
  219. /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/LRU_CACHE_CODE_PATTERNS.md +0 -0
  220. /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/LRU_CACHE_INTEGRATION_GUIDE.md +0 -0
  221. /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/LRU_CACHE_RESEARCH_INDEX.md +0 -0
  222. /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/REFLECTION_INDEX.md +0 -0
  223. /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/REFLECTION_RESEARCH_REPORT.md +0 -0
  224. /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/RESEARCH_SUMMARY.md +0 -0
  225. /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/anthropic-sdk.md +0 -0
  226. /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/async-local-storage.md +0 -0
  227. /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/reflection-code-patterns.md +0 -0
  228. /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/reflection-decision-matrix.md +0 -0
  229. /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/reflection-implementation-guide.md +0 -0
  230. /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/reflection-integration-guide.md +0 -0
  231. /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/reflection-patterns.md +0 -0
  232. /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/reflection-quick-reference.md +0 -0
  233. /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/zod-schema.md +0 -0
  234. /package/plan/{P3P4/research → 001_d3bb02af4886/docs/research/P3P4}/caching-lru.md +0 -0
  235. /package/plan/{P3P4/research → 001_d3bb02af4886/docs/research/P3P4}/introspection-tools.md +0 -0
  236. /package/plan/{P3P4/research → 001_d3bb02af4886/docs/research/P3P4}/reflection-patterns.md +0 -0
  237. /package/plan/{P4P5/research → 001_d3bb02af4886/docs/research/P4P5}/RESEARCH_SUMMARY.md +0 -0
  238. /package/plan/{research → 001_d3bb02af4886/docs/research/general}/INTROSPECTION_RESEARCH_SUMMARY.md +0 -0
  239. /package/plan/{research → 001_d3bb02af4886/docs/research/general}/README-INTROSPECTION.md +0 -0
  240. /package/plan/{research → 001_d3bb02af4886/docs/research/general}/agent-introspection-patterns.md +0 -0
  241. /package/plan/{research → 001_d3bb02af4886/docs/research/general}/introspection-tool-examples.md +0 -0
  242. /package/{PRPs/PRDs/001-hierarchical-workflow-engine.md → plan/001_d3bb02af4886/prd_snapshot.md} +0 -0
@@ -0,0 +1,754 @@
1
+ # Vitest Best Practices for Testing Observer Error Logging
2
+
3
+ **Research Date:** 2026-01-12
4
+ **Task:** Research external best practices for testing observer error logging with vitest
5
+ **Status:** Complete
6
+
7
+ ---
8
+
9
+ ## Executive Summary
10
+
11
+ This research document compiles best practices for testing observer error logging patterns using Vitest, including:
12
+
13
+ 1. Mocking and verifying logger usage (not console output)
14
+ 2. Testing that errors don't crash execution
15
+ 3. Testing observer pattern error handling
16
+ 4. Verifying error context in logs
17
+ 5. Official Vitest documentation with section anchors
18
+
19
+ ---
20
+
21
+ ## 1. Official Vitest Documentation URLs
22
+
23
+ ### Core Documentation
24
+
25
+ | Resource | URL | Key Sections |
26
+ |----------|-----|--------------|
27
+ | **Vitest Main Docs** | https://vitest.dev/ | Overview, getting started |
28
+ | **Assertions API** | https://vitest.dev/api/expect.html | `toThrow()`, `toHaveBeenCalledWith()`, `objectContaining()` |
29
+ | **Mocking Guide** | https://vitest.dev/guide/mocking.html | `vi.fn()`, `vi.spyOn()`, mock implementations |
30
+ | **Async Testing** | https://vitest.dev/guide/async.html | `.resolves`, `.rejects` modifiers |
31
+ | **Test Context** | https://vitest.dev/api/context.html | `beforeEach()`, `afterEach()` setup |
32
+ | **Mock Functions** | https://vitest.dev/api/mock.html | Mock function APIs and expectations |
33
+
34
+ ### Section-Specific Anchors
35
+
36
+ **Error Testing Assertions:**
37
+ - `toThrow()`: https://vitest.dev/api/expect.html#tothrow
38
+ - `.resolves` / `.rejects`: https://vitest.dev/api/expect.html#resolves
39
+ - Custom matchers: https://vitest.dev/api/expect.html#objectcontaining
40
+
41
+ **Mocking Patterns:**
42
+ - `vi.spyOn()`: https://vitest.dev/guide/mocking.html#spy-on
43
+ - `vi.fn()`: https://vitest.dev/guide/mocking.html#mock-functions
44
+ - Mock restoration: https://vitest.dev/guide/mocking.html#restoring-mocks
45
+
46
+ ---
47
+
48
+ ## 2. Mocking Logger in Vitest (Not Console Output)
49
+
50
+ ### Pattern 1: Mock Logger Interface
51
+
52
+ **Best Practice:** Create a logger interface and mock it, rather than spying on `console.error`.
53
+
54
+ ```typescript
55
+ // Logger interface
56
+ export interface ObservableLogger {
57
+ error(message: string, data?: unknown): void;
58
+ }
59
+
60
+ // Test with mock logger
61
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
62
+
63
+ describe('Observable error logging', () => {
64
+ let mockLogger: ObservableLogger;
65
+
66
+ beforeEach(() => {
67
+ mockLogger = {
68
+ error: vi.fn(),
69
+ };
70
+ });
71
+
72
+ it('should log subscriber errors via logger', () => {
73
+ const observable = new Observable<number>(mockLogger);
74
+ const testError = new Error('Next error');
75
+
76
+ const throwingSubscriber = {
77
+ next: () => {
78
+ throw testError;
79
+ },
80
+ };
81
+
82
+ observable.subscribe(throwingSubscriber);
83
+ observable.next(42);
84
+
85
+ // Verify logger was called (not console)
86
+ expect(mockLogger.error).toHaveBeenCalledWith('Observable subscriber error', {
87
+ error: testError,
88
+ });
89
+ });
90
+ });
91
+ ```
92
+
93
+ **Source:** `/home/dustin/projects/groundswell/src/__tests__/unit/observable.test.ts` (lines 14-30)
94
+
95
+ ### Pattern 2: Verify Logger Call Count and Arguments
96
+
97
+ ```typescript
98
+ it('should log errors for multiple throwing subscribers', () => {
99
+ const observable = new Observable<number>(mockLogger);
100
+ const error1 = new Error('Error 1');
101
+ const error2 = new Error('Error 2');
102
+
103
+ const throwingSubscriber1 = { next: () => { throw error1; } };
104
+ const throwingSubscriber2 = { next: () => { throw error2; } };
105
+
106
+ observable.subscribe(throwingSubscriber1);
107
+ observable.subscribe(throwingSubscriber2);
108
+ observable.next(42);
109
+
110
+ // Verify call count
111
+ expect(mockLogger.error).toHaveBeenCalledTimes(2);
112
+
113
+ // Verify specific calls
114
+ expect(mockLogger.error).toHaveBeenNthCalledWith(1, 'Observable subscriber error', {
115
+ error: error1,
116
+ });
117
+ expect(mockLogger.error).toHaveBeenNthCalledWith(2, 'Observable subscriber error', {
118
+ error: error2,
119
+ });
120
+ });
121
+ ```
122
+
123
+ **Source:** `/home/dustin/projects/groundswell/src/__tests__/unit/observable.test.ts` (lines 95-123)
124
+
125
+ ### Pattern 3: Console Fallback Testing
126
+
127
+ When testing fallback to `console.error`, use `vi.spyOn()`:
128
+
129
+ ```typescript
130
+ it('should fall back to console.error when no logger provided', () => {
131
+ const consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
132
+ const observable = new Observable<number>();
133
+ const testError = new Error('Next error');
134
+
135
+ const throwingSubscriber = { next: () => { throw testError; } };
136
+
137
+ observable.subscribe(throwingSubscriber);
138
+ observable.next(42);
139
+
140
+ expect(consoleErrorSpy).toHaveBeenCalledWith('Observable subscriber error', testError);
141
+ consoleErrorSpy.mockRestore();
142
+ });
143
+ ```
144
+
145
+ **Source:** `/home/dustin/projects/groundswell/src/__tests__/unit/observable.test.ts` (lines 127-143)
146
+
147
+ ---
148
+
149
+ ## 3. Testing Errors Don't Crash Execution
150
+
151
+ ### Pattern 1: Error Isolation Tests
152
+
153
+ **Best Practice:** Verify that observer errors are caught and logged, not propagated.
154
+
155
+ ```typescript
156
+ describe('Error isolation', () => {
157
+ let mockLogger: ObservableLogger;
158
+
159
+ beforeEach(() => {
160
+ mockLogger = { error: vi.fn() };
161
+ });
162
+
163
+ it('should not propagate errors outside try-catch', () => {
164
+ const observable = new Observable<number>(mockLogger);
165
+ const testError = new Error('Subscriber error');
166
+
167
+ const throwingSubscriber = { next: () => { throw testError; } };
168
+
169
+ observable.subscribe(throwingSubscriber);
170
+
171
+ // This should NOT throw
172
+ expect(() => {
173
+ observable.next(42);
174
+ }).not.toThrow();
175
+
176
+ // But error should be logged
177
+ expect(mockLogger.error).toHaveBeenCalled();
178
+ });
179
+ });
180
+ ```
181
+
182
+ **Source:** `/home/dustin/projects/groundswell/src/__tests__/unit/observable.test.ts` (lines 252-279)
183
+
184
+ ### Pattern 2: Continue Notifying Other Observers
185
+
186
+ ```typescript
187
+ it('should continue notifying other subscribers after one throws', () => {
188
+ const observable = new Observable<number>(mockLogger);
189
+ const testError = new Error('First subscriber error');
190
+ const results: number[] = [];
191
+
192
+ const throwingSubscriber = { next: () => { throw testError; } };
193
+
194
+ const workingSubscriber = {
195
+ next: (value: number) => {
196
+ results.push(value);
197
+ },
198
+ };
199
+
200
+ observable.subscribe(throwingSubscriber);
201
+ observable.subscribe(workingSubscriber);
202
+ observable.next(42);
203
+
204
+ // Verify working subscriber received value
205
+ expect(results).toEqual([42]);
206
+ // Verify error was logged
207
+ expect(mockLogger.error).toHaveBeenCalled();
208
+ });
209
+ ```
210
+
211
+ **Source:** `/home/dustin/projects/groundswell/src/__tests__/unit/observable.test.ts` (lines 69-93)
212
+
213
+ ### Pattern 3: Workflow Observer Error Isolation
214
+
215
+ ```typescript
216
+ it('should not crash workflow when observer onLog throws', async () => {
217
+ const throwingObserver: WorkflowObserver = {
218
+ onLog: () => {
219
+ throw new Error('Observer onLog error');
220
+ },
221
+ onEvent: () => {},
222
+ onStateUpdated: () => {},
223
+ onTreeChanged: () => {},
224
+ };
225
+
226
+ class TestWorkflow extends Workflow {
227
+ async run() {
228
+ this.logger.info('Message 1');
229
+ this.logger.info('Message 2');
230
+ this.logger.info('Message 3');
231
+ }
232
+ }
233
+
234
+ const workflow = new TestWorkflow();
235
+ workflow.addObserver(throwingObserver);
236
+
237
+ // Should complete without throwing
238
+ await expect(workflow.run()).resolves.toBeUndefined();
239
+
240
+ // All messages should be logged
241
+ expect(workflow.node.logs.length).toBe(6); // 3 messages + 3 error logs
242
+ });
243
+ ```
244
+
245
+ **Source:** `/home/dustin/projects/groundswell/src/__tests__/integration/observer-logging.test.ts` (lines 242-268)
246
+
247
+ ---
248
+
249
+ ## 4. Testing Observer Pattern Error Handling
250
+
251
+ ### Pattern 1: Multiple Observers with Some Failing
252
+
253
+ ```typescript
254
+ it('should continue notifying other observers after one throws', async () => {
255
+ let observer2Called = false;
256
+ let observer3Called = false;
257
+
258
+ const throwingObserver: WorkflowObserver = {
259
+ onLog: () => {
260
+ throw new Error('Observer 1 failed');
261
+ },
262
+ onEvent: () => {},
263
+ onStateUpdated: () => {},
264
+ onTreeChanged: () => {},
265
+ };
266
+
267
+ const workingObserver2: WorkflowObserver = {
268
+ onLog: () => {
269
+ observer2Called = true;
270
+ },
271
+ onEvent: () => {},
272
+ onStateUpdated: () => {},
273
+ onTreeChanged: () => {},
274
+ };
275
+
276
+ const workingObserver3: WorkflowObserver = {
277
+ onLog: () => {
278
+ observer3Called = true;
279
+ },
280
+ onEvent: () => {},
281
+ onStateUpdated: () => {},
282
+ onTreeChanged: () => {},
283
+ };
284
+
285
+ class TestWorkflow extends Workflow {
286
+ async run() {
287
+ this.logger.info('Test message');
288
+ }
289
+ }
290
+
291
+ const workflow = new TestWorkflow();
292
+ workflow.addObserver(throwingObserver);
293
+ workflow.addObserver(workingObserver2);
294
+ workflow.addObserver(workingObserver3);
295
+
296
+ await workflow.run();
297
+
298
+ // Both working observers should have been called
299
+ expect(observer2Called).toBe(true);
300
+ expect(observer3Called).toBe(true);
301
+
302
+ // Should have error log for throwing observer
303
+ const errorLog = workflow.node.logs.find((log) => log.message === 'Observer onLog error');
304
+ expect(errorLog).toBeDefined();
305
+ });
306
+ ```
307
+
308
+ **Source:** `/home/dustin/projects/groundswell/src/__tests__/integration/observer-logging.test.ts` (lines 327-378)
309
+
310
+ ### Pattern 2: Log Errors from Multiple Throwing Observers
311
+
312
+ ```typescript
313
+ it('should log errors for multiple throwing observers', async () => {
314
+ const throwingObserver1: WorkflowObserver = {
315
+ onLog: () => {
316
+ throw new Error('Observer 1 error');
317
+ },
318
+ onEvent: () => {},
319
+ onStateUpdated: () => {},
320
+ onTreeChanged: () => {},
321
+ };
322
+
323
+ const throwingObserver2: WorkflowObserver = {
324
+ onLog: () => {
325
+ throw new Error('Observer 2 error');
326
+ },
327
+ onEvent: () => {},
328
+ onStateUpdated: () => {},
329
+ onTreeChanged: () => {},
330
+ };
331
+
332
+ class TestWorkflow extends Workflow {
333
+ async run() {
334
+ this.logger.info('Test message');
335
+ }
336
+ }
337
+
338
+ const workflow = new TestWorkflow();
339
+ workflow.addObserver(throwingObserver1);
340
+ workflow.addObserver(throwingObserver2);
341
+
342
+ await workflow.run();
343
+
344
+ // Should have error logs for both throwing observers
345
+ const errorLogs = workflow.node.logs.filter((log) => log.message === 'Observer onLog error');
346
+ expect(errorLogs.length).toBe(2);
347
+ });
348
+ ```
349
+
350
+ **Source:** `/home/dustin/projects/groundswell/src/__tests__/integration/observer-logging.test.ts` (lines 380-414)
351
+
352
+ ### Pattern 3: Avoid Infinite Recursion
353
+
354
+ ```typescript
355
+ it('should avoid infinite recursion when observer onLog throws', async () => {
356
+ let callCount = 0;
357
+ const maxCalls = 10; // Safety limit to prevent actual infinite loop
358
+
359
+ const throwingObserver: WorkflowObserver = {
360
+ onLog: () => {
361
+ callCount++;
362
+ if (callCount < maxCalls) {
363
+ throw new Error('Recursive error');
364
+ }
365
+ },
366
+ onEvent: () => {},
367
+ onStateUpdated: () => {},
368
+ onTreeChanged: () => {},
369
+ };
370
+
371
+ class TestWorkflow extends Workflow {
372
+ async run() {
373
+ this.logger.info('Test message');
374
+ }
375
+ }
376
+
377
+ const workflow = new TestWorkflow();
378
+ workflow.addObserver(throwingObserver);
379
+ await workflow.run();
380
+
381
+ // Should only call onLog once (original) + one error log, then stop
382
+ // The error log should NOT trigger another observer notification
383
+ expect(callCount).toBe(1);
384
+
385
+ // Should have 2 logs: original + error
386
+ expect(workflow.node.logs.length).toBe(2);
387
+ });
388
+ ```
389
+
390
+ **Source:** `/home/dustin/projects/groundswell/src/__tests__/integration/observer-logging.test.ts` (lines 42-74)
391
+
392
+ ---
393
+
394
+ ## 5. Verifying Error Context in Logs
395
+
396
+ ### Pattern 1: Verify Error Object in Log Data
397
+
398
+ ```typescript
399
+ it('should log observer onLog errors to workflow.node.logs', async () => {
400
+ const onLogError = new Error('Observer onLog failed');
401
+
402
+ const throwingObserver: WorkflowObserver = {
403
+ onLog: () => {
404
+ throw onLogError;
405
+ },
406
+ onEvent: () => {},
407
+ onStateUpdated: () => {},
408
+ onTreeChanged: () => {},
409
+ };
410
+
411
+ class TestWorkflow extends Workflow {
412
+ async run() {
413
+ this.logger.info('Test message');
414
+ }
415
+ }
416
+
417
+ const workflow = new TestWorkflow();
418
+ workflow.addObserver(throwingObserver);
419
+ await workflow.run();
420
+
421
+ // Should have 2 logs: the original "Test message" and the observer error
422
+ expect(workflow.node.logs.length).toBe(2);
423
+
424
+ // First log is the original message
425
+ expect(workflow.node.logs[0].message).toBe('Test message');
426
+ expect(workflow.node.logs[0].level).toBe('info');
427
+
428
+ // Second log is the observer error
429
+ expect(workflow.node.logs[1].message).toBe('Observer onLog error');
430
+ expect(workflow.node.logs[1].level).toBe('error');
431
+ expect(workflow.node.logs[1].data).toEqual({ error: onLogError });
432
+ });
433
+ ```
434
+
435
+ **Source:** `/home/dustin/projects/groundswell/src/__tests__/integration/observer-logging.test.ts` (lines 7-40)
436
+
437
+ ### Pattern 2: Include Event Type in Error Data
438
+
439
+ ```typescript
440
+ it('should include event type in error data', () => {
441
+ const throwingObserver: WorkflowObserver = {
442
+ onLog: () => {},
443
+ onEvent: () => {
444
+ throw new Error('Event error');
445
+ },
446
+ onStateUpdated: () => {},
447
+ onTreeChanged: () => {},
448
+ };
449
+
450
+ class TestWorkflow extends Workflow {
451
+ async run() {
452
+ this.emitEvent({ type: 'treeUpdated', root: this.node });
453
+ }
454
+ }
455
+
456
+ const workflow = new TestWorkflow();
457
+ workflow.addObserver(throwingObserver);
458
+
459
+ workflow.run();
460
+
461
+ const errorLog = workflow.node.logs.find((log) => log.message === 'Observer onEvent error');
462
+ expect(errorLog?.data).toHaveProperty('eventType', 'treeUpdated');
463
+ });
464
+ ```
465
+
466
+ **Source:** `/home/dustin/projects/groundswell/src/__tests__/integration/observer-logging.test.ts` (lines 111-134)
467
+
468
+ ### Pattern 3: Include Node ID in Error Data
469
+
470
+ ```typescript
471
+ it('should include node ID in error data', async () => {
472
+ const throwingObserver: WorkflowObserver = {
473
+ onLog: () => {},
474
+ onEvent: () => {},
475
+ onStateUpdated: () => {
476
+ throw new Error('State update error');
477
+ },
478
+ onTreeChanged: () => {},
479
+ };
480
+
481
+ class TestWorkflow extends Workflow {
482
+ async run() {
483
+ this.snapshotState();
484
+ }
485
+ }
486
+
487
+ const workflow = new TestWorkflow();
488
+ workflow.addObserver(throwingObserver);
489
+ await workflow.run();
490
+
491
+ const errorLog = workflow.node.logs.find(
492
+ (log) => log.message === 'Observer onStateUpdated error'
493
+ );
494
+ expect(errorLog?.data).toHaveProperty('nodeId', workflow.node.id);
495
+ });
496
+ ```
497
+
498
+ **Source:** `/home/dustin/projects/groundswell/src/__tests__/integration/observer-logging.test.ts` (lines 172-196)
499
+
500
+ ### Pattern 4: Verify Structured Error Context
501
+
502
+ ```typescript
503
+ it('should log structured error context', async () => {
504
+ const events: WorkflowEvent[] = [];
505
+
506
+ const throwingObserver: WorkflowObserver = {
507
+ onEvent: () => {
508
+ throw new Error('Observer onEvent failed');
509
+ },
510
+ onLog: () => {},
511
+ onStateUpdated: () => {},
512
+ onTreeChanged: () => {},
513
+ };
514
+
515
+ class TestWorkflow extends Workflow {
516
+ async run() {
517
+ this.emitEvent({ type: 'testEvent' });
518
+ }
519
+ }
520
+
521
+ const workflow = new TestWorkflow();
522
+ workflow.addObserver(throwingObserver);
523
+
524
+ workflow.run();
525
+
526
+ // Should have error log entry
527
+ const errorLog = workflow.node.logs.find((log) => log.message === 'Observer onEvent error');
528
+ expect(errorLog).toBeDefined();
529
+ expect(errorLog?.level).toBe('error');
530
+ expect(errorLog?.data).toEqual({
531
+ error: expect.any(Error),
532
+ eventType: 'testEvent',
533
+ });
534
+ });
535
+ ```
536
+
537
+ **Source:** `/home/dustin/projects/groundswell/src/__tests__/integration/observer-logging.test.ts` (lines 77-109)
538
+
539
+ ---
540
+
541
+ ## 6. Mocking Patterns for Loggers in Vitest
542
+
543
+ ### Pattern 1: beforeEach/afterEach Setup
544
+
545
+ **Best Practice:** Always restore mocks in cleanup.
546
+
547
+ ```typescript
548
+ describe('Logger tests', () => {
549
+ let mockLogger: ObservableLogger;
550
+ let consoleErrorSpy: ReturnType<typeof vi.spyOn>;
551
+
552
+ beforeEach(() => {
553
+ mockLogger = {
554
+ error: vi.fn(),
555
+ };
556
+ consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
557
+ });
558
+
559
+ afterEach(() => {
560
+ consoleErrorSpy.mockRestore();
561
+ vi.restoreAllMocks();
562
+ });
563
+
564
+ it('test case', () => {
565
+ // mockLogger and consoleErrorSpy are already set up
566
+ });
567
+ });
568
+ ```
569
+
570
+ ### Pattern 2: Partial Mocking
571
+
572
+ ```typescript
573
+ // Mock only specific methods
574
+ const mockLogger = {
575
+ error: vi.fn(),
576
+ info: vi.fn(),
577
+ warn: vi.fn(),
578
+ debug: vi.fn(),
579
+ };
580
+
581
+ // Use in tests
582
+ expect(mockLogger.error).toHaveBeenCalledWith('message', { context: 'value' });
583
+ expect(mockLogger.error).toHaveBeenCalledTimes(1);
584
+ ```
585
+
586
+ ### Pattern 3: Module Mocking
587
+
588
+ ```typescript
589
+ // Mock entire logger module
590
+ vi.mock('./logger', () => ({
591
+ logger: {
592
+ info: vi.fn(),
593
+ error: vi.fn(),
594
+ warn: vi.fn(),
595
+ debug: vi.fn(),
596
+ },
597
+ }));
598
+
599
+ import { logger } from './logger';
600
+
601
+ describe('Module mocking', () => {
602
+ it('should use mocked logger', () => {
603
+ logger.info('test');
604
+ expect(logger.info).toHaveBeenCalledWith('test');
605
+ });
606
+ });
607
+ ```
608
+
609
+ ---
610
+
611
+ ## 7. Best Practices Summary
612
+
613
+ ### DO's
614
+
615
+ 1. **Mock logger interfaces, not console output**
616
+ ```typescript
617
+ const mockLogger = { error: vi.fn() };
618
+ expect(mockLogger.error).toHaveBeenCalledWith(...);
619
+ ```
620
+
621
+ 2. **Verify errors don't crash execution**
622
+ ```typescript
623
+ expect(() => observable.next(42)).not.toThrow();
624
+ expect(mockLogger.error).toHaveBeenCalled();
625
+ ```
626
+
627
+ 3. **Test multiple observers with mixed success/failure**
628
+ ```typescript
629
+ // Some throw, some succeed
630
+ expect(observer2Called).toBe(true);
631
+ expect(errorLogs.length).toBe(2);
632
+ ```
633
+
634
+ 4. **Verify error context in logs**
635
+ ```typescript
636
+ expect(errorLog.data).toEqual({
637
+ error: expect.any(Error),
638
+ eventType: 'testEvent',
639
+ });
640
+ ```
641
+
642
+ 5. **Always restore mocks**
643
+ ```typescript
644
+ afterEach(() => {
645
+ consoleSpy.mockRestore();
646
+ vi.restoreAllMocks();
647
+ });
648
+ ```
649
+
650
+ ### DON'Ts
651
+
652
+ 1. **Don't test console.output directly for logger verification**
653
+ ```typescript
654
+ // BAD
655
+ expect(console.error).toHaveBeenCalledWith(...);
656
+
657
+ // GOOD
658
+ expect(mockLogger.error).toHaveBeenCalledWith(...);
659
+ ```
660
+
661
+ 2. **Don't forget to test error isolation**
662
+ ```typescript
663
+ // BAD - only tests error thrown
664
+ expect(() => observable.next(42)).toThrow();
665
+
666
+ // GOOD - tests error caught and logged
667
+ expect(() => observable.next(42)).not.toThrow();
668
+ expect(mockLogger.error).toHaveBeenCalled();
669
+ ```
670
+
671
+ 3. **Don't skip testing multiple observers**
672
+ ```typescript
673
+ // Test with 3+ observers to ensure isolation
674
+ ```
675
+
676
+ 4. **Don't ignore error context verification**
677
+ ```typescript
678
+ // Verify error objects, not just messages
679
+ expect(errorLog.data.error).toBeInstanceOf(Error);
680
+ ```
681
+
682
+ ---
683
+
684
+ ## 8. Quick Reference: Vitest Assertions for Logger Testing
685
+
686
+ ```typescript
687
+ // Mock logger creation
688
+ const mockLogger = { error: vi.fn() };
689
+
690
+ // Verify logger was called
691
+ expect(mockLogger.error).toHaveBeenCalled();
692
+ expect(mockLogger.error).toHaveBeenCalledTimes(1);
693
+ expect(mockLogger.error).toHaveBeenCalledWith('message', { error });
694
+
695
+ // Verify specific call
696
+ expect(mockLogger.error).toHaveBeenNthCalledWith(1, 'message', { error: expect.any(Error) });
697
+
698
+ // Verify error isolation
699
+ expect(() => observable.next(42)).not.toThrow();
700
+
701
+ // Verify log data structure
702
+ expect(logEntry.data).toEqual({
703
+ error: expect.any(Error),
704
+ eventType: 'testEvent',
705
+ });
706
+
707
+ // Console fallback testing
708
+ const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
709
+ expect(consoleSpy).toHaveBeenCalledWith('message', error);
710
+ consoleSpy.mockRestore();
711
+ ```
712
+
713
+ ---
714
+
715
+ ## 9. External Resources
716
+
717
+ ### Vitest Official Documentation
718
+ - Main: https://vitest.dev/
719
+ - Assertions: https://vitest.dev/api/expect.html
720
+ - Mocking: https://vitest.dev/guide/mocking.html
721
+ - Async: https://vitest.dev/guide/async.html
722
+
723
+ ### Observer Pattern Resources
724
+ - Observer pattern error handling: https://en.wikipedia.org/wiki/Observer_pattern
725
+ - Testing observer patterns: https://refactoring.guru/design-patterns/observer
726
+
727
+ ### Error Handling Best Practices
728
+ - Structured logging: https://www.loggly.com/blog/structured-logging-best-practices/
729
+ - Error context capture: https://planetaria.co/blog/capturing-error-context-in-javascript
730
+
731
+ ---
732
+
733
+ ## 10. Related Files in Groundswell Project
734
+
735
+ ### Test Files (Reference Implementations)
736
+ - `/home/dustin/projects/groundswell/src/__tests__/integration/observer-logging.test.ts` - Observer error logging integration tests
737
+ - `/home/dustin/projects/groundswell/src/__tests__/unit/observable.test.ts` - Observable error handling unit tests
738
+ - `/home/dustin/projects/groundswell/src/__tests__/unit/workflow.test.ts` - Workflow error state tests
739
+
740
+ ### Source Files (Implementation)
741
+ - `/home/dustin/projects/groundswell/src/utils/observable.ts` - Observable class with logger injection
742
+ - `/home/dustin/projects/groundswell/src/core/logger.ts` - WorkflowLogger implementation
743
+ - `/home/dustin/projects/groundswell/src/core/workflow.ts` - Workflow class with observer error handling
744
+
745
+ ### Research Documents
746
+ - `/home/dustin/projects/groundswell/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S4/research/vitest_testing_patterns.md` - Vitest testing patterns
747
+ - `/home/dustin/projects/groundswell/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T1S3/research/vitest_concurrent_testing.md` - Concurrent testing patterns
748
+ - `/home/dustin/projects/groundswell/plan/001_d3bb02af4886/docs/research/error-testing-research.md` - Error state capture research
749
+
750
+ ---
751
+
752
+ **Document Version:** 1.0
753
+ **Last Updated:** 2026-01-12
754
+ **Research Summary:** Comprehensive best practices for testing observer error logging in Vitest