@probelabs/visor 0.1.106 → 0.1.111

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 (530) hide show
  1. package/README.md +71 -2
  2. package/action.yml +1 -1
  3. package/defaults/code-refiner.yaml +114 -0
  4. package/defaults/{.visor.yaml → code-review.yaml} +35 -226
  5. package/defaults/override.yaml +52 -0
  6. package/defaults/task-refinement.yaml +624 -0
  7. package/defaults/visor.tests.yaml +685 -0
  8. package/defaults/visor.yaml +483 -0
  9. package/dist/action-cli-bridge.d.ts +11 -82
  10. package/dist/action-cli-bridge.d.ts.map +1 -1
  11. package/dist/ai-review-service.d.ts +28 -9
  12. package/dist/ai-review-service.d.ts.map +1 -1
  13. package/dist/check-execution-engine.d.ts +19 -331
  14. package/dist/check-execution-engine.d.ts.map +1 -1
  15. package/dist/cli-main.d.ts.map +1 -1
  16. package/dist/cli.d.ts +0 -1
  17. package/dist/cli.d.ts.map +1 -1
  18. package/dist/config.d.ts +16 -0
  19. package/dist/config.d.ts.map +1 -1
  20. package/dist/cron-scheduler.d.ts +3 -3
  21. package/dist/cron-scheduler.d.ts.map +1 -1
  22. package/dist/debug-visualizer/ws-server.d.ts +7 -1
  23. package/dist/debug-visualizer/ws-server.d.ts.map +1 -1
  24. package/dist/defaults/code-refiner.yaml +114 -0
  25. package/dist/defaults/{.visor.yaml → code-review.yaml} +35 -226
  26. package/dist/defaults/override.yaml +52 -0
  27. package/dist/defaults/task-refinement.yaml +624 -0
  28. package/dist/defaults/visor.tests.yaml +685 -0
  29. package/dist/defaults/visor.yaml +483 -0
  30. package/dist/docs/DEPLOYMENT.md +118 -0
  31. package/dist/docs/GITHUB_CHECKS.md +280 -0
  32. package/dist/docs/NPM_USAGE.md +208 -0
  33. package/dist/docs/action-reference.md +19 -0
  34. package/dist/docs/advanced-ai.md +237 -0
  35. package/dist/docs/ai-configuration.md +535 -0
  36. package/dist/docs/ai-custom-tools-usage.md +261 -0
  37. package/dist/docs/ai-custom-tools.md +392 -0
  38. package/dist/docs/author-permissions.md +610 -0
  39. package/dist/docs/bot-transports-rfc.md +23 -0
  40. package/dist/docs/ci-cli-mode.md +34 -0
  41. package/dist/docs/claude-code.md +74 -0
  42. package/dist/docs/command-provider.md +559 -0
  43. package/dist/docs/commands.md +8 -0
  44. package/dist/docs/configuration.md +324 -0
  45. package/dist/docs/custom-tools.md +424 -0
  46. package/dist/docs/dashboards/README.md +23 -0
  47. package/dist/docs/dashboards/grafana-visor-diagrams.json +20 -0
  48. package/dist/docs/dashboards/grafana-visor-overview.json +33 -0
  49. package/dist/docs/debug-visualizer-progress.md +572 -0
  50. package/dist/docs/debug-visualizer-rfc.md +691 -0
  51. package/dist/docs/debug-visualizer.md +114 -0
  52. package/dist/docs/debugging.md +636 -0
  53. package/dist/docs/default-output-schema.md +28 -0
  54. package/dist/docs/dependencies.md +369 -0
  55. package/dist/docs/dev-playbook.md +9 -0
  56. package/dist/docs/engine-pause-resume-rfc.md +192 -0
  57. package/dist/docs/engine-state-machine-plan.md +333 -0
  58. package/dist/docs/event-driven-github-integration-rfc.md +743 -0
  59. package/dist/docs/event-triggers.md +292 -0
  60. package/dist/docs/execution-statistics-rfc.md +290 -0
  61. package/dist/docs/fact-validator-gap-analysis.md +178 -0
  62. package/dist/docs/fact-validator-implementation-plan.md +1235 -0
  63. package/dist/docs/fail-if.md +95 -0
  64. package/dist/docs/failure-conditions-implementation.md +271 -0
  65. package/dist/docs/failure-conditions-schema.md +173 -0
  66. package/dist/docs/failure-routing-rfc.md +193 -0
  67. package/dist/docs/failure-routing.md +507 -0
  68. package/dist/docs/foreach-dependency-propagation.md +473 -0
  69. package/dist/docs/github-ops.md +89 -0
  70. package/dist/docs/goto-forward-run-plan.md +113 -0
  71. package/dist/docs/guides/criticality-modes.md +332 -0
  72. package/dist/docs/guides/fault-management-and-contracts.md +738 -0
  73. package/dist/docs/guides/workflow-style-guide.md +224 -0
  74. package/dist/docs/http.md +299 -0
  75. package/dist/docs/human-input-provider.md +372 -0
  76. package/dist/docs/lifecycle-hooks.md +253 -0
  77. package/dist/docs/limits.md +64 -0
  78. package/dist/docs/liquid-templates.md +490 -0
  79. package/dist/docs/loop-routing-refactor.md +89 -0
  80. package/dist/docs/mcp-provider.md +557 -0
  81. package/dist/docs/mcp.md +124 -0
  82. package/dist/docs/memory.md +903 -0
  83. package/dist/docs/observability.md +12 -0
  84. package/dist/docs/output-formats.md +20 -0
  85. package/dist/docs/output-formatting.md +29 -0
  86. package/dist/docs/output-history.md +383 -0
  87. package/dist/docs/performance.md +6 -0
  88. package/dist/docs/pluggable.md +124 -0
  89. package/dist/docs/proposals/snapshot-scope-execution.md +236 -0
  90. package/dist/docs/providers/git-checkout.md +589 -0
  91. package/dist/docs/recipes.md +474 -0
  92. package/dist/docs/rfc/git-checkout-step.md +601 -0
  93. package/dist/docs/rfc/on_init-hook.md +1294 -0
  94. package/dist/docs/rfc/workspace-isolation.md +216 -0
  95. package/dist/docs/roadmap/criticality-implementation-tasks.md +92 -0
  96. package/dist/docs/router-patterns.md +339 -0
  97. package/dist/docs/schema-next-pr.md +10 -0
  98. package/dist/docs/schema-templates.md +68 -0
  99. package/dist/docs/script.md +34 -0
  100. package/dist/docs/sdk.md +222 -0
  101. package/dist/docs/security.md +7 -0
  102. package/dist/docs/suppressions.md +89 -0
  103. package/dist/docs/tag-filtering.md +258 -0
  104. package/dist/docs/telemetry-setup.md +119 -0
  105. package/dist/docs/telemetry-tracing-rfc.md +275 -0
  106. package/dist/docs/test-framework-rfc.md +680 -0
  107. package/dist/docs/testing/assertions.md +85 -0
  108. package/dist/docs/testing/ci.md +44 -0
  109. package/dist/docs/testing/cli.md +41 -0
  110. package/dist/docs/testing/cookbook.md +172 -0
  111. package/dist/docs/testing/dsl-reference.md +199 -0
  112. package/dist/docs/testing/fixtures-and-mocks.md +91 -0
  113. package/dist/docs/testing/flows.md +92 -0
  114. package/dist/docs/testing/getting-started.md +93 -0
  115. package/dist/docs/testing/troubleshooting.md +55 -0
  116. package/dist/docs/timeouts.md +50 -0
  117. package/dist/docs/troubleshooting.md +7 -0
  118. package/dist/docs/visor-sdk-rfc.md +186 -0
  119. package/dist/docs/workflows.md +569 -0
  120. package/dist/engine/on-finish/orchestrator.d.ts +19 -0
  121. package/dist/engine/on-finish/orchestrator.d.ts.map +1 -0
  122. package/dist/engine/on-finish/utils.d.ts +44 -0
  123. package/dist/engine/on-finish/utils.d.ts.map +1 -0
  124. package/dist/event-bus/event-bus.d.ts +13 -0
  125. package/dist/event-bus/event-bus.d.ts.map +1 -0
  126. package/dist/event-bus/types.d.ts +71 -0
  127. package/dist/event-bus/types.d.ts.map +1 -0
  128. package/dist/examples/.claude/agents/code-reviewer.md +69 -0
  129. package/dist/examples/.mcp.json +34 -0
  130. package/dist/examples/CALCULATOR-SDK.md +364 -0
  131. package/dist/examples/README.md +384 -0
  132. package/dist/examples/ai-custom-tools-example.yaml +206 -0
  133. package/dist/examples/ai-custom-tools-simple.yaml +76 -0
  134. package/dist/examples/ai-retry-fallback-config.yaml +180 -0
  135. package/dist/examples/ai-with-bash.yaml +126 -0
  136. package/dist/examples/ai-with-mcp.yaml +82 -0
  137. package/dist/examples/basic-human-input.yaml +15 -0
  138. package/dist/examples/bedrock-config.yaml +77 -0
  139. package/dist/examples/calculator-config.yaml +133 -0
  140. package/dist/examples/calculator-json-output-guide.md +311 -0
  141. package/dist/examples/calculator-sdk-automated.ts +340 -0
  142. package/dist/examples/calculator-sdk-example.ts +275 -0
  143. package/dist/examples/calculator-sdk-json.ts +331 -0
  144. package/dist/examples/calculator-sdk-real.ts +374 -0
  145. package/dist/examples/calculator-sdk-test.ts +148 -0
  146. package/dist/examples/claude-code-config.yaml +191 -0
  147. package/dist/examples/cron-webhook-config.yaml +215 -0
  148. package/dist/examples/custom-template.liquid +57 -0
  149. package/dist/examples/custom-tools-example.yaml +281 -0
  150. package/dist/examples/enhanced-config.yaml +165 -0
  151. package/dist/examples/environments/visor.base.yaml +92 -0
  152. package/dist/examples/environments/visor.dev.yaml +33 -0
  153. package/dist/examples/environments/visor.prod.yaml +95 -0
  154. package/dist/examples/environments/visor.staging.yaml +46 -0
  155. package/dist/examples/fact-validator.yaml +361 -0
  156. package/dist/examples/fail-if-simple.yaml +90 -0
  157. package/dist/examples/failure-conditions-advanced.yaml +136 -0
  158. package/dist/examples/failure-conditions-basic.yaml +48 -0
  159. package/dist/examples/failure-conditions-github-style.yaml +119 -0
  160. package/dist/examples/failure-conditions-migration.yaml +74 -0
  161. package/dist/examples/for-loop-example.yaml +176 -0
  162. package/dist/examples/forEach-example.yaml +120 -0
  163. package/dist/examples/git-checkout-basic.yaml +32 -0
  164. package/dist/examples/git-checkout-compare.yaml +59 -0
  165. package/dist/examples/git-checkout-cross-repo.yaml +76 -0
  166. package/dist/examples/github-workflow-with-tags.yml +163 -0
  167. package/dist/examples/http-integration-config.yaml +240 -0
  168. package/dist/examples/https-server-config.yaml +209 -0
  169. package/dist/examples/human-input-example.yaml +63 -0
  170. package/dist/examples/if-conditions.yaml +173 -0
  171. package/dist/examples/jira-simple-example.yaml +56 -0
  172. package/dist/examples/jira-single-issue-workflow.yaml +166 -0
  173. package/dist/examples/jira-workflow-mcp.yaml +182 -0
  174. package/dist/examples/mcp/analyzer.py +119 -0
  175. package/dist/examples/mcp-provider-example.yaml +301 -0
  176. package/dist/examples/memory-counter.yaml +99 -0
  177. package/dist/examples/memory-error-collection.yaml +104 -0
  178. package/dist/examples/memory-exec-js.yaml +247 -0
  179. package/dist/examples/memory-namespace-isolation.yaml +184 -0
  180. package/dist/examples/memory-retry-counter.yaml +65 -0
  181. package/dist/examples/memory-state-machine.yaml +170 -0
  182. package/dist/examples/on-init-import-demo.yaml +179 -0
  183. package/dist/examples/outputs-raw-basic.yaml +26 -0
  184. package/dist/examples/project-with-tools.yaml +174 -0
  185. package/dist/examples/prompts/architecture-analysis.liquid +116 -0
  186. package/dist/examples/prompts/security-comprehensive.liquid +107 -0
  187. package/dist/examples/quick-start-tags.yaml +53 -0
  188. package/dist/examples/reusable-tools.yaml +92 -0
  189. package/dist/examples/reusable-workflows.yaml +88 -0
  190. package/dist/examples/routing-basic.yaml +35 -0
  191. package/dist/examples/routing-dynamic-js.yaml +46 -0
  192. package/dist/examples/routing-foreach.yaml +34 -0
  193. package/dist/examples/routing-goto-event.yaml +34 -0
  194. package/dist/examples/routing-on-success.yaml +25 -0
  195. package/dist/examples/run-calculator-demo.sh +71 -0
  196. package/dist/examples/sdk-basic.mjs +10 -0
  197. package/dist/examples/sdk-cjs.cjs +10 -0
  198. package/dist/examples/sdk-comprehensive.mjs +175 -0
  199. package/dist/examples/sdk-manual-config.mjs +65 -0
  200. package/dist/examples/sdk-typescript.js +81 -0
  201. package/dist/examples/sdk-typescript.ts +92 -0
  202. package/dist/examples/session-reuse-config.yaml +151 -0
  203. package/dist/examples/session-reuse-self.yaml +81 -0
  204. package/dist/examples/slack-simple-chat.yaml +775 -0
  205. package/dist/examples/templates/security-report.liquid +137 -0
  206. package/dist/examples/tools-library.yaml +281 -0
  207. package/dist/examples/transform-example.yaml +199 -0
  208. package/dist/examples/visor-with-tags.yaml +198 -0
  209. package/dist/examples/webhook-pipeline-config.yaml +218 -0
  210. package/dist/examples/workflows/calculator-workflow.yaml +163 -0
  211. package/dist/examples/workflows/code-quality.yaml +222 -0
  212. package/dist/examples/workflows/quick-pr-check.yaml +90 -0
  213. package/dist/examples/workflows/workflow-composition-example.yaml +130 -0
  214. package/dist/failure-condition-evaluator.d.ts +3 -0
  215. package/dist/failure-condition-evaluator.d.ts.map +1 -1
  216. package/dist/frontends/github-frontend.d.ts +58 -0
  217. package/dist/frontends/github-frontend.d.ts.map +1 -0
  218. package/dist/frontends/host.d.ts +47 -0
  219. package/dist/frontends/host.d.ts.map +1 -0
  220. package/dist/frontends/ndjson-sink.d.ts +12 -0
  221. package/dist/frontends/ndjson-sink.d.ts.map +1 -0
  222. package/dist/frontends/slack-frontend.d.ts +58 -0
  223. package/dist/frontends/slack-frontend.d.ts.map +1 -0
  224. package/dist/generated/config-schema.d.ts +967 -57
  225. package/dist/generated/config-schema.d.ts.map +1 -1
  226. package/dist/generated/config-schema.json +1033 -56
  227. package/dist/github-check-service.d.ts +4 -6
  228. package/dist/github-check-service.d.ts.map +1 -1
  229. package/dist/github-comments.d.ts +2 -4
  230. package/dist/github-comments.d.ts.map +1 -1
  231. package/dist/index.d.ts.map +1 -1
  232. package/dist/index.js +134327 -99004
  233. package/dist/liquid-extensions.d.ts.map +1 -1
  234. package/dist/logger.d.ts +2 -0
  235. package/dist/logger.d.ts.map +1 -1
  236. package/dist/memory-store.d.ts +6 -0
  237. package/dist/memory-store.d.ts.map +1 -1
  238. package/dist/output/assistant-json/template.liquid +0 -0
  239. package/dist/output/traces/run-2026-01-20T19-22-58-043Z.ndjson +138 -0
  240. package/dist/output/traces/run-2026-01-20T19-23-52-175Z.ndjson +1067 -0
  241. package/dist/output-formatters.d.ts +1 -1
  242. package/dist/output-formatters.d.ts.map +1 -1
  243. package/dist/providers/ai-check-provider.d.ts +12 -0
  244. package/dist/providers/ai-check-provider.d.ts.map +1 -1
  245. package/dist/providers/check-provider-registry.d.ts +6 -0
  246. package/dist/providers/check-provider-registry.d.ts.map +1 -1
  247. package/dist/providers/check-provider.interface.d.ts +43 -1
  248. package/dist/providers/check-provider.interface.d.ts.map +1 -1
  249. package/dist/providers/claude-code-check-provider.d.ts.map +1 -1
  250. package/dist/providers/command-check-provider.d.ts +1 -1
  251. package/dist/providers/command-check-provider.d.ts.map +1 -1
  252. package/dist/providers/custom-tool-executor.d.ts +61 -0
  253. package/dist/providers/custom-tool-executor.d.ts.map +1 -0
  254. package/dist/providers/git-checkout-provider.d.ts +25 -0
  255. package/dist/providers/git-checkout-provider.d.ts.map +1 -0
  256. package/dist/providers/github-ops-provider.d.ts.map +1 -1
  257. package/dist/providers/http-client-provider.d.ts +4 -4
  258. package/dist/providers/http-client-provider.d.ts.map +1 -1
  259. package/dist/providers/human-input-check-provider.d.ts +5 -0
  260. package/dist/providers/human-input-check-provider.d.ts.map +1 -1
  261. package/dist/providers/index.d.ts +1 -0
  262. package/dist/providers/index.d.ts.map +1 -1
  263. package/dist/providers/log-check-provider.d.ts +2 -5
  264. package/dist/providers/log-check-provider.d.ts.map +1 -1
  265. package/dist/providers/mcp-check-provider.d.ts +10 -4
  266. package/dist/providers/mcp-check-provider.d.ts.map +1 -1
  267. package/dist/providers/mcp-custom-sse-server.d.ts +66 -0
  268. package/dist/providers/mcp-custom-sse-server.d.ts.map +1 -0
  269. package/dist/providers/memory-check-provider.d.ts +2 -8
  270. package/dist/providers/memory-check-provider.d.ts.map +1 -1
  271. package/dist/providers/script-check-provider.d.ts +25 -0
  272. package/dist/providers/script-check-provider.d.ts.map +1 -0
  273. package/dist/providers/workflow-check-provider.d.ts +56 -0
  274. package/dist/providers/workflow-check-provider.d.ts.map +1 -0
  275. package/dist/reviewer.d.ts +2 -1
  276. package/dist/reviewer.d.ts.map +1 -1
  277. package/dist/sdk/check-provider-registry-534KL5HT.mjs +27 -0
  278. package/dist/sdk/chunk-23L3QRYX.mjs +16872 -0
  279. package/dist/sdk/chunk-23L3QRYX.mjs.map +1 -0
  280. package/dist/sdk/{chunk-TUTOLSFV.mjs → chunk-3OMWVM6J.mjs} +11 -1
  281. package/dist/sdk/chunk-3OMWVM6J.mjs.map +1 -0
  282. package/dist/sdk/chunk-7UK3NIIT.mjs +482 -0
  283. package/dist/sdk/chunk-7UK3NIIT.mjs.map +1 -0
  284. package/dist/sdk/chunk-AGIZJ4UZ.mjs +173 -0
  285. package/dist/sdk/chunk-AGIZJ4UZ.mjs.map +1 -0
  286. package/dist/sdk/chunk-AIVFBIS4.mjs +1371 -0
  287. package/dist/sdk/chunk-AIVFBIS4.mjs.map +1 -0
  288. package/dist/sdk/chunk-AK6BVWIT.mjs +426 -0
  289. package/dist/sdk/chunk-AK6BVWIT.mjs.map +1 -0
  290. package/dist/sdk/chunk-AUT26LHW.mjs +139 -0
  291. package/dist/sdk/chunk-AUT26LHW.mjs.map +1 -0
  292. package/dist/sdk/chunk-BOVFH3LI.mjs +232 -0
  293. package/dist/sdk/chunk-BOVFH3LI.mjs.map +1 -0
  294. package/dist/sdk/chunk-CNX7V5JK.mjs +89 -0
  295. package/dist/sdk/chunk-CNX7V5JK.mjs.map +1 -0
  296. package/dist/sdk/chunk-HTOKWMPO.mjs +157 -0
  297. package/dist/sdk/chunk-HTOKWMPO.mjs.map +1 -0
  298. package/dist/sdk/chunk-NAW3DB3I.mjs +197 -0
  299. package/dist/sdk/chunk-NAW3DB3I.mjs.map +1 -0
  300. package/dist/sdk/chunk-O5EZDNYL.mjs +274 -0
  301. package/dist/sdk/chunk-O5EZDNYL.mjs.map +1 -0
  302. package/dist/sdk/chunk-QR7MOMJH.mjs +558 -0
  303. package/dist/sdk/chunk-QR7MOMJH.mjs.map +1 -0
  304. package/dist/sdk/chunk-QY2XYPEV.mjs +3556 -0
  305. package/dist/sdk/chunk-QY2XYPEV.mjs.map +1 -0
  306. package/dist/sdk/chunk-S2RUE2RG.mjs +145 -0
  307. package/dist/sdk/chunk-S2RUE2RG.mjs.map +1 -0
  308. package/dist/sdk/chunk-SIWNBRTK.mjs +800 -0
  309. package/dist/sdk/chunk-SIWNBRTK.mjs.map +1 -0
  310. package/dist/sdk/chunk-YSN4G6CI.mjs +146 -0
  311. package/dist/sdk/chunk-YSN4G6CI.mjs.map +1 -0
  312. package/dist/sdk/chunk-ZYAUYXSW.mjs +206 -0
  313. package/dist/sdk/chunk-ZYAUYXSW.mjs.map +1 -0
  314. package/dist/sdk/command-executor-TYUV6HUS.mjs +14 -0
  315. package/dist/sdk/config-YNC2EOOT.mjs +16 -0
  316. package/dist/sdk/config-merger-PX3WIT57.mjs +10 -0
  317. package/dist/sdk/event-bus-5BEVPQ6T.mjs +35 -0
  318. package/dist/sdk/event-bus-5BEVPQ6T.mjs.map +1 -0
  319. package/dist/sdk/failure-condition-evaluator-YGTF2GHG.mjs +17 -0
  320. package/dist/sdk/git-repository-analyzer-HJC4MYW4.mjs +458 -0
  321. package/dist/sdk/git-repository-analyzer-HJC4MYW4.mjs.map +1 -0
  322. package/dist/sdk/github-frontend-SIAEOCON.mjs +1420 -0
  323. package/dist/sdk/github-frontend-SIAEOCON.mjs.map +1 -0
  324. package/dist/sdk/host-DXUYTNMU.mjs +52 -0
  325. package/dist/sdk/host-DXUYTNMU.mjs.map +1 -0
  326. package/dist/sdk/{liquid-extensions-KVL4MKRH.mjs → liquid-extensions-PKWCKK7E.mjs} +8 -2
  327. package/dist/sdk/memory-store-XGBB7LX7.mjs +12 -0
  328. package/dist/sdk/memory-store-XGBB7LX7.mjs.map +1 -0
  329. package/dist/sdk/metrics-7PP3EJUH.mjs +29 -0
  330. package/dist/sdk/metrics-7PP3EJUH.mjs.map +1 -0
  331. package/dist/sdk/ndjson-sink-B4V4NTAQ.mjs +44 -0
  332. package/dist/sdk/ndjson-sink-B4V4NTAQ.mjs.map +1 -0
  333. package/dist/sdk/prompt-state-YRJY6QAL.mjs +16 -0
  334. package/dist/sdk/prompt-state-YRJY6QAL.mjs.map +1 -0
  335. package/dist/sdk/renderer-schema-LPKN5UJS.mjs +51 -0
  336. package/dist/sdk/renderer-schema-LPKN5UJS.mjs.map +1 -0
  337. package/dist/sdk/routing-6N45MJ4F.mjs +24 -0
  338. package/dist/sdk/routing-6N45MJ4F.mjs.map +1 -0
  339. package/dist/sdk/sdk.d.mts +541 -22
  340. package/dist/sdk/sdk.d.ts +541 -22
  341. package/dist/sdk/sdk.js +27963 -16505
  342. package/dist/sdk/sdk.js.map +1 -1
  343. package/dist/sdk/sdk.mjs +1116 -2169
  344. package/dist/sdk/sdk.mjs.map +1 -1
  345. package/dist/sdk/session-registry-4E6YRQ77.mjs +10 -0
  346. package/dist/sdk/session-registry-4E6YRQ77.mjs.map +1 -0
  347. package/dist/sdk/slack-frontend-BVKW3GD5.mjs +735 -0
  348. package/dist/sdk/slack-frontend-BVKW3GD5.mjs.map +1 -0
  349. package/dist/sdk/trace-helpers-VP6QYVBX.mjs +23 -0
  350. package/dist/sdk/trace-helpers-VP6QYVBX.mjs.map +1 -0
  351. package/dist/sdk/{tracer-init-WC75N5NW.mjs → tracer-init-GSLPPLCD.mjs} +2 -2
  352. package/dist/sdk/tracer-init-GSLPPLCD.mjs.map +1 -0
  353. package/dist/sdk/workflow-registry-R6KSACFR.mjs +12 -0
  354. package/dist/sdk/workflow-registry-R6KSACFR.mjs.map +1 -0
  355. package/dist/sdk.d.ts.map +1 -1
  356. package/dist/slack/adapter.d.ts +36 -0
  357. package/dist/slack/adapter.d.ts.map +1 -0
  358. package/dist/slack/cache-prewarmer.d.ts +31 -0
  359. package/dist/slack/cache-prewarmer.d.ts.map +1 -0
  360. package/dist/slack/client.d.ts +77 -0
  361. package/dist/slack/client.d.ts.map +1 -0
  362. package/dist/slack/markdown.d.ts +45 -0
  363. package/dist/slack/markdown.d.ts.map +1 -0
  364. package/dist/slack/prompt-state.d.ts +33 -0
  365. package/dist/slack/prompt-state.d.ts.map +1 -0
  366. package/dist/slack/rate-limiter.d.ts +56 -0
  367. package/dist/slack/rate-limiter.d.ts.map +1 -0
  368. package/dist/slack/signature.d.ts +2 -0
  369. package/dist/slack/signature.d.ts.map +1 -0
  370. package/dist/slack/socket-runner.d.ts +42 -0
  371. package/dist/slack/socket-runner.d.ts.map +1 -0
  372. package/dist/slack/thread-cache.d.ts +51 -0
  373. package/dist/slack/thread-cache.d.ts.map +1 -0
  374. package/dist/snapshot-store.d.ts +59 -0
  375. package/dist/snapshot-store.d.ts.map +1 -0
  376. package/dist/state-machine/context/build-engine-context.d.ts +17 -0
  377. package/dist/state-machine/context/build-engine-context.d.ts.map +1 -0
  378. package/dist/state-machine/dispatch/dependency-gating.d.ts +12 -0
  379. package/dist/state-machine/dispatch/dependency-gating.d.ts.map +1 -0
  380. package/dist/state-machine/dispatch/execution-invoker.d.ts +14 -0
  381. package/dist/state-machine/dispatch/execution-invoker.d.ts.map +1 -0
  382. package/dist/state-machine/dispatch/foreach-processor.d.ts +8 -0
  383. package/dist/state-machine/dispatch/foreach-processor.d.ts.map +1 -0
  384. package/dist/state-machine/dispatch/history-snapshot.d.ts +8 -0
  385. package/dist/state-machine/dispatch/history-snapshot.d.ts.map +1 -0
  386. package/dist/state-machine/dispatch/on-init-handlers.d.ts +43 -0
  387. package/dist/state-machine/dispatch/on-init-handlers.d.ts.map +1 -0
  388. package/dist/state-machine/dispatch/renderer-schema.d.ts +8 -0
  389. package/dist/state-machine/dispatch/renderer-schema.d.ts.map +1 -0
  390. package/dist/state-machine/dispatch/stats-manager.d.ts +15 -0
  391. package/dist/state-machine/dispatch/stats-manager.d.ts.map +1 -0
  392. package/dist/state-machine/dispatch/template-renderer.d.ts +7 -0
  393. package/dist/state-machine/dispatch/template-renderer.d.ts.map +1 -0
  394. package/dist/state-machine/execution/summary.d.ts +8 -0
  395. package/dist/state-machine/execution/summary.d.ts.map +1 -0
  396. package/dist/state-machine/runner.d.ts +79 -0
  397. package/dist/state-machine/runner.d.ts.map +1 -0
  398. package/dist/state-machine/states/check-running.d.ts +14 -0
  399. package/dist/state-machine/states/check-running.d.ts.map +1 -0
  400. package/dist/state-machine/states/completed.d.ts +12 -0
  401. package/dist/state-machine/states/completed.d.ts.map +1 -0
  402. package/dist/state-machine/states/error.d.ts +11 -0
  403. package/dist/state-machine/states/error.d.ts.map +1 -0
  404. package/dist/state-machine/states/init.d.ts +11 -0
  405. package/dist/state-machine/states/init.d.ts.map +1 -0
  406. package/dist/state-machine/states/level-dispatch.d.ts +17 -0
  407. package/dist/state-machine/states/level-dispatch.d.ts.map +1 -0
  408. package/dist/state-machine/states/plan-ready.d.ts +12 -0
  409. package/dist/state-machine/states/plan-ready.d.ts.map +1 -0
  410. package/dist/state-machine/states/routing.d.ts +52 -0
  411. package/dist/state-machine/states/routing.d.ts.map +1 -0
  412. package/dist/state-machine/states/wave-planning.d.ts +14 -0
  413. package/dist/state-machine/states/wave-planning.d.ts.map +1 -0
  414. package/dist/state-machine/workflow-projection.d.ts +47 -0
  415. package/dist/state-machine/workflow-projection.d.ts.map +1 -0
  416. package/dist/state-machine-execution-engine.d.ts +159 -0
  417. package/dist/state-machine-execution-engine.d.ts.map +1 -0
  418. package/dist/telemetry/opentelemetry.d.ts.map +1 -1
  419. package/dist/telemetry/state-capture.d.ts +5 -0
  420. package/dist/telemetry/state-capture.d.ts.map +1 -1
  421. package/dist/test-runner/assertions.d.ts +59 -0
  422. package/dist/test-runner/assertions.d.ts.map +1 -0
  423. package/dist/test-runner/core/environment.d.ts +8 -0
  424. package/dist/test-runner/core/environment.d.ts.map +1 -0
  425. package/dist/test-runner/core/fixture.d.ts +3 -0
  426. package/dist/test-runner/core/fixture.d.ts.map +1 -0
  427. package/dist/test-runner/core/flow-stage.d.ts +32 -0
  428. package/dist/test-runner/core/flow-stage.d.ts.map +1 -0
  429. package/dist/test-runner/core/mocks.d.ts +8 -0
  430. package/dist/test-runner/core/mocks.d.ts.map +1 -0
  431. package/dist/test-runner/core/test-execution-wrapper.d.ts +18 -0
  432. package/dist/test-runner/core/test-execution-wrapper.d.ts.map +1 -0
  433. package/dist/test-runner/evaluators.d.ts +45 -0
  434. package/dist/test-runner/evaluators.d.ts.map +1 -0
  435. package/dist/test-runner/fixture-loader.d.ts +30 -0
  436. package/dist/test-runner/fixture-loader.d.ts.map +1 -0
  437. package/dist/test-runner/index.d.ts +127 -0
  438. package/dist/test-runner/index.d.ts.map +1 -0
  439. package/dist/test-runner/recorders/github-recorder.d.ts +23 -0
  440. package/dist/test-runner/recorders/github-recorder.d.ts.map +1 -0
  441. package/dist/test-runner/recorders/global-recorder.d.ts +4 -0
  442. package/dist/test-runner/recorders/global-recorder.d.ts.map +1 -0
  443. package/dist/test-runner/recorders/slack-recorder.d.ts +17 -0
  444. package/dist/test-runner/recorders/slack-recorder.d.ts.map +1 -0
  445. package/dist/test-runner/utils/selectors.d.ts +2 -0
  446. package/dist/test-runner/utils/selectors.d.ts.map +1 -0
  447. package/dist/test-runner/validator.d.ts +8 -0
  448. package/dist/test-runner/validator.d.ts.map +1 -0
  449. package/dist/traces/run-2026-01-20T19-22-58-043Z.ndjson +138 -0
  450. package/dist/traces/run-2026-01-20T19-23-52-175Z.ndjson +1067 -0
  451. package/dist/types/bot.d.ts +109 -0
  452. package/dist/types/bot.d.ts.map +1 -0
  453. package/dist/types/cli.d.ts +8 -1
  454. package/dist/types/cli.d.ts.map +1 -1
  455. package/dist/types/config.d.ts +459 -9
  456. package/dist/types/config.d.ts.map +1 -1
  457. package/dist/types/engine.d.ts +177 -0
  458. package/dist/types/engine.d.ts.map +1 -0
  459. package/dist/types/execution.d.ts +73 -0
  460. package/dist/types/execution.d.ts.map +1 -0
  461. package/dist/types/git-checkout.d.ts +76 -0
  462. package/dist/types/git-checkout.d.ts.map +1 -0
  463. package/dist/types/github.d.ts +51 -0
  464. package/dist/types/github.d.ts.map +1 -0
  465. package/dist/types/workflow.d.ts +237 -0
  466. package/dist/types/workflow.d.ts.map +1 -0
  467. package/dist/utils/command-executor.d.ts +43 -0
  468. package/dist/utils/command-executor.d.ts.map +1 -0
  469. package/dist/utils/comment-metadata.d.ts +21 -0
  470. package/dist/utils/comment-metadata.d.ts.map +1 -0
  471. package/dist/utils/config-loader.d.ts.map +1 -1
  472. package/dist/utils/config-merger.d.ts.map +1 -1
  473. package/dist/utils/env-exposure.d.ts +3 -0
  474. package/dist/utils/env-exposure.d.ts.map +1 -0
  475. package/dist/utils/file-exclusion.d.ts.map +1 -1
  476. package/dist/utils/interactive-prompt.d.ts +1 -1
  477. package/dist/utils/interactive-prompt.d.ts.map +1 -1
  478. package/dist/utils/json-text-extractor.d.ts +17 -0
  479. package/dist/utils/json-text-extractor.d.ts.map +1 -0
  480. package/dist/utils/sandbox.d.ts +10 -0
  481. package/dist/utils/sandbox.d.ts.map +1 -1
  482. package/dist/utils/script-memory-ops.d.ts +21 -0
  483. package/dist/utils/script-memory-ops.d.ts.map +1 -0
  484. package/dist/utils/template-context.d.ts +8 -0
  485. package/dist/utils/template-context.d.ts.map +1 -0
  486. package/dist/utils/tracer-init.d.ts.map +1 -1
  487. package/dist/utils/workspace-manager.d.ts +118 -0
  488. package/dist/utils/workspace-manager.d.ts.map +1 -0
  489. package/dist/utils/worktree-cleanup.d.ts +33 -0
  490. package/dist/utils/worktree-cleanup.d.ts.map +1 -0
  491. package/dist/utils/worktree-manager.d.ts +153 -0
  492. package/dist/utils/worktree-manager.d.ts.map +1 -0
  493. package/dist/webhook-server.d.ts +3 -3
  494. package/dist/webhook-server.d.ts.map +1 -1
  495. package/dist/workflow-executor.d.ts +81 -0
  496. package/dist/workflow-executor.d.ts.map +1 -0
  497. package/dist/workflow-registry.d.ts +79 -0
  498. package/dist/workflow-registry.d.ts.map +1 -0
  499. package/package.json +12 -5
  500. package/dist/output/traces/run-2025-10-22T18-22-56-873Z.ndjson +0 -218
  501. package/dist/sdk/check-execution-engine-2YYKUUSH.mjs +0 -11
  502. package/dist/sdk/check-execution-engine-6QJXYYON.mjs +0 -11
  503. package/dist/sdk/check-execution-engine-PJZ4ZOKG.mjs +0 -11
  504. package/dist/sdk/chunk-33QVZ2D4.mjs +0 -316
  505. package/dist/sdk/chunk-33QVZ2D4.mjs.map +0 -1
  506. package/dist/sdk/chunk-B5QBV2QJ.mjs +0 -752
  507. package/dist/sdk/chunk-B5QBV2QJ.mjs.map +0 -1
  508. package/dist/sdk/chunk-BVFNRCHT.mjs +0 -14129
  509. package/dist/sdk/chunk-BVFNRCHT.mjs.map +0 -1
  510. package/dist/sdk/chunk-KWZW23FG.mjs +0 -14129
  511. package/dist/sdk/chunk-KWZW23FG.mjs.map +0 -1
  512. package/dist/sdk/chunk-O4RP4BRH.mjs +0 -14092
  513. package/dist/sdk/chunk-O4RP4BRH.mjs.map +0 -1
  514. package/dist/sdk/chunk-TUTOLSFV.mjs.map +0 -1
  515. package/dist/sdk/chunk-U5D2LY66.mjs +0 -245
  516. package/dist/sdk/chunk-U5D2LY66.mjs.map +0 -1
  517. package/dist/sdk/chunk-U7X54EMV.mjs +0 -331
  518. package/dist/sdk/chunk-U7X54EMV.mjs.map +0 -1
  519. package/dist/sdk/config-merger-TWUBWFC2.mjs +0 -8
  520. package/dist/sdk/mermaid-telemetry-SN6A2TKW.mjs +0 -61
  521. package/dist/sdk/mermaid-telemetry-SN6A2TKW.mjs.map +0 -1
  522. package/dist/sdk/mermaid-telemetry-YCTIG76M.mjs +0 -61
  523. package/dist/sdk/mermaid-telemetry-YCTIG76M.mjs.map +0 -1
  524. package/dist/traces/run-2025-10-22T18-22-56-873Z.ndjson +0 -218
  525. /package/dist/sdk/{check-execution-engine-2YYKUUSH.mjs.map → check-provider-registry-534KL5HT.mjs.map} +0 -0
  526. /package/dist/sdk/{check-execution-engine-6QJXYYON.mjs.map → command-executor-TYUV6HUS.mjs.map} +0 -0
  527. /package/dist/sdk/{check-execution-engine-PJZ4ZOKG.mjs.map → config-YNC2EOOT.mjs.map} +0 -0
  528. /package/dist/sdk/{config-merger-TWUBWFC2.mjs.map → config-merger-PX3WIT57.mjs.map} +0 -0
  529. /package/dist/sdk/{liquid-extensions-KVL4MKRH.mjs.map → failure-condition-evaluator-YGTF2GHG.mjs.map} +0 -0
  530. /package/dist/sdk/{tracer-init-WC75N5NW.mjs.map → liquid-extensions-PKWCKK7E.mjs.map} +0 -0
@@ -0,0 +1,193 @@
1
+ # Failure Routing (Retry/Goto/Remediate) — RFC
2
+
3
+ Status: Draft
4
+
5
+ Last updated: 2025-10-03
6
+
7
+ Owner: Visor team
8
+
9
+ ## Objectives
10
+
11
+ - Enable a workflow step to handle failure by retrying, jumping back to a prior step, or running a remediation step, then continuing.
12
+ - Keep runs deterministic and safe: no infinite loops, clear audit trail, reproducible results.
13
+ - Make it ergonomic in YAML and backward-compatible with existing Visor configs.
14
+
15
+ ## Approach
16
+
17
+ - Add “failure routes” to the execution graph: normal success edges remain; failure edges are now explicit.
18
+ - Introduce lightweight “checkpoints” via step IDs (no heavy snapshots). Re-execution rebuilds state deterministically.
19
+ - Provide per-step retry policies with backoff and a global loop budget to avoid livelock.
20
+
21
+ ## Config Sketch (MVP)
22
+
23
+ Proposed additions use Visor’s existing 2.0 style (type/exec/depends_on). New keys are `on_fail`, `on_success`, and optional top‑level `routing` for defaults.
24
+
25
+ ```yaml
26
+ version: "2.0"
27
+
28
+ # Optional global defaults for routing (new)
29
+ routing:
30
+ max_loops: 10 # per-scope cap on routing transitions
31
+ defaults:
32
+ on_fail:
33
+ retry:
34
+ max: 0 # attempts per step on failure (0 = disabled)
35
+ backoff:
36
+ mode: fixed # fixed|exponential
37
+ delay_ms: 2000 # initial delay in milliseconds
38
+
39
+ steps:
40
+ setup-env:
41
+ type: command
42
+ exec: "npm ci"
43
+
44
+ unit-tests:
45
+ type: command
46
+ exec: "npm test"
47
+ on_fail:
48
+ retry: { max: 1, backoff: { mode: fixed, delay_ms: 3000 } }
49
+ goto: setup-env # jump back, then continue forward
50
+ # Dynamic routing alternatives (evaluated on failure):
51
+ # - goto_js returns a step-id or null
52
+ # - run_js returns an array of step-ids or []
53
+ goto_js: |
54
+ // Provided variables: step, attempt, loop, error, foreach, outputs, pr, files
55
+ if (error.message?.includes('module not found')) return 'setup-env';
56
+ return null;
57
+
58
+ run_js: |
59
+ // Optionally compute remediation steps dynamically.
60
+ const fixes = [];
61
+ if (error.stderr?.includes('lint')) fixes.push('lint-fix');
62
+ return fixes;
63
+
64
+ lint-fix:
65
+ type: command
66
+ exec: "npm run lint:fix"
67
+
68
+ build:
69
+ type: command
70
+ exec: "npm run build"
71
+ on_fail:
72
+ run: [lint-fix] # remediation steps
73
+ retry: { max: 1 }
74
+
75
+ summary:
76
+ type: command
77
+ exec: "node scripts/summarize.js"
78
+ on_success:
79
+ run: [notify]
80
+ # Allow goto on success (ancestor-only) with optional dynamic variant
81
+ goto: unit-tests
82
+ goto_js: |
83
+ // Jump back to re-validate if summary indicates retest
84
+ if (/retest/i.test(outputs?.overview ?? '')) return 'unit-tests';
85
+ return null;
86
+
87
+ notify:
88
+ type: command
89
+ exec: "echo notify"
90
+ ```
91
+
92
+ ## Execution Semantics
93
+
94
+ - Retry: Re-run the same step up to `retry.max` with backoff; counts toward `max_loops`.
95
+ - Goto (failure): After retries are exhausted, jump to `goto` step (ancestor-only), then proceed forward to eventually re-run the failed step.
96
+ - Run (failure remediation): On failure, run listed steps in order; if all succeed, re-attempt the failed step once (counted).
97
+ - on_success actions: After a step succeeds, run `on_success.run` plus `run_js` (if any), then optionally `goto`/`goto_js` (ancestor-only). After the jump, proceed forward along the normal path.
98
+ - Loop safety: Maintain per-check attempt counters (for retries) and a per-scope `max_loops` routing counter covering ALL routing transitions (failure and success). Abort with a clear error if exceeded.
99
+ - State: Carry forward run context; recompute outputs of any steps that are re-executed (no stale artifact reuse by default).
100
+ - Telemetry: Log structured events for failure, retry, goto, remediation, and loop-abort to aid debugging.
101
+
102
+ ### Dynamic Routing (goto_js, run_js)
103
+
104
+ - When present, `goto_js` and `run_js` are evaluated inside a safe JS sandbox on routing events:
105
+ - on_fail: evaluate both after a failure.
106
+ - on_success: evaluate `run_js` after success; evaluate `goto_js` after run/run_js.
107
+ - Provided variables (read‑only):
108
+ - `step` – current step metadata: `{ id, tags, group }`.
109
+ - `attempt` – attempt count for this step (1 on first try).
110
+ - `loop` – number of routing transitions taken so far in this scope.
111
+ - `error` – for failures: `{ message, code, stdout, stderr, exitCode }` (truncated strings).
112
+ - `foreach` – if inside forEach: `{ key, index, total, path }`, else `null`.
113
+ - `outputs` – dependency outputs (same as in templates/transform_js).
114
+ - `pr`, `files`, `env` – standard Visor template context.
115
+ - Results:
116
+ - `goto_js`: must return a step-id string or `null`/`undefined`.
117
+ - `run_js`: must return an array of step-id strings (may be empty).
118
+ - Precedence and merge:
119
+ - If `goto_js` returns a valid id, it overrides static `goto`.
120
+ - `run_js` result is concatenated after static `run` (duplicates removed, original order preserved).
121
+ - on_success ordering: execute run/run_js first; then evaluate and apply goto/goto_js.
122
+ - Determinism: No IO, no randomness unless seeded; evaluation is pure and time-limited.
123
+
124
+ ### Safe Evaluation
125
+
126
+ - Engine executes JS via a restricted VM with:
127
+ - Whitelisted globals only: `Math`, `JSON`, limited `Date.now()`; no `require`, no `process`, no timers, no async.
128
+ - CPU time limit (e.g., 25 ms) and memory cap; code size limit (e.g., 8 KB) per evaluation.
129
+ - Inputs are immutable; outputs validated (types, size) before use.
130
+ - Any sandbox violation or timeout is treated as evaluation failure; static `on_fail` keys still apply.
131
+
132
+ ### Loop Counters and Routing Behavior
133
+
134
+ - Per-check counters: Each step maintains its own `attempt` counter; increments on each retry of that step.
135
+ - Per-scope loop budget: `max_loops` is tracked per execution scope and counts ALL routing transitions (failure gotos, success gotos, and remediation-triggered reattempts):
136
+ - Root scope: applies across the top-level graph.
137
+ - `forEach` scope: each item has its own independent loop counter (a separate “parallel universe”).
138
+ - On exceeding `max_loops`, the engine fails the current scope immediately with a clear error (no silent recovery), regardless of whether routing was triggered by failure or success.
139
+ - Counters are keyed by `(scopeId, stepId)`; `scopeId` changes for each `forEach` item.
140
+
141
+ ### forEach Semantics
142
+
143
+ - Each `forEach` item creates an isolated subgraph with:
144
+ - Independent step attempt counters and loop budget.
145
+ - Local name resolution for `goto`/`run`/`*_js` targets (must reference steps within the same scope).
146
+ - Cross-scope jumps are disallowed by default to prevent non-local effects and loops.
147
+ - The `foreach` context exposes `{ key, index, total, path }` to drive dynamic decisions in `*_js` code.
148
+
149
+ ## Engine Work
150
+
151
+ - Represent failure edges in the internal DAG and scheduler.
152
+ - Implement retry/backoff, goto transitions, and remediation chains.
153
+ - Add loop detection with `max_loops` and per-step retry budgets.
154
+ - Validate `goto` targets, detect cycles, and provide actionable errors.
155
+ - Add a JS evaluator module with sandboxing, type guards, and timeouts.
156
+ - Integrate dynamic routing evaluation and precedence rules.
157
+
158
+ ## CLI and UX
159
+
160
+ - Flags: `--on-fail-max-loops`, `--retry-max`, `--no-failure-routing` (to disable feature globally).
161
+ - Run summary shows failure routes taken with timestamps and attempt counts.
162
+ - Debug: when `--debug` is set, include evaluated `*_js` results (with sensitive data redacted), sandbox timing, retry/backoff decisions, goto/run transitions, and per-scope loop counters.
163
+
164
+ ## Tests and Demo
165
+
166
+ - Unit tests: each policy in isolation (retry, goto, remediation, loop-abort, `goto_js`, `run_js`, timeouts, type errors).
167
+ - Integration: top-level and `forEach` flows, ensuring per-item loop isolation and correct scoping.
168
+
169
+ ## Acceptance Criteria
170
+
171
+ - Goto: Given a failing step with `goto: setup-env`, engine jumps to `setup-env`, proceeds, and re-runs the failed step.
172
+ - Remediation: Given `run: [lint-fix]`, if remediation succeeds, the failed step re-runs once; if remediation fails, the run stops with a clear message.
173
+ - Retry: Per-step retries respect backoff and caps; global `max_loops` prevents infinite ping-pong.
174
+ - Compatibility: Configs without `on_fail` behave exactly as today.
175
+ - Observability: Logs show ordered trace of retries and jumps; exit codes reflect final outcome.
176
+ - Dynamic routing: `goto_js` and `run_js` work with pure, time-limited evaluation; precedence and merging behave as specified.
177
+ - forEach: Each item runs with isolated counters; `*_js` receives `foreach` context and cannot jump across scopes.
178
+ - on_success goto: After a step succeeds, `goto` (ancestor-only) can jump back to a prior step; with `max_loops` enforcement the run either converges or fails with a clear trace.
179
+
180
+ ## Open Questions
181
+
182
+ - Should `goto` support only step IDs, or also labeled checkpoints (e.g., `goto_checkpoint`)?
183
+ - Should remediation steps be “ephemeral” (only run on failure) or regular steps reused elsewhere?
184
+ - Any preferred global default (e.g., retry once everywhere with linear 2s backoff)?
185
+ - Should we allow opt-in cross-scope targets via explicit qualifiers (e.g., `parent:setup-env`), guarded by additional loop caps?
186
+
187
+ ## Next Steps
188
+
189
+ 1. Audit current workflow engine & failure handling.
190
+ 2. Finalize config keys and schema validation messages.
191
+ 3. Implement engine changes with loop safeguards.
192
+ 4. Add tests and the `lab-05-retry.yaml` demo.
193
+ 5. Extend docs and workshop slides.
@@ -0,0 +1,507 @@
1
+ # Failure Routing (Auto-fix Loops)
2
+
3
+ This guide explains how to configure Visor to automatically remediate failures and re-run steps until convergence, using safe, deterministic routing.
4
+
5
+ ## What You Can Do
6
+
7
+ - Retry failed steps with backoff (fixed or exponential)
8
+ - Run remediation steps on failure (e.g., `lint-fix`, `npm ci`)
9
+ - Jump back to an ancestor step on failure or success (`goto`)
10
+ - Compute remediation and targets dynamically with safe JS (`run_js`, `goto_js`)
11
+ - Protect against infinite loops with per-scope loop caps and per-step attempt counters
12
+ - Use the same semantics inside forEach branches (each item is isolated)
13
+
14
+ ## Outputs Surface (Routing JS)
15
+
16
+ When writing `run_js`/`goto_js`, you have three accessors:
17
+
18
+ - `outputs['x']` — nearest value for check `x` in the current snapshot and scope.
19
+ - `outputs_raw['x']` — aggregate value for `x` (e.g., the full array from a forEach parent).
20
+ - `outputs.history['x']` (alias: `outputs_history['x']`) — all historical values for `x` up to this snapshot.
21
+
22
+ Precedence for `outputs['x']` in routing sandboxes:
23
+ - If running inside a forEach item of `x`, resolves to that item’s value.
24
+ - Else prefer an ancestor scope value of `x`.
25
+ - Else the latest committed value of `x` in the snapshot.
26
+
27
+ Quick example using `outputs_raw` in `goto_js`:
28
+
29
+ ```yaml
30
+ checks:
31
+ list:
32
+ type: command
33
+ exec: echo '["a","b","c"]'
34
+ forEach: true
35
+
36
+ decide:
37
+ type: script
38
+ depends_on: [list]
39
+ content: 'return { n: (outputs_raw["list"] || []).length }'
40
+ on_success:
41
+ goto_js: |
42
+ // Branch by aggregate size, not per-item value
43
+ return (outputs_raw['list'] || []).length >= 3 ? 'bulk-process' : null;
44
+
45
+ bulk-process: { type: log, message: 'bulk mode' }
46
+ ```
47
+
48
+ Tip: `outputs_raw` is also available in provider templates (AI/command/log/memory), mirroring routing JS.
49
+
50
+ ## Quick Examples
51
+
52
+ Retry + goto on failure:
53
+ ```yaml
54
+ version: "2.0"
55
+ routing: { max_loops: 5 }
56
+ steps:
57
+ setup: { type: command, exec: "echo setup" }
58
+ build:
59
+ type: command
60
+ depends_on: [setup]
61
+ exec: |
62
+ test -f .ok || (echo first try fails >&2; touch .ok; exit 1)
63
+ echo ok
64
+ on_fail:
65
+ goto: setup
66
+ retry: { max: 1, backoff: { mode: exponential, delay_ms: 400 } }
67
+ ```
68
+
69
+ on_success jump-back once + post-steps:
70
+ ```yaml
71
+ steps:
72
+ unit: { type: command, exec: "echo unit" }
73
+ build:
74
+ type: command
75
+ depends_on: [unit]
76
+ exec: "echo build"
77
+ on_success:
78
+ run: [notify]
79
+ goto_js: |
80
+ return attempt === 1 ? 'unit' : null; # only once
81
+ notify: { type: command, exec: "echo notify" }
82
+ ```
83
+
84
+ Note on outputs access:
85
+ - `outputs['step-id']` returns the latest value for that step in the current snapshot.
86
+ - `outputs.history['step-id']` returns the cross-loop history array.
87
+ - `outputs_history['step-id']` is an alias for `outputs.history['step-id']` and is available in routing JS and provider templates.
88
+ See [Output History](./output-history.md) for more details.
89
+
90
+ forEach remediation with retry:
91
+ ```yaml
92
+ steps:
93
+ list: { type: command, exec: "echo '[\\"a\\",\\"b\\"]'", forEach: true }
94
+ mark: { type: command, depends_on: [list], exec: "touch .m_{{ outputs.list }}" }
95
+ process:
96
+ type: command
97
+ depends_on: [list]
98
+ exec: "test -f .m_{{ outputs.list }} || exit 1"
99
+ on_fail:
100
+ run: [mark]
101
+ retry: { max: 1 }
102
+ ```
103
+
104
+ ## Configuration Keys
105
+
106
+ Top-level defaults (optional):
107
+ ```yaml
108
+ routing:
109
+ max_loops: 10 # per-scope cap on routing transitions
110
+ defaults:
111
+ on_fail:
112
+ retry: { max: 1, backoff: { mode: fixed, delay_ms: 300 } }
113
+ ```
114
+
115
+ Per-step actions:
116
+ - `on_fail`:
117
+ - `retry`: `{ max, backoff: { mode: fixed|exponential, delay_ms } }`
118
+ - `run`: `[step-id, …]`
119
+ - `goto`: `step-id` (ancestor-only)
120
+ - `run_js`: JS returning `string[]`
121
+ - `goto_js`: JS returning `string | null`
122
+ - `on_success`:
123
+ - `run`, `goto`, `run_js`, `goto_js` (same types and constraints as above)
124
+
125
+ ## Semantics
126
+
127
+ - Retry: re-run the same step up to `retry.max`; backoff adds fixed or exponential delay with deterministic jitter.
128
+ - Run: on failure (or success), run listed steps first; if successful, the failed step is re-attempted once (failure path).
129
+ - Goto (ancestor-only): jump back to a previously executed dependency, then continue forward. On success, Visor re-runs the current step once after the jump.
130
+ - Loop safety: `routing.max_loops` counts all routing transitions (runs, gotos, retries). Exceeding it aborts the current scope with a clear error. For a hard cap on repeated executions of the same step, see [Execution Limits](./limits.md).
131
+ - forEach: each item is isolated with its own loop/attempt counters; `*_js` receives `{ foreach: { index, total, parent } }`.
132
+
133
+ ### Fan‑out vs. Reduce (Phase 5)
134
+
135
+ You can control how routing targets behave when invoked from a forEach context:
136
+
137
+ - `fanout: map` — schedule the target once per item (runs under each item scope).
138
+ - `fanout: reduce` (or `reduce: true`) — schedule a single aggregation run (default/back‑compat).
139
+
140
+ Where it applies:
141
+ - on_success.run / on_success.goto
142
+ - on_fail.run / on_fail.goto
143
+ - on_finish.run / on_finish.goto (when defined on the forEach producer)
144
+
145
+ Example — per‑item side‑effects via routing:
146
+ ```yaml
147
+ checks:
148
+ list:
149
+ type: command
150
+ exec: echo '["a","b","c"]'
151
+ forEach: true
152
+ on_success:
153
+ run: [notify-item]
154
+
155
+ notify-item:
156
+ type: log
157
+ fanout: map # ← run once for each item from 'list'
158
+ message: "Item: {{ outputs['list'] }}"
159
+ ```
160
+
161
+ Example — single aggregation after forEach:
162
+ ```yaml
163
+ checks:
164
+ extract:
165
+ forEach: true
166
+ on_success:
167
+ run: [summarize]
168
+
169
+ summarize:
170
+ type: script
171
+ fanout: reduce # ← single run
172
+ content: |
173
+ const arr = outputs_raw['extract'] || [];
174
+ return { total: arr.length };
175
+ ```
176
+
177
+ ## Goto Event Override (goto_event)
178
+
179
+ You can instruct a `goto` jump to simulate a different event so that the target step is filtered as if that event occurred. This is useful when you need to re-run an ancestor step under PR semantics from a different context (e.g., from an issue comment or internal assistant flow).
180
+
181
+ Key points:
182
+ - Add `goto_event: <event>` alongside `goto` or use it with `goto_js`.
183
+ - Valid values are the same as `on:` triggers (e.g., `pr_updated`, `pr_opened`, `issue_comment`, `issue_opened`).
184
+ - During the inline `goto` execution, Visor sets an internal event override:
185
+ - Event filtering uses the overridden event for the target step.
186
+ - `if:` expressions see `event.event_name` derived from the override (e.g., `pr_*` → `pull_request`, `issue_comment` → `issue_comment`, `issue_*` → `issues`).
187
+ - After the jump, the current step is re-run once; the override applies only to the inline target and that immediate re-run.
188
+ - `goto` remains ancestor-only.
189
+
190
+ Example: After `security` succeeds, jump back to `overview` and re-run `security`, evaluating both as if a PR update happened:
191
+
192
+ ```yaml
193
+ steps:
194
+ overview:
195
+ type: ai
196
+ on: [pr_opened, pr_updated]
197
+
198
+ security:
199
+ type: ai
200
+ depends_on: [overview]
201
+ on: [pr_opened, pr_updated]
202
+ on_success:
203
+ goto: overview # ancestor-only
204
+ goto_event: pr_updated # simulate PR updated during the jump
205
+ ```
206
+
207
+ Dynamic variant (only jump on first success):
208
+
209
+ ```yaml
210
+ steps:
211
+ quality:
212
+ type: ai
213
+ depends_on: [overview]
214
+ on: [pr_opened, pr_updated]
215
+ on_success:
216
+ goto_js: |
217
+ return attempt === 1 ? 'overview' : null
218
+ goto_event: pr_updated
219
+ ```
220
+
221
+ When to use goto_event vs. full re-run:
222
+ - Use `goto_event` for a targeted, in-process jump to a specific ancestor step with PR semantics.
223
+ - Use a higher-level “internal re-invoke” (e.g., synthesize a `pull_request` `synchronize` event and call the action entrypoint) when you need to re-run the entire PR workflow chain from an issue comment trigger.
224
+
225
+ ## Dynamic JS (safe, sync only)
226
+
227
+ - `goto_js` / `run_js` are evaluated in a sandbox with:
228
+ - Read-only context: `{ step, attempt, loop, error, foreach, outputs, pr, files, env }`
229
+ - `outputs` contains current values, `outputs.history` contains arrays of all previous values (see [Output History](./output-history.md))
230
+ - Pure sync execution; no IO, no async, no timers, no require/process.
231
+ - Time and size limits (short wall time; small code/output caps) — evaluation failures fall back to static routing.
232
+
233
+ Return types:
234
+ - `goto_js`: a `string` (step id) or `null`/`undefined` to skip.
235
+ - `run_js`: a `string[]` (may be empty). Duplicates are removed preserving order.
236
+
237
+ ## Guardrails & Tips
238
+
239
+ - Keep `max_loops` small (5–10). Add retries sparingly and prefer remediation over blind loops.
240
+ - Restrict `goto` to ancestors to preserve dependency semantics and avoid hard-to-reason paths.
241
+ - For expensive remediations, put them behind `run_js` conditions keyed to `error.message`/`stderr`.
242
+ - In CI, you can override defaults with CLI flags (future): `--on-fail-max-loops`, `--retry-max`.
243
+
244
+ ## on_finish Hook (forEach Aggregation & Routing)
245
+
246
+ The `on_finish` hook is a special routing action that triggers **once** after a `forEach` check completes **all** of its dependent checks across **all** iterations. This is the ideal place to aggregate results from forEach iterations and make routing decisions based on the collective outcome.
247
+
248
+ ### When on_finish Triggers
249
+
250
+ - Only on checks with `forEach: true`
251
+ - Triggers **after** all dependent checks complete all their iterations
252
+ - Does **not** trigger if the forEach array is empty
253
+ - Executes even if some iterations failed (you decide how to handle failures)
254
+
255
+ ### Execution Order
256
+
257
+ ```
258
+ forEach check executes once → outputs array [item1, item2, ...]
259
+
260
+ All dependent checks execute N times (forEach propagation)
261
+ - dependent-check runs for item1
262
+ - dependent-check runs for item2
263
+ - ...
264
+
265
+ on_finish.run executes (checks run sequentially in order)
266
+
267
+ on_finish.run_js evaluates (dynamic check selection)
268
+
269
+ on_finish.goto_js evaluates (routing decision)
270
+
271
+ If goto returned, jump to ancestor check and re-run current check
272
+ ```
273
+
274
+ ### How It Differs from on_success and on_fail
275
+
276
+ | Hook | Triggers When | Use Case |
277
+ |------|--------------|----------|
278
+ | `on_fail` | Check fails | Handle single check failure, retry, remediate |
279
+ | `on_success` | Check succeeds | Post-process single check success |
280
+ | `on_finish` | **All** forEach dependents complete | Aggregate **all** forEach iteration results, decide next step |
281
+
282
+ Key difference: `on_finish` sees the **complete picture** of all forEach iterations and all dependent check results, making it perfect for validation and aggregation scenarios.
283
+
284
+ ### Available Context in on_finish
285
+
286
+ The `on_finish` hooks have access to the complete execution context:
287
+
288
+ ```javascript
289
+ {
290
+ step: { id: 'extract-facts', tags: [...], group: '...' },
291
+ attempt: 1, // Current attempt number for this check
292
+ loop: 2, // Current loop number in routing
293
+ outputs: {
294
+ 'extract-facts': [...], // Array of forEach items
295
+ 'validate-fact': [...], // Array of ALL dependent results
296
+ },
297
+ outputs.history: {
298
+ 'extract-facts': [[...], ...], // Cross-loop history
299
+ 'validate-fact': [[...], ...], // All results from all iterations
300
+ },
301
+ // Alias (also available):
302
+ outputs_history: {
303
+ 'extract-facts': [[...], ...],
304
+ 'validate-fact': [[...], ...],
305
+ },
306
+ forEach: {
307
+ total: 3, // Total number of items
308
+ successful: 3, // Number of successful iterations
309
+ failed: 0, // Number of failed iterations
310
+ items: [...] // The forEach items array
311
+ },
312
+ memory, // Memory access functions
313
+ pr, // PR metadata
314
+ files, // Changed files
315
+ env // Environment variables
316
+ }
317
+ ```
318
+
319
+ ### Configuration
320
+
321
+ ```yaml
322
+ checks:
323
+ extract-facts:
324
+ type: ai
325
+ forEach: true
326
+ # ... regular check configuration ...
327
+
328
+ on_finish:
329
+ # Optional: Run additional checks to aggregate results
330
+ run: [aggregate-validations]
331
+
332
+ # Optional: Dynamically compute additional checks to run
333
+ run_js: |
334
+ return error ? ['log-error'] : [];
335
+
336
+ # Optional: Static routing decision
337
+ goto: previous-check
338
+
339
+ # Optional: Dynamic routing decision
340
+ goto_js: |
341
+ const allValid = memory.get('all_facts_valid', 'fact-validation');
342
+ const attempt = memory.get('fact_validation_attempt', 'fact-validation') || 0;
343
+
344
+ if (allValid) {
345
+ return null; // Continue normal flow
346
+ }
347
+
348
+ if (attempt >= 1) {
349
+ return null; // Max attempts reached, give up
350
+ }
351
+
352
+ // Retry with correction context
353
+ memory.increment('fact_validation_attempt', 1, 'fact-validation');
354
+ return 'issue-assistant'; // Jump back to ancestor
355
+
356
+ # Optional: Override event for goto target
357
+ goto_event: pr_updated
358
+ ```
359
+
360
+ ### Common Patterns
361
+
362
+ #### Pattern 1: Validation with Retry
363
+
364
+ Aggregate validation results and retry if any fail:
365
+
366
+ ```yaml
367
+ checks:
368
+ extract-claims:
369
+ type: ai
370
+ forEach: true
371
+ transform_js: JSON.parse(output).claims
372
+ on_finish:
373
+ run: [aggregate-results]
374
+ goto_js: |
375
+ const allValid = memory.get('all_valid', 'validation');
376
+ const attempt = memory.get('attempt', 'validation') || 0;
377
+
378
+ if (allValid || attempt >= 2) {
379
+ return null; // Success or max attempts
380
+ }
381
+
382
+ memory.increment('attempt', 1, 'validation');
383
+ return 'generate-response'; // Retry
384
+
385
+ validate-claim:
386
+ type: ai
387
+ depends_on: [extract-claims]
388
+ # Validates each claim individually
389
+
390
+ aggregate-results:
391
+ type: script
392
+ content: |
393
+ const results = outputs.history['validate-claim'];
394
+ const allValid = results.every(r => r.is_valid);
395
+ memory.set('all_valid', allValid, 'validation');
396
+ return { total: results.length, valid: results.filter(r => r.is_valid).length };
397
+ ```
398
+
399
+ #### Pattern 2: Conditional Post-Processing
400
+
401
+ Run different post-processing based on forEach results:
402
+
403
+ ```yaml
404
+ checks:
405
+ scan-files:
406
+ type: command
407
+ forEach: true
408
+ exec: "find . -name '*.ts'"
409
+ on_finish:
410
+ run_js: |
411
+ const hasErrors = outputs.history['analyze-file'].some(r => r.errors > 0);
412
+ return hasErrors ? ['generate-fix-pr'] : ['post-success-comment'];
413
+
414
+ analyze-file:
415
+ type: command
416
+ depends_on: [scan-files]
417
+ exec: "eslint {{ outputs['scan-files'] }}"
418
+ ```
419
+
420
+ #### Pattern 3: Multi-Dependent Aggregation
421
+
422
+ Aggregate results from **multiple** dependent checks:
423
+
424
+ ```yaml
425
+ checks:
426
+ extract-facts:
427
+ type: ai
428
+ forEach: true
429
+ on_finish:
430
+ run: [aggregate-all-validations]
431
+ goto_js: |
432
+ const securityValid = memory.get('security_valid', 'validation');
433
+ const technicalValid = memory.get('technical_valid', 'validation');
434
+ const formatValid = memory.get('format_valid', 'validation');
435
+
436
+ if (!securityValid || !technicalValid || !formatValid) {
437
+ return 'retry-with-context';
438
+ }
439
+ return null;
440
+
441
+ validate-security:
442
+ type: ai
443
+ depends_on: [extract-facts]
444
+ # Runs N times, validates security aspects
445
+
446
+ validate-technical:
447
+ type: ai
448
+ depends_on: [extract-facts]
449
+ # Runs N times, validates technical aspects
450
+
451
+ validate-format:
452
+ type: ai
453
+ depends_on: [extract-facts]
454
+ # Runs N times, validates format/style
455
+
456
+ aggregate-all-validations:
457
+ type: script
458
+ content: |
459
+ // Access ALL results from ALL dependent checks
460
+ const securityResults = outputs.history['validate-security'];
461
+ const technicalResults = outputs.history['validate-technical'];
462
+ const formatResults = outputs.history['validate-format'];
463
+
464
+ memory.set('security_valid', securityResults.every(r => r.is_valid), 'validation');
465
+ memory.set('technical_valid', technicalResults.every(r => r.is_valid), 'validation');
466
+ memory.set('format_valid', formatResults.every(r => r.is_valid), 'validation');
467
+
468
+ return { aggregated: true };
469
+ ```
470
+
471
+ ### Error Handling
472
+
473
+ - If `on_finish.run` checks fail, the forEach check is marked as failed
474
+ - If `goto_js` throws an error, the engine falls back to static `goto` (if present)
475
+ - Clear error messages are logged for debugging
476
+ - Loop safety: `on_finish.goto` counts toward `max_loops`
477
+
478
+ ### Best Practices
479
+
480
+ 1. **Use for Aggregation**: Perfect for collecting and analyzing results from all forEach iterations
481
+ 2. **Memory for State**: Store aggregated results in memory for use in routing decisions and downstream checks
482
+ 3. **Fail Gracefully**: Handle both success and failure scenarios in `goto_js`
483
+ 4. **Limit Retries**: Use attempt counters to prevent infinite loops
484
+ 5. **Log Decisions**: Use `log()` in JS to debug routing decisions
485
+ 6. **Validate First**: Run aggregation checks before routing to ensure data is ready
486
+
487
+ ### Debugging
488
+
489
+ ```javascript
490
+ // In on_finish.goto_js
491
+ log('forEach stats:', forEach);
492
+ log('All results:', outputs.history['dependent-check']);
493
+ log('Current attempt:', attempt, 'loop:', loop);
494
+
495
+ const results = outputs.history['validate-fact'];
496
+ log('Valid:', results.filter(r => r.is_valid).length);
497
+ log('Invalid:', results.filter(r => !r.is_valid).length);
498
+ ```
499
+
500
+ ## Full Examples
501
+
502
+ See the repository examples:
503
+ - `examples/routing-basic.yaml`
504
+ - `examples/routing-on-success.yaml`
505
+ - `examples/routing-foreach.yaml`
506
+ - `examples/routing-dynamic-js.yaml`
507
+ - `examples/fact-validator.yaml` - Complete `on_finish` example with validation and retry