smol-symphony 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (716) hide show
  1. package/AGENTS.md +41 -22
  2. package/DESIGN.md +494 -273
  3. package/README.md +109 -57
  4. package/SPEC.md +33 -24
  5. package/WORKFLOW.minimal.yaml +34 -0
  6. package/{WORKFLOW.template.md → WORKFLOW.template.yaml} +409 -256
  7. package/WORKFLOW.yaml +487 -0
  8. package/assets/skills/symphony-issues/SKILL.md +136 -0
  9. package/assets/symphony-mise.system.toml +68 -0
  10. package/dist/src/bin/symphony.js +30 -0
  11. package/dist/src/bin/symphony.js.map +1 -0
  12. package/dist/src/core/actions/context.js +109 -0
  13. package/dist/src/core/actions/context.js.map +1 -0
  14. package/dist/{actions/parsing.js → src/core/actions/parse.js} +33 -114
  15. package/dist/src/core/actions/parse.js.map +1 -0
  16. package/dist/src/core/actions/plan.js +197 -0
  17. package/dist/src/core/actions/plan.js.map +1 -0
  18. package/dist/src/core/actions/predicates.js +111 -0
  19. package/dist/src/core/actions/predicates.js.map +1 -0
  20. package/dist/src/core/actions/run-fold.js +248 -0
  21. package/dist/src/core/actions/run-fold.js.map +1 -0
  22. package/dist/src/core/actions/template.js +118 -0
  23. package/dist/src/core/actions/template.js.map +1 -0
  24. package/dist/src/core/cli/args.js +116 -0
  25. package/dist/src/core/cli/args.js.map +1 -0
  26. package/dist/src/core/coerce.js +75 -0
  27. package/dist/src/core/coerce.js.map +1 -0
  28. package/dist/src/core/credential/account-id.js +20 -0
  29. package/dist/src/core/credential/account-id.js.map +1 -0
  30. package/dist/src/core/credential/adapter-config.js +136 -0
  31. package/dist/src/core/credential/adapter-config.js.map +1 -0
  32. package/dist/src/core/credential/availability.js +98 -0
  33. package/dist/src/core/credential/availability.js.map +1 -0
  34. package/dist/src/core/credential/extract.js +228 -0
  35. package/dist/src/core/credential/extract.js.map +1 -0
  36. package/dist/src/core/credential/fake-creds.js +171 -0
  37. package/dist/src/core/credential/fake-creds.js.map +1 -0
  38. package/dist/src/core/credential/identity.js +125 -0
  39. package/dist/src/core/credential/identity.js.map +1 -0
  40. package/dist/src/core/credential/shape.js +230 -0
  41. package/dist/src/core/credential/shape.js.map +1 -0
  42. package/dist/src/core/credential/strings.js +15 -0
  43. package/dist/src/core/credential/strings.js.map +1 -0
  44. package/dist/src/core/doctor/checks.js +303 -0
  45. package/dist/src/core/doctor/checks.js.map +1 -0
  46. package/dist/src/core/git/result.js +107 -0
  47. package/dist/src/core/git/result.js.map +1 -0
  48. package/dist/src/core/http/decisions.js +225 -0
  49. package/dist/src/core/http/decisions.js.map +1 -0
  50. package/dist/{http.js → src/core/http/render.js} +472 -738
  51. package/dist/src/core/http/render.js.map +1 -0
  52. package/dist/{http-handlers.js → src/core/http/routes.js} +52 -87
  53. package/dist/src/core/http/routes.js.map +1 -0
  54. package/dist/src/core/http/views.js +181 -0
  55. package/dist/src/core/http/views.js.map +1 -0
  56. package/dist/src/core/image/managed-image.js +95 -0
  57. package/dist/src/core/image/managed-image.js.map +1 -0
  58. package/dist/src/core/issue/file.js +149 -0
  59. package/dist/src/core/issue/file.js.map +1 -0
  60. package/dist/src/core/issue/parse.js +210 -0
  61. package/dist/src/core/issue/parse.js.map +1 -0
  62. package/dist/src/core/mcp/dispatch.js +239 -0
  63. package/dist/src/core/mcp/dispatch.js.map +1 -0
  64. package/dist/src/core/mcp/post-move.js +92 -0
  65. package/dist/src/core/mcp/post-move.js.map +1 -0
  66. package/dist/src/core/mcp/protocol.js +293 -0
  67. package/dist/src/core/mcp/protocol.js.map +1 -0
  68. package/dist/src/core/mcp/url.js +162 -0
  69. package/dist/src/core/mcp/url.js.map +1 -0
  70. package/dist/src/core/path.js +63 -0
  71. package/dist/src/core/path.js.map +1 -0
  72. package/dist/src/core/reconcile/image-decide.js +48 -0
  73. package/dist/src/core/reconcile/image-decide.js.map +1 -0
  74. package/dist/src/core/reconcile/ledger.js +142 -0
  75. package/dist/src/core/reconcile/ledger.js.map +1 -0
  76. package/dist/src/core/reconcile/pr-classify.js +62 -0
  77. package/dist/src/core/reconcile/pr-classify.js.map +1 -0
  78. package/dist/{reconciler → src/core/reconcile}/pr-decide.js +25 -12
  79. package/dist/src/core/reconcile/pr-decide.js.map +1 -0
  80. package/dist/src/core/reconcile/pr-loop.js +161 -0
  81. package/dist/src/core/reconcile/pr-loop.js.map +1 -0
  82. package/dist/src/core/reconcile/pr-notes.js +35 -0
  83. package/dist/src/core/reconcile/pr-notes.js.map +1 -0
  84. package/dist/src/core/reconcile/vm-decide.js +70 -0
  85. package/dist/src/core/reconcile/vm-decide.js.map +1 -0
  86. package/dist/src/core/reconcile/vm-reap.js +207 -0
  87. package/dist/src/core/reconcile/vm-reap.js.map +1 -0
  88. package/dist/src/core/reconcile/workspace-decide.js +162 -0
  89. package/dist/src/core/reconcile/workspace-decide.js.map +1 -0
  90. package/dist/src/core/runlog/summary.js +231 -0
  91. package/dist/src/core/runlog/summary.js.map +1 -0
  92. package/dist/src/core/runner/dispatch-config.js +95 -0
  93. package/dist/src/core/runner/dispatch-config.js.map +1 -0
  94. package/dist/src/core/runner/injection.js +61 -0
  95. package/dist/src/core/runner/injection.js.map +1 -0
  96. package/dist/src/core/runner/mise.js +210 -0
  97. package/dist/src/core/runner/mise.js.map +1 -0
  98. package/dist/src/core/runner/prompt.js +720 -0
  99. package/dist/src/core/runner/prompt.js.map +1 -0
  100. package/dist/src/core/runner/turn.js +242 -0
  101. package/dist/src/core/runner/turn.js.map +1 -0
  102. package/dist/src/core/runner/vm-plan.js +390 -0
  103. package/dist/src/core/runner/vm-plan.js.map +1 -0
  104. package/dist/src/core/schedule/admission.js +123 -0
  105. package/dist/src/core/schedule/admission.js.map +1 -0
  106. package/dist/src/core/schedule/circuit-breaker.js +111 -0
  107. package/dist/src/core/schedule/circuit-breaker.js.map +1 -0
  108. package/dist/src/core/schedule/eligibility.js +83 -0
  109. package/dist/src/core/schedule/eligibility.js.map +1 -0
  110. package/dist/src/core/schedule/reconcile-issue.js +82 -0
  111. package/dist/src/core/schedule/reconcile-issue.js.map +1 -0
  112. package/dist/src/core/schedule/retry.js +96 -0
  113. package/dist/src/core/schedule/retry.js.map +1 -0
  114. package/dist/src/core/schedule/sleep-cycle.js +133 -0
  115. package/dist/src/core/schedule/sleep-cycle.js.map +1 -0
  116. package/dist/src/core/schedule/slots.js +124 -0
  117. package/dist/src/core/schedule/slots.js.map +1 -0
  118. package/dist/src/core/schedule/tick.js +553 -0
  119. package/dist/src/core/schedule/tick.js.map +1 -0
  120. package/dist/src/core/schedule/token-fold.js +181 -0
  121. package/dist/src/core/schedule/token-fold.js.map +1 -0
  122. package/dist/src/core/state-resolve.js +86 -0
  123. package/dist/src/core/state-resolve.js.map +1 -0
  124. package/dist/src/core/vm-guards.js +278 -0
  125. package/dist/src/core/vm-guards.js.map +1 -0
  126. package/dist/src/core/workflow/derive.js +107 -0
  127. package/dist/src/core/workflow/derive.js.map +1 -0
  128. package/dist/src/core/workflow/parse.js +687 -0
  129. package/dist/src/core/workflow/parse.js.map +1 -0
  130. package/dist/src/core/workflow/prompt-probe.js +78 -0
  131. package/dist/src/core/workflow/prompt-probe.js.map +1 -0
  132. package/dist/src/core/workflow/validate.js +189 -0
  133. package/dist/src/core/workflow/validate.js.map +1 -0
  134. package/dist/src/core/workspace-key.js +19 -0
  135. package/dist/src/core/workspace-key.js.map +1 -0
  136. package/dist/src/shell/actions-runner.js +356 -0
  137. package/dist/src/shell/actions-runner.js.map +1 -0
  138. package/dist/src/shell/adapter/adapter-registry.js +45 -0
  139. package/dist/src/shell/adapter/adapter-registry.js.map +1 -0
  140. package/dist/src/shell/adapter/clock-random.js +96 -0
  141. package/dist/src/shell/adapter/clock-random.js.map +1 -0
  142. package/dist/src/shell/adapter/gondolin-dispatch-helpers.js +158 -0
  143. package/dist/src/shell/adapter/gondolin-dispatch-helpers.js.map +1 -0
  144. package/dist/src/shell/adapter/gondolin-dispatch.js +385 -0
  145. package/dist/src/shell/adapter/gondolin-dispatch.js.map +1 -0
  146. package/dist/src/shell/adapter/gondolin-image-converter.js +233 -0
  147. package/dist/src/shell/adapter/gondolin-image-converter.js.map +1 -0
  148. package/dist/src/shell/adapter/gondolin-image-fetch.js +180 -0
  149. package/dist/src/shell/adapter/gondolin-image-fetch.js.map +1 -0
  150. package/dist/src/shell/adapter/launcher-asset.js +57 -0
  151. package/dist/src/shell/adapter/launcher-asset.js.map +1 -0
  152. package/dist/src/shell/adapter/mise-config-asset.js +65 -0
  153. package/dist/src/shell/adapter/mise-config-asset.js.map +1 -0
  154. package/dist/src/shell/adapter/workflow-loader.js +304 -0
  155. package/dist/src/shell/adapter/workflow-loader.js.map +1 -0
  156. package/dist/src/shell/cli/doctor.js +268 -0
  157. package/dist/src/shell/cli/doctor.js.map +1 -0
  158. package/dist/src/shell/effect-interpreter-families.js +314 -0
  159. package/dist/src/shell/effect-interpreter-families.js.map +1 -0
  160. package/dist/src/shell/effect-interpreter.js +29 -0
  161. package/dist/src/shell/effect-interpreter.js.map +1 -0
  162. package/dist/src/shell/interp/acp-frame.js +137 -0
  163. package/dist/src/shell/interp/acp-frame.js.map +1 -0
  164. package/dist/src/shell/interp/acp-ws-conn.js +320 -0
  165. package/dist/src/shell/interp/acp-ws-conn.js.map +1 -0
  166. package/dist/src/shell/interp/acp-ws-frames.js +159 -0
  167. package/dist/src/shell/interp/acp-ws-frames.js.map +1 -0
  168. package/dist/src/shell/interp/acp-ws.js +197 -0
  169. package/dist/src/shell/interp/acp-ws.js.map +1 -0
  170. package/dist/src/shell/interp/acp.js +319 -0
  171. package/dist/src/shell/interp/acp.js.map +1 -0
  172. package/dist/src/shell/interp/credential-defaults.js +128 -0
  173. package/dist/src/shell/interp/credential-defaults.js.map +1 -0
  174. package/dist/src/shell/interp/credential-hooks.js +149 -0
  175. package/dist/src/shell/interp/credential-hooks.js.map +1 -0
  176. package/dist/src/shell/interp/credential-registry.js +226 -0
  177. package/dist/src/shell/interp/credential-registry.js.map +1 -0
  178. package/dist/src/shell/interp/credential.js +103 -0
  179. package/dist/src/shell/interp/credential.js.map +1 -0
  180. package/dist/src/shell/interp/gh.js +163 -0
  181. package/dist/src/shell/interp/gh.js.map +1 -0
  182. package/dist/src/shell/interp/git.js +28 -0
  183. package/dist/src/shell/interp/git.js.map +1 -0
  184. package/dist/src/shell/interp/log.js +213 -0
  185. package/dist/src/shell/interp/log.js.map +1 -0
  186. package/dist/src/shell/interp/process.js +178 -0
  187. package/dist/src/shell/interp/process.js.map +1 -0
  188. package/dist/src/shell/interp/runlog.js +193 -0
  189. package/dist/src/shell/interp/runlog.js.map +1 -0
  190. package/dist/src/shell/interp/timer.js +64 -0
  191. package/dist/src/shell/interp/timer.js.map +1 -0
  192. package/dist/src/shell/interp/tracker-disk.js +99 -0
  193. package/dist/src/shell/interp/tracker-disk.js.map +1 -0
  194. package/dist/src/shell/interp/tracker-parse.js +71 -0
  195. package/dist/src/shell/interp/tracker-parse.js.map +1 -0
  196. package/dist/src/shell/interp/tracker-scan.js +238 -0
  197. package/dist/src/shell/interp/tracker-scan.js.map +1 -0
  198. package/dist/src/shell/interp/tracker-write.js +91 -0
  199. package/dist/src/shell/interp/tracker-write.js.map +1 -0
  200. package/dist/src/shell/interp/tracker.js +41 -0
  201. package/dist/src/shell/interp/tracker.js.map +1 -0
  202. package/dist/src/shell/interp/tty.js +48 -0
  203. package/dist/src/shell/interp/tty.js.map +1 -0
  204. package/dist/src/shell/interp/vm.js +199 -0
  205. package/dist/src/shell/interp/vm.js.map +1 -0
  206. package/dist/src/shell/interp/workspace.js +310 -0
  207. package/dist/src/shell/interp/workspace.js.map +1 -0
  208. package/dist/src/shell/main-acp.js +78 -0
  209. package/dist/src/shell/main-acp.js.map +1 -0
  210. package/dist/src/shell/main-adapters.js +222 -0
  211. package/dist/src/shell/main-adapters.js.map +1 -0
  212. package/dist/src/shell/main-credential.js +122 -0
  213. package/dist/src/shell/main-credential.js.map +1 -0
  214. package/dist/src/shell/main-doctor.js +22 -0
  215. package/dist/src/shell/main-doctor.js.map +1 -0
  216. package/dist/src/shell/main-entry.js +46 -0
  217. package/dist/src/shell/main-entry.js.map +1 -0
  218. package/dist/src/shell/main-http-csrf.js +45 -0
  219. package/dist/src/shell/main-http-csrf.js.map +1 -0
  220. package/dist/src/shell/main-http-handler.js +389 -0
  221. package/dist/src/shell/main-http-handler.js.map +1 -0
  222. package/dist/src/shell/main-http-mcp.js +122 -0
  223. package/dist/src/shell/main-http-mcp.js.map +1 -0
  224. package/dist/src/shell/main-http-views.js +253 -0
  225. package/dist/src/shell/main-http-views.js.map +1 -0
  226. package/dist/src/shell/main-http.js +76 -0
  227. package/dist/src/shell/main-http.js.map +1 -0
  228. package/dist/src/shell/main-loops.js +130 -0
  229. package/dist/src/shell/main-loops.js.map +1 -0
  230. package/dist/src/shell/main-mcp.js +129 -0
  231. package/dist/src/shell/main-mcp.js.map +1 -0
  232. package/dist/src/shell/main-orchestrator.js +120 -0
  233. package/dist/src/shell/main-orchestrator.js.map +1 -0
  234. package/dist/src/shell/main-preflight.js +43 -0
  235. package/dist/src/shell/main-preflight.js.map +1 -0
  236. package/dist/src/shell/main-reconcilers-helpers.js +244 -0
  237. package/dist/src/shell/main-reconcilers-helpers.js.map +1 -0
  238. package/dist/src/shell/main-reconcilers-pr.js +148 -0
  239. package/dist/src/shell/main-reconcilers-pr.js.map +1 -0
  240. package/dist/src/shell/main-reconcilers.js +225 -0
  241. package/dist/src/shell/main-reconcilers.js.map +1 -0
  242. package/dist/src/shell/main-runner.js +355 -0
  243. package/dist/src/shell/main-runner.js.map +1 -0
  244. package/dist/src/shell/main-scaffold.js +116 -0
  245. package/dist/src/shell/main-scaffold.js.map +1 -0
  246. package/dist/src/shell/main-shutdown.js +115 -0
  247. package/dist/src/shell/main-shutdown.js.map +1 -0
  248. package/dist/src/shell/main-startup.js +48 -0
  249. package/dist/src/shell/main-startup.js.map +1 -0
  250. package/dist/src/shell/main-substrates.js +43 -0
  251. package/dist/src/shell/main-substrates.js.map +1 -0
  252. package/dist/src/shell/main.js +385 -0
  253. package/dist/src/shell/main.js.map +1 -0
  254. package/dist/src/shell/orchestrator-feedback.js +69 -0
  255. package/dist/src/shell/orchestrator-feedback.js.map +1 -0
  256. package/dist/src/shell/orchestrator-image.js +167 -0
  257. package/dist/src/shell/orchestrator-image.js.map +1 -0
  258. package/dist/src/shell/orchestrator-loop.js +468 -0
  259. package/dist/src/shell/orchestrator-loop.js.map +1 -0
  260. package/dist/src/shell/orchestrator-reconcile.js +36 -0
  261. package/dist/src/shell/orchestrator-reconcile.js.map +1 -0
  262. package/dist/src/shell/reconciler-loop.js +228 -0
  263. package/dist/src/shell/reconciler-loop.js.map +1 -0
  264. package/dist/src/shell/runner-loop-turn.js +301 -0
  265. package/dist/src/shell/runner-loop-turn.js.map +1 -0
  266. package/dist/src/shell/runner-loop.js +338 -0
  267. package/dist/src/shell/runner-loop.js.map +1 -0
  268. package/dist/src/shell/server/http.js +208 -0
  269. package/dist/src/shell/server/http.js.map +1 -0
  270. package/dist/src/shell/server/mcp-runtime-effects.js +237 -0
  271. package/dist/src/shell/server/mcp-runtime-effects.js.map +1 -0
  272. package/dist/src/shell/server/mcp-runtime.js +99 -0
  273. package/dist/src/shell/server/mcp-runtime.js.map +1 -0
  274. package/dist/src/shell/workspace-key.js +14 -0
  275. package/dist/src/shell/workspace-key.js.map +1 -0
  276. package/dist/src/types/acp.js +8 -0
  277. package/dist/src/types/acp.js.map +1 -0
  278. package/dist/src/types/actions/plan.js +6 -0
  279. package/dist/src/types/actions/plan.js.map +1 -0
  280. package/dist/src/types/actions/predicates.js +6 -0
  281. package/dist/src/types/actions/predicates.js.map +1 -0
  282. package/dist/src/types/actions/run-fold.js +8 -0
  283. package/dist/src/types/actions/run-fold.js.map +1 -0
  284. package/dist/src/types/actions.js +7 -0
  285. package/dist/src/types/actions.js.map +1 -0
  286. package/dist/src/types/adapter/clock-random.js +4 -0
  287. package/dist/src/types/adapter/clock-random.js.map +1 -0
  288. package/dist/src/types/adapter/gondolin-image-converter.js +5 -0
  289. package/dist/src/types/adapter/gondolin-image-converter.js.map +1 -0
  290. package/dist/src/types/adapter/gondolin-image-fetch.js +5 -0
  291. package/dist/src/types/adapter/gondolin-image-fetch.js.map +1 -0
  292. package/dist/src/types/adapter/workflow-loader.js +4 -0
  293. package/dist/src/types/adapter/workflow-loader.js.map +1 -0
  294. package/dist/src/types/cli/args.js +8 -0
  295. package/dist/src/types/cli/args.js.map +1 -0
  296. package/dist/src/types/config.js +8 -0
  297. package/dist/src/types/config.js.map +1 -0
  298. package/dist/src/types/credential-interp.js +6 -0
  299. package/dist/src/types/credential-interp.js.map +1 -0
  300. package/dist/src/types/credentials.js +10 -0
  301. package/dist/src/types/credentials.js.map +1 -0
  302. package/dist/src/types/doctor.js +7 -0
  303. package/dist/src/types/doctor.js.map +1 -0
  304. package/dist/src/types/domain.js +7 -0
  305. package/dist/src/types/domain.js.map +1 -0
  306. package/dist/src/types/effect.js +15 -0
  307. package/dist/src/types/effect.js.map +1 -0
  308. package/dist/src/types/errors.js +39 -0
  309. package/dist/src/types/errors.js.map +1 -0
  310. package/dist/src/types/http/decisions.js +6 -0
  311. package/dist/src/types/http/decisions.js.map +1 -0
  312. package/dist/src/types/http/render.js +10 -0
  313. package/dist/src/types/http/render.js.map +1 -0
  314. package/dist/src/types/http/views.js +6 -0
  315. package/dist/src/types/http/views.js.map +1 -0
  316. package/dist/src/types/http.js +9 -0
  317. package/dist/src/types/http.js.map +1 -0
  318. package/dist/src/types/image/managed-image.js +7 -0
  319. package/dist/src/types/image/managed-image.js.map +1 -0
  320. package/dist/src/types/interp/effect-interpreter.js +8 -0
  321. package/dist/src/types/interp/effect-interpreter.js.map +1 -0
  322. package/dist/src/types/interp/tracker.js +7 -0
  323. package/dist/src/types/interp/tracker.js.map +1 -0
  324. package/dist/src/types/issue/file.js +6 -0
  325. package/dist/src/types/issue/file.js.map +1 -0
  326. package/dist/src/types/issue/parse.js +8 -0
  327. package/dist/src/types/issue/parse.js.map +1 -0
  328. package/dist/src/types/main-acp.js +13 -0
  329. package/dist/src/types/main-acp.js.map +1 -0
  330. package/dist/src/types/main-adapters.js +5 -0
  331. package/dist/src/types/main-adapters.js.map +1 -0
  332. package/dist/src/types/main-credential.js +21 -0
  333. package/dist/src/types/main-credential.js.map +1 -0
  334. package/dist/src/types/main-doctor.js +6 -0
  335. package/dist/src/types/main-doctor.js.map +1 -0
  336. package/dist/src/types/main-http-handler.js +12 -0
  337. package/dist/src/types/main-http-handler.js.map +1 -0
  338. package/dist/src/types/main-http.js +5 -0
  339. package/dist/src/types/main-http.js.map +1 -0
  340. package/dist/src/types/main-loops.js +5 -0
  341. package/dist/src/types/main-loops.js.map +1 -0
  342. package/dist/src/types/main-mcp.js +12 -0
  343. package/dist/src/types/main-mcp.js.map +1 -0
  344. package/dist/src/types/main-orchestrator.js +5 -0
  345. package/dist/src/types/main-orchestrator.js.map +1 -0
  346. package/dist/src/types/main-reconcilers.js +11 -0
  347. package/dist/src/types/main-reconcilers.js.map +1 -0
  348. package/dist/src/types/main-runner.js +13 -0
  349. package/dist/src/types/main-runner.js.map +1 -0
  350. package/dist/src/types/main-startup.js +5 -0
  351. package/dist/src/types/main-startup.js.map +1 -0
  352. package/dist/src/types/main-substrates.js +5 -0
  353. package/dist/src/types/main-substrates.js.map +1 -0
  354. package/dist/src/types/mcp/dispatch.js +4 -0
  355. package/dist/src/types/mcp/dispatch.js.map +1 -0
  356. package/dist/src/types/mcp/post-move.js +7 -0
  357. package/dist/src/types/mcp/post-move.js.map +1 -0
  358. package/dist/src/types/mcp.js +9 -0
  359. package/dist/src/types/mcp.js.map +1 -0
  360. package/dist/src/types/ports.js +12 -0
  361. package/dist/src/types/ports.js.map +1 -0
  362. package/dist/src/types/reconcile/image-decide.js +5 -0
  363. package/dist/src/types/reconcile/image-decide.js.map +1 -0
  364. package/dist/src/types/reconcile/ledger.js +7 -0
  365. package/dist/src/types/reconcile/ledger.js.map +1 -0
  366. package/dist/src/types/reconcile/pr-loop.js +8 -0
  367. package/dist/src/types/reconcile/pr-loop.js.map +1 -0
  368. package/dist/src/types/reconcile/vm-reap.js +8 -0
  369. package/dist/src/types/reconcile/vm-reap.js.map +1 -0
  370. package/dist/src/types/reconcile/workspace-decide.js +7 -0
  371. package/dist/src/types/reconcile/workspace-decide.js.map +1 -0
  372. package/dist/src/types/reconcile.js +9 -0
  373. package/dist/src/types/reconcile.js.map +1 -0
  374. package/dist/src/types/runlog.js +7 -0
  375. package/dist/src/types/runlog.js.map +1 -0
  376. package/dist/src/types/runner/actions-runner.js +12 -0
  377. package/dist/src/types/runner/actions-runner.js.map +1 -0
  378. package/dist/src/types/runner/gondolin-dispatch.js +5 -0
  379. package/dist/src/types/runner/gondolin-dispatch.js.map +1 -0
  380. package/dist/src/types/runner/injection.js +6 -0
  381. package/dist/src/types/runner/injection.js.map +1 -0
  382. package/dist/src/types/runner/runner-loop.js +5 -0
  383. package/dist/src/types/runner/runner-loop.js.map +1 -0
  384. package/dist/src/types/runner/turn.js +4 -0
  385. package/dist/src/types/runner/turn.js.map +1 -0
  386. package/dist/src/types/runner/vm-plan.js +4 -0
  387. package/dist/src/types/runner/vm-plan.js.map +1 -0
  388. package/dist/src/types/runtime.js +9 -0
  389. package/dist/src/types/runtime.js.map +1 -0
  390. package/dist/src/types/schedule/admission.js +7 -0
  391. package/dist/src/types/schedule/admission.js.map +1 -0
  392. package/dist/src/types/schedule/circuit-breaker.js +2 -0
  393. package/dist/src/types/schedule/circuit-breaker.js.map +1 -0
  394. package/dist/src/types/schedule/eligibility.js +9 -0
  395. package/dist/src/types/schedule/eligibility.js.map +1 -0
  396. package/dist/src/types/schedule/orchestrator-loop.js +10 -0
  397. package/dist/src/types/schedule/orchestrator-loop.js.map +1 -0
  398. package/dist/src/types/schedule/sleep-cycle.js +4 -0
  399. package/dist/src/types/schedule/sleep-cycle.js.map +1 -0
  400. package/dist/src/types/schedule/slots.js +8 -0
  401. package/dist/src/types/schedule/slots.js.map +1 -0
  402. package/dist/src/types/schedule/tick.js +9 -0
  403. package/dist/src/types/schedule/tick.js.map +1 -0
  404. package/dist/src/types/server/mcp-runtime.js +8 -0
  405. package/dist/src/types/server/mcp-runtime.js.map +1 -0
  406. package/dist/src/types/workflow/parse.js +4 -0
  407. package/dist/src/types/workflow/parse.js.map +1 -0
  408. package/dist/tests/core/account-id.test.js +35 -0
  409. package/dist/tests/core/account-id.test.js.map +1 -0
  410. package/dist/tests/core/actions-parse.test.js +176 -0
  411. package/dist/tests/core/actions-parse.test.js.map +1 -0
  412. package/dist/tests/core/adapter-config.test.js +133 -0
  413. package/dist/tests/core/adapter-config.test.js.map +1 -0
  414. package/dist/tests/core/admission.test.js +215 -0
  415. package/dist/tests/core/admission.test.js.map +1 -0
  416. package/dist/tests/core/args.test.js +132 -0
  417. package/dist/tests/core/args.test.js.map +1 -0
  418. package/dist/tests/core/availability.test.js +62 -0
  419. package/dist/tests/core/availability.test.js.map +1 -0
  420. package/dist/tests/core/checks.test.js +395 -0
  421. package/dist/tests/core/checks.test.js.map +1 -0
  422. package/dist/tests/core/circuit-breaker.test.js +172 -0
  423. package/dist/tests/core/circuit-breaker.test.js.map +1 -0
  424. package/dist/tests/core/coerce.test.js +87 -0
  425. package/dist/tests/core/coerce.test.js.map +1 -0
  426. package/dist/tests/core/context.test.js +228 -0
  427. package/dist/tests/core/context.test.js.map +1 -0
  428. package/dist/tests/core/decisions.test.js +310 -0
  429. package/dist/tests/core/decisions.test.js.map +1 -0
  430. package/dist/tests/core/derive.test.js +205 -0
  431. package/dist/tests/core/derive.test.js.map +1 -0
  432. package/dist/tests/core/dispatch-config.test.js +164 -0
  433. package/dist/tests/core/dispatch-config.test.js.map +1 -0
  434. package/dist/tests/core/dispatch.test.js +302 -0
  435. package/dist/tests/core/dispatch.test.js.map +1 -0
  436. package/dist/tests/core/eligibility.test.js +163 -0
  437. package/dist/tests/core/eligibility.test.js.map +1 -0
  438. package/dist/tests/core/extract.test.js +139 -0
  439. package/dist/tests/core/extract.test.js.map +1 -0
  440. package/dist/tests/core/fake-creds.test.js +134 -0
  441. package/dist/tests/core/fake-creds.test.js.map +1 -0
  442. package/dist/tests/core/file.test.js +197 -0
  443. package/dist/tests/core/file.test.js.map +1 -0
  444. package/dist/tests/core/git-result.test.js +113 -0
  445. package/dist/tests/core/git-result.test.js.map +1 -0
  446. package/dist/tests/core/identity.test.js +180 -0
  447. package/dist/tests/core/identity.test.js.map +1 -0
  448. package/dist/tests/core/image-decide.test.js +59 -0
  449. package/dist/tests/core/image-decide.test.js.map +1 -0
  450. package/dist/tests/core/injection.test.js +163 -0
  451. package/dist/tests/core/injection.test.js.map +1 -0
  452. package/dist/tests/core/ledger.test.js +218 -0
  453. package/dist/tests/core/ledger.test.js.map +1 -0
  454. package/dist/tests/core/managed-image.test.js +68 -0
  455. package/dist/tests/core/managed-image.test.js.map +1 -0
  456. package/dist/tests/core/mise.test.js +138 -0
  457. package/dist/tests/core/mise.test.js.map +1 -0
  458. package/dist/tests/core/parse.test.js +174 -0
  459. package/dist/tests/core/parse.test.js.map +1 -0
  460. package/dist/tests/core/path.test.js +50 -0
  461. package/dist/tests/core/path.test.js.map +1 -0
  462. package/dist/tests/core/plan.test.js +218 -0
  463. package/dist/tests/core/plan.test.js.map +1 -0
  464. package/dist/tests/core/post-move.test.js +162 -0
  465. package/dist/tests/core/post-move.test.js.map +1 -0
  466. package/dist/tests/core/pr-classify.test.js +117 -0
  467. package/dist/tests/core/pr-classify.test.js.map +1 -0
  468. package/dist/tests/core/pr-decide.test.js +298 -0
  469. package/dist/tests/core/pr-decide.test.js.map +1 -0
  470. package/dist/tests/core/pr-loop.test.js +301 -0
  471. package/dist/tests/core/pr-loop.test.js.map +1 -0
  472. package/dist/tests/core/pr-notes.test.js +165 -0
  473. package/dist/tests/core/pr-notes.test.js.map +1 -0
  474. package/dist/tests/core/predicates.test.js +154 -0
  475. package/dist/tests/core/predicates.test.js.map +1 -0
  476. package/dist/tests/core/prompt.test.js +189 -0
  477. package/dist/tests/core/prompt.test.js.map +1 -0
  478. package/dist/tests/core/protocol.test.js +195 -0
  479. package/dist/tests/core/protocol.test.js.map +1 -0
  480. package/dist/tests/core/reconcile-issue.test.js +116 -0
  481. package/dist/tests/core/reconcile-issue.test.js.map +1 -0
  482. package/dist/tests/core/render.test.js +549 -0
  483. package/dist/tests/core/render.test.js.map +1 -0
  484. package/dist/tests/core/retry.test.js +186 -0
  485. package/dist/tests/core/retry.test.js.map +1 -0
  486. package/dist/tests/core/routes.test.js +247 -0
  487. package/dist/tests/core/routes.test.js.map +1 -0
  488. package/dist/tests/core/run-fold.test.js +299 -0
  489. package/dist/tests/core/run-fold.test.js.map +1 -0
  490. package/dist/tests/core/shape.test.js +185 -0
  491. package/dist/tests/core/shape.test.js.map +1 -0
  492. package/dist/tests/core/sleep-cycle.test.js +150 -0
  493. package/dist/tests/core/sleep-cycle.test.js.map +1 -0
  494. package/dist/tests/core/slots.test.js +201 -0
  495. package/dist/tests/core/slots.test.js.map +1 -0
  496. package/dist/tests/core/state-resolve.test.js +80 -0
  497. package/dist/tests/core/state-resolve.test.js.map +1 -0
  498. package/dist/tests/core/summary.test.js +200 -0
  499. package/dist/tests/core/summary.test.js.map +1 -0
  500. package/dist/tests/core/template.test.js +116 -0
  501. package/dist/tests/core/template.test.js.map +1 -0
  502. package/dist/tests/core/tick.test.js +558 -0
  503. package/dist/tests/core/tick.test.js.map +1 -0
  504. package/dist/tests/core/token-fold.test.js +176 -0
  505. package/dist/tests/core/token-fold.test.js.map +1 -0
  506. package/dist/tests/core/turn.test.js +388 -0
  507. package/dist/tests/core/turn.test.js.map +1 -0
  508. package/dist/tests/core/url.test.js +118 -0
  509. package/dist/tests/core/url.test.js.map +1 -0
  510. package/dist/tests/core/validate.test.js +247 -0
  511. package/dist/tests/core/validate.test.js.map +1 -0
  512. package/dist/tests/core/views.test.js +252 -0
  513. package/dist/tests/core/views.test.js.map +1 -0
  514. package/dist/tests/core/vm-decide.test.js +110 -0
  515. package/dist/tests/core/vm-decide.test.js.map +1 -0
  516. package/dist/tests/core/vm-guards.test.js +153 -0
  517. package/dist/tests/core/vm-guards.test.js.map +1 -0
  518. package/dist/tests/core/vm-plan.test.js +332 -0
  519. package/dist/tests/core/vm-plan.test.js.map +1 -0
  520. package/dist/tests/core/vm-reap.test.js +196 -0
  521. package/dist/tests/core/vm-reap.test.js.map +1 -0
  522. package/dist/tests/core/workflow-parse.test.js +493 -0
  523. package/dist/tests/core/workflow-parse.test.js.map +1 -0
  524. package/dist/tests/core/workspace-decide.test.js +236 -0
  525. package/dist/tests/core/workspace-decide.test.js.map +1 -0
  526. package/dist/tests/helpers/fixtures.js +167 -0
  527. package/dist/tests/helpers/fixtures.js.map +1 -0
  528. package/dist/tests/shell/acp-substrate.test.js +101 -0
  529. package/dist/tests/shell/acp-substrate.test.js.map +1 -0
  530. package/dist/tests/shell/actions-runner-push.test.js +203 -0
  531. package/dist/tests/shell/actions-runner-push.test.js.map +1 -0
  532. package/dist/tests/shell/credential-hooks.test.js +36 -0
  533. package/dist/tests/shell/credential-hooks.test.js.map +1 -0
  534. package/dist/tests/shell/credential-registry.test.js +165 -0
  535. package/dist/tests/shell/credential-registry.test.js.map +1 -0
  536. package/dist/tests/shell/credential-substrate.test.js +179 -0
  537. package/dist/tests/shell/credential-substrate.test.js.map +1 -0
  538. package/dist/tests/shell/dockerfile-mise-pin.test.js +51 -0
  539. package/dist/tests/shell/dockerfile-mise-pin.test.js.map +1 -0
  540. package/dist/tests/shell/doctor.test.js +101 -0
  541. package/dist/tests/shell/doctor.test.js.map +1 -0
  542. package/dist/tests/shell/effect-vm-create.test.js +52 -0
  543. package/dist/tests/shell/effect-vm-create.test.js.map +1 -0
  544. package/dist/tests/shell/gh-port.test.js +63 -0
  545. package/dist/tests/shell/gh-port.test.js.map +1 -0
  546. package/dist/tests/shell/gondolin-dispatch-guard.test.js +144 -0
  547. package/dist/tests/shell/gondolin-dispatch-guard.test.js.map +1 -0
  548. package/dist/tests/shell/gondolin-dispatch-shquote.test.js +168 -0
  549. package/dist/tests/shell/gondolin-dispatch-shquote.test.js.map +1 -0
  550. package/dist/tests/shell/gondolin-image-converter.test.js +208 -0
  551. package/dist/tests/shell/gondolin-image-converter.test.js.map +1 -0
  552. package/dist/tests/shell/gondolin-image-fetch.test.js +93 -0
  553. package/dist/tests/shell/gondolin-image-fetch.test.js.map +1 -0
  554. package/dist/tests/shell/http-handler.test.js +608 -0
  555. package/dist/tests/shell/http-handler.test.js.map +1 -0
  556. package/dist/tests/shell/http-server.test.js +53 -0
  557. package/dist/tests/shell/http-server.test.js.map +1 -0
  558. package/dist/tests/shell/mcp-runtime.test.js +366 -0
  559. package/dist/tests/shell/mcp-runtime.test.js.map +1 -0
  560. package/dist/tests/shell/mise-config-asset.test.js +87 -0
  561. package/dist/tests/shell/mise-config-asset.test.js.map +1 -0
  562. package/dist/tests/shell/orchestrator-loop.test.js +583 -0
  563. package/dist/tests/shell/orchestrator-loop.test.js.map +1 -0
  564. package/dist/tests/shell/reconciler-passes.test.js +314 -0
  565. package/dist/tests/shell/reconciler-passes.test.js.map +1 -0
  566. package/dist/tests/shell/runner-loop-turn.test.js +97 -0
  567. package/dist/tests/shell/runner-loop-turn.test.js.map +1 -0
  568. package/dist/tests/shell/runner-slice.test.js +536 -0
  569. package/dist/tests/shell/runner-slice.test.js.map +1 -0
  570. package/dist/tests/shell/scaffold.test.js +65 -0
  571. package/dist/tests/shell/scaffold.test.js.map +1 -0
  572. package/dist/tests/shell/tick-config.test.js +83 -0
  573. package/dist/tests/shell/tick-config.test.js.map +1 -0
  574. package/dist/tests/shell/tracker-parse-dates.test.js +44 -0
  575. package/dist/tests/shell/tracker-parse-dates.test.js.map +1 -0
  576. package/dist/tests/shell/tracker-write-issue.test.js +154 -0
  577. package/dist/tests/shell/tracker-write-issue.test.js.map +1 -0
  578. package/dist/tests/shell/workflow-prompt-split.test.js +208 -0
  579. package/dist/tests/shell/workflow-prompt-split.test.js.map +1 -0
  580. package/dist/tests/shell/workspace-live-config.test.js +140 -0
  581. package/dist/tests/shell/workspace-live-config.test.js.map +1 -0
  582. package/package.json +21 -9
  583. package/patches/@earendil-works+gondolin+0.12.0.patch +173 -0
  584. package/prompts/Reflect.md +91 -0
  585. package/prompts/Review.md +97 -0
  586. package/prompts/Todo.md +96 -0
  587. package/prompts/_footer.md +41 -0
  588. package/prompts/_preamble.md +42 -0
  589. package/prompts-minimal/Todo.md +26 -0
  590. package/scripts/postinstall.mjs +63 -0
  591. package/scripts/vm-agent.mjs +312 -90
  592. package/WORKFLOW.md +0 -744
  593. package/dist/acp-bridge.js +0 -324
  594. package/dist/acp-bridge.js.map +0 -1
  595. package/dist/actions/cache.js +0 -191
  596. package/dist/actions/cache.js.map +0 -1
  597. package/dist/actions/effects.js +0 -41
  598. package/dist/actions/effects.js.map +0 -1
  599. package/dist/actions/executor.js +0 -570
  600. package/dist/actions/executor.js.map +0 -1
  601. package/dist/actions/index.js +0 -13
  602. package/dist/actions/index.js.map +0 -1
  603. package/dist/actions/parsing.js.map +0 -1
  604. package/dist/actions/predicate-env.js +0 -27
  605. package/dist/actions/predicate-env.js.map +0 -1
  606. package/dist/actions/predicates.js +0 -49
  607. package/dist/actions/predicates.js.map +0 -1
  608. package/dist/actions/templating.js +0 -66
  609. package/dist/actions/templating.js.map +0 -1
  610. package/dist/actions/types.js +0 -15
  611. package/dist/actions/types.js.map +0 -1
  612. package/dist/agent/acp.js +0 -473
  613. package/dist/agent/acp.js.map +0 -1
  614. package/dist/agent/adapter-names.js +0 -159
  615. package/dist/agent/adapter-names.js.map +0 -1
  616. package/dist/agent/adapters.js +0 -511
  617. package/dist/agent/adapters.js.map +0 -1
  618. package/dist/agent/credential-extractors.js +0 -342
  619. package/dist/agent/credential-extractors.js.map +0 -1
  620. package/dist/agent/credential-secrets.js +0 -628
  621. package/dist/agent/credential-secrets.js.map +0 -1
  622. package/dist/agent/credential-ticker.js +0 -57
  623. package/dist/agent/credential-ticker.js.map +0 -1
  624. package/dist/agent/gondolin-creds-staging.js +0 -356
  625. package/dist/agent/gondolin-creds-staging.js.map +0 -1
  626. package/dist/agent/gondolin-dispatch.js +0 -375
  627. package/dist/agent/gondolin-dispatch.js.map +0 -1
  628. package/dist/agent/gondolin.js +0 -124
  629. package/dist/agent/gondolin.js.map +0 -1
  630. package/dist/agent/runner-decisions.js +0 -134
  631. package/dist/agent/runner-decisions.js.map +0 -1
  632. package/dist/agent/runner.js +0 -1456
  633. package/dist/agent/runner.js.map +0 -1
  634. package/dist/agent/tool-call-summary.js +0 -102
  635. package/dist/agent/tool-call-summary.js.map +0 -1
  636. package/dist/agent/vm-acp-mapping.js +0 -73
  637. package/dist/agent/vm-acp-mapping.js.map +0 -1
  638. package/dist/agent/vm-guards.js +0 -262
  639. package/dist/agent/vm-guards.js.map +0 -1
  640. package/dist/agent/vm-port.js +0 -22
  641. package/dist/agent/vm-port.js.map +0 -1
  642. package/dist/agent/vm-process-registry.js +0 -79
  643. package/dist/agent/vm-process-registry.js.map +0 -1
  644. package/dist/bin/cli-args.js +0 -105
  645. package/dist/bin/cli-args.js.map +0 -1
  646. package/dist/bin/symphony.js +0 -794
  647. package/dist/bin/symphony.js.map +0 -1
  648. package/dist/errors.js +0 -15
  649. package/dist/errors.js.map +0 -1
  650. package/dist/http-disk.js +0 -135
  651. package/dist/http-disk.js.map +0 -1
  652. package/dist/http-handlers.js.map +0 -1
  653. package/dist/http.js.map +0 -1
  654. package/dist/issues.js +0 -178
  655. package/dist/issues.js.map +0 -1
  656. package/dist/logging.js +0 -203
  657. package/dist/logging.js.map +0 -1
  658. package/dist/mcp.js +0 -706
  659. package/dist/mcp.js.map +0 -1
  660. package/dist/memory.js +0 -85
  661. package/dist/memory.js.map +0 -1
  662. package/dist/orchestrator-decisions.js +0 -331
  663. package/dist/orchestrator-decisions.js.map +0 -1
  664. package/dist/orchestrator.js +0 -1569
  665. package/dist/orchestrator.js.map +0 -1
  666. package/dist/prompt.js +0 -65
  667. package/dist/prompt.js.map +0 -1
  668. package/dist/reconciler/cache.js +0 -65
  669. package/dist/reconciler/cache.js.map +0 -1
  670. package/dist/reconciler/index.js +0 -448
  671. package/dist/reconciler/index.js.map +0 -1
  672. package/dist/reconciler/ledger.js +0 -131
  673. package/dist/reconciler/ledger.js.map +0 -1
  674. package/dist/reconciler/pr-adapters.js +0 -174
  675. package/dist/reconciler/pr-adapters.js.map +0 -1
  676. package/dist/reconciler/pr-decide.js.map +0 -1
  677. package/dist/reconciler/pr.js +0 -422
  678. package/dist/reconciler/pr.js.map +0 -1
  679. package/dist/reconciler/types.js +0 -12
  680. package/dist/reconciler/types.js.map +0 -1
  681. package/dist/reconciler/vm.js +0 -243
  682. package/dist/reconciler/vm.js.map +0 -1
  683. package/dist/reconciler/workspace-defaults.js +0 -83
  684. package/dist/reconciler/workspace-defaults.js.map +0 -1
  685. package/dist/reconciler/workspace.js +0 -272
  686. package/dist/reconciler/workspace.js.map +0 -1
  687. package/dist/runlog.js +0 -403
  688. package/dist/runlog.js.map +0 -1
  689. package/dist/scaffold.js +0 -165
  690. package/dist/scaffold.js.map +0 -1
  691. package/dist/trackers/local.js +0 -445
  692. package/dist/trackers/local.js.map +0 -1
  693. package/dist/trackers/types.js +0 -10
  694. package/dist/trackers/types.js.map +0 -1
  695. package/dist/types.js +0 -3
  696. package/dist/types.js.map +0 -1
  697. package/dist/util/clock.js +0 -12
  698. package/dist/util/clock.js.map +0 -1
  699. package/dist/util/crypto.js +0 -25
  700. package/dist/util/crypto.js.map +0 -1
  701. package/dist/util/frontmatter.js +0 -70
  702. package/dist/util/frontmatter.js.map +0 -1
  703. package/dist/util/fs-issues.js +0 -22
  704. package/dist/util/fs-issues.js.map +0 -1
  705. package/dist/util/process.js +0 -152
  706. package/dist/util/process.js.map +0 -1
  707. package/dist/util/workspace-key.js +0 -10
  708. package/dist/util/workspace-key.js.map +0 -1
  709. package/dist/workflow-loader.js +0 -147
  710. package/dist/workflow-loader.js.map +0 -1
  711. package/dist/workflow.js +0 -822
  712. package/dist/workflow.js.map +0 -1
  713. package/dist/workspace-types.js +0 -8
  714. package/dist/workspace-types.js.map +0 -1
  715. package/dist/workspace.js +0 -443
  716. package/dist/workspace.js.map +0 -1
@@ -0,0 +1,83 @@
1
+ // FCIS rewrite — pure dispatch-eligibility decisions.
2
+ //
3
+ // Ported faithfully from `src/orchestrator-decisions.ts`
4
+ // (computeEligibilityReason / hasNonTerminalBlocker / resolveActorString) of the
5
+ // reference orchestrator. These are deterministic, side-effect-free decision
6
+ // functions: every nondeterministic input (the active/terminal/running/claimed
7
+ // state sets and the per-state slot availability) is passed in as plain data,
8
+ // so the functions stay (data) -> data.
9
+ //
10
+ // The orchestrator shell holds the live tracker view and concurrency
11
+ // bookkeeping; it materialises an EligibilitySnapshot each poll and calls
12
+ // computeEligibilityReason to learn whether an issue may be dispatched. A null
13
+ // return means "dispatch it"; a non-null string is a short, human-facing reason
14
+ // the issue is currently ineligible (surfaced in the run log / dashboard).
15
+ //
16
+ // 100% SYNCHRONOUS. No IO, no clock, no randomness. Imports only from
17
+ // src/types. (NodeNext ESM: .js extension on the relative type import.)
18
+ import { resolveStateKey } from '../state-resolve.js';
19
+ /**
20
+ * Returns null when the issue is eligible to dispatch, otherwise a short reason
21
+ * string. `ignoreOwnClaim` is set by the retry path so an issue's own claim does
22
+ * not block its redispatch.
23
+ *
24
+ * Order of checks mirrors the reference exactly (callers and tests depend on
25
+ * the precedence): required-fields → state-active → already-running →
26
+ * already-claimed → per-state-slot → todo-blocker. The first failing check
27
+ * wins; later checks are not evaluated.
28
+ */
29
+ export function computeEligibilityReason(issue, ignoreOwnClaim, snap) {
30
+ if (!issue.id || !issue.identifier || !issue.title || !issue.state) {
31
+ return 'missing required issue fields';
32
+ }
33
+ const state = issue.state.toLowerCase();
34
+ if (!snap.active.has(state) || snap.terminal.has(state))
35
+ return 'state not active';
36
+ if (snap.running.has(issue.id))
37
+ return 'already running';
38
+ if (!ignoreOwnClaim && snap.claimed.has(issue.id))
39
+ return 'already claimed';
40
+ if (!snap.perStateSlot(issue.state))
41
+ return 'no per-state slot';
42
+ if (state === 'todo' && hasNonTerminalBlocker(issue, snap.terminal)) {
43
+ return 'has non-terminal blocker';
44
+ }
45
+ return null;
46
+ }
47
+ /**
48
+ * True when the issue has at least one blocker that is NOT in a terminal state.
49
+ * An unresolvable blocker (null `state`) counts as non-terminal — we cannot
50
+ * prove it is done, so we keep the issue blocked. Blocker state membership is
51
+ * tested against the LOWERCASED terminal set.
52
+ */
53
+ export function hasNonTerminalBlocker(issue, terminal) {
54
+ for (const b of issue.blocked_by) {
55
+ if (!b.state)
56
+ return true;
57
+ if (!terminal.has(b.state.toLowerCase()))
58
+ return true;
59
+ }
60
+ return false;
61
+ }
62
+ /**
63
+ * Resolved actor string (`"<adapter>/<model or 'default'>"`) for the
64
+ * dispatch-time RunningEntry. When the state is not declared in the workflow,
65
+ * falls back to the workflow-level adapter/model (the reference returned null
66
+ * from the canonical-key lookup and substituted the defaults inline; we keep
67
+ * the same observable result — the function always returns a string).
68
+ *
69
+ * Per-state `adapter` overrides the workflow adapter when set. For the model,
70
+ * `undefined` inherits the workflow model while an explicit `null` clears it to
71
+ * `'default'` — matching the StateConfig.model "undefined inherits / null
72
+ * clears" contract.
73
+ */
74
+ export function resolveActorString(states, workflowAdapter, workflowModel, state) {
75
+ const key = resolveStateKey(states, state);
76
+ if (key === null)
77
+ return `${workflowAdapter}/${workflowModel ?? 'default'}`;
78
+ const s = states[key];
79
+ const adapter = s.adapter ?? workflowAdapter;
80
+ const model = s.model === undefined ? workflowModel : s.model;
81
+ return `${adapter}/${model ?? 'default'}`;
82
+ }
83
+ //# sourceMappingURL=eligibility.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eligibility.js","sourceRoot":"","sources":["../../../../src/core/schedule/eligibility.ts"],"names":[],"mappings":"AAAA,sDAAsD;AACtD,EAAE;AACF,yDAAyD;AACzD,iFAAiF;AACjF,6EAA6E;AAC7E,+EAA+E;AAC/E,8EAA8E;AAC9E,wCAAwC;AACxC,EAAE;AACF,qEAAqE;AACrE,0EAA0E;AAC1E,+EAA+E;AAC/E,gFAAgF;AAChF,2EAA2E;AAC3E,EAAE;AACF,sEAAsE;AACtE,wEAAwE;AAIxE,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAOtD;;;;;;;;;GASG;AACH,MAAM,UAAU,wBAAwB,CACtC,KAAY,EACZ,cAAuB,EACvB,IAAyB;IAEzB,IAAI,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,UAAU,IAAI,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACnE,OAAO,+BAA+B,CAAC;IACzC,CAAC;IACD,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC;IACxC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC;QAAE,OAAO,kBAAkB,CAAC;IACnF,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;QAAE,OAAO,iBAAiB,CAAC;IACzD,IAAI,CAAC,cAAc,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;QAAE,OAAO,iBAAiB,CAAC;IAC5E,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,KAAK,CAAC;QAAE,OAAO,mBAAmB,CAAC;IAChE,IAAI,KAAK,KAAK,MAAM,IAAI,qBAAqB,CAAC,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;QACpE,OAAO,0BAA0B,CAAC;IACpC,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CAAC,KAAY,EAAE,QAA6B;IAC/E,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,UAAU,EAAE,CAAC;QACjC,IAAI,CAAC,CAAC,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC;QAC1B,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC;YAAE,OAAO,IAAI,CAAC;IACxD,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,kBAAkB,CAChC,MAAmC,EACnC,eAAuB,EACvB,aAAwC,EACxC,KAAa;IAEb,MAAM,GAAG,GAAG,eAAe,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAC3C,IAAI,GAAG,KAAK,IAAI;QAAE,OAAO,GAAG,eAAe,IAAI,aAAa,IAAI,SAAS,EAAE,CAAC;IAC5E,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,CAAE,CAAC;IACvB,MAAM,OAAO,GAAG,CAAC,CAAC,OAAO,IAAI,eAAe,CAAC;IAC7C,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IAC9D,OAAO,GAAG,OAAO,IAAI,KAAK,IAAI,SAAS,EAAE,CAAC;AAC5C,CAAC"}
@@ -0,0 +1,82 @@
1
+ // FCIS rewrite — pure per-running-issue reconcile decision.
2
+ //
3
+ // Ported faithfully from `src/orchestrator-decisions.ts`
4
+ // (decideReconcileForIssue / ReconcileAction) of the reference orchestrator.
5
+ // Deterministic and side-effect free: the only inputs are the freshly-fetched
6
+ // tracker view of one running issue and the workflow `states:` map. The shell
7
+ // owns the running-issue bookkeeping and the actual terminate/refresh/cleanup
8
+ // IO; this function only DECIDES which of those to perform.
9
+ //
10
+ // 100% SYNCHRONOUS. No IO, no clock, no randomness, no node: imports. Imports
11
+ // only from src/types. (NodeNext ESM: .js extension on the relative type
12
+ // imports.)
13
+ //
14
+ // The role filters `activeStateNames` / `terminalStateNames` are the canonical
15
+ // pure folds in core/issue/parse.ts (the WIRED home for the state-role helpers);
16
+ // imported from there so the three former copies can't drift.
17
+ import { activeStateNames, terminalStateNames } from '../issue/parse.js';
18
+ /**
19
+ * Per-running-issue reconcile decision based on the freshly-fetched tracker
20
+ * view. Branch precedence is ported exactly from the reference (callers/tests
21
+ * depend on it):
22
+ *
23
+ * 1. Missing row (`fresh === undefined`) → terminate, NO cleanup
24
+ * (`reason: 'tracker_state_missing'`). The issue vanished from the tracker;
25
+ * we can't know whether its workspace is safe to reap, so leave it.
26
+ * 2. Terminal-role state → terminate, cleanup driven BY ROLE
27
+ * (`reason: 'tracker_state_terminal'`). Routing the cleanup flag through
28
+ * the canonical state's `role` (rather than hard-coding `true`) lets a
29
+ * future per-state `cleanup_workspace` flag flip without touching the
30
+ * orchestrator. A terminal-role state cleans up; anything else does not.
31
+ * 3. Active-role state → refresh the in-memory issue snapshot.
32
+ * 4. Anything else (holding, or a state not declared in the workflow) →
33
+ * terminate, NO cleanup (`reason: 'tracker_state_non_active'`).
34
+ *
35
+ * State membership is compared case-insensitively (the tracker may store a
36
+ * differently-cased directory name than the workflow declares), matching the
37
+ * rest of symphony's eligibility/reconcile paths.
38
+ *
39
+ * Thin wrapper over {@link decideReconcileForState}: the only field consulted is
40
+ * `fresh.state`, so the state-keyed decider holds the logic and the operator-move
41
+ * reducer (which has the moved-to state, not a full Issue) shares it verbatim —
42
+ * the poll-loop reconcile and the dashboard move path can't drift (issue 211).
43
+ */
44
+ export function decideReconcileForIssue(fresh, states) {
45
+ return decideReconcileForState(fresh?.state, states);
46
+ }
47
+ /**
48
+ * The state-keyed core of {@link decideReconcileForIssue}: decide the reconcile
49
+ * action from a freshly-resolved tracker STATE NAME (or `undefined` for a row that
50
+ * is no longer present). Same branch precedence + case-insensitive matching as the
51
+ * Issue-keyed wrapper; shared by the operator-move reducer, which holds the move
52
+ * target state rather than a full Issue.
53
+ */
54
+ export function decideReconcileForState(state, states) {
55
+ if (state === undefined) {
56
+ return { kind: 'terminate', cleanup: false, reason: 'tracker_state_missing' };
57
+ }
58
+ const s = state.toLowerCase();
59
+ const terminal = new Set(terminalStateNames(states).map((n) => n.toLowerCase()));
60
+ if (terminal.has(s)) {
61
+ // Cleanup is driven by the canonical state's role: a terminal-role state
62
+ // reaps its workspace, anything matched here that somehow isn't terminal
63
+ // (it can't be, given `terminalStateNames`, but keep the reference's
64
+ // defensive null-handling) does not.
65
+ //
66
+ // Canonicalize via a declaration-order case-insensitive scan over the
67
+ // ALREADY-LOWERCASED `s` — matching the reference exactly
68
+ // (`Object.keys(states).find((n) => n.toLowerCase() === s)`). No
69
+ // exact-own-property short-circuit: the first declared name whose lowercased
70
+ // form equals `s` wins, so a (pathological) name declared twice resolves to
71
+ // the first declaration's role.
72
+ const canonical = Object.keys(states).find((n) => n.toLowerCase() === s);
73
+ const cleanup = canonical !== undefined ? states[canonical].role === 'terminal' : false;
74
+ return { kind: 'terminate', cleanup, reason: 'tracker_state_terminal' };
75
+ }
76
+ const active = new Set(activeStateNames(states).map((n) => n.toLowerCase()));
77
+ if (active.has(s)) {
78
+ return { kind: 'refresh' };
79
+ }
80
+ return { kind: 'terminate', cleanup: false, reason: 'tracker_state_non_active' };
81
+ }
82
+ //# sourceMappingURL=reconcile-issue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reconcile-issue.js","sourceRoot":"","sources":["../../../../src/core/schedule/reconcile-issue.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,EAAE;AACF,yDAAyD;AACzD,6EAA6E;AAC7E,8EAA8E;AAC9E,8EAA8E;AAC9E,8EAA8E;AAC9E,4DAA4D;AAC5D,EAAE;AACF,8EAA8E;AAC9E,yEAAyE;AACzE,YAAY;AACZ,EAAE;AACF,+EAA+E;AAC/E,iFAAiF;AACjF,8DAA8D;AAK9D,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAEzE;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,UAAU,uBAAuB,CACrC,KAAwB,EACxB,MAAmC;IAEnC,OAAO,uBAAuB,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;AACvD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,uBAAuB,CACrC,KAAyB,EACzB,MAAmC;IAEnC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,uBAAuB,EAAE,CAAC;IAChF,CAAC;IAED,MAAM,CAAC,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;IAE9B,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;IACjF,IAAI,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QACpB,yEAAyE;QACzE,yEAAyE;QACzE,qEAAqE;QACrE,qCAAqC;QACrC,EAAE;QACF,sEAAsE;QACtE,0DAA0D;QAC1D,iEAAiE;QACjE,6EAA6E;QAC7E,4EAA4E;QAC5E,gCAAgC;QAChC,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,CAAC;QACzE,MAAM,OAAO,GAAG,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAE,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC;QACzF,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,EAAE,wBAAwB,EAAE,CAAC;IAC1E,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;IAC7E,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QAClB,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;IAC7B,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,0BAA0B,EAAE,CAAC;AACnF,CAAC"}
@@ -0,0 +1,96 @@
1
+ // FCIS rewrite — pure retry/continuation scheduling core.
2
+ //
3
+ // Ported faithfully from the original `src/orchestrator-decisions.ts`
4
+ // (`decideExitRetry`, `decideRetryAfterIneligible`, `RetrySchedulePlan`). These
5
+ // are the deciders the orchestrator folds over a freshly-exited worker (clean vs
6
+ // abnormal exit) and over a re-polled-but-ineligible retry candidate.
7
+ //
8
+ // Every function here is pure and SYNCHRONOUS: (data) -> data. The only side
9
+ // effect the original orchestrator performed at these sites — arming a timer to
10
+ // redispatch — becomes a returned `timer.schedule_retry` Effect (see
11
+ // `scheduleRetryEffect`), which the shell EXECUTES. No clock, no randomness, no
12
+ // IO. Imports are restricted to src/types.
13
+ /**
14
+ * Exponential-backoff delay for a failure retry, capped at `maxBackoffMs`.
15
+ *
16
+ * `attempt` is the 1-based attempt number being scheduled, so the first failure
17
+ * (`attempt === 1`) waits `baseMs * 2^0 === baseMs`, the second `baseMs * 2`,
18
+ * and so on. Mirrors the inline `Math.min(base * 2^(attempt-1), max)` the
19
+ * original carried at both retry sites.
20
+ */
21
+ export function backoffDelayMs(attempt, baseMs, maxBackoffMs) {
22
+ return Math.min(baseMs * Math.pow(2, attempt - 1), maxBackoffMs);
23
+ }
24
+ /**
25
+ * Retry schedule for a worker that just exited. A normal exit becomes a
26
+ * `continuation` (short, slot-holding, no error) so the same issue resumes its
27
+ * post-transition state; an abnormal exit becomes a `failure` with exponential
28
+ * backoff capped at `maxBackoffMs` (does NOT hold a slot). `target_state` is
29
+ * whatever state the running entry was carrying at exit time.
30
+ *
31
+ * A `continuation` always reports `attempt: 1` — it is a fresh handoff, not a
32
+ * retry of a prior attempt. A `failure` increments the prior attempt (or starts
33
+ * at 1 when there was none).
34
+ */
35
+ export function decideExitRetry(input) {
36
+ if (input.normal) {
37
+ return {
38
+ attempt: 1,
39
+ delayMs: input.continuationDelayMs,
40
+ error: null,
41
+ kind: 'continuation',
42
+ target_state: input.targetState,
43
+ };
44
+ }
45
+ const nextAttempt = input.priorAttempt !== null && input.priorAttempt !== undefined ? input.priorAttempt + 1 : 1;
46
+ return {
47
+ attempt: nextAttempt,
48
+ delayMs: backoffDelayMs(nextAttempt, input.failureBaseMs, input.maxBackoffMs),
49
+ error: input.reason,
50
+ kind: 'failure',
51
+ target_state: input.targetState,
52
+ };
53
+ }
54
+ /** The no-slot reason that the ineligible path treats as a transient reschedule. */
55
+ export const NO_SLOT_REASON = 'no per-state slot';
56
+ /**
57
+ * Retry-timer response when a re-polled issue is found ineligible. A
58
+ * `no per-state slot` reason yields a failure-backoff reschedule (the loop can
59
+ * dispatch other work during the wait); any other ineligibility releases the
60
+ * claim. Mirrors the inline switch the original orchestrator carried.
61
+ *
62
+ * The reschedule delay backs off on `priorAttempt` (NOT `priorAttempt + 1`):
63
+ * the original computed `base * 2^priorAttempt` for the new `attempt:
64
+ * priorAttempt + 1`, matching `backoffDelayMs(priorAttempt + 1, …)`.
65
+ */
66
+ export function decideRetryAfterIneligible(input) {
67
+ if (input.reason !== NO_SLOT_REASON)
68
+ return { kind: 'release' };
69
+ const nextAttempt = input.priorAttempt + 1;
70
+ return {
71
+ kind: 'reschedule',
72
+ plan: {
73
+ attempt: nextAttempt,
74
+ delayMs: backoffDelayMs(nextAttempt, input.failureBaseMs, input.maxBackoffMs),
75
+ error: 'no available orchestrator slots',
76
+ kind: 'failure',
77
+ target_state: input.targetState,
78
+ },
79
+ };
80
+ }
81
+ /**
82
+ * Fold a {@link RetrySchedulePlan} into the `timer.schedule_retry` Effect the
83
+ * shell executes to arm the (continuation or backoff) redispatch. This is the
84
+ * single seam where a retry decision becomes a side effect: core returns the
85
+ * Effect, the shell registers the actual timer.
86
+ */
87
+ export function scheduleRetryEffect(issueId, identifier, plan) {
88
+ return {
89
+ family: 'timer',
90
+ kind: 'schedule_retry',
91
+ issueId,
92
+ identifier,
93
+ plan,
94
+ };
95
+ }
96
+ //# sourceMappingURL=retry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry.js","sourceRoot":"","sources":["../../../../src/core/schedule/retry.ts"],"names":[],"mappings":"AAAA,0DAA0D;AAC1D,EAAE;AACF,sEAAsE;AACtE,gFAAgF;AAChF,iFAAiF;AACjF,sEAAsE;AACtE,EAAE;AACF,6EAA6E;AAC7E,gFAAgF;AAChF,qEAAqE;AACrE,gFAAgF;AAChF,2CAA2C;AAM3C;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc,CAAC,OAAe,EAAE,MAAc,EAAE,YAAoB;IAClF,OAAO,IAAI,CAAC,GAAG,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC;AACnE,CAAC;AAmBD;;;;;;;;;;GAUG;AACH,MAAM,UAAU,eAAe,CAAC,KAA2B;IACzD,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;QACjB,OAAO;YACL,OAAO,EAAE,CAAC;YACV,OAAO,EAAE,KAAK,CAAC,mBAAmB;YAClC,KAAK,EAAE,IAAI;YACX,IAAI,EAAE,cAAkC;YACxC,YAAY,EAAE,KAAK,CAAC,WAAW;SAChC,CAAC;IACJ,CAAC;IACD,MAAM,WAAW,GACf,KAAK,CAAC,YAAY,KAAK,IAAI,IAAI,KAAK,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/F,OAAO;QACL,OAAO,EAAE,WAAW;QACpB,OAAO,EAAE,cAAc,CAAC,WAAW,EAAE,KAAK,CAAC,aAAa,EAAE,KAAK,CAAC,YAAY,CAAC;QAC7E,KAAK,EAAE,KAAK,CAAC,MAAM;QACnB,IAAI,EAAE,SAA6B;QACnC,YAAY,EAAE,KAAK,CAAC,WAAW;KAChC,CAAC;AACJ,CAAC;AAED,oFAAoF;AACpF,MAAM,CAAC,MAAM,cAAc,GAAG,mBAAmB,CAAC;AAmBlD;;;;;;;;;GASG;AACH,MAAM,UAAU,0BAA0B,CACxC,KAAsC;IAEtC,IAAI,KAAK,CAAC,MAAM,KAAK,cAAc;QAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;IAChE,MAAM,WAAW,GAAG,KAAK,CAAC,YAAY,GAAG,CAAC,CAAC;IAC3C,OAAO;QACL,IAAI,EAAE,YAAY;QAClB,IAAI,EAAE;YACJ,OAAO,EAAE,WAAW;YACpB,OAAO,EAAE,cAAc,CAAC,WAAW,EAAE,KAAK,CAAC,aAAa,EAAE,KAAK,CAAC,YAAY,CAAC;YAC7E,KAAK,EAAE,iCAAiC;YACxC,IAAI,EAAE,SAA6B;YACnC,YAAY,EAAE,KAAK,CAAC,WAAW;SAChC;KACF,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CACjC,OAAe,EACf,UAAkB,EAClB,IAAuB;IAEvB,OAAO;QACL,MAAM,EAAE,OAAO;QACf,IAAI,EAAE,gBAAgB;QACtB,OAAO;QACP,UAAU;QACV,IAAI;KACL,CAAC;AACJ,CAAC"}
@@ -0,0 +1,133 @@
1
+ // FCIS rewrite — pure sleep-cycle (recurring reflection spawn) decisions.
2
+ //
3
+ // The sleep cycle is modelled as a recurring STATE that spawns ephemeral
4
+ // reflection issues, NOT as one immortal ticket parked in a holding state. When
5
+ // the orchestrator has accumulated enough finished work (a `done_threshold`
6
+ // trigger) or goes idle with at least one issue finished since the last cycle (an
7
+ // `idle` trigger), `decideSpawn` mints a FRESH issue into the spawn state. Each
8
+ // reflection is born there, runs once, and terminates in a dedicated terminal —
9
+ // like every other ticket. The shell folds each freshly-exited worker into a
10
+ // terminal-transition counter via `recordSleepCycleProgress`, then each poll asks
11
+ // `decideSpawn` whether a trigger fires; on a fire it returns the new issue's
12
+ // title + body (provenance the static prompt can't know), which the shell turns
13
+ // into a create-issue effect, resetting the counter only on a successful mint.
14
+ //
15
+ // 100% SYNCHRONOUS. No IO, no clock, no randomness, no node: imports. Every
16
+ // decision is (data) -> data; the only side effect the shell performs at these
17
+ // sites (the async create + counter reset) stays in the shell — core just returns
18
+ // the spawn intent / note text / next counter value. The "now" stamp is injected
19
+ // as `nowIso` data (the same "inject the clock as data" precedent as
20
+ // `summarizeRunLog`'s required `generatedAt`). Imports only from src/types.
21
+ // (NodeNext ESM: .js extension on the relative type import.)
22
+ /**
23
+ * Decide whether to mint a fresh reflection issue this tick, and on which
24
+ * trigger. Returns the spawn intent (trigger + derived title/body) or null when
25
+ * no trigger fires.
26
+ *
27
+ * The done-threshold trigger takes precedence over idle when both hold (it's
28
+ * the stronger, count-based signal — handy for the operator-visible log line).
29
+ *
30
+ * The idle trigger is deliberately gated on `doneSinceReflect > 0`: an idle
31
+ * orchestrator with nothing finished since the last cycle has nothing new to
32
+ * reflect on, and spawning anyway would spin (spawn -> reflect -> terminal ->
33
+ * idle -> spawn ...) forever. Requiring fresh terminal work breaks that loop
34
+ * while still honoring the "sleep when not busy" framing.
35
+ *
36
+ * `max_in_flight` is load-bearing: minting removed the immortal ticket's built-in
37
+ * "one location = one reflection" mutex, so without this guard a busy stretch's
38
+ * `after_terminal` trigger could mint a second cycle while one is still live.
39
+ * When `inFlight >= maxInFlight` no issue is minted, regardless of trigger.
40
+ *
41
+ * Returns null when spawning is disabled, the in-flight cap is reached, or no
42
+ * trigger fires.
43
+ */
44
+ export function decideSpawn(input) {
45
+ if (!input.enabled)
46
+ return null;
47
+ // Never mint a second while one (or `maxInFlight`) is already live in the spawn
48
+ // state — the recurring-state replacement for the immortal ticket's mutex.
49
+ if (input.inFlight >= input.maxInFlight)
50
+ return null;
51
+ const trigger = decideTrigger(input);
52
+ if (trigger === null)
53
+ return null;
54
+ return {
55
+ trigger,
56
+ title: renderTitle(input.titleTemplate, input.nowIso),
57
+ body: spawnBody(trigger, input.doneSinceReflect, input.afterTerminal, input.nowIso, input.bodyLeadIn),
58
+ };
59
+ }
60
+ /** Which trigger (if any) fires this tick — the pure trigger half of {@link decideSpawn}. */
61
+ function decideTrigger(input) {
62
+ if (input.afterTerminal > 0 && input.doneSinceReflect >= input.afterTerminal) {
63
+ return 'done_threshold';
64
+ }
65
+ if (input.onIdle && input.idle && input.doneSinceReflect > 0)
66
+ return 'idle';
67
+ return null;
68
+ }
69
+ /**
70
+ * Render the minted issue's title from the configured template, substituting a
71
+ * human-readable `{{ stamp }}` (e.g. `2026-06-03 13:56`) derived purely from the
72
+ * injected `nowIso`. A template with no placeholder is used verbatim.
73
+ */
74
+ function renderTitle(template, nowIso) {
75
+ return template.replace(/\{\{\s*stamp\s*\}\}/g, readableStamp(nowIso));
76
+ }
77
+ /** `2026-06-03T13:56:12.000Z` → `2026-06-03 13:56` (date + HH:MM, no seconds/Z). Pure. */
78
+ function readableStamp(nowIso) {
79
+ return nowIso.slice(0, 16).replace('T', ' ');
80
+ }
81
+ /**
82
+ * The provenance body for the minted reflection issue. Plain text, generated once
83
+ * at mint — the point-in-time provenance the static `prompts/Reflect.md` can't
84
+ * know (the trigger, the counter, the timestamp). It exists for the human reading
85
+ * the archived issue later; the reflector itself works from the prompt + the
86
+ * eval_mode mounts, not from this body. NO instructions / guardrails (those live
87
+ * in the prompt) and NO templating (the issue body is inert data the prompt
88
+ * interpolates, not a Liquid template).
89
+ */
90
+ function spawnBody(trigger, doneSinceReflect, afterTerminal, nowIso, leadIn) {
91
+ const why = trigger === 'done_threshold'
92
+ ? `${doneSinceReflect} issues reached a terminal state since the last reflection cycle (threshold: ${afterTerminal}).`
93
+ : `the orchestrator went idle with ${doneSinceReflect} issue(s) finished since the last reflection cycle.`;
94
+ return [
95
+ leadIn && leadIn.length > 0 ? leadIn : 'Auto-spawned reflection cycle.',
96
+ '',
97
+ `Trigger: ${trigger} — ${why}`,
98
+ `Spawned at: ${nowIso}.`,
99
+ ].join('\n');
100
+ }
101
+ /**
102
+ * Fold a freshly-exited worker into the terminal-transition counter the sleep
103
+ * cycle triggers read, returning the NEXT counter value (the original mutated
104
+ * `this.doneSinceReflect`; here it is pure).
105
+ *
106
+ * Only the work the reflector mines counts — a transition into a `role: terminal`
107
+ * state (Done / Cancelled / the spawn's terminal), as recorded by
108
+ * `last_transition.terminal`. A reflection's OWN terminal move is excluded
109
+ * STRUCTURALLY — by its from-state, not a fixed issue id: with ephemeral
110
+ * reflections there is no immortal ticket to match, so any terminal transition
111
+ * ORIGINATING from the spawn state is a finished reflection's own move and must
112
+ * not count toward spawning the next cycle (else the cycle never settles). A
113
+ * non-terminal exit (a continuation, a reroute) never advances the counter.
114
+ *
115
+ * `spawnState` is the configured spawn state (`SpawnRouting.spawnState`); a null
116
+ * value means spawning is unconfigured, in which case the counter is left
117
+ * untouched (matching the original's disabled-block no-op).
118
+ */
119
+ export function recordSleepCycleProgress(doneSinceReflect, entry, spawnState) {
120
+ // Spawning unconfigured: never advance the counter.
121
+ if (!spawnState)
122
+ return doneSinceReflect;
123
+ const t = entry.last_transition;
124
+ // Only a terminal transition (into a role: terminal state) is mineable work.
125
+ if (!t?.terminal)
126
+ return doneSinceReflect;
127
+ // A reflection's own terminal move (out of the spawn state) never counts toward
128
+ // spawning the next cycle — exclude it structurally by its from-state.
129
+ if (t.from_state.toLowerCase() === spawnState.toLowerCase())
130
+ return doneSinceReflect;
131
+ return doneSinceReflect + 1;
132
+ }
133
+ //# sourceMappingURL=sleep-cycle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sleep-cycle.js","sourceRoot":"","sources":["../../../../src/core/schedule/sleep-cycle.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,124 @@
1
+ // FCIS rewrite — pure slot accounting (functional core).
2
+ //
3
+ // Ports the orchestrator's concurrency gate (REF: src/orchestrator.ts
4
+ // `availableGlobalSlots`, `hasPerStateSlot`, `perStateConcurrencyCap`,
5
+ // `sortForDispatch`) into pure, synchronous functions over plain-data
6
+ // snapshots.
7
+ //
8
+ // The keystone behaviour this module owns:
9
+ // - GLOBAL slots: max(0, effectiveCap - running - pendingContinuations)
10
+ // - PER-STATE slots: inState < cap && globalSlots > 0 (cap from config)
11
+ // - CONTINUATIONS HOLD A SLOT, FAILURES DO NOT. A continuation is the
12
+ // post-transition resume of an issue that just normal-exited; reserving its
13
+ // slot during the (short) continuation delay stops a tick that fires inside
14
+ // that window from dispatching a brand-new issue and stealing the slot the
15
+ // resuming worker is about to reclaim. Failure-backoff retries do NOT hold a
16
+ // slot, so the orchestrator is free to run other work during the backoff.
17
+ // - sortForDispatch: priority ASC (null last), created_at ASC (unparseable
18
+ // last), identifier localeCompare as the final tiebreak.
19
+ //
20
+ // This module is given the ALREADY-RESOLVED effective cap (the memory-admission
21
+ // clamp is a separate core concern that folds a /proc/meminfo probe + config
22
+ // into `effectiveCap`); slot accounting just reads it from the snapshot so the
23
+ // snapshot endpoint and the dispatch loop can never desync. Nothing here reads
24
+ // the clock, randomness, or any IO — `created_at` is parsed deterministically
25
+ // from the issue's ISO string via the injected `parseTimestamp` (default uses
26
+ // Date.parse, which is pure — it does not read the wall clock).
27
+ /** Count pending retries that hold a slot (continuations only). */
28
+ function pendingContinuationCount(pendingRetries) {
29
+ let n = 0;
30
+ for (const r of pendingRetries) {
31
+ if (r.kind === 'continuation')
32
+ n++;
33
+ }
34
+ return n;
35
+ }
36
+ /**
37
+ * Global available-slot count.
38
+ *
39
+ * REF: `availableGlobalSlots()` — `max(0, effective_cap - running - pendingContinuations)`.
40
+ * Pending continuations are reserved against the cap; failure-backoff retries
41
+ * are not (they are absent from the holding set by construction — only `kind ===
42
+ * 'continuation'` entries count).
43
+ */
44
+ export function availableGlobalSlots(snapshot) {
45
+ const held = pendingContinuationCount(snapshot.pendingRetries);
46
+ return Math.max(0, snapshot.effectiveCap - snapshot.runningCount - held);
47
+ }
48
+ /** True iff the global gate has at least one free slot. */
49
+ export function hasGlobalSlot(snapshot) {
50
+ return availableGlobalSlots(snapshot) > 0;
51
+ }
52
+ /**
53
+ * Resolve a state's per-state concurrency cap (`states.<name>.max_concurrent`)
54
+ * with a case-insensitive name lookup, mirroring how issue states arrive from
55
+ * the tracker in arbitrary case.
56
+ *
57
+ * REF: `perStateConcurrencyCap()`. Returns `undefined` when the state is
58
+ * unknown, declares no cap, or declares a zero cap — in REF, `if (!cap)` treats
59
+ * both `undefined` and `0` as "no per-state cap, only the global ceiling
60
+ * applies," so we collapse them to `undefined` here.
61
+ */
62
+ export function resolvePerStateCap(stateName, caps) {
63
+ const lower = stateName.toLowerCase();
64
+ for (const name of Object.keys(caps)) {
65
+ if (name.toLowerCase() === lower) {
66
+ const cap = caps[name]?.max_concurrent;
67
+ return cap ? cap : undefined;
68
+ }
69
+ }
70
+ return undefined;
71
+ }
72
+ /**
73
+ * Per-state slot accounting.
74
+ *
75
+ * REF: `hasPerStateSlot()`. With no per-state cap declared the global gate is
76
+ * the only constraint. With a cap, count the running attempts in that state
77
+ * PLUS any pending continuation whose target state matches (so the resuming
78
+ * worker is guaranteed its slot when the timer fires), and require both
79
+ * `inState < cap` and a free global slot.
80
+ *
81
+ * `caps` is the `states` config keyed by state name (case-insensitive lookup).
82
+ */
83
+ export function hasPerStateSlot(stateName, snapshot, caps) {
84
+ const cap = resolvePerStateCap(stateName, caps);
85
+ if (cap === undefined)
86
+ return hasGlobalSlot(snapshot);
87
+ const lower = stateName.toLowerCase();
88
+ let inState = 0;
89
+ for (const s of snapshot.runningStates) {
90
+ if (s.toLowerCase() === lower)
91
+ inState++;
92
+ }
93
+ for (const r of snapshot.pendingRetries) {
94
+ if (r.kind === 'continuation' && r.target_state.toLowerCase() === lower) {
95
+ inState++;
96
+ }
97
+ }
98
+ return inState < cap && hasGlobalSlot(snapshot);
99
+ }
100
+ const defaultParseTimestamp = (iso) => iso ? Date.parse(iso) : Number.NaN;
101
+ /**
102
+ * Dispatch ordering.
103
+ *
104
+ * REF: `sortForDispatch()` — priority ASC with null priority ordered last,
105
+ * then created_at ASC with unparseable/null created_at ordered last, then
106
+ * identifier `localeCompare` as the final stable tiebreak. Returns a NEW array
107
+ * (does not mutate the input).
108
+ */
109
+ export function sortForDispatch(issues, parseTimestamp = defaultParseTimestamp) {
110
+ return [...issues].sort((a, b) => {
111
+ const pa = a.priority ?? Number.POSITIVE_INFINITY;
112
+ const pb = b.priority ?? Number.POSITIVE_INFINITY;
113
+ if (pa !== pb)
114
+ return pa - pb;
115
+ const rawA = parseTimestamp(a.created_at);
116
+ const rawB = parseTimestamp(b.created_at);
117
+ const ca = Number.isFinite(rawA) ? rawA : Number.POSITIVE_INFINITY;
118
+ const cb = Number.isFinite(rawB) ? rawB : Number.POSITIVE_INFINITY;
119
+ if (Number.isFinite(ca) && Number.isFinite(cb) && ca !== cb)
120
+ return ca - cb;
121
+ return a.identifier.localeCompare(b.identifier);
122
+ });
123
+ }
124
+ //# sourceMappingURL=slots.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slots.js","sourceRoot":"","sources":["../../../../src/core/schedule/slots.ts"],"names":[],"mappings":"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"}