specrails-desktop 2.36.0 → 2.42.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (510) hide show
  1. package/README.md +94 -247
  2. package/client/dist/assets/ActivityFeedPage-DoEMumQS.js +1 -0
  3. package/client/dist/assets/AgentBrowserCapture-DIh4K0gh.js +1 -0
  4. package/client/dist/assets/AgentModeAnalyticsPane-mbq4WEoO.js +2 -0
  5. package/client/dist/assets/AgentModeCodePane-CKh7zuA4.js +2 -0
  6. package/client/dist/assets/AgentModeJobsPane-BDokPiLJ.js +1 -0
  7. package/client/dist/assets/AgentsPage-BFVAZbBj.js +87 -0
  8. package/client/dist/assets/AnalyticsPage-3Y9LuWwz.js +1 -0
  9. package/client/dist/assets/CodePage-C9KyuV_C.js +3 -0
  10. package/client/dist/assets/DesktopAnalyticsPage-Bhi54bXQ.js +1 -0
  11. package/client/dist/assets/{DocsDialog-C76VdBJC.js → DocsDialog-Dj6mt4ga.js} +2 -2
  12. package/client/dist/assets/{DocsPage-ziMlj6B6.js → DocsPage-24yWglNI.js} +1 -1
  13. package/client/dist/assets/ExportDropdown-ophapHrT.js +1 -0
  14. package/client/dist/assets/InteractiveJobComposer-C1ucmxQh.js +19 -0
  15. package/client/dist/assets/JobDetailModal-DNWmgVHD.js +1 -0
  16. package/client/dist/assets/JobDetailPage-BcajZyuu.js +1 -0
  17. package/client/dist/assets/JobsPage-B9nTZw6e.js +1 -0
  18. package/client/dist/assets/LoopBuilderPage-Oc48iOFW.js +7 -0
  19. package/client/dist/assets/LoopPreviewModal-ae0Fr6SU.js +1 -0
  20. package/client/dist/assets/LoopsPage-CUEqzUBI.js +1 -0
  21. package/client/dist/assets/MinimizedChatsContext-Deg39peL.js +1 -0
  22. package/client/dist/assets/PluginsPage-C1xtARIx.js +2 -0
  23. package/client/dist/assets/ProjectSettingsDialog-JZzrXFBN.js +1 -0
  24. package/client/dist/assets/RepositoryDeliveries-CSDsiVUz.js +5 -0
  25. package/client/dist/assets/RepositoryScopeSelector-D-RCaknl.js +1 -0
  26. package/client/dist/assets/ReviewPacketPage-x5EfGTiL.js +1 -0
  27. package/client/dist/assets/TemplatePreviewModal-BSyuZxGq.js +1 -0
  28. package/client/dist/assets/TicketDetailModalContext-DqyF0so-.js +14 -0
  29. package/client/dist/assets/Trans-SnMX4MhW.js +1 -0
  30. package/client/dist/assets/agent-BdT0SB1D.js +1 -0
  31. package/client/dist/assets/agent-Bh9K7iEt.js +1 -0
  32. package/client/dist/assets/agent-C4ibdFk9.js +1 -0
  33. package/client/dist/assets/agent-CSFY22Zo.js +1 -0
  34. package/client/dist/assets/agent-DAnqxUn8.js +1 -0
  35. package/client/dist/assets/agent-DTQiu0Mi.js +1 -0
  36. package/client/dist/assets/agent-T54WuR_Y.js +1 -0
  37. package/client/dist/assets/agent-i75WDZOA.js +1 -0
  38. package/client/dist/assets/browser-05vRDg_y.js +1 -0
  39. package/client/dist/assets/browser-Bulb-cB1.js +1 -0
  40. package/client/dist/assets/browser-C7f-Jsg1.js +1 -0
  41. package/client/dist/assets/browser-CG0PE1j_.js +1 -0
  42. package/client/dist/assets/browser-CMzaqAjo.js +1 -0
  43. package/client/dist/assets/browser-DMajYdNX.js +1 -0
  44. package/client/dist/assets/browser-DxcOHrdP.js +1 -0
  45. package/client/dist/assets/browser-ObE7xVo3.js +1 -0
  46. package/client/dist/assets/builder-765NeYTp.js +1 -0
  47. package/client/dist/assets/builder-8MG3V6ea.js +1 -0
  48. package/client/dist/assets/builder-B-1UBs5K.js +1 -0
  49. package/client/dist/assets/builder-BTiGnPT0.js +1 -0
  50. package/client/dist/assets/builder-Cx9Rz-7u.js +1 -0
  51. package/client/dist/assets/builder-DKFMELBl.js +1 -0
  52. package/client/dist/assets/builder-OcmKrC0h.js +1 -0
  53. package/client/dist/assets/builder-P9qVBXFZ.js +1 -0
  54. package/client/dist/assets/{button-CJqFnUOL.js → button-DCBqEaZl.js} +1 -1
  55. package/client/dist/assets/{code-CkUuW4m9.js → code-B37GRg9C.js} +1 -1
  56. package/client/dist/assets/{code-B0O8-p8k.js → code-BBOEZbf9.js} +1 -1
  57. package/client/dist/assets/{code-B1VLZDhS.js → code-BRm-jcyx.js} +1 -1
  58. package/client/dist/assets/{code-Bpj4Ddml.js → code-CF7w62CR.js} +1 -1
  59. package/client/dist/assets/{code-BykBZ5-e.js → code-CLuvJt2r.js} +1 -1
  60. package/client/dist/assets/{code-B86IMAfz.js → code-D0RCm59f.js} +1 -1
  61. package/client/dist/assets/code-DaZ-ZwCT.js +1 -0
  62. package/client/dist/assets/{code-cAqaqMTx.js → code-iIHkGaCL.js} +1 -1
  63. package/client/dist/assets/commands-0XjAftla.js +1 -0
  64. package/client/dist/assets/commands-BAWSYHjQ.js +1 -0
  65. package/client/dist/assets/commands-BBwowgiE.js +1 -0
  66. package/client/dist/assets/commands-BacjIZLN.js +1 -0
  67. package/client/dist/assets/commands-Bs62IAZ3.js +1 -0
  68. package/client/dist/assets/commands-CLPdh-Hh.js +1 -0
  69. package/client/dist/assets/commands-DlbFzgrp.js +1 -0
  70. package/client/dist/assets/commands-LjPSsi5F.js +1 -0
  71. package/client/dist/assets/common-B5AZNYMH.js +1 -0
  72. package/client/dist/assets/common-BFZ0c_vN.js +1 -0
  73. package/client/dist/assets/common-BrlwEnL7.js +1 -0
  74. package/client/dist/assets/common-BttQx3z4.js +1 -0
  75. package/client/dist/assets/common-CM65k_-e.js +1 -0
  76. package/client/dist/assets/common-D4mvFFlu.js +1 -0
  77. package/client/dist/assets/common-TZ9Ny96S.js +1 -0
  78. package/client/dist/assets/common-nFpSF4GC.js +1 -0
  79. package/client/dist/assets/dashboard-B14uYXkG.js +1 -0
  80. package/client/dist/assets/dashboard-BK_mez-z.js +1 -0
  81. package/client/dist/assets/dashboard-BfBir_6o.js +1 -0
  82. package/client/dist/assets/dashboard-Bt0cCzeG.js +1 -0
  83. package/client/dist/assets/dashboard-BwkjxI6H.js +1 -0
  84. package/client/dist/assets/{dashboard-C8WOEiPu.js → dashboard-C3bDKf7s.js} +1 -1
  85. package/client/dist/assets/dashboard-CdvjGfog.js +1 -0
  86. package/client/dist/assets/dashboard-fRrP0Kv0.js +1 -0
  87. package/client/dist/assets/dialog-SRw01_QU.js +45 -0
  88. package/client/dist/assets/dist-js-CJ_2XX1Y.js +1 -0
  89. package/client/dist/assets/formatDistanceToNow-DSj5DprF.js +1 -0
  90. package/client/dist/assets/getTimezoneOffsetInMilliseconds-YhD8rIEs.js +1 -0
  91. package/client/dist/assets/index-DwAmL7m5.css +2 -0
  92. package/client/dist/assets/index-EzrkUb8B.js +76 -0
  93. package/client/dist/assets/{jira-api-B1-MUehg.js → jira-api-CSCqGr-Q.js} +1 -1
  94. package/client/dist/assets/{jobs-CN_zv4Gr.js → jobs-B8rrzfyZ.js} +1 -1
  95. package/client/dist/assets/{jobs-DUlWSYq2.js → jobs-BS6RTurf.js} +1 -1
  96. package/client/dist/assets/{jobs-Bpks6doU.js → jobs-BTT0Bsks.js} +1 -1
  97. package/client/dist/assets/{jobs-Bgq-PZkC.js → jobs-CezU69AE.js} +1 -1
  98. package/client/dist/assets/{jobs-SwYS2M-B.js → jobs-ClFJae0s.js} +1 -1
  99. package/client/dist/assets/{jobs-BAls3bWq.js → jobs-DJSFIFVy.js} +1 -1
  100. package/client/dist/assets/{jobs-DhxKgWFq.js → jobs-DhgGr8vm.js} +1 -1
  101. package/client/dist/assets/{jobs-B_TeSQxb.js → jobs-DzMjUcaN.js} +1 -1
  102. package/client/dist/assets/mcp-6rMoZfEO.js +1 -0
  103. package/client/dist/assets/mcp-BD8sL5mP.js +1 -0
  104. package/client/dist/assets/mcp-BkcA3I5s.js +1 -0
  105. package/client/dist/assets/mcp-CCpSelOh.js +1 -0
  106. package/client/dist/assets/mcp-CUAN6ORK.js +1 -0
  107. package/client/dist/assets/mcp-CqbRxRTE.js +1 -0
  108. package/client/dist/assets/mcp-DP2YfVhO.js +1 -0
  109. package/client/dist/assets/mcp-DUVQamDz.js +1 -0
  110. package/client/dist/assets/narration-B-ynWTpn.js +1 -0
  111. package/client/dist/assets/narration-Bj_laZwg.js +1 -0
  112. package/client/dist/assets/narration-BxHpmMv_.js +1 -0
  113. package/client/dist/assets/narration-C1Px0-0j.js +1 -0
  114. package/client/dist/assets/narration-CAXhGbzM.js +1 -0
  115. package/client/dist/assets/narration-DQ1l_Kq6.js +1 -0
  116. package/client/dist/assets/narration-XISXwqZd.js +1 -0
  117. package/client/dist/assets/narration-kwzfglQo.js +1 -0
  118. package/client/dist/assets/nav-1-Hh2kOz.js +1 -0
  119. package/client/dist/assets/nav-B34QkESm.js +1 -0
  120. package/client/dist/assets/nav-Bap_UXAq.js +1 -0
  121. package/client/dist/assets/{nav-pYuXq7sf.js → nav-BwxXIB24.js} +1 -1
  122. package/client/dist/assets/nav-Ch-zHBG5.js +1 -0
  123. package/client/dist/assets/nav-CygC_WN-.js +1 -0
  124. package/client/dist/assets/{nav-iwjCg5FR.js → nav-KnnLQtOQ.js} +1 -1
  125. package/client/dist/assets/nav-m00uxYUG.js +1 -0
  126. package/client/dist/assets/packet-BQ2tXfJI.js +1 -0
  127. package/client/dist/assets/packet-BdpOJ1Cy.js +1 -0
  128. package/client/dist/assets/packet-C3Ievb9R.js +1 -0
  129. package/client/dist/assets/packet-C4zJIG0Y.js +1 -0
  130. package/client/dist/assets/packet-Cx-zRuWn.js +1 -0
  131. package/client/dist/assets/packet-DUTGX52M.js +1 -0
  132. package/client/dist/assets/packet-DhsKtUPB.js +1 -0
  133. package/client/dist/assets/packet-z3LJ8Zyy.js +1 -0
  134. package/client/dist/assets/project-repositories-DYhTvwQ1.js +1 -0
  135. package/client/dist/assets/provider-capabilities-B-wOHfLP.js +1 -0
  136. package/client/dist/assets/settings-BBt2xtDQ.js +1 -0
  137. package/client/dist/assets/settings-BJB9RKJj.js +1 -0
  138. package/client/dist/assets/settings-CHwQR2rB.js +1 -0
  139. package/client/dist/assets/settings-CrMi3kSi.js +1 -0
  140. package/client/dist/assets/settings-DKyhDGD1.js +1 -0
  141. package/client/dist/assets/settings-Deupji9c.js +1 -0
  142. package/client/dist/assets/settings-DqRMmwAM.js +1 -0
  143. package/client/dist/assets/settings-J4rj6vo-.js +1 -0
  144. package/client/dist/assets/setup-2xGgu4Sk.js +1 -0
  145. package/client/dist/assets/setup-Ba11l2JA.js +1 -0
  146. package/client/dist/assets/setup-BzW4kMok.js +1 -0
  147. package/client/dist/assets/setup-COzwYhkJ.js +1 -0
  148. package/client/dist/assets/setup-CRVULhtF.js +1 -0
  149. package/client/dist/assets/setup-DgvlxwpE.js +1 -0
  150. package/client/dist/assets/setup-Dw_wYeEY.js +1 -0
  151. package/client/dist/assets/setup-ZPtEeJPW.js +1 -0
  152. package/client/dist/assets/spending-BqbdPm_4.js +1 -0
  153. package/client/dist/assets/square-Ci-PFcFe.js +1 -0
  154. package/client/dist/assets/{terminal-BFRZnMPP.js → terminal-BAzpHtpY.js} +1 -1
  155. package/client/dist/assets/{terminal-IahE4LW9.js → terminal-C7dHeR3x.js} +1 -1
  156. package/client/dist/assets/{terminal-tITa81iz.js → terminal-CMla5Qsz.js} +1 -1
  157. package/client/dist/assets/{terminal-BZiIu3rf.js → terminal-CdNXH-n9.js} +1 -1
  158. package/client/dist/assets/{terminal-ScjyXNxQ.js → terminal-Cw5bZsmV.js} +1 -1
  159. package/client/dist/assets/{terminal-C2NAd7BW.js → terminal-DFUP4eNv.js} +1 -1
  160. package/client/dist/assets/{terminal-d7GadXbN.js → terminal-DGqljeK_.js} +1 -1
  161. package/client/dist/assets/{terminal-QpXZU2Bn.js → terminal-cU70NodO.js} +1 -1
  162. package/client/dist/assets/useDesktop-RSMTyy7V.js +1 -0
  163. package/client/dist/assets/useSharedWebSocket-BOdS5_Iz.js +2 -0
  164. package/client/dist/index.html +34 -35
  165. package/docs/README.md +3 -0
  166. package/docs/agent-live-steering.md +57 -0
  167. package/docs/ci-cd.md +57 -0
  168. package/docs/code-explorer.md +48 -0
  169. package/docs/codex.md +12 -1
  170. package/docs/features/detachable-mission-windows.md +59 -0
  171. package/docs/guide/de/integrations/5-mcp-server.md +13 -9
  172. package/docs/guide/de/integrations/6-agent-chat.md +1 -0
  173. package/docs/guide/en/integrations/5-mcp-server.md +13 -9
  174. package/docs/guide/en/integrations/6-agent-chat.md +1 -0
  175. package/docs/guide/es/integrations/5-mcp-server.md +13 -9
  176. package/docs/guide/es/integrations/6-agent-chat.md +1 -0
  177. package/docs/guide/fr/integrations/5-mcp-server.md +13 -9
  178. package/docs/guide/fr/integrations/6-agent-chat.md +1 -0
  179. package/docs/guide/it/integrations/5-mcp-server.md +13 -9
  180. package/docs/guide/it/integrations/6-agent-chat.md +1 -0
  181. package/docs/guide/ja/integrations/5-mcp-server.md +13 -9
  182. package/docs/guide/ja/integrations/6-agent-chat.md +1 -0
  183. package/docs/guide/pt/integrations/5-mcp-server.md +13 -9
  184. package/docs/guide/pt/integrations/6-agent-chat.md +1 -0
  185. package/docs/guide/zh/integrations/5-mcp-server.md +13 -9
  186. package/docs/guide/zh/integrations/6-agent-chat.md +1 -0
  187. package/docs/internals/README.md +1 -0
  188. package/docs/internals/browser-capture-performance.md +55 -3
  189. package/docs/internals/browser-login-popups.md +45 -0
  190. package/docs/internals/browser-native-retina-audit.md +39 -0
  191. package/docs/internals/ci-cd-audit.md +39 -0
  192. package/docs/internals/core-runtime-updates.md +68 -0
  193. package/docs/internals/embedded-browser-native-webview-evaluation.md +2 -0
  194. package/docs/internals/implementation-reliability-audit.md +93 -0
  195. package/docs/internals/interactive-jobs.md +110 -6
  196. package/docs/internals/mcp-mission-audit.md +76 -0
  197. package/docs/internals/project-builder.md +404 -42
  198. package/docs/internals/safe-pr-review-flow.md +52 -10
  199. package/docs/internals/startup-recovery-audit.md +58 -0
  200. package/docs/mcp.md +74 -41
  201. package/docs/mission-processes.md +59 -0
  202. package/docs/multi-repo-projects.md +51 -0
  203. package/docs/platforms/windows-parity.md +70 -0
  204. package/docs/platforms/windows.md +13 -11
  205. package/docs/running-pipelines.md +14 -0
  206. package/mcp-bridge/dist/specrails-mcp.js +7186 -0
  207. package/package.json +9 -4
  208. package/server/dist/agent-chat-manager.js +537 -68
  209. package/server/dist/agent-chat-router.js +87 -6
  210. package/server/dist/agent-context-resolver.js +129 -25
  211. package/server/dist/agent-defaults.js +19 -11
  212. package/server/dist/agent-input-store.js +206 -0
  213. package/server/dist/agent-mcp-config.js +54 -15
  214. package/server/dist/agent-operator-prompt.js +255 -65
  215. package/server/dist/agent-spec-framing.js +202 -0
  216. package/server/dist/agent-steering.js +218 -0
  217. package/server/dist/agent-store.js +153 -0
  218. package/server/dist/api-not-found.js +8 -0
  219. package/server/dist/background-process-control.js +164 -0
  220. package/server/dist/background-process-service.js +61 -0
  221. package/server/dist/background-process-store.js +242 -0
  222. package/server/dist/background-windows-bootstrap.js +238 -0
  223. package/server/dist/blueprint-chat-manager.js +476 -62
  224. package/server/dist/blueprint-commit.js +21 -1
  225. package/server/dist/blueprint-draft-parser.js +122 -17
  226. package/server/dist/blueprint-generation.js +238 -0
  227. package/server/dist/blueprint-operator-prompt.js +91 -63
  228. package/server/dist/blueprint-router.js +55 -3
  229. package/server/dist/blueprint-spec-fixtures.js +85 -0
  230. package/server/dist/blueprint-spec-quality.js +57 -16
  231. package/server/dist/blueprint-store.js +92 -1
  232. package/server/dist/browser-capture-manager.js +86 -30
  233. package/server/dist/browser-playwright.js +168 -45
  234. package/server/dist/browser-viewport.js +26 -0
  235. package/server/dist/chat-manager.js +23 -15
  236. package/server/dist/chromium-archive.cjs +83 -0
  237. package/server/dist/chromium-resolver.js +72 -64
  238. package/server/dist/code-activity.js +145 -0
  239. package/server/dist/code-explorer-router.js +714 -114
  240. package/server/dist/core-compat.js +28 -1
  241. package/server/dist/core-execution.js +111 -0
  242. package/server/dist/core-package.js +4 -16
  243. package/server/dist/core-runtime.js +202 -0
  244. package/server/dist/core-update-manager.js +161 -60
  245. package/server/dist/core-update-state.js +29 -0
  246. package/server/dist/db.js +66 -35
  247. package/server/dist/delivery-evidence.js +142 -39
  248. package/server/dist/desktop-db.js +239 -43
  249. package/server/dist/desktop-router.js +109 -9
  250. package/server/dist/dev-ports.js +8 -3
  251. package/server/dist/file-provenance.js +34 -22
  252. package/server/dist/file-story-manager.js +62 -64
  253. package/server/dist/file-story.js +118 -35
  254. package/server/dist/file-summary-generator.js +46 -5
  255. package/server/dist/file-summary-manager.js +355 -106
  256. package/server/dist/framework-manager.js +98 -110
  257. package/server/dist/framework-reseed.js +76 -10
  258. package/server/dist/git-diagnostics.js +2 -2
  259. package/server/dist/headroom-manager.js +38 -3
  260. package/server/dist/host-control.js +52 -0
  261. package/server/dist/index.js +43 -2
  262. package/server/dist/interactive-job-session.js +149 -16
  263. package/server/dist/internal-api.js +48 -0
  264. package/server/dist/jira/jira-materializer.js +1 -0
  265. package/server/dist/json-tolerant.js +174 -0
  266. package/server/dist/legacy-migration.js +4 -2
  267. package/server/dist/loop-command-catalog.js +83 -21
  268. package/server/dist/loop-constants.js +6 -1
  269. package/server/dist/loop-decider.js +11 -1
  270. package/server/dist/loop-executors.js +194 -45
  271. package/server/dist/loop-factory.js +11 -4
  272. package/server/dist/loop-graph.js +90 -4
  273. package/server/dist/loop-run-manager.js +301 -69
  274. package/server/dist/loop-shell-invocation.js +21 -0
  275. package/server/dist/loop-step-idle.js +55 -0
  276. package/server/dist/loop-templates.js +31 -7
  277. package/server/dist/mcp/agent-capability.js +37 -4
  278. package/server/dist/mcp/guide.js +149 -36
  279. package/server/dist/mcp/mcp-admin-router.js +20 -4
  280. package/server/dist/mcp/mcp-server.js +89 -43
  281. package/server/dist/mcp/mcp-tiers.js +6 -5
  282. package/server/dist/mcp/mcp-token.js +3 -1
  283. package/server/dist/mcp/resources.js +5 -4
  284. package/server/dist/mcp/tools/catalog.js +4 -0
  285. package/server/dist/mcp/tools/code.js +125 -14
  286. package/server/dist/mcp/tools/context.js +153 -0
  287. package/server/dist/mcp/tools/git.js +15 -5
  288. package/server/dist/mcp/tools/jobs.js +84 -71
  289. package/server/dist/mcp/tools/loops.js +17 -6
  290. package/server/dist/mcp/tools/meta.js +74 -27
  291. package/server/dist/mcp/tools/mission.js +29 -0
  292. package/server/dist/mcp/tools/projects.js +22 -6
  293. package/server/dist/mcp/tools/rails.js +48 -11
  294. package/server/dist/mcp/tools/specs.js +86 -14
  295. package/server/dist/mcp/tools/support.js +1 -1
  296. package/server/dist/mcp/tools/types.js +117 -43
  297. package/server/dist/mcp/tools/watch.js +144 -51
  298. package/server/dist/milestone-chain-store.js +164 -0
  299. package/server/dist/milestone-chain.js +487 -0
  300. package/server/dist/milestone-progress.js +348 -0
  301. package/server/dist/mobile/mobile-devices.js +10 -7
  302. package/server/dist/mobile/mobile-gateway.js +2 -0
  303. package/server/dist/mobile/mobile-missions.js +214 -0
  304. package/server/dist/mobile/mobile-redact.js +17 -3
  305. package/server/dist/mobile/mobile-router.js +46 -4
  306. package/server/dist/mobile/mobile-ws.js +49 -4
  307. package/server/dist/multi-repo-bases.js +56 -0
  308. package/server/dist/multi-repo-checkout.js +101 -0
  309. package/server/dist/multi-repo-delivery.js +100 -0
  310. package/server/dist/multi-repo-execution-store.js +65 -0
  311. package/server/dist/multi-repo-execution.js +453 -0
  312. package/server/dist/offline-assemble.js +10 -8
  313. package/server/dist/openspec-runtime-plugin-commands.json +18 -0
  314. package/server/dist/openspec-runtime-plugin.js +120 -0
  315. package/server/dist/plugins/codex-spawn.js +49 -0
  316. package/server/dist/plugins/serena/manifest.js +2 -2
  317. package/server/dist/plugins/serena/templates/instructions.md +16 -0
  318. package/server/dist/pr-publisher.js +1 -1
  319. package/server/dist/profiles-router.js +3 -18
  320. package/server/dist/project-code-discovery.js +142 -0
  321. package/server/dist/project-git.js +19 -21
  322. package/server/dist/project-registry.js +272 -20
  323. package/server/dist/project-repositories.js +157 -0
  324. package/server/dist/project-repository-provenance.js +31 -0
  325. package/server/dist/project-router-background-processes.js +105 -0
  326. package/server/dist/project-router-git.js +75 -16
  327. package/server/dist/project-router-jobs.js +2 -126
  328. package/server/dist/project-router-loop-runs.js +72 -2
  329. package/server/dist/project-router-tickets.js +53 -8
  330. package/server/dist/project-router.js +239 -38
  331. package/server/dist/provider-detection.js +18 -6
  332. package/server/dist/provider-limit.js +64 -0
  333. package/server/dist/providers/claude-adapter.js +26 -1
  334. package/server/dist/providers/claude-background-tasks.js +18 -0
  335. package/server/dist/providers/claude-live-session.js +383 -0
  336. package/server/dist/providers/codex-adapter.js +19 -0
  337. package/server/dist/providers/codex-live-session.js +545 -0
  338. package/server/dist/providers/gemini-adapter.js +1 -0
  339. package/server/dist/providers/live-session-types.js +12 -0
  340. package/server/dist/providers/live-session.js +13 -0
  341. package/server/dist/providers/terminal-result.js +24 -0
  342. package/server/dist/queue-manager.js +2 -0
  343. package/server/dist/rail-isolated-launch.js +141 -16
  344. package/server/dist/rail-pr-decision.js +364 -99
  345. package/server/dist/rail-pr-store.js +24 -10
  346. package/server/dist/rail-worktree-release.js +34 -2
  347. package/server/dist/rail-worktrees-store.js +4 -4
  348. package/server/dist/rails-router.js +249 -55
  349. package/server/dist/repo-lock.js +92 -17
  350. package/server/dist/review-packet.js +23 -13
  351. package/server/dist/schemas/file-summary.v1.json +59 -59
  352. package/server/dist/schemas/profile.v1.json +137 -137
  353. package/server/dist/setup-manager.js +52 -8
  354. package/server/dist/shell-integration/bash-shim.bash +45 -0
  355. package/server/dist/shell-integration/fish-shim.fish +36 -0
  356. package/server/dist/shell-integration/powershell-shim.ps1 +48 -0
  357. package/server/dist/shell-integration/zsh-shim.zsh +47 -0
  358. package/server/dist/smash-runner.js +1 -0
  359. package/server/dist/spawn-lifecycle.js +44 -27
  360. package/server/dist/spec-contract-prompt.js +143 -0
  361. package/server/dist/spec-draft-parser.js +6 -1
  362. package/server/dist/spec-models.js +1 -0
  363. package/server/dist/stuck-run-detector.js +1 -0
  364. package/server/dist/terminal-manager.js +21 -1
  365. package/server/dist/terminal-shell-integration.js +4 -1
  366. package/server/dist/transient-children.js +619 -230
  367. package/server/dist/util/cli-prompt.js +78 -5
  368. package/server/dist/util/sqlite-migrations.js +20 -0
  369. package/server/dist/util/win-spawn.js +18 -3
  370. package/server/dist/util/windows-provider-shell.js +29 -0
  371. package/server/dist/verification-sentinel.js +14 -0
  372. package/server/dist/vitest-setup.js +2 -0
  373. package/server/dist/windows-job-supervisor.js +133 -0
  374. package/server/dist/workspace-manager.js +9 -30
  375. package/server/dist/worktree-manager.js +17 -2
  376. package/server/dist/worktree-overlay.js +3 -1
  377. package/client/dist/assets/ActivityFeedPage-tAQcWs1R.js +0 -1
  378. package/client/dist/assets/AgentBrowserCapture-BX8BNae5.js +0 -1
  379. package/client/dist/assets/AgentModeAnalyticsPane-BVAqCL0K.js +0 -2
  380. package/client/dist/assets/AgentModeCodePane-9XfqQc9c.js +0 -2
  381. package/client/dist/assets/AgentModeJobsPane-BCjLsPhc.js +0 -1
  382. package/client/dist/assets/AgentsPage-C8J_42sm.js +0 -87
  383. package/client/dist/assets/AnalyticsPage-BtQuyfJm.js +0 -1
  384. package/client/dist/assets/CodePage-BZ2MwdCu.js +0 -2
  385. package/client/dist/assets/DesktopAnalyticsPage-Bh_29V4g.js +0 -1
  386. package/client/dist/assets/ExportDropdown-BrtfWzEG.js +0 -1
  387. package/client/dist/assets/InteractiveJobComposer-BCZiSfzc.js +0 -19
  388. package/client/dist/assets/JobDetailModal-NAJmuYIT.js +0 -1
  389. package/client/dist/assets/JobDetailPage-fE0ZycUX.js +0 -1
  390. package/client/dist/assets/JobsPage-z5M_HVJG.js +0 -1
  391. package/client/dist/assets/LoopBuilderPage-j1FQS47c.js +0 -7
  392. package/client/dist/assets/LoopPreviewModal-DhDJjdCe.js +0 -1
  393. package/client/dist/assets/LoopsPage-Ll7zORZb.js +0 -1
  394. package/client/dist/assets/MinimizedChatsContext-Bd3OqR_S.js +0 -1
  395. package/client/dist/assets/PluginsPage-DN4kGvJt.js +0 -2
  396. package/client/dist/assets/ProjectSettingsDialog-OgsgxjzF.js +0 -1
  397. package/client/dist/assets/ReviewPacketPage-DFog4sXn.js +0 -1
  398. package/client/dist/assets/TemplatePreviewModal-L2XxqiOD.js +0 -1
  399. package/client/dist/assets/TicketDetailModal-CsF-AWZX.js +0 -14
  400. package/client/dist/assets/Trans-Bsz9_gyq.js +0 -1
  401. package/client/dist/assets/agent-BQgKv_2F.js +0 -1
  402. package/client/dist/assets/agent-C1NRDJqL.js +0 -1
  403. package/client/dist/assets/agent-CLNleiy6.js +0 -1
  404. package/client/dist/assets/agent-CmceArkQ.js +0 -1
  405. package/client/dist/assets/agent-D3UxQ3SR.js +0 -1
  406. package/client/dist/assets/agent-DB1JeE64.js +0 -1
  407. package/client/dist/assets/agent-DXkHcQ-D.js +0 -1
  408. package/client/dist/assets/agent-DjJJJ2M8.js +0 -1
  409. package/client/dist/assets/auth-D_5bQv5W.js +0 -1
  410. package/client/dist/assets/ban-E4EaZe3a.js +0 -1
  411. package/client/dist/assets/bot-DzuuuC5R.js +0 -1
  412. package/client/dist/assets/browser-BgqHDMXP.js +0 -1
  413. package/client/dist/assets/browser-CsKJtrpv.js +0 -1
  414. package/client/dist/assets/browser-Cu58EpZU.js +0 -1
  415. package/client/dist/assets/browser-CvXOJm-j.js +0 -1
  416. package/client/dist/assets/browser-DOrFh1c7.js +0 -1
  417. package/client/dist/assets/browser-DQv_Jo7x.js +0 -1
  418. package/client/dist/assets/browser-LPgxvJu2.js +0 -1
  419. package/client/dist/assets/browser-eL-3MIEI.js +0 -1
  420. package/client/dist/assets/builder-0IWtosUm.js +0 -1
  421. package/client/dist/assets/builder-Bf2N6XWn.js +0 -1
  422. package/client/dist/assets/builder-BnqaaBkT.js +0 -1
  423. package/client/dist/assets/builder-BxxfGgAO.js +0 -1
  424. package/client/dist/assets/builder-C5IIgWsq.js +0 -1
  425. package/client/dist/assets/builder-CHuahItu.js +0 -1
  426. package/client/dist/assets/builder-CjWosXL_.js +0 -1
  427. package/client/dist/assets/builder-CpCIOoKj.js +0 -1
  428. package/client/dist/assets/code-CHPkOkDS.js +0 -1
  429. package/client/dist/assets/commands-6tYQih5m.js +0 -1
  430. package/client/dist/assets/commands-BK2QinXN.js +0 -1
  431. package/client/dist/assets/commands-C2Nca76h.js +0 -1
  432. package/client/dist/assets/commands-CKdLihNX.js +0 -1
  433. package/client/dist/assets/commands-CYIBTAlc.js +0 -1
  434. package/client/dist/assets/commands-CjUtYJIM.js +0 -1
  435. package/client/dist/assets/commands-Cq_u_8y9.js +0 -1
  436. package/client/dist/assets/commands-D_ZHYQug.js +0 -1
  437. package/client/dist/assets/common-6MLbD-jM.js +0 -1
  438. package/client/dist/assets/common-BKGEu4rm.js +0 -1
  439. package/client/dist/assets/common-BNbnv8cE.js +0 -1
  440. package/client/dist/assets/common-BqGWtDbt.js +0 -1
  441. package/client/dist/assets/common-DBtTzeYm.js +0 -1
  442. package/client/dist/assets/common-DEW3Nr8n.js +0 -1
  443. package/client/dist/assets/common-DHsv9N5d.js +0 -1
  444. package/client/dist/assets/common-mkrEcW-Y.js +0 -1
  445. package/client/dist/assets/dashboard-B9GhC5ku.js +0 -1
  446. package/client/dist/assets/dashboard-CBnv6zOI.js +0 -1
  447. package/client/dist/assets/dashboard-CaP0fU87.js +0 -1
  448. package/client/dist/assets/dashboard-D4ZZ4x84.js +0 -1
  449. package/client/dist/assets/dashboard-DmuTQBX8.js +0 -1
  450. package/client/dist/assets/dashboard-DynLYj3d.js +0 -1
  451. package/client/dist/assets/dashboard-zj4gGFJ1.js +0 -1
  452. package/client/dist/assets/dialog-CdWCb02j.js +0 -45
  453. package/client/dist/assets/dist-bVqfYmby.js +0 -1
  454. package/client/dist/assets/dist-js-CWeUdf5Z.js +0 -1
  455. package/client/dist/assets/formatDistanceToNow-DQCvMgUc.js +0 -1
  456. package/client/dist/assets/getTimezoneOffsetInMilliseconds-C16cxSe1.js +0 -1
  457. package/client/dist/assets/git-refresh-wTW0rO0Z.js +0 -1
  458. package/client/dist/assets/i18n-hnX2DPmo.js +0 -2
  459. package/client/dist/assets/index-DIhMEAVw.js +0 -66
  460. package/client/dist/assets/index-DwygcU7s.css +0 -2
  461. package/client/dist/assets/mcp-B8X8wBLu.js +0 -1
  462. package/client/dist/assets/mcp-C2AojZZN.js +0 -1
  463. package/client/dist/assets/mcp-D8BT78_L.js +0 -1
  464. package/client/dist/assets/mcp-Df5RWBNk.js +0 -1
  465. package/client/dist/assets/mcp-Dj7BgMQW.js +0 -1
  466. package/client/dist/assets/mcp-Q7iT7rcz.js +0 -1
  467. package/client/dist/assets/mcp-YlvNvJbW.js +0 -1
  468. package/client/dist/assets/mcp-mKFpTSRb.js +0 -1
  469. package/client/dist/assets/narration-4Z2VUhZw.js +0 -1
  470. package/client/dist/assets/narration-BGuiEDj3.js +0 -1
  471. package/client/dist/assets/narration-BuSoqRmv.js +0 -1
  472. package/client/dist/assets/narration-CB9t29fy.js +0 -1
  473. package/client/dist/assets/narration-CU3x8FHD.js +0 -1
  474. package/client/dist/assets/narration-CWeXhfP5.js +0 -1
  475. package/client/dist/assets/narration-DRaDnhT5.js +0 -1
  476. package/client/dist/assets/narration-DtEbQgCw.js +0 -1
  477. package/client/dist/assets/nav-ApJVg3xu.js +0 -1
  478. package/client/dist/assets/nav-BKNky1Bg.js +0 -1
  479. package/client/dist/assets/nav-C6vWWKYx.js +0 -1
  480. package/client/dist/assets/nav-CXJ6Aw89.js +0 -1
  481. package/client/dist/assets/nav-CsmFBIDf.js +0 -1
  482. package/client/dist/assets/nav-DjkmQJjd.js +0 -1
  483. package/client/dist/assets/packet-B1IxaL5f.js +0 -1
  484. package/client/dist/assets/packet-Bh5kkbiB.js +0 -1
  485. package/client/dist/assets/packet-By8fqYxW.js +0 -1
  486. package/client/dist/assets/packet-CZdvA44E.js +0 -1
  487. package/client/dist/assets/packet-CrjHRQCP.js +0 -1
  488. package/client/dist/assets/packet-Dwi2pTtx.js +0 -1
  489. package/client/dist/assets/packet-_-ZIa0IR.js +0 -1
  490. package/client/dist/assets/packet-n0W6E1Hn.js +0 -1
  491. package/client/dist/assets/play-DNlrawbS.js +0 -1
  492. package/client/dist/assets/provider-capabilities-Doej9lfa.js +0 -1
  493. package/client/dist/assets/settings-Bd0x4TBa.js +0 -1
  494. package/client/dist/assets/settings-C1-7cXzC.js +0 -1
  495. package/client/dist/assets/settings-CAFaT38b.js +0 -1
  496. package/client/dist/assets/settings-Ct3v1nW2.js +0 -1
  497. package/client/dist/assets/settings-DHh7_IF5.js +0 -1
  498. package/client/dist/assets/settings-DQXAmdcv.js +0 -1
  499. package/client/dist/assets/settings-guzlhpup.js +0 -1
  500. package/client/dist/assets/settings-sZfTPMEH.js +0 -1
  501. package/client/dist/assets/setup-3jWaoVUO.js +0 -1
  502. package/client/dist/assets/setup-BjgRneb2.js +0 -1
  503. package/client/dist/assets/setup-BzFIjv-f.js +0 -1
  504. package/client/dist/assets/setup-C4VfQsxE.js +0 -1
  505. package/client/dist/assets/setup-DfUkpDbN.js +0 -1
  506. package/client/dist/assets/setup-ECe90Pmu.js +0 -1
  507. package/client/dist/assets/setup-dlqC4Jmm.js +0 -1
  508. package/client/dist/assets/setup-jwfLMiM2.js +0 -1
  509. package/client/dist/assets/spending-EC9xqio-.js +0 -1
  510. package/client/dist/assets/useDesktop-BQVt8lFd.js +0 -1
@@ -0,0 +1,39 @@
1
+ # Browser performance and Retina audit
2
+
3
+ Date: 2026-09-05. Implemented on `feat/codex-gpt-6-astra`.
4
+
5
+ ## Cause
6
+
7
+ The mission browser opened `BrowserCaptureModal`, which displayed a headless Chromium screencast. Only links opened the existing native browser. Navigation in missions therefore encoded JPEG frames, transferred them through WebSocket, decoded them, and painted them on a canvas; every input went through the reverse path. The default stream had one physical pixel per CSS pixel, so Retina screens enlarged a low-resolution image.
8
+
9
+ Increasing JPEG quality or setting `deviceScaleFactor` alone does not solve this. The local Chromium experiment confirmed that a context at DPR 2 still emitted 1280×800 screencast frames for a 1280×800 CSS viewport. An ordinary screenshot and an actual native browser can retain the physical pixels.
10
+
11
+ The user then reproduced a development-browser regression: the streamed page occupied only the upper-left quarter of the pane. The initial Retina change enlarged the compositor surface with `Emulation.setVisibleSize`, but the actual JPEG content still occupied its original dimensions. Checking bitmap dimensions alone missed the white padding. Regression checks now inspect page markers at all four corners of actual screencast JPEG frames, as well as layout, input coordinates and screenshot crops.
12
+
13
+ ## Implemented
14
+
15
+ - **Native mission browsing on macOS.** `AgentBrowserCapture` checks native capture support before mounting a browser. The supported route uses the real WKWebView; no Playwright session, frame stream, canvas repaint or input relay runs during navigation. The address bar accepts HTTP localhost development servers and remembers the last URL per project.
16
+ - **Capture the page the user is actually viewing.** Rust evaluates a fixed selector in WebKit's isolated client world and calls WKWebView's snapshot API. Screenshots preserve the display's backing resolution, including zoom and clipped visible element bounds. There is no second navigation or transfer to another cookie profile. Element selection suppresses page actions, including long presses. Custom application commands are rejected centrally for any webview other than the main app view; this also covers the native page and login popups. Tauri otherwise allowed custom commands without an app ACL manifest, so merely omitting remote capability origins was insufficient.
17
+ - **Keep annotations and retry failures.** The native pane is hidden while the shared image editor annotates the captured bitmap, then shown again without reloading when returning to the page. Flattening uses natural image dimensions. Image redaction is opaque in both preview and PNG, avoiding the unsupported canvas blur path in WebKit. Rendering/upload failures retain the editor and its changes instead of silently sending the original uncensored image. Both the native and advanced flows await the attachment destination before closing. Advanced captures run from the pointer event, outside React state updaters, so StrictMode does not execute each capture twice.
18
+ - **Scope pane operations to their owner.** Each mount has a distinct owner ID, propagated through commands and events. Open/close calls are serialized; stale cleanup cannot close another pane. Late listeners are released, changed URLs navigate the existing pane, geometry updates are deduplicated, and transient startup probe failures can recover.
19
+ - **Correct sizing for advanced capture and fallback.** Both fallback browser surfaces fit their actual containers. The interactive Chromium page keeps its normal CSS viewport and DPR 1. `Page.captureScreenshot` uses `clip.scale` to render PNGs at the host display density, bounded by a 3840×2400 raster budget and scale 2, without changing page state. Its live screencast remains CSS-sized: enlarging the surface with `setVisibleSize` caused the quarter-pane regression; an explicit viewport clip failed after scrolling; changing compositor scale or page DPR altered pointer/wheel semantics. Those approaches were removed. Viewport updates are retained before connection, deduplicated, and follow monitor density changes. Desktop native browsing supplies actual display-resolution rendering without that CDP limitation.
20
+ - **Recover the capture transport.** Failed screencast starts release the partial CDP state and can retry; permanently failed streams disconnect clearly. Stale popup frames are ignored. Chromium uses its default graphics path, with an explicit environment opt-out for incompatible drivers.
21
+
22
+ ## Verification
23
+
24
+ Reproducible checks include:
25
+
26
+ - `scripts/smoke-browser-rendering.mjs`: isolated local Chromium fixture; full-page coverage at all four corners of real JPEG frames, CSS input and wheel events after resizing/scrolling, and Retina screenshot crops, including fractional density. Half-pixel patterns verify that the 2× PNG retains detail unavailable in an interpolated 1× bitmap. It checks image content as well as dimensions. No production profile or database is used.
27
+ - The macOS native browser smoke under `src-tauri`: actual WKWebView snapshots, same-page element selection, long-press suppression, zoom, isolated picker state and stale-owner cleanup. A 900×550 logical view produced a 1800×1100 PNG on the Mac's 2× display. `src-tauri/examples/native-browser-selector-smoke.mjs` uses real WebKit clicks to verify cross-origin iframe selection without activating page buttons, open Shadow DOM, long presses and restored browsing.
28
+ - `scripts/smoke-browser-annotations.mjs`: real client CSS and the shared editor in Chromium and WebKit; landscape/portrait Retina images fit the editor, controls remain visible, exported pixels preserve redactions, and encoding failures retain annotations for retry.
29
+ - A separate read-only check opened `https://specrails.dev/` with a fresh temporary Chromium profile, the production `PlaywrightPageHandle`, a 1984×1068 CSS viewport and requested capture density 2. The actual streamed JPEG was visually inspected: the page filled the surface and its hero was centered, reproducing the user's page without the quarter-frame padding.
30
+ - Frontend regression tests cover native/fallback routing, pane lifetime, deferred listeners, native capture/annotation, stable viewport synchronization, uploads and preservation of annotations after failures. Failed native selector polling releases its input shield; if native cleanup itself fails, the UI keeps the selector active with an error and allows cancellation to be retried.
31
+ - Full server/client coverage, TypeScript and production builds passed; coverage thresholds are retained.
32
+
33
+ Completed checks include full server coverage (282 files, 7,408 tests; 88.32% lines, 78.39% branches, 90.02% functions), full client coverage (354 files, 4,417 tests; 89.24% statements/lines, 83.04% branches, 74.60% functions), plus all 11 native-pane tests after the final selector cleanup fix; all 25 Rust tests and `cargo check --offline --all-targets`; global TypeScript; the production server/client/CLI build; and core compatibility. The Chromium rendering smoke passed all ten size/density/graphics combinations. Native snapshots and selector input were checked with actual macOS WebKit, and the annotation smoke passed in Chromium and WebKit.
34
+
35
+ The Chromium benchmark reports observed timing on a local synthetic page, not a controlled comparison with Cursor. The architectural change removes the continuous streaming path from native mission browsing; it does not establish identical performance on every website or machine. Native capture is currently macOS-specific; other runtimes keep the compatible Chromium path. This change does not replace the installed signed desktop application.
36
+
37
+ ## References
38
+
39
+ Cursor documents its integrated browser and element-to-agent workflow in its [Browser documentation](https://prod.cursor.com/docs/agent/tools/browser). Tauri exposes the platform webview through [`with_webview`](https://docs.rs/tauri/2.10.3/tauri/webview/struct.Webview.html#method.with_webview). The implementation was checked against the locally installed Tauri, Wry and Objective-C crate sources, not inferred from newer API versions.
@@ -0,0 +1,39 @@
1
+ # CI/CD and README audit — 6 September 2026
2
+
3
+ This audit covers the current Desktop and Core source branches. It does not publish either package, modify repository protection rules, configure npm accounts, or exercise production hosting/signing credentials.
4
+
5
+ ## Findings and changes
6
+
7
+ | Finding | Change |
8
+ | --- | --- |
9
+ | Release automation ran independently of CI and could publish after failed verification. | Publication now requires successful main-branch CI for the exact release commit; tag/package identity is checked before distribution. Stale main pushes cannot advance release metadata. |
10
+ | Tests against a checkout did not prove the npm payload was usable. Desktop omitted its compiled MCP bridge and filesystem-loaded server resources. | Both repositories install and inspect the actual tarball in a temporary consumer. Desktop builds and ships MCP, schemas, shell-integration shims and Serena templates. Core exercises both CLI entries, four provider assemblies and installed pipeline journals. |
11
+ | Credential-bearing release jobs also performed package installation/build work. | Preparation and tests use read-only jobs. npm publication consumes verified bytes with lifecycle scripts disabled; npm credentials are limited to the publish step. |
12
+ | Concurrent or late releases could move mutable `latest` channels backwards. | Global publication serialization and numeric version guards reject older promotions. Exact existing npm versions require matching integrity for retry. |
13
+ | Core notified the former web repository but not Desktop; Desktop's compatibility check could skip the intended package. | Core dispatches to both consumers with their expected version formats. Desktop validates an explicitly installed candidate and fails if its contract cannot be checked. Only actual drift opens a deduplicated issue. |
14
+ | Workflow syntax and downloaded CI utilities had incomplete verification; native dependency update coverage was missing. | Actionlint becomes a CI gate; utilities are checksum-verified, actions are commit-pinned, and Desktop dependency automation includes Cargo and the MCP bridge. |
15
+ | Native download promotion uploaded its public manifest directly and used plaintext FTP. | Host publication requires FTPS and promotes the manifest using a server-side rename after uploading and checking the referenced installers. Hosting support must be verified during deployment acceptance. |
16
+ | Chromium's optional macOS bundle concealed ad-hoc binaries in an encoded archive, and the launcher's sandbox comment did not match Playwright's default. | New assembly uses transparent archives and a release signing/notarization gate. The resolver prefers those archives, preserves framework links and rolls back failed cache publication. macOS/Windows launches explicitly enable Chromium's sandbox. Hosted signing and clean-machine browser acceptance remain pending. |
17
+ | READMEs contained older architecture, installation claims, unsupported comparisons and incomplete native development steps. | Both READMEs now distinguish the native app, npm/browser use, provider workflows, source development and published releases, with links to detailed feature and release documentation. |
18
+
19
+ ## Verification boundaries
20
+
21
+ Package checks do not invoke a model or read the user's project registry. Desktop's package smoke verifies CLI execution and runtime resource discovery with dependency lifecycle scripts disabled; it does not certify native SQLite/PTY ABI behavior or launch a complete installed server. Native fixtures and installer gates cover separate parts of that acceptance surface.
22
+
23
+ Local workflow syntax, helper regression, build, typecheck, package and coverage results are recorded in the [verification report](../../openspec/changes/ci-cd-documentation-hardening/verification.md). Windows/Linux runner execution and real signed publication require the hosted workflows after these changes are merged. Coverage thresholds were retained.
24
+
25
+ ### Native Chromium signing: implementation repaired, hosted acceptance pending
26
+
27
+ The former optional macOS bundle used XOR-encoded `chromium.pak` to prevent inspection of Chromium's ad-hoc signatures. Outer-app notarization therefore did not establish that the extracted browser met distribution-signing requirements. The audit also found that omitting `--no-sandbox` was insufficient: Playwright disables its Chromium sandbox by default unless `chromiumSandbox` is explicitly enabled.
28
+
29
+ The new `scripts/assemble-chromium.mjs` packages Chromium as transparent `chromium.tar.gz`, preserving versioned framework symlinks. Release mode on macOS requires Developer ID signing from inner components to their enclosing bundles, Hardened Runtime, the appropriate Chromium component entitlements, signature verification and notarization before distribution. Local assembly invokes the same packager without release credentials, producing an explicitly unsigned development artifact. `scripts/obfuscate-chromium.mjs` remains only for legacy compatibility and fixtures; new release assembly does not produce `.pak` files.
30
+
31
+ The resolver selects `.tar.gz` and `.tar` before legacy `.pak`, binds cache reuse to the selected archive's path and filesystem revision, rechecks deleted caches and preserves the prior extraction if replacement fails. Regression fixtures exercise transparent/legacy migration and framework symlinks. The production Playwright launcher explicitly sets `chromiumSandbox: true` on macOS and Windows; Linux retains its existing compatibility fallback.
32
+
33
+ These code changes do not certify an unsigned local browser or a future signed release. Acceptance still requires the real Developer ID/notary workflow and a clean Mac run of the **extracted distributed** browser, including renderer and GPU processes with the sandbox enabled, plus the relevant hosted Windows checks. No signing credential, quarantine attribute or production installer was modified to claim that acceptance locally. A blanket `codesign --deep` substitution is insufficient. See [Chromium's signing process](https://chromium.googlesource.com/chromium/src/+/main/chrome/installer/mac/signing/README.md) and [Apple's distribution signing guidance](https://developer.apple.com/documentation/xcode/creating-distribution-signed-code-for-the-mac/).
34
+
35
+ ## Observed production release failure
36
+
37
+ Desktop [CI run 33986784637](https://github.com/fjpulidop/specrails-desktop/actions/runs/33986784637) and the [v2.41.0 native release run](https://github.com/fjpulidop/specrails-desktop/actions/runs/33986801426) succeeded. The separate [npm publication run 33986784639](https://github.com/fjpulidop/specrails-desktop/actions/runs/33986784639) failed with `E404` on `PUT https://registry.npmjs.org/specrails-desktop`. The package remains readable in the registry. This result requires checking npm publication authorization; it does not establish exactly which credential or account setting is wrong. Source changes cannot prove that the configured secret can publish.
38
+
39
+ Follow [Desktop CI and releases](../ci-cd.md) and [Core CI and publishing](https://github.com/fjpulidop/specrails-core/blob/main/docs/ci-cd.md) when configuring credentials or retrying publication. npm trusted publishing needs repository/workflow configuration in the npm account before token authentication can be removed. The implementation follows [GitHub's workflow permission rules](https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-syntax) and [npm's provenance requirements](https://docs.npmjs.com/generating-provenance-statements/).
@@ -0,0 +1,68 @@
1
+ # Core runtime selection and updates
2
+
3
+ Desktop resolves one Core runtime for framework materialization, project setup,
4
+ compatibility checks and execution helpers. `server/core-runtime.ts` performs
5
+ read-only discovery; it does not execute a PATH shim or install a global package.
6
+
7
+ An explicit `SPECRAILS_CORE_BIN` wins when it resolves to a usable compatible
8
+ package. Otherwise Desktop selects the newest compatible package from its
9
+ activated managed installation, bundled resources, local dependency and external
10
+ CLI on PATH. Core 4 and 5 remain supported. A runtime older than the active
11
+ framework is rejected rather than silently replacing an update.
12
+
13
+ ## Persistence and publication
14
+
15
+ Desktop updates retain the complete npm installation, including dependencies,
16
+ under `~/.specrails/core/<version>/`. The registry home override applies to this
17
+ directory. Only the managed package corresponding to the active framework is
18
+ eligible; an unpublished staging directory is not an installation candidate.
19
+
20
+ Updates verify the downloaded version, retain the package, materialize every
21
+ requested provider without swapping, and persist recovery state before moving
22
+ `framework/current`. Incomplete retained packages are moved to a retained
23
+ `.previous-<version>-*` directory before their verified replacement is published.
24
+ Previous framework versions are retained. Windows repair reads the activated
25
+ version instead of choosing the highest directory, which could be an unfinished
26
+ stage.
27
+
28
+ Changing the shared pointer does not update copied project files. The update
29
+ therefore waits for all affected workspaces to be assembled again. Existing
30
+ provider installation configuration and MCP configuration are preserved. A
31
+ workspace's version marker and any runtime helper declared by the selected Core
32
+ contract are verified before that workspace is considered refreshed.
33
+
34
+ ## Partial refresh and recovery
35
+
36
+ The global `core/update-status.json` stores a pending version before publication.
37
+ Affected workspaces receive `.specrails/core-update-pending.json` before the
38
+ first asynchronous assembly. New implementations in those workspaces are
39
+ blocked until verification clears the marker; reading projects and conversations
40
+ remains available. The global pending state also protects an old workspace whose
41
+ local marker could not be written.
42
+
43
+ If one workspace fails after publication, Desktop reports a partial update and
44
+ retains the pending state across restart. It does not claim that a global pointer
45
+ rollback restored already updated copies. **Finish updating** retries with the
46
+ retained package and works offline. Successful completion is emitted only after
47
+ all workspace refreshes and the final recovery-state write succeed.
48
+
49
+ ## Version reporting
50
+
51
+ Global status distinguishes the selected runtime and its source, the active
52
+ framework, the version included in Desktop, and the last successful registry
53
+ check. Installing an explicit target does not overwrite a newer known registry
54
+ version. Registry-check cache failures do not erase installed-version information;
55
+ recovery-state write failures prevent publication or successful completion.
56
+
57
+ Project status reports provider link versions separately from the workspace seed
58
+ marker. Mixed links/copies or a pending refresh produce `mixed: true` and no
59
+ single claimed installed version. Copied and deliberately pinned projects retain
60
+ their own version instead of inheriting global `current`.
61
+
62
+ Core 5 uses deterministic installation. Legacy enrichment entry points complete
63
+ only when the native Core 5 role and command artifacts are present; otherwise
64
+ they request installation repair and never invoke a removed enrichment command.
65
+
66
+ Tests use temporary installations and fake CLI processes, including a fresh Node
67
+ process that resolves an updated package and materializes another provider
68
+ offline. No global CLI or user project is updated by these tests.
@@ -1,5 +1,7 @@
1
1
  # Embedded browser: native-webview evaluation (Cursor-class experience)
2
2
 
3
+ > Update 2026-09-05: mission browsing now also uses the native pane on macOS, with same-page Retina snapshots, DOM selection and annotations. The original evaluation below is historical; current behavior and validation are documented in [the browser audit](browser-native-retina-audit.md).
4
+
3
5
  > Status: **implemented (phases 0–1 + devtools/zoom from phase 2)** — researched
4
6
  > 2026-07-26, shipped via OpenSpec change `native-embedded-browser`. As-built:
5
7
  > `src-tauri/src/browser.rs`, `client/src/lib/native-browser.ts`,
@@ -0,0 +1,93 @@
1
+ # Implementation reliability audit — 2026-09-05
2
+
3
+ Scope: built-in Implement, Batch Implement, Freestyle and SDD Quick loops;
4
+ custom-loop execution; mission-to-rail launches; delivery review, local
5
+ integration and Git worktree checkout. Implemented on `feat/codex-gpt-6-astra`,
6
+ preserving the unfinished Astra catalog changes already on that branch.
7
+
8
+ The subsequent startup/update disconnection investigation is documented in
9
+ [Startup and update recovery audit](./startup-recovery-audit.md).
10
+
11
+ The 2026-09-06 Claude Implement follow-up is documented in
12
+ [Claude implementation reliability](../../openspec/changes/claude-implement-reliability/verification.md).
13
+ It corrects early termination of pending architect tasks, explicitly registers
14
+ the packaged `opsx:*` commands, and makes verification/refinement retain the
15
+ complete frozen multi-repository spec scope. Passing baseline checks cannot
16
+ substitute for implementing the requested behavior.
17
+
18
+ ## Findings and changes
19
+
20
+ | Area | Failure found | Resulting behavior |
21
+ | --- | --- | --- |
22
+ | Loop outcome | AI/shell errors could reach a successful End; a Decider STOP could override a failed step. | Failed passes cannot succeed. Repair must be followed by a successful verification. |
23
+ | Verification | A successful CLI invocation or parseable Decider reply was insufficient proof of verification. | Built-in verification requires an explicit final `VERIFICATION: PASS` line and a successful invocation. Failed/absent verdicts trigger repair. |
24
+ | Decider execution | JSON from a timed-out or failed CLI could be accepted. | Transport/process errors invalidate the decision. |
25
+ | Resident CLI errors | A terminal Claude error result could be treated as a successful turn while the process remained alive; an earlier PASS could survive when the error omitted text. | Terminal result errors stop the failed step after recording usage. Recoverable individual tool errors remain available for the agent to fix. |
26
+ | Progress detection | Hashing only HEAD and status/path names treated edits to the same files as no progress. | The fingerprint includes tracked/index binary diffs and untracked content, without following external symlinks. |
27
+ | Deadlines | The run deadline was checked only between steps; untimed built-ins could remain silent forever. | Remaining deadlines reach each executor. Both AI transports have a configurable inactivity watchdog; active long implementations retain their untimed behavior. |
28
+ | Inactivity retry | Retrying a stalled invocation reused its checkpoint and lost the first attempt's cost. | Every attempt has its own recorded checkpoint and usage; retries respect the remaining budget and deadline. |
29
+ | Provider limits | A throwing notification subscriber could disrupt settlement after a provider limit. | Reporting the provider limit cannot replace or interrupt the persisted execution outcome. |
30
+ | Run isolation | Shared settlement options could carry one run's stall reason into another run. | Each run receives independently derived settlement options. |
31
+ | SDD shell steps | Relocated projects executed shell commands in the artifact workspace. | Shell steps execute in the actual repository/worktree. |
32
+ | Gemini | Loop spawns skipped the provider's headless initialization. | The provider preparation hook runs before spawning, matching QueueManager. |
33
+ | Isolation failure | Operational worktree allocation failures fell back to the user's checkout. | Launch fails explicitly without executing the implementation in the shared checkout. Initial non-Git/unborn repositories retain their explicit degraded path. |
34
+ | Batch review | The Decider received only the first ticket's spec. | Every ticket's launch snapshot reaches the evaluation context. |
35
+ | Custom graphs | Duplicate IDs, invalid limits, ambiguous branches and unsupported fan-out could skip work silently. | Validation rejects graphs the sequential engine cannot execute faithfully. This does not add AND/OR execution semantics. |
36
+ | Rail profiles | The selected profile was resolved by the route but dropped before loop execution. | Isolated/shared launches and interactive/one-shot steps receive the selection. Named profiles get immutable snapshots and the orchestrator model is honored; explicit model selection wins. Missing named profiles fail before launch. |
37
+ | Model handoff | Mission launches could inherit effort while dropping the selected model. | Matching-engine launches inherit both together unless explicitly overridden. |
38
+ | Local integration | Any dirty checkout blocked integration, even unrelated files; a different checked-out branch also blocked it. | Integration assembles away from the user's checkout and uses a non-forced fast-forward. Compatible edits survive; conflicting tracked, untracked and ignored files remain protected. Another active branch remains untouched while the integration branch is updated through a temporary worktree. |
39
+ | Commit authority | Missing delivery SHA could fall back to a mutable branch tip. | Integration requires recorded, available commits; stale/missing evidence cannot authorize unrelated work. |
40
+ | Stacked milestone acceptance | With no assembled delivery SHA, proving only the first unit could complete tickets and clean branches for the whole delivery. | Every unit must have a valid immutable SHA and proven ancestry before acceptance or cleanup; incomplete evidence retains review state. |
41
+ | Integration races | A checkout change near the final advance could make cleanup unsafe. | Destination identity is checked before and after the advance; failure preserves work and does not mark tickets done. |
42
+ | Checkout | The UI required a remote PR, and dirty/cleanup guards blocked compatible local handoffs. | A single verified local result can be checked out before creating a PR. Branch/SHA checks remain mandatory. Cleanup warnings from other retained worktrees do not prevent a valid checkout. |
43
+ | Cleanup | A directory listed as ignored at settlement could gain new files before cleanup. | Its contents are preserved in a recorded safety archive before release, including subsequent additions. |
44
+ | Review evidence | Persisted `{line}` log envelopes were read as raw JSON; interrupted verification could still advertise PASS. | Logs are decoded, verdicts must occupy a verdict line, and incomplete/failed verification cannot provide green evidence. |
45
+ | Mission/board state | Every 409 was treated as already resolved; failed aborts could hide a running job; late Git responses could overwrite current state. | Only stale decisions reconcile neutrally. Real errors remain visible, rejected aborts retain the active session, and old responses cannot overwrite newer project state. |
46
+ | Project routing | A mission review card could open using the currently active project's API. | The review opens in the delivery's own project. |
47
+ | Agent instructions | The operator conflated implementation success with Done and omitted the local Git handoff contract. | Instructions distinguish `on_review`, acceptance, checkout and integration, and preserve user data when an action is blocked. |
48
+ | Astra | Partial catalog work omitted standalone loops and had an unresolved test import. Generic effort lists also offered unsupported model tiers. | Astra is available throughout the selectors and Max preset, with GPT-5.5 still the default and no invented pricing. Current Codex model-specific effort lists are reflected in client and server. |
49
+
50
+ ## Verification
51
+
52
+ Regression tests exercise real temporary Git repositories for dirty indexes,
53
+ compatible and conflicting edits, untracked/ignored files, detached HEAD,
54
+ other checked-out branches, branch occupation, exact commit identity, retries,
55
+ batch conflicts, external branch changes and worktree cleanup. Provider process
56
+ tests inject controlled CLI streams, failures and inactivity rather than
57
+ spending quota on real model calls. UI tests cover mission and board actions,
58
+ project switching, stale responses, abort rejection and error presentation.
59
+
60
+ Final validation on 2026-09-05:
61
+
62
+ | Check | Result |
63
+ | --- | --- |
64
+ | `npm run test:coverage` (server/CLI/MCP) | 272 files, **7,263 tests passed**. |
65
+ | Server/CLI coverage | **87.81% lines**, 85.43% statements, 77.62% branches, 89.52% functions; all configured thresholds passed. |
66
+ | Client `npm run test:coverage -- --maxWorkers=2` | 348 files, **4,310 tests passed**. |
67
+ | Client coverage | **89.06% lines/statements**, 82.87% branches, 74.21% functions; all configured thresholds passed. |
68
+ | `npm run typecheck` | Passed across server, CLI, MCP bridge and client. |
69
+ | `npm run build` | Passed (server, client and CLI); existing Vite chunk-size advisory remains. |
70
+ | `npm run check-core-compat` | Passed against locally installed `specrails-core@4.11.1`. |
71
+ | `git diff --check` | Passed. |
72
+
73
+ Total: **11,573 passing tests**. The final terminal-result regression reproduced
74
+ eight failures before its fix. No test thresholds were lowered or files excluded
75
+ to obtain coverage. HTTP/IPC/Git suites ran outside the filesystem sandbox where
76
+ necessary for their temporary local sockets and repositories.
77
+
78
+ ## Operational boundaries
79
+
80
+ `SPECRAILS_LOOP_INACTIVITY_MS` controls the AI-step inactivity watchdog
81
+ (milliseconds; default 1,800,000 = 30 minutes; `0` disables it). Output resets
82
+ this timer. Explicit graph run/step deadlines still apply independently.
83
+
84
+ Actual source conflicts and another checkout holding the integration branch
85
+ remain actionable blocks; local user data is never forcibly overwritten to
86
+ make an action appear successful. A preserved directory is exposed through the
87
+ delivery's safety-archive metadata and cleanup warnings.
88
+
89
+ These changes remove reproduced application faults. Provider quota, service
90
+ availability, model decisions, external Git writers and project-specific build
91
+ failures remain external inputs; the application must report and preserve work
92
+ when they fail. No live provider execution, remote PR publication or release
93
+ deployment is part of the automated validation.
@@ -63,7 +63,7 @@ spawnInteractive = isInteractiveJobsEnabled() // SPECRAILS_INTERACTIV
63
63
  | Who gets it | freestyle/Freestyle QueueManager jobs (claude) | every other interactive job + ALL loop ai-steps |
64
64
  | End of session | explicit human **Finalize** only (SIGTERM → 2s → SIGKILL) | **quiescence**: a turn `result` arrived, nothing queued, no write in flight — torn down GRACEFULLY: stdin EOF (the CLI exits itself, flushing its session transcript so the next loop step can `--resume`), SIGTERM only after a grace window (`quiescentEofGraceMs`, default 5s) or when stdin is already gone |
65
65
  | Idle between turns | by design (awaiting the human) | only transiently (microtask window) |
66
- | Wedge detector | never armed | the queue's zombie-timeout budget, reset on any raw child output; silence for the whole budget → fold in-flight turn, settle `crashed` |
66
+ | Wedge detector | never armed | the queue's zombie-timeout budget (QueueManager) / the loop-step idle budget (loop ai-steps — `server/loop-step-idle.ts`, default 30 min, `SPECRAILS_LOOP_STEP_IDLE_TIMEOUT_MS`), reset on any raw child output; silence for the whole budget → fold in-flight turn, settle `crashed` (loop steps: tagged `stalled`, retried once by resume) |
67
67
  | Composer action | **Finalize Job** | **Wrap up now** (QueueManager) / **Settle this step** (loop step) |
68
68
 
69
69
  **Quiescence detail:** the auto-settle is deferred to a microtask after the `result` so anything
@@ -98,9 +98,16 @@ persistent stdin, each claude **ai-step** runs as its own `InteractiveJobSession
98
98
  quiescence / explicit finalize → `'finalized'` (step ok); step timeout → `session.abort()` →
99
99
  fold in-flight turn → `'crashed'`; run cancel → `abort()` → `'crashed'` → engine settles the
100
100
  run `'stopped'` at the next boundary; manager shutdown / project removal → `dispose()` (kill,
101
- NO settle; the startup orphan sweeps reconcile rows on next boot). No zombie timer is armed on
102
- loop steps — the loop's ai-step timeout bounds the whole step and is the sole watchdog
103
- (byte-parity with the one-shot loop path, which has no zombie detector either).
101
+ NO settle; the startup orphan sweeps reconcile rows on next boot). The session's zombie timer
102
+ IS the loop step's **idle watchdog** (`zombieTimeoutMs = plan.idleTimeoutMs`, `onZombieTimeout`
103
+ tags the settle `stalled`): factory loops are UNTIMED (`aiStepTimeoutMinutes = 0`), so before
104
+ this bound a wedged provider left the run `running` forever. Silence for the idle budget →
105
+ `loop_step_end { status:'stalled', reason:'idle_timeout', idleMs }` → the engine retries the
106
+ SAME step once by resuming the captured session (`loop_step { attempt: 2 }`); a second stall
107
+ settles the run `stalled` (tickets → `todo`, delivery row auto-closes). The one-shot loop path
108
+ arms the same bound through `runAiCliInvocation`'s `inactivityTimeoutMs`. Contract:
109
+ `server/loop-step-idle.ts` — `SPECRAILS_LOOP_STEP_IDLE_TIMEOUT_MS` (default 30 min; `0|false|off`
110
+ disables; clamped ≥ the stuck-notification threshold so `job.stuck` always precedes teardown).
104
111
 
105
112
  ## Accounting reconciliation
106
113
 
@@ -159,6 +166,100 @@ command didn't actually run, the settle is FAILED.**
159
166
  from the step result's accumulated signals (one-shot `text` accumulates only from assistant
160
167
  text-deltas, so non-empty text ⇒ assistant events were seen).
161
168
 
169
+ ## CLI notification turns, orphaned background tasks, resume misses (run `5c958db2`)
170
+
171
+ Live evidence (loop run `5c958db2`, claude 2.1.260, factory Freestyle): the **verify** step
172
+ backgrounded the CI chain (`run_in_background`), replied *"I'll deliver the final verdict line
173
+ when it lands"*, and quiesced. The auto-settle EOF'd stdin; the CLI kept the process alive for
174
+ its background tasks, so the 5 s grace expired and SIGTERM tore it down — orphaning the tasks.
175
+ The Decider (rightly) said *continue*, and the **fix** step `--resume`d the same session. On
176
+ resume the CLI reported the orphans (`system/task_notification … "Orphaned by a previous Claude
177
+ Code process exit"`) and emitted a **turn of its own** BEFORE processing our prompt: a `result`
178
+ frame with `origin: {kind:'task-notification'}`, `num_turns: 0`, `stop_reason: null`, empty
179
+ `result`, zero usage. The session took it as our turn's terminal result → quiescent auto-settle →
180
+ the real turn (already thinking) was killed 5 s later as a zero-work FAILED step in "0.1 s". Three
181
+ guards now cover the chain:
182
+
183
+ - **Notification frames are not turn results.** `isClaudeNotificationResultFrame`
184
+ (`server/providers/claude-adapter.ts`) recognises `origin.kind === 'task-notification'`; the
185
+ adapter surfaces such a frame as a NON-terminal `{kind:'other', type:'result'}` event, so every
186
+ adapter-event consumer (persistent Explore turns, agent chat, `extractResult`, crash recovery)
187
+ ignores it. `InteractiveJobSession._handleStdoutLine` classifies through the adapter BEFORE the
188
+ drop logic: a result frame with no `kind:'result'` adapter event leaves the turn armed, is NOT
189
+ persisted as a `result` row (recovery counts persisted result rows as completed turns), and
190
+ logs `↷ claude reported a background-task notification (not this turn's result) — continuing.`
191
+ The caller's own turns carry no `origin` at all; other `origin.kind` values the CLI bundle
192
+ knows (`human`, `auto-continuation`, `observer-activity`, `channel`) are deliberately NOT
193
+ special-cased — only the observed no-op kind is.
194
+ - **Resume miss ⇒ one fresh retry (loop engine).** `isResumeMiss` (`loop-run-manager.ts`): a
195
+ step that resumed the previous step's session and settled zero-work WITHOUT an
196
+ `Unknown command:` text and WITHOUT the step timeout was answered by session bookkeeping, not
197
+ the model — the prompt never ran. The engine logs
198
+ `↻ Resuming session <id> produced no work — retrying this step in a fresh session.` and re-runs
199
+ the SAME prompt once with no `sessionId`, inside the same step (one `loop_step`/`loop_step_end`
200
+ pair, one `record()` row from the final attempt; the empty attempt has nothing to account).
201
+ A fresh (non-resumed) zero-work step, an Unknown-command, a timeout, a cancel, or a zero-work
202
+ retry all keep the existing FAILED path. This is the belt-and-braces for the OTHER resume-miss
203
+ cause — a transcript the SIGTERM escalation raced (the graceful-EOF fix in `_finalizeQuiescent`
204
+ made that rare, not impossible).
205
+ - **Backgrounding is forbidden and visible.** `FOREGROUND_RULE` (`loop-constants.ts`) rides
206
+ `{{const:GUARDRAILS}}` and the verify / fix / freestyle templates (plus the default Freestyle
207
+ pre-prompt): run every command in the foreground, never `run_in_background`/`&`, the reply ends
208
+ the step. At quiescent auto-settle the session mirrors claude's
209
+ `system/background_tasks_changed` roster and, when tasks are still running, persists
210
+ `⚠️ The agent ended its turn with N background task(s) still running (…) — long commands must
211
+ run in the foreground.` so a verdict-less verify step explains itself. Finalize mode (idling by
212
+ design) never emits it.
213
+ - **User cancel is not a provider failure.** The `AI_FAILFAST_THRESHOLD` streak skips a step
214
+ torn down by `cancel()`, so the run settles `stopped` instead of `failed` with a misleading
215
+ *"provider appears down"* (the live run hit exactly that when the user stopped it mid-verify).
216
+
217
+ ## Provider usage / rate limits (run `52124009`, 2026-09-04)
218
+
219
+ The claude subscription hit its session limit mid-batch. The CLI answered
220
+ every later spawn in ~0.5 s with a `result` frame whose text was
221
+ *"You've hit your session limit · resets 3am (Europe/Madrid)"* and
222
+ `is_error: true`. The engine saw a non-empty, exit-0 reply → step `ok` →
223
+ verify → decider (unparseable → continue) → fix … three full cycles until the
224
+ no-progress stall guard finally stopped the run — nine steps of nothing after
225
+ the real cause. A limit is not something to iterate on.
226
+
227
+ - **Structural signal.** The claude adapter now carries `is_error` on the
228
+ `result` AdapterEvent (`isError`); `InteractiveJobSession` captures it per
229
+ turn (`SettleInfo.resultIsError`) and the one-shot executor reads it off the
230
+ result event. Both AI-step paths mark such a step `failed` with the result
231
+ text as `errorText` (`AiStepResult.resultIsError`), and the engine's
232
+ fail-fast counts an error result even though it carried text (two in a row
233
+ ⇒ "provider appears down", as for no-output crashes).
234
+ - **Limit classifier (`server/provider-limit.ts`).** `classifyProviderLimit`
235
+ judges only the TAIL of a step's final text / error text (a spec discussing
236
+ rate limiting never trips it): claude session/usage limits and the API
237
+ wrapper (`error type rate_limit`, `HTTP 429`), codex quota notices, gemini
238
+ `RESOURCE_EXHAUSTED`; `extractLimitReset` pulls the provider's reset hint
239
+ ("3am (Europe/Madrid)", "in 2 hours").
240
+ - **Engine stop.** On a hit the AI step closes `loop_step_end { status:
241
+ 'failed', reason: 'provider_limit' }`, logs `■ Provider limit reached
242
+ (<provider>): <the provider's sentence> — relaunch or Recover & retry after
243
+ the reset`, records the invocation as failed, broadcasts the project-scoped
244
+ `loop.provider_limit { runId, provider, kind, message, resetsAt }` and
245
+ settles the run `stalled` with `LoopRunResult.stallReason = 'provider_limit'`
246
+ (+ `providerLimit`) — no verify, no decider, no retry. The other stall paths
247
+ now name their reason too (`idle_timeout`, `no_progress`).
248
+ - **Propagation.** Every run-finished caller forwards `stallReason` to
249
+ `onLoopRunFinished(runId, outcome, { stallReason })`; the milestone chain
250
+ records `last_run_outcome = 'provider_limit'` and pauses with its OWN reason
251
+ `provider_limit` (Resume after the reset relaunches the same chunk). Client:
252
+ `useOsNotifications` toasts `loop.provider_limit` (provider + reset hint +
253
+ the provider's sentence, OS notification when permitted), the step section
254
+ shows a **Provider limit** badge, narration says "Step N stopped — the
255
+ provider's usage limit was reached", the chain row/toast localise the reason.
256
+ i18n `jobs:loopExplorer.providerLimit*`, `narration:step.providerLimit`,
257
+ `commands:notifications.providerLimit*`,
258
+ `builder:milestoneProgress.chain.reasons.provider_limit` ×8.
259
+ - **Not detected (by design):** a Decider whose own reply is the limit
260
+ notice — the executor exposes no raw text; in practice the preceding AI
261
+ step already stopped the run.
262
+
162
263
  ## Zombie / timeout interplay
163
264
 
164
265
  - **One-shot jobs**: unchanged — the queue's zombie timer kills a silent child.
@@ -166,8 +267,11 @@ command didn't actually run, the settle is FAILED.**
166
267
  stdout/stderr `data`); firing folds the in-flight turn and settles `'crashed'`.
167
268
  - **Interactive `'finalize'`**: no timer at all — an idle session awaiting Finalize is the
168
269
  feature. QueueManager's queue-level timer is never armed for interactive jobs.
169
- - **Loop ai-steps**: no zombie timer; the step timeout aborts the session (`'crashed'`,
170
- `errorText: 'AI step timed out'`), partial work accounted.
270
+ - **Loop ai-steps**: the idle watchdog (`loop-step-idle`) is armed as the session's zombie timer
271
+ (`'crashed'` + `stalled` flag, `errorText: 'AI step stalled'`, retried once by resume); the
272
+ optional step timeout still aborts the session (`'crashed'`, `errorText: 'AI step timed out'`),
273
+ partial work accounted either way. `job.stuck` carries `actions: ['stop']` — the client toast
274
+ offers **Stop run** through the existing `POST /jobs/:id/cancel` route.
171
275
  - **Finalize hard-deadline**: SIGTERM → 2s → SIGKILL, plus a forced settle if the child never
172
276
  emits `close` (D-state / signal-swallowing) so the queue slot can never leak.
173
277
  - **Undeliverable turns**: a confirmed-failed stdin write (destroyed/EPIPE) is surfaced as a
@@ -0,0 +1,76 @@
1
+ # MCP and mission operator reliability audit
2
+
3
+ Date: 2026-09-05. Branch: `feat/codex-gpt-6-astra`.
4
+
5
+ This audit covers the embedded MCP server, stdio bridge, tool contracts and
6
+ mission operator context. It builds on the implementation/worktree and startup
7
+ recovery fixes already present on this branch. No production AI runs were
8
+ launched, no project state was changed through the audited operational tools,
9
+ and no remote PRs were created. Source changes are retained on this branch.
10
+
11
+ ## Findings and corrections
12
+
13
+ | Failure | Correction |
14
+ | --- | --- |
15
+ | A missing scoped spec/job could resolve to an entity in another project; references were deduplicated without their project scope. | Treat a project id as an exact address, retain scope in deduplication, report ambiguous/unavailable references, and never substitute another repository. |
16
+ | Missions received a project id but little current project context. A fresh provider session could lose conversation history. | Add bounded live project/provider/backlog/job orientation per turn and restore recent persisted history only on fresh invocations. Historical messages are labelled as data; current settings and live evidence take precedence. |
17
+ | An empty resumed reply could trigger a replay after tools had already executed. Missing MCP wiring silently launched a tool-less paid agent. | Retry only explicit stale-session errors without tool activity. Fail before provider launch if MCP preparation fails. |
18
+ | Project selection was process-global across external MCP clients. Mission selection could claim success despite its immutable capability pin. | Isolate defaults per MCP session. Preserve the mission pin, including Home; explicit project ids address intentional operations elsewhere. |
19
+ | Invalid/revoked mission capabilities could fall through to external-client permissions. Sessions were not bound to their originating capability. | Reject invalid capabilities, bind session ownership to the capability, close revoked/expired/idle sessions, and fail explicitly when the bridge cannot read its capability file. |
20
+ | Token rotation and session loss left clients disconnected or hanging. | Refresh bridge authentication on each request, retry a rejected 401 only after a token change, reinitialize after a protocol session 404, and terminate remote sessions on close. Network failures never replay a possibly-started mutation. |
21
+ | MCP admin tier edits could partially apply before returning 400; token rotation left old streams alive. | Validate all tier fields before writes; rotating the token closes existing sessions. Failed token persistence cannot silently publish an unusable token. |
22
+ | Mixed read/write facades advertised read-only MCP annotations. Some draft commits that can spawn Contract Refine were classified as Write. | Publish conservative facade annotations, expose precise action/argument tier previews, and enforce AI-spawn for potentially cost-incurring commits. |
23
+ | The project catalog and diagnostics hid registered projects whose databases were unavailable. | Use durable registry rows for tools/resources, preserve identity and show availability explicitly. Context sections fail independently rather than implying empty state. |
24
+ | Tool discovery ignored action names and nested argument structure. | Search names/actions/schema descriptions, support common Spanish intents, expose full SDK-generated JSON schemas, and validate prospective arguments without execution. |
25
+ | Watch only observed future events and could wait for completed jobs/loops; whole-payload substring matching could settle on the wrong entity. | Read durable job/loop state before waiting, match typed identity fields, retain bounded events, distinguish failure, and support cancellation. |
26
+ | Raw file reads and job histories could consume excessive model context; Code Explorer only searched filenames. | Add literal content search, bounded source pages with line/column continuations and revision hashes, compact spec/job lists and paginated event history. Partial results explicitly report their limits. |
27
+ | Operational tools omitted useful review evidence and conversational launch defaults. | Add PR candidates/review packets, Git/worktree information, PR lookup and phase breakdowns. Preserve conversation provider/model/effort when launching compatible jobs/loops, and report when isolation is unavailable. |
28
+ | Binary attachments were forwarded through a text response path. | Return attachment metadata and a download reference instead of decoding arbitrary bytes as text. |
29
+
30
+ ## New investigation workflow
31
+
32
+ 1. Identify the intended project from the conversation pin or durable catalog.
33
+ 2. Read `specrails_context` sections relevant to the question: `overview`,
34
+ `backlog`, `runs`, `git`, `blueprint`. Each result names its source and reports
35
+ unavailable data; these independent reads are not an atomic snapshot.
36
+ 3. Locate behavior/tests with `specrails_code(search)` and read exact source
37
+ ranges. Use the returned hash when continuing to detect intervening edits.
38
+ 4. Discover exact tool arguments and permissions with `specrails_describe`.
39
+ Schema validation does not execute the tool or replace backend checks.
40
+ 5. Inspect execution evidence and the verified review packet before describing
41
+ completion. Refresh affected context after operations.
42
+
43
+ The catalog now has 22 tools. Existing domain tools gain focused read actions;
44
+ implementation and delivery still use the app's existing validated routes.
45
+
46
+ ## Validation
47
+
48
+ Focused regression suites cover real HTTP/SDK session isolation and recovery,
49
+ capability revocation, tier boundaries, temporary project databases, source
50
+ search/read bounds, historical context and no-replay behavior.
51
+
52
+ - Server/CLI/MCP: 281 test files, 7,394 passing tests. Coverage: statements
53
+ 85.97%, branches 78.38%, functions 90.02%, lines 88.31%; all thresholds pass.
54
+ - Client: 348 test files, 4,335 passing tests. Coverage: statements/lines 89.13%,
55
+ branches 82.86%, functions 74.35%; all thresholds pass.
56
+ - TypeScript, app/server/CLI build and the bundled MCP bridge build pass.
57
+ - Core compatibility passes: core 4.11.1 with desktop 2.40.0.
58
+ - `git diff --check` passes. The app build retains the existing Vite large-chunk
59
+ advisory; it is not a build failure.
60
+
61
+ Total for this audit's complete run: 11,729 passing tests, including 120 more
62
+ server/CLI/MCP tests than the preceding startup-recovery audit. Test fixtures
63
+ use temporary databases/repositories and local HTTP servers.
64
+
65
+ ## Practical limits
66
+
67
+ - This establishes deterministic platform behavior under the tested failures;
68
+ it cannot guarantee the quality or success of every future model-generated
69
+ implementation or third-party provider/GitHub operation.
70
+ - Durable watch recovery covers jobs and loop runs. Other async operations use
71
+ future bus events and their domain reads; there is no generic durable replay.
72
+ - Context is deliberately bounded, and blueprint milestones are plans rather
73
+ than proof that work is done. Truncated or unavailable results require a
74
+ narrower source read, never a fabricated conclusion.
75
+ - The application sources and bundles are updated on this branch. Updating the
76
+ installed native application remains a separate release/install operation.