factory-factory 0.4.1 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (707) hide show
  1. package/README.md +1 -1
  2. package/dist/client/assets/abnfDiagram-VRR7QNED-Bz06FkfB.js +1 -0
  3. package/dist/client/assets/arc--1iscGgN.js +1 -0
  4. package/dist/client/assets/architectureDiagram-ZJ3FMSHR-Ds-52hDI.js +36 -0
  5. package/dist/client/assets/blockDiagram-677ZJIJ3-DZwPPZmp.js +132 -0
  6. package/dist/client/assets/{c4Diagram-AAUBKEIU-CT8hJB-h.js → c4Diagram-LMCZKHZV-RQch21fC.js} +1 -1
  7. package/dist/client/assets/channel-DFzHt_cl.js +1 -0
  8. package/dist/client/assets/{chunk-QZHKN3VN-Ce3Q_vrs.js → chunk-2Q5K7J3B-Df6Q19iI.js} +1 -1
  9. package/dist/client/assets/{chunk-ND2GUHAM-Qhi4WqzZ.js → chunk-32BRIVSS-DlbaZtVC.js} +1 -1
  10. package/dist/client/assets/{chunk-FMBD7UC4-B4C3KvLe.js → chunk-5VM5RSS4-KgkMhS6k.js} +1 -1
  11. package/dist/client/assets/chunk-EX3LRPZG-DAfTWCem.js +231 -0
  12. package/dist/client/assets/{chunk-4BX2VUAB-km6NpEMz.js → chunk-JWPE2WC7-D6Y5C5Yz.js} +1 -1
  13. package/dist/client/assets/chunk-MOJQB5TN-B_P4pqPC.js +88 -0
  14. package/dist/client/assets/chunk-RYQCIY6F-CzFboHFv.js +1 -0
  15. package/dist/client/assets/{chunk-727SXJPM-Bp-ts2at.js → chunk-V7JOEXUC-8yT3lW_D.js} +5 -5
  16. package/dist/client/assets/{chunk-2J33WTMH-B0h8q8fD.js → chunk-VR4S4FIN-B_QG1di-.js} +1 -1
  17. package/dist/client/assets/{chunk-55IACEB6-COUWt3oA.js → chunk-XXDRQBXY-CzL4_omu.js} +1 -1
  18. package/dist/client/assets/classDiagram-OUVF2IWQ-IkvZ4qsF.js +1 -0
  19. package/dist/client/assets/classDiagram-v2-EOCWNBFH-IkvZ4qsF.js +1 -0
  20. package/dist/client/assets/{cose-bilkent-S5V4N54A-D6QofwFq.js → cose-bilkent-JH36ORCC-DmZLPx5-.js} +1 -1
  21. package/dist/client/assets/cynefin-VYW2F7L2-DUejQU5F.js +166 -0
  22. package/dist/client/assets/cynefinDiagram-TSTJHNR4-BjallChk.js +62 -0
  23. package/dist/client/assets/cytoscape.esm-D3_iZ_3b.js +321 -0
  24. package/dist/client/assets/dagre-VKFMJZFB-COdOy8Kp.js +4 -0
  25. package/dist/client/assets/{diagram-KO2AKTUF-B9ABz-Wk.js → diagram-FQU43EPY-C8Xk7Fyh.js} +3 -3
  26. package/dist/client/assets/diagram-G47NLZAW-B_qqKBqq.js +24 -0
  27. package/dist/client/assets/diagram-NH7WQ7WH-DS1-6fzl.js +24 -0
  28. package/dist/client/assets/diagram-OA4YK3LP-enaDU5V4.js +30 -0
  29. package/dist/client/assets/diagram-WEI45ONY-Cx6LFRuh.js +41 -0
  30. package/dist/client/assets/ebnfDiagram-CCIWWBDH-DVGMcsj6.js +1 -0
  31. package/dist/client/assets/erDiagram-Q63AITRT-DCsDfIB_.js +85 -0
  32. package/dist/client/assets/flowDiagram-23GEKE2U-C5QCjsF8.js +156 -0
  33. package/dist/client/assets/ganttDiagram-NO4QXBWP-CLvtSsZ-.js +292 -0
  34. package/dist/client/assets/gitGraphDiagram-IHSO6WYX-BS6vNDTo.js +106 -0
  35. package/dist/client/assets/{graph--OzhPTMs.js → graph-DOmOIIwC.js} +1 -1
  36. package/dist/client/assets/index-0-xpZu6O.js +689 -0
  37. package/dist/client/assets/index-CxLzpVmH.css +1 -0
  38. package/dist/client/assets/infoDiagram-FWYZ7A6U-CIuYQAoE.js +2 -0
  39. package/dist/client/assets/{ishikawaDiagram-YF4QCWOH-BLrvV5ke.js → ishikawaDiagram-FXEZZL3T-DeVUVV8X.js} +5 -5
  40. package/dist/client/assets/{journeyDiagram-JHISSGLW-B2-TMwJI.js → journeyDiagram-5HDEW3XC-BsmmwqMS.js} +3 -3
  41. package/dist/client/assets/{kanban-definition-UN3LZRKU-B5mGKgYF.js → kanban-definition-HUTT4EX6-D-mDPzR0.js} +20 -20
  42. package/dist/client/assets/katex-HP8lGamR.js +257 -0
  43. package/dist/client/assets/layout-D-LzfAck.js +1 -0
  44. package/dist/client/assets/{linear-ConE9euY.js → linear-BSdMIO3_.js} +1 -1
  45. package/dist/client/assets/map-DxJ2ADlA.js +1 -0
  46. package/dist/client/assets/{mindmap-definition-RKZ34NQL-B0BaMk8D.js → mindmap-definition-LN4V7U3C-DOuSISM2.js} +3 -3
  47. package/dist/client/assets/{mobile-baseline-DWCt7ZGJ.js → mobile-baseline-C-1Tc5b_.js} +1 -1
  48. package/dist/client/assets/pegDiagram-2B236MQR-C8CMsmVK.js +1 -0
  49. package/dist/client/assets/pieDiagram-ENE6RG2P-B1UfUhQO.js +39 -0
  50. package/dist/client/assets/{quadrantDiagram-W4KKPZXB-DDbeggF4.js → quadrantDiagram-ABIIQ3AL-DujmyYtF.js} +3 -3
  51. package/dist/client/assets/railroadDiagram-RFXS5EU6-DaF-IoiS.js +1 -0
  52. package/dist/client/assets/{requirementDiagram-4Y6WPE33-Cc3ozz7U.js → requirementDiagram-TGXJPOKE-dfpBVIPb.js} +1 -1
  53. package/dist/client/assets/sankeyDiagram-HTMAVEWB-BYCvwHlS.js +40 -0
  54. package/dist/client/assets/sequenceDiagram-DBY2YBRQ-DOdQoxUf.js +162 -0
  55. package/dist/client/assets/sizeCapture-X5ZJPWSS-9sUXw3Q8.js +1 -0
  56. package/dist/client/assets/stateDiagram-2N3HPSRC-QZszWUA_.js +1 -0
  57. package/dist/client/assets/stateDiagram-v2-6OUMAXLB-CueME36n.js +1 -0
  58. package/dist/client/assets/swimlanes-5IMT3BWC-CtEVTRNN.js +2 -0
  59. package/dist/client/assets/swimlanesDiagram-G3AALYLV-DITFxuwY.js +8 -0
  60. package/dist/client/assets/{terminal-instance-CDKJdDaO.js → terminal-instance-nU4PXHMm.js} +1 -1
  61. package/dist/client/assets/{timeline-definition-PNZ67QCA-CyxBqgqv.js → timeline-definition-FHXFAJF6-0fOfnsxU.js} +3 -3
  62. package/dist/client/assets/vennDiagram-L72KCM5P-5eWMXdkg.js +34 -0
  63. package/dist/client/assets/{wardleyDiagram-YWT4CUSO-CjJBpd3P.js → wardleyDiagram-EHGQE667-BwNCxx2w.js} +4 -4
  64. package/dist/client/assets/xychartDiagram-FW5EYKEG-VIc8vlw6.js +7 -0
  65. package/dist/client/index.html +2 -2
  66. package/dist/prisma/generated/browser.d.ts +4 -0
  67. package/dist/prisma/generated/browser.d.ts.map +1 -1
  68. package/dist/prisma/generated/client.d.ts +4 -0
  69. package/dist/prisma/generated/client.d.ts.map +1 -1
  70. package/dist/prisma/generated/commonInputTypes.d.ts +88 -148
  71. package/dist/prisma/generated/commonInputTypes.d.ts.map +1 -1
  72. package/dist/prisma/generated/enums.d.ts +0 -6
  73. package/dist/prisma/generated/enums.d.ts.map +1 -1
  74. package/dist/prisma/generated/enums.js +0 -5
  75. package/dist/prisma/generated/enums.js.map +1 -1
  76. package/dist/prisma/generated/internal/class.d.ts +16 -2
  77. package/dist/prisma/generated/internal/class.d.ts.map +1 -1
  78. package/dist/prisma/generated/internal/class.js +6 -6
  79. package/dist/prisma/generated/internal/class.js.map +1 -1
  80. package/dist/prisma/generated/internal/prismaNamespace.d.ts +370 -47
  81. package/dist/prisma/generated/internal/prismaNamespace.d.ts.map +1 -1
  82. package/dist/prisma/generated/internal/prismaNamespace.js +51 -37
  83. package/dist/prisma/generated/internal/prismaNamespace.js.map +1 -1
  84. package/dist/prisma/generated/internal/prismaNamespaceBrowser.d.ts +52 -34
  85. package/dist/prisma/generated/internal/prismaNamespaceBrowser.d.ts.map +1 -1
  86. package/dist/prisma/generated/internal/prismaNamespaceBrowser.js +49 -35
  87. package/dist/prisma/generated/internal/prismaNamespaceBrowser.js.map +1 -1
  88. package/dist/prisma/generated/models/Workspace.d.ts +1017 -2537
  89. package/dist/prisma/generated/models/Workspace.d.ts.map +1 -1
  90. package/dist/prisma/generated/models/WorkspaceAutoIteration.d.ts +524 -0
  91. package/dist/prisma/generated/models/WorkspaceAutoIteration.d.ts.map +1 -0
  92. package/dist/prisma/generated/models/WorkspaceAutoIteration.js +2 -0
  93. package/dist/prisma/generated/models/WorkspaceAutoIteration.js.map +1 -0
  94. package/dist/prisma/generated/models/WorkspacePR.d.ts +858 -0
  95. package/dist/prisma/generated/models/WorkspacePR.d.ts.map +1 -0
  96. package/dist/prisma/generated/models/WorkspacePR.js +2 -0
  97. package/dist/prisma/generated/models/WorkspacePR.js.map +1 -0
  98. package/dist/prisma/generated/models/WorkspaceRatchet.d.ts +593 -0
  99. package/dist/prisma/generated/models/WorkspaceRatchet.d.ts.map +1 -0
  100. package/dist/prisma/generated/models/WorkspaceRatchet.js +2 -0
  101. package/dist/prisma/generated/models/WorkspaceRatchet.js.map +1 -0
  102. package/dist/prisma/generated/models/WorkspaceRunScript.d.ts +631 -0
  103. package/dist/prisma/generated/models/WorkspaceRunScript.d.ts.map +1 -0
  104. package/dist/prisma/generated/models/WorkspaceRunScript.js +2 -0
  105. package/dist/prisma/generated/models/WorkspaceRunScript.js.map +1 -0
  106. package/dist/prisma/generated/models.d.ts +4 -0
  107. package/dist/prisma/generated/models.d.ts.map +1 -1
  108. package/dist/src/backend/app-context.d.ts +4 -1
  109. package/dist/src/backend/app-context.d.ts.map +1 -1
  110. package/dist/src/backend/app-context.js +8 -6
  111. package/dist/src/backend/app-context.js.map +1 -1
  112. package/dist/src/backend/interceptors/auto-branch-rename.d.ts +19 -0
  113. package/dist/src/backend/interceptors/auto-branch-rename.d.ts.map +1 -0
  114. package/dist/src/backend/interceptors/auto-branch-rename.js +76 -0
  115. package/dist/src/backend/interceptors/auto-branch-rename.js.map +1 -0
  116. package/dist/src/backend/interceptors/branch-naming.interceptor.d.ts +4 -0
  117. package/dist/src/backend/interceptors/branch-naming.interceptor.d.ts.map +1 -0
  118. package/dist/src/backend/interceptors/branch-naming.interceptor.js +391 -0
  119. package/dist/src/backend/interceptors/branch-naming.interceptor.js.map +1 -0
  120. package/dist/src/backend/interceptors/branch-naming.interceptor.test.d.ts +2 -0
  121. package/dist/src/backend/interceptors/branch-naming.interceptor.test.d.ts.map +1 -0
  122. package/dist/src/backend/interceptors/branch-naming.interceptor.test.js +780 -0
  123. package/dist/src/backend/interceptors/branch-naming.interceptor.test.js.map +1 -0
  124. package/dist/src/backend/interceptors/branch-rename.utils.d.ts +1 -1
  125. package/dist/src/backend/interceptors/branch-rename.utils.d.ts.map +1 -1
  126. package/dist/src/backend/interceptors/branch-rename.utils.js +10 -14
  127. package/dist/src/backend/interceptors/branch-rename.utils.js.map +1 -1
  128. package/dist/src/backend/interceptors/index.d.ts.map +1 -1
  129. package/dist/src/backend/interceptors/index.js +2 -6
  130. package/dist/src/backend/interceptors/index.js.map +1 -1
  131. package/dist/src/backend/orchestration/data-backup.service.d.ts.map +1 -1
  132. package/dist/src/backend/orchestration/data-backup.service.js +103 -53
  133. package/dist/src/backend/orchestration/data-backup.service.js.map +1 -1
  134. package/dist/src/backend/orchestration/data-backup.service.test.js +186 -47
  135. package/dist/src/backend/orchestration/data-backup.service.test.js.map +1 -1
  136. package/dist/src/backend/orchestration/domain-bridges.orchestrator.d.ts +7 -5
  137. package/dist/src/backend/orchestration/domain-bridges.orchestrator.d.ts.map +1 -1
  138. package/dist/src/backend/orchestration/domain-bridges.orchestrator.js +116 -60
  139. package/dist/src/backend/orchestration/domain-bridges.orchestrator.js.map +1 -1
  140. package/dist/src/backend/orchestration/domain-bridges.orchestrator.test.js +262 -104
  141. package/dist/src/backend/orchestration/domain-bridges.orchestrator.test.js.map +1 -1
  142. package/dist/src/backend/orchestration/event-collector-lifecycle.integration.test.js +2 -2
  143. package/dist/src/backend/orchestration/event-collector-lifecycle.integration.test.js.map +1 -1
  144. package/dist/src/backend/orchestration/event-collector.orchestrator.d.ts +5 -6
  145. package/dist/src/backend/orchestration/event-collector.orchestrator.d.ts.map +1 -1
  146. package/dist/src/backend/orchestration/event-collector.orchestrator.js +12 -35
  147. package/dist/src/backend/orchestration/event-collector.orchestrator.js.map +1 -1
  148. package/dist/src/backend/orchestration/event-collector.orchestrator.test.js +42 -26
  149. package/dist/src/backend/orchestration/event-collector.orchestrator.test.js.map +1 -1
  150. package/dist/src/backend/orchestration/reconciliation.service.d.ts +4 -3
  151. package/dist/src/backend/orchestration/reconciliation.service.d.ts.map +1 -1
  152. package/dist/src/backend/orchestration/reconciliation.service.js +26 -38
  153. package/dist/src/backend/orchestration/reconciliation.service.js.map +1 -1
  154. package/dist/src/backend/orchestration/reconciliation.service.test.js +3 -3
  155. package/dist/src/backend/orchestration/reconciliation.service.test.js.map +1 -1
  156. package/dist/src/backend/orchestration/scheduler.service.d.ts +4 -3
  157. package/dist/src/backend/orchestration/scheduler.service.d.ts.map +1 -1
  158. package/dist/src/backend/orchestration/scheduler.service.js +40 -43
  159. package/dist/src/backend/orchestration/scheduler.service.js.map +1 -1
  160. package/dist/src/backend/orchestration/scheduler.service.test.js +52 -10
  161. package/dist/src/backend/orchestration/scheduler.service.test.js.map +1 -1
  162. package/dist/src/backend/orchestration/snapshot-reconciliation.orchestrator.d.ts +5 -5
  163. package/dist/src/backend/orchestration/snapshot-reconciliation.orchestrator.d.ts.map +1 -1
  164. package/dist/src/backend/orchestration/snapshot-reconciliation.orchestrator.js +20 -61
  165. package/dist/src/backend/orchestration/snapshot-reconciliation.orchestrator.js.map +1 -1
  166. package/dist/src/backend/orchestration/snapshot-reconciliation.orchestrator.test.js +29 -3
  167. package/dist/src/backend/orchestration/snapshot-reconciliation.orchestrator.test.js.map +1 -1
  168. package/dist/src/backend/orchestration/workspace-archive.orchestrator.d.ts +3 -37
  169. package/dist/src/backend/orchestration/workspace-archive.orchestrator.d.ts.map +1 -1
  170. package/dist/src/backend/orchestration/workspace-archive.orchestrator.js +2 -2
  171. package/dist/src/backend/orchestration/workspace-archive.orchestrator.js.map +1 -1
  172. package/dist/src/backend/orchestration/workspace-archive.orchestrator.test.js +9 -9
  173. package/dist/src/backend/orchestration/workspace-archive.orchestrator.test.js.map +1 -1
  174. package/dist/src/backend/orchestration/workspace-init.orchestrator.js +3 -3
  175. package/dist/src/backend/orchestration/workspace-init.orchestrator.js.map +1 -1
  176. package/dist/src/backend/orchestration/workspace-init.orchestrator.test.js +18 -18
  177. package/dist/src/backend/orchestration/workspace-init.orchestrator.test.js.map +1 -1
  178. package/dist/src/backend/orchestration/workspace-notification-delivery.orchestrator.d.ts.map +1 -1
  179. package/dist/src/backend/orchestration/workspace-notification-delivery.orchestrator.js +8 -1
  180. package/dist/src/backend/orchestration/workspace-notification-delivery.orchestrator.js.map +1 -1
  181. package/dist/src/backend/orchestration/workspace-notification-delivery.orchestrator.test.js +23 -0
  182. package/dist/src/backend/orchestration/workspace-notification-delivery.orchestrator.test.js.map +1 -1
  183. package/dist/src/backend/routers/websocket/chat.handler.d.ts.map +1 -1
  184. package/dist/src/backend/routers/websocket/chat.handler.js +10 -6
  185. package/dist/src/backend/routers/websocket/chat.handler.js.map +1 -1
  186. package/dist/src/backend/routers/websocket/chat.handler.test.js +37 -11
  187. package/dist/src/backend/routers/websocket/chat.handler.test.js.map +1 -1
  188. package/dist/src/backend/routers/websocket/index.d.ts +1 -2
  189. package/dist/src/backend/routers/websocket/index.d.ts.map +1 -1
  190. package/dist/src/backend/routers/websocket/index.js +1 -2
  191. package/dist/src/backend/routers/websocket/index.js.map +1 -1
  192. package/dist/src/backend/routers/websocket/log-stream-dev.handler.test.d.ts +2 -0
  193. package/dist/src/backend/routers/websocket/log-stream-dev.handler.test.d.ts.map +1 -0
  194. package/dist/src/backend/routers/websocket/{dev-logs.handler.test.js → log-stream-dev.handler.test.js} +2 -2
  195. package/dist/src/backend/routers/websocket/log-stream-dev.handler.test.js.map +1 -0
  196. package/dist/src/backend/routers/websocket/log-stream-post-run.handler.test.d.ts +2 -0
  197. package/dist/src/backend/routers/websocket/log-stream-post-run.handler.test.d.ts.map +1 -0
  198. package/dist/src/backend/routers/websocket/{post-run-logs.handler.test.js → log-stream-post-run.handler.test.js} +2 -2
  199. package/dist/src/backend/routers/websocket/log-stream-post-run.handler.test.js.map +1 -0
  200. package/dist/src/backend/routers/websocket/log-stream.handler.d.ts +8 -0
  201. package/dist/src/backend/routers/websocket/log-stream.handler.d.ts.map +1 -0
  202. package/dist/src/backend/routers/websocket/log-stream.handler.js +35 -0
  203. package/dist/src/backend/routers/websocket/log-stream.handler.js.map +1 -0
  204. package/dist/src/backend/routers/websocket/terminal.handler.d.ts.map +1 -1
  205. package/dist/src/backend/routers/websocket/terminal.handler.js +4 -2
  206. package/dist/src/backend/routers/websocket/terminal.handler.js.map +1 -1
  207. package/dist/src/backend/routers/websocket/terminal.handler.test.js +37 -0
  208. package/dist/src/backend/routers/websocket/terminal.handler.test.js.map +1 -1
  209. package/dist/src/backend/routers/websocket/websocket.integration.test.js +6 -9
  210. package/dist/src/backend/routers/websocket/websocket.integration.test.js.map +1 -1
  211. package/dist/src/backend/server.d.ts.map +1 -1
  212. package/dist/src/backend/server.js +12 -3
  213. package/dist/src/backend/server.js.map +1 -1
  214. package/dist/src/backend/server.upgrade.test.js +35 -6
  215. package/dist/src/backend/server.upgrade.test.js.map +1 -1
  216. package/dist/src/backend/services/auto-iteration/service/auto-iteration.service.test.js +15 -0
  217. package/dist/src/backend/services/auto-iteration/service/auto-iteration.service.test.js.map +1 -1
  218. package/dist/src/backend/services/auto-iteration/service/git-ops.d.ts.map +1 -1
  219. package/dist/src/backend/services/auto-iteration/service/git-ops.integration.test.d.ts +2 -0
  220. package/dist/src/backend/services/auto-iteration/service/git-ops.integration.test.d.ts.map +1 -0
  221. package/dist/src/backend/services/auto-iteration/service/git-ops.integration.test.js +86 -0
  222. package/dist/src/backend/services/auto-iteration/service/git-ops.integration.test.js.map +1 -0
  223. package/dist/src/backend/services/auto-iteration/service/git-ops.js +37 -2
  224. package/dist/src/backend/services/auto-iteration/service/git-ops.js.map +1 -1
  225. package/dist/src/backend/services/auto-iteration/service/test-runner.service.d.ts.map +1 -1
  226. package/dist/src/backend/services/auto-iteration/service/test-runner.service.js +9 -8
  227. package/dist/src/backend/services/auto-iteration/service/test-runner.service.js.map +1 -1
  228. package/dist/src/backend/services/auto-iteration/service/test-runner.service.test.d.ts +2 -0
  229. package/dist/src/backend/services/auto-iteration/service/test-runner.service.test.d.ts.map +1 -0
  230. package/dist/src/backend/services/auto-iteration/service/test-runner.service.test.js +80 -0
  231. package/dist/src/backend/services/auto-iteration/service/test-runner.service.test.js.map +1 -0
  232. package/dist/src/backend/services/check-single-writer.test.js +303 -32
  233. package/dist/src/backend/services/check-single-writer.test.js.map +1 -1
  234. package/dist/src/backend/services/constants.d.ts +1 -0
  235. package/dist/src/backend/services/constants.d.ts.map +1 -1
  236. package/dist/src/backend/services/constants.js +1 -0
  237. package/dist/src/backend/services/constants.js.map +1 -1
  238. package/dist/src/backend/services/env-schemas.d.ts +46 -46
  239. package/dist/src/backend/services/github/service/bridges.d.ts +6 -5
  240. package/dist/src/backend/services/github/service/bridges.d.ts.map +1 -1
  241. package/dist/src/backend/services/github/service/github-cli/mappers.d.ts +5 -2
  242. package/dist/src/backend/services/github/service/github-cli/mappers.d.ts.map +1 -1
  243. package/dist/src/backend/services/github/service/github-cli/mappers.js.map +1 -1
  244. package/dist/src/backend/services/github/service/github-cli/schemas.d.ts +4 -4
  245. package/dist/src/backend/services/github/service/github-cli.service.d.ts +5 -1
  246. package/dist/src/backend/services/github/service/github-cli.service.d.ts.map +1 -1
  247. package/dist/src/backend/services/github/service/github-cli.service.js.map +1 -1
  248. package/dist/src/backend/services/github/service/index.d.ts +2 -3
  249. package/dist/src/backend/services/github/service/index.d.ts.map +1 -1
  250. package/dist/src/backend/services/github/service/index.js +2 -2
  251. package/dist/src/backend/services/github/service/index.js.map +1 -1
  252. package/dist/src/backend/services/github/service/pr-fetch-coordinator.d.ts +33 -0
  253. package/dist/src/backend/services/github/service/pr-fetch-coordinator.d.ts.map +1 -0
  254. package/dist/src/backend/services/github/service/{pr-fetch-registry.js → pr-fetch-coordinator.js} +80 -69
  255. package/dist/src/backend/services/github/service/pr-fetch-coordinator.js.map +1 -0
  256. package/dist/src/backend/services/github/service/pr-fetch-coordinator.test.d.ts +2 -0
  257. package/dist/src/backend/services/github/service/pr-fetch-coordinator.test.d.ts.map +1 -0
  258. package/dist/src/backend/services/github/service/pr-fetch-coordinator.test.js +222 -0
  259. package/dist/src/backend/services/github/service/pr-fetch-coordinator.test.js.map +1 -0
  260. package/dist/src/backend/services/github/service/pr-snapshot.service.d.ts +12 -11
  261. package/dist/src/backend/services/github/service/pr-snapshot.service.d.ts.map +1 -1
  262. package/dist/src/backend/services/github/service/pr-snapshot.service.js +23 -22
  263. package/dist/src/backend/services/github/service/pr-snapshot.service.js.map +1 -1
  264. package/dist/src/backend/services/github/service/pr-snapshot.service.test.js +134 -75
  265. package/dist/src/backend/services/github/service/pr-snapshot.service.test.js.map +1 -1
  266. package/dist/src/backend/services/job-runner.service.d.ts +24 -0
  267. package/dist/src/backend/services/job-runner.service.d.ts.map +1 -0
  268. package/dist/src/backend/services/job-runner.service.js +168 -0
  269. package/dist/src/backend/services/job-runner.service.js.map +1 -0
  270. package/dist/src/backend/services/job-runner.service.test.d.ts +2 -0
  271. package/dist/src/backend/services/job-runner.service.test.d.ts.map +1 -0
  272. package/dist/src/backend/services/job-runner.service.test.js +498 -0
  273. package/dist/src/backend/services/job-runner.service.test.js.map +1 -0
  274. package/dist/src/backend/services/periodic-task/service/periodic-task.service.d.ts +8 -11
  275. package/dist/src/backend/services/periodic-task/service/periodic-task.service.d.ts.map +1 -1
  276. package/dist/src/backend/services/periodic-task/service/periodic-task.service.js +28 -50
  277. package/dist/src/backend/services/periodic-task/service/periodic-task.service.js.map +1 -1
  278. package/dist/src/backend/services/port.service.d.ts.map +1 -1
  279. package/dist/src/backend/services/port.service.js +4 -0
  280. package/dist/src/backend/services/port.service.js.map +1 -1
  281. package/dist/src/backend/services/port.service.test.js +9 -0
  282. package/dist/src/backend/services/port.service.test.js.map +1 -1
  283. package/dist/src/backend/services/ratchet/service/bridges.d.ts +24 -7
  284. package/dist/src/backend/services/ratchet/service/bridges.d.ts.map +1 -1
  285. package/dist/src/backend/services/ratchet/service/ratchet-active-session.helpers.d.ts.map +1 -1
  286. package/dist/src/backend/services/ratchet/service/ratchet-active-session.helpers.js +11 -10
  287. package/dist/src/backend/services/ratchet/service/ratchet-active-session.helpers.js.map +1 -1
  288. package/dist/src/backend/services/ratchet/service/ratchet-decision-logging.helpers.d.ts +1 -1
  289. package/dist/src/backend/services/ratchet/service/ratchet-decision-logging.helpers.js +1 -1
  290. package/dist/src/backend/services/ratchet/service/ratchet-decision-logging.helpers.js.map +1 -1
  291. package/dist/src/backend/services/ratchet/service/ratchet-fixer-dispatch.helpers.d.ts.map +1 -1
  292. package/dist/src/backend/services/ratchet/service/ratchet-fixer-dispatch.helpers.js +8 -3
  293. package/dist/src/backend/services/ratchet/service/ratchet-fixer-dispatch.helpers.js.map +1 -1
  294. package/dist/src/backend/services/ratchet/service/ratchet-pr-state.helpers.d.ts +1 -1
  295. package/dist/src/backend/services/ratchet/service/ratchet-pr-state.helpers.d.ts.map +1 -1
  296. package/dist/src/backend/services/ratchet/service/ratchet-pr-state.helpers.js +103 -95
  297. package/dist/src/backend/services/ratchet/service/ratchet-pr-state.helpers.js.map +1 -1
  298. package/dist/src/backend/services/ratchet/service/ratchet-pr-state.helpers.test.js +36 -22
  299. package/dist/src/backend/services/ratchet/service/ratchet-pr-state.helpers.test.js.map +1 -1
  300. package/dist/src/backend/services/ratchet/service/ratchet.service.d.ts +6 -8
  301. package/dist/src/backend/services/ratchet/service/ratchet.service.d.ts.map +1 -1
  302. package/dist/src/backend/services/ratchet/service/ratchet.service.js +58 -136
  303. package/dist/src/backend/services/ratchet/service/ratchet.service.js.map +1 -1
  304. package/dist/src/backend/services/ratchet/service/ratchet.service.test.js +323 -273
  305. package/dist/src/backend/services/ratchet/service/ratchet.service.test.js.map +1 -1
  306. package/dist/src/backend/services/ratchet/service/ratchet.types.d.ts +3 -1
  307. package/dist/src/backend/services/ratchet/service/ratchet.types.d.ts.map +1 -1
  308. package/dist/src/backend/services/registry.d.ts +6 -2
  309. package/dist/src/backend/services/registry.d.ts.map +1 -1
  310. package/dist/src/backend/services/registry.js +17 -1
  311. package/dist/src/backend/services/registry.js.map +1 -1
  312. package/dist/src/backend/services/resources.integration.test.js +73 -45
  313. package/dist/src/backend/services/resources.integration.test.js.map +1 -1
  314. package/dist/src/backend/services/run-script/service/run-script-proxy.service.d.ts +1 -0
  315. package/dist/src/backend/services/run-script/service/run-script-proxy.service.d.ts.map +1 -1
  316. package/dist/src/backend/services/run-script/service/run-script-proxy.service.js +25 -2
  317. package/dist/src/backend/services/run-script/service/run-script-proxy.service.js.map +1 -1
  318. package/dist/src/backend/services/run-script/service/run-script-proxy.service.test.js +124 -6
  319. package/dist/src/backend/services/run-script/service/run-script-proxy.service.test.js.map +1 -1
  320. package/dist/src/backend/services/run-script/service/run-script-state-machine.service.d.ts.map +1 -1
  321. package/dist/src/backend/services/run-script/service/run-script-state-machine.service.js.map +1 -1
  322. package/dist/src/backend/services/run-script/service/run-script-state-machine.service.test.js +125 -125
  323. package/dist/src/backend/services/run-script/service/run-script-state-machine.service.test.js.map +1 -1
  324. package/dist/src/backend/services/run-script/service/startup-script.service.d.ts.map +1 -1
  325. package/dist/src/backend/services/run-script/service/startup-script.service.js +20 -5
  326. package/dist/src/backend/services/run-script/service/startup-script.service.js.map +1 -1
  327. package/dist/src/backend/services/run-script/service/startup-script.service.test.js +95 -1
  328. package/dist/src/backend/services/run-script/service/startup-script.service.test.js.map +1 -1
  329. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/load-session.handler.d.ts.map +1 -1
  330. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/load-session.handler.js +4 -4
  331. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/load-session.handler.js.map +1 -1
  332. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/load-session.handler.test.js +4 -2
  333. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/load-session.handler.test.js.map +1 -1
  334. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/permission-response.handler.d.ts +2 -2
  335. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/permission-response.handler.d.ts.map +1 -1
  336. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/permission-response.handler.js +2 -2
  337. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/permission-response.handler.js.map +1 -1
  338. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/permission-response.handler.test.js +10 -25
  339. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/permission-response.handler.test.js.map +1 -1
  340. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/set-config-option.handler.d.ts.map +1 -1
  341. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/set-config-option.handler.js +10 -2
  342. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/set-config-option.handler.js.map +1 -1
  343. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/set-config-option.handler.test.js +41 -2
  344. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/set-config-option.handler.test.js.map +1 -1
  345. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/set-model.handler.d.ts +2 -2
  346. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/set-model.handler.d.ts.map +1 -1
  347. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/set-model.handler.js +4 -4
  348. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/set-model.handler.js.map +1 -1
  349. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/set-model.handler.test.js +1 -4
  350. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/set-model.handler.test.js.map +1 -1
  351. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/set-thinking-budget.handler.js +2 -2
  352. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/set-thinking-budget.handler.js.map +1 -1
  353. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/set-thinking-budget.handler.test.js +2 -2
  354. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/set-thinking-budget.handler.test.js.map +1 -1
  355. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/start.handler.js +2 -2
  356. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/start.handler.js.map +1 -1
  357. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/start.handler.test.js +2 -2
  358. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/start.handler.test.js.map +1 -1
  359. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/stop.handler.js +2 -2
  360. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/stop.handler.js.map +1 -1
  361. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/stop.handler.test.js +2 -2
  362. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/stop.handler.test.js.map +1 -1
  363. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/user-input.handler.d.ts +3 -2
  364. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/user-input.handler.d.ts.map +1 -1
  365. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/user-input.handler.js +2 -2
  366. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/user-input.handler.js.map +1 -1
  367. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/user-input.handler.test.js +17 -20
  368. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/user-input.handler.test.js.map +1 -1
  369. package/dist/src/backend/services/session/service/chat/chat-message-handlers/registry.d.ts.map +1 -1
  370. package/dist/src/backend/services/session/service/chat/chat-message-handlers/registry.js +15 -6
  371. package/dist/src/backend/services/session/service/chat/chat-message-handlers/registry.js.map +1 -1
  372. package/dist/src/backend/services/session/service/chat/chat-message-handlers/types.d.ts +12 -3
  373. package/dist/src/backend/services/session/service/chat/chat-message-handlers/types.d.ts.map +1 -1
  374. package/dist/src/backend/services/session/service/chat/chat-message-handlers.service.d.ts.map +1 -1
  375. package/dist/src/backend/services/session/service/chat/chat-message-handlers.service.js +18 -14
  376. package/dist/src/backend/services/session/service/chat/chat-message-handlers.service.js.map +1 -1
  377. package/dist/src/backend/services/session/service/chat/chat-message-handlers.service.test.js +7 -1
  378. package/dist/src/backend/services/session/service/chat/chat-message-handlers.service.test.js.map +1 -1
  379. package/dist/src/backend/services/session/service/data/session-provider-resolver.service.test.js +1 -3
  380. package/dist/src/backend/services/session/service/data/session-provider-resolver.service.test.js.map +1 -1
  381. package/dist/src/backend/services/session/service/index.d.ts +6 -1
  382. package/dist/src/backend/services/session/service/index.d.ts.map +1 -1
  383. package/dist/src/backend/services/session/service/index.js +5 -1
  384. package/dist/src/backend/services/session/service/index.js.map +1 -1
  385. package/dist/src/backend/services/session/service/interceptor.bridge.d.ts.map +1 -1
  386. package/dist/src/backend/services/session/service/interceptor.bridge.js +47 -3
  387. package/dist/src/backend/services/session/service/interceptor.bridge.js.map +1 -1
  388. package/dist/src/backend/services/session/service/interceptor.bridge.test.d.ts +2 -0
  389. package/dist/src/backend/services/session/service/interceptor.bridge.test.d.ts.map +1 -0
  390. package/dist/src/backend/services/session/service/interceptor.bridge.test.js +83 -0
  391. package/dist/src/backend/services/session/service/interceptor.bridge.test.js.map +1 -0
  392. package/dist/src/backend/services/session/service/lifecycle/session-services.d.ts +16 -0
  393. package/dist/src/backend/services/session/service/lifecycle/session-services.d.ts.map +1 -0
  394. package/dist/src/backend/services/session/service/lifecycle/session-services.js +79 -0
  395. package/dist/src/backend/services/session/service/lifecycle/session-services.js.map +1 -0
  396. package/dist/src/backend/services/session/service/lifecycle/session.lifecycle.service.d.ts +4 -2
  397. package/dist/src/backend/services/session/service/lifecycle/session.lifecycle.service.d.ts.map +1 -1
  398. package/dist/src/backend/services/session/service/lifecycle/session.lifecycle.service.js +6 -4
  399. package/dist/src/backend/services/session/service/lifecycle/session.lifecycle.service.js.map +1 -1
  400. package/dist/src/backend/services/session/service/lifecycle/session.lifecycle.service.test.js +10 -11
  401. package/dist/src/backend/services/session/service/lifecycle/session.lifecycle.service.test.js.map +1 -1
  402. package/dist/src/backend/services/session/service/lifecycle/session.prompt.service.test.d.ts +2 -0
  403. package/dist/src/backend/services/session/service/lifecycle/session.prompt.service.test.d.ts.map +1 -0
  404. package/dist/src/backend/services/session/service/lifecycle/session.prompt.service.test.js +142 -0
  405. package/dist/src/backend/services/session/service/lifecycle/session.prompt.service.test.js.map +1 -0
  406. package/dist/src/backend/services/session/service/lifecycle/session.repository.d.ts +5 -2
  407. package/dist/src/backend/services/session/service/lifecycle/session.repository.d.ts.map +1 -1
  408. package/dist/src/backend/services/session/service/lifecycle/session.repository.js.map +1 -1
  409. package/dist/src/backend/services/session/service/lifecycle/session.repository.test.js.map +1 -1
  410. package/dist/src/backend/services/session/service/lifecycle/session.service.d.ts +16 -76
  411. package/dist/src/backend/services/session/service/lifecycle/session.service.d.ts.map +1 -1
  412. package/dist/src/backend/services/session/service/lifecycle/session.service.js +21 -215
  413. package/dist/src/backend/services/session/service/lifecycle/session.service.js.map +1 -1
  414. package/dist/src/backend/services/session/service/lifecycle/session.service.test.js +159 -66
  415. package/dist/src/backend/services/session/service/lifecycle/session.service.test.js.map +1 -1
  416. package/dist/src/backend/services/settings/resources/data-backup.accessor.d.ts +10 -2
  417. package/dist/src/backend/services/settings/resources/data-backup.accessor.d.ts.map +1 -1
  418. package/dist/src/backend/services/settings/resources/data-backup.accessor.js +4 -1
  419. package/dist/src/backend/services/settings/resources/data-backup.accessor.js.map +1 -1
  420. package/dist/src/backend/services/settings/resources/user-settings.accessor.d.ts.map +1 -1
  421. package/dist/src/backend/services/settings/resources/user-settings.accessor.js +1 -0
  422. package/dist/src/backend/services/settings/resources/user-settings.accessor.js.map +1 -1
  423. package/dist/src/backend/services/settings/resources/user-settings.accessor.test.d.ts +2 -0
  424. package/dist/src/backend/services/settings/resources/user-settings.accessor.test.d.ts.map +1 -0
  425. package/dist/src/backend/services/settings/resources/user-settings.accessor.test.js +24 -0
  426. package/dist/src/backend/services/settings/resources/user-settings.accessor.test.js.map +1 -0
  427. package/dist/src/backend/services/terminal/service/terminal-session.service.d.ts +3 -37
  428. package/dist/src/backend/services/terminal/service/terminal-session.service.d.ts.map +1 -1
  429. package/dist/src/backend/services/workspace/resources/workspace-auto-iteration.accessor.d.ts +25 -0
  430. package/dist/src/backend/services/workspace/resources/workspace-auto-iteration.accessor.d.ts.map +1 -0
  431. package/dist/src/backend/services/workspace/resources/workspace-auto-iteration.accessor.js +73 -0
  432. package/dist/src/backend/services/workspace/resources/workspace-auto-iteration.accessor.js.map +1 -0
  433. package/dist/src/backend/services/workspace/resources/workspace-auto-iteration.accessor.test.d.ts +2 -0
  434. package/dist/src/backend/services/workspace/resources/workspace-auto-iteration.accessor.test.d.ts.map +1 -0
  435. package/dist/src/backend/services/workspace/resources/workspace-auto-iteration.accessor.test.js +155 -0
  436. package/dist/src/backend/services/workspace/resources/workspace-auto-iteration.accessor.test.js.map +1 -0
  437. package/dist/src/backend/services/workspace/resources/workspace-pr.accessor.d.ts +61 -0
  438. package/dist/src/backend/services/workspace/resources/workspace-pr.accessor.d.ts.map +1 -0
  439. package/dist/src/backend/services/workspace/resources/workspace-pr.accessor.js +265 -0
  440. package/dist/src/backend/services/workspace/resources/workspace-pr.accessor.js.map +1 -0
  441. package/dist/src/backend/services/workspace/resources/workspace-pr.accessor.test.d.ts +2 -0
  442. package/dist/src/backend/services/workspace/resources/workspace-pr.accessor.test.d.ts.map +1 -0
  443. package/dist/src/backend/services/workspace/resources/workspace-pr.accessor.test.js +398 -0
  444. package/dist/src/backend/services/workspace/resources/workspace-pr.accessor.test.js.map +1 -0
  445. package/dist/src/backend/services/workspace/resources/workspace-ratchet.accessor.d.ts +50 -0
  446. package/dist/src/backend/services/workspace/resources/workspace-ratchet.accessor.d.ts.map +1 -0
  447. package/dist/src/backend/services/workspace/resources/workspace-ratchet.accessor.js +179 -0
  448. package/dist/src/backend/services/workspace/resources/workspace-ratchet.accessor.js.map +1 -0
  449. package/dist/src/backend/services/workspace/resources/workspace-ratchet.accessor.test.d.ts +2 -0
  450. package/dist/src/backend/services/workspace/resources/workspace-ratchet.accessor.test.d.ts.map +1 -0
  451. package/dist/src/backend/services/workspace/resources/workspace-ratchet.accessor.test.js +311 -0
  452. package/dist/src/backend/services/workspace/resources/workspace-ratchet.accessor.test.js.map +1 -0
  453. package/dist/src/backend/services/workspace/resources/workspace-run-script.accessor.d.ts +33 -0
  454. package/dist/src/backend/services/workspace/resources/workspace-run-script.accessor.d.ts.map +1 -0
  455. package/dist/src/backend/services/workspace/resources/workspace-run-script.accessor.js +110 -0
  456. package/dist/src/backend/services/workspace/resources/workspace-run-script.accessor.js.map +1 -0
  457. package/dist/src/backend/services/workspace/resources/workspace-run-script.accessor.test.d.ts +2 -0
  458. package/dist/src/backend/services/workspace/resources/workspace-run-script.accessor.test.d.ts.map +1 -0
  459. package/dist/src/backend/services/workspace/resources/workspace-run-script.accessor.test.js +192 -0
  460. package/dist/src/backend/services/workspace/resources/workspace-run-script.accessor.test.js.map +1 -0
  461. package/dist/src/backend/services/workspace/resources/workspace.accessor.d.ts +61 -118
  462. package/dist/src/backend/services/workspace/resources/workspace.accessor.d.ts.map +1 -1
  463. package/dist/src/backend/services/workspace/resources/workspace.accessor.js +186 -426
  464. package/dist/src/backend/services/workspace/resources/workspace.accessor.js.map +1 -1
  465. package/dist/src/backend/services/workspace/resources/workspace.accessor.test.js +286 -623
  466. package/dist/src/backend/services/workspace/resources/workspace.accessor.test.js.map +1 -1
  467. package/dist/src/backend/services/workspace/service/bridges.d.ts +0 -1
  468. package/dist/src/backend/services/workspace/service/bridges.d.ts.map +1 -1
  469. package/dist/src/backend/services/workspace/service/index.d.ts +3 -3
  470. package/dist/src/backend/services/workspace/service/index.d.ts.map +1 -1
  471. package/dist/src/backend/services/workspace/service/index.js +2 -2
  472. package/dist/src/backend/services/workspace/service/index.js.map +1 -1
  473. package/dist/src/backend/services/workspace/service/lifecycle/creation.service.d.ts +3 -2
  474. package/dist/src/backend/services/workspace/service/lifecycle/creation.service.d.ts.map +1 -1
  475. package/dist/src/backend/services/workspace/service/lifecycle/creation.service.js +1 -1
  476. package/dist/src/backend/services/workspace/service/lifecycle/creation.service.js.map +1 -1
  477. package/dist/src/backend/services/workspace/service/lifecycle/creation.service.test.js +2 -3
  478. package/dist/src/backend/services/workspace/service/lifecycle/creation.service.test.js.map +1 -1
  479. package/dist/src/backend/services/workspace/service/lifecycle/data.service.d.ts +117 -387
  480. package/dist/src/backend/services/workspace/service/lifecycle/data.service.d.ts.map +1 -1
  481. package/dist/src/backend/services/workspace/service/lifecycle/data.service.js +7 -11
  482. package/dist/src/backend/services/workspace/service/lifecycle/data.service.js.map +1 -1
  483. package/dist/src/backend/services/workspace/service/lifecycle/data.service.test.js +13 -13
  484. package/dist/src/backend/services/workspace/service/lifecycle/data.service.test.js.map +1 -1
  485. package/dist/src/backend/services/workspace/service/lifecycle/state-machine.service.d.ts.map +1 -1
  486. package/dist/src/backend/services/workspace/service/lifecycle/state-machine.service.js +13 -30
  487. package/dist/src/backend/services/workspace/service/lifecycle/state-machine.service.js.map +1 -1
  488. package/dist/src/backend/services/workspace/service/lifecycle/state-machine.service.test.js +99 -29
  489. package/dist/src/backend/services/workspace/service/lifecycle/state-machine.service.test.js.map +1 -1
  490. package/dist/src/backend/services/workspace/service/lifecycle/workspace-auto-iteration.service.d.ts +3 -192
  491. package/dist/src/backend/services/workspace/service/lifecycle/workspace-auto-iteration.service.d.ts.map +1 -1
  492. package/dist/src/backend/services/workspace/service/lifecycle/workspace-auto-iteration.service.js +3 -3
  493. package/dist/src/backend/services/workspace/service/lifecycle/workspace-auto-iteration.service.js.map +1 -1
  494. package/dist/src/backend/services/workspace/service/lifecycle/workspace-pr-snapshot.service.d.ts +6 -66
  495. package/dist/src/backend/services/workspace/service/lifecycle/workspace-pr-snapshot.service.d.ts.map +1 -1
  496. package/dist/src/backend/services/workspace/service/lifecycle/workspace-pr-snapshot.service.js +10 -17
  497. package/dist/src/backend/services/workspace/service/lifecycle/workspace-pr-snapshot.service.js.map +1 -1
  498. package/dist/src/backend/services/workspace/service/lifecycle/workspace-pr-snapshot.service.test.js +16 -4
  499. package/dist/src/backend/services/workspace/service/lifecycle/workspace-pr-snapshot.service.test.js.map +1 -1
  500. package/dist/src/backend/services/workspace/service/lifecycle/workspace-ratchet.service.d.ts +6 -230
  501. package/dist/src/backend/services/workspace/service/lifecycle/workspace-ratchet.service.d.ts.map +1 -1
  502. package/dist/src/backend/services/workspace/service/lifecycle/workspace-ratchet.service.js +12 -22
  503. package/dist/src/backend/services/workspace/service/lifecycle/workspace-ratchet.service.js.map +1 -1
  504. package/dist/src/backend/services/workspace/service/lifecycle/workspace-relationships.service.d.ts +78 -75
  505. package/dist/src/backend/services/workspace/service/lifecycle/workspace-relationships.service.d.ts.map +1 -1
  506. package/dist/src/backend/services/workspace/service/lifecycle/workspace-run-script.service.d.ts +5 -132
  507. package/dist/src/backend/services/workspace/service/lifecycle/workspace-run-script.service.d.ts.map +1 -1
  508. package/dist/src/backend/services/workspace/service/lifecycle/workspace-run-script.service.js +3 -6
  509. package/dist/src/backend/services/workspace/service/lifecycle/workspace-run-script.service.js.map +1 -1
  510. package/dist/src/backend/services/workspace/service/lifecycle/workspace-state-capabilities.test.js +27 -4
  511. package/dist/src/backend/services/workspace/service/lifecycle/workspace-state-capabilities.test.js.map +1 -1
  512. package/dist/src/backend/services/workspace/service/query/project-management.service.d.ts +2 -70
  513. package/dist/src/backend/services/workspace/service/query/project-management.service.d.ts.map +1 -1
  514. package/dist/src/backend/services/workspace/service/query/workspace-maintenance.service.d.ts +110 -280
  515. package/dist/src/backend/services/workspace/service/query/workspace-maintenance.service.d.ts.map +1 -1
  516. package/dist/src/backend/services/workspace/service/query/workspace-maintenance.service.js +4 -3
  517. package/dist/src/backend/services/workspace/service/query/workspace-maintenance.service.js.map +1 -1
  518. package/dist/src/backend/services/workspace/service/query/workspace-maintenance.service.test.js +7 -4
  519. package/dist/src/backend/services/workspace/service/query/workspace-maintenance.service.test.js.map +1 -1
  520. package/dist/src/backend/services/workspace/service/query/workspace-notification.service.d.ts +4 -4
  521. package/dist/src/backend/services/workspace/service/query/workspace-query.service.d.ts +29 -216
  522. package/dist/src/backend/services/workspace/service/query/workspace-query.service.d.ts.map +1 -1
  523. package/dist/src/backend/services/workspace/service/query/workspace-query.service.js +91 -139
  524. package/dist/src/backend/services/workspace/service/query/workspace-query.service.js.map +1 -1
  525. package/dist/src/backend/services/workspace/service/query/workspace-query.service.test.js +113 -102
  526. package/dist/src/backend/services/workspace/service/query/workspace-query.service.test.js.map +1 -1
  527. package/dist/src/backend/services/workspace/service/snapshot/workspace-snapshot-store.service.d.ts +1 -0
  528. package/dist/src/backend/services/workspace/service/snapshot/workspace-snapshot-store.service.d.ts.map +1 -1
  529. package/dist/src/backend/services/workspace/service/snapshot/workspace-snapshot-store.service.js +1 -1
  530. package/dist/src/backend/services/workspace/service/snapshot/workspace-snapshot-store.service.js.map +1 -1
  531. package/dist/src/backend/services/workspace/service/state/kanban-state.d.ts +1 -29
  532. package/dist/src/backend/services/workspace/service/state/kanban-state.d.ts.map +1 -1
  533. package/dist/src/backend/services/workspace/service/state/kanban-state.js +0 -191
  534. package/dist/src/backend/services/workspace/service/state/kanban-state.js.map +1 -1
  535. package/dist/src/backend/services/workspace/service/state/kanban-state.test.js +2 -410
  536. package/dist/src/backend/services/workspace/service/state/kanban-state.test.js.map +1 -1
  537. package/dist/src/backend/services/workspace/service/workspace-domain-exports.test.js +1 -4
  538. package/dist/src/backend/services/workspace/service/workspace-domain-exports.test.js.map +1 -1
  539. package/dist/src/backend/services/workspace/service/worktree/worktree-init.test.js +1 -1
  540. package/dist/src/backend/services/workspace/service/worktree/worktree-init.test.js.map +1 -1
  541. package/dist/src/backend/services/workspace-depth-triggers.integration.test.d.ts +2 -0
  542. package/dist/src/backend/services/workspace-depth-triggers.integration.test.d.ts.map +1 -0
  543. package/dist/src/backend/services/workspace-depth-triggers.integration.test.js +68 -0
  544. package/dist/src/backend/services/workspace-depth-triggers.integration.test.js.map +1 -0
  545. package/dist/src/backend/testing/check-prisma-versions-script.test.d.ts +2 -0
  546. package/dist/src/backend/testing/check-prisma-versions-script.test.d.ts.map +1 -0
  547. package/dist/src/backend/testing/check-prisma-versions-script.test.js +52 -0
  548. package/dist/src/backend/testing/check-prisma-versions-script.test.js.map +1 -0
  549. package/dist/src/backend/trpc/admin.router.test.js +7 -7
  550. package/dist/src/backend/trpc/admin.router.test.js.map +1 -1
  551. package/dist/src/backend/trpc/admin.trpc.d.ts +2 -4
  552. package/dist/src/backend/trpc/admin.trpc.d.ts.map +1 -1
  553. package/dist/src/backend/trpc/admin.trpc.js +3 -3
  554. package/dist/src/backend/trpc/admin.trpc.js.map +1 -1
  555. package/dist/src/backend/trpc/closed-sessions.trpc.d.ts +1 -1
  556. package/dist/src/backend/trpc/index.d.ts +227 -804
  557. package/dist/src/backend/trpc/index.d.ts.map +1 -1
  558. package/dist/src/backend/trpc/periodic-task.trpc.d.ts +4 -4
  559. package/dist/src/backend/trpc/project.trpc.d.ts +2 -70
  560. package/dist/src/backend/trpc/project.trpc.d.ts.map +1 -1
  561. package/dist/src/backend/trpc/session.router.test.js +22 -16
  562. package/dist/src/backend/trpc/session.router.test.js.map +1 -1
  563. package/dist/src/backend/trpc/session.trpc.d.ts +11 -45
  564. package/dist/src/backend/trpc/session.trpc.d.ts.map +1 -1
  565. package/dist/src/backend/trpc/session.trpc.js +13 -13
  566. package/dist/src/backend/trpc/session.trpc.js.map +1 -1
  567. package/dist/src/backend/trpc/workspace/children.router.test.js +42 -2
  568. package/dist/src/backend/trpc/workspace/children.router.test.js.map +1 -1
  569. package/dist/src/backend/trpc/workspace/children.trpc.d.ts +3 -37
  570. package/dist/src/backend/trpc/workspace/children.trpc.d.ts.map +1 -1
  571. package/dist/src/backend/trpc/workspace/children.trpc.js +38 -14
  572. package/dist/src/backend/trpc/workspace/children.trpc.js.map +1 -1
  573. package/dist/src/backend/trpc/workspace/composition.test.js +8 -5
  574. package/dist/src/backend/trpc/workspace/composition.test.js.map +1 -1
  575. package/dist/src/backend/trpc/workspace/init.trpc.d.ts +52 -40
  576. package/dist/src/backend/trpc/workspace/init.trpc.d.ts.map +1 -1
  577. package/dist/src/backend/trpc/workspace/workspace-helpers.d.ts +80 -77
  578. package/dist/src/backend/trpc/workspace/workspace-helpers.d.ts.map +1 -1
  579. package/dist/src/backend/trpc/workspace.router.test.js +22 -25
  580. package/dist/src/backend/trpc/workspace.router.test.js.map +1 -1
  581. package/dist/src/backend/trpc/workspace.trpc.d.ts +553 -1477
  582. package/dist/src/backend/trpc/workspace.trpc.d.ts.map +1 -1
  583. package/dist/src/backend/trpc/workspace.trpc.js +13 -43
  584. package/dist/src/backend/trpc/workspace.trpc.js.map +1 -1
  585. package/dist/src/cli/runtime-utils.d.ts.map +1 -1
  586. package/dist/src/cli/runtime-utils.js +4 -0
  587. package/dist/src/cli/runtime-utils.js.map +1 -1
  588. package/dist/src/cli/runtime-utils.test.d.ts +2 -0
  589. package/dist/src/cli/runtime-utils.test.d.ts.map +1 -0
  590. package/dist/src/cli/runtime-utils.test.js +28 -0
  591. package/dist/src/cli/runtime-utils.test.js.map +1 -0
  592. package/dist/src/shared/acp-protocol/protocol/renderer-window.d.ts +1 -0
  593. package/dist/src/shared/acp-protocol/protocol/renderer-window.d.ts.map +1 -1
  594. package/dist/src/shared/acp-protocol/protocol/renderer-window.js +13 -2
  595. package/dist/src/shared/acp-protocol/protocol/renderer-window.js.map +1 -1
  596. package/dist/src/shared/core/index.d.ts +1 -0
  597. package/dist/src/shared/core/index.d.ts.map +1 -1
  598. package/dist/src/shared/core/index.js +1 -0
  599. package/dist/src/shared/core/index.js.map +1 -1
  600. package/dist/src/shared/core/ratchet-state.d.ts +10 -0
  601. package/dist/src/shared/core/ratchet-state.d.ts.map +1 -0
  602. package/dist/src/shared/core/ratchet-state.js +32 -0
  603. package/dist/src/shared/core/ratchet-state.js.map +1 -0
  604. package/dist/src/shared/schemas/export-data.schema.d.ts +2 -12
  605. package/dist/src/shared/schemas/export-data.schema.d.ts.map +1 -1
  606. package/dist/src/shared/schemas/export-data.schema.js +2 -4
  607. package/dist/src/shared/schemas/export-data.schema.js.map +1 -1
  608. package/dist/src/shared/workspace-snapshot.d.ts +1 -1
  609. package/dist/src/test-utils/application-graph.d.ts.map +1 -1
  610. package/dist/src/test-utils/application-graph.js +16 -9
  611. package/dist/src/test-utils/application-graph.js.map +1 -1
  612. package/dist/tsconfig.backend.tsbuildinfo +1 -1
  613. package/package.json +90 -150
  614. package/prisma/migrations/20260726112950_drop_cached_kanban_column/migration.sql +132 -0
  615. package/prisma/migrations/20260726135402_split_workspace_ratchet/migration.sql +149 -0
  616. package/prisma/migrations/20260726181500_split_workspace_pr/migration.sql +142 -0
  617. package/prisma/migrations/20260726200000_derive_ratchet_state/migration.sql +101 -0
  618. package/prisma/migrations/20260726220000_split_workspace_run_script/migration.sql +131 -0
  619. package/prisma/migrations/20260726230000_split_workspace_auto_iteration/migration.sql +123 -0
  620. package/prisma/schema.prisma +219 -62
  621. package/dist/client/assets/arc-lK3Ig9GV.js +0 -1
  622. package/dist/client/assets/architectureDiagram-3BPJPVTR-CeUbfBqe.js +0 -36
  623. package/dist/client/assets/blockDiagram-GPEHLZMM-DiVGPkq2.js +0 -132
  624. package/dist/client/assets/channel-CvY1mvIl.js +0 -1
  625. package/dist/client/assets/chunk-AQP2D5EJ-dyo9i4xa.js +0 -231
  626. package/dist/client/assets/classDiagram-4FO5ZUOK-Db7ZXJ6w.js +0 -1
  627. package/dist/client/assets/classDiagram-v2-Q7XG4LA2-Db7ZXJ6w.js +0 -1
  628. package/dist/client/assets/cytoscape.esm-DkOyvmE4.js +0 -321
  629. package/dist/client/assets/dagre-BM42HDAG-CDzpFdgD.js +0 -4
  630. package/dist/client/assets/diagram-2AECGRRQ-dl1_7lyq.js +0 -43
  631. package/dist/client/assets/diagram-5GNKFQAL-B0ynMwBY.js +0 -10
  632. package/dist/client/assets/diagram-LMA3HP47-DZxXcfiX.js +0 -24
  633. package/dist/client/assets/diagram-OG6HWLK6-BncGM9Gv.js +0 -24
  634. package/dist/client/assets/erDiagram-TEJ5UH35-B9hxScvO.js +0 -85
  635. package/dist/client/assets/flowDiagram-I6XJVG4X-DgZ2jwJQ.js +0 -162
  636. package/dist/client/assets/ganttDiagram-6RSMTGT7-BrnNMNRY.js +0 -292
  637. package/dist/client/assets/gitGraphDiagram-PVQCEYII-BJmed6oD.js +0 -106
  638. package/dist/client/assets/index-Btlruz7h.css +0 -1
  639. package/dist/client/assets/index-DEKuJM5_.js +0 -674
  640. package/dist/client/assets/infoDiagram-5YYISTIA-CtLzR4ip.js +0 -2
  641. package/dist/client/assets/katex-DHMw6HUq.js +0 -257
  642. package/dist/client/assets/layout-SsrduOYp.js +0 -1
  643. package/dist/client/assets/pieDiagram-4H26LBE5-DgPu3GTs.js +0 -30
  644. package/dist/client/assets/sankeyDiagram-5OEKKPKP-DmYoq588.js +0 -40
  645. package/dist/client/assets/sequenceDiagram-3UESZ5HK-EVqdDzgf.js +0 -162
  646. package/dist/client/assets/stateDiagram-AJRCARHV-BRd6IxSa.js +0 -1
  647. package/dist/client/assets/stateDiagram-v2-BHNVJYJU-DR2vMoX5.js +0 -1
  648. package/dist/client/assets/vennDiagram-CIIHVFJN-CLslQYVi.js +0 -34
  649. package/dist/client/assets/wardley-L42UT6IY-DyEDLg3x.js +0 -161
  650. package/dist/client/assets/xychartDiagram-2RQKCTM6-DwzoT5Dl.js +0 -7
  651. package/dist/src/backend/interceptors/branch-rename.interceptor.d.ts +0 -3
  652. package/dist/src/backend/interceptors/branch-rename.interceptor.d.ts.map +0 -1
  653. package/dist/src/backend/interceptors/branch-rename.interceptor.js +0 -117
  654. package/dist/src/backend/interceptors/branch-rename.interceptor.js.map +0 -1
  655. package/dist/src/backend/interceptors/branch-rename.interceptor.test.d.ts +0 -2
  656. package/dist/src/backend/interceptors/branch-rename.interceptor.test.d.ts.map +0 -1
  657. package/dist/src/backend/interceptors/branch-rename.interceptor.test.js +0 -184
  658. package/dist/src/backend/interceptors/branch-rename.interceptor.test.js.map +0 -1
  659. package/dist/src/backend/interceptors/pre-pr-rename.interceptor.d.ts +0 -6
  660. package/dist/src/backend/interceptors/pre-pr-rename.interceptor.d.ts.map +0 -1
  661. package/dist/src/backend/interceptors/pre-pr-rename.interceptor.js +0 -225
  662. package/dist/src/backend/interceptors/pre-pr-rename.interceptor.js.map +0 -1
  663. package/dist/src/backend/interceptors/pre-pr-rename.interceptor.test.d.ts +0 -2
  664. package/dist/src/backend/interceptors/pre-pr-rename.interceptor.test.d.ts.map +0 -1
  665. package/dist/src/backend/interceptors/pre-pr-rename.interceptor.test.js +0 -348
  666. package/dist/src/backend/interceptors/pre-pr-rename.interceptor.test.js.map +0 -1
  667. package/dist/src/backend/interceptors/pre-push-rename.interceptor.d.ts +0 -4
  668. package/dist/src/backend/interceptors/pre-push-rename.interceptor.d.ts.map +0 -1
  669. package/dist/src/backend/interceptors/pre-push-rename.interceptor.js +0 -136
  670. package/dist/src/backend/interceptors/pre-push-rename.interceptor.js.map +0 -1
  671. package/dist/src/backend/interceptors/pre-push-rename.interceptor.test.d.ts +0 -2
  672. package/dist/src/backend/interceptors/pre-push-rename.interceptor.test.d.ts.map +0 -1
  673. package/dist/src/backend/interceptors/pre-push-rename.interceptor.test.js +0 -260
  674. package/dist/src/backend/interceptors/pre-push-rename.interceptor.test.js.map +0 -1
  675. package/dist/src/backend/routers/websocket/dev-logs.handler.d.ts +0 -5
  676. package/dist/src/backend/routers/websocket/dev-logs.handler.d.ts.map +0 -1
  677. package/dist/src/backend/routers/websocket/dev-logs.handler.js +0 -28
  678. package/dist/src/backend/routers/websocket/dev-logs.handler.js.map +0 -1
  679. package/dist/src/backend/routers/websocket/dev-logs.handler.test.d.ts +0 -2
  680. package/dist/src/backend/routers/websocket/dev-logs.handler.test.d.ts.map +0 -1
  681. package/dist/src/backend/routers/websocket/dev-logs.handler.test.js.map +0 -1
  682. package/dist/src/backend/routers/websocket/post-run-logs.handler.d.ts +0 -5
  683. package/dist/src/backend/routers/websocket/post-run-logs.handler.d.ts.map +0 -1
  684. package/dist/src/backend/routers/websocket/post-run-logs.handler.js +0 -18
  685. package/dist/src/backend/routers/websocket/post-run-logs.handler.js.map +0 -1
  686. package/dist/src/backend/routers/websocket/post-run-logs.handler.test.d.ts +0 -2
  687. package/dist/src/backend/routers/websocket/post-run-logs.handler.test.d.ts.map +0 -1
  688. package/dist/src/backend/routers/websocket/post-run-logs.handler.test.js.map +0 -1
  689. package/dist/src/backend/services/github/service/pr-fetch-registry.d.ts +0 -20
  690. package/dist/src/backend/services/github/service/pr-fetch-registry.d.ts.map +0 -1
  691. package/dist/src/backend/services/github/service/pr-fetch-registry.js.map +0 -1
  692. package/dist/src/backend/services/github/service/pr-fetch-registry.test.d.ts +0 -2
  693. package/dist/src/backend/services/github/service/pr-fetch-registry.test.d.ts.map +0 -1
  694. package/dist/src/backend/services/github/service/pr-fetch-registry.test.js +0 -112
  695. package/dist/src/backend/services/github/service/pr-fetch-registry.test.js.map +0 -1
  696. package/dist/src/backend/services/ratchet/service/ratchet-state-machine.d.ts +0 -11
  697. package/dist/src/backend/services/ratchet/service/ratchet-state-machine.d.ts.map +0 -1
  698. package/dist/src/backend/services/ratchet/service/ratchet-state-machine.js +0 -77
  699. package/dist/src/backend/services/ratchet/service/ratchet-state-machine.js.map +0 -1
  700. package/dist/src/backend/services/ratchet/service/ratchet-state-machine.test.d.ts +0 -2
  701. package/dist/src/backend/services/ratchet/service/ratchet-state-machine.test.d.ts.map +0 -1
  702. package/dist/src/backend/services/ratchet/service/ratchet-state-machine.test.js +0 -66
  703. package/dist/src/backend/services/ratchet/service/ratchet-state-machine.test.js.map +0 -1
  704. package/dist/src/backend/services/session/service/lifecycle/session.service.coverage.test.d.ts +0 -2
  705. package/dist/src/backend/services/session/service/lifecycle/session.service.coverage.test.d.ts.map +0 -1
  706. package/dist/src/backend/services/session/service/lifecycle/session.service.coverage.test.js +0 -279
  707. package/dist/src/backend/services/session/service/lifecycle/session.service.coverage.test.js.map +0 -1
@@ -12,8 +12,7 @@ vi.mock('@/backend/services/workspace', () => ({
12
12
  clearActiveSession: vi.fn(),
13
13
  enable: vi.fn(),
14
14
  disable: vi.fn(),
15
- transitionStateIfEnabled: vi.fn(),
16
- settleIdleWhileDisabled: vi.fn(),
15
+ recordCheckIfEnabled: vi.fn(),
17
16
  recordDispatchIfEnabled: vi.fn(),
18
17
  adoptActiveSessionIfEnabled: vi.fn(),
19
18
  recordSessionEnd: vi.fn(),
@@ -66,29 +65,47 @@ const mockWorkspaceBridge = {
66
65
  findFixerContext: vi.fn(),
67
66
  recordSessionEnd: vi.fn(),
68
67
  };
68
+ const fakeCoordinator = { cooldownActive: false, inFlightSkips: 0 };
69
69
  const mockGitHubBridge = {
70
70
  extractPRInfo: vi.fn(),
71
71
  getPRFullDetails: vi.fn(),
72
72
  getReviewComments: vi.fn(),
73
73
  getResolvedReviewCommentIds: vi.fn(),
74
74
  computeCIStatus: vi.fn(),
75
+ computePRState: vi.fn(() => 'OPEN'),
75
76
  getAuthenticatedUsername: vi.fn(),
76
77
  fetchAndComputePRState: vi.fn(),
77
- isRecentlyFetched: vi.fn(),
78
- isFetchInFlight: vi.fn(),
79
- startFetch: vi.fn(() => 41),
80
- registerFetch: vi.fn(),
81
- cancelFetch: vi.fn(),
78
+ coordinatePrFetch: vi.fn(async (_workspaceId, fetch, options) => {
79
+ if (fakeCoordinator.inFlightSkips > 0) {
80
+ fakeCoordinator.inFlightSkips -= 1;
81
+ return { status: 'skipped', reason: 'recently_fetched' };
82
+ }
83
+ if (fakeCoordinator.cooldownActive && !options?.ignoreCooldown) {
84
+ return { status: 'skipped', reason: 'recently_fetched' };
85
+ }
86
+ return { status: 'fetched', value: await fetch() };
87
+ }),
82
88
  };
83
89
  const mockSnapshotBridge = {
84
- recordCIObservation: vi.fn(),
90
+ recordPrObservation: vi.fn(),
85
91
  recordCINotification: vi.fn(),
86
92
  recordReviewCheck: vi.fn(),
87
93
  };
94
+ function setRatchetShuttingDown(shuttingDown) {
95
+ const controller = new AbortController();
96
+ if (shuttingDown) {
97
+ controller.abort();
98
+ }
99
+ const internals = unsafeCoerce(ratchetService);
100
+ internals.runSignal = controller.signal;
101
+ internals.stopped = shuttingDown;
102
+ }
88
103
  describe('ratchet service (state-change + idle dispatch)', () => {
89
104
  beforeEach(() => {
90
105
  vi.clearAllMocks();
91
- unsafeCoerce(ratchetService).isShuttingDown = false;
106
+ fakeCoordinator.cooldownActive = false;
107
+ fakeCoordinator.inFlightSkips = 0;
108
+ setRatchetShuttingDown(false);
92
109
  unsafeCoerce(ratchetService).workspaceCheckTimeoutMs =
93
110
  SERVICE_TIMEOUT_MS.ratchetWorkspaceCheck;
94
111
  ratchetService.configure({
@@ -97,8 +114,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
97
114
  snapshot: mockSnapshotBridge,
98
115
  workspace: mockWorkspaceBridge,
99
116
  });
100
- vi.mocked(workspaceRatchetService.transitionStateIfEnabled).mockResolvedValue(true);
101
- vi.mocked(workspaceRatchetService.settleIdleWhileDisabled).mockResolvedValue(true);
117
+ vi.mocked(workspaceRatchetService.recordCheckIfEnabled).mockResolvedValue(true);
102
118
  vi.mocked(workspaceRatchetService.recordDispatchIfEnabled).mockResolvedValue(true);
103
119
  vi.mocked(workspaceRatchetService.adoptActiveSessionIfEnabled).mockResolvedValue(true);
104
120
  vi.mocked(workspaceRatchetService.recordSessionEnd).mockResolvedValue(true);
@@ -147,13 +163,16 @@ describe('ratchet service (state-change + idle dispatch)', () => {
147
163
  prUrl: 'https://github.com/example/repo/pull/1',
148
164
  prNumber: 1,
149
165
  prState: 'OPEN',
166
+ prReviewState: null,
167
+ prHasMergeConflict: false,
150
168
  prCiStatus: CIStatus.UNKNOWN,
151
169
  defaultSessionProvider: 'WORKSPACE_DEFAULT',
152
170
  ratchetSessionProvider: 'WORKSPACE_DEFAULT',
153
171
  ratchetEnabled: true,
154
172
  ratchetState: RatchetState.IDLE,
173
+ ratchetLastCheckedAt: null,
155
174
  ratchetActiveSessionId: null,
156
- ratchetLastCiRunId: null,
175
+ ratchetDispatchSnapshotKey: null,
157
176
  prReviewLastCheckedAt: null,
158
177
  ratchetDispatchOutcome: null,
159
178
  ratchetDispatchRetryCount: 0,
@@ -174,11 +193,13 @@ describe('ratchet service (state-change + idle dispatch)', () => {
174
193
  prUrl: 'https://github.com/example/repo/pull/2',
175
194
  prNumber: 2,
176
195
  prState: 'OPEN',
196
+ prReviewState: null,
197
+ prHasMergeConflict: false,
177
198
  prCiStatus: CIStatus.UNKNOWN,
178
199
  ratchetEnabled: false,
179
200
  ratchetState: RatchetState.IDLE,
180
201
  ratchetActiveSessionId: null,
181
- ratchetLastCiRunId: null,
202
+ ratchetDispatchSnapshotKey: null,
182
203
  prReviewLastCheckedAt: null,
183
204
  ratchetDispatchOutcome: null,
184
205
  ratchetDispatchRetryCount: 0,
@@ -192,70 +213,37 @@ describe('ratchet service (state-change + idle dispatch)', () => {
192
213
  action: { type: 'DISABLED', reason: 'Workspace ratcheting disabled' },
193
214
  newState: RatchetState.IDLE,
194
215
  });
195
- expect(workspaceRatchetService.settleIdleWhileDisabled).toHaveBeenCalledWith('ws-disabled', RatchetState.IDLE);
216
+ expect(workspaceRatchetService.recordCheckIfEnabled).not.toHaveBeenCalled();
196
217
  });
197
- it('settles a disabled workspace to IDLE via CAS and emits an accurate fromState', async () => {
218
+ it('reports a disabled workspace as IDLE without writing anything', async () => {
198
219
  const workspace = {
199
220
  id: 'ws-disabled-settle',
200
221
  prUrl: 'https://github.com/example/repo/pull/2',
201
222
  prNumber: 2,
202
223
  prState: 'OPEN',
224
+ prReviewState: null,
225
+ prHasMergeConflict: false,
203
226
  prCiStatus: CIStatus.UNKNOWN,
204
227
  ratchetEnabled: false,
205
- ratchetState: RatchetState.CI_FAILED,
228
+ ratchetState: RatchetState.IDLE,
206
229
  ratchetActiveSessionId: null,
207
- ratchetLastCiRunId: null,
230
+ ratchetDispatchSnapshotKey: null,
208
231
  prReviewLastCheckedAt: null,
209
232
  ratchetDispatchOutcome: null,
210
233
  ratchetDispatchRetryCount: 0,
211
234
  };
212
- vi.mocked(workspaceRatchetService.settleIdleWhileDisabled).mockResolvedValue(true);
213
235
  const events = [];
214
236
  ratchetService.on(RATCHET_STATE_CHANGED, (event) => {
215
237
  events.push(event);
216
238
  });
217
239
  const result = await unsafeCoerce(ratchetService).processWorkspace(workspace);
218
- expect(workspaceRatchetService.settleIdleWhileDisabled).toHaveBeenCalledWith('ws-disabled-settle', RatchetState.CI_FAILED);
219
240
  expect(result).toMatchObject({
220
- previousState: RatchetState.CI_FAILED,
241
+ previousState: RatchetState.IDLE,
221
242
  newState: RatchetState.IDLE,
222
243
  action: { type: 'DISABLED' },
223
244
  });
224
- expect(events).toEqual([
225
- {
226
- workspaceId: 'ws-disabled-settle',
227
- fromState: RatchetState.CI_FAILED,
228
- toState: RatchetState.IDLE,
229
- },
230
- ]);
231
- });
232
- it('does not emit for a disabled workspace when the settle CAS loses', async () => {
233
- const workspace = {
234
- id: 'ws-disabled-settle-race',
235
- prUrl: 'https://github.com/example/repo/pull/2',
236
- prNumber: 2,
237
- prState: 'OPEN',
238
- prCiStatus: CIStatus.UNKNOWN,
239
- ratchetEnabled: false,
240
- ratchetState: RatchetState.CI_FAILED,
241
- ratchetActiveSessionId: null,
242
- ratchetLastCiRunId: null,
243
- prReviewLastCheckedAt: null,
244
- ratchetDispatchOutcome: null,
245
- ratchetDispatchRetryCount: 0,
246
- };
247
- vi.mocked(workspaceRatchetService.settleIdleWhileDisabled).mockResolvedValue(false);
248
- const events = [];
249
- ratchetService.on(RATCHET_STATE_CHANGED, (event) => {
250
- events.push(event);
251
- });
252
- const result = await unsafeCoerce(ratchetService).processWorkspace(workspace);
253
- expect(result).toMatchObject({
254
- previousState: RatchetState.CI_FAILED,
255
- newState: RatchetState.CI_FAILED,
256
- action: { type: 'DISABLED' },
257
- });
258
245
  expect(events).toEqual([]);
246
+ expect(workspaceRatchetService.recordCheckIfEnabled).not.toHaveBeenCalled();
259
247
  });
260
248
  it('does not dispatch when workspace is not idle', async () => {
261
249
  const workspace = {
@@ -263,11 +251,13 @@ describe('ratchet service (state-change + idle dispatch)', () => {
263
251
  prUrl: 'https://github.com/example/repo/pull/3',
264
252
  prNumber: 3,
265
253
  prState: 'OPEN',
254
+ prReviewState: null,
255
+ prHasMergeConflict: false,
266
256
  prCiStatus: CIStatus.UNKNOWN,
267
257
  ratchetEnabled: true,
268
258
  ratchetState: RatchetState.IDLE,
269
259
  ratchetActiveSessionId: null,
270
- ratchetLastCiRunId: null,
260
+ ratchetDispatchSnapshotKey: null,
271
261
  prReviewLastCheckedAt: new Date('2026-01-01T00:00:00Z'),
272
262
  ratchetDispatchOutcome: null,
273
263
  ratchetDispatchRetryCount: 0,
@@ -313,11 +303,13 @@ describe('ratchet service (state-change + idle dispatch)', () => {
313
303
  prUrl: 'https://github.com/example/repo/pull/4',
314
304
  prNumber: 4,
315
305
  prState: 'OPEN',
306
+ prReviewState: null,
307
+ prHasMergeConflict: false,
316
308
  prCiStatus: CIStatus.UNKNOWN,
317
309
  ratchetEnabled: true,
318
310
  ratchetState: RatchetState.IDLE,
319
311
  ratchetActiveSessionId: null,
320
- ratchetLastCiRunId: '2026-01-01T00:00:00Z',
312
+ ratchetDispatchSnapshotKey: '2026-01-01T00:00:00Z',
321
313
  prReviewLastCheckedAt: new Date('2026-01-01T00:00:00Z'),
322
314
  ratchetDispatchOutcome: null,
323
315
  ratchetDispatchRetryCount: 0,
@@ -346,11 +338,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
346
338
  snapshotKey: '2026-01-02T00:00:00Z',
347
339
  retryCount: 0,
348
340
  });
349
- const finalUpdatePayload = vi
350
- .mocked(workspaceRatchetService.transitionStateIfEnabled)
351
- .mock.calls.at(-1)?.[2];
352
- expect(finalUpdatePayload).not.toHaveProperty('ratchetLastCiRunId');
353
- expect(finalUpdatePayload).not.toHaveProperty('prReviewLastCheckedAt');
341
+ expect(workspaceRatchetService.recordCheckIfEnabled).toHaveBeenLastCalledWith('ws-change', expect.any(Date));
354
342
  expect(mockSnapshotBridge.recordReviewCheck).toHaveBeenCalledWith('ws-change', expect.any(Date));
355
343
  });
356
344
  it('stops fixer and returns disabled when active-session recording loses disable race', async () => {
@@ -359,11 +347,13 @@ describe('ratchet service (state-change + idle dispatch)', () => {
359
347
  prUrl: 'https://github.com/example/repo/pull/40',
360
348
  prNumber: 40,
361
349
  prState: 'OPEN',
350
+ prReviewState: null,
351
+ prHasMergeConflict: false,
362
352
  prCiStatus: CIStatus.UNKNOWN,
363
353
  ratchetEnabled: true,
364
354
  ratchetState: RatchetState.IDLE,
365
355
  ratchetActiveSessionId: null,
366
- ratchetLastCiRunId: 'old-snapshot',
356
+ ratchetDispatchSnapshotKey: 'old-snapshot',
367
357
  prReviewLastCheckedAt: new Date('2026-01-01T00:00:00Z'),
368
358
  ratchetDispatchOutcome: null,
369
359
  ratchetDispatchRetryCount: 0,
@@ -384,7 +374,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
384
374
  promptSent: true,
385
375
  });
386
376
  vi.mocked(workspaceRatchetService.recordDispatchIfEnabled).mockResolvedValue(false);
387
- vi.mocked(workspaceRatchetService.transitionStateIfEnabled).mockResolvedValue(false);
377
+ vi.mocked(workspaceRatchetService.recordCheckIfEnabled).mockResolvedValue(false);
388
378
  vi.mocked(workspaceDataService.findById).mockResolvedValue({
389
379
  id: 'ws-disable-race-dispatch',
390
380
  ratchetEnabled: false,
@@ -410,11 +400,13 @@ describe('ratchet service (state-change + idle dispatch)', () => {
410
400
  prUrl: 'https://github.com/example/repo/pull/44',
411
401
  prNumber: 44,
412
402
  prState: 'OPEN',
403
+ prReviewState: null,
404
+ prHasMergeConflict: false,
413
405
  prCiStatus: CIStatus.UNKNOWN,
414
406
  ratchetEnabled: true,
415
407
  ratchetState: RatchetState.IDLE,
416
408
  ratchetActiveSessionId: null,
417
- ratchetLastCiRunId: '2026-01-01T00:00:00Z',
409
+ ratchetDispatchSnapshotKey: '2026-01-01T00:00:00Z',
418
410
  prReviewLastCheckedAt: new Date('2026-01-01T00:00:00Z'),
419
411
  ratchetDispatchOutcome: null,
420
412
  ratchetDispatchRetryCount: 0,
@@ -455,11 +447,13 @@ describe('ratchet service (state-change + idle dispatch)', () => {
455
447
  prUrl: 'https://github.com/example/repo/pull/5',
456
448
  prNumber: 5,
457
449
  prState: 'OPEN',
450
+ prReviewState: null,
451
+ prHasMergeConflict: false,
458
452
  prCiStatus: CIStatus.UNKNOWN,
459
453
  ratchetEnabled: true,
460
454
  ratchetState: RatchetState.READY,
461
455
  ratchetActiveSessionId: null,
462
- ratchetLastCiRunId: '2026-01-02T00:00:00Z',
456
+ ratchetDispatchSnapshotKey: '2026-01-02T00:00:00Z',
463
457
  prReviewLastCheckedAt: new Date('2026-01-02T00:00:00Z'),
464
458
  ratchetDispatchOutcome: null,
465
459
  ratchetDispatchRetryCount: 0,
@@ -490,11 +484,13 @@ describe('ratchet service (state-change + idle dispatch)', () => {
490
484
  prUrl: 'https://github.com/example/repo/pull/55',
491
485
  prNumber: 55,
492
486
  prState: 'OPEN',
487
+ prReviewState: null,
488
+ prHasMergeConflict: false,
493
489
  prCiStatus: CIStatus.UNKNOWN,
494
490
  ratchetEnabled: true,
495
491
  ratchetState: RatchetState.REVIEW_PENDING,
496
492
  ratchetActiveSessionId: null,
497
- ratchetLastCiRunId: 'ci:SUCCESS|changes-requested:1735776000000',
493
+ ratchetDispatchSnapshotKey: 'ci:SUCCESS|changes-requested:1735776000000',
498
494
  prReviewLastCheckedAt: new Date('2026-01-02T00:00:00Z'),
499
495
  ratchetDispatchOutcome: null,
500
496
  ratchetDispatchRetryCount: 0,
@@ -535,11 +531,13 @@ describe('ratchet service (state-change + idle dispatch)', () => {
535
531
  prUrl: 'https://github.com/example/repo/pull/56',
536
532
  prNumber: 56,
537
533
  prState: 'OPEN',
534
+ prReviewState: null,
535
+ prHasMergeConflict: false,
538
536
  prCiStatus: CIStatus.UNKNOWN,
539
537
  ratchetEnabled: true,
540
538
  ratchetState: RatchetState.REVIEW_PENDING,
541
539
  ratchetActiveSessionId: null,
542
- ratchetLastCiRunId: 'ci:SUCCESS|changes-requested:old',
540
+ ratchetDispatchSnapshotKey: 'ci:SUCCESS|changes-requested:old',
543
541
  prReviewLastCheckedAt: new Date('2026-01-02T00:00:00Z'),
544
542
  ratchetDispatchOutcome: null,
545
543
  ratchetDispatchRetryCount: 0,
@@ -573,11 +571,13 @@ describe('ratchet service (state-change + idle dispatch)', () => {
573
571
  prUrl: 'https://github.com/example/repo/pull/57',
574
572
  prNumber: 57,
575
573
  prState: 'OPEN',
574
+ prReviewState: null,
575
+ prHasMergeConflict: false,
576
576
  prCiStatus: CIStatus.UNKNOWN,
577
577
  ratchetEnabled: true,
578
578
  ratchetState: RatchetState.READY,
579
579
  ratchetActiveSessionId: null,
580
- ratchetLastCiRunId: 'ci:SUCCESS|no-changes-requested:old|merge:clean',
580
+ ratchetDispatchSnapshotKey: 'ci:SUCCESS|no-changes-requested:old|merge:clean',
581
581
  prReviewLastCheckedAt: new Date('2026-01-02T00:00:00Z'),
582
582
  ratchetDispatchOutcome: null,
583
583
  ratchetDispatchRetryCount: 0,
@@ -639,11 +639,13 @@ describe('ratchet service (state-change + idle dispatch)', () => {
639
639
  prUrl: 'https://github.com/example/repo/pull/7',
640
640
  prNumber: 7,
641
641
  prState: 'OPEN',
642
+ prReviewState: null,
643
+ prHasMergeConflict: false,
642
644
  prCiStatus: CIStatus.UNKNOWN,
643
645
  ratchetEnabled: true,
644
646
  ratchetState: RatchetState.IDLE,
645
647
  ratchetActiveSessionId: null,
646
- ratchetLastCiRunId: null,
648
+ ratchetDispatchSnapshotKey: null,
647
649
  prReviewLastCheckedAt: null,
648
650
  ratchetDispatchOutcome: null,
649
651
  ratchetDispatchRetryCount: 0,
@@ -678,7 +680,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
678
680
  expect(result).toMatchObject({
679
681
  action: { type: 'ERROR', error: 'Failed to deliver initial ratchet prompt' },
680
682
  });
681
- expect(workspaceRatchetService.clearActiveSession).toHaveBeenCalledWith(workspace.id);
683
+ expect(workspaceRatchetService.clearActiveSession).toHaveBeenCalledWith(workspace.id, 'ratchet-session');
682
684
  expect(mockSessionBridge.stopSession).toHaveBeenCalledWith('ratchet-session');
683
685
  });
684
686
  it('routes an aborted prompt-failure path through orphan cleanup', async () => {
@@ -735,11 +737,13 @@ describe('ratchet service (state-change + idle dispatch)', () => {
735
737
  prUrl: 'https://github.com/example/repo/pull/8',
736
738
  prNumber: 8,
737
739
  prState: 'OPEN',
740
+ prReviewState: null,
741
+ prHasMergeConflict: false,
738
742
  prCiStatus: CIStatus.UNKNOWN,
739
743
  ratchetEnabled: true,
740
744
  ratchetState: RatchetState.READY,
741
745
  ratchetActiveSessionId: null,
742
- ratchetLastCiRunId: '2026-01-01T00:00:00Z',
746
+ ratchetDispatchSnapshotKey: '2026-01-01T00:00:00Z',
743
747
  prReviewLastCheckedAt: recentCheck,
744
748
  ratchetDispatchOutcome: null,
745
749
  ratchetDispatchRetryCount: 0,
@@ -771,11 +775,13 @@ describe('ratchet service (state-change + idle dispatch)', () => {
771
775
  prUrl: 'https://github.com/example/repo/pull/43',
772
776
  prNumber: 43,
773
777
  prState: 'OPEN',
778
+ prReviewState: null,
779
+ prHasMergeConflict: false,
774
780
  prCiStatus: CIStatus.FAILURE,
775
781
  ratchetEnabled: true,
776
782
  ratchetState: RatchetState.CI_FAILED,
777
783
  ratchetActiveSessionId: null,
778
- ratchetLastCiRunId: 'failed-snapshot',
784
+ ratchetDispatchSnapshotKey: 'failed-snapshot',
779
785
  prReviewLastCheckedAt: recentCheck,
780
786
  ratchetDispatchOutcome: 'COMPLETED',
781
787
  ratchetDispatchRetryCount: 0,
@@ -821,11 +827,13 @@ describe('ratchet service (state-change + idle dispatch)', () => {
821
827
  prUrl: 'https://github.com/example/repo/pull/41',
822
828
  prNumber: 41,
823
829
  prState: 'OPEN',
830
+ prReviewState: null,
831
+ prHasMergeConflict: false,
824
832
  prCiStatus: CIStatus.UNKNOWN,
825
833
  ratchetEnabled: true,
826
834
  ratchetState: RatchetState.READY,
827
835
  ratchetActiveSessionId: null,
828
- ratchetLastCiRunId: 'old-snapshot',
836
+ ratchetDispatchSnapshotKey: 'old-snapshot',
829
837
  prReviewLastCheckedAt: recentCheck,
830
838
  ratchetDispatchOutcome: null,
831
839
  ratchetDispatchRetryCount: 0,
@@ -839,7 +847,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
839
847
  prState: 'OPEN',
840
848
  prNumber: 41,
841
849
  });
842
- vi.mocked(workspaceRatchetService.transitionStateIfEnabled).mockResolvedValue(false);
850
+ vi.mocked(workspaceRatchetService.recordCheckIfEnabled).mockResolvedValue(false);
843
851
  vi.mocked(workspaceDataService.findById).mockResolvedValue({
844
852
  id: 'ws-disable-race-state',
845
853
  ratchetEnabled: false,
@@ -857,55 +865,117 @@ describe('ratchet service (state-change + idle dispatch)', () => {
857
865
  expect(events).toHaveLength(0);
858
866
  ratchetService.removeAllListeners();
859
867
  });
860
- it('reports a concurrent state change without emitting when the check loses the CAS while still enabled', async () => {
861
- const recentCheck = new Date();
868
+ it('persists PR state and review decision the check observed, not just CI', async () => {
862
869
  const workspace = {
863
- id: 'ws-superseded',
864
- prUrl: 'https://github.com/example/repo/pull/42',
865
- prNumber: 42,
870
+ id: 'ws-observation',
871
+ prUrl: 'https://github.com/example/repo/pull/44',
872
+ prNumber: 44,
866
873
  prState: 'OPEN',
867
- prCiStatus: CIStatus.UNKNOWN,
874
+ prReviewState: null,
875
+ prHasMergeConflict: false,
876
+ prCiStatus: CIStatus.SUCCESS,
868
877
  ratchetEnabled: true,
869
- ratchetState: RatchetState.CI_RUNNING,
878
+ ratchetState: RatchetState.READY,
870
879
  ratchetActiveSessionId: null,
871
- ratchetLastCiRunId: 'old-snapshot',
872
- prReviewLastCheckedAt: recentCheck,
880
+ ratchetDispatchSnapshotKey: 'observation-snapshot',
881
+ prReviewLastCheckedAt: null,
873
882
  ratchetDispatchOutcome: null,
874
883
  ratchetDispatchRetryCount: 0,
875
884
  };
876
885
  vi.spyOn(unsafeCoerce(ratchetService), 'fetchPRState').mockResolvedValue({
877
886
  ciStatus: CIStatus.SUCCESS,
878
- snapshotKey: 'new-snapshot',
879
- hasChangesRequested: false,
880
- latestReviewActivityAtMs: recentCheck.getTime() - 1000,
887
+ snapshotKey: 'observation-snapshot',
888
+ hasChangesRequested: true,
889
+ hasMergeConflict: false,
890
+ latestReviewActivityAtMs: null,
881
891
  statusCheckRollup: null,
882
892
  prState: 'OPEN',
883
- prNumber: 42,
893
+ cachedPrState: 'CHANGES_REQUESTED',
894
+ reviewDecision: 'CHANGES_REQUESTED',
895
+ prNumber: 44,
896
+ reviewComments: [],
884
897
  });
885
- vi.mocked(workspaceRatchetService.transitionStateIfEnabled).mockResolvedValue(false);
886
- vi.mocked(workspaceDataService.findById).mockResolvedValue({
887
- id: 'ws-superseded',
898
+ vi.mocked(mockSessionBridge.findSessionsByWorkspaceId).mockResolvedValue([]);
899
+ await unsafeCoerce(ratchetService).processWorkspace(workspace);
900
+ expect(mockSnapshotBridge.recordPrObservation).toHaveBeenCalledWith(expect.objectContaining({
901
+ workspaceId: 'ws-observation',
902
+ prState: 'CHANGES_REQUESTED',
903
+ reviewState: 'CHANGES_REQUESTED',
904
+ ciStatus: CIStatus.SUCCESS,
905
+ hasMergeConflict: false,
906
+ }));
907
+ });
908
+ it('persists a merge observed by the check even when CI status is unchanged', async () => {
909
+ const workspace = {
910
+ id: 'ws-merged',
911
+ prUrl: 'https://github.com/example/repo/pull/45',
912
+ prNumber: 45,
913
+ prState: 'OPEN',
914
+ prReviewState: null,
915
+ prHasMergeConflict: false,
916
+ prCiStatus: CIStatus.SUCCESS,
888
917
  ratchetEnabled: true,
889
- ratchetState: RatchetState.IDLE,
918
+ ratchetState: RatchetState.READY,
919
+ ratchetActiveSessionId: null,
920
+ ratchetDispatchSnapshotKey: 'merged-snapshot',
921
+ prReviewLastCheckedAt: null,
922
+ ratchetDispatchOutcome: null,
923
+ ratchetDispatchRetryCount: 0,
924
+ };
925
+ vi.spyOn(unsafeCoerce(ratchetService), 'fetchPRState').mockResolvedValue({
926
+ ciStatus: CIStatus.SUCCESS,
927
+ snapshotKey: 'merged-snapshot',
928
+ hasChangesRequested: false,
929
+ hasMergeConflict: false,
930
+ latestReviewActivityAtMs: null,
931
+ statusCheckRollup: null,
932
+ prState: 'MERGED',
933
+ cachedPrState: 'MERGED',
934
+ reviewDecision: null,
935
+ prNumber: 45,
936
+ reviewComments: [],
890
937
  });
891
938
  vi.mocked(mockSessionBridge.findSessionsByWorkspaceId).mockResolvedValue([]);
892
- const events = [];
893
- ratchetService.on(RATCHET_STATE_CHANGED, (event) => {
894
- events.push(event);
895
- });
896
- const result = await unsafeCoerce(ratchetService).processWorkspace(workspace);
897
- expect(workspaceRatchetService.transitionStateIfEnabled).toHaveBeenCalledWith('ws-superseded', RatchetState.CI_RUNNING, expect.objectContaining({ ratchetState: RatchetState.READY }));
898
- expect(result).toMatchObject({
899
- previousState: RatchetState.CI_RUNNING,
900
- newState: RatchetState.CI_RUNNING,
901
- action: {
902
- type: 'WAITING',
903
- reason: 'Ratchet state changed concurrently during this check; re-evaluating next cycle',
904
- },
939
+ await unsafeCoerce(ratchetService).processWorkspace(workspace);
940
+ expect(mockSnapshotBridge.recordPrObservation).toHaveBeenCalledWith(expect.objectContaining({ workspaceId: 'ws-merged', prState: 'MERGED' }));
941
+ });
942
+ it('persists a newly observed merge conflict even when CI status is unchanged', async () => {
943
+ const workspace = {
944
+ id: 'ws-conflict',
945
+ prUrl: 'https://github.com/example/repo/pull/43',
946
+ prNumber: 43,
947
+ prState: 'OPEN',
948
+ prReviewState: null,
949
+ prHasMergeConflict: false,
950
+ prCiStatus: CIStatus.SUCCESS,
951
+ ratchetEnabled: true,
952
+ ratchetState: RatchetState.READY,
953
+ ratchetActiveSessionId: null,
954
+ ratchetDispatchSnapshotKey: 'conflict-snapshot',
955
+ prReviewLastCheckedAt: null,
956
+ ratchetDispatchOutcome: null,
957
+ ratchetDispatchRetryCount: 0,
958
+ };
959
+ vi.spyOn(unsafeCoerce(ratchetService), 'fetchPRState').mockResolvedValue({
960
+ ciStatus: CIStatus.SUCCESS,
961
+ snapshotKey: 'conflict-snapshot',
962
+ hasChangesRequested: false,
963
+ hasMergeConflict: true,
964
+ latestReviewActivityAtMs: null,
965
+ statusCheckRollup: null,
966
+ prState: 'OPEN',
967
+ cachedPrState: 'OPEN',
968
+ reviewDecision: null,
969
+ prNumber: 43,
970
+ reviewComments: [],
905
971
  });
906
- expect(events).toHaveLength(0);
907
- expect(mockSnapshotBridge.recordCIObservation).not.toHaveBeenCalled();
908
- expect(mockSnapshotBridge.recordReviewCheck).not.toHaveBeenCalled();
972
+ vi.mocked(mockSessionBridge.findSessionsByWorkspaceId).mockResolvedValue([]);
973
+ await unsafeCoerce(ratchetService).processWorkspace(workspace);
974
+ expect(mockSnapshotBridge.recordPrObservation).toHaveBeenCalledWith(expect.objectContaining({
975
+ workspaceId: 'ws-conflict',
976
+ ciStatus: CIStatus.SUCCESS,
977
+ hasMergeConflict: true,
978
+ }));
909
979
  });
910
980
  it('redispatches with an incremented retry count when the previous fixer died', async () => {
911
981
  const workspace = {
@@ -913,11 +983,13 @@ describe('ratchet service (state-change + idle dispatch)', () => {
913
983
  prUrl: 'https://github.com/example/repo/pull/13',
914
984
  prNumber: 13,
915
985
  prState: 'OPEN',
986
+ prReviewState: null,
987
+ prHasMergeConflict: false,
916
988
  prCiStatus: CIStatus.FAILURE,
917
989
  ratchetEnabled: true,
918
990
  ratchetState: RatchetState.CI_FAILED,
919
991
  ratchetActiveSessionId: null,
920
- ratchetLastCiRunId: 'same-snapshot',
992
+ ratchetDispatchSnapshotKey: 'same-snapshot',
921
993
  prReviewLastCheckedAt: new Date('2026-01-01T00:00:00Z'),
922
994
  ratchetDispatchOutcome: 'DIED',
923
995
  ratchetDispatchRetryCount: 1,
@@ -954,11 +1026,13 @@ describe('ratchet service (state-change + idle dispatch)', () => {
954
1026
  prUrl: 'https://github.com/example/repo/pull/14',
955
1027
  prNumber: 14,
956
1028
  prState: 'OPEN',
1029
+ prReviewState: null,
1030
+ prHasMergeConflict: false,
957
1031
  prCiStatus: CIStatus.SUCCESS,
958
1032
  ratchetEnabled: true,
959
1033
  ratchetState: RatchetState.READY,
960
1034
  ratchetActiveSessionId: null,
961
- ratchetLastCiRunId: 'clean-snapshot',
1035
+ ratchetDispatchSnapshotKey: 'clean-snapshot',
962
1036
  prReviewLastCheckedAt: checkedAt,
963
1037
  ratchetDispatchOutcome: 'DIED',
964
1038
  ratchetDispatchRetryCount: 0,
@@ -1000,11 +1074,13 @@ describe('ratchet service (state-change + idle dispatch)', () => {
1000
1074
  prUrl: 'https://github.com/example/repo/pull/15',
1001
1075
  prNumber: 15,
1002
1076
  prState: 'OPEN',
1077
+ prReviewState: null,
1078
+ prHasMergeConflict: false,
1003
1079
  prCiStatus: CIStatus.FAILURE,
1004
1080
  ratchetEnabled: true,
1005
1081
  ratchetState: RatchetState.CI_FAILED,
1006
1082
  ratchetActiveSessionId: null,
1007
- ratchetLastCiRunId: 'same-snapshot',
1083
+ ratchetDispatchSnapshotKey: 'same-snapshot',
1008
1084
  prReviewLastCheckedAt: new Date('2026-01-01T00:00:00Z'),
1009
1085
  ratchetDispatchOutcome: 'DIED',
1010
1086
  ratchetDispatchRetryCount: 3,
@@ -1033,11 +1109,13 @@ describe('ratchet service (state-change + idle dispatch)', () => {
1033
1109
  prUrl: 'https://github.com/example/repo/pull/16',
1034
1110
  prNumber: 16,
1035
1111
  prState: 'OPEN',
1112
+ prReviewState: null,
1113
+ prHasMergeConflict: false,
1036
1114
  prCiStatus: CIStatus.FAILURE,
1037
1115
  ratchetEnabled: true,
1038
1116
  ratchetState: RatchetState.CI_FAILED,
1039
1117
  ratchetActiveSessionId: null,
1040
- ratchetLastCiRunId: 'old-snapshot',
1118
+ ratchetDispatchSnapshotKey: 'old-snapshot',
1041
1119
  prReviewLastCheckedAt: new Date('2026-01-01T00:00:00Z'),
1042
1120
  ratchetDispatchOutcome: 'DIED',
1043
1121
  ratchetDispatchRetryCount: 3,
@@ -1069,11 +1147,13 @@ describe('ratchet service (state-change + idle dispatch)', () => {
1069
1147
  prUrl: 'https://github.com/example/repo/pull/17',
1070
1148
  prNumber: 17,
1071
1149
  prState: 'OPEN',
1150
+ prReviewState: null,
1151
+ prHasMergeConflict: false,
1072
1152
  prCiStatus: CIStatus.FAILURE,
1073
1153
  ratchetEnabled: true,
1074
1154
  ratchetState: RatchetState.CI_FAILED,
1075
1155
  ratchetActiveSessionId: null,
1076
- ratchetLastCiRunId: 'same-snapshot',
1156
+ ratchetDispatchSnapshotKey: 'same-snapshot',
1077
1157
  prReviewLastCheckedAt: new Date('2026-01-01T00:00:00Z'),
1078
1158
  ratchetDispatchOutcome: 'COMPLETED',
1079
1159
  ratchetDispatchRetryCount: 2,
@@ -1106,11 +1186,13 @@ describe('ratchet service (state-change + idle dispatch)', () => {
1106
1186
  prUrl: 'https://github.com/example/repo/pull/456',
1107
1187
  prNumber: 456,
1108
1188
  prState: 'OPEN',
1189
+ prReviewState: null,
1190
+ prHasMergeConflict: false,
1109
1191
  prCiStatus: CIStatus.SUCCESS,
1110
1192
  ratchetEnabled: true,
1111
1193
  ratchetState: RatchetState.MERGE_CONFLICT,
1112
1194
  ratchetActiveSessionId: null,
1113
- ratchetLastCiRunId: previousSnapshotKey,
1195
+ ratchetDispatchSnapshotKey: previousSnapshotKey,
1114
1196
  prReviewLastCheckedAt: new Date('2026-01-01T00:00:00Z'),
1115
1197
  ratchetDispatchOutcome: 'COMPLETED',
1116
1198
  ratchetDispatchRetryCount: 2,
@@ -1147,11 +1229,13 @@ describe('ratchet service (state-change + idle dispatch)', () => {
1147
1229
  prUrl: 'https://github.com/example/repo/pull/9',
1148
1230
  prNumber: 9,
1149
1231
  prState: 'OPEN',
1232
+ prReviewState: null,
1233
+ prHasMergeConflict: false,
1150
1234
  prCiStatus: CIStatus.UNKNOWN,
1151
1235
  ratchetEnabled: true,
1152
1236
  ratchetState: RatchetState.CI_FAILED,
1153
1237
  ratchetActiveSessionId: 'ratchet-session',
1154
- ratchetLastCiRunId: 'previous-snapshot-key',
1238
+ ratchetDispatchSnapshotKey: 'previous-snapshot-key',
1155
1239
  prReviewLastCheckedAt: new Date('2026-01-01T00:00:00Z'),
1156
1240
  ratchetDispatchOutcome: 'RUNNING',
1157
1241
  ratchetDispatchRetryCount: 0,
@@ -1172,11 +1256,13 @@ describe('ratchet service (state-change + idle dispatch)', () => {
1172
1256
  prUrl: 'https://github.com/example/repo/pull/12',
1173
1257
  prNumber: 12,
1174
1258
  prState: 'OPEN',
1259
+ prReviewState: null,
1260
+ prHasMergeConflict: false,
1175
1261
  prCiStatus: CIStatus.UNKNOWN,
1176
1262
  ratchetEnabled: true,
1177
1263
  ratchetState: RatchetState.CI_FAILED,
1178
1264
  ratchetActiveSessionId: 'deleted-session',
1179
- ratchetLastCiRunId: 'previous-snapshot-key',
1265
+ ratchetDispatchSnapshotKey: 'previous-snapshot-key',
1180
1266
  prReviewLastCheckedAt: new Date('2026-01-01T00:00:00Z'),
1181
1267
  ratchetDispatchOutcome: 'RUNNING',
1182
1268
  ratchetDispatchRetryCount: 0,
@@ -1197,11 +1283,13 @@ describe('ratchet service (state-change + idle dispatch)', () => {
1197
1283
  prUrl: 'https://github.com/example/repo/pull/12',
1198
1284
  prNumber: 12,
1199
1285
  prState: 'OPEN',
1286
+ prReviewState: null,
1287
+ prHasMergeConflict: false,
1200
1288
  prCiStatus: CIStatus.UNKNOWN,
1201
1289
  ratchetEnabled: true,
1202
1290
  ratchetState: RatchetState.CI_FAILED,
1203
1291
  ratchetActiveSessionId: 'finished-session',
1204
- ratchetLastCiRunId: 'previous-snapshot-key',
1292
+ ratchetDispatchSnapshotKey: 'previous-snapshot-key',
1205
1293
  prReviewLastCheckedAt: new Date('2026-01-01T00:00:00Z'),
1206
1294
  ratchetDispatchOutcome: 'RUNNING',
1207
1295
  ratchetDispatchRetryCount: 0,
@@ -1222,11 +1310,13 @@ describe('ratchet service (state-change + idle dispatch)', () => {
1222
1310
  prUrl: 'https://github.com/example/repo/pull/12',
1223
1311
  prNumber: 12,
1224
1312
  prState: 'OPEN',
1313
+ prReviewState: null,
1314
+ prHasMergeConflict: false,
1225
1315
  prCiStatus: CIStatus.UNKNOWN,
1226
1316
  ratchetEnabled: true,
1227
1317
  ratchetState: RatchetState.CI_FAILED,
1228
1318
  ratchetActiveSessionId: 'finished-session',
1229
- ratchetLastCiRunId: 'previous-snapshot-key',
1319
+ ratchetDispatchSnapshotKey: 'previous-snapshot-key',
1230
1320
  prReviewLastCheckedAt: new Date('2026-01-01T00:00:00Z'),
1231
1321
  ratchetDispatchOutcome: 'RUNNING',
1232
1322
  ratchetDispatchRetryCount: 0,
@@ -1257,11 +1347,13 @@ describe('ratchet service (state-change + idle dispatch)', () => {
1257
1347
  prUrl: 'https://github.com/example/repo/pull/11',
1258
1348
  prNumber: 11,
1259
1349
  prState: 'OPEN',
1350
+ prReviewState: null,
1351
+ prHasMergeConflict: false,
1260
1352
  prCiStatus: CIStatus.UNKNOWN,
1261
1353
  ratchetEnabled: true,
1262
1354
  ratchetState: RatchetState.CI_FAILED,
1263
1355
  ratchetActiveSessionId: 'ratchet-session',
1264
- ratchetLastCiRunId: 'snapshot-key',
1356
+ ratchetDispatchSnapshotKey: 'snapshot-key',
1265
1357
  prReviewLastCheckedAt: new Date('2026-01-01T00:00:00Z'),
1266
1358
  ratchetDispatchOutcome: 'RUNNING',
1267
1359
  ratchetDispatchRetryCount: 0,
@@ -1327,11 +1419,13 @@ describe('ratchet service (state-change + idle dispatch)', () => {
1327
1419
  prUrl: 'https://github.com/example/repo/pull/10',
1328
1420
  prNumber: 10,
1329
1421
  prState: 'OPEN',
1422
+ prReviewState: null,
1423
+ prHasMergeConflict: false,
1330
1424
  prCiStatus: CIStatus.UNKNOWN,
1331
1425
  ratchetEnabled: true,
1332
1426
  ratchetState: RatchetState.READY,
1333
1427
  ratchetActiveSessionId: null,
1334
- ratchetLastCiRunId: 'prev-snapshot',
1428
+ ratchetDispatchSnapshotKey: 'prev-snapshot',
1335
1429
  prReviewLastCheckedAt: null,
1336
1430
  ratchetDispatchOutcome: null,
1337
1431
  ratchetDispatchRetryCount: 0,
@@ -1543,7 +1637,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
1543
1637
  ratchetEnabled: true,
1544
1638
  ratchetState: RatchetState.IDLE,
1545
1639
  ratchetActiveSessionId: null,
1546
- ratchetLastCiRunId: null,
1640
+ ratchetDispatchSnapshotKey: null,
1547
1641
  prReviewLastCheckedAt: null,
1548
1642
  ratchetDispatchOutcome: null,
1549
1643
  ratchetDispatchRetryCount: 0,
@@ -1563,7 +1657,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
1563
1657
  ratchetEnabled: true,
1564
1658
  ratchetState: RatchetState.IDLE,
1565
1659
  ratchetActiveSessionId: null,
1566
- ratchetLastCiRunId: null,
1660
+ ratchetDispatchSnapshotKey: null,
1567
1661
  prReviewLastCheckedAt: null,
1568
1662
  ratchetDispatchOutcome: null,
1569
1663
  ratchetDispatchRetryCount: 0,
@@ -1577,7 +1671,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
1577
1671
  expect(workspaceRatchetService.clearActiveSession).not.toHaveBeenCalled();
1578
1672
  });
1579
1673
  it('returns WAITING when shutting down', async () => {
1580
- unsafeCoerce(ratchetService).isShuttingDown = true;
1674
+ setRatchetShuttingDown(true);
1581
1675
  const workspace = {
1582
1676
  id: 'ws-shutdown',
1583
1677
  prUrl: 'https://github.com/example/repo/pull/1',
@@ -1585,7 +1679,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
1585
1679
  ratchetEnabled: true,
1586
1680
  ratchetState: RatchetState.CI_FAILED,
1587
1681
  ratchetActiveSessionId: null,
1588
- ratchetLastCiRunId: null,
1682
+ ratchetDispatchSnapshotKey: null,
1589
1683
  prReviewLastCheckedAt: null,
1590
1684
  ratchetDispatchOutcome: null,
1591
1685
  ratchetDispatchRetryCount: 0,
@@ -1605,7 +1699,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
1605
1699
  ratchetEnabled: true,
1606
1700
  ratchetState: RatchetState.CI_FAILED,
1607
1701
  ratchetActiveSessionId: null,
1608
- ratchetLastCiRunId: null,
1702
+ ratchetDispatchSnapshotKey: null,
1609
1703
  prReviewLastCheckedAt: null,
1610
1704
  ratchetDispatchOutcome: null,
1611
1705
  ratchetDispatchRetryCount: 0,
@@ -1621,7 +1715,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
1621
1715
  });
1622
1716
  describe('checkAllWorkspaces', () => {
1623
1717
  it('returns zero counts when shutting down', async () => {
1624
- unsafeCoerce(ratchetService).isShuttingDown = true;
1718
+ setRatchetShuttingDown(true);
1625
1719
  const result = await ratchetService.checkAllWorkspaces();
1626
1720
  expect(result).toEqual({ checked: 0, stateChanges: 0, actionsTriggered: 0, results: [] });
1627
1721
  });
@@ -1636,11 +1730,13 @@ describe('ratchet service (state-change + idle dispatch)', () => {
1636
1730
  prUrl: `https://github.com/example/repo/pull/${id}`,
1637
1731
  prNumber: 1,
1638
1732
  prState: 'OPEN',
1733
+ prReviewState: null,
1734
+ prHasMergeConflict: false,
1639
1735
  prCiStatus: CIStatus.UNKNOWN,
1640
1736
  ratchetEnabled: true,
1641
1737
  ratchetState: RatchetState.IDLE,
1642
1738
  ratchetActiveSessionId: null,
1643
- ratchetLastCiRunId: null,
1739
+ ratchetDispatchSnapshotKey: null,
1644
1740
  prReviewLastCheckedAt: null,
1645
1741
  ratchetDispatchOutcome: null,
1646
1742
  ratchetDispatchRetryCount: 0,
@@ -1665,7 +1761,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
1665
1761
  ratchetEnabled: true,
1666
1762
  ratchetState: RatchetState.IDLE,
1667
1763
  ratchetActiveSessionId: null,
1668
- ratchetLastCiRunId: null,
1764
+ ratchetDispatchSnapshotKey: null,
1669
1765
  prReviewLastCheckedAt: null,
1670
1766
  ratchetDispatchOutcome: null,
1671
1767
  ratchetDispatchRetryCount: 0,
@@ -1681,7 +1777,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
1681
1777
  ratchetEnabled: true,
1682
1778
  ratchetState: RatchetState.CI_RUNNING,
1683
1779
  ratchetActiveSessionId: null,
1684
- ratchetLastCiRunId: null,
1780
+ ratchetDispatchSnapshotKey: null,
1685
1781
  prReviewLastCheckedAt: null,
1686
1782
  ratchetDispatchOutcome: null,
1687
1783
  ratchetDispatchRetryCount: 0,
@@ -1723,13 +1819,15 @@ describe('ratchet service (state-change + idle dispatch)', () => {
1723
1819
  prUrl: `https://github.com/example/repo/pull/${index + 1}`,
1724
1820
  prNumber: index + 1,
1725
1821
  prState: 'OPEN',
1822
+ prReviewState: null,
1823
+ prHasMergeConflict: false,
1726
1824
  prCiStatus: CIStatus.UNKNOWN,
1727
1825
  defaultSessionProvider: 'WORKSPACE_DEFAULT',
1728
1826
  ratchetSessionProvider: 'WORKSPACE_DEFAULT',
1729
1827
  ratchetEnabled: true,
1730
1828
  ratchetState: RatchetState.IDLE,
1731
1829
  ratchetActiveSessionId: null,
1732
- ratchetLastCiRunId: null,
1830
+ ratchetDispatchSnapshotKey: null,
1733
1831
  prReviewLastCheckedAt: null,
1734
1832
  ratchetDispatchOutcome: null,
1735
1833
  ratchetDispatchRetryCount: 0,
@@ -1796,13 +1894,15 @@ describe('ratchet service (state-change + idle dispatch)', () => {
1796
1894
  prUrl: `https://github.com/example/repo/pull/${index + 1}`,
1797
1895
  prNumber: index + 1,
1798
1896
  prState: 'OPEN',
1897
+ prReviewState: null,
1898
+ prHasMergeConflict: false,
1799
1899
  prCiStatus: CIStatus.UNKNOWN,
1800
1900
  defaultSessionProvider: 'WORKSPACE_DEFAULT',
1801
1901
  ratchetSessionProvider: 'WORKSPACE_DEFAULT',
1802
1902
  ratchetEnabled: true,
1803
1903
  ratchetState: RatchetState.IDLE,
1804
1904
  ratchetActiveSessionId: null,
1805
- ratchetLastCiRunId: null,
1905
+ ratchetDispatchSnapshotKey: null,
1806
1906
  prReviewLastCheckedAt: null,
1807
1907
  ratchetDispatchOutcome: null,
1808
1908
  ratchetDispatchRetryCount: 0,
@@ -1852,98 +1952,10 @@ describe('ratchet service (state-change + idle dispatch)', () => {
1852
1952
  vi.useRealTimers();
1853
1953
  });
1854
1954
  });
1855
- describe('markPrClosed', () => {
1955
+ describe('check abort safety', () => {
1856
1956
  afterEach(() => {
1857
1957
  ratchetService.removeAllListeners();
1858
1958
  });
1859
- it('resets ratchet state to IDLE via CAS on fromState and emits a state change', async () => {
1860
- vi.mocked(workspaceDataService.findById).mockResolvedValue({
1861
- id: 'ws-closed',
1862
- ratchetEnabled: true,
1863
- ratchetState: RatchetState.CI_FAILED,
1864
- });
1865
- vi.mocked(workspaceRatchetService.transitionStateIfEnabled).mockResolvedValue(true);
1866
- const stateEvents = [];
1867
- ratchetService.on(RATCHET_STATE_CHANGED, (event) => {
1868
- stateEvents.push(event);
1869
- });
1870
- await ratchetService.markPrClosed('ws-closed');
1871
- expect(workspaceRatchetService.transitionStateIfEnabled).toHaveBeenCalledWith('ws-closed', RatchetState.CI_FAILED, {
1872
- ratchetState: RatchetState.IDLE,
1873
- ratchetLastCheckedAt: expect.any(Date),
1874
- });
1875
- expect(stateEvents).toEqual([
1876
- {
1877
- workspaceId: 'ws-closed',
1878
- fromState: RatchetState.CI_FAILED,
1879
- toState: RatchetState.IDLE,
1880
- },
1881
- ]);
1882
- });
1883
- it('emits the fromState that actually won the compare-and-swap after losing a race', async () => {
1884
- vi.mocked(workspaceDataService.findById)
1885
- .mockResolvedValueOnce({
1886
- id: 'ws-closed',
1887
- ratchetEnabled: true,
1888
- ratchetState: RatchetState.CI_FAILED,
1889
- })
1890
- .mockResolvedValueOnce({
1891
- id: 'ws-closed',
1892
- ratchetEnabled: true,
1893
- ratchetState: RatchetState.CI_RUNNING,
1894
- });
1895
- vi.mocked(workspaceRatchetService.transitionStateIfEnabled)
1896
- .mockResolvedValueOnce(false)
1897
- .mockResolvedValueOnce(true);
1898
- const stateEvents = [];
1899
- ratchetService.on(RATCHET_STATE_CHANGED, (event) => {
1900
- stateEvents.push(event);
1901
- });
1902
- await ratchetService.markPrClosed('ws-closed');
1903
- expect(workspaceRatchetService.transitionStateIfEnabled).toHaveBeenNthCalledWith(1, 'ws-closed', RatchetState.CI_FAILED, expect.objectContaining({ ratchetState: RatchetState.IDLE }));
1904
- expect(workspaceRatchetService.transitionStateIfEnabled).toHaveBeenNthCalledWith(2, 'ws-closed', RatchetState.CI_RUNNING, expect.objectContaining({ ratchetState: RatchetState.IDLE }));
1905
- expect(stateEvents).toEqual([
1906
- {
1907
- workspaceId: 'ws-closed',
1908
- fromState: RatchetState.CI_RUNNING,
1909
- toState: RatchetState.IDLE,
1910
- },
1911
- ]);
1912
- });
1913
- it('is a no-op when ratchet state is already IDLE', async () => {
1914
- vi.mocked(workspaceDataService.findById).mockResolvedValue({
1915
- id: 'ws-closed',
1916
- ratchetEnabled: true,
1917
- ratchetState: RatchetState.IDLE,
1918
- });
1919
- await ratchetService.markPrClosed('ws-closed');
1920
- expect(workspaceRatchetService.transitionStateIfEnabled).not.toHaveBeenCalled();
1921
- });
1922
- it('does not emit when ratcheting was disabled concurrently', async () => {
1923
- vi.mocked(workspaceDataService.findById)
1924
- .mockResolvedValueOnce({
1925
- id: 'ws-closed',
1926
- ratchetEnabled: true,
1927
- ratchetState: RatchetState.CI_FAILED,
1928
- })
1929
- .mockResolvedValueOnce({
1930
- id: 'ws-closed',
1931
- ratchetEnabled: false,
1932
- ratchetState: RatchetState.IDLE,
1933
- });
1934
- vi.mocked(workspaceRatchetService.transitionStateIfEnabled).mockResolvedValue(false);
1935
- const stateEvents = [];
1936
- ratchetService.on(RATCHET_STATE_CHANGED, (event) => {
1937
- stateEvents.push(event);
1938
- });
1939
- await ratchetService.markPrClosed('ws-closed');
1940
- expect(stateEvents).toEqual([]);
1941
- });
1942
- it('is a no-op when workspace is not found', async () => {
1943
- vi.mocked(workspaceDataService.findById).mockResolvedValue(null);
1944
- await ratchetService.markPrClosed('ws-missing');
1945
- expect(workspaceRatchetService.transitionStateIfEnabled).not.toHaveBeenCalled();
1946
- });
1947
1959
  it('does not continue to side effects after a timed-out await completes', async () => {
1948
1960
  unsafeCoerce(ratchetService).workspaceCheckTimeoutMs = 5;
1949
1961
  const workspace = {
@@ -1951,13 +1963,15 @@ describe('ratchet service (state-change + idle dispatch)', () => {
1951
1963
  prUrl: 'https://github.com/example/repo/pull/1',
1952
1964
  prNumber: 1,
1953
1965
  prState: 'OPEN',
1966
+ prReviewState: null,
1967
+ prHasMergeConflict: false,
1954
1968
  prCiStatus: CIStatus.FAILURE,
1955
1969
  defaultSessionProvider: 'WORKSPACE_DEFAULT',
1956
1970
  ratchetSessionProvider: 'WORKSPACE_DEFAULT',
1957
1971
  ratchetEnabled: true,
1958
1972
  ratchetState: RatchetState.IDLE,
1959
1973
  ratchetActiveSessionId: null,
1960
- ratchetLastCiRunId: null,
1974
+ ratchetDispatchSnapshotKey: null,
1961
1975
  prReviewLastCheckedAt: null,
1962
1976
  ratchetDispatchOutcome: null,
1963
1977
  ratchetDispatchRetryCount: 0,
@@ -1987,17 +2001,17 @@ describe('ratchet service (state-change + idle dispatch)', () => {
1987
2001
  releaseFetch();
1988
2002
  await new Promise((resolve) => setTimeout(resolve, 0));
1989
2003
  expect(finishSpy).not.toHaveBeenCalled();
1990
- expect(workspaceRatchetService.transitionStateIfEnabled).not.toHaveBeenCalled();
2004
+ expect(workspaceRatchetService.recordCheckIfEnabled).not.toHaveBeenCalled();
1991
2005
  });
1992
2006
  });
1993
2007
  describe('checkWorkspaceById', () => {
1994
2008
  it('returns null when shutting down', async () => {
1995
- unsafeCoerce(ratchetService).isShuttingDown = true;
2009
+ setRatchetShuttingDown(true);
1996
2010
  const result = await ratchetService.checkWorkspaceById('ws-1');
1997
2011
  expect(result).toBeNull();
1998
2012
  });
1999
2013
  it('returns null when workspace not found', async () => {
2000
- unsafeCoerce(ratchetService).isShuttingDown = false;
2014
+ setRatchetShuttingDown(false);
2001
2015
  vi.mocked(workspaceRatchetService.findCandidateById).mockResolvedValue(null);
2002
2016
  const result = await ratchetService.checkWorkspaceById('ws-nonexistent');
2003
2017
  expect(result).toBeNull();
@@ -2008,11 +2022,13 @@ describe('ratchet service (state-change + idle dispatch)', () => {
2008
2022
  prUrl: 'https://github.com/example/repo/pull/9',
2009
2023
  prNumber: 9,
2010
2024
  prState: 'OPEN',
2025
+ prReviewState: null,
2026
+ prHasMergeConflict: false,
2011
2027
  prCiStatus: CIStatus.UNKNOWN,
2012
2028
  ratchetEnabled: true,
2013
2029
  ratchetState: RatchetState.CI_RUNNING,
2014
2030
  ratchetActiveSessionId: null,
2015
- ratchetLastCiRunId: null,
2031
+ ratchetDispatchSnapshotKey: null,
2016
2032
  prReviewLastCheckedAt: null,
2017
2033
  ratchetDispatchOutcome: null,
2018
2034
  ratchetDispatchRetryCount: 0,
@@ -2023,7 +2039,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
2023
2039
  repo: 'repo',
2024
2040
  number: 9,
2025
2041
  });
2026
- vi.mocked(mockGitHubBridge.isRecentlyFetched).mockReturnValue(true);
2042
+ fakeCoordinator.cooldownActive = true;
2027
2043
  const result = await ratchetService.checkWorkspaceById('ws-cooldown');
2028
2044
  expect(result?.action).toEqual({ type: 'WAITING', reason: 'recently_fetched' });
2029
2045
  expect(mockGitHubBridge.getPRFullDetails).not.toHaveBeenCalled();
@@ -2034,13 +2050,15 @@ describe('ratchet service (state-change + idle dispatch)', () => {
2034
2050
  prUrl: 'https://github.com/example/repo/pull/9',
2035
2051
  prNumber: 9,
2036
2052
  prState: 'OPEN',
2053
+ prReviewState: null,
2054
+ prHasMergeConflict: false,
2037
2055
  prCiStatus: CIStatus.UNKNOWN,
2038
2056
  defaultSessionProvider: 'WORKSPACE_DEFAULT',
2039
2057
  ratchetSessionProvider: 'WORKSPACE_DEFAULT',
2040
2058
  ratchetEnabled: true,
2041
2059
  ratchetState: RatchetState.CI_RUNNING,
2042
2060
  ratchetActiveSessionId: null,
2043
- ratchetLastCiRunId: null,
2061
+ ratchetDispatchSnapshotKey: null,
2044
2062
  prReviewLastCheckedAt: null,
2045
2063
  ratchetDispatchOutcome: null,
2046
2064
  ratchetDispatchRetryCount: 0,
@@ -2051,8 +2069,9 @@ describe('ratchet service (state-change + idle dispatch)', () => {
2051
2069
  repo: 'repo',
2052
2070
  number: 9,
2053
2071
  });
2054
- vi.mocked(mockGitHubBridge.isRecentlyFetched).mockReturnValue(true);
2072
+ fakeCoordinator.cooldownActive = true;
2055
2073
  vi.mocked(mockGitHubBridge.getPRFullDetails).mockResolvedValue({
2074
+ isDraft: false,
2056
2075
  state: 'OPEN',
2057
2076
  number: 9,
2058
2077
  url: 'https://github.com/example/repo/pull/9',
@@ -2077,13 +2096,15 @@ describe('ratchet service (state-change + idle dispatch)', () => {
2077
2096
  prUrl: 'https://github.com/example/repo/pull/9',
2078
2097
  prNumber: 9,
2079
2098
  prState: 'OPEN',
2099
+ prReviewState: null,
2100
+ prHasMergeConflict: false,
2080
2101
  prCiStatus: CIStatus.UNKNOWN,
2081
2102
  defaultSessionProvider: 'WORKSPACE_DEFAULT',
2082
2103
  ratchetSessionProvider: 'WORKSPACE_DEFAULT',
2083
2104
  ratchetEnabled: true,
2084
2105
  ratchetState: RatchetState.CI_RUNNING,
2085
2106
  ratchetActiveSessionId: null,
2086
- ratchetLastCiRunId: null,
2107
+ ratchetDispatchSnapshotKey: null,
2087
2108
  prReviewLastCheckedAt: null,
2088
2109
  ratchetDispatchOutcome: null,
2089
2110
  ratchetDispatchRetryCount: 0,
@@ -2094,8 +2115,9 @@ describe('ratchet service (state-change + idle dispatch)', () => {
2094
2115
  repo: 'repo',
2095
2116
  number: 9,
2096
2117
  });
2097
- vi.mocked(mockGitHubBridge.isFetchInFlight).mockReturnValueOnce(true).mockReturnValue(false);
2118
+ fakeCoordinator.inFlightSkips = 1;
2098
2119
  vi.mocked(mockGitHubBridge.getPRFullDetails).mockResolvedValue({
2120
+ isDraft: false,
2099
2121
  state: 'OPEN',
2100
2122
  number: 9,
2101
2123
  url: 'https://github.com/example/repo/pull/9',
@@ -2120,11 +2142,13 @@ describe('ratchet service (state-change + idle dispatch)', () => {
2120
2142
  prUrl: 'https://github.com/example/repo/pull/9',
2121
2143
  prNumber: 9,
2122
2144
  prState: 'OPEN',
2145
+ prReviewState: null,
2146
+ prHasMergeConflict: false,
2123
2147
  prCiStatus: CIStatus.UNKNOWN,
2124
2148
  ratchetEnabled: true,
2125
2149
  ratchetState: RatchetState.CI_RUNNING,
2126
2150
  ratchetActiveSessionId: null,
2127
- ratchetLastCiRunId: null,
2151
+ ratchetDispatchSnapshotKey: null,
2128
2152
  prReviewLastCheckedAt: null,
2129
2153
  ratchetDispatchOutcome: null,
2130
2154
  ratchetDispatchRetryCount: 0,
@@ -2135,28 +2159,30 @@ describe('ratchet service (state-change + idle dispatch)', () => {
2135
2159
  repo: 'repo',
2136
2160
  number: 9,
2137
2161
  });
2138
- vi.mocked(mockGitHubBridge.isFetchInFlight).mockReturnValue(true);
2162
+ fakeCoordinator.inFlightSkips = Number.POSITIVE_INFINITY;
2139
2163
  const result = await ratchetService.checkWorkspaceById('ws-rerun-cap', {
2140
2164
  bypassPrFetchCooldown: true,
2141
2165
  });
2142
2166
  expect(result?.action).toEqual({ type: 'WAITING', reason: 'recently_fetched' });
2143
- expect(mockGitHubBridge.isFetchInFlight).toHaveBeenCalledTimes(2);
2167
+ expect(mockGitHubBridge.coordinatePrFetch).toHaveBeenCalledTimes(2);
2144
2168
  expect(mockGitHubBridge.getPRFullDetails).not.toHaveBeenCalled();
2145
2169
  });
2146
2170
  it('deduplicates concurrent checks for the same workspace', async () => {
2147
- unsafeCoerce(ratchetService).isShuttingDown = false;
2171
+ setRatchetShuttingDown(false);
2148
2172
  const workspace = {
2149
2173
  id: 'ws-1',
2150
2174
  prUrl: 'https://github.com/example/repo/pull/1',
2151
2175
  prNumber: 1,
2152
2176
  prState: 'OPEN',
2177
+ prReviewState: null,
2178
+ prHasMergeConflict: false,
2153
2179
  prCiStatus: CIStatus.UNKNOWN,
2154
2180
  defaultSessionProvider: 'WORKSPACE_DEFAULT',
2155
2181
  ratchetSessionProvider: 'WORKSPACE_DEFAULT',
2156
2182
  ratchetEnabled: true,
2157
2183
  ratchetState: RatchetState.IDLE,
2158
2184
  ratchetActiveSessionId: null,
2159
- ratchetLastCiRunId: null,
2185
+ ratchetDispatchSnapshotKey: null,
2160
2186
  prReviewLastCheckedAt: null,
2161
2187
  ratchetDispatchOutcome: null,
2162
2188
  ratchetDispatchRetryCount: 0,
@@ -2486,22 +2512,58 @@ describe('ratchet service (state-change + idle dispatch)', () => {
2486
2512
  expect(result).toEqual({ kind: 'settled', outcome: 'DIED' });
2487
2513
  expect(mockWorkspaceBridge.recordSessionEnd).toHaveBeenCalledWith('ws-4', 'failed-session', 'DIED');
2488
2514
  });
2489
- it('settles a provider-mismatched session as DIED and stops it', async () => {
2515
+ it('waits for provider-mismatch cleanup before returning a successful settlement', async () => {
2516
+ let finishStop;
2517
+ const pendingStop = new Promise((resolve) => {
2518
+ finishStop = resolve;
2519
+ });
2490
2520
  vi.mocked(mockSessionBridge.findSessionById).mockResolvedValue({
2491
2521
  id: 'codex-session',
2492
2522
  provider: 'CODEX',
2493
2523
  status: SessionStatus.RUNNING,
2494
2524
  });
2495
- vi.mocked(mockSessionBridge.stopSession).mockResolvedValue();
2496
- const result = await callCheckActiveFixerSession({
2525
+ vi.mocked(mockSessionBridge.stopSession).mockReturnValue(pendingStop);
2526
+ const check = callCheckActiveFixerSession({
2497
2527
  id: 'ws-5',
2498
2528
  ratchetActiveSessionId: 'codex-session',
2499
2529
  defaultSessionProvider: 'WORKSPACE_DEFAULT',
2500
2530
  ratchetSessionProvider: 'WORKSPACE_DEFAULT',
2501
2531
  });
2502
- expect(result).toEqual({ kind: 'settled', outcome: 'DIED' });
2532
+ await vi.waitFor(() => expect(mockSessionBridge.stopSession).toHaveBeenCalledWith('codex-session'));
2533
+ await expect(Promise.race([check, Promise.resolve({ kind: 'cleanup_pending' })])).resolves.toEqual({ kind: 'cleanup_pending' });
2503
2534
  expect(mockWorkspaceBridge.recordSessionEnd).toHaveBeenCalledWith('ws-5', 'codex-session', 'DIED');
2504
- expect(mockSessionBridge.stopSession).toHaveBeenCalledWith('codex-session');
2535
+ finishStop();
2536
+ await expect(check).resolves.toEqual({ kind: 'settled', outcome: 'DIED' });
2537
+ });
2538
+ it('returns cancellation without waiting for provider-mismatch cleanup', async () => {
2539
+ const controller = new AbortController();
2540
+ const timeoutError = new Error('Workspace check timed out');
2541
+ let finishStop;
2542
+ const pendingStop = new Promise((resolve) => {
2543
+ finishStop = resolve;
2544
+ });
2545
+ vi.mocked(mockSessionBridge.findSessionById).mockResolvedValue({
2546
+ id: 'codex-session',
2547
+ provider: 'CODEX',
2548
+ status: SessionStatus.RUNNING,
2549
+ });
2550
+ vi.mocked(mockSessionBridge.stopSession).mockReturnValue(pendingStop);
2551
+ vi.mocked(mockWorkspaceBridge.recordSessionEnd).mockImplementation(() => {
2552
+ controller.abort(timeoutError);
2553
+ return Promise.resolve(true);
2554
+ });
2555
+ const check = unsafeCoerce(ratchetService).checkActiveFixerSession({
2556
+ id: 'ws-provider-mismatch-cancelled-after-settlement',
2557
+ ratchetActiveSessionId: 'codex-session',
2558
+ defaultSessionProvider: 'WORKSPACE_DEFAULT',
2559
+ ratchetSessionProvider: 'WORKSPACE_DEFAULT',
2560
+ }, controller.signal);
2561
+ const outcome = check.then((value) => ({ status: 'resolved', value }), (error) => ({ status: 'rejected', error }));
2562
+ await vi.waitFor(() => expect(mockSessionBridge.stopSession).toHaveBeenCalledWith('codex-session'));
2563
+ await expect(Promise.race([outcome, Promise.resolve({ status: 'pending' })])).resolves.toEqual({ status: 'rejected', error: timeoutError });
2564
+ expect(mockWorkspaceBridge.recordSessionEnd).toHaveBeenCalledWith('ws-provider-mismatch-cancelled-after-settlement', 'codex-session', 'DIED');
2565
+ finishStop();
2566
+ await pendingStop;
2505
2567
  });
2506
2568
  it('returns the active fixer when the session is working', async () => {
2507
2569
  vi.mocked(mockSessionBridge.findSessionById).mockResolvedValue({
@@ -2703,6 +2765,10 @@ describe('ratchet service (state-change + idle dispatch)', () => {
2703
2765
  promptCompletion: Promise.resolve(false),
2704
2766
  });
2705
2767
  vi.mocked(mockSessionBridge.isSessionRunning).mockReturnValue(true);
2768
+ const events = [];
2769
+ ratchetService.on(RATCHET_DISPATCH_CHANGED, (event) => {
2770
+ events.push(event);
2771
+ });
2706
2772
  const result = await unsafeCoerce(ratchetService).triggerFixer({
2707
2773
  id: 'ws-failed-prompt',
2708
2774
  prUrl: 'https://github.com/example/repo/pull/20',
@@ -2716,6 +2782,10 @@ describe('ratchet service (state-change + idle dispatch)', () => {
2716
2782
  expect(result).toMatchObject({ type: 'TRIGGERED_FIXER' });
2717
2783
  await vi.waitFor(() => expect(workspaceRatchetService.recordSessionEnd).toHaveBeenCalledWith('ws-failed-prompt', 'failed-prompt-session', 'DIED'));
2718
2784
  expect(mockSessionBridge.stopSession).toHaveBeenCalledWith('failed-prompt-session');
2785
+ await vi.waitFor(() => expect(events).toEqual([
2786
+ { workspaceId: 'ws-failed-prompt' },
2787
+ { workspaceId: 'ws-failed-prompt' },
2788
+ ]));
2719
2789
  });
2720
2790
  it('does not stop a newer active session when an old prompt completion fails', async () => {
2721
2791
  vi.mocked(fixerSessionService.acquireAndDispatch).mockResolvedValue({
@@ -2726,6 +2796,10 @@ describe('ratchet service (state-change + idle dispatch)', () => {
2726
2796
  });
2727
2797
  vi.mocked(workspaceRatchetService.recordSessionEnd).mockResolvedValue(false);
2728
2798
  vi.mocked(mockSessionBridge.isSessionRunning).mockReturnValue(true);
2799
+ const events = [];
2800
+ ratchetService.on(RATCHET_DISPATCH_CHANGED, (event) => {
2801
+ events.push(event);
2802
+ });
2729
2803
  await unsafeCoerce(ratchetService).triggerFixer({
2730
2804
  id: 'ws-replaced-prompt',
2731
2805
  prUrl: 'https://github.com/example/repo/pull/20',
@@ -2738,6 +2812,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
2738
2812
  }, 0);
2739
2813
  await vi.waitFor(() => expect(workspaceRatchetService.recordSessionEnd).toHaveBeenCalled());
2740
2814
  expect(mockSessionBridge.stopSession).not.toHaveBeenCalled();
2815
+ expect(events).toEqual([{ workspaceId: 'ws-replaced-prompt' }]);
2741
2816
  });
2742
2817
  it('cleans up a fixer through prompt failure after its dispatch record is persisted', async () => {
2743
2818
  const controller = new AbortController();
@@ -2805,7 +2880,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
2805
2880
  ratchetEnabled: true,
2806
2881
  ratchetState: RatchetState.CI_FAILED,
2807
2882
  ratchetActiveSessionId: null,
2808
- ratchetLastCiRunId: null,
2883
+ ratchetDispatchSnapshotKey: null,
2809
2884
  prReviewLastCheckedAt: null,
2810
2885
  ratchetDispatchOutcome: null,
2811
2886
  ratchetDispatchRetryCount: 0,
@@ -2828,7 +2903,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
2828
2903
  ratchetEnabled: true,
2829
2904
  ratchetState: RatchetState.CI_FAILED,
2830
2905
  ratchetActiveSessionId: null,
2831
- ratchetLastCiRunId: null,
2906
+ ratchetDispatchSnapshotKey: null,
2832
2907
  prReviewLastCheckedAt: null,
2833
2908
  ratchetDispatchOutcome: null,
2834
2909
  ratchetDispatchRetryCount: 2,
@@ -2861,7 +2936,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
2861
2936
  ratchetEnabled: true,
2862
2937
  ratchetState: RatchetState.CI_FAILED,
2863
2938
  ratchetActiveSessionId: null,
2864
- ratchetLastCiRunId: null,
2939
+ ratchetDispatchSnapshotKey: null,
2865
2940
  prReviewLastCheckedAt: null,
2866
2941
  ratchetDispatchOutcome: null,
2867
2942
  ratchetDispatchRetryCount: 0,
@@ -2890,7 +2965,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
2890
2965
  ratchetEnabled: true,
2891
2966
  ratchetState: RatchetState.CI_FAILED,
2892
2967
  ratchetActiveSessionId: null,
2893
- ratchetLastCiRunId: null,
2968
+ ratchetDispatchSnapshotKey: null,
2894
2969
  prReviewLastCheckedAt: null,
2895
2970
  ratchetDispatchOutcome: null,
2896
2971
  ratchetDispatchRetryCount: 0,
@@ -3000,32 +3075,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
3000
3075
  afterEach(() => {
3001
3076
  ratchetService.removeAllListeners();
3002
3077
  });
3003
- it('emits ratchet_state_changed when disabled workspace state changes', async () => {
3004
- const workspace = {
3005
- id: 'ws-disabled-change',
3006
- prUrl: 'https://github.com/example/repo/pull/30',
3007
- prNumber: 30,
3008
- ratchetEnabled: false,
3009
- ratchetState: RatchetState.CI_FAILED,
3010
- ratchetActiveSessionId: null,
3011
- ratchetLastCiRunId: null,
3012
- prReviewLastCheckedAt: null,
3013
- ratchetDispatchOutcome: null,
3014
- ratchetDispatchRetryCount: 0,
3015
- };
3016
- const events = [];
3017
- ratchetService.on(RATCHET_STATE_CHANGED, (event) => {
3018
- events.push(event);
3019
- });
3020
- await unsafeCoerce(ratchetService).processWorkspace(workspace);
3021
- expect(events).toHaveLength(1);
3022
- expect(events[0]).toEqual({
3023
- workspaceId: 'ws-disabled-change',
3024
- fromState: RatchetState.CI_FAILED,
3025
- toState: RatchetState.IDLE,
3026
- });
3027
- });
3028
- it('does NOT emit when disabled workspace state is already IDLE', async () => {
3078
+ it('never emits from a check on a disabled workspace', async () => {
3029
3079
  const workspace = {
3030
3080
  id: 'ws-disabled-idle',
3031
3081
  prUrl: 'https://github.com/example/repo/pull/31',
@@ -3033,7 +3083,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
3033
3083
  ratchetEnabled: false,
3034
3084
  ratchetState: RatchetState.IDLE,
3035
3085
  ratchetActiveSessionId: null,
3036
- ratchetLastCiRunId: null,
3086
+ ratchetDispatchSnapshotKey: null,
3037
3087
  prReviewLastCheckedAt: null,
3038
3088
  ratchetDispatchOutcome: null,
3039
3089
  ratchetDispatchRetryCount: 0,
@@ -3053,7 +3103,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
3053
3103
  ratchetEnabled: true,
3054
3104
  ratchetState: RatchetState.IDLE,
3055
3105
  ratchetActiveSessionId: null,
3056
- ratchetLastCiRunId: null,
3106
+ ratchetDispatchSnapshotKey: null,
3057
3107
  prReviewLastCheckedAt: null,
3058
3108
  ratchetDispatchOutcome: null,
3059
3109
  ratchetDispatchRetryCount: 0,
@@ -3094,7 +3144,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
3094
3144
  ratchetEnabled: true,
3095
3145
  ratchetState: RatchetState.CI_FAILED,
3096
3146
  ratchetActiveSessionId: null,
3097
- ratchetLastCiRunId: null,
3147
+ ratchetDispatchSnapshotKey: null,
3098
3148
  prReviewLastCheckedAt: null,
3099
3149
  ratchetDispatchOutcome: null,
3100
3150
  ratchetDispatchRetryCount: 0,
@@ -3129,7 +3179,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
3129
3179
  ratchetEnabled: true,
3130
3180
  ratchetState: RatchetState.CI_FAILED,
3131
3181
  ratchetActiveSessionId: null,
3132
- ratchetLastCiRunId: null,
3182
+ ratchetDispatchSnapshotKey: null,
3133
3183
  prReviewLastCheckedAt: null,
3134
3184
  ratchetDispatchOutcome: null,
3135
3185
  ratchetDispatchRetryCount: 0,