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,140 @@
1
+ // Focused tests for finding #3: the workspace adapter must read workspace.root /
2
+ // source-repo via a LIVE config closure, NOT a boot snapshot, so a WORKFLOW.yaml
3
+ // hot-reload that moves workspace.root retargets create/list/remove instead of
4
+ // stranding them on the stale path.
5
+ import { test } from 'node:test';
6
+ import assert from 'node:assert/strict';
7
+ import { mkdtemp, mkdir, rm, writeFile } from 'node:fs/promises';
8
+ import os from 'node:os';
9
+ import path from 'node:path';
10
+ import { createWorkspaceAdapter } from '../../src/shell/interp/workspace.js';
11
+ // A ProcessRunner stub — list/remove/workspacePathFor don't spawn, so a throwing
12
+ // runner proves these paths are pure fs against the LIVE root.
13
+ const noProcess = {
14
+ run: async () => { throw new Error('process.run must not be called on the list/remove path'); },
15
+ };
16
+ // assertContained is the pure core guard; the identity-on-contained behaviour is
17
+ // all the adapter needs here (root/<key> is always a strict child).
18
+ const assertContained = (_root, target) => target;
19
+ async function withDirs(fn) {
20
+ const base = await mkdtemp(path.join(os.tmpdir(), 'symphony-ws-live-'));
21
+ const a = path.join(base, 'root-a');
22
+ const b = path.join(base, 'root-b');
23
+ await mkdir(a, { recursive: true });
24
+ await mkdir(b, { recursive: true });
25
+ try {
26
+ await fn(a, b);
27
+ }
28
+ finally {
29
+ await rm(base, { recursive: true, force: true });
30
+ }
31
+ }
32
+ test('workspacePathFor follows a live workspace.root change (no boot snapshot)', async () => {
33
+ await withDirs(async (rootA, rootB) => {
34
+ let liveRoot = rootA;
35
+ const ws = createWorkspaceAdapter({
36
+ root: () => liveRoot,
37
+ sourceRepo: () => '/unused',
38
+ process: noProcess,
39
+ assertContained,
40
+ });
41
+ assert.equal(ws.workspacePathFor('7'), path.join(rootA, '7'));
42
+ // Simulate a WORKFLOW.yaml hot-reload that moved workspace.root.
43
+ liveRoot = rootB;
44
+ assert.equal(ws.workspacePathFor('7'), path.join(rootB, '7'), 'path uses the NEW live root');
45
+ });
46
+ });
47
+ test('list() enumerates the NEW root after a config change', async () => {
48
+ await withDirs(async (rootA, rootB) => {
49
+ // Seed a workspace dir under each root.
50
+ await mkdir(path.join(rootA, 'old-ws'), { recursive: true });
51
+ await mkdir(path.join(rootB, 'new-ws'), { recursive: true });
52
+ let liveRoot = rootA;
53
+ const ws = createWorkspaceAdapter({
54
+ root: () => liveRoot,
55
+ sourceRepo: () => '/unused',
56
+ process: noProcess,
57
+ assertContained,
58
+ });
59
+ assert.deepEqual((await ws.list()).map((l) => l.name).sort(), ['old-ws']);
60
+ liveRoot = rootB;
61
+ assert.deepEqual((await ws.list()).map((l) => l.name).sort(), ['new-ws'], 'list reads the NEW root');
62
+ });
63
+ });
64
+ test('an in-flight ensureFor after a root change targets the NEW root (not the stale old-root clone)', async () => {
65
+ await withDirs(async (rootA, rootB) => {
66
+ // The source repo must look like a git dir (setup() stats <source>/.git first).
67
+ const sourceRepo = path.dirname(rootA);
68
+ await mkdir(path.join(sourceRepo, '.git'), { recursive: true });
69
+ const ok = (overrides = {}) => ({ ran: true, exit_code: 0, signal: null, timed_out: false, stdout: '', stderr: '', ...overrides });
70
+ // Record the cwd (= workspace path) of every `git clone` and gate the FIRST clone
71
+ // so it stays in-flight while we change the root and fire a second ensureFor.
72
+ const cloneCwds = [];
73
+ let firstCloneSeen;
74
+ const firstCloneStarted = new Promise((res) => { firstCloneSeen = res; });
75
+ let releaseFirstClone;
76
+ const firstCloneGate = new Promise((res) => { releaseFirstClone = res; });
77
+ let cloneCount = 0;
78
+ const recordingProcess = {
79
+ run: async (argv, opts) => {
80
+ const cwd = opts?.cwd ?? '';
81
+ if (argv[0] === 'git' && argv[1] === 'clone') {
82
+ cloneCwds.push(cwd);
83
+ if (cloneCount++ === 0) {
84
+ firstCloneSeen();
85
+ await firstCloneGate;
86
+ }
87
+ }
88
+ // restorePushedBranch: `git remote get-url origin` exit!=0 → local-only → checkout -b.
89
+ if (argv[1] === 'remote' && argv[2] === 'get-url')
90
+ return ok({ exit_code: 1 });
91
+ if (argv[1] === 'remote' && argv.length === 2)
92
+ return ok({ stdout: '' }); // no remotes to strip
93
+ return ok();
94
+ },
95
+ };
96
+ let liveRoot = rootA;
97
+ const ws = createWorkspaceAdapter({
98
+ root: () => liveRoot,
99
+ sourceRepo: () => sourceRepo,
100
+ process: recordingProcess,
101
+ assertContained,
102
+ });
103
+ const opts = { baseBranch: 'main', githubRepo: null };
104
+ const first = ws.ensureFor('9', opts); // clones into rootA, then parks on the gate
105
+ await firstCloneStarted;
106
+ // WORKFLOW.yaml hot-reload moves workspace.root mid-clone.
107
+ liveRoot = rootB;
108
+ // A fresh ensureFor for the SAME id must NOT reuse the parked old-root promise —
109
+ // the in-flight key includes the live root, so this starts a new clone under rootB.
110
+ const second = ws.ensureFor('9', opts);
111
+ releaseFirstClone();
112
+ const [r1, r2] = await Promise.all([first, second]);
113
+ assert.equal(r1.path, path.join(rootA, '9'), 'first ensureFor resolved under the OLD root');
114
+ assert.equal(r2.path, path.join(rootB, '9'), 'second ensureFor targets the NEW root');
115
+ // Two DISTINCT clones happened (one per root) — the stale promise was not reused.
116
+ assert.deepEqual(cloneCwds.sort(), [path.join(rootA, '9'), path.join(rootB, '9')].sort());
117
+ });
118
+ });
119
+ test('remove() targets the NEW root after a config change', async () => {
120
+ await withDirs(async (rootA, rootB) => {
121
+ // Same workspace key exists under both roots; remove must hit the live one.
122
+ await mkdir(path.join(rootA, 'dup'), { recursive: true });
123
+ await writeFile(path.join(rootA, 'dup', 'keep.txt'), 'a', 'utf8');
124
+ await mkdir(path.join(rootB, 'dup'), { recursive: true });
125
+ await writeFile(path.join(rootB, 'dup', 'gone.txt'), 'b', 'utf8');
126
+ let liveRoot = rootB;
127
+ const ws = createWorkspaceAdapter({
128
+ root: () => liveRoot,
129
+ sourceRepo: () => '/unused',
130
+ process: noProcess,
131
+ assertContained,
132
+ });
133
+ await ws.remove('dup', 'stale_issue');
134
+ // The dir under the LIVE root (B) is gone; the same-named dir under A survives.
135
+ assert.deepEqual((await ws.list()).map((l) => l.name), [], 'live root dir removed');
136
+ liveRoot = rootA;
137
+ assert.deepEqual((await ws.list()).map((l) => l.name), ['dup'], 'stale-root dir untouched');
138
+ });
139
+ });
140
+ //# sourceMappingURL=workspace-live-config.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace-live-config.test.js","sourceRoot":"","sources":["../../../tests/shell/workspace-live-config.test.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "smol-symphony",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "TypeScript orchestrator that runs coding agents (Claude, Codex, OpenCode) in per-issue Gondolin microVMs over ACP.",
5
5
  "keywords": [
6
6
  "orchestrator",
@@ -29,26 +29,37 @@
29
29
  },
30
30
  "files": [
31
31
  "dist/",
32
- "WORKFLOW.md",
33
- "WORKFLOW.template.md",
32
+ "patches/",
33
+ "WORKFLOW.yaml",
34
+ "WORKFLOW.minimal.yaml",
35
+ "WORKFLOW.template.yaml",
36
+ "assets/",
37
+ "prompts/",
38
+ "prompts-minimal/",
34
39
  "AGENTS.md",
35
40
  "SPEC.md",
36
41
  "PRODUCT.md",
37
42
  "DESIGN.md",
43
+ "scripts/postinstall.mjs",
38
44
  "scripts/vm-agent.mjs",
39
45
  "README.md",
40
46
  "LICENSE"
41
47
  ],
42
48
  "scripts": {
49
+ "postinstall": "node scripts/postinstall.mjs",
43
50
  "build": "tsc",
44
- "start": "tsx src/bin/symphony.ts",
45
- "symphony": "tsx src/bin/symphony.ts WORKFLOW.md",
46
- "dev": "tsx watch src/bin/symphony.ts",
51
+ "start": "tsx src/shell/main.ts",
52
+ "symphony": "tsx src/shell/main.ts WORKFLOW.yaml",
53
+ "dev": "tsx watch src/shell/main.ts",
47
54
  "typecheck": "tsc --noEmit",
48
- "test": "node --test --import tsx tests/*.test.ts",
49
- "prepublishOnly": "npm run typecheck && npm test && npm run build",
50
55
  "lint": "eslint src --max-warnings 0",
51
- "lint:arch": "depcruise src --ts-config tsconfig.json --ignore-known",
56
+ "lint:arch": "depcruise src --ts-config tsconfig.json",
57
+ "check:ratio": "node scripts/check-core-ratio.mjs",
58
+ "check:pokes": "node scripts/check-state-pokes.mjs",
59
+ "check:io": "node scripts/check-shell-io.mjs",
60
+ "test": "node --test --import tsx $(find tests -name '*.test.ts')",
61
+ "verify": "npm run typecheck && npm run lint && npm run lint:arch && npm run check:ratio && npm run check:pokes && npm run check:io && npm test",
62
+ "prepublishOnly": "npm run typecheck && npm test && npm run build",
52
63
  "build:image": "bash images/agents/build-image-oci.sh"
53
64
  },
54
65
  "dependencies": {
@@ -56,6 +67,7 @@
56
67
  "@earendil-works/gondolin": "^0.12.0",
57
68
  "chokidar": "^4.0.3",
58
69
  "liquidjs": "^10.21.1",
70
+ "patch-package": "^8.0.1",
59
71
  "yaml": "^2.6.1"
60
72
  },
61
73
  "devDependencies": {
@@ -0,0 +1,173 @@
1
+ diff --git a/node_modules/@earendil-works/gondolin/dist/src/qemu/network-stack.js b/node_modules/@earendil-works/gondolin/dist/src/qemu/network-stack.js
2
+ index f08a11f..b8603bd 100644
3
+ --- a/node_modules/@earendil-works/gondolin/dist/src/qemu/network-stack.js
4
+ +++ b/node_modules/@earendil-works/gondolin/dist/src/qemu/network-stack.js
5
+ @@ -10,6 +10,35 @@ const IP_PROTO_ICMP = 1;
6
+ function makeTcpNatKey(srcIP, srcPort, dstIP, dstPort) {
7
+ return `TCP:${srcIP}:${srcPort}:${dstIP}:${dstPort}`;
8
+ }
9
+ +// TCP sequence and acknowledgement numbers are 32 bits wide and wrap at 2^32.
10
+ +// We keep every stored counter (mySeq/myAck/vmSeq/vmAck) masked into [0, 2^32)
11
+ +// and compare them with RFC 1982 serial-number arithmetic instead of raw </>,
12
+ +// which break across the wrap boundary. Skipping either half re-introduces the
13
+ +// `writeUInt32BE` overflow crash or silent reassembly desync near 0xFFFFFFFF.
14
+ +/** Fold a value into the 32-bit TCP sequence space [0, 2^32). */
15
+ +function wrapSeq(value) {
16
+ + return value >>> 0;
17
+ +}
18
+ +/**
19
+ + * Signed RFC 1982 distance between two sequence numbers: > 0 when `a` is "after"
20
+ + * `b`, < 0 when "before", 0 when equal. ToInt32 (`| 0`) folds the difference into
21
+ + * the [-2^31, 2^31) serial window so comparisons stay correct across wrap.
22
+ + */
23
+ +function seqDistance(a, b) {
24
+ + return (a - b) | 0;
25
+ +}
26
+ +/** `a` is strictly after `b` in serial-number order. */
27
+ +function seqGt(a, b) {
28
+ + return seqDistance(a, b) > 0;
29
+ +}
30
+ +/** `a` is strictly before `b` in serial-number order. */
31
+ +function seqLt(a, b) {
32
+ + return seqDistance(a, b) < 0;
33
+ +}
34
+ +/** `a` is at or before `b` in serial-number order. */
35
+ +function seqLe(a, b) {
36
+ + return seqDistance(a, b) <= 0;
37
+ +}
38
+ const HTTP_METHODS = [
39
+ "GET",
40
+ "POST",
41
+ @@ -503,7 +532,7 @@ export class NetworkStack extends EventEmitter {
42
+ vmSeq: seq,
43
+ vmAck: ack,
44
+ mySeq: Math.floor(Math.random() * 0x0fffffff),
45
+ - myAck: seq + 1,
46
+ + myAck: wrapSeq(seq + 1),
47
+ peerWindow: window,
48
+ pendingOutbound: Buffer.alloc(0),
49
+ endPending: false,
50
+ @@ -527,14 +556,14 @@ export class NetworkStack extends EventEmitter {
51
+ }
52
+ if (!session) {
53
+ if (!SYN) {
54
+ - this.sendTCP(srcIP, srcPort, dstIP, dstPort, 0, seq + (payload.length || 1), 0x04);
55
+ + this.sendTCP(srcIP, srcPort, dstIP, dstPort, 0, wrapSeq(seq + (payload.length || 1)), 0x04);
56
+ }
57
+ return;
58
+ }
59
+ const prevPeerWindow = session.peerWindow;
60
+ session.peerWindow = window;
61
+ let shouldDrainOutbound = false;
62
+ - if (ack > session.vmAck && ack <= session.mySeq) {
63
+ + if (seqGt(ack, session.vmAck) && seqLe(ack, session.mySeq)) {
64
+ session.vmAck = ack;
65
+ shouldDrainOutbound = true;
66
+ }
67
+ @@ -553,12 +582,12 @@ export class NetworkStack extends EventEmitter {
68
+ // This matters for SSH in particular: duplicating bytes can desync the
69
+ // protocol and trigger errors like "Bad packet length".
70
+ const expectedSeq = session.myAck;
71
+ - if (seq > expectedSeq) {
72
+ + if (seqGt(seq, expectedSeq)) {
73
+ // Out-of-order: re-ACK what we've already seen.
74
+ this.sendTCP(session.srcIP, session.srcPort, session.dstIP, session.dstPort, session.mySeq, session.myAck, 0x10);
75
+ return;
76
+ }
77
+ - const skip = Math.max(0, expectedSeq - seq);
78
+ + const skip = Math.max(0, seqDistance(expectedSeq, seq));
79
+ if (skip >= payload.length) {
80
+ // Pure retransmit (or segment contains only already-acked bytes)
81
+ this.sendTCP(session.srcIP, session.srcPort, session.dstIP, session.dstPort, session.mySeq, session.myAck, 0x10);
82
+ @@ -568,7 +597,7 @@ export class NetworkStack extends EventEmitter {
83
+ }
84
+ const newPayload = payload.subarray(skip);
85
+ let sendBuffer = null;
86
+ - const nextAck = expectedSeq + newPayload.length;
87
+ + const nextAck = wrapSeq(expectedSeq + newPayload.length);
88
+ if (!session.flowProtocol) {
89
+ session.pendingData = Buffer.concat([session.pendingData, newPayload]);
90
+ if (session.allowRawTcp) {
91
+ @@ -635,20 +664,20 @@ export class NetworkStack extends EventEmitter {
92
+ if (FIN) {
93
+ // FIN consumes one sequence number, so only accept it once the sequence
94
+ // space up to the FIN is fully received.
95
+ - const finSeq = seq + payload.length;
96
+ - if (finSeq > session.myAck) {
97
+ + const finSeq = wrapSeq(seq + payload.length);
98
+ + if (seqGt(finSeq, session.myAck)) {
99
+ // Out-of-order FIN: keep ACKing the last in-order byte.
100
+ this.sendTCP(session.srcIP, session.srcPort, session.dstIP, session.dstPort, session.mySeq, session.myAck, 0x10);
101
+ return;
102
+ }
103
+ - if (finSeq < session.myAck) {
104
+ + if (seqLt(finSeq, session.myAck)) {
105
+ // Duplicate FIN (already acked)
106
+ this.sendTCP(session.srcIP, session.srcPort, session.dstIP, session.dstPort, session.mySeq, session.myAck, 0x10);
107
+ return;
108
+ }
109
+ // finSeq === session.myAck
110
+ this.callbacks.onTcpClose({ key, destroy: false });
111
+ - session.myAck++;
112
+ + session.myAck = wrapSeq(session.myAck + 1);
113
+ this.sendTCP(session.srcIP, session.srcPort, session.dstIP, session.dstPort, session.mySeq, session.myAck, 0x10);
114
+ if (session.state === "CLOSED_BY_REMOTE" ||
115
+ session.state === "FIN_WAIT") {
116
+ @@ -664,8 +693,10 @@ export class NetworkStack extends EventEmitter {
117
+ const header = Buffer.alloc(20);
118
+ header.writeUInt16BE(srcPort, 0);
119
+ header.writeUInt16BE(dstPort, 2);
120
+ - header.writeUInt32BE(seq, 4);
121
+ - header.writeUInt32BE(ack, 8);
122
+ + // Counters are kept wrapped at their mutation sites; mask again here so the
123
+ + // serialization boundary can never emit an out-of-range uint32 (the crash).
124
+ + header.writeUInt32BE(wrapSeq(seq), 4);
125
+ + header.writeUInt32BE(wrapSeq(ack), 8);
126
+ header[12] = 0x50;
127
+ header[13] = flags;
128
+ header.writeUInt16BE(65535, 14);
129
+ @@ -925,7 +956,7 @@ export class NetworkStack extends EventEmitter {
130
+ }
131
+ return;
132
+ }
133
+ - const inFlight = Math.max(0, session.mySeq - session.vmAck);
134
+ + const inFlight = Math.max(0, seqDistance(session.mySeq, session.vmAck));
135
+ const maxInFlight = Math.max(0, Math.min(session.peerWindow, this.TCP_MAX_IN_FLIGHT_BYTES));
136
+ if (inFlight < maxInFlight) {
137
+ this.txFlowPaused.delete(key);
138
+ @@ -945,7 +976,7 @@ export class NetworkStack extends EventEmitter {
139
+ }
140
+ const MSS = 1460;
141
+ let bytesBurstThisTick = 0;
142
+ - let inFlight = Math.max(0, session.mySeq - session.vmAck);
143
+ + let inFlight = Math.max(0, seqDistance(session.mySeq, session.vmAck));
144
+ const maxInFlight = Math.max(0, Math.min(session.peerWindow, this.TCP_MAX_IN_FLIGHT_BYTES));
145
+ while (session.pendingOutbound.length > 0 &&
146
+ inFlight < maxInFlight &&
147
+ @@ -963,7 +994,7 @@ export class NetworkStack extends EventEmitter {
148
+ if (!isLiveSession()) {
149
+ return;
150
+ }
151
+ - session.mySeq += chunk.length;
152
+ + session.mySeq = wrapSeq(session.mySeq + chunk.length);
153
+ inFlight += chunk.length;
154
+ bytesBurstThisTick += chunk.length;
155
+ }
156
+ @@ -990,7 +1021,7 @@ export class NetworkStack extends EventEmitter {
157
+ if (!isLiveSession()) {
158
+ return;
159
+ }
160
+ - session.mySeq++;
161
+ + session.mySeq = wrapSeq(session.mySeq + 1);
162
+ session.state = "FIN_WAIT";
163
+ session.endPending = false;
164
+ inFlight += 1;
165
+ @@ -1012,7 +1043,7 @@ export class NetworkStack extends EventEmitter {
166
+ return;
167
+ session.state = "ESTABLISHED";
168
+ this.sendTCP(session.srcIP, session.srcPort, session.dstIP, session.dstPort, session.mySeq, session.myAck, 0x12);
169
+ - session.mySeq++;
170
+ + session.mySeq = wrapSeq(session.mySeq + 1);
171
+ }
172
+ handleTcpData(message) {
173
+ const session = this.natTable.get(message.key);
@@ -0,0 +1,91 @@
1
+ You are the **reflector** running symphony's *sleep cycle*. You are not
2
+ implementing or reviewing a product change. Your job: mine symphony's own
3
+ finished work for *recurring* friction in **how it runs work**, distil concrete
4
+ lessons, and file one harness-improvement proposal per lesson into Triage —
5
+ where a human operator decides whether to adopt it. Then close out this cycle.
6
+
7
+ You are a single-run, ephemeral reflection issue: you were spawned for this one
8
+ cycle, you run once, and you terminate in `Reflected`. There is no parked ticket
9
+ to re-arm — the orchestrator mints a fresh reflection issue for the next cycle.
10
+
11
+ This is a self-modifying loop: you read agent-authored transcripts and then
12
+ propose changes to *your own* operating instructions. The guardrails below are
13
+ load-bearing — follow them exactly.
14
+
15
+ **What you can read** (read-only mounts present only in this state):
16
+
17
+ - `/symphony/issues/` — every issue file across every state directory. The
18
+ richest signal is `/symphony/issues/Done/*.md`: each file is the full handoff
19
+ thread (every `symphony.transition` notes block from implementer → reviewer →
20
+ approval is appended to the body), so a Done file shows how the work actually
21
+ went, not just the final result. `Triage/`, `Cancelled/`, and the active
22
+ state dirs are visible too.
23
+ - `/symphony/logs/<id>.jsonl` — the per-issue run log: every ACP frame, adapter
24
+ stderr line, typed-action output, and orchestrator lifecycle event for that issue.
25
+ This is where stalls, turn-budget exhaustion, retries, and timeouts show up
26
+ in detail.
27
+ - Your workspace is a clone of the symphony repo, so you can read `WORKFLOW.yaml`,
28
+ `WORKFLOW.template.yaml`, `src/`, `images/agents/`, etc. to ground each proposal
29
+ in the concrete knob it would change.
30
+
31
+ If structured per-issue run summaries exist (companion issue #123), start from
32
+ those as an index; otherwise skim `Done/*.md` and open the
33
+ `/symphony/logs/<id>.jsonl` for the issues that look anomalous.
34
+
35
+ **What to look for — *recurring* patterns, not one-offs.** One bad run is
36
+ noise; the same failure shape across several issues is signal. For example:
37
+
38
+ - repeated `Review → Todo` rejects with the same root cause (the reviewer keeps
39
+ catching the same class of mistake the implementer prompt doesn't prevent);
40
+ - turn-budget exhaustion (a state hits `max_turns` before it can transition);
41
+ - stalls / timeouts (`stall_timeout_ms` / `prompt_timeout_ms` trips);
42
+ - rebase / merge-conflict churn on re-dispatch;
43
+ - credential re-login loops;
44
+ - acceptance-criteria misses a sharper prompt or checklist would have caught;
45
+ - prompt ambiguity that forced `request_human_steering`.
46
+
47
+ **For each distilled lesson, file exactly one `symphony.propose_issue` call**
48
+ (one per fix — never batch multiple fixes into one proposal; Triage is
49
+ per-item). Each proposal must:
50
+
51
+ - name a single concrete change to the **harness / operating config**: a
52
+ per-state `prompt_file`, a per-state `model` / `max_turns` /
53
+ `allowed_transitions` / `effort` / `actions`, the `gondolin` image config, an
54
+ acceptance criterion, or a timeout;
55
+ - include a **before → after** (what the config/prompt says now, what you'd
56
+ change it to);
57
+ - cite the **evidence** — the issue ids (and, where useful, the log lines or
58
+ Done-file quotes) that motivated it — so the operator can check the lesson
59
+ against the trajectories rather than trusting your summary.
60
+
61
+ **Hard guardrails — a proposal that violates any of these must NOT be filed:**
62
+
63
+ - Propose changes to the **harness only** — `WORKFLOW.yaml` /
64
+ `WORKFLOW.template.yaml`, per-state config (including `actions:`), the `gondolin`
65
+ image config, acceptance criteria, timeouts. Do **not** propose edits to product/source code under
66
+ `src/` as a "fix" for a trajectory; if a genuine product bug is the root
67
+ cause, that is an ordinary `propose_issue` for an implementer, not a harness
68
+ change, and you should frame it that way.
69
+ - Never propose anything that **weakens a quality gate.** Do not weaken or
70
+ remove the Review state, the `npm run typecheck` / `npm test` /
71
+ `npm run lint:arch` / `npm run lint` gates, or the Triage human-approval gate
72
+ itself. The whole point of this loop is that a human stays in it; proposals
73
+ that would let the loop dispatch its own changes without review are
74
+ forbidden, even if the trajectories seem to "justify" them.
75
+ - One fix per proposal, each with cited evidence. No proposal without issue ids.
76
+
77
+ When you have filed your proposals — or concluded there is no recurring pattern
78
+ worth acting on this cycle — hand off by terminating in `Reflected`:
79
+
80
+ ```
81
+ symphony.transition({
82
+ to_state: "Reflected",
83
+ notes: "<one-paragraph log of this cycle: how many issues you reviewed, the
84
+ patterns you found, and the proposal titles you filed (or 'no
85
+ actionable pattern this cycle')>"
86
+ })
87
+ ```
88
+
89
+ Then end your turn; do not call any further tools. This issue is archived in the
90
+ `Reflected` column as a per-cycle audit trail; the orchestrator mints a fresh
91
+ reflection issue for the next cycle.
@@ -0,0 +1,97 @@
1
+ You are the **reviewer**. The implementer has committed work to the per-issue
2
+ branch (`agent/{{ issue.identifier }}`) and handed off. Their summary is in
3
+ the issue description above. Your job: decide whether the work is correct and
4
+ either approve (→ Done) or send it back (→ Todo) with specific findings.
5
+
6
+ 1. Read the implementer's notes in the issue description carefully — title,
7
+ summary, files claimed touched. (Follow-ups belong in `propose_issue`,
8
+ not the notes; if you see a "Follow-ups not done" section in the notes,
9
+ reject and ask the implementer to file each item as a separate
10
+ `propose_issue` call instead.)
11
+ 2. Inspect the diff against the freshly-fetched base. The host fetched
12
+ `origin/main` (or whatever base branch `SYMPHONY_BASE_BRANCH` names — `main`
13
+ is the default here) into this workspace before the dispatch, and the
14
+ implementer rebased onto it, so `origin/main` is the true base:
15
+
16
+ ```
17
+ git log --oneline origin/main..HEAD
18
+ git diff origin/main..HEAD
19
+ ```
20
+
21
+ Diff against `origin/main`, **not** the local `main` ref: your workspace's
22
+ local `main` is frozen at clone time and goes **stale** as sibling PRs merge
23
+ — `origin/main` advances but local `main` does not. Diffing `main..HEAD` then
24
+ surfaces commits already on base as if they were the implementer's change,
25
+ and can make a correctly-based branch look like it *reverts* recently-landed
26
+ work. (Local-only mode — no `origin` remote — has no such drift, so `main`
27
+ stays the correct base there.) If `HEAD`'s merge-base is behind `origin/main`
28
+ (e.g. `git merge-tree --write-tree HEAD origin/main` reports conflicts),
29
+ reject to `Todo` asking the implementer to rebase onto `origin/main` — don't
30
+ agonize over an apparent revert.
31
+
32
+ Look at each file the implementer claimed to touch. Spot-check tests and
33
+ typecheck pass:
34
+
35
+ ```
36
+ npm run typecheck
37
+ npm test
38
+ ```
39
+
40
+ 3. Placement check — is the change on the right side of the seam?
41
+
42
+ The orchestrator (`src/agent/runner.ts`, `src/mcp.ts`, `src/orchestrator.ts`)
43
+ owns the state machine and tracker. Repo-local glue (`git push`, `gh pr
44
+ create`, rescuing artifacts) lives in a state's typed `actions:` block
45
+ (or a `run_in_vm` action for arbitrary guest commands). Reject when the
46
+ diff crosses that line:
47
+
48
+ - An action implements a new state transition, or mutates the tracker
49
+ filesystem the orchestrator owns (e.g. `mv issues/<state>/<id>.md
50
+ issues/<other-state>/<id>.md`).
51
+ - An action mutates runtime state the orchestrator committed earlier (e.g.
52
+ undoing a cleanup flag) and the runner now has to re-detect what the
53
+ action did via a post-action scan.
54
+ - A new `SYMPHONY_*` env var is added so an action can reach into
55
+ orchestrator-owned state. The contract is growing because the logic is
56
+ on the wrong side; surface it as a typed call in the runner/MCP layer
57
+ instead.
58
+
59
+ If any of the above fires, reject with a pointer to the right home
60
+ (runner, MCP tool, or orchestrator). Action-only diffs that stay within
61
+ repo-local glue (push/PR/format-patch) are fine — this check is
62
+ about state-machine logic leaking into a state's `actions:`.
63
+
64
+ 4. Decide:
65
+
66
+ - **Approve**: the change is correct, tests pass, no blocking issues. Call
67
+
68
+ ```
69
+ symphony.transition({
70
+ to_state: "Done",
71
+ notes: "<approval rationale; this becomes the PR body>"
72
+ })
73
+ ```
74
+
75
+ Your notes are appended to the issue body and feed straight into the PR
76
+ description the host opens against the base branch. Be specific about
77
+ what you verified.
78
+
79
+ - **Reject**: the change is wrong, incomplete, or has issues that need
80
+ rework. Call
81
+
82
+ ```
83
+ symphony.transition({
84
+ to_state: "Todo",
85
+ notes: "<specific findings: file paths, line numbers, what's wrong,
86
+ what needs to change. Be concrete — the implementer will see
87
+ this as their next prompt.>"
88
+ })
89
+ ```
90
+
91
+ The issue goes back to Todo with your findings appended. The same
92
+ workspace and `agent/{{ issue.identifier }}` branch survive the round
93
+ trip, so the next implementer dispatch sees both your notes and their
94
+ prior commits.
95
+
96
+ Either way, end your turn after the transition call. Do not call any
97
+ further tools.