@moretea-labs/forge 1.5.1 → 1.7.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 (434) hide show
  1. package/AGENTS.md +2 -0
  2. package/CHANGELOG.md +46 -0
  3. package/CLAUDE.md +2 -0
  4. package/DESIGN.md +7 -2
  5. package/README.md +4 -4
  6. package/README.zh-CN.md +2 -2
  7. package/SKILL.md +2 -2
  8. package/THIRD_PARTY_NOTICES.md +1 -1
  9. package/agents/openai.yaml +1 -1
  10. package/assets/hooks/hook-input.sh +11 -8
  11. package/assets/hooks/lib/session-state.sh +10 -7
  12. package/assets/hooks/lib/workflow-state.sh +13 -177
  13. package/assets/hooks/post-tool-observer.sh +8 -2
  14. package/assets/hooks/pre-edit-guard.sh +8 -39
  15. package/assets/hooks/prompt-guard.sh +7 -83
  16. package/assets/hooks/session-start-context.sh +56 -1
  17. package/assets/partials/05-workflow.partial.md +1 -1
  18. package/assets/partials-agents/03-orchestration.partial.md +1 -1
  19. package/assets/plugin-registry.v1.json +54 -3
  20. package/assets/reference-configs/document-generation.md +1 -1
  21. package/assets/reference-configs/harness-overview.md +1 -1
  22. package/assets/reference-configs/hook-operations.md +1 -1
  23. package/assets/reference-configs/sprint-contracts.md +3 -3
  24. package/assets/skill-version.json +2 -2
  25. package/assets/templates/contract.template.md +2 -7
  26. package/assets/templates/helpers/capture-plan.sh +2 -2
  27. package/assets/templates/helpers/check-task-workflow.sh +4 -4
  28. package/assets/templates/helpers/contract-worktree.sh +1 -21
  29. package/assets/templates/helpers/ensure-task-workflow.sh +13 -38
  30. package/assets/templates/helpers/migrate-project-template.sh +22 -45
  31. package/assets/templates/helpers/new-plan.sh +1 -1
  32. package/assets/templates/helpers/plan-to-todo.sh +12 -37
  33. package/assets/templates/helpers/ship-worktrees.sh +2 -29
  34. package/assets/templates/helpers/sprint-backlog.sh +6 -6
  35. package/assets/templates/helpers/verify-contract.sh +1 -111
  36. package/assets/templates/helpers/verify-sprint.sh +3 -180
  37. package/assets/templates/plan.template.md +1 -1
  38. package/assets/templates/review.template.md +9 -34
  39. package/assets/workflow-contract.v1.json +10 -19
  40. package/docs/README.md +10 -10
  41. package/docs/architecture/CURRENT.md +170 -0
  42. package/docs/architecture/EVOLUTION.md +42 -0
  43. package/docs/architecture/current/README.md +4 -156
  44. package/docs/architecture/decisions/20260803-release-identity-binding-and-exit-policy.md +2 -2
  45. package/docs/architecture/decisions/20260823-immediate-controller-relay.md +53 -0
  46. package/docs/architecture/decisions/20260826-browser-runtime-v2.md +73 -0
  47. package/docs/architecture/history/README.md +7 -0
  48. package/docs/architecture/{chatgpt-handoff-facade.md → history/chatgpt-handoff-facade.md} +4 -0
  49. package/docs/architecture/{global-hook-runtime.md → history/global-hook-runtime.md} +7 -3
  50. package/docs/architecture/{ios-semantic-automation-provider-v2.md → history/ios-semantic-automation-provider-v2.md} +6 -2
  51. package/docs/architecture/history.md +3 -34
  52. package/docs/architecture/index.md +15 -98
  53. package/docs/architecture/modules/controller-runtime/transport-lifecycle.md +1 -1
  54. package/docs/architecture/reviews/2026-08-22-semantic-harness-convergence-acceptance.md +39 -0
  55. package/docs/architecture/versions/1.6.md +38 -0
  56. package/docs/architecture/versions/1.7.md +41 -0
  57. package/docs/forge-chatgpt-browser-engine.md +2 -2
  58. package/docs/forge-chatgpt-mcp-setup.md +4 -28
  59. package/docs/forge-chatgpt-supervised-automation.md +3 -3
  60. package/docs/forge-github-issue-launcher.md +1 -1
  61. package/docs/forge-runtime-self-healing-loop.md +1 -1
  62. package/docs/operations/controller-browser-plugin.md +38 -22
  63. package/docs/operations/controller-performance-and-502.md +124 -0
  64. package/docs/operations/controller-reliability-runbook.md +1 -1
  65. package/docs/operations/features.md +3 -3
  66. package/docs/operations/github-repository.md +1 -1
  67. package/docs/operations/homebrew.md +2 -2
  68. package/docs/operations/mcp-tool-exposure.md +5 -3
  69. package/docs/tutorials/01-install-and-start.md +1 -1
  70. package/docs/tutorials/01-install-and-start.zh-CN.md +1 -1
  71. package/docs/wiki/Architecture.md +6 -6
  72. package/docs/wiki/Implementation.md +2 -2
  73. package/docs/wiki/Installation.md +1 -1
  74. package/docs/wiki/Integrations.md +2 -2
  75. package/docs/wiki/Quick-Start.md +1 -1
  76. package/docs/wiki/Work-Lifecycle.md +1 -1
  77. package/package.json +29 -10
  78. package/scripts/activate-source-baseline.ts +17 -13
  79. package/scripts/benchmark-background-check-overlap.ts +228 -0
  80. package/scripts/benchmark-mcp-host.sh +117 -0
  81. package/scripts/benchmark-mcp-transport.ts +170 -0
  82. package/scripts/benchmark-quality-harness.ts +146 -0
  83. package/scripts/benchmark-route-session-concurrency.ts +207 -6
  84. package/scripts/benchmark-thin-harness-mcp-e2e.ts +7 -1
  85. package/scripts/benchmark-typescript-navigation.ts +186 -0
  86. package/scripts/benchmark-work-efficiency.ts +334 -0
  87. package/scripts/capture-plan.sh +3 -3
  88. package/scripts/check-agent-tooling.sh +8 -35
  89. package/scripts/check-architecture-sync.sh +17 -86
  90. package/scripts/check-mcp-compatibility.ts +14 -0
  91. package/scripts/check-public-docs.sh +14 -1
  92. package/scripts/check-runtime-architecture.mjs +107 -64
  93. package/scripts/check-stable-baseline.ts +92 -0
  94. package/scripts/check-task-workflow.sh +4 -4
  95. package/scripts/contract-worktree.sh +1 -21
  96. package/scripts/ensure-task-workflow.sh +22 -55
  97. package/scripts/host-temporary-cloud-mcp-e2e.sh +265 -0
  98. package/scripts/install-standalone-recovery.ts +24 -0
  99. package/scripts/lib/project-init-lib.sh +15 -44
  100. package/scripts/migrate-chatgpt-automation-schedules.ts +64 -0
  101. package/scripts/migrate-project-template.sh +23 -1179
  102. package/scripts/new-plan.sh +1 -1
  103. package/scripts/plan-to-todo.sh +11 -36
  104. package/scripts/run-governed-gate.ts +2 -1
  105. package/scripts/ship-worktrees.sh +2 -29
  106. package/scripts/smoke-ios-physical-device.ts +4 -2
  107. package/scripts/smoke-runtime-recovery.ts +1 -35
  108. package/scripts/smoke-schedule-engine.ts +1 -20
  109. package/scripts/sprint-backlog.sh +1 -1
  110. package/scripts/verify-contract.sh +1 -111
  111. package/scripts/verify-forge-runtime.sh +0 -1
  112. package/scripts/verify-sprint.sh +3 -180
  113. package/scripts/workflow-contract.ts +1 -5
  114. package/src/cli/commands/chatgpt.ts +31 -2
  115. package/src/cli/commands/init-hook.ts +3 -3
  116. package/src/cli/commands/mcp.ts +9 -5
  117. package/src/cli/commands/plugin.ts +37 -10
  118. package/src/cli/commands/recovery.ts +25 -3
  119. package/src/cli/commands/runtime.ts +55 -3
  120. package/src/cli/commands/security.ts +12 -1
  121. package/src/cli/commands/setup-profile.ts +31 -21
  122. package/src/cli/controller/check-runner.ts +106 -3
  123. package/src/cli/controller/composite-result.ts +1 -1
  124. package/src/cli/controller/context/focus.ts +51 -0
  125. package/src/cli/controller/context/instruction-context.ts +114 -0
  126. package/src/cli/controller/context/known-paths.ts +76 -0
  127. package/src/cli/controller/context/query-planning.ts +110 -0
  128. package/src/cli/controller/context/rule-resolution.ts +532 -0
  129. package/src/cli/controller/context/source-materializer.ts +278 -0
  130. package/src/cli/controller/context/structural.ts +16 -0
  131. package/src/cli/controller/context/types.ts +286 -0
  132. package/src/cli/controller/context-pack.ts +898 -430
  133. package/src/cli/controller/launch-agents.ts +77 -2
  134. package/src/cli/controller/operational-plan.ts +2 -2
  135. package/src/cli/controller/work-mode.ts +6 -4
  136. package/src/cli/editing/edit-session.ts +60 -7
  137. package/src/cli/github/github.ts +133 -0
  138. package/src/cli/hook/prompt-guard-decision.ts +17 -18
  139. package/src/cli/hook/prompt-intents.ts +1 -1
  140. package/src/cli/installer/managed-entries.ts +15 -1
  141. package/src/cli/local-bridge/console-automations.ts +225 -67
  142. package/src/cli/local-bridge/console-view-models.ts +3 -35
  143. package/src/cli/local-bridge/facade-api.ts +2 -217
  144. package/src/cli/local-bridge/frontend/src/App.tsx +3 -3
  145. package/src/cli/local-bridge/frontend/src/features/automations/AutomationsView.tsx +153 -3
  146. package/src/cli/local-bridge/frontend/src/features/capabilities/CapabilitiesView.tsx +37 -4
  147. package/src/cli/local-bridge/frontend/src/features/overview/OverviewView.tsx +183 -3
  148. package/src/cli/local-bridge/frontend/src/features/repositories/RepositoriesView.tsx +1 -1
  149. package/src/cli/local-bridge/frontend/src/features/work/WorkView.tsx +4 -3
  150. package/src/cli/local-bridge/frontend/src/lib/api.ts +18 -11
  151. package/src/cli/local-bridge/frontend/src/lib/routes.ts +1 -1
  152. package/src/cli/local-bridge/frontend/src/shell/CommandBar.tsx +1 -1
  153. package/src/cli/local-bridge/frontend/src/shell/Sidebar.tsx +4 -3
  154. package/src/cli/local-bridge/frontend/src/styles.css +27 -11
  155. package/src/cli/local-bridge/frontend/src/types.ts +8 -7
  156. package/src/cli/local-bridge/job-store.ts +1 -490
  157. package/src/cli/local-bridge/server.ts +29 -532
  158. package/src/cli/local-bridge/ui-dist/app.css +1 -1
  159. package/src/cli/local-bridge/ui-dist/app.js +5101 -4967
  160. package/src/cli/mcp/auth.ts +5 -5
  161. package/src/cli/mcp/instructions.ts +3 -2
  162. package/src/cli/mcp/legacy-tool-service.ts +0 -189
  163. package/src/cli/mcp/multi-repository.ts +16 -5
  164. package/src/cli/mcp/oauth.ts +175 -26
  165. package/src/cli/mcp/paths.ts +8 -2
  166. package/src/cli/mcp/repository-tools.ts +356 -101
  167. package/src/cli/mcp/server.ts +625 -54
  168. package/src/cli/mcp/tool-capability-cache.ts +1 -1
  169. package/src/cli/mcp/toolset-selection.ts +1 -1
  170. package/src/cli/mcp/toolset.ts +42 -5
  171. package/src/cli/mcp/transports/http.ts +125 -15
  172. package/src/cli/mcp/transports/session-registry.ts +67 -5
  173. package/src/cli/mcp/types.ts +3 -3
  174. package/src/cli/repositories/command-classifier.ts +209 -14
  175. package/src/cli/repositories/command-executor.ts +55 -521
  176. package/src/cli/repositories/command-process.ts +108 -0
  177. package/src/cli/repositories/command-scope.ts +99 -41
  178. package/src/cli/repositories/controller-home.ts +7 -8
  179. package/src/cli/repositories/git-command-executor.ts +2 -0
  180. package/src/cli/repositories/locks.ts +53 -16
  181. package/src/cli/repositories/repository-snapshot.ts +121 -0
  182. package/src/cli/repositories/safe-patch.ts +6 -4
  183. package/src/cli/repositories/selected-path-actions.ts +17 -9
  184. package/src/cli/repositories/structured-git.ts +110 -10
  185. package/src/cli/repository/inspector.ts +565 -62
  186. package/src/cli/repository/session-cache.ts +58 -17
  187. package/src/cli/v81-entry.ts +1 -4
  188. package/src/effects/fs-transaction.ts +85 -17
  189. package/src/runtime/context/codegraph-read-provider.ts +233 -2
  190. package/src/runtime/context/codegraph-sidecar.cjs +74 -40
  191. package/src/runtime/context/generic-lsp-provider.ts +355 -0
  192. package/src/runtime/context/lsp-client.ts +283 -0
  193. package/src/runtime/context/semantic-navigation.ts +275 -0
  194. package/src/runtime/context/swift-navigation.ts +565 -0
  195. package/src/runtime/context/typescript-navigation.ts +226 -0
  196. package/src/runtime/control-plane/dispatch-priority.ts +28 -0
  197. package/src/runtime/control-plane/execution/direct-edit-work-completion.ts +196 -2
  198. package/src/runtime/control-plane/execution/edit-validation-coordinator.ts +86 -24
  199. package/src/runtime/control-plane/execution/execution-identity.ts +65 -14
  200. package/src/runtime/control-plane/execution/session-store.ts +18 -0
  201. package/src/runtime/control-plane/execution/validation.ts +15 -2
  202. package/src/runtime/control-plane/execution/verification-evidence.ts +58 -3
  203. package/src/runtime/control-plane/execution/work-handle-store.ts +27 -2
  204. package/src/runtime/control-plane/execution/work-lifecycle-audit.ts +258 -0
  205. package/src/runtime/control-plane/execution/work-remote-delivery.ts +215 -0
  206. package/src/runtime/control-plane/execution/work-task-receipt.ts +54 -11
  207. package/src/runtime/control-plane/execution/work-terminal-cleanup.ts +175 -8
  208. package/src/runtime/control-plane/execution/work-validation-reconciler.ts +28 -21
  209. package/src/runtime/control-plane/execution/work-verification-snapshot.ts +87 -9
  210. package/src/runtime/control-plane/facade/capability-registry.ts +129 -25
  211. package/src/runtime/control-plane/facade/controller-round-relay.ts +991 -0
  212. package/src/runtime/control-plane/facade/controller-session-store.ts +144 -14
  213. package/src/runtime/control-plane/facade/goal-workloop-access.ts +9 -2
  214. package/src/runtime/control-plane/facade/goal-workloop.ts +885 -105
  215. package/src/runtime/control-plane/facade/index.ts +1 -0
  216. package/src/runtime/control-plane/facade/plan-contract-store.ts +211 -26
  217. package/src/runtime/control-plane/facade/requirement-board.ts +24 -8
  218. package/src/runtime/control-plane/facade/semantic-admission.ts +205 -0
  219. package/src/runtime/control-plane/facade/suggested-actions.ts +5 -1
  220. package/src/runtime/control-plane/facade/types.ts +55 -11
  221. package/src/runtime/control-plane/facade/work-contract-store.ts +204 -73
  222. package/src/runtime/control-plane/generated-cache-retention.ts +271 -0
  223. package/src/runtime/control-plane/global-scheduler/config.ts +44 -0
  224. package/src/runtime/control-plane/global-scheduler/dispatch-capacity.ts +80 -0
  225. package/src/runtime/control-plane/global-scheduler/durable-admission.ts +46 -0
  226. package/src/runtime/control-plane/global-scheduler/maintenance.ts +145 -0
  227. package/src/runtime/control-plane/global-scheduler/projection-refresh.ts +84 -0
  228. package/src/runtime/control-plane/global-scheduler/reconciliation.ts +3 -3
  229. package/src/runtime/control-plane/global-scheduler/scheduler.ts +273 -542
  230. package/src/runtime/control-plane/global-scheduler/source-scan.ts +59 -0
  231. package/src/runtime/control-plane/global-scheduler/state.ts +88 -0
  232. package/src/runtime/control-plane/global-scheduler/worker-attachment.ts +57 -0
  233. package/src/runtime/control-plane/global-scheduler/worker-exit-decision.ts +38 -0
  234. package/src/runtime/control-plane/global-scheduler/worker-exit-reconciler.ts +175 -0
  235. package/src/runtime/control-plane/global-scheduler/worker-launch.ts +111 -0
  236. package/src/runtime/control-plane/global-scheduler/worker-lifecycle-store.ts +64 -0
  237. package/src/runtime/control-plane/global-scheduler/worker-lifecycle.ts +150 -0
  238. package/src/runtime/control-plane/global-scheduler/worker-process.ts +119 -0
  239. package/src/runtime/control-plane/global-scheduler/worker-stderr.ts +60 -0
  240. package/src/runtime/control-plane/launcher/chatgpt-work-binding-store.ts +50 -0
  241. package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +642 -51
  242. package/src/runtime/control-plane/launcher/launch-reservation-store.ts +40 -0
  243. package/src/runtime/control-plane/launcher/thin-launcher.ts +194 -10
  244. package/src/runtime/control-plane/persistence/controller-home-migration.ts +487 -0
  245. package/src/runtime/control-plane/persistence/requirement-store.ts +15 -11
  246. package/src/runtime/control-plane/persistence/sqlite-store.ts +33 -2
  247. package/src/runtime/control-plane/release-retention.ts +62 -2
  248. package/src/runtime/control-plane/routing/route-policy.ts +7 -16
  249. package/src/runtime/control-plane/runtime-status-client.ts +0 -2
  250. package/src/runtime/diagnostics/mcp-timing.ts +19 -0
  251. package/src/runtime/diagnostics/mcp-transport-benchmark.ts +129 -0
  252. package/src/runtime/diagnostics/performance.ts +24 -1
  253. package/src/runtime/evidence/event-ledger.ts +1 -1
  254. package/src/runtime/execution/jobs/store.ts +58 -4
  255. package/src/runtime/execution/jobs/types.ts +1 -1
  256. package/src/runtime/execution/managed-workspace.ts +203 -1
  257. package/src/runtime/execution/process-runtime/check-facade.ts +52 -14
  258. package/src/runtime/execution/process-runtime/check-result.ts +63 -2
  259. package/src/runtime/execution/process-runtime/check-scheduling.ts +114 -0
  260. package/src/runtime/execution/process-runtime/command-facade.ts +346 -40
  261. package/src/runtime/execution/process-runtime/gc.ts +98 -12
  262. package/src/runtime/execution/process-runtime/lightweight-managed.ts +1184 -0
  263. package/src/runtime/execution/process-runtime/persisted-check.ts +57 -6
  264. package/src/runtime/execution/process-runtime/resource-claims.ts +97 -8
  265. package/src/runtime/execution/process-runtime/runtime.ts +59 -4
  266. package/src/runtime/execution/process-runtime/store.ts +7 -0
  267. package/src/runtime/execution/process-runtime/types.ts +2 -0
  268. package/src/runtime/execution/thin-harness/async-process.ts +12 -2
  269. package/src/runtime/execution/thin-harness/search-worker.ts +54 -5
  270. package/src/runtime/execution/workers/executor.ts +0 -48
  271. package/src/runtime/gateway/mcp/execution-tools.ts +1219 -126
  272. package/src/runtime/gateway/mcp/process-tools.ts +83 -37
  273. package/src/runtime/gateway/mcp/router.ts +185 -83
  274. package/src/runtime/gateway/mcp/runtime-tool-definitions.ts +546 -0
  275. package/src/runtime/gateway/mcp/runtime-tools.ts +2555 -1616
  276. package/src/runtime/model-clients/deepseek-adapter.ts +0 -32
  277. package/src/runtime/plugins/app-store-connect-adapter.ts +123 -19
  278. package/src/runtime/plugins/browser-adapter.ts +2925 -318
  279. package/src/runtime/plugins/browser-automation-service.ts +10 -0
  280. package/src/runtime/plugins/browser-handoff-host.ts +6 -31
  281. package/src/runtime/plugins/browser-handoff.ts +92 -5
  282. package/src/runtime/plugins/browser-macos-bridge.ts +586 -45
  283. package/src/runtime/plugins/browser-node-bridge.ts +6 -34
  284. package/src/runtime/plugins/browser-provider-registry.ts +109 -0
  285. package/src/runtime/plugins/browser-runtime-contract.ts +152 -0
  286. package/src/runtime/plugins/browser-runtime.ts +183 -0
  287. package/src/runtime/plugins/browser-session-authority.ts +332 -0
  288. package/src/runtime/plugins/capability-authorization-grants.ts +354 -0
  289. package/src/runtime/plugins/desktop-operator-registration.ts +15 -12
  290. package/src/runtime/plugins/external-adapter.ts +324 -3
  291. package/src/runtime/plugins/external-registration.ts +84 -5
  292. package/src/runtime/plugins/external-unix-socket.ts +7 -1
  293. package/src/runtime/plugins/first-party-registry.ts +4 -2
  294. package/src/runtime/plugins/github-adapter.ts +125 -0
  295. package/src/runtime/plugins/gmail-adapter.ts +28 -2
  296. package/src/runtime/plugins/ios/agent-device-provider.ts +1 -1
  297. package/src/runtime/plugins/ios/agent-device-typed-provider.ts +52 -9
  298. package/src/runtime/plugins/ios/remote-xpc-hid.ts +1171 -0
  299. package/src/runtime/plugins/ios-adapter.ts +106 -16
  300. package/src/runtime/plugins/ios-agent-device.ts +234 -64
  301. package/src/runtime/plugins/ios-physical-device.ts +1143 -392
  302. package/src/runtime/plugins/lightweight-action.ts +153 -0
  303. package/src/runtime/plugins/local-system-adapter.ts +125 -8
  304. package/src/runtime/plugins/macos-capability-broker.ts +55 -9
  305. package/src/runtime/plugins/plugin-action-sidecar.ts +59 -0
  306. package/src/runtime/plugins/plugin-management-adapter.ts +181 -0
  307. package/src/runtime/plugins/resend-adapter.ts +1 -1
  308. package/src/runtime/plugins/store.ts +366 -24
  309. package/src/runtime/plugins/types.ts +39 -2
  310. package/src/runtime/plugins/xiaohongshu-publish.ts +515 -0
  311. package/src/runtime/projections/git-status-sampler.ts +16 -16
  312. package/src/runtime/projections/materialized-view.ts +28 -10
  313. package/src/runtime/recovery/actions.ts +0 -10
  314. package/src/runtime/recovery/classifier.ts +0 -9
  315. package/src/runtime/recovery/maintenance-executor.ts +415 -18
  316. package/src/runtime/recovery/probe.ts +0 -1
  317. package/src/runtime/recovery/types.ts +0 -1
  318. package/src/runtime/root/mcp-transport.ts +180 -10
  319. package/src/runtime/root/package-connector-service.ts +186 -8
  320. package/src/runtime/root/package-runtime-release.ts +143 -17
  321. package/src/runtime/root/package-runtime-service.ts +430 -22
  322. package/src/runtime/root/release-manifest.ts +7 -2
  323. package/src/runtime/root/release-materialize.ts +162 -19
  324. package/src/runtime/root/release-store.ts +48 -11
  325. package/src/runtime/root/runtime.ts +23 -5
  326. package/src/runtime/root/service.ts +100 -27
  327. package/src/runtime/root/types.ts +2 -0
  328. package/src/runtime/safe-tooling/index.ts +0 -1
  329. package/src/runtime/safe-tooling/ios-development.ts +321 -63
  330. package/src/runtime/safe-tooling/types.ts +0 -30
  331. package/src/runtime/shared/trusted-executable.ts +62 -0
  332. package/src/runtime/shared/trusted-node-executable.ts +48 -0
  333. package/src/runtime/standalone-recovery/core.ts +702 -94
  334. package/src/runtime/standalone-recovery/entry.ts +99 -23
  335. package/src/runtime/standalone-recovery/installer.ts +19 -3
  336. package/src/runtime/standalone-recovery/service-labels.ts +2 -0
  337. package/src/runtime/standalone-recovery/watchdog-heartbeat.ts +160 -0
  338. package/src/runtime/workflow/schedules/browser-probe.ts +258 -0
  339. package/src/runtime/workflow/schedules/chatgpt-automation-migration.ts +40 -0
  340. package/src/runtime/workflow/schedules/engine.ts +509 -80
  341. package/src/runtime/workflow/schedules/github-issue-watch.ts +158 -0
  342. package/src/runtime/workflow/schedules/settlement.ts +48 -4
  343. package/src/runtime/workflow/schedules/store.ts +131 -10
  344. package/src/runtime/workflow/schedules/types.ts +6 -3
  345. package/src/runtime/workflow/schedules/work-continuation.ts +120 -34
  346. package/src/testing/test-governance.ts +8 -40
  347. package/assets/reference-configs/heartbeat-triage.md +0 -57
  348. package/assets/templates/helpers/harness-trace-grade.sh +0 -150
  349. package/assets/templates/helpers/heartbeat-triage.sh +0 -361
  350. package/assets/templates/helpers/maintenance-triage.sh +0 -167
  351. package/bin/forge-desktop-helper.mjs +0 -204
  352. package/docs/architecture/current/approved-target-architecture.zh-CN.md +0 -1501
  353. package/docs/architecture/current/architecture-invariants.md +0 -331
  354. package/docs/architecture/current/automation-and-schedule-engine.md +0 -453
  355. package/docs/architecture/current/codegraph-context-provider.md +0 -226
  356. package/docs/architecture/current/control-plane-authority-inventory.md +0 -94
  357. package/docs/architecture/current/controller-repository-decoupling.md +0 -148
  358. package/docs/architecture/current/dispatch-and-agent-strategy.md +0 -354
  359. package/docs/architecture/current/entity-model.md +0 -592
  360. package/docs/architecture/current/external-plugin-governance.md +0 -396
  361. package/docs/architecture/current/failure-recovery.md +0 -447
  362. package/docs/architecture/current/governance.md +0 -213
  363. package/docs/architecture/current/human-interaction-plane.md +0 -87
  364. package/docs/architecture/current/implementation-status.md +0 -128
  365. package/docs/architecture/current/job-and-run-lifecycle.md +0 -413
  366. package/docs/architecture/current/legacy-governance.md +0 -58
  367. package/docs/architecture/current/local-workspace-target-grants.md +0 -70
  368. package/docs/architecture/current/migration-roadmap.md +0 -105
  369. package/docs/architecture/current/multi-repository-execution.md +0 -371
  370. package/docs/architecture/current/operations-runbook.md +0 -45
  371. package/docs/architecture/current/peer-supercontroller-runtime.md +0 -32
  372. package/docs/architecture/current/personal-assistant-plugin-baseline.md +0 -206
  373. package/docs/architecture/current/repository-access-modes.md +0 -102
  374. package/docs/architecture/current/route-policy.md +0 -15
  375. package/docs/architecture/current/route-session-concurrency.md +0 -85
  376. package/docs/architecture/current/runtime-architecture-simplification.md +0 -214
  377. package/docs/architecture/current/runtime-directory-map.md +0 -49
  378. package/docs/architecture/current/runtime-health-and-resource-lifecycle.md +0 -85
  379. package/docs/architecture/current/scheduler-and-resource-claims.md +0 -422
  380. package/docs/architecture/current/session-aware-execution-and-authorization.md +0 -77
  381. package/docs/architecture/current/system-overview.md +0 -144
  382. package/docs/architecture/current/target-requirements-traceability.md +0 -202
  383. package/docs/architecture/current/thin-harness-governance-policy.md +0 -32
  384. package/docs/architecture/current/thin-harness-v1.md +0 -311
  385. package/docs/architecture/current/verification-and-release-gates.md +0 -391
  386. package/docs/forge-autonomous-goal-loop.md +0 -9
  387. package/docs/forge-provider-configuration.md +0 -7
  388. package/docs/operations/chatgpt-personal-assistant-runtime.md +0 -83
  389. package/docs/operations/controller-desktop-plugin.md +0 -112
  390. package/docs/operations/gmail-assistant-routines.md +0 -186
  391. package/docs/operations/personal-assistant-operator-guide.md +0 -61
  392. package/docs/operations/provider-configuration.md +0 -31
  393. package/scripts/harness-trace-grade.sh +0 -150
  394. package/scripts/heartbeat-triage.sh +0 -361
  395. package/scripts/maintenance-triage.sh +0 -167
  396. package/src/cli/local-bridge/frontend/src/features/settings/SettingsView.tsx +0 -2
  397. package/src/cli/repositories/goal-registry.ts +0 -239
  398. package/src/runtime/assistant/action-proposals.ts +0 -279
  399. package/src/runtime/assistant/intent.ts +0 -395
  400. package/src/runtime/assistant/model-provider.ts +0 -460
  401. package/src/runtime/assistant/openapi.ts +0 -223
  402. package/src/runtime/assistant/policy.ts +0 -89
  403. package/src/runtime/assistant/readiness.ts +0 -258
  404. package/src/runtime/assistant/routine-runtime.ts +0 -477
  405. package/src/runtime/assistant/schedule-binding.ts +0 -171
  406. package/src/runtime/assistant/standing-grants.ts +0 -375
  407. package/src/runtime/assistant/store.ts +0 -243
  408. package/src/runtime/assistant/types.ts +0 -135
  409. package/src/runtime/control-plane/goal-loop/config-facade.ts +0 -700
  410. package/src/runtime/control-plane/goal-loop/config-store.ts +0 -570
  411. package/src/runtime/control-plane/goal-loop/config-types.ts +0 -213
  412. package/src/runtime/control-plane/goal-loop/executor-router.ts +0 -109
  413. package/src/runtime/control-plane/goal-loop/failure-taxonomy.ts +0 -149
  414. package/src/runtime/control-plane/goal-loop/goal-contract-store.ts +0 -304
  415. package/src/runtime/control-plane/goal-loop/goal-loop-engine.ts +0 -1001
  416. package/src/runtime/control-plane/goal-loop/handoff-packet.ts +0 -160
  417. package/src/runtime/control-plane/goal-loop/index.ts +0 -13
  418. package/src/runtime/control-plane/goal-loop/local-tools.ts +0 -290
  419. package/src/runtime/control-plane/goal-loop/policy-gates.ts +0 -203
  420. package/src/runtime/control-plane/goal-loop/provider-dispatch.ts +0 -93
  421. package/src/runtime/control-plane/goal-loop/provider-registry.ts +0 -545
  422. package/src/runtime/control-plane/goal-loop/types.ts +0 -378
  423. package/src/runtime/control-plane/startup-recovery.ts +0 -198
  424. package/src/runtime/gateway/mcp/resource-policy.ts +0 -186
  425. package/src/runtime/personal-assistant/gmail-triage-manager.ts +0 -231
  426. package/src/runtime/personal-assistant/reporting-runtime.ts +0 -344
  427. package/src/runtime/personal-assistant/triage-runtime.ts +0 -748
  428. package/src/runtime/plugins/desktop-adapter.ts +0 -374
  429. package/src/runtime/safe-tooling/browser-safe.ts +0 -133
  430. package/src/runtime/workflow/findings/store.ts +0 -204
  431. package/src/runtime/workflow/findings/types.ts +0 -58
  432. package/src/runtime/workflow/portfolio/engine.ts +0 -20
  433. package/src/runtime/workflow/portfolio/store.ts +0 -185
  434. package/src/runtime/workflow/portfolio/types.ts +0 -29
@@ -1,5 +1,5 @@
1
1
  import { createHash } from 'crypto';
2
- import { existsSync, mkdirSync, realpathSync } from 'fs';
2
+ import { existsSync, mkdirSync, readFileSync, realpathSync, symlinkSync } from 'fs';
3
3
  import { dirname, join, resolve } from 'path';
4
4
  import { repositoryControllerRoot } from '../../cli/repositories/controller-home';
5
5
  import type { RepositoryRecord } from '../../cli/repositories/types';
@@ -14,6 +14,7 @@ import { branchSlugSegment, validateBranchName } from '../../cli/repositories/br
14
14
  import { withControllerLock } from '../../cli/repositories/locks';
15
15
  import { resolveGitExecutable } from '../../effects/git-executable';
16
16
  import { runProcess } from '../../effects/process-runner';
17
+ import { repositoryChildProcessEnvironment, resolveBunExecutable } from '../shared/process-environment';
17
18
  import { readJsonFile, writeJsonAtomic } from '../shared/json-files';
18
19
 
19
20
  export interface EnsureManagedWorkspaceInput {
@@ -21,6 +22,24 @@ export interface EnsureManagedWorkspaceInput {
21
22
  title: string;
22
23
  baseRef?: string;
23
24
  branchName?: string;
25
+ /** Explicitly materialize lockfile-backed Node dependencies in this isolated worktree. */
26
+ prepareDependencies?: boolean;
27
+ }
28
+
29
+ export interface ManagedWorkspaceDependencyBootstrap {
30
+ packageManager: 'bun' | 'pnpm' | 'npm' | 'yarn';
31
+ lockfile: string;
32
+ command: string[];
33
+ }
34
+
35
+ export interface ManagedWorkspaceDependencyPreparation {
36
+ mode: 'already_ready' | 'canonical_reuse' | 'installed';
37
+ nodeModulesRoot: string;
38
+ canonicalRoot?: string;
39
+ }
40
+
41
+ export interface ManagedWorkspaceDependencies {
42
+ materializeDependencies?: (workspaceRoot: string) => void;
24
43
  }
25
44
 
26
45
  export interface ManagedWorkspace {
@@ -73,6 +92,180 @@ function assertBranch(root: string, branch: string): string {
73
92
  return normalized;
74
93
  }
75
94
 
95
+ export function managedWorkspaceDependencyBootstrap(repoRoot: string): ManagedWorkspaceDependencyBootstrap | undefined {
96
+ if (!existsSync(join(repoRoot, 'package.json')) || existsSync(join(repoRoot, 'node_modules'))) return undefined;
97
+ const lockCandidates = [
98
+ ['bun', 'bun.lock', ['bun', 'install', '--frozen-lockfile']],
99
+ ['bun', 'bun.lockb', ['bun', 'install', '--frozen-lockfile']],
100
+ ['pnpm', 'pnpm-lock.yaml', ['pnpm', 'install', '--frozen-lockfile']],
101
+ ['npm', 'package-lock.json', ['npm', 'ci']],
102
+ ['yarn', 'yarn.lock', ['yarn', 'install', '--frozen-lockfile']],
103
+ ] as const;
104
+ const detected = lockCandidates.find(([, lockfile]) => existsSync(join(repoRoot, lockfile)));
105
+ if (!detected) return undefined;
106
+ return { packageManager: detected[0], lockfile: detected[1], command: [...detected[2]] };
107
+ }
108
+
109
+ const DEPENDENCY_REUSE_CONFIG_PATHS = [
110
+ '.npmrc',
111
+ 'bunfig.toml',
112
+ 'pnpm-workspace.yaml',
113
+ '.yarnrc.yml',
114
+ ] as const;
115
+
116
+ function dependencyInputMatches(leftRoot: string, rightRoot: string, path: string): boolean {
117
+ const left = join(leftRoot, path);
118
+ const right = join(rightRoot, path);
119
+ const leftExists = existsSync(left);
120
+ const rightExists = existsSync(right);
121
+ if (leftExists !== rightExists) return false;
122
+ return !leftExists || readFileSync(left).equals(readFileSync(right));
123
+ }
124
+
125
+ function linkedWorkspaceCanonicalRoot(repoRoot: string): string | undefined {
126
+ const common = runProcess(resolveGitExecutable(), ['-C', repoRoot, 'rev-parse', '--path-format=absolute', '--git-common-dir'], {
127
+ timeoutMs: 15_000,
128
+ maxOutputBytes: 8 * 1024,
129
+ });
130
+ if (!common.ok || !common.stdout.trim()) return undefined;
131
+ const canonicalRoot = dirname(resolve(common.stdout.trim()));
132
+ if (!existsSync(canonicalRoot)) return undefined;
133
+ try {
134
+ if (realpathSync(canonicalRoot) === realpathSync(repoRoot)) return undefined;
135
+ } catch {
136
+ return undefined;
137
+ }
138
+ const topLevel = runProcess(resolveGitExecutable(), ['-C', canonicalRoot, 'rev-parse', '--show-toplevel'], {
139
+ timeoutMs: 15_000,
140
+ maxOutputBytes: 8 * 1024,
141
+ });
142
+ if (!topLevel.ok || !topLevel.stdout.trim()) return undefined;
143
+ try {
144
+ return realpathSync(topLevel.stdout.trim()) === realpathSync(canonicalRoot) ? canonicalRoot : undefined;
145
+ } catch {
146
+ return undefined;
147
+ }
148
+ }
149
+
150
+ export function resolveManagedWorkspaceCanonicalDependencies(repoRoot: string): {
151
+ canonicalRoot: string;
152
+ nodeModulesRoot: string;
153
+ } | undefined {
154
+ const bootstrap = managedWorkspaceDependencyBootstrap(repoRoot);
155
+ if (!bootstrap) return undefined;
156
+ const canonicalRoot = linkedWorkspaceCanonicalRoot(repoRoot);
157
+ if (!canonicalRoot) return undefined;
158
+ const nodeModulesRoot = join(canonicalRoot, 'node_modules');
159
+ if (!existsSync(nodeModulesRoot)) return undefined;
160
+ const dependencyInputs = ['package.json', bootstrap.lockfile, ...DEPENDENCY_REUSE_CONFIG_PATHS];
161
+ if (!dependencyInputs.every((path) => dependencyInputMatches(repoRoot, canonicalRoot, path))) return undefined;
162
+ return { canonicalRoot, nodeModulesRoot: realpathSync(nodeModulesRoot) };
163
+ }
164
+
165
+ function packageManifestRequiresDependencyMaterialization(repoRoot: string): boolean {
166
+ const packagePath = join(repoRoot, 'package.json');
167
+ if (!existsSync(packagePath)) return false;
168
+ let manifest: Record<string, unknown>;
169
+ try {
170
+ const parsed = JSON.parse(readFileSync(packagePath, 'utf8')) as unknown;
171
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) return true;
172
+ manifest = parsed as Record<string, unknown>;
173
+ } catch {
174
+ // Preserve fail-closed dependency preparation for malformed manifests. The
175
+ // package manager remains the authority for the concrete parse error once a
176
+ // supported frozen lockfile is present.
177
+ return true;
178
+ }
179
+
180
+ const dependencyFields = [
181
+ 'dependencies',
182
+ 'devDependencies',
183
+ 'optionalDependencies',
184
+ 'peerDependencies',
185
+ 'bundleDependencies',
186
+ 'bundledDependencies',
187
+ ] as const;
188
+ if (dependencyFields.some((field) => {
189
+ const value = manifest[field];
190
+ return Array.isArray(value)
191
+ ? value.length > 0
192
+ : Boolean(value && typeof value === 'object' && Object.keys(value as Record<string, unknown>).length > 0);
193
+ })) return true;
194
+
195
+ const workspaces = manifest.workspaces;
196
+ if (Array.isArray(workspaces)) return workspaces.length > 0;
197
+ if (workspaces && typeof workspaces === 'object') {
198
+ const packages = (workspaces as Record<string, unknown>).packages;
199
+ if (Array.isArray(packages)) return packages.length > 0;
200
+ return Object.keys(workspaces as Record<string, unknown>).length > 0;
201
+ }
202
+ return false;
203
+ }
204
+
205
+ function reuseManagedWorkspaceCanonicalDependencies(repoRoot: string): ManagedWorkspaceDependencyPreparation | undefined {
206
+ const nodeModulesRoot = join(repoRoot, 'node_modules');
207
+ const reusable = resolveManagedWorkspaceCanonicalDependencies(repoRoot);
208
+ if (!reusable) return undefined;
209
+ try {
210
+ symlinkSync(reusable.nodeModulesRoot, nodeModulesRoot, process.platform === 'win32' ? 'junction' : 'dir');
211
+ } catch (error) {
212
+ if (!existsSync(nodeModulesRoot)) {
213
+ const detail = error instanceof Error ? error.message : String(error);
214
+ throw new Error(`MANAGED_WORKSPACE_DEPENDENCY_REUSE_FAILED: ${detail}`);
215
+ }
216
+ }
217
+ return {
218
+ mode: 'canonical_reuse',
219
+ nodeModulesRoot: realpathSync(nodeModulesRoot),
220
+ canonicalRoot: reusable.canonicalRoot,
221
+ };
222
+ }
223
+
224
+ export function materializeManagedWorkspaceDependencies(repoRoot: string): ManagedWorkspaceDependencyPreparation | undefined {
225
+ if (!existsSync(join(repoRoot, 'package.json'))) return undefined;
226
+ const nodeModulesRoot = join(repoRoot, 'node_modules');
227
+ if (existsSync(nodeModulesRoot)) {
228
+ return { mode: 'already_ready', nodeModulesRoot: realpathSync(nodeModulesRoot) };
229
+ }
230
+ // A linked worktree may safely reuse canonical dependencies even when the
231
+ // package manifest itself declares no dependencies. The supported lockfile
232
+ // and dependency-reuse inputs remain the authority for proving equivalence.
233
+ const reused = reuseManagedWorkspaceCanonicalDependencies(repoRoot);
234
+ if (reused) return reused;
235
+ // A package manifest can define dependency-free scripts (for example a
236
+ // built-in `node -e` check). Such checks do not need node_modules and must not
237
+ // be rejected merely because the repository intentionally has no lockfile.
238
+ if (!packageManifestRequiresDependencyMaterialization(repoRoot)) return undefined;
239
+ const bootstrap = managedWorkspaceDependencyBootstrap(repoRoot);
240
+ if (!bootstrap) {
241
+ throw new Error('MANAGED_WORKSPACE_DEPENDENCY_LOCK_REQUIRED: package.json declares dependencies but no supported lockfile was found');
242
+ }
243
+ const childEnv = repositoryChildProcessEnvironment();
244
+ const executable = bootstrap.packageManager === 'bun'
245
+ ? resolveBunExecutable(process.execPath, childEnv)
246
+ : bootstrap.command[0]!;
247
+ const result = runProcess(executable, bootstrap.command.slice(1), {
248
+ cwd: repoRoot,
249
+ env: childEnv,
250
+ timeoutMs: 10 * 60_000,
251
+ maxOutputBytes: 4 * 1024 * 1024,
252
+ });
253
+ if (!result.ok) {
254
+ const detail = result.stderr || result.error || `exit ${result.status}`;
255
+ throw new Error(`MANAGED_WORKSPACE_DEPENDENCY_INSTALL_FAILED: ${bootstrap.command.join(' ')}: ${detail}`);
256
+ }
257
+ if (!existsSync(nodeModulesRoot)) {
258
+ throw new Error(`MANAGED_WORKSPACE_DEPENDENCY_INSTALL_INCOMPLETE: ${bootstrap.command.join(' ')} completed without node_modules`);
259
+ }
260
+ return { mode: 'installed', nodeModulesRoot: realpathSync(nodeModulesRoot) };
261
+ }
262
+
263
+ export function materializeManagedWorkspaceCheckDependencies(repoRoot: string): ManagedWorkspaceDependencyPreparation | undefined {
264
+ if (!existsSync(join(repoRoot, 'package.json')) || existsSync(join(repoRoot, 'node_modules'))) return undefined;
265
+ if (!linkedWorkspaceCanonicalRoot(repoRoot)) return undefined;
266
+ return materializeManagedWorkspaceDependencies(repoRoot);
267
+ }
268
+
76
269
  function existingWorkspace(path: string, branch: string): boolean {
77
270
  if (!existsSync(path)) return false;
78
271
  const root = runProcess(resolveGitExecutable(), ['-C', path, 'rev-parse', '--show-toplevel'], {
@@ -109,6 +302,7 @@ export function ensureManagedWorkspace(
109
302
  controllerHome: string,
110
303
  repository: RepositoryRecord,
111
304
  input: EnsureManagedWorkspaceInput,
305
+ dependencies: ManagedWorkspaceDependencies = {},
112
306
  ): ManagedWorkspace {
113
307
  const requestId = input.requestId.trim();
114
308
  if (!requestId) throw new Error('MANAGED_WORKSPACE_REQUEST_ID_REQUIRED');
@@ -159,6 +353,14 @@ export function ensureManagedWorkspace(
159
353
  if (!repositoryCheckoutRootMatches(repository, path)) {
160
354
  throw new Error(`MANAGED_WORKSPACE_REPOSITORY_MISMATCH: ${path}`);
161
355
  }
356
+ if (input.prepareDependencies === true) {
357
+ (dependencies.materializeDependencies ?? materializeManagedWorkspaceDependencies)(path);
358
+ } else {
359
+ // Reusing a byte-equivalent canonical dependency tree is cheap and
360
+ // deterministic, so isolated Work checkouts should get it even when a
361
+ // full package-manager install was not explicitly requested.
362
+ reuseManagedWorkspaceCanonicalDependencies(path);
363
+ }
162
364
 
163
365
  const record = addRepositoryCheckout({
164
366
  repoId: repository.repoId,
@@ -1,8 +1,9 @@
1
1
  /**
2
2
  * Lightweight run_check facade.
3
3
  *
4
- * Short checks complete via Process Runtime and return results directly.
5
- * Long checks return a Managed Process handle for the same OS process.
4
+ * Ordinary checks execute through an in-memory lightweight handle and return
5
+ * within the interactive budget without creating Process/Lease state. Checks
6
+ * with real Work/Edit/verification consumers keep persisted Process receipts.
6
7
  * Multi-phase and release checks require explicit external Controller handling.
7
8
  */
8
9
 
@@ -15,6 +16,12 @@ import {
15
16
  } from '../../../cli/controller/check-runner';
16
17
  import { claimsForCheck, scopeResourceClaims, toProcessClaims } from './resource-claims';
17
18
  import { spawnManagedProcess, waitForProcess, getProcessHandle } from './runtime';
19
+ import {
20
+ getLightweightProcessHandle,
21
+ isLightweightProcessId,
22
+ startLightweightControllerCheck,
23
+ waitForLightweightProcess,
24
+ } from './lightweight-managed';
18
25
  import type { ProcessHandle } from './types';
19
26
  import { DEFAULT_INTERACTIVE_WAIT_MS } from './types';
20
27
  import { durationAwareInteractiveWaitMs } from './interactive-admission';
@@ -37,10 +44,14 @@ export interface RunCheckFacadeInput {
37
44
  */
38
45
  leaseWaitMs?: number;
39
46
  requestId?: string;
47
+ /** Stable caller-owned semantic identity for safely reattaching the same request before rebuilding ephemeral execution inputs. */
48
+ requestSemanticFingerprint?: string;
40
49
  workId?: string;
41
50
  commandId?: string;
42
51
  /** Force durable workflow (release / multi-phase). */
43
52
  forceDurable?: boolean;
53
+ /** Internal-only: allow an already-authorized external Work Controller to execute a durable-class check through persisted Process Runtime. */
54
+ allowDurableCheckExecution?: boolean;
44
55
  signal?: AbortSignal;
45
56
  /** Immutable resolved identity — required; never inferred from main/active/cwd. */
46
57
  executionIdentity: ResolvedExecutionIdentity;
@@ -64,16 +75,7 @@ export function processCheckSemanticScopeKey(
64
75
  input: Pick<RunCheckFacadeInput, 'workId' | 'verificationBinding' | 'checkoutId'>,
65
76
  reuseScope: 'repository' | 'checkout',
66
77
  ): string {
67
- const base = reuseScope === 'repository' ? 'repository' : `checkout:${input.checkoutId ?? 'unknown'}`;
68
- const binding = input.verificationBinding;
69
- const owner = [
70
- input.workId ? `work:${input.workId}` : undefined,
71
- binding?.executionSessionId ? `execution:${binding.executionSessionId}` : undefined,
72
- binding?.editSessionId ? `edit:${binding.editSessionId}:r${binding.editRevision ?? 'unknown'}` : undefined,
73
- binding?.issueId ? `issue:${binding.issueId}` : undefined,
74
- binding?.taskId ? `task:${binding.taskId}` : undefined,
75
- ].filter(Boolean).join('|') || 'unbound';
76
- return `${base}|owner:${owner}`;
78
+ return reuseScope === 'repository' ? 'repository' : `checkout:${input.checkoutId ?? 'unknown'}`;
77
79
  }
78
80
 
79
81
  export interface RunCheckFacadeResult {
@@ -152,8 +154,9 @@ export async function runCheckViaProcessRuntime(
152
154
  };
153
155
  }
154
156
 
155
- // Most checks are builds/tests; return their existing Process handle at once.
156
- // Only predictable shell primitives keep a short synchronous admission.
157
+ // The wait budget is an interaction preference, not a persistence reason.
158
+ // Ordinary checks stay in memory; only a real durable evidence consumer may
159
+ // allocate Process/Lease state.
157
160
  const interactiveWaitMs = durationAwareInteractiveWaitMs(
158
161
  check.command,
159
162
  input.interactiveWaitMs,
@@ -165,6 +168,14 @@ export async function runCheckViaProcessRuntime(
165
168
  ? Math.max(1_000, Math.trunc(input.timeoutMs))
166
169
  : check.timeoutMs,
167
170
  );
171
+ const durableVerificationBinding = Boolean(
172
+ input.workId
173
+ || input.verificationSnapshot
174
+ || input.verificationBinding?.executionSessionId
175
+ || input.verificationBinding?.editSessionId
176
+ || input.verificationBinding?.issueId
177
+ || input.verificationBinding?.taskId,
178
+ );
168
179
  if (!input.executionIdentity) {
169
180
  throw new Error('EXECUTION_IDENTITY_REQUIRED: run_check requires an immutable executionIdentity');
170
181
  }
@@ -179,6 +190,27 @@ export async function runCheckViaProcessRuntime(
179
190
  `CHECKOUT_ROUTE_MISMATCH: check checkout ${input.checkoutId} differs from identity ${executionIdentity.checkoutId}`,
180
191
  );
181
192
  }
193
+ if (!durableVerificationBinding) {
194
+ const lightweight = await startLightweightControllerCheck({
195
+ controllerHome: input.controllerHome,
196
+ repoId: input.repoId,
197
+ repoRoot: input.repoRoot,
198
+ checkId: input.checkId,
199
+ interactiveWaitMs,
200
+ timeoutMs,
201
+ workId: input.workId,
202
+ commandId: input.commandId ?? input.requestId,
203
+ });
204
+ const handle = lightweight.handle;
205
+ return {
206
+ mode: handle.completed ? 'direct' : 'managed',
207
+ checkId: input.checkId,
208
+ check,
209
+ process: handle,
210
+ ok: handle.completed ? handle.ok : undefined,
211
+ durableSideEffects: emptyEffects,
212
+ };
213
+ }
182
214
  const claims = scopeResourceClaims(
183
215
  claimsForCheck(
184
216
  input.checkId,
@@ -261,6 +293,9 @@ export async function waitForCheckProcess(
261
293
  processId: string,
262
294
  timeoutMs?: number,
263
295
  ): Promise<ProcessHandle> {
296
+ if (isLightweightProcessId(processId)) {
297
+ return waitForLightweightProcess(controllerHome, repoId, processId, { timeoutMs });
298
+ }
264
299
  return waitForProcess(controllerHome, repoId, processId, { timeoutMs });
265
300
  }
266
301
 
@@ -269,6 +304,9 @@ export function getCheckProcessHandle(
269
304
  repoId: string,
270
305
  processId: string,
271
306
  ): ProcessHandle | undefined {
307
+ if (isLightweightProcessId(processId)) {
308
+ return getLightweightProcessHandle(controllerHome, repoId, processId);
309
+ }
272
310
  return getProcessHandle(controllerHome, repoId, processId);
273
311
  }
274
312
 
@@ -2,6 +2,7 @@ import { createHash, randomUUID } from 'crypto';
2
2
  import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'fs';
3
3
  import { dirname, join } from 'path';
4
4
  import { processLogDir } from './store';
5
+ import type { ManagedProcessRecord } from './types';
5
6
 
6
7
  export interface PersistedCheckResultReceipt {
7
8
  schemaVersion: 1;
@@ -18,10 +19,18 @@ export interface PersistedCheckResultReceipt {
18
19
  cacheHit?: boolean;
19
20
  }
20
21
 
21
- export function allocatePersistedCheckResultReceiptPath(controllerHome: string, repoId: string): string {
22
+ export function allocatePersistedCheckResultReceiptPath(
23
+ controllerHome: string,
24
+ repoId: string,
25
+ requestId?: string,
26
+ ): string {
22
27
  const root = join(processLogDir(controllerHome, repoId), 'check-results');
23
28
  mkdirSync(root, { recursive: true });
24
- return join(root, `${randomUUID()}.json`);
29
+ const stableRequestId = requestId?.trim();
30
+ const receiptId = stableRequestId
31
+ ? `request-${createHash('sha256').update(stableRequestId).digest('hex').slice(0, 32)}`
32
+ : randomUUID();
33
+ return join(root, `${receiptId}.json`);
25
34
  }
26
35
 
27
36
  export function writePersistedCheckResultReceipt(path: string, input: Omit<PersistedCheckResultReceipt, 'schemaVersion' | 'receiptId'>): PersistedCheckResultReceipt {
@@ -43,3 +52,55 @@ export function readPersistedCheckResultReceipt(path: string | undefined): Persi
43
52
  return undefined;
44
53
  }
45
54
  }
55
+
56
+ export type PersistedCheckTerminalEvidenceState =
57
+ | 'matched'
58
+ | 'process_runtime_failed_before_result'
59
+ | 'missing'
60
+ | 'mismatch';
61
+
62
+ export interface PersistedCheckTerminalEvidence {
63
+ state: PersistedCheckTerminalEvidenceState;
64
+ failureClass?: PersistedCheckResultReceipt['failureClass'];
65
+ warning?: string;
66
+ infrastructureReason?: string;
67
+ }
68
+
69
+ /**
70
+ * Classify one terminal Check Process using the structured result emitted by
71
+ * the check-runner sidecar. A Process Runtime/admission failure can terminate
72
+ * before that result exists (for example PROCESS_LEASE_CONFLICT); such a
73
+ * Process is infrastructure failure, never evidence that repository checks
74
+ * rejected the candidate. Missing/mismatched result identity also fails closed
75
+ * as infrastructure rather than manufacturing acceptance evidence.
76
+ */
77
+ export function classifyPersistedCheckTerminalEvidence(
78
+ record: ManagedProcessRecord,
79
+ expectedCheckId: string,
80
+ ): PersistedCheckTerminalEvidence {
81
+ const structured = readPersistedCheckResultReceipt(record.origin?.checkResultReceiptPath);
82
+ const structuredMatches = Boolean(
83
+ structured
84
+ && record.checkExecution
85
+ && structured.checkId === expectedCheckId
86
+ && structured.cacheKey === record.checkExecution.cacheKey,
87
+ );
88
+ if (structuredMatches) {
89
+ return { state: 'matched', failureClass: structured?.failureClass };
90
+ }
91
+ if (!structured && record.error?.message?.trim()) {
92
+ const reason = record.error.message.trim().slice(0, 512);
93
+ return {
94
+ state: 'process_runtime_failed_before_result',
95
+ warning: `check process failed before structured result receipt: ${reason}`,
96
+ infrastructureReason: reason,
97
+ };
98
+ }
99
+ if (structured) {
100
+ return {
101
+ state: 'mismatch',
102
+ warning: 'check result receipt did not match the terminal Process semantic identity',
103
+ };
104
+ }
105
+ return { state: 'missing', warning: 'check result receipt is missing for the terminal Check Process' };
106
+ }
@@ -0,0 +1,114 @@
1
+ import type { ControllerCheck } from '../../../cli/controller/check-runner';
2
+ import type { ResourceClaimSpec } from '../jobs/types';
3
+ import { resourceClaimsConflict } from '../../resources/claims/conflicts';
4
+ import { claimsForCheck } from './resource-claims';
5
+
6
+ export interface CheckExecutionWave {
7
+ wave: number;
8
+ checkIds: string[];
9
+ parallelSafe: boolean;
10
+ }
11
+
12
+ export interface CheckExecutionConflict {
13
+ leftCheckId: string;
14
+ rightCheckId: string;
15
+ resources: Array<{
16
+ left: Pick<ResourceClaimSpec, 'resourceKey' | 'mode'>;
17
+ right: Pick<ResourceClaimSpec, 'resourceKey' | 'mode'>;
18
+ }>;
19
+ }
20
+
21
+ interface ScheduledCheck {
22
+ check: ControllerCheck;
23
+ claims: ResourceClaimSpec[];
24
+ }
25
+
26
+ function conflictingResources(left: ScheduledCheck, right: ScheduledCheck): CheckExecutionConflict['resources'] {
27
+ const conflicts: CheckExecutionConflict['resources'] = [];
28
+ for (const leftClaim of left.claims) {
29
+ for (const rightClaim of right.claims) {
30
+ if (!resourceClaimsConflict(leftClaim, rightClaim)) continue;
31
+ conflicts.push({
32
+ left: { resourceKey: leftClaim.resourceKey, mode: leftClaim.mode },
33
+ right: { resourceKey: rightClaim.resourceKey, mode: rightClaim.mode },
34
+ });
35
+ }
36
+ }
37
+ return conflicts;
38
+ }
39
+
40
+ /**
41
+ * Produce deterministic execution waves from the exact same resource-claim model
42
+ * used by Process Runtime. Checks in one wave may overlap; waves run in order.
43
+ * This is advisory scheduling metadata, not a second lease authority.
44
+ */
45
+ export function buildCheckExecutionSchedule(input: {
46
+ checks: ControllerCheck[];
47
+ requestedCheckIds: string[];
48
+ repoId: string;
49
+ checkoutId?: string;
50
+ }): {
51
+ waves: CheckExecutionWave[];
52
+ conflicts: CheckExecutionConflict[];
53
+ invalidCheckIds: string[];
54
+ maxParallel: number;
55
+ guidance: string[];
56
+ claimsByCheck: Array<{ checkId: string; claims: Array<Pick<ResourceClaimSpec, 'resourceKey' | 'mode'>> }>;
57
+ } {
58
+ const byId = new Map(input.checks.map((check) => [check.id, check]));
59
+ const requested = [...new Set(input.requestedCheckIds.filter(Boolean))];
60
+ const invalidCheckIds = requested.filter((checkId) => !byId.has(checkId));
61
+ const scheduled: ScheduledCheck[] = requested.flatMap((checkId) => {
62
+ const check = byId.get(checkId);
63
+ if (!check) return [];
64
+ return [{
65
+ check,
66
+ claims: claimsForCheck(check.id, check.command, input.repoId, input.checkoutId, check.effects),
67
+ }];
68
+ });
69
+
70
+ const conflicts: CheckExecutionConflict[] = [];
71
+ for (let leftIndex = 0; leftIndex < scheduled.length; leftIndex += 1) {
72
+ for (let rightIndex = leftIndex + 1; rightIndex < scheduled.length; rightIndex += 1) {
73
+ const left = scheduled[leftIndex]!;
74
+ const right = scheduled[rightIndex]!;
75
+ const resources = conflictingResources(left, right);
76
+ if (resources.length === 0) continue;
77
+ conflicts.push({ leftCheckId: left.check.id, rightCheckId: right.check.id, resources });
78
+ }
79
+ }
80
+
81
+ const waves: ScheduledCheck[][] = [];
82
+ for (const entry of scheduled) {
83
+ const compatible = waves.find((wave) => wave.every((other) => conflictingResources(entry, other).length === 0));
84
+ if (compatible) compatible.push(entry);
85
+ else waves.push([entry]);
86
+ }
87
+
88
+ const projectedWaves = waves.map((wave, index) => ({
89
+ wave: index + 1,
90
+ checkIds: wave.map((entry) => entry.check.id),
91
+ parallelSafe: wave.length > 1,
92
+ }));
93
+ const maxParallel = projectedWaves.reduce((max, wave) => Math.max(max, wave.checkIds.length), 0);
94
+ const guidance: string[] = [];
95
+ if (projectedWaves.length > 1) {
96
+ guidance.push('Run check waves in order; only checks within the same wave are resource-compatible for overlap.');
97
+ } else if (maxParallel > 1) {
98
+ guidance.push('Requested checks are resource-compatible and may run concurrently for this checkout.');
99
+ } else if (maxParallel === 1) {
100
+ guidance.push('Run the requested check as one focused verification unit.');
101
+ }
102
+
103
+ return {
104
+ waves: projectedWaves,
105
+ conflicts,
106
+ invalidCheckIds,
107
+ maxParallel,
108
+ guidance,
109
+ claimsByCheck: scheduled.map((entry) => ({
110
+ checkId: entry.check.id,
111
+ claims: entry.claims.map((claim) => ({ resourceKey: claim.resourceKey, mode: claim.mode })),
112
+ })),
113
+ };
114
+ }