@moretea-labs/forge 1.8.0 → 1.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (528) hide show
  1. package/AGENTS.md +70 -7
  2. package/CHANGELOG.md +14 -0
  3. package/CLAUDE.md +17 -2
  4. package/CONTRIBUTING.md +3 -2
  5. package/THIRD_PARTY_NOTICES.md +1 -1
  6. package/adapters/chatgpt/browser-delivery-host.ts +7 -1
  7. package/adapters/chatgpt/browser-delivery-runtime.ts +529 -56
  8. package/adapters/chatgpt/controller-binding-store.ts +101 -22
  9. package/adapters/chatgpt/controller-round-host.ts +15 -25
  10. package/adapters/chatgpt/controller-round-settlement-store.ts +58 -4
  11. package/adapters/chatgpt/provider-delivery.ts +228 -1
  12. package/adapters/chatgpt/work-conversation-binding-store.ts +79 -53
  13. package/adapters/computer/chatgpt-extension-target.ts +463 -0
  14. package/adapters/computer/chatgpt-target-router.ts +103 -0
  15. package/adapters/computer/chrome-extension/background.js +385 -0
  16. package/adapters/computer/chrome-extension/content.js +378 -0
  17. package/adapters/computer/chrome-extension/core.js +24 -0
  18. package/adapters/computer/chrome-extension/manifest.json +30 -0
  19. package/adapters/computer/desktop-operator-discovery.ts +11 -31
  20. package/adapters/computer/interaction-target-authority.ts +142 -18
  21. package/adapters/mcp/auth.ts +0 -1
  22. package/adapters/mcp/instructions.ts +5 -4
  23. package/adapters/mcp/multi-repository.ts +3 -19
  24. package/adapters/mcp/oauth.ts +73 -0
  25. package/adapters/mcp/paths.ts +4 -1
  26. package/adapters/mcp/runtime-gateway/automation-receipt-adapter.ts +87 -0
  27. package/adapters/mcp/runtime-gateway/bounded-result-runtime.ts +62 -0
  28. package/adapters/mcp/runtime-gateway/cognition-settlement.ts +201 -0
  29. package/adapters/mcp/runtime-gateway/context-adapter.ts +411 -73
  30. package/adapters/mcp/runtime-gateway/context-pack-sidecar.ts +91 -0
  31. package/adapters/mcp/runtime-gateway/controller-authority-adapter.ts +20 -5
  32. package/adapters/mcp/runtime-gateway/core-capability-adapter.ts +258 -0
  33. package/adapters/mcp/runtime-gateway/engineering-preconditions.ts +10 -27
  34. package/adapters/mcp/runtime-gateway/engineering-tool-contract.ts +15 -0
  35. package/adapters/mcp/runtime-gateway/execution-tools.ts +8 -42
  36. package/adapters/mcp/runtime-gateway/gateway-execution-adapter.ts +2 -1
  37. package/adapters/mcp/runtime-gateway/plugin-adapter.ts +117 -45
  38. package/adapters/mcp/runtime-gateway/process-tools.ts +190 -22
  39. package/adapters/mcp/runtime-gateway/protected-computer-adapter.ts +16 -4
  40. package/adapters/mcp/runtime-gateway/recovery-adapter.ts +69 -52
  41. package/adapters/mcp/runtime-gateway/repository-compat-adapter.ts +4 -35
  42. package/adapters/mcp/runtime-gateway/result-adapter.ts +10 -4
  43. package/adapters/mcp/runtime-gateway/router.ts +18 -504
  44. package/adapters/mcp/runtime-gateway/routing-policy.ts +499 -0
  45. package/adapters/mcp/runtime-gateway/runtime-observation-adapter.ts +14 -65
  46. package/adapters/mcp/runtime-gateway/runtime-readiness-observation.ts +218 -0
  47. package/adapters/mcp/runtime-gateway/runtime-tool-definitions.ts +113 -173
  48. package/adapters/mcp/runtime-gateway/runtime-tools.ts +15 -5
  49. package/adapters/mcp/runtime-gateway/scheduler-adapter.ts +1 -0
  50. package/adapters/mcp/runtime-gateway/shared-adapter.ts +20 -0
  51. package/adapters/mcp/runtime-gateway/status-inbox-adapter.ts +358 -266
  52. package/adapters/mcp/runtime-gateway/typescript-navigation-sidecar.ts +136 -0
  53. package/adapters/mcp/runtime-gateway/work-adapter.ts +261 -3122
  54. package/adapters/mcp/runtime-gateway/work-controller-operations.ts +257 -0
  55. package/adapters/mcp/runtime-gateway/work-detail-projection.ts +60 -0
  56. package/adapters/mcp/runtime-gateway/work-input-wire-migration.ts +246 -0
  57. package/adapters/mcp/runtime-gateway/work-learning-operations.ts +145 -0
  58. package/adapters/mcp/runtime-gateway/work-list-projection.ts +38 -0
  59. package/adapters/mcp/runtime-gateway/work-plan-operations.ts +382 -0
  60. package/adapters/mcp/runtime-gateway/work-repair-adapter.ts +308 -0
  61. package/adapters/mcp/runtime-gateway/work-requirement-operations.ts +148 -0
  62. package/adapters/mcp/runtime-gateway/work-semantic-operations.ts +263 -0
  63. package/adapters/mcp/runtime-gateway/work-workflow-operations.ts +113 -0
  64. package/adapters/mcp/runtime-gateway/workflow-supervisor-adapter.ts +156 -0
  65. package/adapters/mcp/server.ts +67 -23
  66. package/adapters/mcp/setup.ts +1 -3
  67. package/adapters/mcp/tool-mapping/legacy-tool-service.ts +44 -170
  68. package/adapters/mcp/tool-mapping/post-finalize-work-attribution.ts +4 -9
  69. package/adapters/mcp/tool-mapping/repository-tools.ts +133 -142
  70. package/adapters/mcp/toolset-names.ts +5 -0
  71. package/adapters/mcp/toolset.ts +6 -5
  72. package/adapters/mcp/transports/http-observation.ts +365 -0
  73. package/adapters/mcp/transports/http.ts +154 -677
  74. package/adapters/mcp/transports/oauth-http.ts +322 -0
  75. package/adapters/mcp/transports/session-registry.ts +6 -0
  76. package/adapters/mcp/tunnels/openai-secure-tunnel.ts +89 -5
  77. package/assets/plugin-registry.v1.json +6 -4
  78. package/assets/reference-configs/agentic-development-flow.md +25 -0
  79. package/assets/reference-configs/global-working-rules.md +19 -0
  80. package/assets/skill-version.json +2 -2
  81. package/docs/architecture/CURRENT.md +111 -41
  82. package/docs/architecture/decisions/20260803-release-identity-binding-and-exit-policy.md +14 -5
  83. package/docs/architecture/decisions/20260823-immediate-controller-relay.md +6 -3
  84. package/docs/architecture/decisions/20260907-assistant-learning-loop.md +2 -0
  85. package/docs/architecture/decisions/20260907-controller-round-transition-policy.md +19 -4
  86. package/docs/architecture/decisions/20260916-workflow-supervisor-authority.md +249 -0
  87. package/docs/architecture/decisions/20260917-cognitive-memory-foundation.md +82 -0
  88. package/docs/architecture/decisions/20260918-stable-candidate-release-lifecycle.md +221 -0
  89. package/docs/architecture/decisions/20260919-autonomous-work-liveness.md +62 -0
  90. package/docs/architecture/decisions/20260924-thin-semantic-working-context.md +72 -0
  91. package/docs/architecture/decisions/20261001-supervisor-turn-authority.md +237 -0
  92. package/docs/architecture/decisions/20261005-forge-v3-desktop-client-boundary.md +77 -0
  93. package/docs/architecture/domains/verification.md +1 -0
  94. package/docs/architecture/domains/workflow-engine.md +6 -0
  95. package/docs/architecture/modules/controller-runtime/transport-lifecycle.md +1 -1
  96. package/docs/forge-plugin-management.md +2 -2
  97. package/docs/operations/controller-performance-and-502.md +17 -0
  98. package/docs/operations/controller-reliability-runbook.md +2 -2
  99. package/docs/operations/features.md +1 -1
  100. package/docs/operations/features.zh-CN.md +1 -1
  101. package/docs/operations/homebrew.md +2 -2
  102. package/docs/operations/mcp-tool-exposure.md +2 -0
  103. package/docs/operations/releasing.md +2 -0
  104. package/docs/operations/standalone-disaster-recovery.md +14 -6
  105. package/docs/wiki/Implementation.md +1 -1
  106. package/package.json +25 -14
  107. package/packages/kernel/cognition/api/index.ts +6 -0
  108. package/packages/kernel/cognition/application/activation-service.ts +451 -0
  109. package/packages/kernel/cognition/application/consolidation-service.ts +185 -0
  110. package/packages/kernel/cognition/application/legacy-experience-adapter.ts +38 -0
  111. package/packages/kernel/cognition/application/memory-service.ts +64 -0
  112. package/packages/kernel/cognition/domain/learning.ts +106 -0
  113. package/packages/kernel/cognition/domain/memory.ts +254 -0
  114. package/packages/kernel/controller/api/index.ts +1 -0
  115. package/packages/kernel/controller/application/continuation-service.ts +281 -0
  116. package/packages/kernel/controller/application/controller-round-service.ts +12 -0
  117. package/packages/kernel/controller/domain/controller-round-transition-policy.ts +242 -21
  118. package/packages/kernel/controller/domain/controller-round.ts +4 -1
  119. package/packages/kernel/controller/domain/execution-quality.ts +3 -1
  120. package/packages/kernel/controller/infrastructure/controller-round-store.ts +689 -103
  121. package/packages/kernel/controller/infrastructure/controller-session-store.ts +297 -71
  122. package/packages/kernel/controller/ports/controller-host.ts +2 -0
  123. package/packages/kernel/identity/api/index.ts +10 -0
  124. package/packages/kernel/identity/domain/activity-projection.ts +43 -0
  125. package/packages/kernel/identity/domain/capability-broker.ts +60 -0
  126. package/packages/kernel/identity/domain/grant.ts +72 -0
  127. package/packages/kernel/identity/domain/owned-resource.ts +116 -0
  128. package/packages/kernel/identity/domain/user-request.ts +93 -0
  129. package/packages/kernel/identity/infrastructure/activity-projection-store.ts +77 -0
  130. package/packages/kernel/identity/infrastructure/capability-broker.ts +81 -0
  131. package/packages/kernel/identity/infrastructure/grant-store.ts +284 -0
  132. package/packages/kernel/identity/infrastructure/owned-resource-store.ts +259 -0
  133. package/packages/kernel/identity/infrastructure/user-request-store.ts +182 -0
  134. package/packages/kernel/scheduler/api/index.ts +0 -2
  135. package/packages/kernel/scheduler/application/schedule-service.ts +3 -0
  136. package/packages/kernel/scheduler/application/settlement.ts +0 -15
  137. package/packages/kernel/scheduler/domain/schedule.ts +87 -0
  138. package/packages/kernel/scheduler/infrastructure/schedule-store.ts +153 -133
  139. package/packages/kernel/work/api/index.ts +3 -2
  140. package/packages/kernel/work/application/work-service.ts +17 -42
  141. package/packages/kernel/work/domain/current-task-lineage.ts +104 -0
  142. package/packages/kernel/work/domain/engineering-design.ts +10 -5
  143. package/packages/kernel/work/domain/engineering-profile.ts +8 -12
  144. package/packages/kernel/work/domain/evaluation-promotion-receipt.ts +186 -0
  145. package/packages/kernel/work/domain/execution-concurrency.ts +19 -26
  146. package/packages/kernel/work/domain/execution-snapshot.ts +0 -31
  147. package/packages/kernel/work/domain/implementation-review.ts +14 -331
  148. package/packages/kernel/work/domain/objective-graph.ts +119 -0
  149. package/packages/kernel/work/domain/project-engineering-contract.ts +23 -1
  150. package/packages/kernel/work/domain/repository-completion-receipt.ts +1 -1
  151. package/packages/kernel/work/domain/state-machine.ts +25 -63
  152. package/packages/kernel/work/domain/types.ts +57 -51
  153. package/packages/kernel/work/infrastructure/work-contract-store.ts +819 -728
  154. package/packages/kernel/work/ports/work-contract-store.ts +5 -2
  155. package/packages/plugin-runtime/browser/session-authority.ts +2 -1
  156. package/packages/plugin-runtime/computer/chatgpt-identity.ts +24 -0
  157. package/packages/plugin-runtime/computer/conversation-target.ts +143 -0
  158. package/packages/plugin-runtime/computer/index.ts +2 -0
  159. package/packages/plugin-runtime/computer/target-authority.ts +26 -1
  160. package/packages/plugin-runtime/external/unix-jsonl-transport.ts +142 -18
  161. package/packages/protocols/computer/contract.ts +27 -1
  162. package/scripts/activate-source-baseline.ts +7 -9
  163. package/scripts/canary-controller-semantic-wait.ts +12 -24
  164. package/scripts/check-mcp-compatibility.ts +48 -136
  165. package/scripts/check-runtime-architecture.mjs +622 -217
  166. package/scripts/forge-local-recovery-helper.mjs +93 -15
  167. package/scripts/lib/project-init-lib.sh +3 -0
  168. package/scripts/open-source-audit-allowlist.txt +1 -2
  169. package/scripts/run-bounded-command.mjs +5 -0
  170. package/scripts/run-governed-gate.ts +0 -1
  171. package/scripts/run-mobile-monitor-bridge.ts +0 -1
  172. package/scripts/smoke-control-plane-failure-domain.ts +94 -0
  173. package/scripts/smoke-mcp-http-runtime.ts +5 -0
  174. package/scripts/smoke-runtime-recovery.ts +12 -43
  175. package/scripts/smoke-schedule-engine.ts +23 -15
  176. package/scripts/smoke-unattended-transport-recovery.ts +223 -0
  177. package/scripts/smoke-user-request-continuation-restart.ts +232 -0
  178. package/scripts/smoke-workflow-supervisor-chrome-adapter.ts +92 -0
  179. package/scripts/smoke-workflow-supervisor-process-restart.ts +276 -0
  180. package/scripts/smoke-workflow-supervisor-restart-recovery.ts +150 -0
  181. package/scripts/smoke-workflow-supervisor.ts +103 -0
  182. package/scripts/verify-forge-runtime.sh +2 -1
  183. package/src/cli/agent-jobs/executor-health.ts +11 -34
  184. package/src/cli/agent-jobs/integration.ts +18 -49
  185. package/src/cli/agent-jobs/job-manager.ts +7 -3
  186. package/src/cli/commands/brain-assistant.ts +27 -13
  187. package/src/cli/commands/brain.ts +13 -15
  188. package/src/cli/commands/chatgpt.ts +1 -163
  189. package/src/cli/commands/recovery.ts +135 -121
  190. package/src/cli/commands/runtime.ts +3 -3
  191. package/src/cli/commands/setup-profile.ts +8 -0
  192. package/src/cli/controller/check-runner.ts +13 -2
  193. package/src/cli/controller/completion-backlog.ts +3 -3
  194. package/src/cli/controller/completion-orchestrator.ts +4 -43
  195. package/src/cli/controller/completion-target.ts +3 -72
  196. package/src/cli/controller/context/source-materializer.ts +81 -100
  197. package/src/cli/controller/context-pack.ts +10 -8
  198. package/src/cli/controller/execution-completion.ts +4 -7
  199. package/src/cli/controller/execution-policy.ts +36 -153
  200. package/src/cli/controller/governance.ts +2 -3
  201. package/src/cli/controller/issue-store.ts +4 -99
  202. package/src/cli/controller/launch-agents.ts +59 -18
  203. package/src/cli/controller/operational-plan.ts +24 -51
  204. package/src/cli/controller/runtime-config.ts +5 -1
  205. package/src/cli/controller/stuck-state-migration.ts +2 -3
  206. package/src/cli/controller/systemd-user.ts +39 -1
  207. package/src/cli/editing/edit-session.ts +1 -7
  208. package/src/cli/local-bridge/console-automations.ts +18 -13
  209. package/src/cli/local-bridge/console-view-models.ts +3 -12
  210. package/src/cli/local-bridge/facade-api.ts +64 -191
  211. package/src/cli/local-bridge/server.ts +24 -147
  212. package/src/cli/local-bridge/types.ts +0 -1
  213. package/src/cli/mcp/oauth-client-retirement.ts +74 -0
  214. package/src/cli/repositories/command-executor.ts +29 -23
  215. package/src/cli/repositories/command-scope.ts +35 -16
  216. package/src/cli/repositories/controller-home.ts +48 -0
  217. package/src/cli/repositories/ephemeral-workspace.ts +20 -30
  218. package/src/cli/repositories/git-command-executor.ts +2 -2
  219. package/src/cli/repositories/registry.ts +77 -11
  220. package/src/cli/repositories/structured-git.ts +62 -2
  221. package/src/cli/repository/session-cache.ts +92 -6
  222. package/src/runtime/context/assistant-context.ts +20 -7
  223. package/src/runtime/context/assistant-work-context.ts +89 -27
  224. package/src/runtime/context/automatic-learning.ts +565 -0
  225. package/src/runtime/context/cognitive-attention.ts +173 -0
  226. package/src/runtime/context/cognitive-skill-canary.ts +158 -0
  227. package/src/runtime/context/context-closure.ts +46 -9
  228. package/src/runtime/context/context-pack-process.ts +103 -0
  229. package/src/runtime/context/context-plane.ts +1 -9
  230. package/src/runtime/context/direct-controller-learning.ts +298 -0
  231. package/src/runtime/context/semantic-navigation-contract.ts +9 -0
  232. package/src/runtime/context/semantic-navigation.ts +6 -34
  233. package/src/runtime/context/typescript-navigation-process.ts +145 -0
  234. package/src/runtime/context/typescript-navigation.ts +89 -3
  235. package/src/runtime/control-plane/cleanup-artifact-retention.ts +212 -9
  236. package/src/runtime/control-plane/concurrency/work-execution-concurrency.ts +9 -47
  237. package/src/runtime/control-plane/execution/controller-authority-recovery.ts +34 -4
  238. package/src/runtime/control-plane/execution/edit-validation-coordinator.ts +29 -20
  239. package/src/runtime/control-plane/execution/execution-identity.ts +23 -3
  240. package/src/runtime/control-plane/execution/repository-work-attribution.ts +7 -30
  241. package/src/runtime/control-plane/execution/retained-work-resume.ts +206 -199
  242. package/src/runtime/control-plane/execution/session-store.ts +31 -1
  243. package/src/runtime/control-plane/execution/validation.ts +6 -8
  244. package/src/runtime/control-plane/execution/work-authority-reconciler.ts +13 -42
  245. package/src/runtime/control-plane/execution/work-check-evidence.ts +137 -0
  246. package/src/runtime/control-plane/execution/work-completion-authority.ts +30 -85
  247. package/src/runtime/control-plane/execution/work-delivery-service.ts +497 -0
  248. package/src/runtime/control-plane/execution/work-evidence-policy.ts +12 -50
  249. package/src/runtime/control-plane/execution/work-execution-support.ts +50 -149
  250. package/src/runtime/control-plane/execution/work-handle-authority.ts +188 -109
  251. package/src/runtime/control-plane/execution/work-handle-store.ts +19 -43
  252. package/src/runtime/control-plane/execution/work-head-settlement.ts +53 -20
  253. package/src/runtime/control-plane/execution/work-lifecycle-audit.ts +52 -29
  254. package/src/runtime/control-plane/execution/work-operation-service.ts +43 -27
  255. package/src/runtime/control-plane/execution/work-preparation-service.ts +126 -266
  256. package/src/runtime/control-plane/execution/work-remote-delivery.ts +2 -3
  257. package/src/runtime/control-plane/execution/work-revision-diff.ts +39 -0
  258. package/src/runtime/control-plane/execution/work-terminal-cleanup.ts +173 -186
  259. package/src/runtime/control-plane/execution/work-validation-reconciler.ts +28 -84
  260. package/src/runtime/control-plane/execution/work-verification-service.ts +406 -50
  261. package/src/runtime/control-plane/execution/work-verification-snapshot.ts +5 -1
  262. package/src/runtime/control-plane/facade/capability-registry.ts +362 -37
  263. package/src/runtime/control-plane/facade/check-normalization.ts +3 -9
  264. package/src/runtime/control-plane/facade/codex-delegation.ts +10 -11
  265. package/src/runtime/control-plane/facade/controller-connection.ts +135 -0
  266. package/src/runtime/control-plane/facade/goal-workloop-access.ts +1 -20
  267. package/src/runtime/control-plane/facade/goal-workloop.ts +281 -1753
  268. package/src/runtime/control-plane/facade/handoff-inbox-application.ts +12 -25
  269. package/src/runtime/control-plane/facade/handoff-inbox-store.ts +256 -52
  270. package/src/runtime/control-plane/facade/index.ts +0 -1
  271. package/src/runtime/control-plane/facade/operation-digest.ts +12 -15
  272. package/src/runtime/control-plane/facade/plan-contract-store.ts +451 -991
  273. package/src/runtime/control-plane/facade/policy-gate.ts +0 -23
  274. package/src/runtime/control-plane/facade/repository-work-admission.ts +12 -22
  275. package/src/runtime/control-plane/facade/requirement-authority.ts +102 -199
  276. package/src/runtime/control-plane/facade/requirement-board.ts +3 -3
  277. package/src/runtime/control-plane/facade/rh-work-operation-contract.ts +51 -14
  278. package/src/runtime/control-plane/facade/self-healing-loop.ts +18 -53
  279. package/src/runtime/control-plane/facade/suggested-actions.ts +15 -18
  280. package/src/runtime/control-plane/facade/types.ts +49 -108
  281. package/src/runtime/control-plane/facade/work-continuation.ts +8 -8
  282. package/src/runtime/control-plane/generated-cache-retention.ts +97 -1
  283. package/src/runtime/control-plane/global-scheduler/autonomous-continuation.ts +248 -0
  284. package/src/runtime/control-plane/global-scheduler/durable-admission.ts +1 -1
  285. package/src/runtime/control-plane/global-scheduler/maintenance.ts +239 -112
  286. package/src/runtime/control-plane/global-scheduler/reconciliation.ts +2 -1
  287. package/src/runtime/control-plane/global-scheduler/scheduler.ts +66 -40
  288. package/src/runtime/control-plane/global-scheduler/wake-signal.ts +42 -2
  289. package/src/runtime/control-plane/governance/access-policy.ts +19 -2
  290. package/src/runtime/control-plane/governance/authorization.ts +20 -3
  291. package/src/runtime/control-plane/launcher/chatgpt-round-continuation.ts +63 -300
  292. package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +28 -300
  293. package/src/runtime/control-plane/launcher/local-conversation-controller.ts +238 -0
  294. package/src/runtime/control-plane/launcher/provider-mcp-bootstrap.ts +5 -2
  295. package/src/runtime/control-plane/launcher/thin-launcher.ts +96 -240
  296. package/src/runtime/control-plane/persistence/cognition-store.ts +820 -0
  297. package/src/runtime/control-plane/persistence/experience-store.ts +162 -29
  298. package/src/runtime/control-plane/persistence/requirement-store.ts +216 -74
  299. package/src/runtime/control-plane/persistence/sqlite-store.ts +113 -6
  300. package/src/runtime/control-plane/release-retention.ts +135 -47
  301. package/src/runtime/control-plane/repository-namespace-retention.ts +2 -2
  302. package/src/runtime/control-plane/runtime-cleanup.ts +290 -21
  303. package/src/runtime/control-plane/workspace/project-onboarding.ts +80 -0
  304. package/src/runtime/control-plane/workspace/semantic-sync-service.ts +19 -5
  305. package/src/runtime/control-plane/workspace/workspace-store.ts +169 -0
  306. package/src/runtime/diagnostics/incident-repair.ts +313 -146
  307. package/src/runtime/diagnostics/mcp-timing.ts +114 -0
  308. package/src/runtime/evidence/artifact-store.ts +158 -40
  309. package/src/runtime/evidence/evidence-store.ts +112 -8
  310. package/src/runtime/evidence/output-handle-index.ts +225 -0
  311. package/src/runtime/evidence/result-store.ts +158 -44
  312. package/src/runtime/execution/jobs/store.ts +3 -4
  313. package/src/runtime/execution/managed-workspace.ts +57 -0
  314. package/src/runtime/execution/process-runtime/check-facade.ts +1 -1
  315. package/src/runtime/execution/process-runtime/check-result-retention.ts +2 -2
  316. package/src/runtime/execution/process-runtime/check-result.ts +105 -1
  317. package/src/runtime/execution/process-runtime/check-runner-sidecar.ts +18 -8
  318. package/src/runtime/execution/process-runtime/command-facade.ts +79 -27
  319. package/src/runtime/execution/process-runtime/gc.ts +15 -2
  320. package/src/runtime/execution/process-runtime/handle-index.ts +176 -0
  321. package/src/runtime/execution/process-runtime/host-command-lane.ts +139 -0
  322. package/src/runtime/execution/process-runtime/index.ts +3 -0
  323. package/src/runtime/execution/process-runtime/lightweight-managed.ts +251 -72
  324. package/src/runtime/execution/process-runtime/persisted-check.ts +3 -3
  325. package/src/runtime/execution/process-runtime/process-runner-entry.ts +47 -5
  326. package/src/runtime/execution/process-runtime/process-scope.ts +160 -0
  327. package/src/runtime/execution/process-runtime/resource-claims.ts +65 -61
  328. package/src/runtime/execution/process-runtime/runtime.ts +35 -2
  329. package/src/runtime/execution/process-runtime/store.ts +30 -2
  330. package/src/runtime/execution/process-runtime/types.ts +6 -1
  331. package/src/runtime/execution/workers/executor.ts +2 -6
  332. package/src/runtime/platform/service-inventory.ts +130 -0
  333. package/src/runtime/platform/service-manager.ts +8 -0
  334. package/src/runtime/plugins/action-application.ts +85 -28
  335. package/src/runtime/plugins/app-store-connect-adapter.ts +38 -14
  336. package/src/runtime/plugins/browser-adapter.ts +757 -34
  337. package/src/runtime/plugins/browser-automation-service.ts +23 -3
  338. package/src/runtime/plugins/browser-macos-bridge.ts +321 -29
  339. package/src/runtime/plugins/browser-manifest-surface.ts +45 -11
  340. package/src/runtime/plugins/browser-native-session-service.ts +63 -13
  341. package/src/runtime/plugins/browser-registration.ts +16 -0
  342. package/src/runtime/plugins/browser-runtime.ts +14 -1
  343. package/src/runtime/plugins/browser-session-authority.ts +2 -2
  344. package/src/runtime/plugins/browser-session-store.ts +46 -76
  345. package/src/runtime/plugins/capability-authorization-grants.ts +258 -62
  346. package/src/runtime/plugins/computer-chatgpt-browser-adapter-installer.ts +219 -0
  347. package/src/runtime/plugins/computer-chatgpt-macos-target.ts +891 -0
  348. package/src/runtime/plugins/computer-registration.ts +222 -11
  349. package/src/runtime/plugins/desktop-operator-external-policy.ts +36 -4
  350. package/src/runtime/plugins/desktop-operator-registration.ts +12 -4
  351. package/src/runtime/plugins/external-adapter.ts +42 -6
  352. package/src/runtime/plugins/external-registration.ts +21 -1
  353. package/src/runtime/plugins/gmail-adapter.ts +23 -2
  354. package/src/runtime/plugins/google-calendar-adapter.ts +2 -2
  355. package/src/runtime/plugins/google-shared.ts +14 -7
  356. package/src/runtime/plugins/google-tasks-adapter.ts +2 -2
  357. package/src/runtime/plugins/ios-adapter.ts +1 -1
  358. package/src/runtime/plugins/lightweight-action.ts +208 -2
  359. package/src/runtime/plugins/local-system-adapter.ts +12 -2
  360. package/src/runtime/plugins/managed-process-adapter.ts +12 -5
  361. package/src/runtime/plugins/plugin-action-sidecar.ts +17 -13
  362. package/src/runtime/plugins/plugin-management-adapter.ts +1 -1
  363. package/src/runtime/plugins/store.ts +602 -428
  364. package/src/runtime/plugins/types.ts +20 -0
  365. package/src/runtime/plugins/xiaohongshu-publish.ts +16 -0
  366. package/src/runtime/projections/invalidation.ts +7 -3
  367. package/src/runtime/projections/materialized-view.ts +80 -36
  368. package/src/runtime/recovery/actions.ts +3 -3
  369. package/src/runtime/recovery/capability-action-application.ts +46 -45
  370. package/src/runtime/recovery/lifecycle-inventory.ts +29 -29
  371. package/src/runtime/recovery/maintenance-executor.ts +374 -123
  372. package/src/runtime/recovery/store.ts +29 -11
  373. package/src/runtime/release/release-coordinator.ts +296 -0
  374. package/src/runtime/release/release-session.ts +716 -0
  375. package/src/runtime/release/release-state-migration.ts +25 -0
  376. package/src/runtime/resources/leases/store.ts +56 -25
  377. package/src/runtime/root/computer-composition.ts +191 -6
  378. package/src/runtime/root/controller-progression-composition.ts +192 -0
  379. package/src/runtime/root/controller-round-composition.ts +20 -1
  380. package/src/runtime/root/deployment-topology.ts +106 -0
  381. package/src/runtime/root/entry.ts +4 -3
  382. package/src/runtime/root/known-good-recovery.ts +184 -0
  383. package/src/runtime/root/local-bridge.ts +0 -1
  384. package/src/runtime/root/mcp-transport.ts +111 -18
  385. package/src/runtime/root/ownership.ts +261 -9
  386. package/src/runtime/root/package-connector-service.ts +105 -19
  387. package/src/runtime/root/package-runtime-release.ts +117 -18
  388. package/src/runtime/root/package-runtime-service.ts +17 -11
  389. package/src/runtime/root/release-execution-canary.ts +44 -12
  390. package/src/runtime/root/release-loader.ts +90 -8
  391. package/src/runtime/root/release-manifest.ts +80 -6
  392. package/src/runtime/root/release-materialize.ts +372 -28
  393. package/src/runtime/root/release-store.ts +395 -36
  394. package/src/runtime/root/runtime-lane.ts +191 -0
  395. package/src/runtime/root/runtime.ts +159 -27
  396. package/src/runtime/root/scheduled-controller-composition.ts +28 -3
  397. package/src/runtime/root/service-runner.ts +2 -2
  398. package/src/runtime/root/service.ts +36 -33
  399. package/src/runtime/root/status.ts +48 -0
  400. package/src/runtime/root/types.ts +32 -3
  401. package/src/runtime/root/workflow-supervisor-composition.ts +493 -0
  402. package/src/runtime/root/workflow-supervisor-runtime.ts +209 -0
  403. package/src/runtime/root/write-fence.ts +50 -2
  404. package/src/runtime/safe-tooling/google-credential-store.ts +76 -21
  405. package/src/runtime/safe-tooling/google-oauth-broker.ts +25 -7
  406. package/src/runtime/safe-tooling/workspace-auth.ts +1 -1
  407. package/src/runtime/shared/bounded-child-supervisor.ts +9 -1
  408. package/src/runtime/shared/process-environment.ts +20 -9
  409. package/src/runtime/shared/response-budget.ts +1 -3
  410. package/src/runtime/standalone-recovery/controller-home-migration.ts +16 -24
  411. package/src/runtime/standalone-recovery/core.ts +3702 -342
  412. package/src/runtime/standalone-recovery/entry.ts +469 -39
  413. package/src/runtime/standalone-recovery/installer.ts +262 -148
  414. package/src/runtime/standalone-recovery/mcp-server.ts +29 -193
  415. package/src/runtime/standalone-recovery/operation-lock.ts +1 -1
  416. package/src/runtime/standalone-recovery/performance.ts +54 -16
  417. package/src/runtime/standalone-recovery/release.ts +53 -5
  418. package/src/runtime/standalone-recovery/service-labels.ts +5 -2
  419. package/src/runtime/standalone-recovery/watchdog-heartbeat.ts +5 -2
  420. package/src/runtime/workflow/schedules/browser-probe.ts +17 -6
  421. package/src/runtime/workflow/schedules/chatgpt-automation-migration.ts +10 -3
  422. package/src/runtime/workflow/schedules/engine.ts +138 -172
  423. package/src/runtime/workflow/schedules/work-continuation.ts +44 -5
  424. package/src/runtime/workflows/runtime.ts +15 -19
  425. package/src/testing/test-governance.ts +5 -1
  426. package/supervisor/chatgpt-conversation.ts +23 -0
  427. package/supervisor/client.ts +201 -0
  428. package/supervisor/control-plane.ts +868 -0
  429. package/supervisor/entry.ts +15 -0
  430. package/supervisor/forge-validators.ts +80 -0
  431. package/supervisor/index.ts +5 -0
  432. package/supervisor/native-browser-adapter.ts +786 -0
  433. package/supervisor/native-messaging/host.ts +39 -0
  434. package/supervisor/native-messaging/manifest.ts +26 -0
  435. package/supervisor/native-messaging/protocol.ts +27 -0
  436. package/supervisor/paths.ts +18 -0
  437. package/supervisor/protocol.ts +202 -0
  438. package/supervisor/server.ts +404 -0
  439. package/supervisor/store.ts +1451 -0
  440. package/supervisor/tsconfig.json +8 -0
  441. package/supervisor/types.ts +255 -0
  442. package/adapters/chatgpt/controller-host.ts +0 -119
  443. package/adapters/mcp/controller-round-compatibility.ts +0 -184
  444. package/adapters/mcp/frozen-client-semantic-compatibility.ts +0 -292
  445. package/adapters/mcp/runtime-gateway/work-compat-adapter.ts +0 -502
  446. package/packages/kernel/progression/api/index.ts +0 -2
  447. package/packages/kernel/progression/application/projector.ts +0 -211
  448. package/packages/kernel/progression/domain/types.ts +0 -116
  449. package/packages/kernel/progression/index.ts +0 -1
  450. package/packages/kernel/scheduler/application/continuation-service.ts +0 -212
  451. package/packages/kernel/scheduler/domain/continuation.ts +0 -38
  452. package/packages/kernel/scheduler/infrastructure/continuation-dispatch-store.ts +0 -38
  453. package/packages/kernel/work/domain/admission-policy.ts +0 -34
  454. package/scripts/benchmark-background-check-overlap.ts +0 -228
  455. package/scripts/benchmark-computer-hotpath.ts +0 -255
  456. package/scripts/benchmark-controller-hotpath.ts +0 -212
  457. package/scripts/benchmark-controller-round2.ts +0 -191
  458. package/scripts/benchmark-ios-agent-device.ts +0 -511
  459. package/scripts/benchmark-mcp-host.sh +0 -117
  460. package/scripts/benchmark-mcp-transport.ts +0 -169
  461. package/scripts/benchmark-operational-memory-activation.ts +0 -235
  462. package/scripts/benchmark-operational-shadow.ts +0 -28
  463. package/scripts/benchmark-quality-harness.ts +0 -146
  464. package/scripts/benchmark-route-session-concurrency.ts +0 -915
  465. package/scripts/benchmark-thin-harness-gateway-ab.ts +0 -632
  466. package/scripts/benchmark-thin-harness-mcp-e2e.ts +0 -498
  467. package/scripts/benchmark-thin-harness.ts +0 -251
  468. package/scripts/benchmark-typescript-navigation.ts +0 -186
  469. package/scripts/benchmark-work-efficiency.ts +0 -334
  470. package/scripts/build-controller-ui.ts +0 -28
  471. package/scripts/check-npm-release.sh +0 -32
  472. package/scripts/check-public-release-surface.sh +0 -19
  473. package/scripts/check-release-published.sh +0 -57
  474. package/scripts/check-release-readiness.sh +0 -37
  475. package/scripts/check-release-version.mjs +0 -74
  476. package/scripts/check-tarball-install-smoke.sh +0 -150
  477. package/scripts/package-source-archive.sh +0 -147
  478. package/scripts/public-release-files.txt +0 -39
  479. package/scripts/public-release.ts +0 -174
  480. package/scripts/publish-release-tarball.sh +0 -27
  481. package/scripts/route-nl-vs-ts-eval.ts +0 -679
  482. package/scripts/stage-runtime-release.ts +0 -44
  483. package/src/cli/controller/progress.ts +0 -656
  484. package/src/cli/controller/work-mode.ts +0 -181
  485. package/src/cli/local-bridge/console-assets.ts +0 -17
  486. package/src/cli/local-bridge/dashboard.ts +0 -17
  487. package/src/cli/local-bridge/frontend/src/App.tsx +0 -10
  488. package/src/cli/local-bridge/frontend/src/components/Button.tsx +0 -1
  489. package/src/cli/local-bridge/frontend/src/components/DetailPane.tsx +0 -3
  490. package/src/cli/local-bridge/frontend/src/components/SearchField.tsx +0 -1
  491. package/src/cli/local-bridge/frontend/src/components/SectionHeader.tsx +0 -1
  492. package/src/cli/local-bridge/frontend/src/components/Segmented.tsx +0 -1
  493. package/src/cli/local-bridge/frontend/src/components/StatusText.tsx +0 -3
  494. package/src/cli/local-bridge/frontend/src/design/icons.tsx +0 -11
  495. package/src/cli/local-bridge/frontend/src/design/tokens.css +0 -8
  496. package/src/cli/local-bridge/frontend/src/features/automations/AutomationsView.tsx +0 -153
  497. package/src/cli/local-bridge/frontend/src/features/capabilities/CapabilitiesView.tsx +0 -37
  498. package/src/cli/local-bridge/frontend/src/features/overview/OverviewView.tsx +0 -183
  499. package/src/cli/local-bridge/frontend/src/features/repositories/RepositoriesView.tsx +0 -2
  500. package/src/cli/local-bridge/frontend/src/features/system/SystemView.tsx +0 -2
  501. package/src/cli/local-bridge/frontend/src/features/work/WorkView.tsx +0 -4
  502. package/src/cli/local-bridge/frontend/src/lib/api.ts +0 -30
  503. package/src/cli/local-bridge/frontend/src/lib/format.ts +0 -4
  504. package/src/cli/local-bridge/frontend/src/lib/routes.ts +0 -7
  505. package/src/cli/local-bridge/frontend/src/main.tsx +0 -1
  506. package/src/cli/local-bridge/frontend/src/shell/AppShell.tsx +0 -1
  507. package/src/cli/local-bridge/frontend/src/shell/CommandBar.tsx +0 -2
  508. package/src/cli/local-bridge/frontend/src/shell/Sidebar.tsx +0 -4
  509. package/src/cli/local-bridge/frontend/src/styles.css +0 -28
  510. package/src/cli/local-bridge/frontend/src/types.ts +0 -15
  511. package/src/cli/local-bridge/frontend/src/vite-env.d.ts +0 -1
  512. package/src/cli/local-bridge/frontend/vite.config.ts +0 -27
  513. package/src/cli/local-bridge/ui-dist/app.css +0 -1
  514. package/src/cli/local-bridge/ui-dist/app.js +0 -11228
  515. package/src/runtime/control-plane/execution/content-equivalent-commit-authority.ts +0 -169
  516. package/src/runtime/control-plane/execution/direct-canonical-work-reconciliation.ts +0 -85
  517. package/src/runtime/control-plane/execution/direct-edit-work-completion.ts +0 -655
  518. package/src/runtime/control-plane/execution/work-finalization-service.ts +0 -2850
  519. package/src/runtime/control-plane/execution/work-path-scope.ts +0 -37
  520. package/src/runtime/control-plane/execution/work-task-receipt.ts +0 -468
  521. package/src/runtime/control-plane/facade/controller-round-relay.ts +0 -3
  522. package/src/runtime/control-plane/facade/work-admission-policy.ts +0 -142
  523. package/src/runtime/control-plane/facade/work-implementation-review.ts +0 -2
  524. package/src/runtime/control-plane/facade/work-state-machine.ts +0 -2
  525. package/src/runtime/control-plane/facade/work-task-projection.ts +0 -66
  526. package/src/runtime/control-plane/routing/index.ts +0 -1
  527. package/src/runtime/control-plane/routing/route-policy.ts +0 -401
  528. package/src/runtime/control-plane/routing/workspace-admission.ts +0 -70
@@ -269,7 +269,7 @@ export async function runPersistedCheckViaProcessRuntime(
269
269
  check,
270
270
  durable: {
271
271
  reason: 'multi_phase_or_release_check_requires_durable_workflow',
272
- suggestedOperation: 'Claim the related WorkContract and run this check through an external Controller.',
272
+ suggestedOperation: 'Run this check through a Work-bound durable verification workflow.',
273
273
  },
274
274
  durableSideEffects: emptyEffects,
275
275
  };
@@ -312,7 +312,7 @@ export async function runPersistedCheckViaProcessRuntime(
312
312
  const liveCertification = check.executionAuthority === 'live_controller_home';
313
313
  if (liveCertification && input.allowDurableCheckExecution !== true) {
314
314
  cleanupVerificationSnapshot();
315
- throw new Error('LIVE_CHECK_CONTROLLER_OWNERSHIP_REQUIRED');
315
+ throw new Error('LIVE_CHECK_DURABLE_AUTHORITY_REQUIRED');
316
316
  }
317
317
  const liveExecutionStateFingerprint = liveCertification
318
318
  ? controllerCheckLiveExecutionStateFingerprint(input.controllerHome)
@@ -422,7 +422,7 @@ export async function runPersistedCheckViaProcessRuntime(
422
422
  issueId: input.verificationBinding?.issueId,
423
423
  taskId: input.verificationBinding?.taskId,
424
424
  checkResultReceiptPath,
425
- workVerificationSnapshot: Boolean(verificationSnapshot),
425
+ ...(verificationSnapshot ? { workVerificationSnapshot: true } : {}),
426
426
  },
427
427
  signal: input.signal,
428
428
  });
@@ -33,9 +33,11 @@ import {
33
33
  rmSync,
34
34
  writeFileSync,
35
35
  } from 'fs';
36
- import { dirname, join } from 'path';
36
+ import { dirname, join, resolve } from 'path';
37
37
  import { spawn, type ChildProcess } from 'child_process';
38
38
  import { repositoryChildProcessEnvironment } from '../../shared/process-environment.ts';
39
+ import { currentRuntimeWriteClaimEnvironment } from '../../root/write-fence.ts';
40
+ import { readRuntimeReleaseAuthority } from '../../root/release-store.ts';
39
41
  import { StreamingSensitiveTextRedactor } from '../../evidence/sensitive-output.ts';
40
42
  import { PROCESS_RUNNER_RELEASE_CANARY_CHILD_ARG } from './canary.ts';
41
43
 
@@ -44,6 +46,7 @@ export interface ProcessCommandDescriptor {
44
46
  processId: string;
45
47
  repoId: string;
46
48
  controllerHome: string;
49
+ trustedRuntimeChild?: 'plugin_action_sidecar';
47
50
  command: {
48
51
  kind: 'argv' | 'shell';
49
52
  executable?: string;
@@ -101,9 +104,26 @@ function loadDescriptor(path: string): ProcessCommandDescriptor {
101
104
  return value;
102
105
  }
103
106
 
104
- function spawnCommand(command: ProcessCommandDescriptor['command']): ChildProcess {
107
+ function commandEnvironment(descriptor: ProcessCommandDescriptor): NodeJS.ProcessEnv {
108
+ const command = descriptor.command;
109
+ const sanitized = repositoryChildProcessEnvironment({ ...process.env, ...(command.env ?? {}) });
110
+ if (descriptor.trustedRuntimeChild !== 'plugin_action_sidecar') return sanitized;
111
+ if (command.kind !== 'argv' || !command.executable) {
112
+ throw new Error('PROCESS_RUNNER_TRUSTED_RUNTIME_CHILD_INVALID: plugin action sidecar requires argv executable');
113
+ }
114
+ const authority = readRuntimeReleaseAuthority(descriptor.controllerHome);
115
+ if (!authority) throw new Error('PROCESS_RUNNER_TRUSTED_RUNTIME_CHILD_INVALID: Runtime release authority is missing');
116
+ const expected = resolve(dirname(authority.active.manifestPath), 'forge-plugin-action-sidecar');
117
+ if (resolve(command.executable) !== expected) {
118
+ throw new Error(`PROCESS_RUNNER_TRUSTED_RUNTIME_CHILD_INVALID: expected ${expected}`);
119
+ }
120
+ return { ...sanitized, ...currentRuntimeWriteClaimEnvironment(descriptor.controllerHome) };
121
+ }
122
+
123
+ function spawnCommand(descriptor: ProcessCommandDescriptor): ChildProcess {
124
+ const command = descriptor.command;
105
125
  const useProcessGroup = process.platform !== 'win32';
106
- const env = repositoryChildProcessEnvironment({ ...process.env, ...(command.env ?? {}) });
126
+ const env = commandEnvironment(descriptor);
107
127
  if (command.kind === 'shell') {
108
128
  const shell = process.platform === 'win32' ? 'cmd.exe' : '/bin/bash';
109
129
  const shellArgs = process.platform === 'win32'
@@ -316,15 +336,37 @@ export async function runProcessRunnerFromDescriptor(
316
336
 
317
337
  let spawnedChild: ChildProcess;
318
338
  try {
319
- spawnedChild = spawnCommand(descriptor.command);
339
+ spawnedChild = spawnCommand(descriptor);
320
340
  child = spawnedChild;
321
341
  if (pendingSignal) void killTree(spawnedChild);
322
342
  } catch (error) {
323
343
  process.removeListener('SIGTERM', onSigterm);
324
344
  process.removeListener('SIGINT', onSigint);
345
+ const message = error instanceof Error ? error.message : String(error);
346
+ stderr.write(Buffer.from(`\n[process-runner] pre-spawn error: ${message}\n`));
325
347
  stdout.close();
326
348
  stderr.close();
327
- throw error;
349
+ const outStats = stdout.stats();
350
+ const errStats = stderr.stats();
351
+ const receipt: ProcessRunnerExitReceipt = {
352
+ schemaVersion: 1,
353
+ processId: descriptor.processId,
354
+ exitCode: 1,
355
+ finishedAt: new Date().toISOString(),
356
+ startedAt: descriptor.startedAt,
357
+ stdoutBytes: outStats.totalBytes,
358
+ stderrBytes: errStats.totalBytes,
359
+ stdoutStoredBytes: outStats.storedBytes,
360
+ stderrStoredBytes: errStats.storedBytes,
361
+ logTruncated: outStats.truncated || errStats.truncated,
362
+ runnerPid: process.pid,
363
+ // The exactly-once logical Process attempt reached a deterministic terminal
364
+ // result before an external child could be spawned; the started claim is
365
+ // therefore consumed and must never authorize replay.
366
+ commandExecutedOnce: true,
367
+ };
368
+ atomicWrite(descriptor.exitReceiptPath, receipt);
369
+ return receipt;
328
370
  }
329
371
 
330
372
  const timeoutHandle = setTimeout(() => {
@@ -0,0 +1,160 @@
1
+ /**
2
+ * Canonical Process/Operation storage scope.
3
+ *
4
+ * Repository placement is optional context for a process, never its address
5
+ * space. A process whose target is the Forge instance itself (host-local
6
+ * command, controller-global operation, ephemeral workspace command) is stored
7
+ * in the instance partition and is addressed by its process handle only.
8
+ *
9
+ * Scope keys are stable partition identifiers:
10
+ * - repository scope key is the registered repository id (unchanged on disk)
11
+ * - instance scope key is `instance`, which cannot collide with a registered
12
+ * repository id (`repo_*`) or workspace id (`workspace_*`)
13
+ */
14
+
15
+ import { join } from 'path';
16
+ import {
17
+ isWorkspaceScopeKey,
18
+ repositoryControllerRoot,
19
+ workspaceScopeRoot,
20
+ } from '../../../cli/repositories/controller-home';
21
+ import {
22
+ forgeInstanceExecutionTarget,
23
+ repositoryExecutionTarget,
24
+ resolveProcessExecutionTarget,
25
+ workspaceExecutionTarget,
26
+ type ProcessExecutionTarget,
27
+ } from './handle-index';
28
+
29
+ export const FORGE_INSTANCE_PROCESS_SCOPE_KEY = 'instance';
30
+ /** Reserved prefix for workspace process scopes; registered repository ids are `repo_*`. */
31
+ export { WORKSPACE_SCOPE_PREFIX as WORKSPACE_PROCESS_SCOPE_PREFIX } from '../../../cli/repositories/controller-home';
32
+
33
+ export interface RepositoryProcessScope {
34
+ schemaVersion: 1;
35
+ kind: 'repository';
36
+ repositoryId: string;
37
+ checkoutId?: string;
38
+ }
39
+
40
+ export interface ForgeInstanceProcessScope {
41
+ schemaVersion: 1;
42
+ kind: 'forge_instance';
43
+ forgeInstanceId?: string;
44
+ }
45
+
46
+ /**
47
+ * An arbitrary workspace target has no repository semantics, so its processes
48
+ * live in a workspace partition instead of a repository partition.
49
+ */
50
+ export interface WorkspaceProcessScope {
51
+ schemaVersion: 1;
52
+ kind: 'workspace';
53
+ workspaceId: string;
54
+ }
55
+
56
+ export type ProcessScope = RepositoryProcessScope | ForgeInstanceProcessScope | WorkspaceProcessScope;
57
+
58
+ function requireSegment(value: string, code: string): string {
59
+ const normalized = value.trim();
60
+ if (!normalized || normalized.length > 512) throw new Error(code);
61
+ return normalized;
62
+ }
63
+
64
+ export function repositoryProcessScope(repositoryId: string, checkoutId?: string): RepositoryProcessScope {
65
+ const repository = requireSegment(repositoryId, 'PROCESS_SCOPE_REPOSITORY_ID_REQUIRED');
66
+ if (repository === FORGE_INSTANCE_PROCESS_SCOPE_KEY) throw new Error('PROCESS_SCOPE_REPOSITORY_ID_RESERVED');
67
+ if (isWorkspaceScopeKey(repository)) throw new Error('PROCESS_SCOPE_REPOSITORY_ID_RESERVED');
68
+ const checkout = checkoutId?.trim();
69
+ return { schemaVersion: 1, kind: 'repository', repositoryId: repository, ...(checkout ? { checkoutId: checkout } : {}) };
70
+ }
71
+
72
+ export function forgeInstanceProcessScope(forgeInstanceId?: string): ForgeInstanceProcessScope {
73
+ const instanceId = forgeInstanceId?.trim();
74
+ return { schemaVersion: 1, kind: 'forge_instance', ...(instanceId ? { forgeInstanceId: instanceId } : {}) };
75
+ }
76
+
77
+ export function workspaceProcessScope(workspaceId: string): WorkspaceProcessScope {
78
+ return { schemaVersion: 1, kind: 'workspace', workspaceId: requireSegment(workspaceId, 'PROCESS_SCOPE_WORKSPACE_ID_REQUIRED') };
79
+ }
80
+
81
+ /** Stable storage/attachment partition key for one process scope. */
82
+ export function processScopeKey(scope: ProcessScope): string {
83
+ if (scope.kind === 'forge_instance') return FORGE_INSTANCE_PROCESS_SCOPE_KEY;
84
+ if (scope.kind === 'workspace') return requireSegment(scope.workspaceId, 'PROCESS_SCOPE_WORKSPACE_ID_REQUIRED');
85
+ if (isWorkspaceScopeKey(scope.repositoryId)) throw new Error('PROCESS_SCOPE_REPOSITORY_ID_RESERVED');
86
+ return requireSegment(scope.repositoryId, 'PROCESS_SCOPE_REPOSITORY_ID_REQUIRED');
87
+ }
88
+
89
+ /**
90
+ * Normalize a scope key supplied by a caller. A bare repository id keeps its
91
+ * established meaning as the repository scope key; `instance` selects the
92
+ * ForgeInstance partition.
93
+ */
94
+ export function normalizeProcessScopeKey(value: string): string {
95
+ const key = requireSegment(value, 'PROCESS_SCOPE_KEY_REQUIRED');
96
+ return key;
97
+ }
98
+
99
+ export function processScopeFromKey(key: string): ProcessScope {
100
+ const normalized = normalizeProcessScopeKey(key);
101
+ if (normalized === FORGE_INSTANCE_PROCESS_SCOPE_KEY) return forgeInstanceProcessScope();
102
+ if (isWorkspaceScopeKey(normalized)) return workspaceProcessScope(normalized);
103
+ return repositoryProcessScope(normalized);
104
+ }
105
+
106
+ export function isForgeInstanceProcessScopeKey(key: string): boolean {
107
+ return key.trim() === FORGE_INSTANCE_PROCESS_SCOPE_KEY;
108
+ }
109
+
110
+ /** An arbitrary workspace target is addressed by its workspace id, never by a repository id. */
111
+ export function isWorkspaceProcessScopeKey(key: string): boolean {
112
+ return isWorkspaceScopeKey(key);
113
+ }
114
+
115
+ /** True when the scope key addresses a registered repository partition. */
116
+ export function isRepositoryProcessScopeKey(key: string): boolean {
117
+ const normalized = key.trim();
118
+ return normalized.length > 0
119
+ && normalized !== FORGE_INSTANCE_PROCESS_SCOPE_KEY
120
+ && !isWorkspaceProcessScopeKey(normalized);
121
+ }
122
+
123
+ /**
124
+ * Controller-Home root for one process scope. Repository scopes keep their
125
+ * existing per-repository layout; instance and workspace scopes own ordinary
126
+ * sibling partitions so non-repository processes never require a synthetic
127
+ * repository identity.
128
+ */
129
+ export function processScopeRoot(controllerHome: string, scopeKey: string): string {
130
+ const key = normalizeProcessScopeKey(scopeKey);
131
+ if (isForgeInstanceProcessScopeKey(key)) return join(controllerHome, FORGE_INSTANCE_PROCESS_SCOPE_KEY);
132
+ if (isWorkspaceProcessScopeKey(key)) return workspaceScopeRoot(controllerHome, key);
133
+ return repositoryControllerRoot(controllerHome, key);
134
+ }
135
+
136
+ /** Read-only legacy location for workspace-scoped facts written before the workspace partition existed. */
137
+ export function legacyWorkspaceScopeRoot(controllerHome: string, scopeKey: string): string | undefined {
138
+ const key = normalizeProcessScopeKey(scopeKey);
139
+ return isWorkspaceProcessScopeKey(key) ? repositoryControllerRoot(controllerHome, key) : undefined;
140
+ }
141
+
142
+ /** Handle-index target for one scope, pinned to the serving ForgeInstance when available. */
143
+ export function processScopeExecutionTarget(controllerHome: string, scope: ProcessScope): ProcessExecutionTarget {
144
+ if (scope.kind === 'repository') return repositoryExecutionTarget(controllerHome, scope.repositoryId, scope.checkoutId);
145
+ if (scope.kind === 'workspace') return workspaceExecutionTarget(controllerHome, scope.workspaceId);
146
+ return forgeInstanceExecutionTarget(controllerHome);
147
+ }
148
+
149
+ /**
150
+ * Scope key recorded for one process handle. The Process Runtime owns this
151
+ * instance-level index, so attachment resolves the target from the handle
152
+ * instead of scanning repositories or replaying placement inputs.
153
+ */
154
+ export function processScopeKeyForHandle(controllerHome: string, processId: string): string | undefined {
155
+ const target = resolveProcessExecutionTarget(controllerHome, processId);
156
+ if (!target) return undefined;
157
+ if (target.scope === 'forge_instance') return FORGE_INSTANCE_PROCESS_SCOPE_KEY;
158
+ if (target.scope === 'workspace') return target.workspaceId;
159
+ return target.repositoryId;
160
+ }
@@ -35,8 +35,12 @@ export type ResourceClaimKind =
35
35
  | 'heavy_check'
36
36
  | 'workspace_write';
37
37
 
38
- function checkoutScope(checkoutId?: string): string {
39
- return checkoutId?.trim() || 'active';
38
+ function checkoutScope(checkoutId?: string, repoId?: string): string {
39
+ const checkout = checkoutId?.trim();
40
+ if (checkout) return checkout;
41
+ const repository = repoId?.trim();
42
+ if (repository) return `repository-${repository.replace(/[^a-zA-Z0-9._-]+/g, '-')}`;
43
+ throw new Error('RESOURCE_CLAIM_PLACEMENT_REQUIRED');
40
44
  }
41
45
 
42
46
  /**
@@ -44,24 +48,24 @@ function checkoutScope(checkoutId?: string): string {
44
48
  * Conflict is expressed via mode (read vs write), not a separate key.
45
49
  * Legacy workspace-read:* keys are normalized in claims/conflicts.ts.
46
50
  */
47
- export function claimWorkspaceRead(checkoutId?: string): ResourceClaimSpec {
48
- return { resourceKey: `workspace:${checkoutScope(checkoutId)}`, mode: 'read' };
51
+ export function claimWorkspaceRead(checkoutId?: string, repoId?: string): ResourceClaimSpec {
52
+ return { resourceKey: `workspace:${checkoutScope(checkoutId, repoId)}`, mode: 'read' };
49
53
  }
50
54
 
51
- export function claimPathRead(path: string, checkoutId?: string): ResourceClaimSpec {
52
- if (path === '.') return claimWorkspaceRead(checkoutId);
55
+ export function claimPathRead(path: string, checkoutId?: string, repoId?: string): ResourceClaimSpec {
56
+ if (path === '.') return claimWorkspaceRead(checkoutId, repoId);
53
57
  const normalized = normalizeClaimPath(path);
54
- if (!normalized) return claimWorkspaceRead(checkoutId);
55
- return { resourceKey: `path:${checkoutScope(checkoutId)}:${normalized}`, mode: 'read' };
58
+ if (!normalized) return claimWorkspaceRead(checkoutId, repoId);
59
+ return { resourceKey: `path:${checkoutScope(checkoutId, repoId)}:${normalized}`, mode: 'read' };
56
60
  }
57
61
 
58
- export function claimPathWrite(path: string, checkoutId?: string): ResourceClaimSpec {
62
+ export function claimPathWrite(path: string, checkoutId?: string, repoId?: string): ResourceClaimSpec {
59
63
  const normalized = normalizeClaimPath(path);
60
64
  if (!normalized) {
61
65
  // Unsafe / ambiguous path → escalate to whole-checkout workspace write.
62
- return claimWorkspaceWrite(checkoutId);
66
+ return claimWorkspaceWrite(checkoutId, repoId);
63
67
  }
64
- return { resourceKey: `path:${checkoutScope(checkoutId)}:${normalized}`, mode: 'write' };
68
+ return { resourceKey: `path:${checkoutScope(checkoutId, repoId)}:${normalized}`, mode: 'write' };
65
69
  }
66
70
 
67
71
  export function claimBuildCacheRead(repoId: string): ResourceClaimSpec {
@@ -72,12 +76,12 @@ export function claimBuildCacheWrite(repoId: string): ResourceClaimSpec {
72
76
  return { resourceKey: `build-cache:${repoId}`, mode: 'write' };
73
77
  }
74
78
 
75
- export function claimGitIndexRead(checkoutId?: string): ResourceClaimSpec {
76
- return { resourceKey: `git-index:${checkoutScope(checkoutId)}`, mode: 'read' };
79
+ export function claimGitIndexRead(checkoutId?: string, repoId?: string): ResourceClaimSpec {
80
+ return { resourceKey: `git-index:${checkoutScope(checkoutId, repoId)}`, mode: 'read' };
77
81
  }
78
82
 
79
- export function claimGitIndex(checkoutId?: string): ResourceClaimSpec {
80
- return { resourceKey: `git-index:${checkoutScope(checkoutId)}`, mode: 'exclusive' };
83
+ export function claimGitIndex(checkoutId?: string, repoId?: string): ResourceClaimSpec {
84
+ return { resourceKey: `git-index:${checkoutScope(checkoutId, repoId)}`, mode: 'exclusive' };
81
85
  }
82
86
 
83
87
  export function claimGitRefsRead(repoId: string): ResourceClaimSpec {
@@ -92,16 +96,12 @@ export function claimIntegration(repoId: string): ResourceClaimSpec {
92
96
  return { resourceKey: `integration:${repoId}`, mode: 'exclusive' };
93
97
  }
94
98
 
95
- export function claimRelease(repoId: string): ResourceClaimSpec {
96
- return { resourceKey: `release:${repoId}`, mode: 'exclusive' };
99
+ export function claimRelease(_repoId: string): ResourceClaimSpec {
100
+ return { resourceKey: 'release:runtime-authority', mode: 'exclusive' };
97
101
  }
98
102
 
99
- export function claimRemoteMutation(repoId: string): ResourceClaimSpec {
100
- return { resourceKey: `remote:${repoId}`, mode: 'exclusive' };
101
- }
102
-
103
- export function claimWorkspaceWrite(checkoutId?: string): ResourceClaimSpec {
104
- return { resourceKey: `workspace:${checkoutScope(checkoutId)}`, mode: 'write' };
103
+ export function claimWorkspaceWrite(checkoutId?: string, repoId?: string): ResourceClaimSpec {
104
+ return { resourceKey: `workspace:${checkoutScope(checkoutId, repoId)}`, mode: 'write' };
105
105
  }
106
106
 
107
107
  export function claimHeavyCheck(repoId: string): ResourceClaimSpec {
@@ -158,7 +158,7 @@ function iosSimulatorTestCommandClaims(
158
158
  }
159
159
  if (!matches) return undefined;
160
160
  return normalizeClaims([
161
- claimWorkspaceRead(checkoutId),
161
+ claimWorkspaceRead(checkoutId, repoId),
162
162
  claimBuildCacheWrite(repoId),
163
163
  claimHostService('ios-simulator-test', 'write'),
164
164
  ]);
@@ -182,7 +182,7 @@ function localHttpServerClaims(command: string | readonly string[]): ResourceCla
182
182
  return [claimHostService(`tcp-listen:${bind}:${port}`, 'write')];
183
183
  }
184
184
 
185
- function loopbackCurlClaims(command: string | readonly string[], repoId: string): ResourceClaimSpec[] | undefined {
185
+ function loopbackCurlClaims(command: string | readonly string[], _repoId: string): ResourceClaimSpec[] | undefined {
186
186
  const canonical = normalizeRepositoryCommand(command);
187
187
  if (canonical.kind !== 'argv') return undefined;
188
188
  const program = (canonical.executable ?? '').split(/[\\/]/).at(-1)?.toLowerCase();
@@ -198,7 +198,7 @@ function loopbackCurlClaims(command: string | readonly string[], repoId: string)
198
198
  return !['127.0.0.1', 'localhost', '::1'].includes(host);
199
199
  } catch { return true; }
200
200
  })) return undefined;
201
- return [claimNetwork(repoId, 'read')];
201
+ return [claimHostService('tcp-client:loopback', 'read')];
202
202
  }
203
203
 
204
204
  function simpleViteScript(script: string): boolean {
@@ -236,7 +236,7 @@ function viteServiceClaims(
236
236
  if (!vite) return undefined;
237
237
  return normalizeClaims([
238
238
  claimBuildCacheWrite(repoId),
239
- claimHostService(`vite:${checkoutScope(checkoutId)}`, 'write'),
239
+ claimHostService(`vite:${checkoutScope(checkoutId, repoId)}`, 'write'),
240
240
  ]);
241
241
  }
242
242
 
@@ -331,13 +331,10 @@ function hostOnlyCommandClaims(command: string | readonly string[], repoId: stri
331
331
  return undefined;
332
332
  }
333
333
 
334
- function claimTemp(checkId: string, repoId: string, scope: 'isolated' | 'shared'): ResourceClaimSpec {
334
+ function claimTemp(checkId: string, repoId: string, scope: 'isolated' | 'shared', checkoutId?: string): ResourceClaimSpec {
335
335
  const identity = checkId.replace(/[^a-zA-Z0-9._-]+/g, '-');
336
- return { resourceKey: scope === 'shared' ? `temp:${repoId}` : `temp:${repoId}:${identity}`, mode: 'write' };
337
- }
338
-
339
- function claimNetwork(repoId: string, mode: 'read' | 'write'): ResourceClaimSpec {
340
- return { resourceKey: `network:${repoId}`, mode };
336
+ const placement = checkoutScope(checkoutId, repoId);
337
+ return { resourceKey: scope === 'shared' ? `temp:${placement}:shared` : `temp:${placement}:${identity}`, mode: 'write' };
341
338
  }
342
339
 
343
340
  function staticAnalysisCheckId(checkId: string): boolean {
@@ -356,22 +353,23 @@ function claimsForDeclaredCheckEffects(
356
353
  ): ResourceClaimSpec[] {
357
354
  const claims: ResourceClaimSpec[] = [];
358
355
  const hasDeclaredField = Object.keys(effects).length > 0;
359
- if (!hasDeclaredField) return [claimWorkspaceWrite(checkoutId)];
356
+ if (!hasDeclaredField) return [claimWorkspaceWrite(checkoutId, repoId)];
360
357
 
361
358
  // Missing read scope is unknown, so custom checks fail closed. An explicit
362
359
  // reads: [] means the command does not inspect repository content.
363
- if (effects.reads === undefined) claims.push(claimWorkspaceWrite(checkoutId));
364
- else for (const path of effects.reads) claims.push(claimPathRead(path, checkoutId));
365
- for (const path of effects.writes ?? []) claims.push(claimPathWrite(path, checkoutId));
360
+ if (effects.reads === undefined) claims.push(claimWorkspaceWrite(checkoutId, repoId));
361
+ else for (const path of effects.reads) claims.push(claimPathRead(path, checkoutId, repoId));
362
+ for (const path of effects.writes ?? []) claims.push(claimPathWrite(path, checkoutId, repoId));
366
363
 
367
364
  if (effects.cache === 'read') claims.push(claimBuildCacheRead(repoId));
368
365
  if (effects.cache === 'write') claims.push(claimBuildCacheWrite(repoId));
369
- if (effects.temp) claims.push(claimTemp(checkId, repoId, effects.temp));
370
- if (effects.git === 'read') claims.push(claimGitIndexRead(checkoutId), claimGitRefsRead(repoId));
371
- if (effects.git === 'index') claims.push(claimGitIndex(checkoutId));
366
+ if (effects.temp) claims.push(claimTemp(checkId, repoId, effects.temp, checkoutId));
367
+ if (effects.git === 'read') claims.push(claimGitIndexRead(checkoutId, repoId), claimGitRefsRead(repoId));
368
+ if (effects.git === 'index') claims.push(claimGitIndex(checkoutId, repoId));
372
369
  if (effects.git === 'refs') claims.push(claimGitRefs(repoId));
373
- if (effects.git === 'write') claims.push(claimWorkspaceWrite(checkoutId), claimGitIndex(checkoutId), claimGitRefs(repoId));
374
- if (effects.network) claims.push(claimNetwork(repoId, effects.network));
370
+ if (effects.git === 'write') claims.push(claimWorkspaceWrite(checkoutId, repoId), claimGitIndex(checkoutId, repoId), claimGitRefs(repoId));
371
+ // A generic network bit has no concrete endpoint/provider identity. Checks
372
+ // that need serialization must name the real shared target in hostServices.
375
373
  for (const service of effects.hostServices ?? []) claims.push(claimHostService(service, 'write'));
376
374
 
377
375
  return normalizeClaims(claims, { readOnly: claims.every((claim) => claim.mode === 'read') });
@@ -495,15 +493,18 @@ export function claimsForRepositoryCommand(
495
493
  if (hostClaims) return hostClaims;
496
494
 
497
495
  if (classification.risk === 'readonly') {
498
- return [claimWorkspaceRead(checkoutId)];
496
+ return [claimWorkspaceRead(checkoutId, repoId)];
499
497
  }
500
498
  if (classification.risk === 'remote_write') {
501
- return [claimRemoteMutation(repoId), claimGitRefs(repoId)];
499
+ // Raw command text cannot prove the external provider/account target. Keep
500
+ // the concrete local Git-ref fence; typed domain APIs own remote-effect
501
+ // identity, idempotency and provider-target serialization.
502
+ return [claimGitRefs(repoId)];
502
503
  }
503
504
  if (classification.risk === 'destructive') {
504
505
  return [
505
- claimWorkspaceWrite(checkoutId),
506
- claimGitIndex(checkoutId),
506
+ claimWorkspaceWrite(checkoutId, repoId),
507
+ claimGitIndex(checkoutId, repoId),
507
508
  claimGitRefs(repoId),
508
509
  ];
509
510
  }
@@ -512,22 +513,22 @@ export function claimsForRepositoryCommand(
512
513
  // while ordinary focused tests are observation unless snapshot-update mode is
513
514
  // explicit. Both can share repository source reads without a workspace writer.
514
515
  if (isTypedTypeScriptNoEmit(command)) {
515
- return [claimWorkspaceRead(checkoutId), claimBuildCacheWrite(repoId)];
516
+ return [claimWorkspaceRead(checkoutId, repoId), claimBuildCacheWrite(repoId)];
516
517
  }
517
518
  if (focused) {
518
- if (!focusedTestRequestsWorkspaceMutation(command)) return [claimWorkspaceRead(checkoutId)];
519
- const claims: ResourceClaimSpec[] = [claimWorkspaceRead(checkoutId)];
520
- for (const path of extractLikelyPaths(command).slice(0, 16)) claims.push(claimPathWrite(path, checkoutId));
519
+ if (!focusedTestRequestsWorkspaceMutation(command)) return [claimWorkspaceRead(checkoutId, repoId)];
520
+ const claims: ResourceClaimSpec[] = [claimWorkspaceRead(checkoutId, repoId)];
521
+ for (const path of extractLikelyPaths(command).slice(0, 16)) claims.push(claimPathWrite(path, checkoutId, repoId));
521
522
  return normalizeClaims(claims);
522
523
  }
523
524
  if (looksLikeBuildOrTest(command)) {
524
525
  const paths = extractLikelyPaths(command);
525
526
  if (paths.length === 0) {
526
527
  // Broad or opaque build/test commands may create arbitrary artifacts.
527
- return [claimWorkspaceWrite(checkoutId), claimBuildCacheWrite(repoId)];
528
+ return [claimWorkspaceWrite(checkoutId, repoId), claimBuildCacheWrite(repoId)];
528
529
  }
529
- const claims: ResourceClaimSpec[] = [claimWorkspaceRead(checkoutId), claimBuildCacheWrite(repoId)];
530
- for (const path of paths.slice(0, 16)) claims.push(claimPathWrite(path, checkoutId));
530
+ const claims: ResourceClaimSpec[] = [claimWorkspaceRead(checkoutId, repoId), claimBuildCacheWrite(repoId)];
531
+ for (const path of paths.slice(0, 16)) claims.push(claimPathWrite(path, checkoutId, repoId));
531
532
  return normalizeClaims(claims);
532
533
  }
533
534
 
@@ -537,23 +538,26 @@ export function claimsForRepositoryCommand(
537
538
  const sub = canonical.kind === 'argv' ? canonical.args?.[0]?.toLowerCase() : undefined;
538
539
  if (program === 'git') {
539
540
  if (sub === 'add' || sub === 'rm' || sub === 'mv' || sub === 'restore' || sub === 'apply') {
540
- return [claimGitIndex(checkoutId), claimWorkspaceWrite(checkoutId)];
541
+ return [claimGitIndex(checkoutId, repoId), claimWorkspaceWrite(checkoutId, repoId)];
541
542
  }
542
543
  if (sub === 'commit' || sub === 'merge' || sub === 'rebase' || sub === 'cherry-pick' || sub === 'revert') {
543
- return [claimGitIndex(checkoutId), claimGitRefs(repoId), claimWorkspaceWrite(checkoutId)];
544
+ return [claimGitIndex(checkoutId, repoId), claimGitRefs(repoId), claimWorkspaceWrite(checkoutId, repoId)];
544
545
  }
545
546
  if (sub === 'checkout' || sub === 'switch' || sub === 'branch' || sub === 'tag') {
546
- return [claimGitRefs(repoId), claimWorkspaceWrite(checkoutId)];
547
+ return [claimGitRefs(repoId), claimWorkspaceWrite(checkoutId, repoId)];
547
548
  }
548
549
  }
549
550
 
550
551
  // Unknown mutating command — workspace write, not heavy-check exclusive.
551
- return [claimWorkspaceWrite(checkoutId)];
552
+ return [claimWorkspaceWrite(checkoutId, repoId)];
552
553
  }
553
554
 
554
555
  /**
555
556
  * Claims for run_check by check id / command.
556
- * Only full CI / release / multi-phase checks take heavy-check exclusive.
557
+ * Full CI/release/multi-phase checks and compiler-intensive latency gates take
558
+ * heavy-check exclusive. The latter fence protects performance assertions from
559
+ * same-repository CPU/JSC contention; it does not replace their real read/cache
560
+ * claims.
557
561
  */
558
562
  export function claimsForCheck(
559
563
  checkId: string,
@@ -563,15 +567,15 @@ export function claimsForCheck(
563
567
  effects?: ControllerCheckEffects,
564
568
  executionAuthority?: ControllerCheckExecutionAuthority,
565
569
  ): ResourceClaimSpec[] {
566
- const heavy = /(?:^|:)(?:test(?::coverage)?|check:(?:ci|forge-runtime|public-export|release(?:-[a-z0-9-]+)?))$/.test(checkId)
570
+ const heavy = /(?:^|:)(?:test(?::coverage)?|check:(?:ci|forge-runtime|public-export|release(?:-[a-z0-9-]+)?|type|typescript-navigation))$/.test(checkId)
567
571
  || /release|migration|integrate/i.test(checkId);
568
572
  const baseClaims = effects
569
573
  ? claimsForDeclaredCheckEffects(checkId, effects, repoId, checkoutId)
570
574
  : staticAnalysisCheckId(checkId)
571
- ? [claimWorkspaceRead(checkoutId), claimBuildCacheWrite(repoId)]
575
+ ? [claimWorkspaceRead(checkoutId, repoId), claimBuildCacheWrite(repoId)]
572
576
  : command && command.length > 0
573
577
  ? claimsForRepositoryCommand(command, repoId, checkoutId)
574
- : [claimWorkspaceWrite(checkoutId)];
578
+ : [claimWorkspaceWrite(checkoutId, repoId)];
575
579
  // Heavy-check is an additional cross-check serialization fence, not a
576
580
  // substitute for the resources the check actually reads or writes.
577
581
  const liveAuthorityClaims = executionAuthority === 'live_controller_home' ? [claimRelease(repoId)] : [];
@@ -31,6 +31,8 @@ import { dirname, join } from 'path';
31
31
  import { fileURLToPath } from 'url';
32
32
  import { capProcessOutput } from '../../../effects/process-runner';
33
33
  import { getRepository, selectRepositoryCheckout } from '../../../cli/repositories/registry';
34
+ import { recordProcessHandleIndexEntry } from './handle-index';
35
+ import { processScopeExecutionTarget, processScopeFromKey } from './process-scope';
34
36
  import { redactSensitiveText, sanitizeSensitiveTextFileInPlace } from '../../evidence/sensitive-output';
35
37
  import { isProcessAlive, terminateProcessTree } from '../../shared/process-tree';
36
38
  import { repositoryChildProcessEnvironment, resolveBunExecutable } from '../../shared/process-environment';
@@ -1224,6 +1226,7 @@ export async function spawnManagedProcess(input: SpawnManagedProcessInput): Prom
1224
1226
  processId,
1225
1227
  repoId: input.repoId,
1226
1228
  checkoutId: input.checkoutId,
1229
+ ...(input.principalId ? { principalId: input.principalId } : {}),
1227
1230
  workId: input.workId,
1228
1231
  executionIdentity: input.executionIdentity,
1229
1232
  commandId: input.commandId?.trim() || processId,
@@ -1253,6 +1256,16 @@ export async function spawnManagedProcess(input: SpawnManagedProcessInput): Prom
1253
1256
  logPath: stdoutPath,
1254
1257
  };
1255
1258
  createProcessRecord(record);
1259
+ // Instance-level locator so attachment resolves the target from the handle
1260
+ // instead of replaying placement inputs or scanning repository partitions.
1261
+ recordProcessHandleIndexEntry(input.controllerHome, {
1262
+ processId,
1263
+ lane: 'managed',
1264
+ target: processScopeExecutionTarget(input.controllerHome, processScopeFromKey(input.repoId)),
1265
+ principalId: input.principalId,
1266
+ workId: input.workId,
1267
+ commandId: record.commandId,
1268
+ });
1256
1269
 
1257
1270
  if (input.signal?.aborted) {
1258
1271
  completeProcessFromEvidence(input.controllerHome, input.repoId, processId, fenceToken, {
@@ -1489,6 +1502,7 @@ export async function spawnManagedProcess(input: SpawnManagedProcessInput): Prom
1489
1502
  repoId: input.repoId,
1490
1503
  controllerHome: input.controllerHome,
1491
1504
  command,
1505
+ ...(input.trustedRuntimeChild ? { trustedRuntimeChild: input.trustedRuntimeChild } : {}),
1492
1506
  timeoutMs,
1493
1507
  maxStdoutBytes: maxOutputBytes,
1494
1508
  maxStderrBytes: maxOutputBytes,
@@ -1627,6 +1641,18 @@ function applyReceiptIfPresent(
1627
1641
  }, { authority: 'durable_exit_receipt' });
1628
1642
  }
1629
1643
 
1644
+
1645
+ function reconcileObservedTerminalProcess(
1646
+ controllerHome: string,
1647
+ repoId: string,
1648
+ record: ManagedProcessRecord,
1649
+ ): ManagedProcessRecord {
1650
+ if (record.terminalWritten !== true) return record;
1651
+ const reconciled = releaseProcessLeasesOnce(controllerHome, repoId, record.processId) ?? record;
1652
+ cleanupTerminalRunnerReceipts(reconciled);
1653
+ return reconciled;
1654
+ }
1655
+
1630
1656
  export function getProcessHandle(
1631
1657
  controllerHome: string,
1632
1658
  repoId: string,
@@ -1634,6 +1660,9 @@ export function getProcessHandle(
1634
1660
  ): ProcessHandle | undefined {
1635
1661
  const record = getProcessRecord(controllerHome, repoId, processId);
1636
1662
  if (!record) return undefined;
1663
+ if (record.terminalWritten === true) {
1664
+ return recordToHandle(reconcileObservedTerminalProcess(controllerHome, repoId, record), { completed: true });
1665
+ }
1637
1666
  if (isManagedProcessActive(record) && !liveMonitors.has(processId)) {
1638
1667
  const fromReceipt = applyReceiptIfPresent(controllerHome, repoId, processId, record);
1639
1668
  if (fromReceipt) return recordToHandle(fromReceipt, { completed: true });
@@ -1656,7 +1685,9 @@ export async function waitForProcess(
1656
1685
  ): Promise<ProcessHandle> {
1657
1686
  const existing = getProcessRecord(controllerHome, repoId, processId);
1658
1687
  if (!existing) throw new Error(`PROCESS_NOT_FOUND: ${processId}`);
1659
- if (existing.terminalWritten) return recordToHandle(existing, { completed: true });
1688
+ if (existing.terminalWritten) {
1689
+ return recordToHandle(reconcileObservedTerminalProcess(controllerHome, repoId, existing), { completed: true });
1690
+ }
1660
1691
 
1661
1692
  const monitor = liveMonitors.get(processId);
1662
1693
  if (monitor) {
@@ -1744,7 +1775,9 @@ export async function cancelProcess(
1744
1775
  ): Promise<ProcessHandle> {
1745
1776
  const record = getProcessRecord(controllerHome, repoId, processId);
1746
1777
  if (!record) throw new Error(`PROCESS_NOT_FOUND: ${processId}`);
1747
- if (record.terminalWritten) return recordToHandle(record, { completed: true });
1778
+ if (record.terminalWritten) {
1779
+ return recordToHandle(reconcileObservedTerminalProcess(controllerHome, repoId, record), { completed: true });
1780
+ }
1748
1781
 
1749
1782
  // Process control is itself a writer mutation. Fence BEFORE sending any
1750
1783
  // signal so a passive/stale runtime cannot kill the active runtime's work.