factory-factory 0.4.0 → 0.4.1

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 (1045) hide show
  1. package/README.md +61 -344
  2. package/dist/client/assets/{arc-BZLkggFv.js → arc-lK3Ig9GV.js} +1 -1
  3. package/dist/client/assets/{architectureDiagram-3BPJPVTR-0dfKDS01.js → architectureDiagram-3BPJPVTR-CeUbfBqe.js} +1 -1
  4. package/dist/client/assets/{blockDiagram-GPEHLZMM-kPnqTUvo.js → blockDiagram-GPEHLZMM-DiVGPkq2.js} +1 -1
  5. package/dist/client/assets/{c4Diagram-AAUBKEIU-fGcSJ5RM.js → c4Diagram-AAUBKEIU-CT8hJB-h.js} +1 -1
  6. package/dist/client/assets/channel-CvY1mvIl.js +1 -0
  7. package/dist/client/assets/{chunk-2J33WTMH-nkRXvoLd.js → chunk-2J33WTMH-B0h8q8fD.js} +1 -1
  8. package/dist/client/assets/{chunk-4BX2VUAB-BzGqW4v8.js → chunk-4BX2VUAB-km6NpEMz.js} +1 -1
  9. package/dist/client/assets/{chunk-55IACEB6-CKYhsw8v.js → chunk-55IACEB6-COUWt3oA.js} +1 -1
  10. package/dist/client/assets/{chunk-727SXJPM-D6c3bkpP.js → chunk-727SXJPM-Bp-ts2at.js} +1 -1
  11. package/dist/client/assets/{chunk-AQP2D5EJ-Cp_aqtpa.js → chunk-AQP2D5EJ-dyo9i4xa.js} +1 -1
  12. package/dist/client/assets/{chunk-FMBD7UC4-CkbLLRk5.js → chunk-FMBD7UC4-B4C3KvLe.js} +1 -1
  13. package/dist/client/assets/{chunk-ND2GUHAM-BZ894oON.js → chunk-ND2GUHAM-Qhi4WqzZ.js} +1 -1
  14. package/dist/client/assets/{chunk-QZHKN3VN-D4NOzC69.js → chunk-QZHKN3VN-Ce3Q_vrs.js} +1 -1
  15. package/dist/client/assets/classDiagram-4FO5ZUOK-Db7ZXJ6w.js +1 -0
  16. package/dist/client/assets/classDiagram-v2-Q7XG4LA2-Db7ZXJ6w.js +1 -0
  17. package/dist/client/assets/{cose-bilkent-S5V4N54A-CPSnsVY6.js → cose-bilkent-S5V4N54A-D6QofwFq.js} +1 -1
  18. package/dist/client/assets/{dagre-BM42HDAG-CDuVn0gJ.js → dagre-BM42HDAG-CDzpFdgD.js} +1 -1
  19. package/dist/client/assets/{diagram-2AECGRRQ-DkPx69Lt.js → diagram-2AECGRRQ-dl1_7lyq.js} +1 -1
  20. package/dist/client/assets/{diagram-5GNKFQAL-CchGithI.js → diagram-5GNKFQAL-B0ynMwBY.js} +1 -1
  21. package/dist/client/assets/{diagram-KO2AKTUF-DQ50kQAK.js → diagram-KO2AKTUF-B9ABz-Wk.js} +1 -1
  22. package/dist/client/assets/{diagram-LMA3HP47-hKBATxk5.js → diagram-LMA3HP47-DZxXcfiX.js} +1 -1
  23. package/dist/client/assets/{diagram-OG6HWLK6-Bga7_0RO.js → diagram-OG6HWLK6-BncGM9Gv.js} +1 -1
  24. package/dist/client/assets/{erDiagram-TEJ5UH35-D26at0F2.js → erDiagram-TEJ5UH35-B9hxScvO.js} +1 -1
  25. package/dist/client/assets/{flowDiagram-I6XJVG4X-Qf-TRw4O.js → flowDiagram-I6XJVG4X-DgZ2jwJQ.js} +1 -1
  26. package/dist/client/assets/{ganttDiagram-6RSMTGT7-CmRredaI.js → ganttDiagram-6RSMTGT7-BrnNMNRY.js} +1 -1
  27. package/dist/client/assets/{gitGraphDiagram-PVQCEYII-QQP7Sl8F.js → gitGraphDiagram-PVQCEYII-BJmed6oD.js} +1 -1
  28. package/dist/client/assets/index-Btlruz7h.css +1 -0
  29. package/dist/client/assets/{index-Db00yCQO.js → index-DEKuJM5_.js} +179 -177
  30. package/dist/client/assets/{infoDiagram-5YYISTIA-YKWLGpI0.js → infoDiagram-5YYISTIA-CtLzR4ip.js} +1 -1
  31. package/dist/client/assets/{ishikawaDiagram-YF4QCWOH-DrCgRttT.js → ishikawaDiagram-YF4QCWOH-BLrvV5ke.js} +1 -1
  32. package/dist/client/assets/{journeyDiagram-JHISSGLW-CcyKXKKG.js → journeyDiagram-JHISSGLW-B2-TMwJI.js} +1 -1
  33. package/dist/client/assets/{kanban-definition-UN3LZRKU-CsGSN3QV.js → kanban-definition-UN3LZRKU-B5mGKgYF.js} +1 -1
  34. package/dist/client/assets/{linear-DG8wt3yl.js → linear-ConE9euY.js} +1 -1
  35. package/dist/client/assets/{mindmap-definition-RKZ34NQL-CD6E0vLi.js → mindmap-definition-RKZ34NQL-B0BaMk8D.js} +1 -1
  36. package/dist/client/assets/{mobile-baseline-CCXJGaWY.js → mobile-baseline-DWCt7ZGJ.js} +1 -1
  37. package/dist/client/assets/{pieDiagram-4H26LBE5-PIN8tU1a.js → pieDiagram-4H26LBE5-DgPu3GTs.js} +1 -1
  38. package/dist/client/assets/{quadrantDiagram-W4KKPZXB-DV6ne1ch.js → quadrantDiagram-W4KKPZXB-DDbeggF4.js} +1 -1
  39. package/dist/client/assets/{requirementDiagram-4Y6WPE33-Cly9IJv1.js → requirementDiagram-4Y6WPE33-Cc3ozz7U.js} +1 -1
  40. package/dist/client/assets/{sankeyDiagram-5OEKKPKP-D2SFbF9j.js → sankeyDiagram-5OEKKPKP-DmYoq588.js} +1 -1
  41. package/dist/client/assets/{sequenceDiagram-3UESZ5HK-BsxZzGc-.js → sequenceDiagram-3UESZ5HK-EVqdDzgf.js} +1 -1
  42. package/dist/client/assets/{stateDiagram-AJRCARHV-DtZoFzqs.js → stateDiagram-AJRCARHV-BRd6IxSa.js} +1 -1
  43. package/dist/client/assets/stateDiagram-v2-BHNVJYJU-DR2vMoX5.js +1 -0
  44. package/dist/client/assets/{terminal-instance-DFzmxfzG.js → terminal-instance-CDKJdDaO.js} +1 -1
  45. package/dist/client/assets/{timeline-definition-PNZ67QCA-B7ZqNmvc.js → timeline-definition-PNZ67QCA-CyxBqgqv.js} +1 -1
  46. package/dist/client/assets/{vennDiagram-CIIHVFJN-Biz7Z4hM.js → vennDiagram-CIIHVFJN-CLslQYVi.js} +1 -1
  47. package/dist/client/assets/{wardley-L42UT6IY-B-ZjZQUx.js → wardley-L42UT6IY-DyEDLg3x.js} +1 -1
  48. package/dist/client/assets/{wardleyDiagram-YWT4CUSO-C9yV9o-K.js → wardleyDiagram-YWT4CUSO-CjJBpd3P.js} +1 -1
  49. package/dist/client/assets/{xychartDiagram-2RQKCTM6-DuWAbR0h.js → xychartDiagram-2RQKCTM6-DwzoT5Dl.js} +1 -1
  50. package/dist/client/index.html +2 -2
  51. package/dist/client/working.png +0 -0
  52. package/dist/prisma/generated/commonInputTypes.d.ts +30 -0
  53. package/dist/prisma/generated/commonInputTypes.d.ts.map +1 -1
  54. package/dist/prisma/generated/enums.d.ts +5 -0
  55. package/dist/prisma/generated/enums.d.ts.map +1 -1
  56. package/dist/prisma/generated/enums.js +4 -0
  57. package/dist/prisma/generated/enums.js.map +1 -1
  58. package/dist/prisma/generated/internal/class.js +4 -4
  59. package/dist/prisma/generated/internal/class.js.map +1 -1
  60. package/dist/prisma/generated/internal/prismaNamespace.d.ts +5 -0
  61. package/dist/prisma/generated/internal/prismaNamespace.d.ts.map +1 -1
  62. package/dist/prisma/generated/internal/prismaNamespace.js +4 -0
  63. package/dist/prisma/generated/internal/prismaNamespace.js.map +1 -1
  64. package/dist/prisma/generated/internal/prismaNamespaceBrowser.d.ts +4 -0
  65. package/dist/prisma/generated/internal/prismaNamespaceBrowser.d.ts.map +1 -1
  66. package/dist/prisma/generated/internal/prismaNamespaceBrowser.js +4 -0
  67. package/dist/prisma/generated/internal/prismaNamespaceBrowser.js.map +1 -1
  68. package/dist/prisma/generated/models/UserSettings.d.ts +32 -1
  69. package/dist/prisma/generated/models/UserSettings.d.ts.map +1 -1
  70. package/dist/prisma/generated/models/Workspace.d.ts +220 -1
  71. package/dist/prisma/generated/models/Workspace.d.ts.map +1 -1
  72. package/dist/src/backend/app-context.d.ts +90 -25
  73. package/dist/src/backend/app-context.d.ts.map +1 -1
  74. package/dist/src/backend/app-context.js +145 -42
  75. package/dist/src/backend/app-context.js.map +1 -1
  76. package/dist/src/backend/app-context.test.d.ts +2 -0
  77. package/dist/src/backend/app-context.test.d.ts.map +1 -0
  78. package/dist/src/backend/app-context.test.js +51 -0
  79. package/dist/src/backend/app-context.test.js.map +1 -0
  80. package/dist/src/backend/clients/git.client.d.ts.map +1 -1
  81. package/dist/src/backend/clients/git.client.js +5 -0
  82. package/dist/src/backend/clients/git.client.js.map +1 -1
  83. package/dist/src/backend/clients/git.client.test.js +24 -0
  84. package/dist/src/backend/clients/git.client.test.js.map +1 -1
  85. package/dist/src/backend/index.js +5 -5
  86. package/dist/src/backend/index.js.map +1 -1
  87. package/dist/src/backend/interceptors/branch-rename.interceptor.d.ts.map +1 -1
  88. package/dist/src/backend/interceptors/branch-rename.interceptor.js +79 -5
  89. package/dist/src/backend/interceptors/branch-rename.interceptor.js.map +1 -1
  90. package/dist/src/backend/interceptors/branch-rename.interceptor.test.js +120 -16
  91. package/dist/src/backend/interceptors/branch-rename.interceptor.test.js.map +1 -1
  92. package/dist/src/backend/interceptors/pre-pr-rename.interceptor.d.ts.map +1 -1
  93. package/dist/src/backend/interceptors/pre-pr-rename.interceptor.js +3 -0
  94. package/dist/src/backend/interceptors/pre-pr-rename.interceptor.js.map +1 -1
  95. package/dist/src/backend/interceptors/pre-pr-rename.interceptor.test.js +8 -0
  96. package/dist/src/backend/interceptors/pre-pr-rename.interceptor.test.js.map +1 -1
  97. package/dist/src/backend/interceptors/pre-push-rename.interceptor.d.ts.map +1 -1
  98. package/dist/src/backend/interceptors/pre-push-rename.interceptor.js +49 -0
  99. package/dist/src/backend/interceptors/pre-push-rename.interceptor.js.map +1 -1
  100. package/dist/src/backend/interceptors/pre-push-rename.interceptor.test.js +98 -0
  101. package/dist/src/backend/interceptors/pre-push-rename.interceptor.test.js.map +1 -1
  102. package/dist/src/backend/lib/application-error.d.ts +6 -0
  103. package/dist/src/backend/lib/application-error.d.ts.map +1 -0
  104. package/dist/src/backend/lib/application-error.js +9 -0
  105. package/dist/src/backend/lib/application-error.js.map +1 -0
  106. package/dist/src/backend/lib/application-error.test.d.ts +2 -0
  107. package/dist/src/backend/lib/application-error.test.d.ts.map +1 -0
  108. package/dist/src/backend/lib/application-error.test.js +23 -0
  109. package/dist/src/backend/lib/application-error.test.js.map +1 -0
  110. package/dist/src/backend/lib/git-helpers.d.ts +1 -7
  111. package/dist/src/backend/lib/git-helpers.d.ts.map +1 -1
  112. package/dist/src/backend/lib/git-helpers.js +4 -33
  113. package/dist/src/backend/lib/git-helpers.js.map +1 -1
  114. package/dist/src/backend/lib/git-helpers.test.js +17 -10
  115. package/dist/src/backend/lib/git-helpers.test.js.map +1 -1
  116. package/dist/src/backend/lib/process-liveness.d.ts +2 -0
  117. package/dist/src/backend/lib/process-liveness.d.ts.map +1 -0
  118. package/dist/src/backend/lib/process-liveness.js +26 -0
  119. package/dist/src/backend/lib/process-liveness.js.map +1 -0
  120. package/dist/src/backend/lib/process-liveness.test.d.ts +2 -0
  121. package/dist/src/backend/lib/process-liveness.test.d.ts.map +1 -0
  122. package/dist/src/backend/lib/process-liveness.test.js +35 -0
  123. package/dist/src/backend/lib/process-liveness.test.js.map +1 -0
  124. package/dist/src/backend/lib/session-summaries.d.ts +4 -5
  125. package/dist/src/backend/lib/session-summaries.d.ts.map +1 -1
  126. package/dist/src/backend/lib/session-summaries.js.map +1 -1
  127. package/dist/src/backend/lib/workspace-derived-state.d.ts +9 -1
  128. package/dist/src/backend/lib/workspace-derived-state.d.ts.map +1 -1
  129. package/dist/src/backend/lib/workspace-derived-state.js +6 -1
  130. package/dist/src/backend/lib/workspace-derived-state.js.map +1 -1
  131. package/dist/src/backend/lib/workspace-derived-state.test.js +11 -3
  132. package/dist/src/backend/lib/workspace-derived-state.test.js.map +1 -1
  133. package/dist/src/backend/middleware/cors.middleware.js +1 -1
  134. package/dist/src/backend/middleware/cors.middleware.js.map +1 -1
  135. package/dist/src/backend/middleware/index.d.ts +1 -1
  136. package/dist/src/backend/middleware/index.d.ts.map +1 -1
  137. package/dist/src/backend/middleware/index.js +1 -1
  138. package/dist/src/backend/middleware/index.js.map +1 -1
  139. package/dist/src/backend/middleware/middleware.test.js +1 -1
  140. package/dist/src/backend/middleware/middleware.test.js.map +1 -1
  141. package/dist/src/backend/middleware/request-logger.middleware.d.ts +1 -2
  142. package/dist/src/backend/middleware/request-logger.middleware.d.ts.map +1 -1
  143. package/dist/src/backend/middleware/request-logger.middleware.js +0 -2
  144. package/dist/src/backend/middleware/request-logger.middleware.js.map +1 -1
  145. package/dist/src/backend/orchestration/data-backup.service.d.ts.map +1 -1
  146. package/dist/src/backend/orchestration/data-backup.service.js +3 -1
  147. package/dist/src/backend/orchestration/data-backup.service.js.map +1 -1
  148. package/dist/src/backend/orchestration/data-backup.service.test.js +29 -0
  149. package/dist/src/backend/orchestration/data-backup.service.test.js.map +1 -1
  150. package/dist/src/backend/orchestration/domain-bridges.orchestrator.d.ts +24 -12
  151. package/dist/src/backend/orchestration/domain-bridges.orchestrator.d.ts.map +1 -1
  152. package/dist/src/backend/orchestration/domain-bridges.orchestrator.js +53 -63
  153. package/dist/src/backend/orchestration/domain-bridges.orchestrator.js.map +1 -1
  154. package/dist/src/backend/orchestration/domain-bridges.orchestrator.test.js +173 -82
  155. package/dist/src/backend/orchestration/domain-bridges.orchestrator.test.js.map +1 -1
  156. package/dist/src/backend/orchestration/event-coalescer.integration.test.d.ts +2 -0
  157. package/dist/src/backend/orchestration/event-coalescer.integration.test.d.ts.map +1 -0
  158. package/dist/src/backend/orchestration/event-coalescer.integration.test.js +47 -0
  159. package/dist/src/backend/orchestration/event-coalescer.integration.test.js.map +1 -0
  160. package/dist/src/backend/orchestration/event-collector-lifecycle.integration.test.d.ts +2 -0
  161. package/dist/src/backend/orchestration/event-collector-lifecycle.integration.test.d.ts.map +1 -0
  162. package/dist/src/backend/orchestration/event-collector-lifecycle.integration.test.js +34 -0
  163. package/dist/src/backend/orchestration/event-collector-lifecycle.integration.test.js.map +1 -0
  164. package/dist/src/backend/orchestration/event-collector.orchestrator.d.ts +37 -10
  165. package/dist/src/backend/orchestration/event-collector.orchestrator.d.ts.map +1 -1
  166. package/dist/src/backend/orchestration/event-collector.orchestrator.js +297 -121
  167. package/dist/src/backend/orchestration/event-collector.orchestrator.js.map +1 -1
  168. package/dist/src/backend/orchestration/event-collector.orchestrator.test.js +354 -42
  169. package/dist/src/backend/orchestration/event-collector.orchestrator.test.js.map +1 -1
  170. package/dist/src/backend/orchestration/health.service.js +2 -2
  171. package/dist/src/backend/orchestration/health.service.js.map +1 -1
  172. package/dist/src/backend/orchestration/linear-config.helper.js +2 -2
  173. package/dist/src/backend/orchestration/linear-config.helper.js.map +1 -1
  174. package/dist/src/backend/orchestration/reconciliation.service.d.ts +13 -1
  175. package/dist/src/backend/orchestration/reconciliation.service.d.ts.map +1 -1
  176. package/dist/src/backend/orchestration/reconciliation.service.js +16 -29
  177. package/dist/src/backend/orchestration/reconciliation.service.js.map +1 -1
  178. package/dist/src/backend/orchestration/reconciliation.service.test.js +15 -47
  179. package/dist/src/backend/orchestration/reconciliation.service.test.js.map +1 -1
  180. package/dist/src/backend/orchestration/scheduler.service.d.ts +2 -1
  181. package/dist/src/backend/orchestration/scheduler.service.d.ts.map +1 -1
  182. package/dist/src/backend/orchestration/scheduler.service.js +107 -44
  183. package/dist/src/backend/orchestration/scheduler.service.js.map +1 -1
  184. package/dist/src/backend/orchestration/scheduler.service.test.js +266 -59
  185. package/dist/src/backend/orchestration/scheduler.service.test.js.map +1 -1
  186. package/dist/src/backend/orchestration/snapshot-reconciliation.orchestrator.d.ts +18 -11
  187. package/dist/src/backend/orchestration/snapshot-reconciliation.orchestrator.d.ts.map +1 -1
  188. package/dist/src/backend/orchestration/snapshot-reconciliation.orchestrator.js +59 -49
  189. package/dist/src/backend/orchestration/snapshot-reconciliation.orchestrator.js.map +1 -1
  190. package/dist/src/backend/orchestration/snapshot-reconciliation.orchestrator.test.js +156 -24
  191. package/dist/src/backend/orchestration/snapshot-reconciliation.orchestrator.test.js.map +1 -1
  192. package/dist/src/backend/orchestration/types.d.ts +2 -2
  193. package/dist/src/backend/orchestration/types.d.ts.map +1 -1
  194. package/dist/src/backend/orchestration/workspace-archive.orchestrator.d.ts +13 -9
  195. package/dist/src/backend/orchestration/workspace-archive.orchestrator.d.ts.map +1 -1
  196. package/dist/src/backend/orchestration/workspace-archive.orchestrator.js +8 -10
  197. package/dist/src/backend/orchestration/workspace-archive.orchestrator.js.map +1 -1
  198. package/dist/src/backend/orchestration/workspace-archive.orchestrator.test.js +44 -13
  199. package/dist/src/backend/orchestration/workspace-archive.orchestrator.test.js.map +1 -1
  200. package/dist/src/backend/orchestration/workspace-children.orchestrator.d.ts.map +1 -1
  201. package/dist/src/backend/orchestration/workspace-children.orchestrator.js +11 -12
  202. package/dist/src/backend/orchestration/workspace-children.orchestrator.js.map +1 -1
  203. package/dist/src/backend/orchestration/workspace-children.orchestrator.test.js +41 -21
  204. package/dist/src/backend/orchestration/workspace-children.orchestrator.test.js.map +1 -1
  205. package/dist/src/backend/orchestration/workspace-init-issue-prompts.js +3 -3
  206. package/dist/src/backend/orchestration/workspace-init-issue-prompts.js.map +1 -1
  207. package/dist/src/backend/orchestration/workspace-init-script-pipeline.d.ts +1 -1
  208. package/dist/src/backend/orchestration/workspace-init-script-pipeline.d.ts.map +1 -1
  209. package/dist/src/backend/orchestration/workspace-init-script-pipeline.js.map +1 -1
  210. package/dist/src/backend/orchestration/workspace-init.orchestrator.d.ts.map +1 -1
  211. package/dist/src/backend/orchestration/workspace-init.orchestrator.js +34 -20
  212. package/dist/src/backend/orchestration/workspace-init.orchestrator.js.map +1 -1
  213. package/dist/src/backend/orchestration/workspace-init.orchestrator.test.js +278 -102
  214. package/dist/src/backend/orchestration/workspace-init.orchestrator.test.js.map +1 -1
  215. package/dist/src/backend/orchestration/workspace-notification-delivery.orchestrator.d.ts +24 -0
  216. package/dist/src/backend/orchestration/workspace-notification-delivery.orchestrator.d.ts.map +1 -0
  217. package/dist/src/backend/orchestration/workspace-notification-delivery.orchestrator.js +66 -0
  218. package/dist/src/backend/orchestration/workspace-notification-delivery.orchestrator.js.map +1 -0
  219. package/dist/src/backend/orchestration/workspace-notification-delivery.orchestrator.test.d.ts +2 -0
  220. package/dist/src/backend/orchestration/workspace-notification-delivery.orchestrator.test.d.ts.map +1 -0
  221. package/dist/src/backend/orchestration/workspace-notification-delivery.orchestrator.test.js +235 -0
  222. package/dist/src/backend/orchestration/workspace-notification-delivery.orchestrator.test.js.map +1 -0
  223. package/dist/src/backend/routers/health.router.d.ts.map +1 -1
  224. package/dist/src/backend/routers/health.router.js +5 -5
  225. package/dist/src/backend/routers/health.router.js.map +1 -1
  226. package/dist/src/backend/routers/health.router.test.js +3 -5
  227. package/dist/src/backend/routers/health.router.test.js.map +1 -1
  228. package/dist/src/backend/routers/websocket/chat-connection-registry.d.ts +15 -6
  229. package/dist/src/backend/routers/websocket/chat-connection-registry.d.ts.map +1 -1
  230. package/dist/src/backend/routers/websocket/chat-connection-registry.js +80 -33
  231. package/dist/src/backend/routers/websocket/chat-connection-registry.js.map +1 -1
  232. package/dist/src/backend/routers/websocket/chat-connection-registry.test.js +60 -21
  233. package/dist/src/backend/routers/websocket/chat-connection-registry.test.js.map +1 -1
  234. package/dist/src/backend/routers/websocket/chat.handler.d.ts.map +1 -1
  235. package/dist/src/backend/routers/websocket/chat.handler.js +4 -3
  236. package/dist/src/backend/routers/websocket/chat.handler.js.map +1 -1
  237. package/dist/src/backend/routers/websocket/chat.handler.test.js +49 -4
  238. package/dist/src/backend/routers/websocket/chat.handler.test.js.map +1 -1
  239. package/dist/src/backend/routers/websocket/context-injection.test.js +450 -14
  240. package/dist/src/backend/routers/websocket/context-injection.test.js.map +1 -1
  241. package/dist/src/backend/routers/websocket/dev-logs.handler.d.ts.map +1 -1
  242. package/dist/src/backend/routers/websocket/dev-logs.handler.js +16 -3
  243. package/dist/src/backend/routers/websocket/dev-logs.handler.js.map +1 -1
  244. package/dist/src/backend/routers/websocket/index.d.ts +2 -1
  245. package/dist/src/backend/routers/websocket/index.d.ts.map +1 -1
  246. package/dist/src/backend/routers/websocket/index.js +2 -1
  247. package/dist/src/backend/routers/websocket/index.js.map +1 -1
  248. package/dist/src/backend/routers/websocket/post-run-logs.handler.d.ts.map +1 -1
  249. package/dist/src/backend/routers/websocket/post-run-logs.handler.js +6 -3
  250. package/dist/src/backend/routers/websocket/post-run-logs.handler.js.map +1 -1
  251. package/dist/src/backend/routers/websocket/snapshots.handler.d.ts +7 -5
  252. package/dist/src/backend/routers/websocket/snapshots.handler.d.ts.map +1 -1
  253. package/dist/src/backend/routers/websocket/snapshots.handler.js +50 -23
  254. package/dist/src/backend/routers/websocket/snapshots.handler.js.map +1 -1
  255. package/dist/src/backend/routers/websocket/snapshots.handler.test.js +128 -62
  256. package/dist/src/backend/routers/websocket/snapshots.handler.test.js.map +1 -1
  257. package/dist/src/backend/routers/websocket/terminal.handler.d.ts.map +1 -1
  258. package/dist/src/backend/routers/websocket/terminal.handler.js +35 -26
  259. package/dist/src/backend/routers/websocket/terminal.handler.js.map +1 -1
  260. package/dist/src/backend/routers/websocket/terminal.handler.test.js +35 -9
  261. package/dist/src/backend/routers/websocket/terminal.handler.test.js.map +1 -1
  262. package/dist/src/backend/routers/websocket/upgrade-utils.d.ts +4 -4
  263. package/dist/src/backend/routers/websocket/upgrade-utils.d.ts.map +1 -1
  264. package/dist/src/backend/routers/websocket/upgrade-utils.js +1 -1
  265. package/dist/src/backend/routers/websocket/upgrade-utils.js.map +1 -1
  266. package/dist/src/backend/routers/websocket/upgrade-utils.test.js +39 -2
  267. package/dist/src/backend/routers/websocket/upgrade-utils.test.js.map +1 -1
  268. package/dist/src/backend/routers/websocket/websocket.integration.test.js +47 -9
  269. package/dist/src/backend/routers/websocket/websocket.integration.test.js.map +1 -1
  270. package/dist/src/backend/server.d.ts +3 -2
  271. package/dist/src/backend/server.d.ts.map +1 -1
  272. package/dist/src/backend/server.js +37 -37
  273. package/dist/src/backend/server.js.map +1 -1
  274. package/dist/src/backend/server.upgrade.test.js +177 -137
  275. package/dist/src/backend/server.upgrade.test.js.map +1 -1
  276. package/dist/src/backend/services/auto-iteration/service/auto-iteration.service.d.ts +4 -0
  277. package/dist/src/backend/services/auto-iteration/service/auto-iteration.service.d.ts.map +1 -1
  278. package/dist/src/backend/services/auto-iteration/service/auto-iteration.service.js +66 -18
  279. package/dist/src/backend/services/auto-iteration/service/auto-iteration.service.js.map +1 -1
  280. package/dist/src/backend/services/auto-iteration/service/auto-iteration.service.test.js +139 -2
  281. package/dist/src/backend/services/auto-iteration/service/auto-iteration.service.test.js.map +1 -1
  282. package/dist/src/backend/services/auto-iteration/service/bridges.d.ts +1 -0
  283. package/dist/src/backend/services/auto-iteration/service/bridges.d.ts.map +1 -1
  284. package/dist/src/backend/services/auto-iteration/service/git-ops.d.ts.map +1 -1
  285. package/dist/src/backend/services/auto-iteration/service/git-ops.js +32 -11
  286. package/dist/src/backend/services/auto-iteration/service/git-ops.js.map +1 -1
  287. package/dist/src/backend/services/auto-iteration/service/git-ops.test.d.ts +2 -0
  288. package/dist/src/backend/services/auto-iteration/service/git-ops.test.d.ts.map +1 -0
  289. package/dist/src/backend/services/auto-iteration/service/git-ops.test.js +59 -0
  290. package/dist/src/backend/services/auto-iteration/service/git-ops.test.js.map +1 -0
  291. package/dist/src/backend/services/check-service-accessor-boundaries.test.d.ts +2 -0
  292. package/dist/src/backend/services/check-service-accessor-boundaries.test.d.ts.map +1 -0
  293. package/dist/src/backend/services/check-service-accessor-boundaries.test.js +386 -0
  294. package/dist/src/backend/services/check-service-accessor-boundaries.test.js.map +1 -0
  295. package/dist/src/backend/services/check-single-writer.test.js +76 -2
  296. package/dist/src/backend/services/check-single-writer.test.js.map +1 -1
  297. package/dist/src/backend/services/config.service.d.ts +7 -0
  298. package/dist/src/backend/services/config.service.d.ts.map +1 -1
  299. package/dist/src/backend/services/config.service.js +9 -0
  300. package/dist/src/backend/services/config.service.js.map +1 -1
  301. package/dist/src/backend/services/config.service.test.js +41 -0
  302. package/dist/src/backend/services/config.service.test.js.map +1 -1
  303. package/dist/src/backend/services/constants.d.ts +3 -0
  304. package/dist/src/backend/services/constants.d.ts.map +1 -1
  305. package/dist/src/backend/services/constants.js +3 -0
  306. package/dist/src/backend/services/constants.js.map +1 -1
  307. package/dist/src/backend/services/decision-log/index.d.ts +1 -1
  308. package/dist/src/backend/services/decision-log/index.d.ts.map +1 -1
  309. package/dist/src/backend/services/decision-log/index.js +1 -1
  310. package/dist/src/backend/services/decision-log/index.js.map +1 -1
  311. package/dist/src/backend/services/decision-log/service/decision-log-domain-exports.test.d.ts +2 -0
  312. package/dist/src/backend/services/decision-log/service/decision-log-domain-exports.test.d.ts.map +1 -0
  313. package/dist/src/backend/services/decision-log/service/decision-log-domain-exports.test.js +8 -0
  314. package/dist/src/backend/services/decision-log/service/decision-log-domain-exports.test.js.map +1 -0
  315. package/dist/src/backend/{orchestration/decision-log-query.service.d.ts → services/decision-log/service/decision-log.service.d.ts} +4 -4
  316. package/dist/src/backend/services/decision-log/service/decision-log.service.d.ts.map +1 -0
  317. package/dist/src/backend/{orchestration/decision-log-query.service.js → services/decision-log/service/decision-log.service.js} +4 -4
  318. package/dist/src/backend/services/decision-log/service/decision-log.service.js.map +1 -0
  319. package/dist/src/backend/services/decision-log/service/decision-log.service.test.d.ts +2 -0
  320. package/dist/src/backend/services/decision-log/service/decision-log.service.test.d.ts.map +1 -0
  321. package/dist/src/backend/services/decision-log/service/decision-log.service.test.js +45 -0
  322. package/dist/src/backend/services/decision-log/service/decision-log.service.test.js.map +1 -0
  323. package/dist/src/backend/services/decision-log/service/index.d.ts +2 -0
  324. package/dist/src/backend/services/decision-log/service/index.d.ts.map +1 -0
  325. package/dist/src/backend/services/decision-log/service/index.js +2 -0
  326. package/dist/src/backend/services/decision-log/service/index.js.map +1 -0
  327. package/dist/src/backend/services/env-schemas.d.ts +3 -0
  328. package/dist/src/backend/services/env-schemas.d.ts.map +1 -1
  329. package/dist/src/backend/services/env-schemas.js +3 -0
  330. package/dist/src/backend/services/env-schemas.js.map +1 -1
  331. package/dist/src/backend/services/github/service/bridges.d.ts +51 -0
  332. package/dist/src/backend/services/github/service/bridges.d.ts.map +1 -1
  333. package/dist/src/backend/services/github/service/github-cli/schemas.d.ts +30 -6
  334. package/dist/src/backend/services/github/service/github-cli/schemas.d.ts.map +1 -1
  335. package/dist/src/backend/services/github/service/github-cli/schemas.js +18 -0
  336. package/dist/src/backend/services/github/service/github-cli/schemas.js.map +1 -1
  337. package/dist/src/backend/services/github/service/github-cli/types.d.ts +6 -0
  338. package/dist/src/backend/services/github/service/github-cli/types.d.ts.map +1 -1
  339. package/dist/src/backend/services/github/service/github-cli.service.d.ts +3 -6
  340. package/dist/src/backend/services/github/service/github-cli.service.d.ts.map +1 -1
  341. package/dist/src/backend/services/github/service/github-cli.service.js +39 -33
  342. package/dist/src/backend/services/github/service/github-cli.service.js.map +1 -1
  343. package/dist/src/backend/services/github/service/github-cli.service.test.js +63 -67
  344. package/dist/src/backend/services/github/service/github-cli.service.test.js.map +1 -1
  345. package/dist/src/backend/services/github/service/index.d.ts +2 -2
  346. package/dist/src/backend/services/github/service/index.d.ts.map +1 -1
  347. package/dist/src/backend/services/github/service/index.js +1 -1
  348. package/dist/src/backend/services/github/service/index.js.map +1 -1
  349. package/dist/src/backend/services/github/service/pr-fetch-registry.d.ts +13 -6
  350. package/dist/src/backend/services/github/service/pr-fetch-registry.d.ts.map +1 -1
  351. package/dist/src/backend/services/github/service/pr-fetch-registry.js +77 -12
  352. package/dist/src/backend/services/github/service/pr-fetch-registry.js.map +1 -1
  353. package/dist/src/backend/services/github/service/pr-fetch-registry.test.d.ts +2 -0
  354. package/dist/src/backend/services/github/service/pr-fetch-registry.test.d.ts.map +1 -0
  355. package/dist/src/backend/services/github/service/pr-fetch-registry.test.js +112 -0
  356. package/dist/src/backend/services/github/service/pr-fetch-registry.test.js.map +1 -0
  357. package/dist/src/backend/services/github/service/pr-snapshot.service.d.ts +19 -3
  358. package/dist/src/backend/services/github/service/pr-snapshot.service.d.ts.map +1 -1
  359. package/dist/src/backend/services/github/service/pr-snapshot.service.js +115 -16
  360. package/dist/src/backend/services/github/service/pr-snapshot.service.js.map +1 -1
  361. package/dist/src/backend/services/github/service/pr-snapshot.service.test.js +255 -9
  362. package/dist/src/backend/services/github/service/pr-snapshot.service.test.js.map +1 -1
  363. package/dist/src/backend/services/periodic-task/index.d.ts +0 -1
  364. package/dist/src/backend/services/periodic-task/index.d.ts.map +1 -1
  365. package/dist/src/backend/services/periodic-task/index.js +0 -1
  366. package/dist/src/backend/services/periodic-task/index.js.map +1 -1
  367. package/dist/src/backend/services/periodic-task/resources/periodic-task.accessor.d.ts +2 -2
  368. package/dist/src/backend/services/periodic-task/resources/periodic-task.accessor.d.ts.map +1 -1
  369. package/dist/src/backend/services/periodic-task/resources/periodic-task.accessor.js +17 -10
  370. package/dist/src/backend/services/periodic-task/resources/periodic-task.accessor.js.map +1 -1
  371. package/dist/src/backend/services/periodic-task/resources/periodic-task.accessor.test.js +29 -10
  372. package/dist/src/backend/services/periodic-task/resources/periodic-task.accessor.test.js.map +1 -1
  373. package/dist/src/backend/services/periodic-task/service/periodic-task.service.d.ts +103 -0
  374. package/dist/src/backend/services/periodic-task/service/periodic-task.service.d.ts.map +1 -1
  375. package/dist/src/backend/services/periodic-task/service/periodic-task.service.js +47 -1
  376. package/dist/src/backend/services/periodic-task/service/periodic-task.service.js.map +1 -1
  377. package/dist/src/backend/services/periodic-task/service/periodic-task.service.test.js +104 -8
  378. package/dist/src/backend/services/periodic-task/service/periodic-task.service.test.js.map +1 -1
  379. package/dist/src/backend/services/ratchet/service/bridges.d.ts +34 -4
  380. package/dist/src/backend/services/ratchet/service/bridges.d.ts.map +1 -1
  381. package/dist/src/backend/services/ratchet/service/fixer-session.service.d.ts +6 -1
  382. package/dist/src/backend/services/ratchet/service/fixer-session.service.d.ts.map +1 -1
  383. package/dist/src/backend/services/ratchet/service/fixer-session.service.js +47 -8
  384. package/dist/src/backend/services/ratchet/service/fixer-session.service.js.map +1 -1
  385. package/dist/src/backend/services/ratchet/service/fixer-session.service.test.js +131 -29
  386. package/dist/src/backend/services/ratchet/service/fixer-session.service.test.js.map +1 -1
  387. package/dist/src/backend/services/ratchet/service/index.d.ts +3 -3
  388. package/dist/src/backend/services/ratchet/service/index.d.ts.map +1 -1
  389. package/dist/src/backend/services/ratchet/service/index.js +1 -1
  390. package/dist/src/backend/services/ratchet/service/index.js.map +1 -1
  391. package/dist/src/backend/services/ratchet/service/ratchet-active-session.helpers.d.ts +5 -1
  392. package/dist/src/backend/services/ratchet/service/ratchet-active-session.helpers.d.ts.map +1 -1
  393. package/dist/src/backend/services/ratchet/service/ratchet-active-session.helpers.js +9 -6
  394. package/dist/src/backend/services/ratchet/service/ratchet-active-session.helpers.js.map +1 -1
  395. package/dist/src/backend/services/ratchet/service/ratchet-fixer-dispatch.helpers.d.ts +3 -0
  396. package/dist/src/backend/services/ratchet/service/ratchet-fixer-dispatch.helpers.d.ts.map +1 -1
  397. package/dist/src/backend/services/ratchet/service/ratchet-fixer-dispatch.helpers.js +47 -10
  398. package/dist/src/backend/services/ratchet/service/ratchet-fixer-dispatch.helpers.js.map +1 -1
  399. package/dist/src/backend/services/ratchet/service/ratchet-pr-state.helpers.d.ts +8 -3
  400. package/dist/src/backend/services/ratchet/service/ratchet-pr-state.helpers.d.ts.map +1 -1
  401. package/dist/src/backend/services/ratchet/service/ratchet-pr-state.helpers.js +63 -27
  402. package/dist/src/backend/services/ratchet/service/ratchet-pr-state.helpers.js.map +1 -1
  403. package/dist/src/backend/services/ratchet/service/ratchet-pr-state.helpers.test.js +325 -15
  404. package/dist/src/backend/services/ratchet/service/ratchet-pr-state.helpers.test.js.map +1 -1
  405. package/dist/src/backend/services/ratchet/service/ratchet-provider-resolver.service.d.ts.map +1 -1
  406. package/dist/src/backend/services/ratchet/service/ratchet-provider-resolver.service.js +4 -4
  407. package/dist/src/backend/services/ratchet/service/ratchet-provider-resolver.service.js.map +1 -1
  408. package/dist/src/backend/services/ratchet/service/ratchet-provider-resolver.service.test.js +14 -14
  409. package/dist/src/backend/services/ratchet/service/ratchet-provider-resolver.service.test.js.map +1 -1
  410. package/dist/src/backend/services/ratchet/service/ratchet.service.d.ts +8 -1
  411. package/dist/src/backend/services/ratchet/service/ratchet.service.d.ts.map +1 -1
  412. package/dist/src/backend/services/ratchet/service/ratchet.service.js +54 -29
  413. package/dist/src/backend/services/ratchet/service/ratchet.service.js.map +1 -1
  414. package/dist/src/backend/services/ratchet/service/ratchet.service.test.js +577 -194
  415. package/dist/src/backend/services/ratchet/service/ratchet.service.test.js.map +1 -1
  416. package/dist/src/backend/services/ratchet/service/ratchet.types.d.ts +2 -2
  417. package/dist/src/backend/services/ratchet/service/ratchet.types.d.ts.map +1 -1
  418. package/dist/src/backend/services/registry.d.ts +43 -0
  419. package/dist/src/backend/services/registry.d.ts.map +1 -1
  420. package/dist/src/backend/services/registry.js +42 -0
  421. package/dist/src/backend/services/registry.js.map +1 -1
  422. package/dist/src/backend/services/resources.integration.test.js +189 -96
  423. package/dist/src/backend/services/resources.integration.test.js.map +1 -1
  424. package/dist/src/backend/services/run-script/service/bridges.d.ts +4 -0
  425. package/dist/src/backend/services/run-script/service/bridges.d.ts.map +1 -1
  426. package/dist/src/backend/services/{factory-config.service.d.ts → run-script/service/factory-config.service.d.ts} +1 -1
  427. package/dist/src/backend/services/run-script/service/factory-config.service.d.ts.map +1 -0
  428. package/dist/src/backend/services/{factory-config.service.js → run-script/service/factory-config.service.js} +1 -1
  429. package/dist/src/backend/services/run-script/service/factory-config.service.js.map +1 -0
  430. package/dist/src/backend/services/run-script/service/factory-config.service.test.d.ts.map +1 -0
  431. package/dist/src/backend/services/{factory-config.service.test.js → run-script/service/factory-config.service.test.js} +1 -1
  432. package/dist/src/backend/services/run-script/service/factory-config.service.test.js.map +1 -0
  433. package/dist/src/backend/services/run-script/service/index.d.ts +2 -0
  434. package/dist/src/backend/services/run-script/service/index.d.ts.map +1 -1
  435. package/dist/src/backend/services/run-script/service/index.js +2 -0
  436. package/dist/src/backend/services/run-script/service/index.js.map +1 -1
  437. package/dist/src/backend/services/run-script/service/port-allocation.service.d.ts.map +1 -0
  438. package/dist/src/backend/services/run-script/service/port-allocation.service.js.map +1 -0
  439. package/dist/src/backend/services/run-script/service/port-allocation.service.test.d.ts.map +1 -0
  440. package/dist/src/backend/services/run-script/service/port-allocation.service.test.js.map +1 -0
  441. package/dist/src/backend/services/{run-script-config-persistence.service.d.ts → run-script/service/run-script-config-persistence.service.d.ts} +10 -1
  442. package/dist/src/backend/services/run-script/service/run-script-config-persistence.service.d.ts.map +1 -0
  443. package/dist/src/backend/services/{run-script-config-persistence.service.js → run-script/service/run-script-config-persistence.service.js} +46 -2
  444. package/dist/src/backend/services/run-script/service/run-script-config-persistence.service.js.map +1 -0
  445. package/dist/src/backend/services/run-script/service/run-script-config-persistence.service.test.d.ts.map +1 -0
  446. package/dist/src/backend/services/{run-script-config-persistence.service.test.js → run-script/service/run-script-config-persistence.service.test.js} +47 -0
  447. package/dist/src/backend/services/run-script/service/run-script-config-persistence.service.test.js.map +1 -0
  448. package/dist/src/backend/services/run-script/service/run-script-domain-exports.test.js +11 -1
  449. package/dist/src/backend/services/run-script/service/run-script-domain-exports.test.js.map +1 -1
  450. package/dist/src/backend/services/run-script/service/run-script-process-utils.d.ts.map +1 -1
  451. package/dist/src/backend/services/run-script/service/run-script-process-utils.js +1 -1
  452. package/dist/src/backend/services/run-script/service/run-script-process-utils.js.map +1 -1
  453. package/dist/src/backend/services/run-script/service/run-script-proxy.service.d.ts.map +1 -0
  454. package/dist/src/backend/services/{run-script-proxy.service.js → run-script/service/run-script-proxy.service.js} +3 -3
  455. package/dist/src/backend/services/run-script/service/run-script-proxy.service.js.map +1 -0
  456. package/dist/src/backend/services/run-script/service/run-script-proxy.service.test.d.ts.map +1 -0
  457. package/dist/src/backend/services/{run-script-proxy.service.test.js → run-script/service/run-script-proxy.service.test.js} +3 -3
  458. package/dist/src/backend/services/run-script/service/run-script-proxy.service.test.js.map +1 -0
  459. package/dist/src/backend/services/run-script/service/run-script-state-machine.service.d.ts +9 -9
  460. package/dist/src/backend/services/run-script/service/run-script-state-machine.service.d.ts.map +1 -1
  461. package/dist/src/backend/services/run-script/service/run-script-state-machine.service.js +8 -8
  462. package/dist/src/backend/services/run-script/service/run-script-state-machine.service.js.map +1 -1
  463. package/dist/src/backend/services/run-script/service/run-script.service.js +16 -16
  464. package/dist/src/backend/services/run-script/service/run-script.service.js.map +1 -1
  465. package/dist/src/backend/services/run-script/service/run-script.service.test.js +5 -5
  466. package/dist/src/backend/services/run-script/service/run-script.service.test.js.map +1 -1
  467. package/dist/src/backend/services/run-script/service/startup-script.service.d.ts.map +1 -1
  468. package/dist/src/backend/services/run-script/service/startup-script.service.js +4 -7
  469. package/dist/src/backend/services/run-script/service/startup-script.service.js.map +1 -1
  470. package/dist/src/backend/services/run-script/service/startup-script.service.test.js +5 -1
  471. package/dist/src/backend/services/run-script/service/startup-script.service.test.js.map +1 -1
  472. package/dist/src/backend/services/service-registry-check.helpers.d.ts +6 -0
  473. package/dist/src/backend/services/service-registry-check.helpers.d.ts.map +1 -0
  474. package/dist/src/backend/services/service-registry-check.helpers.js +22 -0
  475. package/dist/src/backend/services/service-registry-check.helpers.js.map +1 -0
  476. package/dist/src/backend/services/service-registry-check.test.d.ts +2 -0
  477. package/dist/src/backend/services/service-registry-check.test.d.ts.map +1 -0
  478. package/dist/src/backend/services/service-registry-check.test.js +36 -0
  479. package/dist/src/backend/services/service-registry-check.test.js.map +1 -0
  480. package/dist/src/backend/services/session/index.d.ts +0 -2
  481. package/dist/src/backend/services/session/index.d.ts.map +1 -1
  482. package/dist/src/backend/services/session/index.js +0 -2
  483. package/dist/src/backend/services/session/index.js.map +1 -1
  484. package/dist/src/backend/services/session/resources/agent-session.accessor.d.ts +4 -3
  485. package/dist/src/backend/services/session/resources/agent-session.accessor.d.ts.map +1 -1
  486. package/dist/src/backend/services/session/resources/agent-session.accessor.js +6 -15
  487. package/dist/src/backend/services/session/resources/agent-session.accessor.js.map +1 -1
  488. package/dist/src/backend/services/session/resources/agent-session.accessor.test.js +11 -15
  489. package/dist/src/backend/services/session/resources/agent-session.accessor.test.js.map +1 -1
  490. package/dist/src/backend/services/session/service/acp/acp-runtime-manager.d.ts.map +1 -1
  491. package/dist/src/backend/services/session/service/acp/acp-runtime-manager.js +25 -9
  492. package/dist/src/backend/services/session/service/acp/acp-runtime-manager.js.map +1 -1
  493. package/dist/src/backend/services/session/service/acp/acp-runtime-manager.test.js +109 -26
  494. package/dist/src/backend/services/session/service/acp/acp-runtime-manager.test.js.map +1 -1
  495. package/dist/src/backend/services/session/service/acp/child-workspace-mcp-server.js +2 -2
  496. package/dist/src/backend/services/session/service/acp/child-workspace-mcp-server.js.map +1 -1
  497. package/dist/src/backend/services/session/service/acp/child-workspace-mcp-server.test.d.ts +2 -0
  498. package/dist/src/backend/services/session/service/acp/child-workspace-mcp-server.test.d.ts.map +1 -0
  499. package/dist/src/backend/services/session/service/acp/child-workspace-mcp-server.test.js +119 -0
  500. package/dist/src/backend/services/session/service/acp/child-workspace-mcp-server.test.js.map +1 -0
  501. package/dist/src/backend/services/session/service/bridges.d.ts +1 -0
  502. package/dist/src/backend/services/session/service/bridges.d.ts.map +1 -1
  503. package/dist/src/backend/services/session/service/chat/chat-message-handlers.service.js +3 -3
  504. package/dist/src/backend/services/session/service/chat/chat-message-handlers.service.js.map +1 -1
  505. package/dist/src/backend/services/session/service/chat/chat-message-handlers.service.test.js +16 -16
  506. package/dist/src/backend/services/session/service/chat/chat-message-handlers.service.test.js.map +1 -1
  507. package/dist/src/backend/services/session/service/data/session-data.service.d.ts +18 -166
  508. package/dist/src/backend/services/session/service/data/session-data.service.d.ts.map +1 -1
  509. package/dist/src/backend/services/session/service/data/session-data.service.js +68 -36
  510. package/dist/src/backend/services/session/service/data/session-data.service.js.map +1 -1
  511. package/dist/src/backend/services/session/service/data/session-data.service.test.d.ts +2 -0
  512. package/dist/src/backend/services/session/service/data/session-data.service.test.d.ts.map +1 -0
  513. package/dist/src/backend/services/session/service/data/session-data.service.test.js +103 -0
  514. package/dist/src/backend/services/session/service/data/session-data.service.test.js.map +1 -0
  515. package/dist/src/backend/services/session/service/data/session-provider-resolver.service.d.ts +9 -0
  516. package/dist/src/backend/services/session/service/data/session-provider-resolver.service.d.ts.map +1 -1
  517. package/dist/src/backend/services/session/service/data/session-provider-resolver.service.js +15 -5
  518. package/dist/src/backend/services/session/service/data/session-provider-resolver.service.js.map +1 -1
  519. package/dist/src/backend/services/session/service/data/session-provider-resolver.service.test.js +23 -10
  520. package/dist/src/backend/services/session/service/data/session-provider-resolver.service.test.js.map +1 -1
  521. package/dist/src/backend/services/session/service/index.d.ts +3 -2
  522. package/dist/src/backend/services/session/service/index.d.ts.map +1 -1
  523. package/dist/src/backend/services/session/service/index.js +2 -2
  524. package/dist/src/backend/services/session/service/index.js.map +1 -1
  525. package/dist/src/backend/services/session/service/lifecycle/acp-event-processor.d.ts +15 -4
  526. package/dist/src/backend/services/session/service/lifecycle/acp-event-processor.d.ts.map +1 -1
  527. package/dist/src/backend/services/session/service/lifecycle/acp-event-processor.js +63 -6
  528. package/dist/src/backend/services/session/service/lifecycle/acp-event-processor.js.map +1 -1
  529. package/dist/src/backend/services/session/service/lifecycle/acp-event-processor.text-streaming.test.d.ts +2 -0
  530. package/dist/src/backend/services/session/service/lifecycle/acp-event-processor.text-streaming.test.d.ts.map +1 -0
  531. package/dist/src/backend/services/session/service/lifecycle/acp-event-processor.text-streaming.test.js +230 -0
  532. package/dist/src/backend/services/session/service/lifecycle/acp-event-processor.text-streaming.test.js.map +1 -0
  533. package/dist/src/backend/services/session/service/lifecycle/session-pr-discovery.service.d.ts +2 -1
  534. package/dist/src/backend/services/session/service/lifecycle/session-pr-discovery.service.d.ts.map +1 -1
  535. package/dist/src/backend/services/session/service/lifecycle/session-pr-discovery.service.js +3 -28
  536. package/dist/src/backend/services/session/service/lifecycle/session-pr-discovery.service.js.map +1 -1
  537. package/dist/src/backend/services/session/service/lifecycle/session-pr-discovery.service.test.d.ts +2 -0
  538. package/dist/src/backend/services/session/service/lifecycle/session-pr-discovery.service.test.d.ts.map +1 -0
  539. package/dist/src/backend/services/session/service/lifecycle/session-pr-discovery.service.test.js +33 -0
  540. package/dist/src/backend/services/session/service/lifecycle/session-pr-discovery.service.test.js.map +1 -0
  541. package/dist/src/backend/services/session/service/lifecycle/session.config.service.d.ts.map +1 -1
  542. package/dist/src/backend/services/session/service/lifecycle/session.config.service.js +15 -4
  543. package/dist/src/backend/services/session/service/lifecycle/session.config.service.js.map +1 -1
  544. package/dist/src/backend/services/session/service/lifecycle/session.config.service.test.js +59 -6
  545. package/dist/src/backend/services/session/service/lifecycle/session.config.service.test.js.map +1 -1
  546. package/dist/src/backend/services/session/service/lifecycle/session.lifecycle.service.d.ts.map +1 -1
  547. package/dist/src/backend/services/session/service/lifecycle/session.lifecycle.service.js +14 -7
  548. package/dist/src/backend/services/session/service/lifecycle/session.lifecycle.service.js.map +1 -1
  549. package/dist/src/backend/services/session/service/lifecycle/session.lifecycle.service.test.js +74 -44
  550. package/dist/src/backend/services/session/service/lifecycle/session.lifecycle.service.test.js.map +1 -1
  551. package/dist/src/backend/services/session/service/lifecycle/session.prompt-builder.d.ts +5 -0
  552. package/dist/src/backend/services/session/service/lifecycle/session.prompt-builder.d.ts.map +1 -1
  553. package/dist/src/backend/services/session/service/lifecycle/session.prompt-builder.js +19 -11
  554. package/dist/src/backend/services/session/service/lifecycle/session.prompt-builder.js.map +1 -1
  555. package/dist/src/backend/services/session/service/lifecycle/session.prompt-builder.test.js +32 -1
  556. package/dist/src/backend/services/session/service/lifecycle/session.prompt-builder.test.js.map +1 -1
  557. package/dist/src/backend/services/session/service/lifecycle/session.repository.d.ts +1 -1
  558. package/dist/src/backend/services/session/service/lifecycle/session.repository.d.ts.map +1 -1
  559. package/dist/src/backend/services/session/service/lifecycle/session.repository.js +3 -3
  560. package/dist/src/backend/services/session/service/lifecycle/session.repository.js.map +1 -1
  561. package/dist/src/backend/services/session/service/lifecycle/session.repository.test.js +1 -1
  562. package/dist/src/backend/services/session/service/lifecycle/session.repository.test.js.map +1 -1
  563. package/dist/src/backend/services/session/service/lifecycle/session.service.d.ts.map +1 -1
  564. package/dist/src/backend/services/session/service/lifecycle/session.service.js +2 -0
  565. package/dist/src/backend/services/session/service/lifecycle/session.service.js.map +1 -1
  566. package/dist/src/backend/services/session/service/lifecycle/session.service.test.js +18 -2
  567. package/dist/src/backend/services/session/service/lifecycle/session.service.test.js.map +1 -1
  568. package/dist/src/backend/services/session/service/session-domain.service.d.ts.map +1 -1
  569. package/dist/src/backend/services/session/service/session-domain.service.js +2 -1
  570. package/dist/src/backend/services/session/service/session-domain.service.js.map +1 -1
  571. package/dist/src/backend/services/session/service/store/session-queue.test.js +1 -0
  572. package/dist/src/backend/services/session/service/store/session-queue.test.js.map +1 -1
  573. package/dist/src/backend/services/session/service/store/session-replay-builder.d.ts.map +1 -1
  574. package/dist/src/backend/services/session/service/store/session-replay-builder.js +2 -1
  575. package/dist/src/backend/services/session/service/store/session-replay-builder.js.map +1 -1
  576. package/dist/src/backend/services/session/service/store/session-replay-builder.test.js +13 -0
  577. package/dist/src/backend/services/session/service/store/session-replay-builder.test.js.map +1 -1
  578. package/dist/src/backend/services/session/service/store/session-runtime-machine.test.js +1 -0
  579. package/dist/src/backend/services/session/service/store/session-runtime-machine.test.js.map +1 -1
  580. package/dist/src/backend/services/session/service/store/session-store-registry.d.ts.map +1 -1
  581. package/dist/src/backend/services/session/service/store/session-store-registry.js +1 -0
  582. package/dist/src/backend/services/session/service/store/session-store-registry.js.map +1 -1
  583. package/dist/src/backend/services/session/service/store/session-store.types.d.ts +1 -0
  584. package/dist/src/backend/services/session/service/store/session-store.types.d.ts.map +1 -1
  585. package/dist/src/backend/services/session/service/store/session-transcript.d.ts +1 -0
  586. package/dist/src/backend/services/session/service/store/session-transcript.d.ts.map +1 -1
  587. package/dist/src/backend/services/session/service/store/session-transcript.js +83 -15
  588. package/dist/src/backend/services/session/service/store/session-transcript.js.map +1 -1
  589. package/dist/src/backend/services/session/service/store/session-transcript.test.js +148 -30
  590. package/dist/src/backend/services/session/service/store/session-transcript.test.js.map +1 -1
  591. package/dist/src/backend/services/session/service/store/slash-command-cache.service.d.ts.map +1 -1
  592. package/dist/src/backend/services/session/service/store/slash-command-cache.service.js +23 -18
  593. package/dist/src/backend/services/session/service/store/slash-command-cache.service.js.map +1 -1
  594. package/dist/src/backend/services/session/service/store/slash-command-cache.service.test.js +70 -19
  595. package/dist/src/backend/services/session/service/store/slash-command-cache.service.test.js.map +1 -1
  596. package/dist/src/backend/services/session/types.d.ts +25 -0
  597. package/dist/src/backend/services/session/types.d.ts.map +1 -0
  598. package/dist/src/backend/services/session/types.js +2 -0
  599. package/dist/src/backend/services/session/types.js.map +1 -0
  600. package/dist/src/backend/services/settings/index.d.ts +1 -3
  601. package/dist/src/backend/services/settings/index.d.ts.map +1 -1
  602. package/dist/src/backend/services/settings/index.js +1 -3
  603. package/dist/src/backend/services/settings/index.js.map +1 -1
  604. package/dist/src/backend/services/settings/resources/user-settings.accessor.d.ts +3 -1
  605. package/dist/src/backend/services/settings/resources/user-settings.accessor.d.ts.map +1 -1
  606. package/dist/src/backend/services/settings/resources/user-settings.accessor.js +9 -0
  607. package/dist/src/backend/services/settings/resources/user-settings.accessor.js.map +1 -1
  608. package/dist/src/backend/services/settings/service/health.service.d.ts +6 -0
  609. package/dist/src/backend/services/settings/service/health.service.d.ts.map +1 -0
  610. package/dist/src/backend/services/settings/service/health.service.js +8 -0
  611. package/dist/src/backend/services/settings/service/health.service.js.map +1 -0
  612. package/dist/src/backend/services/settings/service/health.service.test.d.ts +2 -0
  613. package/dist/src/backend/services/settings/service/health.service.test.d.ts.map +1 -0
  614. package/dist/src/backend/services/settings/service/health.service.test.js +16 -0
  615. package/dist/src/backend/services/settings/service/health.service.test.js.map +1 -0
  616. package/dist/src/backend/services/settings/service/index.d.ts +3 -0
  617. package/dist/src/backend/services/settings/service/index.d.ts.map +1 -0
  618. package/dist/src/backend/services/settings/service/index.js +3 -0
  619. package/dist/src/backend/services/settings/service/index.js.map +1 -0
  620. package/dist/src/backend/services/settings/service/settings-domain-exports.test.d.ts +2 -0
  621. package/dist/src/backend/services/settings/service/settings-domain-exports.test.d.ts.map +1 -0
  622. package/dist/src/backend/services/settings/service/settings-domain-exports.test.js +9 -0
  623. package/dist/src/backend/services/settings/service/settings-domain-exports.test.js.map +1 -0
  624. package/dist/src/backend/services/settings/service/user-settings.service.d.ts +27 -0
  625. package/dist/src/backend/services/settings/service/user-settings.service.d.ts.map +1 -0
  626. package/dist/src/backend/services/settings/service/user-settings.service.js +23 -0
  627. package/dist/src/backend/services/settings/service/user-settings.service.js.map +1 -0
  628. package/dist/src/backend/services/settings/service/user-settings.service.test.d.ts +2 -0
  629. package/dist/src/backend/services/settings/service/user-settings.service.test.d.ts.map +1 -0
  630. package/dist/src/backend/services/settings/service/user-settings.service.test.js +58 -0
  631. package/dist/src/backend/services/settings/service/user-settings.service.test.js.map +1 -0
  632. package/dist/src/backend/services/terminal/index.d.ts +0 -1
  633. package/dist/src/backend/services/terminal/index.d.ts.map +1 -1
  634. package/dist/src/backend/services/terminal/index.js +0 -1
  635. package/dist/src/backend/services/terminal/index.js.map +1 -1
  636. package/dist/src/backend/services/terminal/service/index.d.ts +2 -0
  637. package/dist/src/backend/services/terminal/service/index.d.ts.map +1 -1
  638. package/dist/src/backend/services/terminal/service/index.js +1 -0
  639. package/dist/src/backend/services/terminal/service/index.js.map +1 -1
  640. package/dist/src/backend/services/terminal/service/terminal-domain-exports.test.js +4 -1
  641. package/dist/src/backend/services/terminal/service/terminal-domain-exports.test.js.map +1 -1
  642. package/dist/src/backend/services/terminal/service/terminal-session.service.d.ts +95 -0
  643. package/dist/src/backend/services/terminal/service/terminal-session.service.d.ts.map +1 -0
  644. package/dist/src/backend/services/terminal/service/terminal-session.service.js +43 -0
  645. package/dist/src/backend/services/terminal/service/terminal-session.service.js.map +1 -0
  646. package/dist/src/backend/services/terminal/service/terminal-session.service.test.d.ts +2 -0
  647. package/dist/src/backend/services/terminal/service/terminal-session.service.test.d.ts.map +1 -0
  648. package/dist/src/backend/services/terminal/service/terminal-session.service.test.js +46 -0
  649. package/dist/src/backend/services/terminal/service/terminal-session.service.test.js.map +1 -0
  650. package/dist/src/backend/services/workspace/index.d.ts +0 -3
  651. package/dist/src/backend/services/workspace/index.d.ts.map +1 -1
  652. package/dist/src/backend/services/workspace/index.js +0 -3
  653. package/dist/src/backend/services/workspace/index.js.map +1 -1
  654. package/dist/src/backend/services/workspace/resources/project.accessor.d.ts +1 -1
  655. package/dist/src/backend/services/workspace/resources/workspace.accessor.d.ts +66 -2
  656. package/dist/src/backend/services/workspace/resources/workspace.accessor.d.ts.map +1 -1
  657. package/dist/src/backend/services/workspace/resources/workspace.accessor.js +259 -2
  658. package/dist/src/backend/services/workspace/resources/workspace.accessor.js.map +1 -1
  659. package/dist/src/backend/services/workspace/resources/workspace.accessor.test.js +517 -0
  660. package/dist/src/backend/services/workspace/resources/workspace.accessor.test.js.map +1 -1
  661. package/dist/src/backend/services/workspace/service/bridges.d.ts +1 -2
  662. package/dist/src/backend/services/workspace/service/bridges.d.ts.map +1 -1
  663. package/dist/src/backend/services/workspace/service/index.d.ts +12 -1
  664. package/dist/src/backend/services/workspace/service/index.d.ts.map +1 -1
  665. package/dist/src/backend/services/workspace/service/index.js +11 -1
  666. package/dist/src/backend/services/workspace/service/index.js.map +1 -1
  667. package/dist/src/backend/services/workspace/service/lifecycle/creation.service.d.ts +9 -0
  668. package/dist/src/backend/services/workspace/service/lifecycle/creation.service.d.ts.map +1 -1
  669. package/dist/src/backend/services/workspace/service/lifecycle/creation.service.js +26 -36
  670. package/dist/src/backend/services/workspace/service/lifecycle/creation.service.js.map +1 -1
  671. package/dist/src/backend/services/workspace/service/lifecycle/creation.service.test.js +47 -10
  672. package/dist/src/backend/services/workspace/service/lifecycle/creation.service.test.js.map +1 -1
  673. package/dist/src/backend/services/workspace/service/lifecycle/data.service.d.ts +156 -122
  674. package/dist/src/backend/services/workspace/service/lifecycle/data.service.d.ts.map +1 -1
  675. package/dist/src/backend/services/workspace/service/lifecycle/data.service.js +27 -7
  676. package/dist/src/backend/services/workspace/service/lifecycle/data.service.js.map +1 -1
  677. package/dist/src/backend/services/workspace/service/lifecycle/data.service.test.js +14 -1
  678. package/dist/src/backend/services/workspace/service/lifecycle/data.service.test.js.map +1 -1
  679. package/dist/src/backend/services/workspace/service/lifecycle/state-machine.service.d.ts.map +1 -1
  680. package/dist/src/backend/services/workspace/service/lifecycle/state-machine.service.js +8 -1
  681. package/dist/src/backend/services/workspace/service/lifecycle/state-machine.service.js.map +1 -1
  682. package/dist/src/backend/services/workspace/service/lifecycle/state-machine.service.test.js +3 -5
  683. package/dist/src/backend/services/workspace/service/lifecycle/state-machine.service.test.js.map +1 -1
  684. package/dist/src/backend/services/workspace/service/lifecycle/workspace-auto-iteration.service.d.ts +206 -0
  685. package/dist/src/backend/services/workspace/service/lifecycle/workspace-auto-iteration.service.d.ts.map +1 -0
  686. package/dist/src/backend/services/workspace/service/lifecycle/workspace-auto-iteration.service.js +26 -0
  687. package/dist/src/backend/services/workspace/service/lifecycle/workspace-auto-iteration.service.js.map +1 -0
  688. package/dist/src/backend/services/workspace/service/lifecycle/workspace-pr-snapshot.service.d.ts +76 -0
  689. package/dist/src/backend/services/workspace/service/lifecycle/workspace-pr-snapshot.service.d.ts.map +1 -0
  690. package/dist/src/backend/services/workspace/service/lifecycle/workspace-pr-snapshot.service.js +32 -0
  691. package/dist/src/backend/services/workspace/service/lifecycle/workspace-pr-snapshot.service.js.map +1 -0
  692. package/dist/src/backend/services/workspace/service/lifecycle/workspace-pr-snapshot.service.test.d.ts +2 -0
  693. package/dist/src/backend/services/workspace/service/lifecycle/workspace-pr-snapshot.service.test.d.ts.map +1 -0
  694. package/dist/src/backend/services/workspace/service/lifecycle/workspace-pr-snapshot.service.test.js +65 -0
  695. package/dist/src/backend/services/workspace/service/lifecycle/workspace-pr-snapshot.service.test.js.map +1 -0
  696. package/dist/src/backend/services/workspace/service/lifecycle/workspace-ratchet.service.d.ts +243 -0
  697. package/dist/src/backend/services/workspace/service/lifecycle/workspace-ratchet.service.d.ts.map +1 -0
  698. package/dist/src/backend/services/workspace/service/lifecycle/workspace-ratchet.service.js +42 -0
  699. package/dist/src/backend/services/workspace/service/lifecycle/workspace-ratchet.service.js.map +1 -0
  700. package/dist/src/backend/services/workspace/service/lifecycle/workspace-relationships.service.d.ts +186 -0
  701. package/dist/src/backend/services/workspace/service/lifecycle/workspace-relationships.service.d.ts.map +1 -0
  702. package/dist/src/backend/services/workspace/service/lifecycle/workspace-relationships.service.js +11 -0
  703. package/dist/src/backend/services/workspace/service/lifecycle/workspace-relationships.service.js.map +1 -0
  704. package/dist/src/backend/services/workspace/service/lifecycle/workspace-run-script.service.d.ts +161 -0
  705. package/dist/src/backend/services/workspace/service/lifecycle/workspace-run-script.service.d.ts.map +1 -0
  706. package/dist/src/backend/services/workspace/service/lifecycle/workspace-run-script.service.js +51 -0
  707. package/dist/src/backend/services/workspace/service/lifecycle/workspace-run-script.service.js.map +1 -0
  708. package/dist/src/backend/services/workspace/service/lifecycle/workspace-state-capabilities.test.d.ts +2 -0
  709. package/dist/src/backend/services/workspace/service/lifecycle/workspace-state-capabilities.test.d.ts.map +1 -0
  710. package/dist/src/backend/services/workspace/service/lifecycle/workspace-state-capabilities.test.js +96 -0
  711. package/dist/src/backend/services/workspace/service/lifecycle/workspace-state-capabilities.test.js.map +1 -0
  712. package/dist/src/backend/services/workspace/service/pr-discovery-schedule.d.ts +2 -0
  713. package/dist/src/backend/services/workspace/service/pr-discovery-schedule.d.ts.map +1 -0
  714. package/dist/src/backend/services/workspace/service/pr-discovery-schedule.js +11 -0
  715. package/dist/src/backend/services/workspace/service/pr-discovery-schedule.js.map +1 -0
  716. package/dist/src/backend/services/workspace/service/pr-discovery-schedule.test.d.ts +2 -0
  717. package/dist/src/backend/services/workspace/service/pr-discovery-schedule.test.d.ts.map +1 -0
  718. package/dist/src/backend/services/workspace/service/pr-discovery-schedule.test.js +24 -0
  719. package/dist/src/backend/services/workspace/service/pr-discovery-schedule.test.js.map +1 -0
  720. package/dist/src/backend/services/workspace/service/query/project-management.service.d.ts +27 -21
  721. package/dist/src/backend/services/workspace/service/query/project-management.service.d.ts.map +1 -1
  722. package/dist/src/backend/services/workspace/service/query/workspace-maintenance.service.d.ts +446 -0
  723. package/dist/src/backend/services/workspace/service/query/workspace-maintenance.service.d.ts.map +1 -0
  724. package/dist/src/backend/services/workspace/service/query/workspace-maintenance.service.js +23 -0
  725. package/dist/src/backend/services/workspace/service/query/workspace-maintenance.service.js.map +1 -0
  726. package/dist/src/backend/services/workspace/service/query/workspace-maintenance.service.test.d.ts +2 -0
  727. package/dist/src/backend/services/workspace/service/query/workspace-maintenance.service.test.d.ts.map +1 -0
  728. package/dist/src/backend/services/workspace/service/query/workspace-maintenance.service.test.js +36 -0
  729. package/dist/src/backend/services/workspace/service/query/workspace-maintenance.service.test.js.map +1 -0
  730. package/dist/src/backend/services/workspace/service/query/workspace-notification.service.d.ts +58 -0
  731. package/dist/src/backend/services/workspace/service/query/workspace-notification.service.d.ts.map +1 -0
  732. package/dist/src/backend/services/workspace/service/query/workspace-notification.service.js +24 -0
  733. package/dist/src/backend/services/workspace/service/query/workspace-notification.service.js.map +1 -0
  734. package/dist/src/backend/services/workspace/service/query/workspace-notification.service.test.d.ts +2 -0
  735. package/dist/src/backend/services/workspace/service/query/workspace-notification.service.test.d.ts.map +1 -0
  736. package/dist/src/backend/services/workspace/service/query/workspace-notification.service.test.js +28 -0
  737. package/dist/src/backend/services/workspace/service/query/workspace-notification.service.test.js.map +1 -0
  738. package/dist/src/backend/services/workspace/service/query/workspace-query.service.d.ts +45 -55
  739. package/dist/src/backend/services/workspace/service/query/workspace-query.service.d.ts.map +1 -1
  740. package/dist/src/backend/services/workspace/service/query/workspace-query.service.js +13 -64
  741. package/dist/src/backend/services/workspace/service/query/workspace-query.service.js.map +1 -1
  742. package/dist/src/backend/services/workspace/service/query/workspace-query.service.test.js +110 -64
  743. package/dist/src/backend/services/workspace/service/query/workspace-query.service.test.js.map +1 -1
  744. package/dist/src/backend/services/{workspace-snapshot-store.service.d.ts → workspace/service/snapshot/workspace-snapshot-store.service.d.ts} +24 -45
  745. package/dist/src/backend/services/workspace/service/snapshot/workspace-snapshot-store.service.d.ts.map +1 -0
  746. package/dist/src/backend/services/{workspace-snapshot-store.service.js → workspace/service/snapshot/workspace-snapshot-store.service.js} +144 -31
  747. package/dist/src/backend/services/workspace/service/snapshot/workspace-snapshot-store.service.js.map +1 -0
  748. package/dist/src/backend/services/workspace/service/snapshot/workspace-snapshot-store.service.test.d.ts.map +1 -0
  749. package/dist/src/backend/services/{workspace-snapshot-store.service.test.js → workspace/service/snapshot/workspace-snapshot-store.service.test.js} +229 -18
  750. package/dist/src/backend/services/workspace/service/snapshot/workspace-snapshot-store.service.test.js.map +1 -0
  751. package/dist/src/backend/services/workspace/service/state/kanban-state.d.ts +18 -3
  752. package/dist/src/backend/services/workspace/service/state/kanban-state.d.ts.map +1 -1
  753. package/dist/src/backend/services/workspace/service/state/kanban-state.js +136 -16
  754. package/dist/src/backend/services/workspace/service/state/kanban-state.js.map +1 -1
  755. package/dist/src/backend/services/workspace/service/state/kanban-state.test.js +319 -63
  756. package/dist/src/backend/services/workspace/service/state/kanban-state.test.js.map +1 -1
  757. package/dist/src/backend/services/workspace/service/workspace-domain-exports.test.js +18 -1
  758. package/dist/src/backend/services/workspace/service/workspace-domain-exports.test.js.map +1 -1
  759. package/dist/src/backend/services/workspace/service/worktree/git-clone.service.d.ts.map +1 -0
  760. package/dist/src/backend/services/{git-clone.service.js → workspace/service/worktree/git-clone.service.js} +4 -4
  761. package/dist/src/backend/services/workspace/service/worktree/git-clone.service.js.map +1 -0
  762. package/dist/src/backend/services/workspace/service/worktree/git-clone.service.test.d.ts.map +1 -0
  763. package/dist/src/backend/services/{git-clone.service.test.js → workspace/service/worktree/git-clone.service.test.js} +1 -1
  764. package/dist/src/backend/services/workspace/service/worktree/git-clone.service.test.js.map +1 -0
  765. package/dist/src/backend/services/{git-ops.service.d.ts → workspace/service/worktree/git-ops.service.d.ts} +3 -4
  766. package/dist/src/backend/services/workspace/service/worktree/git-ops.service.d.ts.map +1 -0
  767. package/dist/src/backend/services/{git-ops.service.js → workspace/service/worktree/git-ops.service.js} +55 -33
  768. package/dist/src/backend/services/workspace/service/worktree/git-ops.service.js.map +1 -0
  769. package/dist/src/backend/services/workspace/service/worktree/git-ops.service.test.d.ts.map +1 -0
  770. package/dist/src/backend/services/{git-ops.service.test.js → workspace/service/worktree/git-ops.service.test.js} +89 -16
  771. package/dist/src/backend/services/workspace/service/worktree/git-ops.service.test.js.map +1 -0
  772. package/dist/src/backend/services/workspace/service/worktree/worktree-init.test.js +27 -19
  773. package/dist/src/backend/services/workspace/service/worktree/worktree-init.test.js.map +1 -1
  774. package/dist/src/backend/services/workspace/service/worktree/worktree-lifecycle.service.d.ts.map +1 -1
  775. package/dist/src/backend/services/workspace/service/worktree/worktree-lifecycle.service.js +3 -1
  776. package/dist/src/backend/services/workspace/service/worktree/worktree-lifecycle.service.js.map +1 -1
  777. package/dist/src/backend/services/workspace/service/worktree/worktree-lifecycle.service.test.js +66 -2
  778. package/dist/src/backend/services/workspace/service/worktree/worktree-lifecycle.service.test.js.map +1 -1
  779. package/dist/src/backend/services/workspace/types.d.ts +32 -0
  780. package/dist/src/backend/services/workspace/types.d.ts.map +1 -0
  781. package/dist/src/backend/services/workspace/types.js +2 -0
  782. package/dist/src/backend/services/workspace/types.js.map +1 -0
  783. package/dist/src/backend/services/workspace-git-state.service.d.ts +99 -0
  784. package/dist/src/backend/services/workspace-git-state.service.d.ts.map +1 -0
  785. package/dist/src/backend/services/workspace-git-state.service.js +393 -0
  786. package/dist/src/backend/services/workspace-git-state.service.js.map +1 -0
  787. package/dist/src/backend/services/workspace-git-state.service.test.d.ts +2 -0
  788. package/dist/src/backend/services/workspace-git-state.service.test.d.ts.map +1 -0
  789. package/dist/src/backend/services/workspace-git-state.service.test.js +476 -0
  790. package/dist/src/backend/services/workspace-git-state.service.test.js.map +1 -0
  791. package/dist/src/backend/testing/typescript-import-test-utils.d.ts +11 -0
  792. package/dist/src/backend/testing/typescript-import-test-utils.d.ts.map +1 -0
  793. package/dist/src/backend/testing/typescript-import-test-utils.js +47 -0
  794. package/dist/src/backend/testing/typescript-import-test-utils.js.map +1 -0
  795. package/dist/src/backend/trpc/admin.router.test.js +18 -26
  796. package/dist/src/backend/trpc/admin.router.test.js.map +1 -1
  797. package/dist/src/backend/trpc/admin.trpc.d.ts +7 -5
  798. package/dist/src/backend/trpc/admin.trpc.d.ts.map +1 -1
  799. package/dist/src/backend/trpc/admin.trpc.js +11 -15
  800. package/dist/src/backend/trpc/admin.trpc.js.map +1 -1
  801. package/dist/src/backend/trpc/application-error-mapper.d.ts +4 -0
  802. package/dist/src/backend/trpc/application-error-mapper.d.ts.map +1 -0
  803. package/dist/src/backend/trpc/application-error-mapper.js +16 -0
  804. package/dist/src/backend/trpc/application-error-mapper.js.map +1 -0
  805. package/dist/src/backend/trpc/application-error-mapper.test.d.ts +2 -0
  806. package/dist/src/backend/trpc/application-error-mapper.test.d.ts.map +1 -0
  807. package/dist/src/backend/trpc/application-error-mapper.test.js +23 -0
  808. package/dist/src/backend/trpc/application-error-mapper.test.js.map +1 -0
  809. package/dist/src/backend/trpc/auto-iteration.trpc.d.ts +1 -1
  810. package/dist/src/backend/trpc/auto-iteration.trpc.d.ts.map +1 -1
  811. package/dist/src/backend/trpc/auto-iteration.trpc.js +20 -12
  812. package/dist/src/backend/trpc/auto-iteration.trpc.js.map +1 -1
  813. package/dist/src/backend/trpc/auto-iteration.trpc.test.js +10 -9
  814. package/dist/src/backend/trpc/auto-iteration.trpc.test.js.map +1 -1
  815. package/dist/src/backend/trpc/closed-sessions.router.test.js +3 -4
  816. package/dist/src/backend/trpc/closed-sessions.router.test.js.map +1 -1
  817. package/dist/src/backend/trpc/closed-sessions.trpc.d.ts +5 -5
  818. package/dist/src/backend/trpc/closed-sessions.trpc.d.ts.map +1 -1
  819. package/dist/src/backend/trpc/closed-sessions.trpc.js +8 -4
  820. package/dist/src/backend/trpc/closed-sessions.trpc.js.map +1 -1
  821. package/dist/src/backend/trpc/context-dependencies.test.d.ts +2 -0
  822. package/dist/src/backend/trpc/context-dependencies.test.d.ts.map +1 -0
  823. package/dist/src/backend/trpc/context-dependencies.test.js +134 -0
  824. package/dist/src/backend/trpc/context-dependencies.test.js.map +1 -0
  825. package/dist/src/backend/trpc/decision-log.router.test.js +11 -8
  826. package/dist/src/backend/trpc/decision-log.router.test.js.map +1 -1
  827. package/dist/src/backend/trpc/decision-log.trpc.d.ts +3 -3
  828. package/dist/src/backend/trpc/decision-log.trpc.d.ts.map +1 -1
  829. package/dist/src/backend/trpc/decision-log.trpc.js +6 -7
  830. package/dist/src/backend/trpc/decision-log.trpc.js.map +1 -1
  831. package/dist/src/backend/trpc/github.router.test.js +12 -6
  832. package/dist/src/backend/trpc/github.router.test.js.map +1 -1
  833. package/dist/src/backend/trpc/github.trpc.d.ts.map +1 -1
  834. package/dist/src/backend/trpc/github.trpc.js +11 -8
  835. package/dist/src/backend/trpc/github.trpc.js.map +1 -1
  836. package/dist/src/backend/trpc/index.d.ts +528 -828
  837. package/dist/src/backend/trpc/index.d.ts.map +1 -1
  838. package/dist/src/backend/trpc/index.js +0 -1
  839. package/dist/src/backend/trpc/index.js.map +1 -1
  840. package/dist/src/backend/trpc/issue-filter.d.ts.map +1 -1
  841. package/dist/src/backend/trpc/issue-filter.js.map +1 -1
  842. package/dist/src/backend/trpc/linear.router.test.js +21 -21
  843. package/dist/src/backend/trpc/linear.router.test.js.map +1 -1
  844. package/dist/src/backend/trpc/linear.trpc.d.ts +4 -4
  845. package/dist/src/backend/trpc/linear.trpc.d.ts.map +1 -1
  846. package/dist/src/backend/trpc/linear.trpc.js +9 -10
  847. package/dist/src/backend/trpc/linear.trpc.js.map +1 -1
  848. package/dist/src/backend/trpc/periodic-task.trpc.d.ts +17 -17
  849. package/dist/src/backend/trpc/periodic-task.trpc.d.ts.map +1 -1
  850. package/dist/src/backend/trpc/periodic-task.trpc.js +17 -17
  851. package/dist/src/backend/trpc/periodic-task.trpc.js.map +1 -1
  852. package/dist/src/backend/trpc/project.router.test.js +20 -21
  853. package/dist/src/backend/trpc/project.router.test.js.map +1 -1
  854. package/dist/src/backend/trpc/project.trpc.d.ts +31 -25
  855. package/dist/src/backend/trpc/project.trpc.d.ts.map +1 -1
  856. package/dist/src/backend/trpc/project.trpc.js +32 -30
  857. package/dist/src/backend/trpc/project.trpc.js.map +1 -1
  858. package/dist/src/backend/trpc/session.router.test.js +11 -9
  859. package/dist/src/backend/trpc/session.router.test.js.map +1 -1
  860. package/dist/src/backend/trpc/session.trpc.d.ts +47 -404
  861. package/dist/src/backend/trpc/session.trpc.d.ts.map +1 -1
  862. package/dist/src/backend/trpc/session.trpc.js +30 -27
  863. package/dist/src/backend/trpc/session.trpc.js.map +1 -1
  864. package/dist/src/backend/trpc/trpc.d.ts +2 -4
  865. package/dist/src/backend/trpc/trpc.d.ts.map +1 -1
  866. package/dist/src/backend/trpc/trpc.js +14 -12
  867. package/dist/src/backend/trpc/trpc.js.map +1 -1
  868. package/dist/src/backend/trpc/trpc.test.js +58 -1
  869. package/dist/src/backend/trpc/trpc.test.js.map +1 -1
  870. package/dist/src/backend/trpc/user-settings.router.test.js +27 -14
  871. package/dist/src/backend/trpc/user-settings.router.test.js.map +1 -1
  872. package/dist/src/backend/trpc/user-settings.trpc.d.ts +6 -3
  873. package/dist/src/backend/trpc/user-settings.trpc.d.ts.map +1 -1
  874. package/dist/src/backend/trpc/user-settings.trpc.js +13 -14
  875. package/dist/src/backend/trpc/user-settings.trpc.js.map +1 -1
  876. package/dist/src/backend/trpc/workspace/children.router.test.d.ts +2 -0
  877. package/dist/src/backend/trpc/workspace/children.router.test.d.ts.map +1 -0
  878. package/dist/src/backend/trpc/workspace/children.router.test.js +257 -0
  879. package/dist/src/backend/trpc/workspace/children.router.test.js.map +1 -0
  880. package/dist/src/backend/trpc/workspace/children.trpc.d.ts +154 -0
  881. package/dist/src/backend/trpc/workspace/children.trpc.d.ts.map +1 -0
  882. package/dist/src/backend/trpc/workspace/children.trpc.js +163 -0
  883. package/dist/src/backend/trpc/workspace/children.trpc.js.map +1 -0
  884. package/dist/src/backend/trpc/workspace/composition.test.d.ts +2 -0
  885. package/dist/src/backend/trpc/workspace/composition.test.d.ts.map +1 -0
  886. package/dist/src/backend/trpc/workspace/composition.test.js +51 -0
  887. package/dist/src/backend/trpc/workspace/composition.test.js.map +1 -0
  888. package/dist/src/backend/trpc/workspace/files.router.test.js +6 -0
  889. package/dist/src/backend/trpc/workspace/files.router.test.js.map +1 -1
  890. package/dist/src/backend/trpc/workspace/files.trpc.d.ts.map +1 -1
  891. package/dist/src/backend/trpc/workspace/files.trpc.js +14 -13
  892. package/dist/src/backend/trpc/workspace/files.trpc.js.map +1 -1
  893. package/dist/src/backend/trpc/workspace/git.router.test.js +137 -147
  894. package/dist/src/backend/trpc/workspace/git.router.test.js.map +1 -1
  895. package/dist/src/backend/trpc/workspace/git.trpc.d.ts +2 -2
  896. package/dist/src/backend/trpc/workspace/git.trpc.d.ts.map +1 -1
  897. package/dist/src/backend/trpc/workspace/git.trpc.js +53 -75
  898. package/dist/src/backend/trpc/workspace/git.trpc.js.map +1 -1
  899. package/dist/src/backend/trpc/workspace/ide.router.test.js +10 -9
  900. package/dist/src/backend/trpc/workspace/ide.router.test.js.map +1 -1
  901. package/dist/src/backend/trpc/workspace/ide.trpc.d.ts.map +1 -1
  902. package/dist/src/backend/trpc/workspace/ide.trpc.js +4 -4
  903. package/dist/src/backend/trpc/workspace/ide.trpc.js.map +1 -1
  904. package/dist/src/backend/trpc/workspace/init.router.test.js +18 -41
  905. package/dist/src/backend/trpc/workspace/init.router.test.js.map +1 -1
  906. package/dist/src/backend/trpc/workspace/init.trpc.d.ts +22 -18
  907. package/dist/src/backend/trpc/workspace/init.trpc.d.ts.map +1 -1
  908. package/dist/src/backend/trpc/workspace/init.trpc.js +14 -11
  909. package/dist/src/backend/trpc/workspace/init.trpc.js.map +1 -1
  910. package/dist/src/backend/trpc/workspace/run-script.router.test.js +6 -10
  911. package/dist/src/backend/trpc/workspace/run-script.router.test.js.map +1 -1
  912. package/dist/src/backend/trpc/workspace/run-script.trpc.d.ts.map +1 -1
  913. package/dist/src/backend/trpc/workspace/run-script.trpc.js +3 -4
  914. package/dist/src/backend/trpc/workspace/run-script.trpc.js.map +1 -1
  915. package/dist/src/backend/trpc/workspace/workspace-helpers.d.ts +43 -35
  916. package/dist/src/backend/trpc/workspace/workspace-helpers.d.ts.map +1 -1
  917. package/dist/src/backend/trpc/workspace/workspace-helpers.js +7 -8
  918. package/dist/src/backend/trpc/workspace/workspace-helpers.js.map +1 -1
  919. package/dist/src/backend/trpc/workspace/workspace-helpers.test.js +17 -15
  920. package/dist/src/backend/trpc/workspace/workspace-helpers.test.js.map +1 -1
  921. package/dist/src/backend/trpc/workspace.router.test.js +139 -265
  922. package/dist/src/backend/trpc/workspace.router.test.js.map +1 -1
  923. package/dist/src/backend/trpc/workspace.trpc.d.ts +1491 -325
  924. package/dist/src/backend/trpc/workspace.trpc.d.ts.map +1 -1
  925. package/dist/src/backend/trpc/workspace.trpc.js +47 -258
  926. package/dist/src/backend/trpc/workspace.trpc.js.map +1 -1
  927. package/dist/src/shared/acp-protocol/protocol/renderer-window.d.ts.map +1 -1
  928. package/dist/src/shared/acp-protocol/protocol/renderer-window.js +2 -1
  929. package/dist/src/shared/acp-protocol/protocol/renderer-window.js.map +1 -1
  930. package/dist/src/shared/acp-protocol/protocol/websocket.d.ts +9 -0
  931. package/dist/src/shared/acp-protocol/protocol/websocket.d.ts.map +1 -1
  932. package/dist/src/shared/acp-protocol/protocol/websocket.js +1 -0
  933. package/dist/src/shared/acp-protocol/protocol/websocket.js.map +1 -1
  934. package/dist/src/shared/core/enums.d.ts +5 -0
  935. package/dist/src/shared/core/enums.d.ts.map +1 -1
  936. package/dist/src/shared/core/enums.js +4 -0
  937. package/dist/src/shared/core/enums.js.map +1 -1
  938. package/dist/src/shared/core/index.d.ts +2 -2
  939. package/dist/src/shared/core/index.d.ts.map +1 -1
  940. package/dist/src/shared/core/index.js +2 -2
  941. package/dist/src/shared/core/index.js.map +1 -1
  942. package/dist/src/shared/core/workspace-sidebar-status.d.ts +4 -2
  943. package/dist/src/shared/core/workspace-sidebar-status.d.ts.map +1 -1
  944. package/dist/src/shared/core/workspace-sidebar-status.js +11 -0
  945. package/dist/src/shared/core/workspace-sidebar-status.js.map +1 -1
  946. package/dist/src/shared/schemas/export-data.schema.d.ts +20 -12
  947. package/dist/src/shared/schemas/export-data.schema.d.ts.map +1 -1
  948. package/dist/src/shared/schemas/export-data.schema.js +3 -1
  949. package/dist/src/shared/schemas/export-data.schema.js.map +1 -1
  950. package/dist/src/shared/session-runtime.d.ts +6 -3
  951. package/dist/src/shared/session-runtime.d.ts.map +1 -1
  952. package/dist/src/shared/session-runtime.js +10 -0
  953. package/dist/src/shared/session-runtime.js.map +1 -1
  954. package/dist/src/shared/workspace-flow-state.d.ts +4 -2
  955. package/dist/src/shared/workspace-flow-state.d.ts.map +1 -1
  956. package/dist/src/shared/workspace-flow-state.js +16 -1
  957. package/dist/src/shared/workspace-flow-state.js.map +1 -1
  958. package/dist/src/shared/workspace-snapshot.d.ts +1020 -0
  959. package/dist/src/shared/workspace-snapshot.d.ts.map +1 -0
  960. package/dist/src/shared/workspace-snapshot.js +113 -0
  961. package/dist/src/shared/workspace-snapshot.js.map +1 -0
  962. package/dist/src/shared/workspace-status-reason.d.ts +6 -3
  963. package/dist/src/shared/workspace-status-reason.d.ts.map +1 -1
  964. package/dist/src/shared/workspace-status-reason.js +35 -0
  965. package/dist/src/shared/workspace-status-reason.js.map +1 -1
  966. package/dist/src/test-utils/application-graph.d.ts +69 -0
  967. package/dist/src/test-utils/application-graph.d.ts.map +1 -0
  968. package/dist/src/test-utils/application-graph.js +353 -0
  969. package/dist/src/test-utils/application-graph.js.map +1 -0
  970. package/dist/tsconfig.backend.tsbuildinfo +1 -1
  971. package/package.json +2 -5
  972. package/prisma/migrations/20260717150000_add_pr_discovery_schedule/migration.sql +8 -0
  973. package/prisma/migrations/20260717160000_add_ratchet_review_trigger_mode/migration.sql +2 -0
  974. package/prisma/schema.prisma +13 -1
  975. package/dist/client/assets/channel-76ipWABm.js +0 -1
  976. package/dist/client/assets/classDiagram-4FO5ZUOK-FuxnCTTL.js +0 -1
  977. package/dist/client/assets/classDiagram-v2-Q7XG4LA2-FuxnCTTL.js +0 -1
  978. package/dist/client/assets/index-kItkrW7R.css +0 -1
  979. package/dist/client/assets/stateDiagram-v2-BHNVJYJU-Dhf9Ohaz.js +0 -1
  980. package/dist/src/backend/clients/index.d.ts +0 -2
  981. package/dist/src/backend/clients/index.d.ts.map +0 -1
  982. package/dist/src/backend/clients/index.js +0 -2
  983. package/dist/src/backend/clients/index.js.map +0 -1
  984. package/dist/src/backend/orchestration/decision-log-query.service.d.ts.map +0 -1
  985. package/dist/src/backend/orchestration/decision-log-query.service.js.map +0 -1
  986. package/dist/src/backend/orchestration/decision-log-query.service.test.d.ts +0 -2
  987. package/dist/src/backend/orchestration/decision-log-query.service.test.d.ts.map +0 -1
  988. package/dist/src/backend/orchestration/decision-log-query.service.test.js +0 -44
  989. package/dist/src/backend/orchestration/decision-log-query.service.test.js.map +0 -1
  990. package/dist/src/backend/services/factory-config.service.d.ts.map +0 -1
  991. package/dist/src/backend/services/factory-config.service.js.map +0 -1
  992. package/dist/src/backend/services/factory-config.service.test.d.ts.map +0 -1
  993. package/dist/src/backend/services/factory-config.service.test.js.map +0 -1
  994. package/dist/src/backend/services/git-clone.service.d.ts.map +0 -1
  995. package/dist/src/backend/services/git-clone.service.js.map +0 -1
  996. package/dist/src/backend/services/git-clone.service.test.d.ts.map +0 -1
  997. package/dist/src/backend/services/git-clone.service.test.js.map +0 -1
  998. package/dist/src/backend/services/git-ops.service.d.ts.map +0 -1
  999. package/dist/src/backend/services/git-ops.service.js.map +0 -1
  1000. package/dist/src/backend/services/git-ops.service.test.d.ts.map +0 -1
  1001. package/dist/src/backend/services/git-ops.service.test.js.map +0 -1
  1002. package/dist/src/backend/services/port-allocation.service.d.ts.map +0 -1
  1003. package/dist/src/backend/services/port-allocation.service.js.map +0 -1
  1004. package/dist/src/backend/services/port-allocation.service.test.d.ts.map +0 -1
  1005. package/dist/src/backend/services/port-allocation.service.test.js.map +0 -1
  1006. package/dist/src/backend/services/run-script-config-persistence.service.d.ts.map +0 -1
  1007. package/dist/src/backend/services/run-script-config-persistence.service.js.map +0 -1
  1008. package/dist/src/backend/services/run-script-config-persistence.service.test.d.ts.map +0 -1
  1009. package/dist/src/backend/services/run-script-config-persistence.service.test.js.map +0 -1
  1010. package/dist/src/backend/services/run-script-proxy.service.d.ts.map +0 -1
  1011. package/dist/src/backend/services/run-script-proxy.service.js.map +0 -1
  1012. package/dist/src/backend/services/run-script-proxy.service.test.d.ts.map +0 -1
  1013. package/dist/src/backend/services/run-script-proxy.service.test.js.map +0 -1
  1014. package/dist/src/backend/services/workspace/service/query/user-settings-query.service.d.ts +0 -24
  1015. package/dist/src/backend/services/workspace/service/query/user-settings-query.service.d.ts.map +0 -1
  1016. package/dist/src/backend/services/workspace/service/query/user-settings-query.service.js +0 -17
  1017. package/dist/src/backend/services/workspace/service/query/user-settings-query.service.js.map +0 -1
  1018. package/dist/src/backend/services/workspace-snapshot-store.service.d.ts.map +0 -1
  1019. package/dist/src/backend/services/workspace-snapshot-store.service.js.map +0 -1
  1020. package/dist/src/backend/services/workspace-snapshot-store.service.test.d.ts.map +0 -1
  1021. package/dist/src/backend/services/workspace-snapshot-store.service.test.js.map +0 -1
  1022. package/dist/src/backend/trpc/procedures/index.d.ts +0 -2
  1023. package/dist/src/backend/trpc/procedures/index.d.ts.map +0 -1
  1024. package/dist/src/backend/trpc/procedures/index.js +0 -2
  1025. package/dist/src/backend/trpc/procedures/index.js.map +0 -1
  1026. package/dist/src/backend/trpc/procedures/project-scoped.d.ts +0 -7
  1027. package/dist/src/backend/trpc/procedures/project-scoped.d.ts.map +0 -1
  1028. package/dist/src/backend/trpc/procedures/project-scoped.js +0 -18
  1029. package/dist/src/backend/trpc/procedures/project-scoped.js.map +0 -1
  1030. package/dist/src/backend/trpc/procedures/project-scoped.test.d.ts +0 -2
  1031. package/dist/src/backend/trpc/procedures/project-scoped.test.d.ts.map +0 -1
  1032. package/dist/src/backend/trpc/procedures/project-scoped.test.js +0 -17
  1033. package/dist/src/backend/trpc/procedures/project-scoped.test.js.map +0 -1
  1034. /package/dist/src/backend/services/{factory-config.service.test.d.ts → run-script/service/factory-config.service.test.d.ts} +0 -0
  1035. /package/dist/src/backend/services/{port-allocation.service.d.ts → run-script/service/port-allocation.service.d.ts} +0 -0
  1036. /package/dist/src/backend/services/{port-allocation.service.js → run-script/service/port-allocation.service.js} +0 -0
  1037. /package/dist/src/backend/services/{port-allocation.service.test.d.ts → run-script/service/port-allocation.service.test.d.ts} +0 -0
  1038. /package/dist/src/backend/services/{port-allocation.service.test.js → run-script/service/port-allocation.service.test.js} +0 -0
  1039. /package/dist/src/backend/services/{run-script-config-persistence.service.test.d.ts → run-script/service/run-script-config-persistence.service.test.d.ts} +0 -0
  1040. /package/dist/src/backend/services/{run-script-proxy.service.d.ts → run-script/service/run-script-proxy.service.d.ts} +0 -0
  1041. /package/dist/src/backend/services/{run-script-proxy.service.test.d.ts → run-script/service/run-script-proxy.service.test.d.ts} +0 -0
  1042. /package/dist/src/backend/services/{workspace-snapshot-store.service.test.d.ts → workspace/service/snapshot/workspace-snapshot-store.service.test.d.ts} +0 -0
  1043. /package/dist/src/backend/services/{git-clone.service.d.ts → workspace/service/worktree/git-clone.service.d.ts} +0 -0
  1044. /package/dist/src/backend/services/{git-clone.service.test.d.ts → workspace/service/worktree/git-clone.service.test.d.ts} +0 -0
  1045. /package/dist/src/backend/services/{git-ops.service.test.d.ts → workspace/service/worktree/git-ops.service.test.d.ts} +0 -0
@@ -3,26 +3,30 @@ import { SERVICE_TIMEOUT_MS } from '../../../../backend/services/constants.js';
3
3
  import { CIStatus, RatchetState, SessionStatus } from '../../../../shared/core/index.js';
4
4
  import { unsafeCoerce } from '../../../../test-utils/unsafe-coerce.js';
5
5
  vi.mock('@/backend/services/workspace', () => ({
6
- workspaceAccessor: {
6
+ workspaceDataService: {
7
7
  findById: vi.fn(),
8
- findWithPRsForRatchet: vi.fn(),
9
- findForRatchetById: vi.fn(),
10
- update: vi.fn(),
11
- transitionRatchetStateIfEnabled: vi.fn(),
12
- settleRatchetIdleWhileDisabled: vi.fn(),
13
- recordRatchetDispatchIfEnabled: vi.fn(),
14
- adoptRatchetActiveSessionIfEnabled: vi.fn(),
15
- recordRatchetSessionEnd: vi.fn(),
8
+ },
9
+ workspaceRatchetService: {
10
+ findCandidates: vi.fn(),
11
+ findCandidateById: vi.fn(),
12
+ clearActiveSession: vi.fn(),
13
+ enable: vi.fn(),
14
+ disable: vi.fn(),
15
+ transitionStateIfEnabled: vi.fn(),
16
+ settleIdleWhileDisabled: vi.fn(),
17
+ recordDispatchIfEnabled: vi.fn(),
18
+ adoptActiveSessionIfEnabled: vi.fn(),
19
+ recordSessionEnd: vi.fn(),
16
20
  },
17
21
  }));
18
22
  vi.mock('@/backend/services/session', () => ({
19
- agentSessionAccessor: {
20
- findById: vi.fn(),
21
- findByWorkspaceId: vi.fn(),
23
+ sessionDataService: {
24
+ findAgentSessionById: vi.fn(),
25
+ findAgentSessionsByWorkspaceId: vi.fn(),
22
26
  },
23
27
  }));
24
28
  vi.mock('@/backend/services/settings', () => ({
25
- userSettingsAccessor: {
29
+ userSettingsService: {
26
30
  get: vi.fn(),
27
31
  getDefaultSessionProvider: vi.fn(),
28
32
  },
@@ -40,15 +44,16 @@ vi.mock('@/backend/services/logger.service', () => ({
40
44
  error: vi.fn(),
41
45
  }),
42
46
  }));
43
- import { agentSessionAccessor } from '../../../../backend/services/session/index.js';
44
- import { userSettingsAccessor } from '../../../../backend/services/settings/index.js';
45
- import { workspaceAccessor } from '../../../../backend/services/workspace/index.js';
47
+ import { userSettingsService } from '../../../../backend/services/settings/index.js';
48
+ import { workspaceDataService, workspaceRatchetService } from '../../../../backend/services/workspace/index.js';
46
49
  import { fixerSessionService } from './fixer-session.service.js';
47
- import { RATCHET_STATE_CHANGED, RATCHET_TOGGLED, ratchetService, } from './ratchet.service.js';
50
+ import { RATCHET_DISPATCH_CHANGED, RATCHET_STATE_CHANGED, RATCHET_TOGGLED, ratchetService, } from './ratchet.service.js';
48
51
  import { buildRatchetingLogContext } from './ratchet-decision-logging.helpers.js';
49
52
  import { computeDispatchSnapshotKey, computeLatestReviewActivityAtMs, determineRatchetState, } from './ratchet-pr-state.helpers.js';
50
53
  const mockSessionBridge = {
54
+ findSessionById: vi.fn(),
51
55
  findSessionsByWorkspaceId: vi.fn(),
56
+ acquireFixerSession: vi.fn(),
52
57
  isSessionRunning: vi.fn(),
53
58
  isSessionWorking: vi.fn(),
54
59
  stopSession: vi.fn(),
@@ -57,6 +62,10 @@ const mockSessionBridge = {
57
62
  sendSessionMessage: vi.fn(),
58
63
  injectCommittedUserMessage: vi.fn(),
59
64
  };
65
+ const mockWorkspaceBridge = {
66
+ findFixerContext: vi.fn(),
67
+ recordSessionEnd: vi.fn(),
68
+ };
60
69
  const mockGitHubBridge = {
61
70
  extractPRInfo: vi.fn(),
62
71
  getPRFullDetails: vi.fn(),
@@ -67,7 +76,7 @@ const mockGitHubBridge = {
67
76
  fetchAndComputePRState: vi.fn(),
68
77
  isRecentlyFetched: vi.fn(),
69
78
  isFetchInFlight: vi.fn(),
70
- startFetch: vi.fn(),
79
+ startFetch: vi.fn(() => 41),
71
80
  registerFetch: vi.fn(),
72
81
  cancelFetch: vi.fn(),
73
82
  };
@@ -86,18 +95,20 @@ describe('ratchet service (state-change + idle dispatch)', () => {
86
95
  session: mockSessionBridge,
87
96
  github: mockGitHubBridge,
88
97
  snapshot: mockSnapshotBridge,
89
- });
90
- vi.mocked(workspaceAccessor.transitionRatchetStateIfEnabled).mockResolvedValue(true);
91
- vi.mocked(workspaceAccessor.settleRatchetIdleWhileDisabled).mockResolvedValue(true);
92
- vi.mocked(workspaceAccessor.recordRatchetDispatchIfEnabled).mockResolvedValue(true);
93
- vi.mocked(workspaceAccessor.adoptRatchetActiveSessionIfEnabled).mockResolvedValue(true);
94
- vi.mocked(workspaceAccessor.recordRatchetSessionEnd).mockResolvedValue(true);
95
- vi.mocked(agentSessionAccessor.findByWorkspaceId).mockResolvedValue([]);
98
+ workspace: mockWorkspaceBridge,
99
+ });
100
+ vi.mocked(workspaceRatchetService.transitionStateIfEnabled).mockResolvedValue(true);
101
+ vi.mocked(workspaceRatchetService.settleIdleWhileDisabled).mockResolvedValue(true);
102
+ vi.mocked(workspaceRatchetService.recordDispatchIfEnabled).mockResolvedValue(true);
103
+ vi.mocked(workspaceRatchetService.adoptActiveSessionIfEnabled).mockResolvedValue(true);
104
+ vi.mocked(workspaceRatchetService.recordSessionEnd).mockResolvedValue(true);
105
+ vi.mocked(mockWorkspaceBridge.recordSessionEnd).mockResolvedValue(true);
106
+ vi.mocked(mockSessionBridge.findSessionsByWorkspaceId).mockResolvedValue([]);
96
107
  vi.mocked(mockSessionBridge.findSessionsByWorkspaceId).mockResolvedValue([]);
97
108
  vi.mocked(mockGitHubBridge.getAuthenticatedUsername).mockResolvedValue(null);
98
109
  vi.mocked(mockGitHubBridge.getResolvedReviewCommentIds).mockResolvedValue(new Set());
99
110
  vi.mocked(mockSessionBridge.isSessionWorking).mockReturnValue(false);
100
- vi.mocked(userSettingsAccessor.get).mockResolvedValue({
111
+ vi.mocked(userSettingsService.get).mockResolvedValue({
101
112
  id: 'settings-1',
102
113
  userId: 'default',
103
114
  preferredIde: 'cursor',
@@ -108,6 +119,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
108
119
  cachedSlashCommands: null,
109
120
  ratchetEnabled: false,
110
121
  ratchetReplyToPrComments: true,
122
+ ratchetReviewTriggerMode: 'CHANGES_REQUESTED',
111
123
  defaultSessionProvider: 'CLAUDE',
112
124
  defaultClaudeModel: 'sonnet',
113
125
  defaultCodexModel: 'default',
@@ -118,13 +130,18 @@ describe('ratchet service (state-change + idle dispatch)', () => {
118
130
  createdAt: new Date('2026-01-01T00:00:00.000Z'),
119
131
  updatedAt: new Date('2026-01-01T00:00:00.000Z'),
120
132
  });
121
- vi.mocked(userSettingsAccessor.getDefaultSessionProvider).mockResolvedValue('CLAUDE');
133
+ vi.mocked(userSettingsService.getDefaultSessionProvider).mockResolvedValue('CLAUDE');
134
+ });
135
+ it('records session completion through the configured workspace bridge', async () => {
136
+ await ratchetService.recordSessionEnd('workspace-1', 'session-1', 'COMPLETED');
137
+ expect(mockWorkspaceBridge.recordSessionEnd).toHaveBeenCalledWith('workspace-1', 'session-1', 'COMPLETED');
138
+ expect(workspaceRatchetService.recordSessionEnd).not.toHaveBeenCalled();
122
139
  });
123
140
  afterEach(() => {
124
141
  ratchetService.removeAllListeners();
125
142
  });
126
143
  it('checks workspaces and processes each', async () => {
127
- vi.mocked(workspaceAccessor.findWithPRsForRatchet).mockResolvedValue([
144
+ vi.mocked(workspaceRatchetService.findCandidates).mockResolvedValue([
128
145
  {
129
146
  id: 'ws-1',
130
147
  prUrl: 'https://github.com/example/repo/pull/1',
@@ -167,7 +184,6 @@ describe('ratchet service (state-change + idle dispatch)', () => {
167
184
  ratchetDispatchRetryCount: 0,
168
185
  };
169
186
  const fetchPRStateSpy = vi.spyOn(unsafeCoerce(ratchetService), 'fetchPRState');
170
- vi.mocked(workspaceAccessor.update).mockResolvedValue({});
171
187
  const triggerSpy = vi.spyOn(unsafeCoerce(ratchetService), 'triggerFixer');
172
188
  const result = await unsafeCoerce(ratchetService).processWorkspace(workspace);
173
189
  expect(fetchPRStateSpy).not.toHaveBeenCalled();
@@ -176,7 +192,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
176
192
  action: { type: 'DISABLED', reason: 'Workspace ratcheting disabled' },
177
193
  newState: RatchetState.IDLE,
178
194
  });
179
- expect(workspaceAccessor.settleRatchetIdleWhileDisabled).toHaveBeenCalledWith('ws-disabled', RatchetState.IDLE);
195
+ expect(workspaceRatchetService.settleIdleWhileDisabled).toHaveBeenCalledWith('ws-disabled', RatchetState.IDLE);
180
196
  });
181
197
  it('settles a disabled workspace to IDLE via CAS and emits an accurate fromState', async () => {
182
198
  const workspace = {
@@ -193,13 +209,13 @@ describe('ratchet service (state-change + idle dispatch)', () => {
193
209
  ratchetDispatchOutcome: null,
194
210
  ratchetDispatchRetryCount: 0,
195
211
  };
196
- vi.mocked(workspaceAccessor.settleRatchetIdleWhileDisabled).mockResolvedValue(true);
212
+ vi.mocked(workspaceRatchetService.settleIdleWhileDisabled).mockResolvedValue(true);
197
213
  const events = [];
198
214
  ratchetService.on(RATCHET_STATE_CHANGED, (event) => {
199
215
  events.push(event);
200
216
  });
201
217
  const result = await unsafeCoerce(ratchetService).processWorkspace(workspace);
202
- expect(workspaceAccessor.settleRatchetIdleWhileDisabled).toHaveBeenCalledWith('ws-disabled-settle', RatchetState.CI_FAILED);
218
+ expect(workspaceRatchetService.settleIdleWhileDisabled).toHaveBeenCalledWith('ws-disabled-settle', RatchetState.CI_FAILED);
203
219
  expect(result).toMatchObject({
204
220
  previousState: RatchetState.CI_FAILED,
205
221
  newState: RatchetState.IDLE,
@@ -228,7 +244,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
228
244
  ratchetDispatchOutcome: null,
229
245
  ratchetDispatchRetryCount: 0,
230
246
  };
231
- vi.mocked(workspaceAccessor.settleRatchetIdleWhileDisabled).mockResolvedValue(false);
247
+ vi.mocked(workspaceRatchetService.settleIdleWhileDisabled).mockResolvedValue(false);
232
248
  const events = [];
233
249
  ratchetService.on(RATCHET_STATE_CHANGED, (event) => {
234
250
  events.push(event);
@@ -274,8 +290,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
274
290
  },
275
291
  ],
276
292
  });
277
- vi.mocked(workspaceAccessor.update).mockResolvedValue({});
278
- vi.mocked(agentSessionAccessor.findByWorkspaceId).mockResolvedValue([
293
+ vi.mocked(mockSessionBridge.findSessionsByWorkspaceId).mockResolvedValue([
279
294
  {
280
295
  id: 'chat-1',
281
296
  workflow: 'default-followup',
@@ -316,8 +331,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
316
331
  prState: 'OPEN',
317
332
  prNumber: 4,
318
333
  });
319
- vi.mocked(workspaceAccessor.update).mockResolvedValue({});
320
- vi.mocked(agentSessionAccessor.findByWorkspaceId).mockResolvedValue([]);
334
+ vi.mocked(mockSessionBridge.findSessionsByWorkspaceId).mockResolvedValue([]);
321
335
  vi.mocked(fixerSessionService.acquireAndDispatch).mockResolvedValue({
322
336
  status: 'started',
323
337
  sessionId: 'ratchet-session',
@@ -327,13 +341,13 @@ describe('ratchet service (state-change + idle dispatch)', () => {
327
341
  expect(result).toMatchObject({
328
342
  action: { type: 'TRIGGERED_FIXER' },
329
343
  });
330
- expect(workspaceAccessor.recordRatchetDispatchIfEnabled).toHaveBeenCalledWith('ws-change', {
344
+ expect(workspaceRatchetService.recordDispatchIfEnabled).toHaveBeenCalledWith('ws-change', {
331
345
  sessionId: 'ratchet-session',
332
346
  snapshotKey: '2026-01-02T00:00:00Z',
333
347
  retryCount: 0,
334
348
  });
335
349
  const finalUpdatePayload = vi
336
- .mocked(workspaceAccessor.transitionRatchetStateIfEnabled)
350
+ .mocked(workspaceRatchetService.transitionStateIfEnabled)
337
351
  .mock.calls.at(-1)?.[2];
338
352
  expect(finalUpdatePayload).not.toHaveProperty('ratchetLastCiRunId');
339
353
  expect(finalUpdatePayload).not.toHaveProperty('prReviewLastCheckedAt');
@@ -363,27 +377,32 @@ describe('ratchet service (state-change + idle dispatch)', () => {
363
377
  prState: 'OPEN',
364
378
  prNumber: 40,
365
379
  });
366
- vi.mocked(agentSessionAccessor.findByWorkspaceId).mockResolvedValue([]);
380
+ vi.mocked(mockSessionBridge.findSessionsByWorkspaceId).mockResolvedValue([]);
367
381
  vi.mocked(fixerSessionService.acquireAndDispatch).mockResolvedValue({
368
382
  status: 'started',
369
383
  sessionId: 'raced-session',
370
384
  promptSent: true,
371
385
  });
372
- vi.mocked(workspaceAccessor.recordRatchetDispatchIfEnabled).mockResolvedValue(false);
373
- vi.mocked(workspaceAccessor.transitionRatchetStateIfEnabled).mockResolvedValue(false);
374
- vi.mocked(workspaceAccessor.findById).mockResolvedValue({
386
+ vi.mocked(workspaceRatchetService.recordDispatchIfEnabled).mockResolvedValue(false);
387
+ vi.mocked(workspaceRatchetService.transitionStateIfEnabled).mockResolvedValue(false);
388
+ vi.mocked(workspaceDataService.findById).mockResolvedValue({
375
389
  id: 'ws-disable-race-dispatch',
376
390
  ratchetEnabled: false,
377
391
  });
378
392
  vi.mocked(mockSessionBridge.isSessionRunning).mockReturnValue(true);
393
+ const events = [];
394
+ ratchetService.on(RATCHET_DISPATCH_CHANGED, (event) => {
395
+ events.push(event);
396
+ });
379
397
  const result = await unsafeCoerce(ratchetService).processWorkspace(workspace);
380
398
  expect(result).toMatchObject({
381
399
  newState: RatchetState.IDLE,
382
400
  action: { type: 'DISABLED', reason: 'Workspace ratcheting disabled' },
383
401
  });
384
- expect(workspaceAccessor.recordRatchetDispatchIfEnabled).toHaveBeenCalledWith('ws-disable-race-dispatch', { sessionId: 'raced-session', snapshotKey: 'new-snapshot', retryCount: 0 });
402
+ expect(workspaceRatchetService.recordDispatchIfEnabled).toHaveBeenCalledWith('ws-disable-race-dispatch', { sessionId: 'raced-session', snapshotKey: 'new-snapshot', retryCount: 0 });
385
403
  expect(mockSessionBridge.stopSession).toHaveBeenCalledWith('raced-session');
386
404
  expect(mockSnapshotBridge.recordReviewCheck).not.toHaveBeenCalled();
405
+ expect(events).toHaveLength(0);
387
406
  });
388
407
  it('dispatches when session is running but idle', async () => {
389
408
  const workspace = {
@@ -409,8 +428,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
409
428
  prState: 'OPEN',
410
429
  prNumber: 44,
411
430
  });
412
- vi.mocked(workspaceAccessor.update).mockResolvedValue({});
413
- vi.mocked(agentSessionAccessor.findByWorkspaceId).mockResolvedValue([
431
+ vi.mocked(mockSessionBridge.findSessionsByWorkspaceId).mockResolvedValue([
414
432
  {
415
433
  id: 'chat-idle-1',
416
434
  workflow: 'default-followup',
@@ -455,8 +473,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
455
473
  prState: 'OPEN',
456
474
  prNumber: 5,
457
475
  });
458
- vi.mocked(workspaceAccessor.update).mockResolvedValue({});
459
- vi.mocked(agentSessionAccessor.findByWorkspaceId).mockResolvedValue([]);
476
+ vi.mocked(mockSessionBridge.findSessionsByWorkspaceId).mockResolvedValue([]);
460
477
  const result = await unsafeCoerce(ratchetService).processWorkspace(workspace);
461
478
  expect(result).toMatchObject({
462
479
  action: {
@@ -464,7 +481,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
464
481
  reason: 'PR state unchanged since last ratchet dispatch',
465
482
  },
466
483
  });
467
- expect(agentSessionAccessor.findByWorkspaceId).not.toHaveBeenCalled();
484
+ expect(mockSessionBridge.findSessionsByWorkspaceId).not.toHaveBeenCalled();
468
485
  expect(mockSnapshotBridge.recordReviewCheck).not.toHaveBeenCalled();
469
486
  });
470
487
  it('does not dispatch repeatedly for unchanged CHANGES_REQUESTED state', async () => {
@@ -500,8 +517,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
500
517
  },
501
518
  ],
502
519
  });
503
- vi.mocked(workspaceAccessor.update).mockResolvedValue({});
504
- vi.mocked(agentSessionAccessor.findByWorkspaceId).mockResolvedValue([]);
520
+ vi.mocked(mockSessionBridge.findSessionsByWorkspaceId).mockResolvedValue([]);
505
521
  const triggerSpy = vi.spyOn(unsafeCoerce(ratchetService), 'triggerFixer');
506
522
  const result = await unsafeCoerce(ratchetService).processWorkspace(workspace);
507
523
  expect(triggerSpy).not.toHaveBeenCalled();
@@ -511,9 +527,9 @@ describe('ratchet service (state-change + idle dispatch)', () => {
511
527
  reason: 'PR state unchanged since last ratchet dispatch',
512
528
  },
513
529
  });
514
- expect(agentSessionAccessor.findByWorkspaceId).not.toHaveBeenCalled();
530
+ expect(mockSessionBridge.findSessionsByWorkspaceId).not.toHaveBeenCalled();
515
531
  });
516
- it('does not dispatch for CHANGES_REQUESTED when there are no PR review comments', async () => {
532
+ it('dispatches for CHANGES_REQUESTED when there are no PR review comments', async () => {
517
533
  const workspace = {
518
534
  id: 'ws-review-no-comments',
519
535
  prUrl: 'https://github.com/example/repo/pull/56',
@@ -538,19 +554,20 @@ describe('ratchet service (state-change + idle dispatch)', () => {
538
554
  prNumber: 56,
539
555
  reviewComments: [],
540
556
  });
541
- vi.mocked(workspaceAccessor.update).mockResolvedValue({});
542
- vi.mocked(agentSessionAccessor.findByWorkspaceId).mockResolvedValue([]);
557
+ vi.mocked(mockSessionBridge.findSessionsByWorkspaceId).mockResolvedValue([]);
558
+ vi.mocked(fixerSessionService.acquireAndDispatch).mockResolvedValue({
559
+ status: 'started',
560
+ sessionId: 'ratchet-session',
561
+ promptSent: true,
562
+ });
543
563
  const triggerSpy = vi.spyOn(unsafeCoerce(ratchetService), 'triggerFixer');
544
564
  const result = await unsafeCoerce(ratchetService).processWorkspace(workspace);
545
- expect(triggerSpy).not.toHaveBeenCalled();
565
+ expect(triggerSpy).toHaveBeenCalled();
546
566
  expect(result).toMatchObject({
547
- action: {
548
- type: 'WAITING',
549
- reason: 'No CI failures or PR review comments to address',
550
- },
567
+ action: { type: 'TRIGGERED_FIXER' },
551
568
  });
552
569
  });
553
- it('dispatches for PR review summary feedback without changes requested', async () => {
570
+ it('dispatches for PR review summary feedback in all-feedback mode', async () => {
554
571
  const workspace = {
555
572
  id: 'ws-review-summary',
556
573
  prUrl: 'https://github.com/example/repo/pull/57',
@@ -565,7 +582,14 @@ describe('ratchet service (state-change + idle dispatch)', () => {
565
582
  ratchetDispatchOutcome: null,
566
583
  ratchetDispatchRetryCount: 0,
567
584
  };
568
- vi.spyOn(unsafeCoerce(ratchetService), 'fetchPRState').mockResolvedValue({
585
+ vi.mocked(userSettingsService.get).mockResolvedValue({
586
+ ratchetReviewTriggerMode: 'ALL_REVIEW_FEEDBACK',
587
+ ratchetReplyToPrComments: true,
588
+ ratchetPermissions: 'YOLO',
589
+ });
590
+ const fetchPRStateSpy = vi
591
+ .spyOn(unsafeCoerce(ratchetService), 'fetchPRState')
592
+ .mockResolvedValue({
569
593
  ciStatus: CIStatus.SUCCESS,
570
594
  snapshotKey: 'ci:SUCCESS|no-changes-requested:1767315600000|merge:clean',
571
595
  hasChangesRequested: false,
@@ -584,8 +608,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
584
608
  },
585
609
  ],
586
610
  });
587
- vi.mocked(workspaceAccessor.update).mockResolvedValue({});
588
- vi.mocked(agentSessionAccessor.findByWorkspaceId).mockResolvedValue([]);
611
+ vi.mocked(mockSessionBridge.findSessionsByWorkspaceId).mockResolvedValue([]);
589
612
  vi.mocked(fixerSessionService.acquireAndDispatch).mockResolvedValue({
590
613
  status: 'started',
591
614
  sessionId: 'ratchet-session',
@@ -597,6 +620,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
597
620
  newState: RatchetState.READY,
598
621
  });
599
622
  expect(fixerSessionService.acquireAndDispatch).toHaveBeenCalled();
623
+ expect(fetchPRStateSpy).toHaveBeenCalledWith(workspace, null, expect.objectContaining({ reviewTriggerMode: 'ALL_REVIEW_FEEDBACK' }), expect.any(AbortSignal));
600
624
  });
601
625
  it('treats closed PR as IDLE and does not dispatch', () => {
602
626
  const state = determineRatchetState({
@@ -642,8 +666,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
642
666
  },
643
667
  ],
644
668
  });
645
- vi.mocked(workspaceAccessor.update).mockResolvedValue({});
646
- vi.mocked(agentSessionAccessor.findByWorkspaceId).mockResolvedValue([]);
669
+ vi.mocked(mockSessionBridge.findSessionsByWorkspaceId).mockResolvedValue([]);
647
670
  vi.mocked(fixerSessionService.acquireAndDispatch).mockResolvedValue({
648
671
  status: 'started',
649
672
  sessionId: 'ratchet-session',
@@ -655,9 +678,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
655
678
  expect(result).toMatchObject({
656
679
  action: { type: 'ERROR', error: 'Failed to deliver initial ratchet prompt' },
657
680
  });
658
- expect(workspaceAccessor.update).toHaveBeenCalledWith(workspace.id, {
659
- ratchetActiveSessionId: null,
660
- });
681
+ expect(workspaceRatchetService.clearActiveSession).toHaveBeenCalledWith(workspace.id);
661
682
  expect(mockSessionBridge.stopSession).toHaveBeenCalledWith('ratchet-session');
662
683
  });
663
684
  it('routes an aborted prompt-failure path through orphan cleanup', async () => {
@@ -669,7 +690,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
669
690
  sessionId: 'aborted-prompt-session',
670
691
  promptSent: false,
671
692
  });
672
- vi.mocked(workspaceAccessor.update).mockImplementation(() => new Promise((resolve) => {
693
+ vi.mocked(workspaceRatchetService.clearActiveSession).mockImplementation(() => new Promise((resolve) => {
673
694
  finishPointerClear = () => resolve({});
674
695
  }));
675
696
  vi.mocked(mockSessionBridge.isSessionRunning).mockReturnValue(true);
@@ -683,13 +704,30 @@ describe('ratchet service (state-change + idle dispatch)', () => {
683
704
  reviewComments: [],
684
705
  hasMergeConflict: false,
685
706
  }, 0, controller.signal);
686
- await vi.waitFor(() => expect(workspaceAccessor.update).toHaveBeenCalled());
707
+ await vi.waitFor(() => expect(workspaceRatchetService.clearActiveSession).toHaveBeenCalled());
687
708
  controller.abort(timeoutError);
688
709
  finishPointerClear();
689
710
  await expect(trigger).rejects.toBe(timeoutError);
690
- expect(workspaceAccessor.recordRatchetSessionEnd).toHaveBeenCalledWith('ws-aborted-prompt', 'aborted-prompt-session', 'COMPLETED');
711
+ expect(workspaceRatchetService.recordSessionEnd).toHaveBeenCalledWith('ws-aborted-prompt', 'aborted-prompt-session', 'COMPLETED');
691
712
  expect(mockSessionBridge.stopSession).toHaveBeenCalledWith('aborted-prompt-session');
692
713
  });
714
+ it('publishes a dispatch invalidation after lifecycle settlement', async () => {
715
+ const events = [];
716
+ ratchetService.on(RATCHET_DISPATCH_CHANGED, (event) => {
717
+ events.push(event);
718
+ });
719
+ await ratchetService.recordSessionEnd('ws-1', 'session-1', 'DIED');
720
+ expect(events).toContainEqual({ workspaceId: 'ws-1' });
721
+ });
722
+ it('does not publish a dispatch change when lifecycle settlement loses its CAS', async () => {
723
+ const events = [];
724
+ ratchetService.on(RATCHET_DISPATCH_CHANGED, (event) => {
725
+ events.push(event);
726
+ });
727
+ vi.mocked(mockWorkspaceBridge.recordSessionEnd).mockResolvedValue(false);
728
+ await ratchetService.recordSessionEnd('ws-1', 'session-1', 'DIED');
729
+ expect(events).toHaveLength(0);
730
+ });
693
731
  it('does not dispatch on a clean PR with no new review activity', async () => {
694
732
  const recentCheck = new Date();
695
733
  const workspace = {
@@ -715,8 +753,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
715
753
  prState: 'OPEN',
716
754
  prNumber: 8,
717
755
  });
718
- vi.mocked(workspaceAccessor.update).mockResolvedValue({});
719
- vi.mocked(agentSessionAccessor.findByWorkspaceId).mockResolvedValue([]);
756
+ vi.mocked(mockSessionBridge.findSessionsByWorkspaceId).mockResolvedValue([]);
720
757
  const triggerSpy = vi.spyOn(unsafeCoerce(ratchetService), 'triggerFixer');
721
758
  const result = await unsafeCoerce(ratchetService).processWorkspace(workspace);
722
759
  expect(triggerSpy).not.toHaveBeenCalled();
@@ -727,6 +764,56 @@ describe('ratchet service (state-change + idle dispatch)', () => {
727
764
  },
728
765
  });
729
766
  });
767
+ it('dispatches stale actionable review comments when the PR snapshot changes', async () => {
768
+ const recentCheck = new Date();
769
+ const workspace = {
770
+ id: 'ws-stale-actionable-review',
771
+ prUrl: 'https://github.com/example/repo/pull/43',
772
+ prNumber: 43,
773
+ prState: 'OPEN',
774
+ prCiStatus: CIStatus.FAILURE,
775
+ ratchetEnabled: true,
776
+ ratchetState: RatchetState.CI_FAILED,
777
+ ratchetActiveSessionId: null,
778
+ ratchetLastCiRunId: 'failed-snapshot',
779
+ prReviewLastCheckedAt: recentCheck,
780
+ ratchetDispatchOutcome: 'COMPLETED',
781
+ ratchetDispatchRetryCount: 0,
782
+ };
783
+ vi.spyOn(unsafeCoerce(ratchetService), 'fetchPRState').mockResolvedValue({
784
+ ciStatus: CIStatus.SUCCESS,
785
+ snapshotKey: 'successful-snapshot',
786
+ hasChangesRequested: false,
787
+ hasMergeConflict: false,
788
+ latestReviewActivityAtMs: recentCheck.getTime() - 1000,
789
+ statusCheckRollup: null,
790
+ prState: 'OPEN',
791
+ prNumber: 43,
792
+ reviewComments: [
793
+ {
794
+ author: 'reviewer',
795
+ body: 'Please handle this edge case.',
796
+ path: 'src/example.ts',
797
+ line: 10,
798
+ url: 'https://github.com/example/repo/pull/43#discussion_r1',
799
+ },
800
+ ],
801
+ });
802
+ vi.mocked(fixerSessionService.acquireAndDispatch).mockResolvedValue({
803
+ status: 'started',
804
+ sessionId: 'ratchet-review-session',
805
+ promptSent: true,
806
+ });
807
+ const result = await unsafeCoerce(ratchetService).processWorkspace(workspace);
808
+ expect(result).toMatchObject({
809
+ action: { type: 'TRIGGERED_FIXER', sessionId: 'ratchet-review-session' },
810
+ });
811
+ expect(workspaceRatchetService.recordDispatchIfEnabled).toHaveBeenCalledWith('ws-stale-actionable-review', {
812
+ sessionId: 'ratchet-review-session',
813
+ snapshotKey: 'successful-snapshot',
814
+ retryCount: 0,
815
+ });
816
+ });
730
817
  it('returns disabled when stale check-state update loses disable race', async () => {
731
818
  const recentCheck = new Date();
732
819
  const workspace = {
@@ -752,12 +839,12 @@ describe('ratchet service (state-change + idle dispatch)', () => {
752
839
  prState: 'OPEN',
753
840
  prNumber: 41,
754
841
  });
755
- vi.mocked(workspaceAccessor.transitionRatchetStateIfEnabled).mockResolvedValue(false);
756
- vi.mocked(workspaceAccessor.findById).mockResolvedValue({
842
+ vi.mocked(workspaceRatchetService.transitionStateIfEnabled).mockResolvedValue(false);
843
+ vi.mocked(workspaceDataService.findById).mockResolvedValue({
757
844
  id: 'ws-disable-race-state',
758
845
  ratchetEnabled: false,
759
846
  });
760
- vi.mocked(agentSessionAccessor.findByWorkspaceId).mockResolvedValue([]);
847
+ vi.mocked(mockSessionBridge.findSessionsByWorkspaceId).mockResolvedValue([]);
761
848
  const events = [];
762
849
  ratchetService.on(RATCHET_STATE_CHANGED, (event) => {
763
850
  events.push(event);
@@ -795,19 +882,19 @@ describe('ratchet service (state-change + idle dispatch)', () => {
795
882
  prState: 'OPEN',
796
883
  prNumber: 42,
797
884
  });
798
- vi.mocked(workspaceAccessor.transitionRatchetStateIfEnabled).mockResolvedValue(false);
799
- vi.mocked(workspaceAccessor.findById).mockResolvedValue({
885
+ vi.mocked(workspaceRatchetService.transitionStateIfEnabled).mockResolvedValue(false);
886
+ vi.mocked(workspaceDataService.findById).mockResolvedValue({
800
887
  id: 'ws-superseded',
801
888
  ratchetEnabled: true,
802
889
  ratchetState: RatchetState.IDLE,
803
890
  });
804
- vi.mocked(agentSessionAccessor.findByWorkspaceId).mockResolvedValue([]);
891
+ vi.mocked(mockSessionBridge.findSessionsByWorkspaceId).mockResolvedValue([]);
805
892
  const events = [];
806
893
  ratchetService.on(RATCHET_STATE_CHANGED, (event) => {
807
894
  events.push(event);
808
895
  });
809
896
  const result = await unsafeCoerce(ratchetService).processWorkspace(workspace);
810
- expect(workspaceAccessor.transitionRatchetStateIfEnabled).toHaveBeenCalledWith('ws-superseded', RatchetState.CI_RUNNING, expect.objectContaining({ ratchetState: RatchetState.READY }));
897
+ expect(workspaceRatchetService.transitionStateIfEnabled).toHaveBeenCalledWith('ws-superseded', RatchetState.CI_RUNNING, expect.objectContaining({ ratchetState: RatchetState.READY }));
811
898
  expect(result).toMatchObject({
812
899
  previousState: RatchetState.CI_RUNNING,
813
900
  newState: RatchetState.CI_RUNNING,
@@ -844,8 +931,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
844
931
  prState: 'OPEN',
845
932
  prNumber: 13,
846
933
  });
847
- vi.mocked(workspaceAccessor.update).mockResolvedValue({});
848
- vi.mocked(agentSessionAccessor.findByWorkspaceId).mockResolvedValue([]);
934
+ vi.mocked(mockSessionBridge.findSessionsByWorkspaceId).mockResolvedValue([]);
849
935
  vi.mocked(fixerSessionService.acquireAndDispatch).mockResolvedValue({
850
936
  status: 'started',
851
937
  sessionId: 'retry-session',
@@ -855,7 +941,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
855
941
  expect(result).toMatchObject({
856
942
  action: { type: 'TRIGGERED_FIXER' },
857
943
  });
858
- expect(workspaceAccessor.recordRatchetDispatchIfEnabled).toHaveBeenCalledWith('ws-died-retry', {
944
+ expect(workspaceRatchetService.recordDispatchIfEnabled).toHaveBeenCalledWith('ws-died-retry', {
859
945
  sessionId: 'retry-session',
860
946
  snapshotKey: 'same-snapshot',
861
947
  retryCount: 2,
@@ -887,22 +973,26 @@ describe('ratchet service (state-change + idle dispatch)', () => {
887
973
  prNumber: 14,
888
974
  reviewComments: [],
889
975
  });
890
- vi.mocked(workspaceAccessor.update).mockResolvedValue({});
891
- vi.mocked(agentSessionAccessor.findByWorkspaceId).mockResolvedValue([]);
976
+ vi.mocked(mockSessionBridge.findSessionsByWorkspaceId).mockResolvedValue([]);
892
977
  vi.mocked(fixerSessionService.acquireAndDispatch).mockResolvedValue({
893
978
  status: 'started',
894
979
  sessionId: 'retry-session',
895
980
  promptSent: true,
896
981
  });
982
+ const events = [];
983
+ ratchetService.on(RATCHET_DISPATCH_CHANGED, (event) => {
984
+ events.push(event);
985
+ });
897
986
  const result = await unsafeCoerce(ratchetService).processWorkspace(workspace);
898
987
  expect(result).toMatchObject({
899
988
  action: { type: 'TRIGGERED_FIXER' },
900
989
  });
901
- expect(workspaceAccessor.recordRatchetDispatchIfEnabled).toHaveBeenCalledWith('ws-died-clean', {
990
+ expect(workspaceRatchetService.recordDispatchIfEnabled).toHaveBeenCalledWith('ws-died-clean', {
902
991
  sessionId: 'retry-session',
903
992
  snapshotKey: 'clean-snapshot',
904
993
  retryCount: 1,
905
994
  });
995
+ expect(events).toContainEqual({ workspaceId: 'ws-died-clean' });
906
996
  });
907
997
  it('stops retrying a died fixer once the retry budget is exhausted', async () => {
908
998
  const workspace = {
@@ -928,7 +1018,6 @@ describe('ratchet service (state-change + idle dispatch)', () => {
928
1018
  prState: 'OPEN',
929
1019
  prNumber: 15,
930
1020
  });
931
- vi.mocked(workspaceAccessor.update).mockResolvedValue({});
932
1021
  const result = await unsafeCoerce(ratchetService).processWorkspace(workspace);
933
1022
  expect(result).toMatchObject({
934
1023
  action: {
@@ -962,8 +1051,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
962
1051
  prState: 'OPEN',
963
1052
  prNumber: 16,
964
1053
  });
965
- vi.mocked(workspaceAccessor.update).mockResolvedValue({});
966
- vi.mocked(agentSessionAccessor.findByWorkspaceId).mockResolvedValue([]);
1054
+ vi.mocked(mockSessionBridge.findSessionsByWorkspaceId).mockResolvedValue([]);
967
1055
  vi.mocked(fixerSessionService.acquireAndDispatch).mockResolvedValue({
968
1056
  status: 'started',
969
1057
  sessionId: 'fresh-session',
@@ -973,7 +1061,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
973
1061
  expect(result).toMatchObject({
974
1062
  action: { type: 'TRIGGERED_FIXER' },
975
1063
  });
976
- expect(workspaceAccessor.recordRatchetDispatchIfEnabled).toHaveBeenCalledWith('ws-died-changed', { sessionId: 'fresh-session', snapshotKey: 'new-snapshot', retryCount: 0 });
1064
+ expect(workspaceRatchetService.recordDispatchIfEnabled).toHaveBeenCalledWith('ws-died-changed', { sessionId: 'fresh-session', snapshotKey: 'new-snapshot', retryCount: 0 });
977
1065
  });
978
1066
  it('does not redispatch when the previous fixer completed and PR state is unchanged', async () => {
979
1067
  const workspace = {
@@ -999,7 +1087,6 @@ describe('ratchet service (state-change + idle dispatch)', () => {
999
1087
  prState: 'OPEN',
1000
1088
  prNumber: 17,
1001
1089
  });
1002
- vi.mocked(workspaceAccessor.update).mockResolvedValue({});
1003
1090
  const result = await unsafeCoerce(ratchetService).processWorkspace(workspace);
1004
1091
  expect(result).toMatchObject({
1005
1092
  action: {
@@ -1009,6 +1096,51 @@ describe('ratchet service (state-change + idle dispatch)', () => {
1009
1096
  });
1010
1097
  expect(fixerSessionService.acquireAndDispatch).not.toHaveBeenCalled();
1011
1098
  });
1099
+ it('dispatches a fresh fixer after switching PRs with identical merge-conflict state', async () => {
1100
+ const previousSnapshotKey = computeDispatchSnapshotKey(123, CIStatus.SUCCESS, false, null, null, true);
1101
+ const currentSnapshotKey = computeDispatchSnapshotKey(456, CIStatus.SUCCESS, false, null, null, true);
1102
+ expect(previousSnapshotKey).toBe('pr:123|ci:SUCCESS|no-changes-requested:none|merge:conflict');
1103
+ expect(currentSnapshotKey).toBe('pr:456|ci:SUCCESS|no-changes-requested:none|merge:conflict');
1104
+ const workspace = {
1105
+ id: 'ws-pr-switch-merge-conflict',
1106
+ prUrl: 'https://github.com/example/repo/pull/456',
1107
+ prNumber: 456,
1108
+ prState: 'OPEN',
1109
+ prCiStatus: CIStatus.SUCCESS,
1110
+ ratchetEnabled: true,
1111
+ ratchetState: RatchetState.MERGE_CONFLICT,
1112
+ ratchetActiveSessionId: null,
1113
+ ratchetLastCiRunId: previousSnapshotKey,
1114
+ prReviewLastCheckedAt: new Date('2026-01-01T00:00:00Z'),
1115
+ ratchetDispatchOutcome: 'COMPLETED',
1116
+ ratchetDispatchRetryCount: 2,
1117
+ };
1118
+ vi.spyOn(unsafeCoerce(ratchetService), 'fetchPRState').mockResolvedValue({
1119
+ ciStatus: CIStatus.SUCCESS,
1120
+ snapshotKey: currentSnapshotKey,
1121
+ hasChangesRequested: false,
1122
+ hasMergeConflict: true,
1123
+ latestReviewActivityAtMs: null,
1124
+ statusCheckRollup: null,
1125
+ prState: 'OPEN',
1126
+ prNumber: 456,
1127
+ reviewComments: [],
1128
+ });
1129
+ vi.mocked(fixerSessionService.acquireAndDispatch).mockResolvedValue({
1130
+ status: 'started',
1131
+ sessionId: 'fresh-pr-session',
1132
+ promptSent: true,
1133
+ });
1134
+ const result = await unsafeCoerce(ratchetService).processWorkspace(workspace);
1135
+ expect(result).toMatchObject({
1136
+ action: { type: 'TRIGGERED_FIXER' },
1137
+ });
1138
+ expect(workspaceRatchetService.recordDispatchIfEnabled).toHaveBeenCalledWith(workspace.id, {
1139
+ sessionId: 'fresh-pr-session',
1140
+ snapshotKey: currentSnapshotKey,
1141
+ retryCount: 0,
1142
+ });
1143
+ });
1012
1144
  it('settles the dispatch as DIED when ratchet session process is not running', async () => {
1013
1145
  const workspace = {
1014
1146
  id: 'ws-stale-active',
@@ -1024,7 +1156,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
1024
1156
  ratchetDispatchOutcome: 'RUNNING',
1025
1157
  ratchetDispatchRetryCount: 0,
1026
1158
  };
1027
- vi.mocked(agentSessionAccessor.findById).mockResolvedValue({
1159
+ vi.mocked(mockSessionBridge.findSessionById).mockResolvedValue({
1028
1160
  id: 'ratchet-session',
1029
1161
  provider: 'CLAUDE',
1030
1162
  status: SessionStatus.RUNNING,
@@ -1032,7 +1164,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
1032
1164
  vi.mocked(mockSessionBridge.isSessionRunning).mockReturnValue(false);
1033
1165
  const result = await unsafeCoerce(ratchetService).checkActiveFixerSession(workspace);
1034
1166
  expect(result).toEqual({ kind: 'settled', outcome: 'DIED' });
1035
- expect(workspaceAccessor.recordRatchetSessionEnd).toHaveBeenCalledWith(workspace.id, 'ratchet-session', 'DIED');
1167
+ expect(mockWorkspaceBridge.recordSessionEnd).toHaveBeenCalledWith(workspace.id, 'ratchet-session', 'DIED');
1036
1168
  });
1037
1169
  it('settles the dispatch as DIED when ratchet session is not found in database', async () => {
1038
1170
  const workspace = {
@@ -1049,10 +1181,15 @@ describe('ratchet service (state-change + idle dispatch)', () => {
1049
1181
  ratchetDispatchOutcome: 'RUNNING',
1050
1182
  ratchetDispatchRetryCount: 0,
1051
1183
  };
1052
- vi.mocked(agentSessionAccessor.findById).mockResolvedValue(null);
1184
+ vi.mocked(mockSessionBridge.findSessionById).mockResolvedValue(null);
1185
+ const events = [];
1186
+ ratchetService.on(RATCHET_DISPATCH_CHANGED, (event) => {
1187
+ events.push(event);
1188
+ });
1053
1189
  const result = await unsafeCoerce(ratchetService).checkActiveFixerSession(workspace);
1054
1190
  expect(result).toEqual({ kind: 'settled', outcome: 'DIED' });
1055
- expect(workspaceAccessor.recordRatchetSessionEnd).toHaveBeenCalledWith(workspace.id, 'deleted-session', 'DIED');
1191
+ expect(mockWorkspaceBridge.recordSessionEnd).toHaveBeenCalledWith(workspace.id, 'deleted-session', 'DIED');
1192
+ expect(events).toEqual([{ workspaceId: 'ws-missing-session' }]);
1056
1193
  });
1057
1194
  it('reports a concurrent end when another path already settled the dispatch', async () => {
1058
1195
  const workspace = {
@@ -1069,10 +1206,15 @@ describe('ratchet service (state-change + idle dispatch)', () => {
1069
1206
  ratchetDispatchOutcome: 'RUNNING',
1070
1207
  ratchetDispatchRetryCount: 0,
1071
1208
  };
1072
- vi.mocked(agentSessionAccessor.findById).mockResolvedValue(null);
1073
- vi.mocked(workspaceAccessor.recordRatchetSessionEnd).mockResolvedValue(false);
1209
+ vi.mocked(mockSessionBridge.findSessionById).mockResolvedValue(null);
1210
+ vi.mocked(mockWorkspaceBridge.recordSessionEnd).mockResolvedValue(false);
1211
+ const events = [];
1212
+ ratchetService.on(RATCHET_DISPATCH_CHANGED, (event) => {
1213
+ events.push(event);
1214
+ });
1074
1215
  const result = await unsafeCoerce(ratchetService).checkActiveFixerSession(workspace);
1075
1216
  expect(result).toEqual({ kind: 'ended_concurrently' });
1217
+ expect(events).toHaveLength(0);
1076
1218
  });
1077
1219
  it('waits for the next cycle when the fixer ends concurrently mid-check', async () => {
1078
1220
  const workspace = {
@@ -1098,9 +1240,8 @@ describe('ratchet service (state-change + idle dispatch)', () => {
1098
1240
  prState: 'OPEN',
1099
1241
  prNumber: 12,
1100
1242
  });
1101
- vi.mocked(agentSessionAccessor.findById).mockResolvedValue(null);
1102
- vi.mocked(workspaceAccessor.recordRatchetSessionEnd).mockResolvedValue(false);
1103
- vi.mocked(workspaceAccessor.update).mockResolvedValue({});
1243
+ vi.mocked(mockSessionBridge.findSessionById).mockResolvedValue(null);
1244
+ vi.mocked(mockWorkspaceBridge.recordSessionEnd).mockResolvedValue(false);
1104
1245
  const result = await unsafeCoerce(ratchetService).processWorkspace(workspace);
1105
1246
  expect(result).toMatchObject({
1106
1247
  action: {
@@ -1125,7 +1266,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
1125
1266
  ratchetDispatchOutcome: 'RUNNING',
1126
1267
  ratchetDispatchRetryCount: 0,
1127
1268
  };
1128
- vi.mocked(agentSessionAccessor.findById).mockResolvedValue({
1269
+ vi.mocked(mockSessionBridge.findSessionById).mockResolvedValue({
1129
1270
  id: 'ratchet-session',
1130
1271
  provider: 'CLAUDE',
1131
1272
  status: SessionStatus.RUNNING,
@@ -1135,7 +1276,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
1135
1276
  vi.mocked(mockSessionBridge.stopSession).mockResolvedValue();
1136
1277
  const result = await unsafeCoerce(ratchetService).checkActiveFixerSession(workspace);
1137
1278
  expect(result).toEqual({ kind: 'settled', outcome: 'COMPLETED' });
1138
- expect(workspaceAccessor.recordRatchetSessionEnd).toHaveBeenCalledWith(workspace.id, 'ratchet-session', 'COMPLETED');
1279
+ expect(mockWorkspaceBridge.recordSessionEnd).toHaveBeenCalledWith(workspace.id, 'ratchet-session', 'COMPLETED');
1139
1280
  expect(mockSessionBridge.stopSession).toHaveBeenCalledWith('ratchet-session');
1140
1281
  });
1141
1282
  it('decides to trigger fixer when context is actionable', async () => {
@@ -1218,11 +1359,19 @@ describe('ratchet service (state-change + idle dispatch)', () => {
1218
1359
  it('ignores review activity authored by the authenticated user', () => {
1219
1360
  const latestActivity = computeLatestReviewActivityAtMs({
1220
1361
  reviews: [
1221
- { submittedAt: '2026-01-02T00:00:00Z', author: { login: 'ratchet-bot' } },
1222
- { submittedAt: '2026-01-01T00:00:00Z', author: { login: 'reviewer' } },
1362
+ {
1363
+ submittedAt: '2026-01-02T00:00:00Z',
1364
+ author: { login: 'ratchet-bot' },
1365
+ state: 'CHANGES_REQUESTED',
1366
+ },
1367
+ {
1368
+ submittedAt: '2026-01-01T00:00:00Z',
1369
+ author: { login: 'reviewer' },
1370
+ state: 'CHANGES_REQUESTED',
1371
+ },
1223
1372
  ],
1224
1373
  comments: [{ updatedAt: '2026-01-02T01:00:00Z', author: { login: 'ratchet-bot' } }],
1225
- }, [{ updatedAt: '2026-01-01T02:00:00Z', author: { login: 'reviewer2' } }], 'ratchet-bot');
1374
+ }, [{ updatedAt: '2026-01-01T02:00:00Z', author: { login: 'reviewer2' } }], 'ratchet-bot', 'CHANGES_REQUESTED');
1226
1375
  expect(latestActivity).toBe(new Date('2026-01-01T02:00:00Z').getTime());
1227
1376
  });
1228
1377
  describe('determineRatchetState', () => {
@@ -1285,7 +1434,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
1285
1434
  });
1286
1435
  });
1287
1436
  describe('computeDispatchSnapshotKey', () => {
1288
- const callComputeSnapshotKey = (ciStatus, hasChangesRequested, latestReviewActivityAtMs, statusChecks) => computeDispatchSnapshotKey(ciStatus, hasChangesRequested, latestReviewActivityAtMs, statusChecks);
1437
+ const callComputeSnapshotKey = (ciStatus, hasChangesRequested, latestReviewActivityAtMs, statusChecks) => computeDispatchSnapshotKey(123, ciStatus, hasChangesRequested, latestReviewActivityAtMs, statusChecks);
1289
1438
  it('includes CI status in key for non-failure states', () => {
1290
1439
  const key = callComputeSnapshotKey(CIStatus.SUCCESS, false, null, null);
1291
1440
  expect(key).toContain('ci:SUCCESS');
@@ -1329,36 +1478,60 @@ describe('ratchet service (state-change + idle dispatch)', () => {
1329
1478
  });
1330
1479
  });
1331
1480
  describe('computeLatestReviewActivityAtMs edge cases', () => {
1332
- const callCompute = (prDetails, reviewComments, authenticatedUsername) => computeLatestReviewActivityAtMs(prDetails, reviewComments, authenticatedUsername);
1481
+ const callCompute = (prDetails, reviewComments, authenticatedUsername) => computeLatestReviewActivityAtMs(prDetails, reviewComments, authenticatedUsername, 'CHANGES_REQUESTED');
1333
1482
  it('returns null when there are no reviews or comments', () => {
1334
1483
  expect(callCompute({ reviews: [], comments: [] }, [], null)).toBeNull();
1335
1484
  });
1336
1485
  it('returns null when all activity is from the authenticated user', () => {
1337
1486
  expect(callCompute({
1338
- reviews: [{ submittedAt: '2026-01-01T00:00:00Z', author: { login: 'me' } }],
1487
+ reviews: [
1488
+ {
1489
+ submittedAt: '2026-01-01T00:00:00Z',
1490
+ author: { login: 'me' },
1491
+ state: 'CHANGES_REQUESTED',
1492
+ },
1493
+ ],
1339
1494
  comments: [{ updatedAt: '2026-01-02T00:00:00Z', author: { login: 'me' } }],
1340
1495
  }, [{ updatedAt: '2026-01-03T00:00:00Z', author: { login: 'me' } }], 'me')).toBeNull();
1341
1496
  });
1342
1497
  it('does not filter when authenticatedUsername is null', () => {
1343
1498
  const result = callCompute({
1344
- reviews: [{ submittedAt: '2026-01-01T00:00:00Z', author: { login: 'bot' } }],
1499
+ reviews: [
1500
+ {
1501
+ submittedAt: '2026-01-01T00:00:00Z',
1502
+ author: { login: 'bot' },
1503
+ state: 'CHANGES_REQUESTED',
1504
+ },
1505
+ ],
1345
1506
  comments: [],
1346
1507
  }, [], null);
1347
1508
  expect(result).toBe(new Date('2026-01-01T00:00:00Z').getTime());
1348
1509
  });
1349
- it('ignores reviews that have null submittedAt', () => {
1510
+ it('ignores reviews with null submittedAt and ordinary PR comments', () => {
1350
1511
  const result = callCompute({
1351
- reviews: [{ submittedAt: null, author: { login: 'reviewer' } }],
1512
+ reviews: [
1513
+ {
1514
+ submittedAt: null,
1515
+ author: { login: 'reviewer' },
1516
+ state: 'CHANGES_REQUESTED',
1517
+ },
1518
+ ],
1352
1519
  comments: [{ updatedAt: '2026-01-02T00:00:00Z', author: { login: 'commenter' } }],
1353
1520
  }, [], null);
1354
- expect(result).toBe(new Date('2026-01-02T00:00:00Z').getTime());
1521
+ expect(result).toBeNull();
1355
1522
  });
1356
1523
  it('returns the latest timestamp across all sources', () => {
1357
1524
  const result = callCompute({
1358
- reviews: [{ submittedAt: '2026-01-01T00:00:00Z', author: { login: 'a' } }],
1525
+ reviews: [
1526
+ {
1527
+ submittedAt: '2026-01-01T00:00:00Z',
1528
+ author: { login: 'a' },
1529
+ state: 'CHANGES_REQUESTED',
1530
+ },
1531
+ ],
1359
1532
  comments: [{ updatedAt: '2026-01-03T00:00:00Z', author: { login: 'b' } }],
1360
1533
  }, [{ updatedAt: '2026-01-02T00:00:00Z', author: { login: 'c' } }], null);
1361
- expect(result).toBe(new Date('2026-01-03T00:00:00Z').getTime());
1534
+ expect(result).toBe(new Date('2026-01-02T00:00:00Z').getTime());
1362
1535
  });
1363
1536
  });
1364
1537
  describe('processWorkspace error handling', () => {
@@ -1376,7 +1549,6 @@ describe('ratchet service (state-change + idle dispatch)', () => {
1376
1549
  ratchetDispatchRetryCount: 0,
1377
1550
  };
1378
1551
  vi.spyOn(unsafeCoerce(ratchetService), 'fetchPRState').mockResolvedValue(null);
1379
- vi.mocked(workspaceAccessor.update).mockResolvedValue({});
1380
1552
  const result = await unsafeCoerce(ratchetService).processWorkspace(workspace);
1381
1553
  expect(result).toMatchObject({
1382
1554
  action: { type: 'ERROR', error: 'Failed to fetch PR state' },
@@ -1402,7 +1574,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
1402
1574
  action: { type: 'WAITING', reason: 'recently_fetched' },
1403
1575
  newState: RatchetState.IDLE,
1404
1576
  });
1405
- expect(workspaceAccessor.update).not.toHaveBeenCalled();
1577
+ expect(workspaceRatchetService.clearActiveSession).not.toHaveBeenCalled();
1406
1578
  });
1407
1579
  it('returns WAITING when shutting down', async () => {
1408
1580
  unsafeCoerce(ratchetService).isShuttingDown = true;
@@ -1454,13 +1626,34 @@ describe('ratchet service (state-change + idle dispatch)', () => {
1454
1626
  expect(result).toEqual({ checked: 0, stateChanges: 0, actionsTriggered: 0, results: [] });
1455
1627
  });
1456
1628
  it('returns zero counts when no workspaces have PRs', async () => {
1457
- vi.mocked(workspaceAccessor.findWithPRsForRatchet).mockResolvedValue([]);
1629
+ vi.mocked(workspaceRatchetService.findCandidates).mockResolvedValue([]);
1458
1630
  const result = await ratchetService.checkAllWorkspaces();
1459
1631
  expect(result).toEqual({ checked: 0, stateChanges: 0, actionsTriggered: 0, results: [] });
1460
1632
  });
1633
+ it('loads the global review trigger mode once for the whole batch', async () => {
1634
+ const workspaces = ['ws-one', 'ws-two'].map((id) => ({
1635
+ id,
1636
+ prUrl: `https://github.com/example/repo/pull/${id}`,
1637
+ prNumber: 1,
1638
+ prState: 'OPEN',
1639
+ prCiStatus: CIStatus.UNKNOWN,
1640
+ ratchetEnabled: true,
1641
+ ratchetState: RatchetState.IDLE,
1642
+ ratchetActiveSessionId: null,
1643
+ ratchetLastCiRunId: null,
1644
+ prReviewLastCheckedAt: null,
1645
+ ratchetDispatchOutcome: null,
1646
+ ratchetDispatchRetryCount: 0,
1647
+ }));
1648
+ vi.mocked(workspaceRatchetService.findCandidates).mockResolvedValue(workspaces);
1649
+ vi.spyOn(unsafeCoerce(ratchetService), 'fetchPRState').mockResolvedValue({ skipped: true, reason: 'recently_fetched' });
1650
+ const result = await ratchetService.checkAllWorkspaces();
1651
+ expect(result.checked).toBe(2);
1652
+ expect(userSettingsService.get).toHaveBeenCalledTimes(1);
1653
+ });
1461
1654
  it('returns an error result when one workspace check times out', async () => {
1462
1655
  unsafeCoerce(ratchetService).workspaceCheckTimeoutMs = 5;
1463
- vi.mocked(workspaceAccessor.findWithPRsForRatchet).mockResolvedValue([
1656
+ vi.mocked(workspaceRatchetService.findCandidates).mockResolvedValue([
1464
1657
  {
1465
1658
  id: 'ws-timeout',
1466
1659
  prUrl: 'https://github.com/example/repo/pull/1',
@@ -1541,7 +1734,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
1541
1734
  ratchetDispatchOutcome: null,
1542
1735
  ratchetDispatchRetryCount: 0,
1543
1736
  }));
1544
- vi.mocked(workspaceAccessor.findWithPRsForRatchet).mockResolvedValue(workspaces);
1737
+ vi.mocked(workspaceRatchetService.findCandidates).mockResolvedValue(workspaces);
1545
1738
  const processWorkspaceSpy = vi.spyOn(unsafeCoerce(ratchetService), 'processWorkspace');
1546
1739
  processWorkspaceSpy.mockImplementation((workspace, _opts, signal) => {
1547
1740
  if (workspace.id !== 'ws-queued-timeout-3') {
@@ -1557,7 +1750,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
1557
1750
  });
1558
1751
  });
1559
1752
  const result = await ratchetService.checkAllWorkspaces();
1560
- expect(processWorkspaceSpy).toHaveBeenCalledWith(expect.objectContaining({ id: 'ws-queued-timeout-3' }), undefined, expect.any(AbortSignal), expect.any(Function));
1753
+ expect(processWorkspaceSpy).toHaveBeenCalledWith(expect.objectContaining({ id: 'ws-queued-timeout-3' }), undefined, expect.any(AbortSignal), expect.any(Function), 'CHANGES_REQUESTED');
1561
1754
  expect(result.results[3]).toMatchObject({
1562
1755
  workspaceId: 'ws-queued-timeout-3',
1563
1756
  action: { type: 'WAITING', reason: 'ran after queue' },
@@ -1572,7 +1765,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
1572
1765
  ratchetEnabled: true,
1573
1766
  ratchetState: RatchetState.IDLE,
1574
1767
  };
1575
- vi.mocked(workspaceAccessor.findWithPRsForRatchet).mockResolvedValue([workspace]);
1768
+ vi.mocked(workspaceRatchetService.findCandidates).mockResolvedValue([workspace]);
1576
1769
  let finishCommit;
1577
1770
  const commitBarrier = new Promise((resolve) => {
1578
1771
  finishCommit = resolve;
@@ -1614,7 +1807,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
1614
1807
  ratchetDispatchOutcome: null,
1615
1808
  ratchetDispatchRetryCount: 0,
1616
1809
  }));
1617
- vi.mocked(workspaceAccessor.findWithPRsForRatchet).mockResolvedValue(workspaces);
1810
+ vi.mocked(workspaceRatchetService.findCandidates).mockResolvedValue(workspaces);
1618
1811
  let active = 0;
1619
1812
  let maximumActive = 0;
1620
1813
  let releaseChecks;
@@ -1664,18 +1857,18 @@ describe('ratchet service (state-change + idle dispatch)', () => {
1664
1857
  ratchetService.removeAllListeners();
1665
1858
  });
1666
1859
  it('resets ratchet state to IDLE via CAS on fromState and emits a state change', async () => {
1667
- vi.mocked(workspaceAccessor.findById).mockResolvedValue({
1860
+ vi.mocked(workspaceDataService.findById).mockResolvedValue({
1668
1861
  id: 'ws-closed',
1669
1862
  ratchetEnabled: true,
1670
1863
  ratchetState: RatchetState.CI_FAILED,
1671
1864
  });
1672
- vi.mocked(workspaceAccessor.transitionRatchetStateIfEnabled).mockResolvedValue(true);
1865
+ vi.mocked(workspaceRatchetService.transitionStateIfEnabled).mockResolvedValue(true);
1673
1866
  const stateEvents = [];
1674
1867
  ratchetService.on(RATCHET_STATE_CHANGED, (event) => {
1675
1868
  stateEvents.push(event);
1676
1869
  });
1677
1870
  await ratchetService.markPrClosed('ws-closed');
1678
- expect(workspaceAccessor.transitionRatchetStateIfEnabled).toHaveBeenCalledWith('ws-closed', RatchetState.CI_FAILED, {
1871
+ expect(workspaceRatchetService.transitionStateIfEnabled).toHaveBeenCalledWith('ws-closed', RatchetState.CI_FAILED, {
1679
1872
  ratchetState: RatchetState.IDLE,
1680
1873
  ratchetLastCheckedAt: expect.any(Date),
1681
1874
  });
@@ -1688,7 +1881,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
1688
1881
  ]);
1689
1882
  });
1690
1883
  it('emits the fromState that actually won the compare-and-swap after losing a race', async () => {
1691
- vi.mocked(workspaceAccessor.findById)
1884
+ vi.mocked(workspaceDataService.findById)
1692
1885
  .mockResolvedValueOnce({
1693
1886
  id: 'ws-closed',
1694
1887
  ratchetEnabled: true,
@@ -1699,7 +1892,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
1699
1892
  ratchetEnabled: true,
1700
1893
  ratchetState: RatchetState.CI_RUNNING,
1701
1894
  });
1702
- vi.mocked(workspaceAccessor.transitionRatchetStateIfEnabled)
1895
+ vi.mocked(workspaceRatchetService.transitionStateIfEnabled)
1703
1896
  .mockResolvedValueOnce(false)
1704
1897
  .mockResolvedValueOnce(true);
1705
1898
  const stateEvents = [];
@@ -1707,8 +1900,8 @@ describe('ratchet service (state-change + idle dispatch)', () => {
1707
1900
  stateEvents.push(event);
1708
1901
  });
1709
1902
  await ratchetService.markPrClosed('ws-closed');
1710
- expect(workspaceAccessor.transitionRatchetStateIfEnabled).toHaveBeenNthCalledWith(1, 'ws-closed', RatchetState.CI_FAILED, expect.objectContaining({ ratchetState: RatchetState.IDLE }));
1711
- expect(workspaceAccessor.transitionRatchetStateIfEnabled).toHaveBeenNthCalledWith(2, 'ws-closed', RatchetState.CI_RUNNING, expect.objectContaining({ ratchetState: RatchetState.IDLE }));
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 }));
1712
1905
  expect(stateEvents).toEqual([
1713
1906
  {
1714
1907
  workspaceId: 'ws-closed',
@@ -1718,16 +1911,16 @@ describe('ratchet service (state-change + idle dispatch)', () => {
1718
1911
  ]);
1719
1912
  });
1720
1913
  it('is a no-op when ratchet state is already IDLE', async () => {
1721
- vi.mocked(workspaceAccessor.findById).mockResolvedValue({
1914
+ vi.mocked(workspaceDataService.findById).mockResolvedValue({
1722
1915
  id: 'ws-closed',
1723
1916
  ratchetEnabled: true,
1724
1917
  ratchetState: RatchetState.IDLE,
1725
1918
  });
1726
1919
  await ratchetService.markPrClosed('ws-closed');
1727
- expect(workspaceAccessor.transitionRatchetStateIfEnabled).not.toHaveBeenCalled();
1920
+ expect(workspaceRatchetService.transitionStateIfEnabled).not.toHaveBeenCalled();
1728
1921
  });
1729
1922
  it('does not emit when ratcheting was disabled concurrently', async () => {
1730
- vi.mocked(workspaceAccessor.findById)
1923
+ vi.mocked(workspaceDataService.findById)
1731
1924
  .mockResolvedValueOnce({
1732
1925
  id: 'ws-closed',
1733
1926
  ratchetEnabled: true,
@@ -1738,7 +1931,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
1738
1931
  ratchetEnabled: false,
1739
1932
  ratchetState: RatchetState.IDLE,
1740
1933
  });
1741
- vi.mocked(workspaceAccessor.transitionRatchetStateIfEnabled).mockResolvedValue(false);
1934
+ vi.mocked(workspaceRatchetService.transitionStateIfEnabled).mockResolvedValue(false);
1742
1935
  const stateEvents = [];
1743
1936
  ratchetService.on(RATCHET_STATE_CHANGED, (event) => {
1744
1937
  stateEvents.push(event);
@@ -1747,9 +1940,9 @@ describe('ratchet service (state-change + idle dispatch)', () => {
1747
1940
  expect(stateEvents).toEqual([]);
1748
1941
  });
1749
1942
  it('is a no-op when workspace is not found', async () => {
1750
- vi.mocked(workspaceAccessor.findById).mockResolvedValue(null);
1943
+ vi.mocked(workspaceDataService.findById).mockResolvedValue(null);
1751
1944
  await ratchetService.markPrClosed('ws-missing');
1752
- expect(workspaceAccessor.transitionRatchetStateIfEnabled).not.toHaveBeenCalled();
1945
+ expect(workspaceRatchetService.transitionStateIfEnabled).not.toHaveBeenCalled();
1753
1946
  });
1754
1947
  it('does not continue to side effects after a timed-out await completes', async () => {
1755
1948
  unsafeCoerce(ratchetService).workspaceCheckTimeoutMs = 5;
@@ -1769,7 +1962,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
1769
1962
  ratchetDispatchOutcome: null,
1770
1963
  ratchetDispatchRetryCount: 0,
1771
1964
  };
1772
- vi.mocked(workspaceAccessor.findWithPRsForRatchet).mockResolvedValue([workspace]);
1965
+ vi.mocked(workspaceRatchetService.findCandidates).mockResolvedValue([workspace]);
1773
1966
  let releaseFetch;
1774
1967
  const fetchBarrier = new Promise((resolve) => {
1775
1968
  releaseFetch = resolve;
@@ -1794,7 +1987,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
1794
1987
  releaseFetch();
1795
1988
  await new Promise((resolve) => setTimeout(resolve, 0));
1796
1989
  expect(finishSpy).not.toHaveBeenCalled();
1797
- expect(workspaceAccessor.transitionRatchetStateIfEnabled).not.toHaveBeenCalled();
1990
+ expect(workspaceRatchetService.transitionStateIfEnabled).not.toHaveBeenCalled();
1798
1991
  });
1799
1992
  });
1800
1993
  describe('checkWorkspaceById', () => {
@@ -1805,7 +1998,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
1805
1998
  });
1806
1999
  it('returns null when workspace not found', async () => {
1807
2000
  unsafeCoerce(ratchetService).isShuttingDown = false;
1808
- vi.mocked(workspaceAccessor.findForRatchetById).mockResolvedValue(null);
2001
+ vi.mocked(workspaceRatchetService.findCandidateById).mockResolvedValue(null);
1809
2002
  const result = await ratchetService.checkWorkspaceById('ws-nonexistent');
1810
2003
  expect(result).toBeNull();
1811
2004
  });
@@ -1824,7 +2017,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
1824
2017
  ratchetDispatchOutcome: null,
1825
2018
  ratchetDispatchRetryCount: 0,
1826
2019
  };
1827
- vi.mocked(workspaceAccessor.findForRatchetById).mockResolvedValue(workspace);
2020
+ vi.mocked(workspaceRatchetService.findCandidateById).mockResolvedValue(workspace);
1828
2021
  vi.mocked(mockGitHubBridge.extractPRInfo).mockReturnValue({
1829
2022
  owner: 'example',
1830
2023
  repo: 'repo',
@@ -1852,7 +2045,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
1852
2045
  ratchetDispatchOutcome: null,
1853
2046
  ratchetDispatchRetryCount: 0,
1854
2047
  };
1855
- vi.mocked(workspaceAccessor.findForRatchetById).mockResolvedValue(workspace);
2048
+ vi.mocked(workspaceRatchetService.findCandidateById).mockResolvedValue(workspace);
1856
2049
  vi.mocked(mockGitHubBridge.extractPRInfo).mockReturnValue({
1857
2050
  owner: 'example',
1858
2051
  repo: 'repo',
@@ -1895,7 +2088,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
1895
2088
  ratchetDispatchOutcome: null,
1896
2089
  ratchetDispatchRetryCount: 0,
1897
2090
  };
1898
- vi.mocked(workspaceAccessor.findForRatchetById).mockResolvedValue(workspace);
2091
+ vi.mocked(workspaceRatchetService.findCandidateById).mockResolvedValue(workspace);
1899
2092
  vi.mocked(mockGitHubBridge.extractPRInfo).mockReturnValue({
1900
2093
  owner: 'example',
1901
2094
  repo: 'repo',
@@ -1936,7 +2129,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
1936
2129
  ratchetDispatchOutcome: null,
1937
2130
  ratchetDispatchRetryCount: 0,
1938
2131
  };
1939
- vi.mocked(workspaceAccessor.findForRatchetById).mockResolvedValue(workspace);
2132
+ vi.mocked(workspaceRatchetService.findCandidateById).mockResolvedValue(workspace);
1940
2133
  vi.mocked(mockGitHubBridge.extractPRInfo).mockReturnValue({
1941
2134
  owner: 'example',
1942
2135
  repo: 'repo',
@@ -1968,7 +2161,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
1968
2161
  ratchetDispatchOutcome: null,
1969
2162
  ratchetDispatchRetryCount: 0,
1970
2163
  };
1971
- vi.mocked(workspaceAccessor.findForRatchetById).mockResolvedValue(workspace);
2164
+ vi.mocked(workspaceRatchetService.findCandidateById).mockResolvedValue(workspace);
1972
2165
  let releaseCheck;
1973
2166
  const checkBarrier = new Promise((resolve) => {
1974
2167
  releaseCheck = () => resolve();
@@ -2009,8 +2202,8 @@ describe('ratchet service (state-change + idle dispatch)', () => {
2009
2202
  makeWorkspace('blocker-3'),
2010
2203
  makeWorkspace('queued-target'),
2011
2204
  ];
2012
- vi.mocked(workspaceAccessor.findWithPRsForRatchet).mockResolvedValue(workspaces);
2013
- vi.mocked(workspaceAccessor.findForRatchetById).mockResolvedValue(workspaces[3]);
2205
+ vi.mocked(workspaceRatchetService.findCandidates).mockResolvedValue(workspaces);
2206
+ vi.mocked(workspaceRatchetService.findCandidateById).mockResolvedValue(workspaces[3]);
2014
2207
  let releaseBlockers;
2015
2208
  const blockerBarrier = new Promise((resolve) => {
2016
2209
  releaseBlockers = resolve;
@@ -2057,7 +2250,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
2057
2250
  makeWorkspace('timed-out-3'),
2058
2251
  makeWorkspace('after-timeouts'),
2059
2252
  ];
2060
- vi.mocked(workspaceAccessor.findWithPRsForRatchet).mockResolvedValue(workspaces);
2253
+ vi.mocked(workspaceRatchetService.findCandidates).mockResolvedValue(workspaces);
2061
2254
  let finishCleanup;
2062
2255
  const cleanupBarrier = new Promise((resolve) => {
2063
2256
  finishCleanup = resolve;
@@ -2103,8 +2296,8 @@ describe('ratchet service (state-change + idle dispatch)', () => {
2103
2296
  makeWorkspace('batch-blocker-3'),
2104
2297
  ];
2105
2298
  const directWorkspace = makeWorkspace('direct-target');
2106
- vi.mocked(workspaceAccessor.findWithPRsForRatchet).mockResolvedValue(batchWorkspaces);
2107
- vi.mocked(workspaceAccessor.findForRatchetById).mockResolvedValue(directWorkspace);
2299
+ vi.mocked(workspaceRatchetService.findCandidates).mockResolvedValue(batchWorkspaces);
2300
+ vi.mocked(workspaceRatchetService.findCandidateById).mockResolvedValue(directWorkspace);
2108
2301
  let releaseBatch;
2109
2302
  const batchBarrier = new Promise((resolve) => {
2110
2303
  releaseBatch = resolve;
@@ -2138,7 +2331,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
2138
2331
  describe('decideRatchetAction edge cases', () => {
2139
2332
  const callDecide = (context) => unsafeCoerce(ratchetService).decideRatchetAction(context);
2140
2333
  const arrangeOtherWorkingSession = () => {
2141
- vi.mocked(agentSessionAccessor.findByWorkspaceId).mockResolvedValue([
2334
+ vi.mocked(mockSessionBridge.findSessionsByWorkspaceId).mockResolvedValue([
2142
2335
  { id: 'other-session' },
2143
2336
  ]);
2144
2337
  vi.mocked(mockSessionBridge.isSessionWorking).mockReturnValue(true);
@@ -2268,7 +2461,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
2268
2461
  expect(result).toEqual({ kind: 'none' });
2269
2462
  });
2270
2463
  it('settles a non-RUNNING session as COMPLETED when its status is not FAILED', async () => {
2271
- vi.mocked(agentSessionAccessor.findById).mockResolvedValue({
2464
+ vi.mocked(mockSessionBridge.findSessionById).mockResolvedValue({
2272
2465
  id: 'completed-session',
2273
2466
  provider: 'CLAUDE',
2274
2467
  status: SessionStatus.IDLE,
@@ -2278,10 +2471,10 @@ describe('ratchet service (state-change + idle dispatch)', () => {
2278
2471
  ratchetActiveSessionId: 'completed-session',
2279
2472
  });
2280
2473
  expect(result).toEqual({ kind: 'settled', outcome: 'COMPLETED' });
2281
- expect(workspaceAccessor.recordRatchetSessionEnd).toHaveBeenCalledWith('ws-3', 'completed-session', 'COMPLETED');
2474
+ expect(mockWorkspaceBridge.recordSessionEnd).toHaveBeenCalledWith('ws-3', 'completed-session', 'COMPLETED');
2282
2475
  });
2283
2476
  it('settles a FAILED session as DIED', async () => {
2284
- vi.mocked(agentSessionAccessor.findById).mockResolvedValue({
2477
+ vi.mocked(mockSessionBridge.findSessionById).mockResolvedValue({
2285
2478
  id: 'failed-session',
2286
2479
  provider: 'CLAUDE',
2287
2480
  status: SessionStatus.FAILED,
@@ -2291,10 +2484,10 @@ describe('ratchet service (state-change + idle dispatch)', () => {
2291
2484
  ratchetActiveSessionId: 'failed-session',
2292
2485
  });
2293
2486
  expect(result).toEqual({ kind: 'settled', outcome: 'DIED' });
2294
- expect(workspaceAccessor.recordRatchetSessionEnd).toHaveBeenCalledWith('ws-4', 'failed-session', 'DIED');
2487
+ expect(mockWorkspaceBridge.recordSessionEnd).toHaveBeenCalledWith('ws-4', 'failed-session', 'DIED');
2295
2488
  });
2296
2489
  it('settles a provider-mismatched session as DIED and stops it', async () => {
2297
- vi.mocked(agentSessionAccessor.findById).mockResolvedValue({
2490
+ vi.mocked(mockSessionBridge.findSessionById).mockResolvedValue({
2298
2491
  id: 'codex-session',
2299
2492
  provider: 'CODEX',
2300
2493
  status: SessionStatus.RUNNING,
@@ -2307,11 +2500,11 @@ describe('ratchet service (state-change + idle dispatch)', () => {
2307
2500
  ratchetSessionProvider: 'WORKSPACE_DEFAULT',
2308
2501
  });
2309
2502
  expect(result).toEqual({ kind: 'settled', outcome: 'DIED' });
2310
- expect(workspaceAccessor.recordRatchetSessionEnd).toHaveBeenCalledWith('ws-5', 'codex-session', 'DIED');
2503
+ expect(mockWorkspaceBridge.recordSessionEnd).toHaveBeenCalledWith('ws-5', 'codex-session', 'DIED');
2311
2504
  expect(mockSessionBridge.stopSession).toHaveBeenCalledWith('codex-session');
2312
2505
  });
2313
2506
  it('returns the active fixer when the session is working', async () => {
2314
- vi.mocked(agentSessionAccessor.findById).mockResolvedValue({
2507
+ vi.mocked(mockSessionBridge.findSessionById).mockResolvedValue({
2315
2508
  id: 'working-session',
2316
2509
  provider: 'CLAUDE',
2317
2510
  status: SessionStatus.RUNNING,
@@ -2326,28 +2519,111 @@ describe('ratchet service (state-change + idle dispatch)', () => {
2326
2519
  kind: 'active',
2327
2520
  action: { type: 'FIXER_ACTIVE', sessionId: 'working-session' },
2328
2521
  });
2329
- expect(workspaceAccessor.recordRatchetSessionEnd).not.toHaveBeenCalled();
2522
+ expect(mockWorkspaceBridge.recordSessionEnd).not.toHaveBeenCalled();
2330
2523
  });
2331
2524
  it('does not settle or stop a fixer after cancellation during session lookup', async () => {
2332
2525
  const controller = new AbortController();
2333
2526
  const timeoutError = new Error('Workspace check timed out');
2334
2527
  let finishLookup;
2335
- vi.mocked(agentSessionAccessor.findById).mockImplementation(() => new Promise((resolve) => {
2528
+ vi.mocked(mockSessionBridge.findSessionById).mockImplementation(() => new Promise((resolve) => {
2336
2529
  finishLookup = resolve;
2337
2530
  }));
2338
2531
  const check = unsafeCoerce(ratchetService).checkActiveFixerSession({
2339
2532
  id: 'ws-cancelled-active-check',
2340
2533
  ratchetActiveSessionId: 'session-1',
2341
2534
  }, controller.signal);
2342
- await vi.waitFor(() => expect(agentSessionAccessor.findById).toHaveBeenCalled());
2535
+ await vi.waitFor(() => expect(mockSessionBridge.findSessionById).toHaveBeenCalled());
2343
2536
  controller.abort(timeoutError);
2344
2537
  finishLookup(null);
2345
2538
  await expect(check).rejects.toBe(timeoutError);
2346
- expect(workspaceAccessor.recordRatchetSessionEnd).not.toHaveBeenCalled();
2539
+ expect(mockWorkspaceBridge.recordSessionEnd).not.toHaveBeenCalled();
2347
2540
  expect(mockSessionBridge.stopSession).not.toHaveBeenCalled();
2348
2541
  });
2542
+ it('publishes a successful fallback settlement before observing post-write cancellation', async () => {
2543
+ const controller = new AbortController();
2544
+ const timeoutError = new Error('Workspace check timed out');
2545
+ vi.mocked(mockSessionBridge.findSessionById).mockResolvedValue(null);
2546
+ vi.mocked(mockWorkspaceBridge.recordSessionEnd).mockImplementation(() => {
2547
+ controller.abort(timeoutError);
2548
+ return Promise.resolve(true);
2549
+ });
2550
+ const events = [];
2551
+ ratchetService.on(RATCHET_DISPATCH_CHANGED, (event) => {
2552
+ events.push(event);
2553
+ });
2554
+ const check = unsafeCoerce(ratchetService).checkActiveFixerSession({
2555
+ id: 'ws-cancelled-after-settlement',
2556
+ ratchetActiveSessionId: 'session-1',
2557
+ ratchetDispatchRetryCount: 2,
2558
+ }, controller.signal);
2559
+ await expect(check).rejects.toBe(timeoutError);
2560
+ expect(events).toEqual([{ workspaceId: 'ws-cancelled-after-settlement' }]);
2561
+ });
2349
2562
  });
2350
2563
  describe('triggerFixer error handling', () => {
2564
+ it('commits the workspace check as soon as the fixer session starts', async () => {
2565
+ const commitSideEffects = vi.fn();
2566
+ vi.mocked(fixerSessionService.acquireAndDispatch).mockImplementation(async (input) => {
2567
+ await input.afterStart?.({ sessionId: 'started-session', prompt: 'prompt' });
2568
+ return {
2569
+ status: 'started',
2570
+ sessionId: 'started-session',
2571
+ promptSent: true,
2572
+ };
2573
+ });
2574
+ const result = await unsafeCoerce(ratchetService).triggerFixer({
2575
+ id: 'ws-started-dispatch',
2576
+ prUrl: 'https://github.com/example/repo/pull/20',
2577
+ }, {
2578
+ ciStatus: CIStatus.FAILURE,
2579
+ snapshotKey: 'failed:20',
2580
+ prNumber: 20,
2581
+ reviewComments: [],
2582
+ hasMergeConflict: false,
2583
+ }, 0, new AbortController().signal, commitSideEffects);
2584
+ expect(result).toMatchObject({
2585
+ type: 'TRIGGERED_FIXER',
2586
+ sessionId: 'started-session',
2587
+ });
2588
+ expect(commitSideEffects).toHaveBeenCalledTimes(2);
2589
+ });
2590
+ it('cleans up a fixer when cancellation races with session startup', async () => {
2591
+ const controller = new AbortController();
2592
+ const timeoutError = new Error('Workspace check timed out');
2593
+ const commitSideEffects = vi.fn();
2594
+ vi.mocked(fixerSessionService.acquireAndDispatch).mockImplementation(async (input) => {
2595
+ controller.abort(timeoutError);
2596
+ try {
2597
+ await input.afterStart?.({ sessionId: 'cancelled-startup-session', prompt: 'prompt' });
2598
+ return {
2599
+ status: 'started',
2600
+ sessionId: 'cancelled-startup-session',
2601
+ promptSent: true,
2602
+ };
2603
+ }
2604
+ catch (error) {
2605
+ return {
2606
+ status: 'error',
2607
+ error: error instanceof Error ? error.message : String(error),
2608
+ };
2609
+ }
2610
+ });
2611
+ vi.mocked(mockSessionBridge.isSessionRunning).mockReturnValue(true);
2612
+ const trigger = unsafeCoerce(ratchetService).triggerFixer({
2613
+ id: 'ws-cancelled-startup',
2614
+ prUrl: 'https://github.com/example/repo/pull/20',
2615
+ }, {
2616
+ ciStatus: CIStatus.FAILURE,
2617
+ snapshotKey: 'failed:20',
2618
+ prNumber: 20,
2619
+ reviewComments: [],
2620
+ hasMergeConflict: false,
2621
+ }, 0, controller.signal, commitSideEffects);
2622
+ await expect(trigger).rejects.toBe(timeoutError);
2623
+ expect(commitSideEffects).toHaveBeenCalledTimes(1);
2624
+ expect(workspaceRatchetService.recordSessionEnd).toHaveBeenCalledWith('ws-cancelled-startup', 'cancelled-startup-session', 'COMPLETED');
2625
+ expect(mockSessionBridge.stopSession).toHaveBeenCalledWith('cancelled-startup-session');
2626
+ });
2351
2627
  it('does not clean up a fixer after its dispatch record is persisted', async () => {
2352
2628
  const controller = new AbortController();
2353
2629
  const timeoutError = new Error('Workspace check timed out');
@@ -2357,11 +2633,15 @@ describe('ratchet service (state-change + idle dispatch)', () => {
2357
2633
  sessionId: 'cancelled-session',
2358
2634
  promptSent: true,
2359
2635
  });
2360
- vi.mocked(workspaceAccessor.recordRatchetDispatchIfEnabled).mockImplementation(() => new Promise((resolve) => {
2636
+ vi.mocked(workspaceRatchetService.recordDispatchIfEnabled).mockImplementation(() => new Promise((resolve) => {
2361
2637
  finishRecord = resolve;
2362
2638
  }));
2363
2639
  vi.mocked(mockSessionBridge.isSessionRunning).mockReturnValue(true);
2364
2640
  const commitSideEffects = vi.fn();
2641
+ const events = [];
2642
+ ratchetService.on(RATCHET_DISPATCH_CHANGED, (event) => {
2643
+ events.push(event);
2644
+ });
2365
2645
  const trigger = unsafeCoerce(ratchetService).triggerFixer({
2366
2646
  id: 'ws-cancelled-dispatch',
2367
2647
  prUrl: 'https://github.com/example/repo/pull/20',
@@ -2372,22 +2652,134 @@ describe('ratchet service (state-change + idle dispatch)', () => {
2372
2652
  reviewComments: [],
2373
2653
  hasMergeConflict: false,
2374
2654
  }, 0, controller.signal, commitSideEffects);
2375
- await vi.waitFor(() => expect(workspaceAccessor.recordRatchetDispatchIfEnabled).toHaveBeenCalled());
2655
+ await vi.waitFor(() => expect(workspaceRatchetService.recordDispatchIfEnabled).toHaveBeenCalled());
2376
2656
  controller.abort(timeoutError);
2377
2657
  finishRecord(true);
2378
2658
  await expect(trigger).rejects.toBe(timeoutError);
2379
2659
  expect(commitSideEffects).toHaveBeenCalledTimes(1);
2380
- expect(workspaceAccessor.recordRatchetSessionEnd).not.toHaveBeenCalled();
2660
+ expect(workspaceRatchetService.recordSessionEnd).not.toHaveBeenCalled();
2661
+ expect(mockSessionBridge.stopSession).not.toHaveBeenCalled();
2662
+ expect(events).toEqual([{ workspaceId: 'ws-cancelled-dispatch' }]);
2663
+ });
2664
+ it('persists and commits a dispatch while prompt completion is pending', async () => {
2665
+ let finishPrompt;
2666
+ const promptCompletion = new Promise((resolve) => {
2667
+ finishPrompt = resolve;
2668
+ });
2669
+ let finishRecord;
2670
+ vi.mocked(fixerSessionService.acquireAndDispatch).mockResolvedValue({
2671
+ status: 'started',
2672
+ sessionId: 'pending-prompt-session',
2673
+ promptSent: true,
2674
+ promptCompletion,
2675
+ });
2676
+ vi.mocked(workspaceRatchetService.recordDispatchIfEnabled).mockImplementation(() => new Promise((resolve) => {
2677
+ finishRecord = resolve;
2678
+ }));
2679
+ const commitSideEffects = vi.fn();
2680
+ const trigger = unsafeCoerce(ratchetService).triggerFixer({
2681
+ id: 'ws-pending-prompt',
2682
+ prUrl: 'https://github.com/example/repo/pull/20',
2683
+ }, {
2684
+ ciStatus: CIStatus.FAILURE,
2685
+ snapshotKey: 'failed:20',
2686
+ prNumber: 20,
2687
+ reviewComments: [],
2688
+ hasMergeConflict: false,
2689
+ }, 0, new AbortController().signal, commitSideEffects);
2690
+ await vi.waitFor(() => expect(workspaceRatchetService.recordDispatchIfEnabled).toHaveBeenCalled());
2691
+ expect(commitSideEffects).toHaveBeenCalledTimes(1);
2692
+ finishRecord(true);
2693
+ await expect(trigger).resolves.toMatchObject({ type: 'TRIGGERED_FIXER' });
2694
+ expect(commitSideEffects).toHaveBeenCalledTimes(1);
2695
+ finishPrompt(true);
2696
+ await promptCompletion;
2697
+ });
2698
+ it('settles a persisted dispatch as died when prompt completion fails', async () => {
2699
+ vi.mocked(fixerSessionService.acquireAndDispatch).mockResolvedValue({
2700
+ status: 'started',
2701
+ sessionId: 'failed-prompt-session',
2702
+ promptSent: true,
2703
+ promptCompletion: Promise.resolve(false),
2704
+ });
2705
+ vi.mocked(mockSessionBridge.isSessionRunning).mockReturnValue(true);
2706
+ const result = await unsafeCoerce(ratchetService).triggerFixer({
2707
+ id: 'ws-failed-prompt',
2708
+ prUrl: 'https://github.com/example/repo/pull/20',
2709
+ }, {
2710
+ ciStatus: CIStatus.FAILURE,
2711
+ snapshotKey: 'failed:20',
2712
+ prNumber: 20,
2713
+ reviewComments: [],
2714
+ hasMergeConflict: false,
2715
+ }, 0);
2716
+ expect(result).toMatchObject({ type: 'TRIGGERED_FIXER' });
2717
+ await vi.waitFor(() => expect(workspaceRatchetService.recordSessionEnd).toHaveBeenCalledWith('ws-failed-prompt', 'failed-prompt-session', 'DIED'));
2718
+ expect(mockSessionBridge.stopSession).toHaveBeenCalledWith('failed-prompt-session');
2719
+ });
2720
+ it('does not stop a newer active session when an old prompt completion fails', async () => {
2721
+ vi.mocked(fixerSessionService.acquireAndDispatch).mockResolvedValue({
2722
+ status: 'started',
2723
+ sessionId: 'stale-prompt-session',
2724
+ promptSent: true,
2725
+ promptCompletion: Promise.resolve(false),
2726
+ });
2727
+ vi.mocked(workspaceRatchetService.recordSessionEnd).mockResolvedValue(false);
2728
+ vi.mocked(mockSessionBridge.isSessionRunning).mockReturnValue(true);
2729
+ await unsafeCoerce(ratchetService).triggerFixer({
2730
+ id: 'ws-replaced-prompt',
2731
+ prUrl: 'https://github.com/example/repo/pull/20',
2732
+ }, {
2733
+ ciStatus: CIStatus.FAILURE,
2734
+ snapshotKey: 'failed:20',
2735
+ prNumber: 20,
2736
+ reviewComments: [],
2737
+ hasMergeConflict: false,
2738
+ }, 0);
2739
+ await vi.waitFor(() => expect(workspaceRatchetService.recordSessionEnd).toHaveBeenCalled());
2381
2740
  expect(mockSessionBridge.stopSession).not.toHaveBeenCalled();
2382
2741
  });
2742
+ it('cleans up a fixer through prompt failure after its dispatch record is persisted', async () => {
2743
+ const controller = new AbortController();
2744
+ const timeoutError = new Error('Workspace check timed out');
2745
+ let finishRecord;
2746
+ vi.mocked(fixerSessionService.acquireAndDispatch).mockResolvedValue({
2747
+ status: 'started',
2748
+ sessionId: 'cancelled-session',
2749
+ promptSent: true,
2750
+ promptCompletion: Promise.resolve(false),
2751
+ });
2752
+ vi.mocked(workspaceRatchetService.recordDispatchIfEnabled).mockImplementation(() => new Promise((resolve) => {
2753
+ finishRecord = resolve;
2754
+ }));
2755
+ vi.mocked(mockSessionBridge.isSessionRunning).mockReturnValue(true);
2756
+ const commitSideEffects = vi.fn();
2757
+ const trigger = unsafeCoerce(ratchetService).triggerFixer({
2758
+ id: 'ws-cancelled-dispatch',
2759
+ prUrl: 'https://github.com/example/repo/pull/20',
2760
+ }, {
2761
+ ciStatus: CIStatus.FAILURE,
2762
+ snapshotKey: 'failed:20',
2763
+ prNumber: 20,
2764
+ reviewComments: [],
2765
+ hasMergeConflict: false,
2766
+ }, 0, controller.signal, commitSideEffects);
2767
+ await vi.waitFor(() => expect(workspaceRatchetService.recordDispatchIfEnabled).toHaveBeenCalled());
2768
+ controller.abort(timeoutError);
2769
+ finishRecord(true);
2770
+ await expect(trigger).rejects.toBe(timeoutError);
2771
+ expect(commitSideEffects).toHaveBeenCalledTimes(1);
2772
+ await vi.waitFor(() => expect(workspaceRatchetService.recordSessionEnd).toHaveBeenCalledWith('ws-cancelled-dispatch', 'cancelled-session', 'DIED'));
2773
+ expect(mockSessionBridge.stopSession).toHaveBeenCalledWith('cancelled-session');
2774
+ });
2383
2775
  it('cleans up a started fixer when dispatch persistence fails', async () => {
2384
2776
  vi.mocked(fixerSessionService.acquireAndDispatch).mockResolvedValue({
2385
2777
  status: 'started',
2386
2778
  sessionId: 'unrecorded-session',
2387
2779
  promptSent: true,
2388
2780
  });
2389
- vi.mocked(workspaceAccessor.recordRatchetDispatchIfEnabled).mockRejectedValue(new Error('dispatch record write failed'));
2390
- vi.mocked(workspaceAccessor.recordRatchetSessionEnd).mockRejectedValue(new Error('dispatch cleanup write failed'));
2781
+ vi.mocked(workspaceRatchetService.recordDispatchIfEnabled).mockRejectedValue(new Error('dispatch record write failed'));
2782
+ vi.mocked(workspaceRatchetService.recordSessionEnd).mockRejectedValue(new Error('dispatch cleanup write failed'));
2391
2783
  vi.mocked(mockSessionBridge.isSessionRunning).mockReturnValue(true);
2392
2784
  const commitSideEffects = vi.fn();
2393
2785
  const result = await unsafeCoerce(ratchetService).triggerFixer({
@@ -2402,7 +2794,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
2402
2794
  }, 0, new AbortController().signal, commitSideEffects);
2403
2795
  expect(result).toMatchObject({ type: 'ERROR', error: 'dispatch record write failed' });
2404
2796
  expect(commitSideEffects).toHaveBeenCalledTimes(1);
2405
- expect(workspaceAccessor.recordRatchetSessionEnd).toHaveBeenCalledWith('ws-unrecorded-dispatch', 'unrecorded-session', 'COMPLETED');
2797
+ expect(workspaceRatchetService.recordSessionEnd).toHaveBeenCalledWith('ws-unrecorded-dispatch', 'unrecorded-session', 'COMPLETED');
2406
2798
  expect(mockSessionBridge.stopSession).toHaveBeenCalledWith('unrecorded-session');
2407
2799
  });
2408
2800
  it('handles acquireAndDispatch throwing an error', async () => {
@@ -2439,13 +2831,16 @@ describe('ratchet service (state-change + idle dispatch)', () => {
2439
2831
  ratchetLastCiRunId: null,
2440
2832
  prReviewLastCheckedAt: null,
2441
2833
  ratchetDispatchOutcome: null,
2442
- ratchetDispatchRetryCount: 0,
2834
+ ratchetDispatchRetryCount: 2,
2443
2835
  };
2444
2836
  vi.mocked(fixerSessionService.acquireAndDispatch).mockResolvedValue({
2445
2837
  status: 'already_active',
2446
2838
  sessionId: 'existing-session',
2447
2839
  });
2448
- vi.mocked(workspaceAccessor.update).mockResolvedValue({});
2840
+ const events = [];
2841
+ ratchetService.on(RATCHET_DISPATCH_CHANGED, (event) => {
2842
+ events.push(event);
2843
+ });
2449
2844
  const result = await unsafeCoerce(ratchetService).triggerFixer(workspace, {
2450
2845
  ciStatus: CIStatus.FAILURE,
2451
2846
  prNumber: 21,
@@ -2454,8 +2849,9 @@ describe('ratchet service (state-change + idle dispatch)', () => {
2454
2849
  type: 'FIXER_ACTIVE',
2455
2850
  sessionId: 'existing-session',
2456
2851
  });
2457
- expect(workspaceAccessor.adoptRatchetActiveSessionIfEnabled).toHaveBeenCalledWith('ws-already-active', 'existing-session');
2458
- expect(workspaceAccessor.recordRatchetDispatchIfEnabled).not.toHaveBeenCalled();
2852
+ expect(workspaceRatchetService.adoptActiveSessionIfEnabled).toHaveBeenCalledWith('ws-already-active', 'existing-session');
2853
+ expect(workspaceRatchetService.recordDispatchIfEnabled).not.toHaveBeenCalled();
2854
+ expect(events).toEqual([{ workspaceId: 'ws-already-active' }]);
2459
2855
  });
2460
2856
  it('stops already-active fixer when active-session recording loses disable race', async () => {
2461
2857
  const workspace = {
@@ -2474,7 +2870,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
2474
2870
  status: 'already_active',
2475
2871
  sessionId: 'existing-session',
2476
2872
  });
2477
- vi.mocked(workspaceAccessor.adoptRatchetActiveSessionIfEnabled).mockResolvedValue(false);
2873
+ vi.mocked(workspaceRatchetService.adoptActiveSessionIfEnabled).mockResolvedValue(false);
2478
2874
  vi.mocked(mockSessionBridge.isSessionRunning).mockReturnValue(true);
2479
2875
  const result = await unsafeCoerce(ratchetService).triggerFixer(workspace, {
2480
2876
  ciStatus: CIStatus.FAILURE,
@@ -2518,12 +2914,13 @@ describe('ratchet service (state-change + idle dispatch)', () => {
2518
2914
  ratchetService.removeAllListeners();
2519
2915
  });
2520
2916
  it('emits ratchet_toggled when enabling workspace ratcheting', async () => {
2521
- vi.mocked(workspaceAccessor.findById).mockResolvedValue({
2917
+ vi.mocked(workspaceDataService.findById).mockResolvedValue({
2522
2918
  id: 'ws-enable',
2523
2919
  ratchetState: RatchetState.CI_FAILED,
2524
2920
  ratchetActiveSessionId: null,
2921
+ ratchetDispatchOutcome: 'DIED',
2922
+ ratchetDispatchRetryCount: 2,
2525
2923
  });
2526
- vi.mocked(workspaceAccessor.update).mockResolvedValue({});
2527
2924
  const toggledEvents = [];
2528
2925
  const stateEvents = [];
2529
2926
  ratchetService.on(RATCHET_TOGGLED, (event) => {
@@ -2533,7 +2930,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
2533
2930
  stateEvents.push(event);
2534
2931
  });
2535
2932
  await ratchetService.setWorkspaceRatcheting('ws-enable', true);
2536
- expect(workspaceAccessor.update).toHaveBeenCalledWith('ws-enable', { ratchetEnabled: true });
2933
+ expect(workspaceRatchetService.enable).toHaveBeenCalledWith('ws-enable');
2537
2934
  expect(toggledEvents).toEqual([
2538
2935
  {
2539
2936
  workspaceId: 'ws-enable',
@@ -2544,12 +2941,11 @@ describe('ratchet service (state-change + idle dispatch)', () => {
2544
2941
  expect(stateEvents).toHaveLength(0);
2545
2942
  });
2546
2943
  it('emits ratchet_toggled and ratchet_state_changed when disabling non-idle workspace', async () => {
2547
- vi.mocked(workspaceAccessor.findById).mockResolvedValue({
2944
+ vi.mocked(workspaceDataService.findById).mockResolvedValue({
2548
2945
  id: 'ws-disable',
2549
2946
  ratchetState: RatchetState.CI_RUNNING,
2550
2947
  ratchetActiveSessionId: null,
2551
2948
  });
2552
- vi.mocked(workspaceAccessor.update).mockResolvedValue({});
2553
2949
  const toggledEvents = [];
2554
2950
  const stateEvents = [];
2555
2951
  ratchetService.on(RATCHET_TOGGLED, (event) => {
@@ -2559,14 +2955,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
2559
2955
  stateEvents.push(event);
2560
2956
  });
2561
2957
  await ratchetService.setWorkspaceRatcheting('ws-disable', false);
2562
- expect(workspaceAccessor.update).toHaveBeenCalledWith('ws-disable', {
2563
- ratchetEnabled: false,
2564
- ratchetState: RatchetState.IDLE,
2565
- ratchetActiveSessionId: null,
2566
- ratchetLastCiRunId: null,
2567
- ratchetDispatchOutcome: null,
2568
- ratchetDispatchRetryCount: 0,
2569
- });
2958
+ expect(workspaceRatchetService.disable).toHaveBeenCalledWith('ws-disable');
2570
2959
  expect(stateEvents).toEqual([
2571
2960
  {
2572
2961
  workspaceId: 'ws-disable',
@@ -2583,12 +2972,11 @@ describe('ratchet service (state-change + idle dispatch)', () => {
2583
2972
  ]);
2584
2973
  });
2585
2974
  it('stops ratchet workflow sessions found after disabling workspace', async () => {
2586
- vi.mocked(workspaceAccessor.findById).mockResolvedValue({
2975
+ vi.mocked(workspaceDataService.findById).mockResolvedValue({
2587
2976
  id: 'ws-disable-raced-session',
2588
2977
  ratchetState: RatchetState.CI_RUNNING,
2589
2978
  ratchetActiveSessionId: null,
2590
2979
  });
2591
- vi.mocked(workspaceAccessor.update).mockResolvedValue({});
2592
2980
  vi.mocked(mockSessionBridge.findSessionsByWorkspaceId).mockResolvedValue([
2593
2981
  {
2594
2982
  id: 'raced-ratchet-session',
@@ -2625,7 +3013,6 @@ describe('ratchet service (state-change + idle dispatch)', () => {
2625
3013
  ratchetDispatchOutcome: null,
2626
3014
  ratchetDispatchRetryCount: 0,
2627
3015
  };
2628
- vi.mocked(workspaceAccessor.update).mockResolvedValue({});
2629
3016
  const events = [];
2630
3017
  ratchetService.on(RATCHET_STATE_CHANGED, (event) => {
2631
3018
  events.push(event);
@@ -2651,7 +3038,6 @@ describe('ratchet service (state-change + idle dispatch)', () => {
2651
3038
  ratchetDispatchOutcome: null,
2652
3039
  ratchetDispatchRetryCount: 0,
2653
3040
  };
2654
- vi.mocked(workspaceAccessor.update).mockResolvedValue({});
2655
3041
  const events = [];
2656
3042
  ratchetService.on(RATCHET_STATE_CHANGED, (event) => {
2657
3043
  events.push(event);
@@ -2681,8 +3067,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
2681
3067
  prState: 'OPEN',
2682
3068
  prNumber: 32,
2683
3069
  });
2684
- vi.mocked(workspaceAccessor.update).mockResolvedValue({});
2685
- vi.mocked(agentSessionAccessor.findByWorkspaceId).mockResolvedValue([]);
3070
+ vi.mocked(mockSessionBridge.findSessionsByWorkspaceId).mockResolvedValue([]);
2686
3071
  vi.mocked(fixerSessionService.acquireAndDispatch).mockResolvedValue({
2687
3072
  status: 'started',
2688
3073
  sessionId: 'ratchet-session-32',
@@ -2723,8 +3108,7 @@ describe('ratchet service (state-change + idle dispatch)', () => {
2723
3108
  prState: 'OPEN',
2724
3109
  prNumber: 33,
2725
3110
  });
2726
- vi.mocked(workspaceAccessor.update).mockResolvedValue({});
2727
- vi.mocked(agentSessionAccessor.findByWorkspaceId).mockResolvedValue([]);
3111
+ vi.mocked(mockSessionBridge.findSessionsByWorkspaceId).mockResolvedValue([]);
2728
3112
  vi.mocked(fixerSessionService.acquireAndDispatch).mockResolvedValue({
2729
3113
  status: 'started',
2730
3114
  sessionId: 'ratchet-session-33',
@@ -2751,7 +3135,6 @@ describe('ratchet service (state-change + idle dispatch)', () => {
2751
3135
  ratchetDispatchRetryCount: 0,
2752
3136
  };
2753
3137
  vi.spyOn(unsafeCoerce(ratchetService), 'fetchPRState').mockResolvedValue(null);
2754
- vi.mocked(workspaceAccessor.update).mockResolvedValue({});
2755
3138
  const events = [];
2756
3139
  ratchetService.on(RATCHET_STATE_CHANGED, (event) => {
2757
3140
  events.push(event);