specrails-desktop 2.55.0 → 2.56.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (368) hide show
  1. package/cli/dist/args.js +80 -0
  2. package/cli/dist/desktop-client.js +125 -0
  3. package/cli/dist/desktop-control.js +339 -0
  4. package/cli/dist/format.js +45 -0
  5. package/cli/dist/help.js +68 -0
  6. package/cli/dist/output.js +47 -0
  7. package/cli/dist/run-command.js +340 -0
  8. package/cli/dist/specrails-desktop.js +41 -1107
  9. package/cli/dist/status.js +111 -0
  10. package/client/dist/assets/{ActivityFeedPage-ILXMZXcb.js → ActivityFeedPage-DdMNmVBk.js} +1 -1
  11. package/client/dist/assets/{AgentBrowserCapture-UcsupCy7.js → AgentBrowserCapture-CeerUf--.js} +1 -1
  12. package/client/dist/assets/{AgentModeAnalyticsPane-CQuxYh8B.js → AgentModeAnalyticsPane-BjGb-8rh.js} +2 -2
  13. package/client/dist/assets/{AgentModeCodePane-zPWbW7ei.js → AgentModeCodePane-8XRkQEo_.js} +2 -2
  14. package/client/dist/assets/{AgentModeJobsPane-CInByIdl.js → AgentModeJobsPane-BN3dgJOA.js} +1 -1
  15. package/client/dist/assets/{AgentsPage-BWvgxaBv.js → AgentsPage-DfHWgP_x.js} +1 -1
  16. package/client/dist/assets/{AnalyticsPage-DP3jakv-.js → AnalyticsPage-CyfhYiBn.js} +1 -1
  17. package/client/dist/assets/{CodePage-BKXiwE5a.js → CodePage-C2Nf-Q5W.js} +1 -1
  18. package/client/dist/assets/{DesktopAnalyticsPage-DryJOaMz.js → DesktopAnalyticsPage-tc0p4jJW.js} +1 -1
  19. package/client/dist/assets/{DocsDialog-BsCG9ksG.js → DocsDialog-Br3bczCp.js} +1 -1
  20. package/client/dist/assets/{DocsPage-Cc-GeKYl.js → DocsPage-BcDr2cBm.js} +1 -1
  21. package/client/dist/assets/{ExportDropdown-ClahJdDn.js → ExportDropdown-BVGKEgkd.js} +1 -1
  22. package/client/dist/assets/{InteractiveJobComposer-DfLF6N0f.js → InteractiveJobComposer-DFPpdg2D.js} +1 -1
  23. package/client/dist/assets/{JobDetailModal-DHeur9YK.js → JobDetailModal-BdOv-l-M.js} +1 -1
  24. package/client/dist/assets/{JobDetailPage-CraDKzeG.js → JobDetailPage-vBbNeRuz.js} +1 -1
  25. package/client/dist/assets/{JobsPage-CcbuSwj7.js → JobsPage-CJCtPhIz.js} +1 -1
  26. package/client/dist/assets/{LoopBuilderPage-BKtNp494.js → LoopBuilderPage-BemvUOxy.js} +1 -1
  27. package/client/dist/assets/{LoopPreviewModal-DbZd9isy.js → LoopPreviewModal-C6hNAeYN.js} +1 -1
  28. package/client/dist/assets/{LoopsPage-DEg6sIkG.js → LoopsPage-BZr0quvh.js} +1 -1
  29. package/client/dist/assets/{MinimizedChatsContext-BGtEjWsc.js → MinimizedChatsContext-D3QzgV0B.js} +1 -1
  30. package/client/dist/assets/{PluginsPage-BVqSsPzL.js → PluginsPage-DOpTV75p.js} +1 -1
  31. package/client/dist/assets/{ProjectSettingsDialog-CAjLgJAZ.js → ProjectSettingsDialog-Dkwrn0z1.js} +1 -1
  32. package/client/dist/assets/{RepositoryDeliveries-DrcrxLe0.js → RepositoryDeliveries-Du2UCf1a.js} +1 -1
  33. package/client/dist/assets/{RepositoryScopeSelector-CAGY3xW6.js → RepositoryScopeSelector-hPGZNRBm.js} +1 -1
  34. package/client/dist/assets/ReviewPacketPage-DcOq-UTA.js +4 -0
  35. package/client/dist/assets/{TemplatePreviewModal-Bqs-9fhn.js → TemplatePreviewModal-Cejcquah.js} +1 -1
  36. package/client/dist/assets/{TicketDetailModalContext-C0jQ5yOk.js → TicketDetailModalContext-DAK-NoK6.js} +1 -1
  37. package/client/dist/assets/{Trans-DtWlCJN9.js → Trans-DEbgkuAY.js} +1 -1
  38. package/client/dist/assets/{dashboard-CTfEtkqX.js → dashboard-B9uWNGO2.js} +1 -1
  39. package/client/dist/assets/{dashboard-DMklepmz.js → dashboard-BIwmO9wc.js} +1 -1
  40. package/client/dist/assets/{dashboard-DBAP2_SQ.js → dashboard-BV4vOZkR.js} +1 -1
  41. package/client/dist/assets/{dashboard-D40HP2ks.js → dashboard-Bf6MPVsM.js} +1 -1
  42. package/client/dist/assets/{dashboard-Csf1yGSN.js → dashboard-C8klWVvZ.js} +1 -1
  43. package/client/dist/assets/{dashboard-C29Qwa-L.js → dashboard-D1ORhPF0.js} +1 -1
  44. package/client/dist/assets/{dashboard-Cr4D8oMn.js → dashboard-DSubvs9x.js} +1 -1
  45. package/client/dist/assets/{dashboard-CSJzf5OT.js → dashboard-px_vlRx_.js} +1 -1
  46. package/client/dist/assets/{formatDistanceToNow-DYmvOA3R.js → formatDistanceToNow-Cc2u5FwQ.js} +1 -1
  47. package/client/dist/assets/{getTimezoneOffsetInMilliseconds-BAhW5E6V.js → getTimezoneOffsetInMilliseconds-BHm2U-w1.js} +1 -1
  48. package/client/dist/assets/index-C51x61Bz.css +2 -0
  49. package/client/dist/assets/{index-BfAZg5DG.js → index-Cxb288Rj.js} +29 -29
  50. package/client/dist/assets/{jira-api-B27Za5FP.js → jira-api-DrGxiD9p.js} +1 -1
  51. package/client/dist/assets/packet-8nn9RsU7.js +1 -0
  52. package/client/dist/assets/packet-B0H15elv.js +1 -0
  53. package/client/dist/assets/packet-BQvBgrwh.js +1 -0
  54. package/client/dist/assets/packet-BR7mO0-a.js +1 -0
  55. package/client/dist/assets/packet-BgcQ6q_K.js +1 -0
  56. package/client/dist/assets/packet-D2s92Jnn.js +1 -0
  57. package/client/dist/assets/packet-YbtcD1HS.js +1 -0
  58. package/client/dist/assets/packet-c0Qj_9eX.js +1 -0
  59. package/client/dist/assets/{project-repositories-DixIZHTA.js → project-repositories-9Wzs0coQ.js} +1 -1
  60. package/client/dist/assets/{spending-BGmZBX5B.js → spending-T5GM7wpn.js} +1 -1
  61. package/client/dist/assets/{useDesktop-CPB4cnwI.js → useDesktop-QogiN0zR.js} +1 -1
  62. package/client/dist/assets/{useRuntimeRuns-DEQ9HdAM.js → useRuntimeRuns-Dqmz9fS9.js} +1 -1
  63. package/client/dist/assets/{useSharedWebSocket-DcPRKR8R.js → useSharedWebSocket-Dz-HI6De.js} +2 -2
  64. package/client/dist/index.html +17 -17
  65. package/docs/codex.md +5 -5
  66. package/docs/customizing.md +1 -1
  67. package/docs/gemini-cli-provider-study.md +14 -14
  68. package/docs/gemini-core-support-evaluation.md +1 -1
  69. package/docs/gemini.md +5 -5
  70. package/docs/internals/README.md +6 -2
  71. package/docs/internals/adding-a-provider.md +22 -15
  72. package/docs/internals/agent-runtime-framework-evaluation.md +8 -8
  73. package/docs/internals/api-reference.md +2 -2
  74. package/docs/internals/architecture.md +9 -9
  75. package/docs/internals/browser-capture-performance.md +3 -3
  76. package/docs/internals/code-explorer-story.md +2 -2
  77. package/docs/internals/companion-rails-as-loops-contract.md +2 -2
  78. package/docs/internals/core-runtime-updates.md +5 -0
  79. package/docs/internals/embedded-browser-native-webview-evaluation.md +5 -5
  80. package/docs/internals/gemini-mcp-registration.md +2 -2
  81. package/docs/internals/global-artifacts-alignment-contract.md +1 -1
  82. package/docs/internals/global-artifacts-relocation-evaluation.md +1 -1
  83. package/docs/internals/interactive-jobs.md +8 -8
  84. package/docs/internals/legacy-implementation-notes.md +722 -0
  85. package/docs/internals/loop-step-log-explorer.md +8 -8
  86. package/docs/internals/mission-rail-cards.md +14 -14
  87. package/docs/internals/modular-architecture.md +107 -0
  88. package/docs/internals/profiles.md +1 -1
  89. package/docs/internals/programmatic-agent-runtime.md +66 -0
  90. package/docs/internals/project-builder.md +18 -18
  91. package/docs/internals/review-packet.md +8 -8
  92. package/docs/internals/safe-pr-review-flow.md +11 -11
  93. package/docs/internals/source-architecture.md +131 -0
  94. package/docs/internals/source-map.md +1356 -0
  95. package/docs/internals/spec-addenda.md +65 -9
  96. package/docs/internals/switch-to-agent-mode-design.md +11 -11
  97. package/docs/tracking-cost.md +1 -1
  98. package/package.json +5 -2
  99. package/server/dist/agent-mcp-config.js +1 -1
  100. package/server/dist/attachment-manager.js +1 -1
  101. package/server/dist/build-dirs.js +2 -2
  102. package/server/dist/config.js +0 -3
  103. package/server/dist/core-completion.js +1 -1
  104. package/server/dist/core-execution.js +1 -1
  105. package/server/dist/db/activity.js +39 -0
  106. package/server/dist/db/connection.js +41 -0
  107. package/server/dist/db/conversations.js +48 -0
  108. package/server/dist/db/jobs.js +251 -0
  109. package/server/dist/db/migrations.js +1521 -0
  110. package/server/dist/db/proposals.js +50 -0
  111. package/server/dist/db/settings.js +15 -0
  112. package/server/dist/db/stats.js +61 -0
  113. package/server/dist/db/telemetry.js +56 -0
  114. package/server/dist/db/templates.js +37 -0
  115. package/server/dist/db/types.js +2 -0
  116. package/server/dist/db.js +66 -2224
  117. package/server/dist/desktop-db.js +3 -3
  118. package/server/dist/desktop-router.js +8 -8
  119. package/server/dist/git-diagnostics.js +1 -1
  120. package/server/dist/index.js +11 -11
  121. package/server/dist/integration-branch.js +3 -14
  122. package/server/dist/jira/jira-issue-fields.js +0 -1
  123. package/server/dist/jira/jira-materializer.js +1 -1
  124. package/server/dist/jira/jira-sync-manager.js +1 -1
  125. package/server/dist/mcp/guide.js +16 -2
  126. package/server/dist/mcp/mcp-admin-router.js +1 -1
  127. package/server/dist/mcp/mcp-server.js +1 -1
  128. package/server/dist/mcp/tools/catalog.js +2 -0
  129. package/server/dist/mcp/tools/jobs.js +23 -5
  130. package/server/dist/mcp/tools/rails.js +2 -2
  131. package/server/dist/mcp/tools/recovery.js +35 -0
  132. package/server/dist/mcp/tools/specs.js +2 -2
  133. package/server/dist/mcp/tools/support.js +4 -1
  134. package/server/dist/mcp/tools/types.js +3 -3
  135. package/server/dist/mobile/mobile-gateway.js +1 -1
  136. package/server/dist/mobile/mobile-missions.js +1 -1
  137. package/server/dist/{desktop-analytics.js → modules/accounting/runtime/desktop-analytics.js} +2 -2
  138. package/server/dist/{pricing.js → modules/accounting/runtime/pricing.js} +10 -3
  139. package/server/dist/{result-event.js → modules/accounting/runtime/result-event.js} +3 -3
  140. package/server/dist/{spending.js → modules/accounting/runtime/spending.js} +0 -3
  141. package/server/dist/{telemetry-compactor.js → modules/accounting/runtime/telemetry-compactor.js} +1 -1
  142. package/server/dist/{telemetry-receiver.js → modules/accounting/runtime/telemetry-receiver.js} +2 -2
  143. package/server/dist/{agent-runtime-bridge.js → modules/agent-runtime/runtime/agent-runtime-bridge.js} +2 -2
  144. package/server/dist/{agent-runtime-controls-router.js → modules/agent-runtime/runtime/agent-runtime-controls-router.js} +16 -0
  145. package/server/dist/{agent-runtime-controls.js → modules/agent-runtime/runtime/agent-runtime-controls.js} +100 -8
  146. package/server/dist/{agent-runtime-effective-config.js → modules/agent-runtime/runtime/agent-runtime-effective-config.js} +1 -1
  147. package/server/dist/{agent-runtime-loader.js → modules/agent-runtime/runtime/agent-runtime-loader.js} +3 -3
  148. package/server/dist/{agent-runtime-paths.js → modules/agent-runtime/runtime/agent-runtime-paths.js} +1 -1
  149. package/server/dist/modules/agent-runtime/runtime/agent-runtime-recovery.js +53 -0
  150. package/server/dist/{agent-runtime-settings-router.js → modules/agent-runtime/runtime/agent-runtime-settings-router.js} +2 -2
  151. package/server/dist/{agent-runtime-settings.js → modules/agent-runtime/runtime/agent-runtime-settings.js} +3 -3
  152. package/server/dist/{agent-runtime-settlement.js → modules/agent-runtime/runtime/agent-runtime-settlement.js} +6 -6
  153. package/server/dist/{agent-defaults.js → modules/agents/runtime/agent-defaults.js} +3 -3
  154. package/server/dist/{agent-generator.js → modules/agents/runtime/agent-generator.js} +7 -7
  155. package/server/dist/{agent-refine-manager.js → modules/agents/runtime/agent-refine-manager.js} +5 -5
  156. package/server/dist/{agent-store.js → modules/agents/runtime/agent-store.js} +1 -1
  157. package/server/dist/{profile-manager.js → modules/agents/runtime/profile-manager.js} +2 -2
  158. package/server/dist/{profiles-router.js → modules/agents/runtime/profiles-router.js} +5 -5
  159. package/server/dist/{browser-capture-manager.js → modules/browser/runtime/browser-capture-manager.js} +2 -4
  160. package/server/dist/{browser-playwright.js → modules/browser/runtime/browser-playwright.js} +1 -1
  161. package/server/dist/{blueprint-chat-manager.js → modules/builder/runtime/blueprint-chat-manager.js} +7 -7
  162. package/server/dist/{blueprint-commit.js → modules/builder/runtime/blueprint-commit.js} +8 -8
  163. package/server/dist/{blueprint-draft-parser.js → modules/builder/runtime/blueprint-draft-parser.js} +1 -1
  164. package/server/dist/{blueprint-generation.js → modules/builder/runtime/blueprint-generation.js} +1 -1
  165. package/server/dist/{blueprint-operator-prompt.js → modules/builder/runtime/blueprint-operator-prompt.js} +1 -1
  166. package/server/dist/{blueprint-router.js → modules/builder/runtime/blueprint-router.js} +3 -3
  167. package/server/dist/{blueprint-spec-quality.js → modules/builder/runtime/blueprint-spec-quality.js} +1 -1
  168. package/server/dist/{milestone-chain.js → modules/builder/runtime/milestone-chain.js} +1 -1
  169. package/server/dist/{milestone-progress.js → modules/builder/runtime/milestone-progress.js} +6 -6
  170. package/server/dist/{code-activity.js → modules/code/runtime/code-activity.js} +1 -1
  171. package/server/dist/{code-explorer-router.js → modules/code/runtime/code-explorer-router.js} +5 -5
  172. package/server/dist/{file-provenance.js → modules/code/runtime/file-provenance.js} +1 -1
  173. package/server/dist/{file-story-manager.js → modules/code/runtime/file-story-manager.js} +2 -2
  174. package/server/dist/{file-story.js → modules/code/runtime/file-story.js} +2 -2
  175. package/server/dist/{file-summary-generator.js → modules/code/runtime/file-summary-generator.js} +3 -3
  176. package/server/dist/{file-summary-manager.js → modules/code/runtime/file-summary-manager.js} +3 -3
  177. package/server/dist/{project-code-discovery.js → modules/code/runtime/project-code-discovery.js} +2 -2
  178. package/server/dist/modules/conversations/domain/draft-stream.js +91 -0
  179. package/server/dist/modules/conversations/domain/recovery-context.js +101 -0
  180. package/server/dist/modules/conversations/index.js +10 -0
  181. package/server/dist/{chat-manager.js → modules/conversations/runtime/chat-manager.js} +32 -216
  182. package/server/dist/{context-budget.js → modules/conversations/runtime/context-budget.js} +1 -1
  183. package/server/dist/{explore-cwd-manager.js → modules/conversations/runtime/explore-cwd-manager.js} +1 -1
  184. package/server/dist/{explore-smash.js → modules/conversations/runtime/explore-smash.js} +1 -1
  185. package/server/dist/{explore-stdin-session.js → modules/conversations/runtime/explore-stdin-session.js} +1 -1
  186. package/server/dist/modules/delivery/adapters/decisions/chains.js +138 -0
  187. package/server/dist/modules/delivery/adapters/decisions/contracts.js +2 -0
  188. package/server/dist/modules/delivery/adapters/decisions/create.js +234 -0
  189. package/server/dist/modules/delivery/adapters/decisions/discard.js +251 -0
  190. package/server/dist/modules/delivery/adapters/decisions/dispatch.js +107 -0
  191. package/server/dist/modules/delivery/adapters/decisions/evidence.js +205 -0
  192. package/server/dist/modules/delivery/adapters/decisions/merge-local.js +338 -0
  193. package/server/dist/modules/delivery/adapters/decisions/metadata.js +109 -0
  194. package/server/dist/modules/delivery/adapters/decisions/observations.js +260 -0
  195. package/server/dist/modules/delivery/adapters/decisions/ownership.js +83 -0
  196. package/server/dist/modules/delivery/adapters/decisions/publish.js +242 -0
  197. package/server/dist/modules/delivery/adapters/decisions/recovery.js +425 -0
  198. package/server/dist/modules/delivery/adapters/decisions/retry.js +112 -0
  199. package/server/dist/modules/delivery/adapters/decisions/transitions.js +94 -0
  200. package/server/dist/modules/delivery/domain/decision-policy.js +50 -0
  201. package/server/dist/modules/delivery/domain/state.js +2 -0
  202. package/server/dist/modules/delivery/index.js +7 -0
  203. package/server/dist/{active-pr-continuation.js → modules/delivery/runtime/active-pr-continuation.js} +2 -2
  204. package/server/dist/{delivery-evidence.js → modules/delivery/runtime/delivery-evidence.js} +3 -3
  205. package/server/dist/{multi-repo-bases.js → modules/delivery/runtime/multi-repo-bases.js} +1 -1
  206. package/server/dist/{multi-repo-checkout.js → modules/delivery/runtime/multi-repo-checkout.js} +4 -4
  207. package/server/dist/{multi-repo-delivery.js → modules/delivery/runtime/multi-repo-delivery.js} +4 -4
  208. package/server/dist/{multi-repo-execution.js → modules/delivery/runtime/multi-repo-execution.js} +8 -8
  209. package/server/dist/{pr-body.js → modules/delivery/runtime/pr-body.js} +1 -1
  210. package/server/dist/{pr-follow-up-scope.js → modules/delivery/runtime/pr-follow-up-scope.js} +2 -2
  211. package/server/dist/{pr-follow-up.js → modules/delivery/runtime/pr-follow-up.js} +1 -1
  212. package/server/dist/{pr-naming.js → modules/delivery/runtime/pr-naming.js} +1 -1
  213. package/server/dist/{pr-publisher.js → modules/delivery/runtime/pr-publisher.js} +2 -2
  214. package/server/dist/{rail-isolated-launch.js → modules/delivery/runtime/rail-isolated-launch.js} +29 -27
  215. package/server/dist/{rail-launch-parser.js → modules/delivery/runtime/rail-launch-parser.js} +2 -2
  216. package/server/dist/{rail-merge-orchestrator.js → modules/delivery/runtime/rail-merge-orchestrator.js} +5 -5
  217. package/server/dist/modules/delivery/runtime/rail-pr-decision.js +12 -0
  218. package/server/dist/{rail-pr-delivery.js → modules/delivery/runtime/rail-pr-delivery.js} +1 -1
  219. package/server/dist/{rail-pr-store.js → modules/delivery/runtime/rail-pr-store.js} +2 -2
  220. package/server/dist/{rail-pr-ticket-effects.js → modules/delivery/runtime/rail-pr-ticket-effects.js} +3 -3
  221. package/server/dist/{rail-worktree-release.js → modules/delivery/runtime/rail-worktree-release.js} +4 -4
  222. package/server/dist/{rails-router.js → modules/delivery/runtime/rails-router.js} +66 -67
  223. package/server/dist/{review-packet.js → modules/delivery/runtime/review-packet.js} +3 -3
  224. package/server/dist/modules/execution/adapters/budget-storage.js +21 -0
  225. package/server/dist/modules/execution/adapters/usage-reader.js +38 -0
  226. package/server/dist/modules/execution/application/enforce-budget.js +14 -0
  227. package/server/dist/modules/execution/application/record-job-invocations.js +64 -0
  228. package/server/dist/modules/execution/application/recover-job-usage.js +200 -0
  229. package/server/dist/modules/execution/domain/job-accounting.js +2 -0
  230. package/server/dist/modules/execution/domain/scheduling.js +24 -0
  231. package/server/dist/modules/execution/domain/usage.js +21 -0
  232. package/server/dist/modules/execution/index.js +14 -0
  233. package/server/dist/modules/execution/ports.js +2 -0
  234. package/server/dist/{accept-ladder.js → modules/execution/runtime/accept-ladder.js} +1 -1
  235. package/server/dist/{interactive-job-session.js → modules/execution/runtime/interactive-job-session.js} +11 -11
  236. package/server/dist/{job-phase-breakdown.js → modules/execution/runtime/job-phase-breakdown.js} +1 -1
  237. package/server/dist/{queue-manager.js → modules/execution/runtime/queue-manager.js} +74 -491
  238. package/server/dist/{revision-seed.js → modules/execution/runtime/revision-seed.js} +1 -1
  239. package/server/dist/{spawn-lifecycle.js → modules/execution/runtime/spawn-lifecycle.js} +3 -3
  240. package/server/dist/{stuck-run-detector.js → modules/execution/runtime/stuck-run-detector.js} +1 -1
  241. package/server/dist/{loop-command-catalog.js → modules/loops/runtime/loop-command-catalog.js} +1 -1
  242. package/server/dist/{loop-executors.js → modules/loops/runtime/loop-executors.js} +17 -17
  243. package/server/dist/{loop-factory.js → modules/loops/runtime/loop-factory.js} +2 -21
  244. package/server/dist/{loop-graph.js → modules/loops/runtime/loop-graph.js} +25 -0
  245. package/server/dist/{loop-role-engines.js → modules/loops/runtime/loop-role-engines.js} +4 -4
  246. package/server/dist/{loop-run-manager.js → modules/loops/runtime/loop-run-manager.js} +101 -26
  247. package/server/dist/{loop-runs-store.js → modules/loops/runtime/loop-runs-store.js} +1 -1
  248. package/server/dist/{loop-shell-invocation.js → modules/loops/runtime/loop-shell-invocation.js} +2 -2
  249. package/server/dist/{loop-step-idle.js → modules/loops/runtime/loop-step-idle.js} +1 -1
  250. package/server/dist/{loop-templates.js → modules/loops/runtime/loop-templates.js} +24 -29
  251. package/server/dist/{loops-router.js → modules/loops/runtime/loops-router.js} +2 -2
  252. package/server/dist/{agent-chat-manager.js → modules/missions/runtime/agent-chat-manager.js} +19 -19
  253. package/server/dist/{agent-chat-router.js → modules/missions/runtime/agent-chat-router.js} +6 -6
  254. package/server/dist/{agent-context-resolver.js → modules/missions/runtime/agent-context-resolver.js} +8 -8
  255. package/server/dist/{agent-failure-briefing.js → modules/missions/runtime/agent-failure-briefing.js} +4 -2
  256. package/server/dist/{agent-fence-promotion.js → modules/missions/runtime/agent-fence-promotion.js} +1 -1
  257. package/server/dist/{agent-input-store.js → modules/missions/runtime/agent-input-store.js} +1 -1
  258. package/server/dist/{agent-operator-prompt.js → modules/missions/runtime/agent-operator-prompt.js} +75 -12
  259. package/server/dist/{agent-spec-framing.js → modules/missions/runtime/agent-spec-framing.js} +4 -4
  260. package/server/dist/{agent-steering.js → modules/missions/runtime/agent-steering.js} +1 -1
  261. package/server/dist/{mission-run-notify.js → modules/missions/runtime/mission-run-notify.js} +5 -2
  262. package/server/dist/modules/project-settings/adapters/http.js +24 -0
  263. package/server/dist/modules/project-settings/adapters/sqlite.js +120 -0
  264. package/server/dist/modules/project-settings/application.js +11 -0
  265. package/server/dist/modules/project-settings/domain.js +95 -0
  266. package/server/dist/modules/project-settings/index.js +11 -0
  267. package/server/dist/modules/project-settings/ports.js +2 -0
  268. package/server/dist/{contract-refine-runner.js → modules/specs/runtime/contract-refine-runner.js} +12 -12
  269. package/server/dist/{proposal-manager.js → modules/specs/runtime/proposal-manager.js} +8 -8
  270. package/server/dist/{smash-runner.js → modules/specs/runtime/smash-runner.js} +26 -58
  271. package/server/dist/{spec-addenda-core.js → modules/specs/runtime/spec-addenda-core.js} +2 -2
  272. package/server/dist/{spec-addenda.js → modules/specs/runtime/spec-addenda.js} +3 -3
  273. package/server/dist/{spec-launcher-manager.js → modules/specs/runtime/spec-launcher-manager.js} +8 -8
  274. package/server/dist/{spec-models.js → modules/specs/runtime/spec-models.js} +1 -1
  275. package/server/dist/{ticket-watcher.js → modules/specs/runtime/ticket-watcher.js} +1 -1
  276. package/server/dist/{background-process-control.js → modules/terminals/runtime/background-process-control.js} +1 -1
  277. package/server/dist/{background-process-service.js → modules/terminals/runtime/background-process-service.js} +3 -3
  278. package/server/dist/{background-process-store.js → modules/terminals/runtime/background-process-store.js} +1 -1
  279. package/server/dist/{background-windows-bootstrap.js → modules/terminals/runtime/background-windows-bootstrap.js} +3 -3
  280. package/server/dist/{terminal-manager.js → modules/terminals/runtime/terminal-manager.js} +3 -3
  281. package/server/dist/project-git.js +1 -1
  282. package/server/dist/project-profile-support.js +32 -0
  283. package/server/dist/project-registry.js +34 -40
  284. package/server/dist/project-router-background-processes.js +1 -1
  285. package/server/dist/project-router-chat.js +6 -6
  286. package/server/dist/project-router-git.js +1 -1
  287. package/server/dist/project-router-helpers.js +2 -2
  288. package/server/dist/project-router-jobs.js +14 -12
  289. package/server/dist/project-router-loop-runs.js +12 -12
  290. package/server/dist/project-router-settings.js +15 -75
  291. package/server/dist/project-router-setup.js +2 -2
  292. package/server/dist/project-router-spending.js +4 -4
  293. package/server/dist/project-router-terminals.js +4 -4
  294. package/server/dist/project-router-tickets.js +14 -14
  295. package/server/dist/project-router.js +13 -13
  296. package/server/dist/providers/claude-adapter.js +3 -2
  297. package/server/dist/providers/codex-adapter.js +3 -3
  298. package/server/dist/providers/gemini-adapter.js +1 -1
  299. package/server/dist/providers/telemetry-env.js +55 -0
  300. package/server/dist/runtime-role-prompts-router.js +2 -2
  301. package/server/dist/setup-manager.js +2 -48
  302. package/server/dist/shared/git-branch-name.js +16 -0
  303. package/server/dist/transient-children.js +3 -3
  304. package/server/dist/util/distribute-int.js +33 -0
  305. package/client/dist/assets/ReviewPacketPage-D-UjTef3.js +0 -4
  306. package/client/dist/assets/index-BAtqmAZR.css +0 -2
  307. package/client/dist/assets/packet-CjS_478C.js +0 -1
  308. package/client/dist/assets/packet-D69dKsHN.js +0 -1
  309. package/client/dist/assets/packet-D9rU6Oxo.js +0 -1
  310. package/client/dist/assets/packet-DMDFoamg.js +0 -1
  311. package/client/dist/assets/packet-Dd2RMs1h.js +0 -1
  312. package/client/dist/assets/packet-DjC9OibC.js +0 -1
  313. package/client/dist/assets/packet-DwPtJoDz.js +0 -1
  314. package/client/dist/assets/packet-ceahDg8_.js +0 -1
  315. package/server/dist/rail-pr-decision.js +0 -2377
  316. package/server/dist/ticket-broadcast.js +0 -47
  317. /package/server/dist/{ai-invocations.js → modules/accounting/runtime/ai-invocations.js} +0 -0
  318. /package/server/dist/{codex-otel-bridge.js → modules/accounting/runtime/codex-otel-bridge.js} +0 -0
  319. /package/server/dist/{metrics.js → modules/accounting/runtime/metrics.js} +0 -0
  320. /package/server/dist/{telemetry-export.js → modules/accounting/runtime/telemetry-export.js} +0 -0
  321. /package/server/dist/{agent-runtime-accounting.js → modules/agent-runtime/runtime/agent-runtime-accounting.js} +0 -0
  322. /package/server/dist/{agent-runtime-events.js → modules/agent-runtime/runtime/agent-runtime-events.js} +0 -0
  323. /package/server/dist/{agent-runtime-history.js → modules/agent-runtime/runtime/agent-runtime-history.js} +0 -0
  324. /package/server/dist/{agent-runtime-metrics.js → modules/agent-runtime/runtime/agent-runtime-metrics.js} +0 -0
  325. /package/server/dist/{agent-runtime-package.js → modules/agent-runtime/runtime/agent-runtime-package.js} +0 -0
  326. /package/server/dist/{agent-runtime-repositories.js → modules/agent-runtime/runtime/agent-runtime-repositories.js} +0 -0
  327. /package/server/dist/{agent-runtime-verification-suggestions.js → modules/agent-runtime/runtime/agent-runtime-verification-suggestions.js} +0 -0
  328. /package/server/dist/{agent-refine-db.js → modules/agents/runtime/agent-refine-db.js} +0 -0
  329. /package/server/dist/{browser-capture-types.js → modules/browser/runtime/browser-capture-types.js} +0 -0
  330. /package/server/dist/{browser-context-pool.js → modules/browser/runtime/browser-context-pool.js} +0 -0
  331. /package/server/dist/{browser-network.js → modules/browser/runtime/browser-network.js} +0 -0
  332. /package/server/dist/{browser-viewport.js → modules/browser/runtime/browser-viewport.js} +0 -0
  333. /package/server/dist/{blueprint-render.js → modules/builder/runtime/blueprint-render.js} +0 -0
  334. /package/server/dist/{blueprint-spec-fixtures.js → modules/builder/runtime/blueprint-spec-fixtures.js} +0 -0
  335. /package/server/dist/{blueprint-store.js → modules/builder/runtime/blueprint-store.js} +0 -0
  336. /package/server/dist/{blueprint-types.js → modules/builder/runtime/blueprint-types.js} +0 -0
  337. /package/server/dist/{builder-cwd-manager.js → modules/builder/runtime/builder-cwd-manager.js} +0 -0
  338. /package/server/dist/{milestone-chain-store.js → modules/builder/runtime/milestone-chain-store.js} +0 -0
  339. /package/server/dist/{changes-reader.js → modules/code/runtime/changes-reader.js} +0 -0
  340. /package/server/dist/{context-scope.js → modules/conversations/runtime/context-scope.js} +0 -0
  341. /package/server/dist/{explore-contract-refine.js → modules/conversations/runtime/explore-contract-refine.js} +0 -0
  342. /package/server/dist/{explore-draft-title.js → modules/conversations/runtime/explore-draft-title.js} +0 -0
  343. /package/server/dist/{merge-manager.js → modules/delivery/runtime/merge-manager.js} +0 -0
  344. /package/server/dist/{multi-repo-execution-store.js → modules/delivery/runtime/multi-repo-execution-store.js} +0 -0
  345. /package/server/dist/{pr-lifecycle.js → modules/delivery/runtime/pr-lifecycle.js} +0 -0
  346. /package/server/dist/{rail-isolation.js → modules/delivery/runtime/rail-isolation.js} +0 -0
  347. /package/server/dist/{rail-pr-recovery-git.js → modules/delivery/runtime/rail-pr-recovery-git.js} +0 -0
  348. /package/server/dist/{rail-worktrees-store.js → modules/delivery/runtime/rail-worktrees-store.js} +0 -0
  349. /package/server/dist/{rails-store.js → modules/delivery/runtime/rails-store.js} +0 -0
  350. /package/server/dist/{job-listing.js → modules/execution/runtime/job-listing.js} +0 -0
  351. /package/server/dist/{job-spawn-idempotency.js → modules/execution/runtime/job-spawn-idempotency.js} +0 -0
  352. /package/server/dist/{run-duration-stats.js → modules/execution/runtime/run-duration-stats.js} +0 -0
  353. /package/server/dist/{verification-sentinel.js → modules/execution/runtime/verification-sentinel.js} +0 -0
  354. /package/server/dist/{loop-constants.js → modules/loops/runtime/loop-constants.js} +0 -0
  355. /package/server/dist/{loop-decider.js → modules/loops/runtime/loop-decider.js} +0 -0
  356. /package/server/dist/{loop-effect.js → modules/loops/runtime/loop-effect.js} +0 -0
  357. /package/server/dist/{loop-preview.js → modules/loops/runtime/loop-preview.js} +0 -0
  358. /package/server/dist/{loop-templates-ported.js → modules/loops/runtime/loop-templates-ported.js} +0 -0
  359. /package/server/dist/{loops-store.js → modules/loops/runtime/loops-store.js} +0 -0
  360. /package/server/dist/{agent-chat-registry.js → modules/missions/runtime/agent-chat-registry.js} +0 -0
  361. /package/server/dist/{agent-cwd-manager.js → modules/missions/runtime/agent-cwd-manager.js} +0 -0
  362. /package/server/dist/{agent-tier.js → modules/missions/runtime/agent-tier.js} +0 -0
  363. /package/server/dist/{spec-contract-prompt.js → modules/specs/runtime/spec-contract-prompt.js} +0 -0
  364. /package/server/dist/{spec-draft-parser.js → modules/specs/runtime/spec-draft-parser.js} +0 -0
  365. /package/server/dist/{ticket-store.js → modules/specs/runtime/ticket-store.js} +0 -0
  366. /package/server/dist/{terminal-marks-store.js → modules/terminals/runtime/terminal-marks-store.js} +0 -0
  367. /package/server/dist/{terminal-osc-parser.js → modules/terminals/runtime/terminal-osc-parser.js} +0 -0
  368. /package/server/dist/{terminal-settings.js → modules/terminals/runtime/terminal-settings.js} +0 -0
@@ -1,12 +1,12 @@
1
1
  # Loop-step log explorer
2
2
 
3
- The premium log surface for **loop runs**. When a job's `command` starts with `loop:`, both job views — the board's Job Detail page (`client/src/pages/JobDetailPage.tsx`, `variant="page"`) and the mission-mode job modal (`client/src/components/JobDetailModal.tsx`, `variant="glass"`) — mount `LoopStepExplorer` (`client/src/components/loop-log/LoopStepExplorer.tsx`) instead of the flat `LogViewer`. Non-loop jobs keep the legacy `LogViewer` byte-identical.
3
+ The premium log surface for **loop runs**. When a job's `command` starts with `loop:`, both job views — the board's Job Detail page (`client/src/features/jobs/pages/JobDetailPage.tsx`, `variant="page"`) and the mission-mode job modal (`client/src/features/jobs/components/JobDetailModal.tsx`, `variant="glass"`) — mount `LoopStepExplorer` (`client/src/features/loops/components/loop-log/LoopStepExplorer.tsx`) instead of the flat `LogViewer`. Non-loop jobs keep the legacy `LogViewer` byte-identical.
4
4
 
5
5
  The explorer does **not** introduce a second log pipeline. It consumes the exact same `events` array (persisted rows + live WS frames) and the exact same line parser (`parseEvent → mergeAssistantLines → applyDiffDetection` from `LogViewer`), then *segments* the result by three structured events the loop engine already persists on the run's backing job row.
6
6
 
7
7
  ## Event contract
8
8
 
9
- Emitted by `server/loop-run-manager.ts` (payload interfaces are exported there — `LoopStepEventPayload`, `LoopStepEndEventPayload`, `LoopGraphEventPayload`). All three ride the run's job row as ordinary persisted `events` rows plus `event` WS broadcasts (`event_type` below, `payload` = JSON of the interface). Purely additive to the existing stream — no DB migration.
9
+ Emitted by `server/modules/loops/runtime/loop-run-manager.ts` (payload interfaces are exported there — `LoopStepEventPayload`, `LoopStepEndEventPayload`, `LoopGraphEventPayload`). All three ride the run's job row as ordinary persisted `events` rows plus `event` WS broadcasts (`event_type` below, `payload` = JSON of the interface). Purely additive to the existing stream — no DB migration.
10
10
 
11
11
  ### `loop_graph` — once, at run start
12
12
 
@@ -137,10 +137,10 @@ All explorer strings live under the `jobs` namespace, `loopExplorer.*` (16 keys
137
137
 
138
138
  | File | Role |
139
139
  |---|---|
140
- | `server/loop-run-manager.ts` | Event emission (`emitStep` / `emitStepEnd` / `loop_graph`), exported payload types, seq allocator |
141
- | `client/src/components/loop-log/loop-log-model.ts` | Pure grouping/status/chip model |
142
- | `client/src/components/loop-log/LoopStepExplorer.tsx` | Container: follow mode, filter, copy, toolbar |
143
- | `client/src/components/loop-log/LoopOverviewStrip.tsx` | Live chip strip + iteration counter |
144
- | `client/src/components/loop-log/LoopStepSection.tsx` | Per-step / Setup collapsible sections (memoized) |
145
- | `client/src/components/loop-log/loop-node-visuals.ts` | Node-kind icon + accent mapping |
140
+ | `server/modules/loops/runtime/loop-run-manager.ts` | Event emission (`emitStep` / `emitStepEnd` / `loop_graph`), exported payload types, seq allocator |
141
+ | `client/src/features/loops/components/loop-log/loop-log-model.ts` | Pure grouping/status/chip model |
142
+ | `client/src/features/loops/components/loop-log/LoopStepExplorer.tsx` | Container: follow mode, filter, copy, toolbar |
143
+ | `client/src/features/loops/components/loop-log/LoopOverviewStrip.tsx` | Live chip strip + iteration counter |
144
+ | `client/src/features/loops/components/loop-log/LoopStepSection.tsx` | Per-step / Setup collapsible sections (memoized) |
145
+ | `client/src/features/loops/components/loop-log/loop-node-visuals.ts` | Node-kind icon + accent mapping |
146
146
  | `client/src/components/loop-log/__tests__/` | Model + explorer tests |
@@ -6,7 +6,7 @@
6
6
 
7
7
  Mission mode (Agent Mode) replaces the routed dashboard, so `RailsBoard`, `SpecsBoard`, `RailRow` (with `RailPrDecisionStrip` and `AgentRuntimeRuns`) are never mounted there. The only object a mission had for an implementation run was the PR-decision card. On 2026-09-18 three gaps were verified:
8
8
 
9
- 1. **No git ⇒ no object.** The shared-cwd launch path in `server/rails-router.ts` (`isolationUnavailable = 'no-git' | 'no-commits'`) never received `originConversationId`; no `rail_pr_deliveries` row, no card, only a `202 { isolationUnavailable }` the agent rarely mentioned.
9
+ 1. **No git ⇒ no object.** The shared-cwd launch path in `server/modules/delivery/runtime/rails-router.ts` (`isolationUnavailable = 'no-git' | 'no-commits'`) never received `originConversationId`; no `rail_pr_deliveries` row, no card, only a `202 { isolationUnavailable }` the agent rarely mentioned.
10
10
  2. **Failure was mute.** `discarded` swallowed `statusDetail` (gated on `deliveryBlocked`); `implementation_failed` offered Discard only; no WS event wrote into the conversation or started a turn; `/agent-runtime/runs` (resume / approve / recover) was absent from MCP.
11
11
  3. **Assignment was prose.** Rails were not a palette entity; assigning specs meant dictating rail / engine / profile / loop in sentences, so users went to Board mode.
12
12
 
@@ -53,7 +53,7 @@ Mission mode (Agent Mode) replaces the routed dashboard, so `RailsBoard`, `Specs
53
53
  }
54
54
  ```
55
55
 
56
- Parser pair `server/rail-launch-parser.ts` ⇄ `client/src/lib/rail-launch-draft.ts` (byte-identical except the mirror note; `server/rail-launch-parser.test.ts` enforces parity). `extractRailLaunchProposals(content, streaming)` returns `{ body, proposals, rejected, pending, truncated, repaired }`:
56
+ Parser pair `server/modules/delivery/runtime/rail-launch-parser.ts` ⇄ `client/src/features/rails/lib/rail-launch-draft.ts` (byte-identical except the mirror note; `server/modules/delivery/runtime/rail-launch-parser.test.ts` enforces parity). `extractRailLaunchProposals(content, streaming)` returns `{ body, proposals, rejected, pending, truncated, repaired }`:
57
57
 
58
58
  - tolerant JSON repair (`json-tolerant`) before rejecting; `repaired` flags it;
59
59
  - unknown keys dropped; `ticketIds` accepts `12`, `"12"`, `"#12"` (also under `specs` / `tickets`); `mode` accepts `batch` for `batch-implement`, `newRail: true` for an unnamed rail; `railIndex` is ignored when `newRail` is set;
@@ -67,29 +67,29 @@ Parser pair `server/rail-launch-parser.ts` ⇄ `client/src/lib/rail-launch-draft
67
67
 
68
68
  | Piece | Where | Notes |
69
69
  |---|---|---|
70
- | Operator prompt | `server/agent-operator-prompt.ts` `RAIL_LAUNCH_CARD_SECTION`, `RAIL_LAUNCH_CARD_SYSTEM_CLAUSE`, `buildOperatorSystemPrompt()` | Propose = block; launch directly only on an explicit "now"; failure briefing reply ≤ 6 lines + one action, no mutation. Gated on `isMissionRailCardsEnabled()`. |
70
+ | Operator prompt | `server/modules/missions/runtime/agent-operator-prompt.ts` `RAIL_LAUNCH_CARD_SECTION`, `RAIL_LAUNCH_CARD_SYSTEM_CLAUSE`, `buildOperatorSystemPrompt()` | Propose = block; launch directly only on an explicit "now"; failure briefing reply ≤ 6 lines + one action, no mutation. Gated on `isMissionRailCardsEnabled()`. |
71
71
  | Message intent | desktop-db migration 29 (`agent_messages.intent`, column-guarded); `agent-store.ts` `setAgentMessageIntent`; `PATCH /api/agent/conversations/:id/messages/:mid/intent` | JSON ARRAY of decisions keyed by `proposalIndex`; append-only; 409 `already_decided`; 403 when the feature is off. Rows expose `intents[]`. |
72
72
  | Envelope | `server/types.ts` `PrDecisionCardEnvelope` (+ `MissionRunPhase`, `MissionRunRuntime`, `MissionRunFailure`) | `hasDelivery`, `phase`, `railName`, `runtime` — all optional; `decision` vocabulary unchanged. |
73
- | Run-only cards | `server/mission-run-notify.ts` `runCardId` / `isRunCardId` / `buildRunCardEnvelope` / `postRunCard` / `settleRunCard` / `failureForLoopOutcome` / `runtimeFromSummary` | Synthetic `prDeliveryId = 'run:<runId>'`, `hasDelivery:false`. Wired in the shared-cwd branch of `rails-router.ts` (origin stored on `railLoopRuns` meta; 202 returns `runIds`). |
73
+ | Run-only cards | `server/modules/missions/runtime/mission-run-notify.ts` `runCardId` / `isRunCardId` / `buildRunCardEnvelope` / `postRunCard` / `settleRunCard` / `failureForLoopOutcome` / `runtimeFromSummary` | Synthetic `prDeliveryId = 'run:<runId>'`, `hasDelivery:false`. Wired in the shared-cwd branch of `rails-router.ts` (origin stored on `railLoopRuns` meta; 202 returns `runIds`). |
74
74
  | Run-only dismiss | `POST /rails/pr-decision { prDeliveryId:'run:…', action:'dismiss', expectedDecision, conversationId }` → `AgentChatManager.dismissRunCard` | Other actions ⇒ 400 `run_card_dismiss_only`; unknown card ⇒ 404 `run_card_not_found`. |
75
75
  | Failure trigger | `notifyMissionRunFailure` (`mission-run-notify.ts`) | Envelope update with `runtime.failure` → `AgentChatManager.postRunFailureRow` (one `system` row per run, WS `agent_run_failure`) → `AgentChatManager.startSystemTurn` (queueId `mission-failure:<runId>`, gated `isMissionFailureTurnEnabled()`). Callers: shared-cwd run promise, isolated settle (`implementation_failed`), `closeFailedGeneration` (`launch_failed`). Cancel updates the card, no turn. No origin ⇒ no-op. |
76
- | Briefing | `server/agent-failure-briefing.ts` `buildFailureBriefing`, `failureBriefingRef`, `FAILURE_CODE_LABELS`, `FAILURE_BRIEFING_MAX_TAIL` | Fixed text: rail, specs, failure code + detail, bounded verify tail, recovery options, "do not relaunch by yourself". Persisted as a `user` row whose `context_refs[0].kind === 'system-briefing'`. |
76
+ | Briefing | `server/modules/missions/runtime/agent-failure-briefing.ts` `buildFailureBriefing`, `failureBriefingRef`, `FAILURE_CODE_LABELS`, `FAILURE_BRIEFING_MAX_TAIL` | Fixed text: rail, specs, failure code + detail, bounded verify tail, recovery options, "do not relaunch by yourself". Persisted as a `user` row whose `context_refs[0].kind === 'system-briefing'`. |
77
77
  | Settle snapshots | `rail-isolated-launch.ts` settle, `rail-pr-store.ts` `toPrDecisionCardEnvelope`, `agent-runtime-controls-router.ts` `runtimeRunSummary()` | `phase` + `runtime` on `implementation_failed` and launch-failed `discarded`; `statusDetail` as text. |
78
78
  | Rails availability | `GET /:projectId/rails` | `availability: 'free' \| 'busy' \| 'pending_decision' \| 'on_review'` per rail. |
79
79
  | MCP | `server/mcp/tools/jobs.ts` `runtime_runs`, `runtime_evidence` (read) · `runtime_resume`, `runtime_recover` (ai-spawn) · `runtime_approve`, `runtime_settle`, `runtime_dismiss` (write) · `runtime_cancel` (destructive); `mcp/guide.ts` recovery section | Over the existing `/agent-runtime/runs` routes; approve/recover are `resume` bodies. |
80
- | Palette | `server/agent-chat-router.ts` `CONTEXT_KINDS` += `rail`; `server/agent-context-resolver.ts` `formatRail` | `@rail-N` reference serialization. |
80
+ | Palette | `server/modules/missions/runtime/agent-chat-router.ts` `CONTEXT_KINDS` += `rail`; `server/modules/missions/runtime/agent-context-resolver.ts` `formatRail` | `@rail-N` reference serialization. |
81
81
 
82
82
  WS messages: `agent_pr_decision` (existing, now carries the new fields), `agent_run_failure` (new, app-global, `AgentRunFailureMessage`).
83
83
 
84
84
  ## Client components
85
85
 
86
- - `client/src/components/agent-chat/AgentMessage.tsx` — extraction step after spec-draft (flag `FEATURE_MISSION_RAIL_CARDS`); renders `AgentRailLaunchCard` per proposal, `AgentRailLaunchPending`, `AgentRailLaunchUnreadable`.
86
+ - `client/src/features/missions/components/AgentMessage.tsx` — extraction step after spec-draft (flag `FEATURE_MISSION_RAIL_CARDS`); renders `AgentRailLaunchCard` per proposal, `AgentRailLaunchPending`, `AgentRailLaunchUnreadable`.
87
87
  - `AgentRailLaunchCard.tsx` — live reconciliation (`/rails` availability, `/tickets`, `/profiles`, `useProviderDetection`, model/effort catalogs, loops), New rail, Play flow (`POST /rails` → `PUT /tickets` → `POST /launch` with `originConversationId` + `originSurface:'agent-chat'` → `notifyGitChanged` → intent PATCH), inline 400/409, launched/dismissed stubs, `FOCUS_PR_CARD_EVENT`.
88
- - `client/src/lib/rail-launch-intents.ts` — session overlay (`recordLocalIntent`, `intentFor`); `useRailLaunchProposals.ts` — undecided proposals for the dock; `AgentPrPinnedDock.tsx` — proposals pinned above PR cards.
88
+ - `client/src/features/rails/lib/rail-launch-intents.ts` — session overlay (`recordLocalIntent`, `intentFor`); `useRailLaunchProposals.ts` — undecided proposals for the dock; `AgentPrPinnedDock.tsx` — proposals pinned above PR cards.
89
89
  - `AgentPrDecisionCard.tsx` — run phase header (`deriveMissionRunStatus`, live `useRuntimeRuns` first), run-only rendering for `hasDelivery === false`, `RunFailureBlock`, Resume / Approve / Recover / Relaunch, focus-bus scroll + flash.
90
90
  - `agent-pr-pinning.ts` `isPrEnvelopePinned`; `agent-run-failure.ts` (`parseRunFailureRow`, `systemBriefingRunId`, `FOCUS_PR_CARD_EVENT`, `MISSION_OPEN_RUN_EVENT`, `requestMissionOpenRun`); `AgentRunFailureMarker.tsx`.
91
- - `client/src/context/AgentChatContext.tsx` — appends the `run-failure` row live on `agent_run_failure`; `AgentWorkspaceContext.tsx` / `AgentModeJobsPane.tsx` — `specrails:mission-open-run` opens the Jobs pane + `JobDetailModal`; `hooks/useOsNotifications.ts` — stays in Mission mode.
92
- - Palette: `client/src/lib/agent-context-palette.ts` (`rail` kind, `railsFromResponse`, `railChip`), `AgentComposer.tsx`, `AgentComposerEditor.tsx`, `AgentContextPalette.tsx`.
91
+ - `client/src/features/missions/context/AgentChatContext.tsx` — appends the `run-failure` row live on `agent_run_failure`; `AgentWorkspaceContext.tsx` / `AgentModeJobsPane.tsx` — `specrails:mission-open-run` opens the Jobs pane + `JobDetailModal`; `hooks/useOsNotifications.ts` — stays in Mission mode.
92
+ - Palette: `client/src/features/missions/lib/agent-context-palette.ts` (`rail` kind, `railsFromResponse`, `railChip`), `AgentComposer.tsx`, `AgentComposerEditor.tsx`, `AgentContextPalette.tsx`.
93
93
 
94
94
  ## Honesty rules
95
95
 
@@ -120,11 +120,11 @@ Migration 29 and the envelope fields are additive; persisted intents are inert w
120
120
 
121
121
  | Area | Tests |
122
122
  |---|---|
123
- | Parser + promotion + mirror parity | `server/rail-launch-parser.test.ts` |
123
+ | Parser + promotion + mirror parity | `server/modules/delivery/runtime/rail-launch-parser.test.ts` |
124
124
  | Intent store/route, `dismissRunCard` | `server/agent-message-intent.test.ts` |
125
- | Run-only cards, availability, run-card dismiss route | `server/rails-router.test.ts`, `server/mcp/tools/rails-origin.test.ts` |
126
- | Failure trigger / briefing / system turn | `server/mission-run-notify.test.ts`, `server/agent-failure-briefing.test.ts`, `server/agent-chat-mission-turn.test.ts`, `server/rail-isolated-launch.test.ts` |
125
+ | Run-only cards, availability, run-card dismiss route | `server/modules/delivery/runtime/rails-router.test.ts`, `server/mcp/tools/rails-origin.test.ts` |
126
+ | Failure trigger / briefing / system turn | `server/modules/missions/runtime/mission-run-notify.test.ts`, `server/modules/missions/runtime/agent-failure-briefing.test.ts`, `server/agent-chat-mission-turn.test.ts`, `server/modules/delivery/runtime/rail-isolated-launch.test.ts` |
127
127
  | MCP runtime actions | `server/mcp/tools/jobs-runtime.test.ts` |
128
- | Launch card, proposals hook, stubs | `client/src/components/agent-chat/__tests__/agent-rail-launch-card.test.tsx` |
128
+ | Launch card, proposals hook, stubs | `client/src/features/missions/components/__tests__/agent-rail-launch-card.test.tsx` |
129
129
  | Run card phases / failure block / pinning / marker | `mission-run-card.test.tsx`, `mission-run-pinning.test.ts`, `agent-run-failure.test.ts`, `agent-run-failure-marker.test.tsx` |
130
130
  | Palette rails, Mission-mode notifications | `client/src/lib/__tests__/agent-context-palette-rails.test.ts`, `client/src/hooks/__tests__/useOsNotifications.mission-mode.test.ts` |
@@ -0,0 +1,107 @@
1
+ # Architecture decision: capability modules with selective ports and adapters
2
+
3
+ Status: capability ownership is implemented across the application, including
4
+ server features, React features and CLI responsibilities. Hexagonal boundaries
5
+ are applied to cores that benefit from substitutable effects. Runtime coordinators
6
+ are explicitly effectful; this is not a claim that every class is infrastructure-free.
7
+
8
+ ## Decision and scope
9
+
10
+ Keep a modular monolith and the existing deployment units. A change should have an
11
+ identifiable owner, focused public entry points and adjacent behavioral tests.
12
+ Use functions and composition; a generic repository, base-manager hierarchy,
13
+ service locator or DI container would add machinery without solving the observed
14
+ coupling. Folder moves alone do not constitute dependency inversion.
15
+
16
+ | Area | Implemented ownership and boundary | Why this shape |
17
+ | --- | --- | --- |
18
+ | Server capabilities | [14 modules](../../server/modules/README.md), [195 production files and public subpaths](../../server/modules/boundaries.json) | Related stores, runtime coordination and tests are discoverable together; dependencies are reviewed explicitly |
19
+ | React capabilities | [21 features](../../client/src/features/README.md), [public subpaths and dependencies](../../client/src/features/boundaries.json) | UI, hooks, state, feature clients and tests belong to the same feature; focused subpath imports avoid eagerly loading every view |
20
+ | Project settings | [Domain, application, repository port, HTTP/SQLite adapters](../../server/modules/project-settings/README.md) | Validation is independent of transport; updates validate first and commit atomically |
21
+ | Execution | [Scheduling, accounting, recovery and budget enforcement](../../server/modules/execution/README.md) | Policies run without a database/process manager; recovery reads ordered evidence through a lazy adapter and preserves native-vs-estimated usage |
22
+ | Delivery | [Decision policy and workflows](../../server/modules/delivery/README.md) | Lifecycle vocabulary is independent of storage; publication, recovery, discard and local merge have separate workflows with an acyclic dependency guard |
23
+ | Conversations | [Recovery context and stream policies](../../server/modules/conversations/README.md) | Byte limits, exact missing-session detection and chunk filtering are testable independently of provider processes |
24
+ | Persistence | [Connection, migrations and domain repositories](../../server/db/) behind [the public facade](../../server/db.ts) | Preserve schema history, query behavior and transaction ownership while separating unrelated concerns |
25
+ | CLI | [Parsing, formatting, output, HTTP transport, execution and lifecycle modules](../../cli/README.md) | The executable only dispatches; parsing/formatting have no infrastructure imports and commands cannot depend on the executable |
26
+
27
+ ## Boundaries deliberately retained
28
+
29
+ These areas were assessed and keep their existing responsibility boundaries;
30
+ moving them again would obscure package/resource contracts or duplicate adapters.
31
+
32
+ | Area | Retained entry points | Rationale |
33
+ | --- | --- | --- |
34
+ | Server composition | [startup](../../server/index.ts), [project registry](../../server/project-registry.ts), [project routes](../../server/project-router.ts), [desktop routes](../../server/desktop-router.ts) | Own project lifetime, route ordering and dependency wiring |
35
+ | Provider strategies | [provider contract](../../server/providers/types.ts), [registry](../../server/providers/registry.ts), [runtime](../../server/providers/runtime.ts) | Existing substitutable provider strategies already model different capabilities and stream semantics |
36
+ | Integrations | [Jira](../../server/jira/), [plugins](../../server/plugins/), [mobile](../../server/mobile/), [MCP](../../server/mcp/) | Existing cohesive subsystems; preserve their public contracts rather than create parallel frameworks |
37
+ | Resource/platform adapters | [Core compatibility](../../server/core-compat.ts), [command resolver](../../server/command-resolver.ts), [shell resources](../../server/terminal-shell-integration.ts), [MCP configuration](../../server/agent-mcp-config.ts) | Resource lookup depends on source/npm/sidecar locations; retain stable package anchors |
38
+ | Local engine | [runner](../../local-runner/src/runner.ts), [HTTP client](../../local-runner/src/openai-client.ts), [tools](../../local-runner/src/tools.ts), [sessions](../../local-runner/src/sessions.ts) | The existing executable, protocol, transport, tools and session split is useful and contract-tested |
39
+ | MCP bridge | [entry](../../mcp-bridge/src/index.ts), [bridge](../../mcp-bridge/src/bridge.ts), [HTTP transport](../../mcp-bridge/src/http-transport.ts) | Already separates process wiring, protocol handling and transport |
40
+ | Native shell | [Tauri composition](../../src-tauri/src/lib.rs), [invoke guard](../../src-tauri/src/invoke_guard.rs), [browser ownership](../../src-tauri/src/browser_ownership.rs), [mission windows](../../src-tauri/src/mission_windows.rs) | Platform/window integration belongs at the native boundary, not behind JavaScript repository interfaces |
41
+ | Shared frontend infrastructure | [App](../../client/src/App.tsx), [API context](../../client/src/lib/api.ts), [project cache](../../client/src/hooks/useProjectCache.ts), [UI primitives](../../client/src/components/ui/) | Application composition and reusable infrastructure remain shared; feature-specific code lives with its owner |
42
+
43
+ ## SOLID and patterns in the implemented design
44
+
45
+ - **Single responsibility:** persistence repositories, CLI handlers, delivery
46
+ workflows and feature-owned source replace unrelated responsibilities in one
47
+ entry file. Runtime coordinators retain lifecycle/state ownership.
48
+ - **Open/closed:** add real variation through existing provider strategies,
49
+ executor callbacks and use-case ports. Do not add an interface for every function.
50
+ - **Liskov substitution:** fake and production ports must preserve atomic writes,
51
+ error propagation, unknown usage values, ordering and provider capability limits.
52
+ - **Interface segregation:** settings exposes read/update; accounting exposes
53
+ write/identity; recovery exposes ordered evidence and provider interpretation;
54
+ budgets expose snapshots and exceeded effects. No complete project registry is
55
+ passed into these application cores.
56
+ - **Dependency inversion:** domain/application files have fixed import allowlists.
57
+ SQLite and provider interpretation implement the recovery boundary; settings
58
+ HTTP/SQLite adapters are wired at composition.
59
+
60
+ Retain strategies/adapters, explicit application use cases, compatibility facades,
61
+ composition roots and durable outboxes. Preserve existing compare-and-set leases
62
+ and transactions: replacing them with ephemeral pub/sub would break crash recovery.
63
+ A state machine is useful for action legality; it does not require replacing the
64
+ existing persisted lifecycle vocabulary with a competing model.
65
+
66
+ ## Enforcement and review
67
+
68
+ [Server architecture tests](../../server/modules/architecture.test.ts) verify the
69
+ reviewed [manifest](../../server/modules/boundaries.json), every core's fixed
70
+ allowlist and the acyclic delivery workflow graph. Regenerating the runtime
71
+ manifest cannot authorize an infrastructure dependency inside a protected core.
72
+ [CLI architecture tests](../../cli/architecture.test.ts) protect pure parsing/
73
+ formatting, entry-point direction and acyclic command dependencies.
74
+
75
+ [Frontend boundary checks](../../scripts/audit-client-features.mjs) record public
76
+ subpaths and direct capability dependencies and reject imports back into
77
+ application composition. Existing cross-feature collaborations are explicit;
78
+ this inventory does not claim that every feature is independent or acyclic.
79
+
80
+ Use `npm run audit:architecture` after a boundary change. Regenerate manifests only
81
+ after reviewing the new dependency and update the owning README. Typecheck enforces
82
+ unused imports/locals; [source audit](../../scripts/audit-source.mjs) inventories
83
+ reachability across application, demo, CLI, local-runner and MCP entry points.
84
+
85
+ ## Preserved behavior and limits
86
+
87
+ - Source moves update imports, dynamic imports, test mocks, source-reading fixtures,
88
+ coverage paths, packaging probes and navigation links together.
89
+ - Keep queue reservation synchronous; keep cancellation, durable promotion,
90
+ terminal settlement, replay and PR ownership idempotent.
91
+ - No historical database migrations are rewritten. Settings updates are atomic;
92
+ accounting/recovery continue inside their original transaction owner.
93
+ - Frontend project switching, streaming state, route shapes and UI behavior remain
94
+ unchanged. Coverage exclusions move to equivalent files; thresholds are unchanged.
95
+ - Large stateful coordinators still exist inside `runtime/`. Their location is
96
+ explicit and their policies have narrower seams; no claim is made that every
97
+ controller is a pure application service or that all architectural debt is gone.
98
+ - No blanket runtime-performance gain is claimed. The concrete query improvement
99
+ reads the six project settings in one query. Source ownership is intended to
100
+ reduce change scope and navigation cost, not to manufacture a benchmark result.
101
+
102
+ ## Human and AI navigation
103
+
104
+ [AGENTS.md](../../AGENTS.md) supplies concise working rules and a feature map;
105
+ [CLAUDE.md](../../CLAUDE.md) imports it. Feature READMEs expose public contracts,
106
+ collaborators and test commands. The [generated source map](source-map.md) links
107
+ source and adjacent tests; historical detail stays in optional reference documents.
@@ -151,7 +151,7 @@ update.
151
151
  A few internals worth knowing if you're working on this surface:
152
152
 
153
153
  - **Version gate.** Profile-aware spawns are gated by
154
- `projectSupportsProfiles()` (`server/queue-manager.ts`), which reads the
154
+ `projectSupportsProfiles()` (`server/modules/execution/runtime/queue-manager.ts`), which reads the
155
155
  project's `.specrails/specrails-version` and requires
156
156
  `specrails-core >= 4.1.0`; Kimi additionally requires the Core 4.12 target.
157
157
  Below the applicable floor, the rail spawns in legacy mode and no profile
@@ -138,3 +138,69 @@ Core's additive runtime metrics v1 are passed from compact status to each saved
138
138
  Older Core versions continue to work without the panel. The server validates numeric fields and known phase IDs, drops unsupported/malformed metrics and projects only the supported fields; it never forwards arbitrary transcripts from the metrics object. Missing billing is displayed as unavailable rather than zero. Cache tokens are already included in input tokens, and agent duration already includes native tool work. The panel does not estimate savings or measure implementation quality.
139
139
 
140
140
  The paired `agent-runtime-efficiency` OpenSpec change in specrails-core documents verification ownership, efficient API tools and the measurement contract. Core exposes the same report through `runtime status` / `runtime-result`, so a fixed set of real tasks can be compared without a Desktop database migration.
141
+
142
+ ## Diagnose before retrying
143
+
144
+ `GET /agent-runtime/runs/:runId/diagnosis` (MCP: `specrails_jobs runtime_diagnose`)
145
+ returns the original scope, historical completed steps, up to eight recent
146
+ failed/interrupted attempts, verification and acceptance reasons, and a recovery
147
+ recommendation. It performs no provider calls or mutations. Repeated matching
148
+ step/error pairs recommend repairing the precondition before retrying. A missing
149
+ history on an older retained Core is unknown, not zero failures.
150
+
151
+ MCP `runtime_evidence` accepts `evidenceId`, `section`, `sourceId`, `cursor` and
152
+ `limit` to inspect the actual evidence beyond its index. `canResume` only means
153
+ resume is available. Changed receipts can still cause verification and review
154
+ to repeat; no zero-cost promise is made. A succeeded run awaiting settlement
155
+ should use `runtime_settle`, preserving the existing implementation.
156
+
157
+ Paired Core now preserves OpenSpec's output when archive exits successfully
158
+ without creating its destination, and distinguishes that from multiple matching
159
+ destinations. Retrying a failed archive keeps valid verification/review receipts;
160
+ changed candidate files or environment still require fresh evidence. These Core
161
+ fixes require a newly bundled/released runtime; retained original runtimes are
162
+ not silently replaced or migrated. Diagnosis does not add arbitrary file-write
163
+ access: repairs without a supported scoped tool are reported as concrete manual
164
+ steps instead of being disguised as a reason to relaunch.
165
+
166
+ ## Repair the original worktree
167
+
168
+ `specrails_recovery` calls `POST /agent-runtime/runs/:runId/recovery` with a
169
+ strict action-specific request. It never constructs a new context/worktree.
170
+
171
+ | Action | Inputs and permission | Result |
172
+ | --- | --- | --- |
173
+ | inspect | read | Original repository IDs, registered check definitions, recent attempts |
174
+ | list_files / read_file / diff | repositoryId + relative path; read | Bounded directory/line/diff output; read_file includes SHA-256 |
175
+ | history | optional offset; read | Latest attempts first, pages of 20 with nextOffset |
176
+ | patch | repositoryId, path, expectedHash, oldText, newText, operationId UUID, reason; write | One unique replacement in an existing file, atomic publication |
177
+ | check | kind openspec or verification; saved checkId for verification; operationId + reason; destructive | Real validation evidence, bounded output and durable outcome |
178
+
179
+ Patches are limited to 16 KiB fragments and files readable within 128 KiB.
180
+ Runtime/provider metadata, secret paths, frozen OpenSpec changes/config/archives,
181
+ agent instructions, traversal, symlinks and platform aliases are rejected. New
182
+ files, deletions and arbitrary commands are not supported. Explicit repository IDs
183
+ prevent cross-project resolution. Verification runs one registered command with a
184
+ 45-second deadline; full acceptance remains the normal resume/settlement path.
185
+
186
+ Desktop blocks admission while project executions are active and reserves the
187
+ run/rail. Core takes the same cross-process lease as Resume. An interrupted write
188
+ requires `acknowledgeInterrupted` after inspecting partial changes. Completed or
189
+ archived runs cannot be patched or checked through recovery. Inspection remains
190
+ available. This is an application boundary, not an OS sandbox against unrelated
191
+ processes modifying the worktree concurrently.
192
+
193
+ Core stores at most 100 attempts in `recovery-history.json` beside the pipeline
194
+ state, separate from checkpoints. Each mutation has a write-ahead operation ID,
195
+ request fingerprint, cause, before/after hashes where relevant and final outcome.
196
+ Reuse the exact request/ID after transport uncertainty. A pending patch whose
197
+ after-hash is present is reconciled; other pending operations become interrupted
198
+ and are not rerun. Repeating a failed check on unchanged candidate code requires
199
+ a documented `changedPrecondition`; this records the operator's explanation, not
200
+ an independent proof that an external prerequisite changed.
201
+
202
+ Resume still enforces verification, review and acceptance. Scoped verification
203
+ uses Core's existing evidence/receipt store and cannot mark workflow phases done.
204
+ OpenSpec checks validate real files without copying or archiving them. Old retained
205
+ Core packages lacking `scopedRecovery` are not upgraded/migrated behind the run's
206
+ back: the tool returns a manual-repair limitation rather than recommending Relaunch.
@@ -30,7 +30,7 @@ route).
30
30
  the in-flight builder turn (`POST /abort`) and resets every session slice.
31
31
  The agent's own chrome (project/mission selectors, conversation, queue,
32
32
  pinned cards) is hidden while active but NEVER unmounted.
33
- - Session logic in `client/src/hooks/useBuilderSession.ts` (extracted from the
33
+ - Session logic in `client/src/features/builder/hooks/useBuilderSession.ts` (extracted from the
34
34
  retired shell): bootstrap, `blueprint.*` WS handling with NULL-SAFE identity
35
35
  checks (a pre-bootstrap/pre-commit null ref must never match a null/absent
36
36
  message id), phases, snapshot, send/commit/launch actions, `dirty` flag.
@@ -101,20 +101,20 @@ generator's pure-output policy. A direct Kimi request is rejected before
101
101
  `BlueprintChatManager` spawns. This does not prevent the approved blueprint
102
102
  from declaring Kimi among the new project's target providers.
103
103
 
104
- - **Manager**: `server/blueprint-chat-manager.ts` `BlueprintChatManager` — an
104
+ - **Manager**: `server/modules/builder/runtime/blueprint-chat-manager.ts` `BlueprintChatManager` — an
105
105
  app-level sibling of `AgentChatManager` reusing `runAiCliInvocation`. Spawns
106
- from `~/.specrails/builder-cwd/` (`server/builder-cwd-manager.ts`: always
107
- re-written instruction files from `server/blueprint-operator-prompt.ts`, NO
106
+ from `~/.specrails/builder-cwd/` (`server/modules/builder/runtime/builder-cwd-manager.ts`: always
107
+ re-written instruction files from `server/modules/builder/runtime/blueprint-operator-prompt.ts`, NO
108
108
  `./project` symlink, NO MCP). Auto-heal: a resume that yields no text retries
109
109
  fresh once. Abort keeps partial text and records `aborted`.
110
110
  - **Persistence**: `blueprint_conversations` / `blueprint_messages` in
111
- `desktop.sqlite` (migration 22; CRUD in `server/blueprint-store.ts`).
111
+ `desktop.sqlite` (migration 22; CRUD in `server/modules/builder/runtime/blueprint-store.ts`).
112
112
  - **WS**: app-global `blueprint.stream` / `blueprint.done` / `blueprint.error`
113
113
  (no `projectId`; NOT in the mobile-ws translation layer). `blueprint.done`
114
114
  carries the STRIPPED `fullText` plus the last valid `blueprint` snapshot.
115
115
  - **Accounting**: one `agent_invocations` row per settled turn with
116
116
  `project_id NULL` (the Home-turn precedent). No backfill after creation.
117
- - **REST**: `/api/blueprint/*` (`server/blueprint-router.ts`) — conversations
117
+ - **REST**: `/api/blueprint/*` (`server/modules/builder/runtime/blueprint-router.ts`) — conversations
118
118
  CRUD, `/send` (202, 409 while streaming), `/abort`, `/models`, `/commit`.
119
119
  `/models` returns the provider's `efforts` catalog; `/send` accepts only a
120
120
  catalog-valid `reasoning_effort`, and providers without the capability omit
@@ -224,7 +224,7 @@ the provider session (later turns `--resume`); two-step inline discard →
224
224
  `DELETE`. The exit confirm copy no longer threatens to discard the blueprint —
225
225
  it says where to pick it up.
226
226
 
227
- **5. Readiness, made legible (client).** `client/src/lib/blueprint-readiness.ts`
227
+ **5. Readiness, made legible (client).** `client/src/features/builder/lib/blueprint-readiness.ts`
228
228
  `deriveReadiness` turns the same deterministic report into three steps —
229
229
  **blueprint** (5 dimensions) · **specs** (count within 5–10 and
230
230
  `specsComplete`) · **audit** (issues excluding the two batch-level codes) —
@@ -285,8 +285,8 @@ Fenced ` ```blueprint-draft ` JSON blocks. FULL snapshots, LAST syntactically
285
285
  valid block wins, streaming tail cut (unterminated trailing fence never
286
286
  parsed/shown — `cutUnterminatedBlock`). Unknown keys dropped; missing or
287
287
  non-integer `blueprintVersion` rejects the block. Parser pair:
288
- `server/blueprint-draft-parser.ts` ⇄ `client/src/lib/blueprint-draft.ts` (keep
289
- coercion rules in sync). Schema types in `server/blueprint-types.ts`:
288
+ `server/modules/builder/runtime/blueprint-draft-parser.ts` ⇄ `client/src/features/builder/lib/blueprint-draft.ts` (keep
289
+ coercion rules in sync). Schema types in `server/modules/builder/runtime/blueprint-types.ts`:
290
290
  `product{name,pitch,audience}`, `coreFlow`, `platform`,
291
291
  `stack{language,framework,db,notes?}`, `assumptions[]`,
292
292
  `milestones[]{id,title,goal,status: planned|committed|done, plannedSpecs[],
@@ -318,7 +318,7 @@ files remain readable (and returns null for missing/corrupt input).
318
318
 
319
319
  There is no Builder-specific “lite spec” format. Every detailed Builder spec
320
320
  uses the normal Specrails contract, and since premium-milestone-progress the
321
- prose that teaches it lives in ONE module — `server/spec-contract-prompt.ts`
321
+ prose that teaches it lives in ONE module — `server/modules/specs/runtime/spec-contract-prompt.ts`
322
322
  (`premiumSpecContract(mode)`, `premiumSpecContractCompact(mode)`,
323
323
  `PREMIUM_SCAFFOLD_EXAMPLE`, `SPEC_DEPTH_FLOORS`) — consumed by the Builder
324
324
  operator prompt, `ChatManager._buildMilestoneSystemPrompt` (M2+) and the
@@ -353,10 +353,10 @@ uncertainty. `PREMIUM_SCAFFOLD_EXAMPLE` is the mandatory first spec written
353
353
  at that depth; "shorter is a defect, not a style". The floors were raised
354
354
  because the old minima ("at least two bullets", 4–10 criteria) became the
355
355
  ceiling the model aimed at (design D6/D8). Test fixtures that need a
356
- gate-valid spec use `server/blueprint-spec-fixtures.ts` ⇄
356
+ gate-valid spec use `server/modules/builder/runtime/blueprint-spec-fixtures.ts` ⇄
357
357
  `client/src/lib/__tests__/premium-spec-fixture.ts`.
358
358
 
359
- `server/blueprint-spec-quality.ts` is the shared deterministic authority. It
359
+ `server/modules/builder/runtime/blueprint-spec-quality.ts` is the shared deterministic authority. It
360
360
  validates `specsComplete=true`, the complete-set size, all fields/sections
361
361
  above (including the depth floors — issue codes `section_depth` carries the
362
362
  heading + min chars, `section_bullets` the min, `criteria_count` the 6–10
@@ -449,7 +449,7 @@ the panel's spec card shows "writing…" / "not written yet" instead of
449
449
  `location_already_registered`; rich-spec failures include actionable spec/field
450
450
  detail) → 202 `{commitId}` → per-step
451
451
  `blueprint.commit_progress` → terminal `blueprint.commit_done{projectId}` /
452
- `commit_failed{step,error}`. Orchestrator: `server/blueprint-commit.ts`
452
+ `commit_failed{step,error}`. Orchestrator: `server/modules/builder/runtime/blueprint-commit.ts`
453
453
  `createBlueprintCommitRunner` (DI IO bag — every step fail-injectable in
454
454
  tests). Step order:
455
455
 
@@ -468,7 +468,7 @@ tests). Step order:
468
468
  ("reinstall the app"). Verifies the workspace exists afterwards.
469
469
  4. `blueprint` — `writeBlueprintPair` into `<workspace>/.specrails/`
470
470
  (`blueprint.json` source of truth + deterministic `blueprint.md`,
471
- `server/blueprint-render.ts`; repo stays pristine)
471
+ `server/modules/builder/runtime/blueprint-render.ts`; repo stays pristine)
472
472
  5. `tickets` — `mutateStore` on the workspace `local-tickets.json`: `todo`,
473
473
  label `M1`, `source='project-builder'`, `created_by='project-builder'`, spec
474
474
  order preserved, generated priority/short summary/domain labels retained,
@@ -510,12 +510,12 @@ execution and can use Kimi.
510
510
 
511
511
  - **Launch Milestone N is SERVER-owned** (premium-milestone-progress D3):
512
512
  `POST /api/projects/:id/blueprint/milestones/:n/launch { mode }`
513
- (`client/src/lib/milestone-launch.ts` `launchMilestone` is one POST; the
513
+ (`client/src/features/builder/lib/milestone-launch.ts` `launchMilestone` is one POST; the
514
514
  old browser-local `MilestoneSequencerContext` + its `localStorage` plan are
515
515
  GONE — `dropLegacySequentialPlans()` forgets the leftover key on load).
516
- `server/milestone-chain.ts` `MilestoneChainManager` gathers the `M<n>`
516
+ `server/modules/builder/runtime/milestone-chain.ts` `MilestoneChainManager` gathers the `M<n>`
517
517
  `todo` tickets, chunks them (≤3, `chainRailName` → `M<n>` / `M<n> · k`),
518
- persists ONE `milestone_launch_chains` row (`server/milestone-chain-store.ts`,
518
+ persists ONE `milestone_launch_chains` row (`server/modules/builder/runtime/milestone-chain-store.ts`,
519
519
  migration 58, partial unique index = one non-terminal chain per milestone;
520
520
  CAS `updateChain`) and launches chunk 1 through the app's OWN rails launch
521
521
  route over loopback (`server/internal-api.ts`, lifted from the MCP tools'
@@ -579,7 +579,7 @@ execution and can use Kimi.
579
579
  (`discardStackedNote` ×3 namespaces). Offered on the Builder done screen and
580
580
  the sidebar entry with the Sequential | Parallel toggle.
581
581
  - **Milestone progress is SERVER-derived** (premium-milestone-progress D2):
582
- `server/milestone-progress.ts` `deriveMilestoneProgress` builds, per
582
+ `server/modules/builder/runtime/milestone-progress.ts` `deriveMilestoneProgress` builds, per
583
583
  milestone, counts by spec state (`total/done/onReview/inProgress/todo/failed`
584
584
  — `failed` = specs back at `todo` whose NEWEST delivery unit failed), the
585
585
  milestone's rails (active runs + non-terminal deliveries, chunk-ordered), the
@@ -20,7 +20,7 @@ verbs.
20
20
 
21
21
  This is the load-bearing design constraint, not a nicety. Three rules:
22
22
 
23
- 1. **Every claim carries its source.** `server/review-packet.ts` splits proof
23
+ 1. **Every claim carries its source.** `server/modules/delivery/runtime/review-packet.ts` splits proof
24
24
  into three tiers and the tier travels with the item so the UI must label it:
25
25
 
26
26
  | Tier | Source | UI framing |
@@ -75,7 +75,7 @@ nothing-changed cases are exactly where a non-technical user is most abandoned:
75
75
 
76
76
  ## Decision verbs
77
77
 
78
- `client/src/lib/packet-verbs.ts` maps the FULL delivery state space (12
78
+ `client/src/features/delivery/lib/packet-verbs.ts` maps the FULL delivery state space (12
79
79
  decisions × 9 actions × orthogonal outcome/status axes ≈ 14 presentation states)
80
80
  onto Accept / Request changes / Discard — and marks every state where that
81
81
  reduction would lie as `fineControlOnly`. Those states (the recovery family, a
@@ -84,7 +84,7 @@ instead of a friendly relabel of git work. The module header carries the full
84
84
  table; `resolvePacketVerbs` is total, defaulting to `fineControlOnly` rather
85
85
  than guessing.
86
86
 
87
- **Accept declares what it physically does.** `server/accept-ladder.ts`
87
+ **Accept declares what it physically does.** `server/modules/execution/runtime/accept-ladder.ts`
88
88
  pre-resolves the ladder from shipped probes (`git remote`, offline
89
89
  `gh auth token`) and fails CLOSED to `merge-local`:
90
90
 
@@ -100,7 +100,7 @@ holds no optimistic state; a raced answer surfaces the neutral
100
100
 
101
101
  ## Surfaces
102
102
 
103
- - Routed page `/review/:prDeliveryId` (`client/src/pages/ReviewPacketPage.tsx`) —
103
+ - Routed page `/review/:prDeliveryId` (`client/src/features/delivery/pages/ReviewPacketPage.tsx`) —
104
104
  chosen over a portal so the documented z-order ladder is irrelevant.
105
105
  - Entry points: a `Review` button on the rail strip's `on_review` row and on the
106
106
  agent-chat PR card. Both keep their precise git actions.
@@ -147,7 +147,7 @@ public catalog: its prompt consumes `{{const:REVISION_REQUEST}}`, which only a
147
147
  revision launch injects. The router forces this loop for any revision whatever
148
148
  the rail's stored mode is; without that, every tweak would re-run implement.
149
149
 
150
- **Fresh session by contract** (`server/revision-seed.ts`). The run is seeded from
150
+ **Fresh session by contract** (`server/modules/execution/runtime/revision-seed.ts`). The run is seeded from
151
151
  durable state — the instruction, the frozen spec, the branch that carries the
152
152
  work, and what the previous run actually REPORTED (failure first). `--resume` of
153
153
  the prior session is not attempted: sessions are cwd-scoped to a released
@@ -177,7 +177,7 @@ rejected: it treats a 40-cent typo fix and a nine-dollar thrash identically.
177
177
  ## Narrated progress (Wave 3b)
178
178
 
179
179
  The third altitude on the job log surfaces, between the glance-level phase chips
180
- and the raw log. `client/src/components/loop-log/narration-model.ts`
180
+ and the raw log. `client/src/features/loops/components/loop-log/narration-model.ts`
181
181
  `buildNarration` turns the persisted event stream into MILESTONES:
182
182
 
183
183
  - Each milestone is a stable i18n key plus factual values — nothing in the model
@@ -204,7 +204,7 @@ synthesised client-side.
204
204
 
205
205
  **The toggle** follows the Code explorer's Story|Log precedent and DEFAULTS to
206
206
  narrated, on both the routed Job Detail page and the mission-mode modal. The
207
- preference is one app-level key (`client/src/lib/job-log-mode.ts`) rather than
207
+ preference is one app-level key (`client/src/features/jobs/lib/job-log-mode.ts`) rather than
208
208
  per-project: it describes the reader, not a project, and splitting it made the
209
209
  two surfaces disagree about what the same person had chosen. With
210
210
  `VITE_FEATURE_NARRATED_PROGRESS=false` both surfaces render byte-identically to
@@ -228,6 +228,6 @@ Observed: the section rendered the spec's *Proposed Solution* digest as raw mark
228
228
 
229
229
  ## 2026-09-19 — Programmatic-runtime evidence (host-run verification + reviewer verdict)
230
230
 
231
- Observed: a delivery built by the programmatic agent runtime (core-host) rendered **"The AI did not report any verification"** and **"No reviewer score"** although the host had run `npm test` (exit 0, output persisted) and the reviewer returned a structured verdict (score 92). The harvest only knew the legacy loop channels — the `VERIFICATION:` prose sentinel and `openspec/changes/**/confidence-score.json` — neither of which that runtime produces. Fix (`server/delivery-evidence.ts` `readRuntimeEvidence`, wired from `rail-isolated-launch.ts` via the new `EvidenceHarvestUnit.runtimeDir` = `<workspace>/.specrails/pipeline/<runId>`): read `state.json` `verification.commands[]` (+ each `verification/evidence/<id>.json` for exit code, duration, bounded output and `origin`), `acceptance.checks[]` / `acceptance.findings[]`, and the reviewer step output in `agent-workflow/<runId>/checkpoint.json` (`approved`, `score`, `aspects`, `issues`, `summary`). Every field is bounded; a malformed file degrades to nothing.
231
+ Observed: a delivery built by the programmatic agent runtime (core-host) rendered **"The AI did not report any verification"** and **"No reviewer score"** although the host had run `npm test` (exit 0, output persisted) and the reviewer returned a structured verdict (score 92). The harvest only knew the legacy loop channels — the `VERIFICATION:` prose sentinel and `openspec/changes/**/confidence-score.json` — neither of which that runtime produces. Fix (`server/modules/delivery/runtime/delivery-evidence.ts` `readRuntimeEvidence`, wired from `rail-isolated-launch.ts` via the new `EvidenceHarvestUnit.runtimeDir` = `<workspace>/.specrails/pipeline/<runId>`): read `state.json` `verification.commands[]` (+ each `verification/evidence/<id>.json` for exit code, duration, bounded output and `origin`), `acceptance.checks[]` / `acceptance.findings[]`, and the reviewer step output in `agent-workflow/<runId>/checkpoint.json` (`approved`, `score`, `aspects`, `issues`, `summary`). Every field is bounded; a malformed file degrades to nothing.
232
232
 
233
233
  Tier placement (`review-packet.ts` `buildProof`): commands whose `origin` includes `host` are **app-verified** (`proof.hostCommandPassed|Failed` with exit code + seconds + output tail) — the runtime executed them and recorded the exit code, which is a measurement, not a claim; non-host acceptance checks, the reviewer summary and findings are **ai-reported** (`proof.acceptanceCheckPassed|Failed`, `proof.reviewerSummary`, `proof.reviewerFinding`); the structured verdict fills `confidence` (score/aspects/issues→flags) ONLY when no file-based score exists, so the **reviewer-score** tier and the human-review band work unchanged. `proof.noVerificationReported` is emitted only when no channel reported anything. Older deliveries heal lazily: `GET …/packet` runs `healRuntimeEvidence` over units lacking `runtime` and persists the result (`updatePrDeliverySettleEvidence`), so a packet stops claiming silence once the pipeline dir exists. Still never a numeric test-count claim: the "70 passed" line rides inside the labelled raw output, not as a number the app asserts.
@@ -10,7 +10,7 @@
10
10
  ## The single source of truth
11
11
 
12
12
  `rail_pr_deliveries` (per-project `jobs.sqlite`, migrations 36/38/48–54; CRUD in
13
- `server/rail-pr-store.ts`) stores one durable **generation** per implementation launch. A partial
13
+ `server/modules/delivery/runtime/rail-pr-store.ts`) stores one durable **generation** per implementation launch. A partial
14
14
  unique index enforces one non-terminal generation per rail. Reimplementing an attached PR creates
15
15
  generation B and atomically moves generation A to terminal `superseded`; A cannot reappear through
16
16
  ordinary replay after B closes. The sole exception is an allocation rollback committed in the same
@@ -110,7 +110,7 @@ branch or detached HEAD, a temporary checkout claims the base without switching
110
110
  A base already held by another worktree remains untouched and reports `integration_branch_busy`.
111
111
  Both temporary checkouts use non-force cleanup, including after a Git runner exception.
112
112
 
113
- ## Launch and recovery wiring (`server/rail-isolated-launch.ts`)
113
+ ## Launch and recovery wiring (`server/modules/delivery/runtime/rail-isolated-launch.ts`)
114
114
 
115
115
  - `prMode` is captured once. Admission is rechecked inside the per-repository allocation lock;
116
116
  two requests cannot both create a generation or reuse the ticket-keyed worktree.
@@ -247,7 +247,7 @@ at launch:
247
247
 
248
248
  `POST /rails/pr-decision` `{ prDeliveryId, action, expectedDecision }` (replaces the stateless
249
249
  v1 `POST /rails/pr-review`). The route validates and delegates to
250
- `server/rail-pr-decision.ts` `executePrDecision` (deps injected — db/git/exec/broadcast/jira/
250
+ `server/modules/delivery/runtime/rail-pr-decision.ts` `executePrDecision` (deps injected — db/git/exec/broadcast/jira/
251
251
  agent-chat — so the whole matrix unit-tests without git/gh/network).
252
252
 
253
253
  Before any Git, GitHub, cleanup or ticket effect, the endpoint atomically claims the row's leased
@@ -279,7 +279,7 @@ Transient observation failure keeps the evidence and fails retryably.
279
279
  Initial settlement records exact post-push `CLOSED` as `pr_closed`; exact post-push `MERGED` stays
280
280
  attached and ready for Verify so that explicit decision can commit terminal ticket intent atomically.
281
281
 
282
- - **create-pr** — deferred `deliverRailAsPr` (`server/rail-pr-delivery.ts`: 1 unit → its
282
+ - **create-pr** — deferred `deliverRailAsPr` (`server/modules/delivery/runtime/rail-pr-delivery.ts`: 1 unit → its
283
283
  branch; N → assembled onto the conventional batch branch off the integration branch, one PR
284
284
  covering every ticket). The PR **title and canonical body are composed here** (see "Branch
285
285
  naming & PR content" below) from the ticket store + `jira_links` + the branch diffs — all
@@ -355,7 +355,7 @@ state → 409 (`stale_decision` + `reason: 'illegal_action'`).
355
355
  ## Branch naming & PR content (pr-naming.ts / pr-body.ts)
356
356
 
357
357
  Conventional, open-source-style naming for everything the user sees on GitHub. All pure string
358
- logic in `server/pr-naming.ts` (branches + titles) and `server/pr-body.ts` (canonical body +
358
+ logic in `server/modules/delivery/runtime/pr-naming.ts` (branches + titles) and `server/modules/delivery/runtime/pr-body.ts` (canonical body +
359
359
  diff collection), fully unit-tested.
360
360
 
361
361
  - **`<ref>`** — the ticket's Jira key when Jira-linked, else the local ticket number. **JIRA
@@ -408,7 +408,7 @@ the `expectedDecision` they rendered.
408
408
  the exact `A.restoredFromDeliveryId=B` rollback after B terminalizes, and advance the same id only
409
409
  through newer `updatedAt` evidence. A delayed A snapshot without that paired proof cannot replace
410
410
  B, and a non-terminal replay cannot ordinarily reopen an id already observed terminal.
411
- - **Option A — dashboard.** `client/src/context/RailPrDecisionContext.tsx` (registerHandler on
411
+ - **Option A — dashboard.** `client/src/features/delivery/context/RailPrDecisionContext.tsx` (registerHandler on
412
412
  the shared socket + `GET /rails` seed) feeds `RailPrDecisionStrip` on `RailRow` (both density
413
413
  branches): on_review → Create PR / Discard; pr_draft → Open PR + Publish / Discard (degraded →
414
414
  retry); pr_ready → Verify PR; no_changes → Done/refine; pr_closed → Reopen; pr_failed derives
@@ -433,7 +433,7 @@ the `expectedDecision` they rendered.
433
433
  no migration; TS unions widened) whose content is the `PrDecisionCardEnvelope` JSON.
434
434
  `AgentChatManager.postPrDecisionCard` / `updatePrDecisionCard` (idempotent update-in-place on
435
435
  every transition, transactionally consolidating legacy duplicate rows by delivery id) are reached via the
436
- process-wide `server/agent-chat-registry.ts` singleton (null-safe: tests/disabled builds).
436
+ process-wide `server/modules/missions/runtime/agent-chat-registry.ts` singleton (null-safe: tests/disabled builds).
437
437
  Live updates ride the app-global `agent_pr_decision` WS event; the client renders
438
438
  `AgentPrDecisionCard` and POSTs the same project-scoped `/rails/pr-decision`. Client hydration,
439
439
  WS upsert and rendering also dedupe by delivery id, so stale blocked and current ready cards can
@@ -469,7 +469,7 @@ launches are unaffected.
469
469
  The launch body accepts an optional `targetPrNumber` — the user's explicit designation of an
470
470
  existing open PR as the delivery destination ("extend PR #151"). It bypasses the automatic-inference
471
471
  status gates (which never probe GitHub for a `todo` ticket) but keeps the authoritative validation
472
- ladder: `resolveExplicitPrTarget` (`server/active-pr-continuation.ts`) resolves the number to its
472
+ ladder: `resolveExplicitPrTarget` (`server/modules/delivery/runtime/active-pr-continuation.ts`) resolves the number to its
473
473
  canonical URL, observes the lifecycle, and throws `ExplicitPrTargetError` with a distinct code —
474
474
  `target_pr_not_found` (404) / `target_pr_not_open` / `target_pr_fork` (`isCrossRepository !== false`)
475
475
  / `target_pr_invalid` / `target_pr_unfetchable` (all 409) — rejecting the launch BEFORE any delivery
@@ -498,7 +498,7 @@ the shared checkout, or isolation is unavailable), and resolved right before all
498
498
  never stacks on a guess). `launchIsolatedRail` threads it as `resolveIntegrationBranch({ explicit })`,
499
499
  so the delivery row records it as `base_branch` and `deliverRailAsPr` creates the PR STACKED on it
500
500
  (`gh pr create --base <branch>`). Today's only driver is the milestone launch chain
501
- (`server/milestone-chain.ts`): chunk k+1 of a sequential "Launch Milestone" launches with
501
+ (`server/modules/builder/runtime/milestone-chain.ts`): chunk k+1 of a sequential "Launch Milestone" launches with
502
502
  `baseBranch = chunk k's delivered branch`, so a greenfield walking skeleton accumulates without waiting
503
503
  for a merge. MCP `specrails_rails(launch, baseBranch)` exposes the same parameter.
504
504
 
@@ -522,7 +522,7 @@ rewound to the previous chunk's branch, else the integration branch) and broadca
522
522
 
523
523
  ## Ticket lifecycle — `on_review`
524
524
 
525
- New status in `TicketStatus` / `VALID_STATUSES` (`server/ticket-store.ts`), between
525
+ New status in `TicketStatus` / `VALID_STATUSES` (`server/modules/specs/runtime/ticket-store.ts`), between
526
526
  `in_progress` and `done`. Pipeline-owned:
527
527
 
528
528
  **Universal ask-first (both completion chokepoints).** Under the default-on PR-delivery flag
@@ -745,7 +745,7 @@ itself: the operator rewrote the ticket description (synced to Jira on linked
745
745
  projects) and the run still re-planned the whole feature. The follow-up is now a
746
746
  typed, frozen delta that travels with the DELIVERY, never with the spec.
747
747
 
748
- - **Shape** (`server/pr-follow-up.ts`): `comments[]` (id, source `user-paste` |
748
+ - **Shape** (`server/modules/delivery/runtime/pr-follow-up.ts`): `comments[]` (id, source `user-paste` |
749
749
  `github`, author, path, line, body — bounded), `scope` (objective, required
750
750
  outcomes, excluded changes, verification), optional `openspecChangeName`.
751
751
  `freezeFollowUp` assigns an `id` and a sha256 `hash` of the canonical content: