@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
@@ -8,7 +8,7 @@ import {
8
8
  rmSync,
9
9
  type Dirent,
10
10
  } from 'fs';
11
- import { join, relative, resolve } from 'path';
11
+ import { basename, dirname, join, relative, resolve } from 'path';
12
12
  import { ensureControllerHome } from '../../cli/repositories/controller-home';
13
13
  import { cleanupTerminalEditSessionRecords } from '../../cli/editing/edit-session';
14
14
  import { listRepositories } from '../../cli/repositories/registry';
@@ -17,7 +17,8 @@ import { migrateManagedWorkspacePhysicalDependenciesToCanonical } from '../execu
17
17
  import { cleanupStaleCodegraphLocators } from '../context/codegraph-cache-boundary';
18
18
  import { listActiveLeases } from '../resources/leases/store';
19
19
  import { cleanupScheduleOccurrenceHistory } from '../../../packages/kernel/scheduler/api/index';
20
- import { isTerminalWorkContractStatus, readWorkContractStore } from '../../../packages/kernel/work/api/index';
20
+ import { isTerminalSemanticWorkState, readWorkContractStore } from '../../../packages/kernel/work/api/index';
21
+ import { assertOwnedResourceCleanupTarget, listOwnedResources, markOwnedResourceCleaned, type OwnedResource } from '../../../packages/kernel/identity/api/index';
21
22
  import { appendJsonLine, readJsonFile, writeJsonAtomic } from '../shared/json-files';
22
23
  import { cleanupControllerReleaseHistory } from './release-retention';
23
24
  import { cleanupWorkPreservationArtifacts } from './cleanup-artifact-retention';
@@ -25,12 +26,17 @@ import { cleanupCodegraphCaches, CODEGRAPH_CACHE_RETENTION_POLICY_VERSION } from
25
26
  import { cleanupRetiredRepositoryNamespaces } from './repository-namespace-retention';
26
27
  import { maintainControlPlaneDatabase, type ControlPlaneDatabaseMaintenanceReport } from './persistence/sqlite-store';
27
28
  import { cleanupExpiredExperiences } from './persistence/experience-store';
28
- import { retireTerminalPlanBoundWorkAuthorities } from './facade/plan-contract-store';
29
29
  import { reconcileOwnerlessWorkAuthorities } from './execution/work-authority-reconciler';
30
30
  import {
31
31
  measureReclaimablePath,
32
32
  RUNTIME_LIFECYCLE_RETENTION_POLICY_VERSION,
33
33
  } from './lifecycle-retention-metrics';
34
+ import {
35
+ listReleaseSessions,
36
+ releaseSessionCandidateIsRetired,
37
+ } from '../release/release-session';
38
+ import { removeRetiredCandidateExecutionLane } from '../root/runtime-lane';
39
+ import { observeRuntimeStatus } from '../root/status';
34
40
 
35
41
  function numericSetting(value: string | undefined, fallback: number, minimum: number): number {
36
42
  const parsed = Number(value);
@@ -193,6 +199,35 @@ export interface RuntimeCleanupLifecycleMetrics {
193
199
  blockerReasons: Record<string, number>;
194
200
  }
195
201
 
202
+ export interface ReleaseSessionCandidatePhaseMetrics {
203
+ observedCount: number;
204
+ observedBytes: number;
205
+ unknownObservedByteCount: number;
206
+ retainedCount: number;
207
+ reclaimableCount: number;
208
+ removedCount: number;
209
+ reclaimedBytes: number;
210
+ unknownReclaimedByteCount: number;
211
+ }
212
+
213
+ export interface ReleaseSessionCandidateRetentionReport {
214
+ inspected: number;
215
+ observedCount: number;
216
+ observedBytes: number;
217
+ unknownObservedByteCount: number;
218
+ retainedCount: number;
219
+ eligible: number;
220
+ attempted: number;
221
+ removedPaths: string[];
222
+ reclaimedBytes: number;
223
+ unknownReclaimedByteCount: number;
224
+ orphanDirectoryCount: number;
225
+ invalidSessionFiles: string[];
226
+ byPhase: Record<string, ReleaseSessionCandidatePhaseMetrics>;
227
+ errors: string[];
228
+ truncated: boolean;
229
+ }
230
+
196
231
  export interface RuntimeCleanupReport {
197
232
  policyVersion: typeof RUNTIME_LIFECYCLE_RETENTION_POLICY_VERSION;
198
233
  at: string;
@@ -204,6 +239,7 @@ export interface RuntimeCleanupReport {
204
239
  removedTemporaryPaths: string[];
205
240
  removedCleanupArtifactPaths: string[];
206
241
  removedReleasePaths: string[];
242
+ releaseSessionCandidates: ReleaseSessionCandidateRetentionReport;
207
243
  removedScheduleOccurrencePaths: string[];
208
244
  removedScheduleDecisionPaths: string[];
209
245
  removedEditSessionPaths: string[];
@@ -212,8 +248,6 @@ export interface RuntimeCleanupReport {
212
248
  removedRepositoryNamespacePaths: string[];
213
249
  /** Physical SQLite checkpoint/compaction receipt; row lifecycle remains domain-owned. */
214
250
  sqliteMaintenance?: ControlPlaneDatabaseMaintenanceReport;
215
- /** Historical non-terminal Work whose owning Plan was already terminal. Records remain for retention/audit. */
216
- retiredPlanBoundWorkAuthorities: string[];
217
251
  /** Work retired only after exact per-Work liveness proved no durable continuation owner remains. */
218
252
  retiredOwnerlessWorkAuthorities: string[];
219
253
  skippedActiveWorktrees: string[];
@@ -456,6 +490,203 @@ function createScanBudget(maxEntries: number): ScanBudget {
456
490
  };
457
491
  }
458
492
 
493
+ function emptyReleaseSessionCandidatePhaseMetrics(): ReleaseSessionCandidatePhaseMetrics {
494
+ return {
495
+ observedCount: 0,
496
+ observedBytes: 0,
497
+ unknownObservedByteCount: 0,
498
+ retainedCount: 0,
499
+ reclaimableCount: 0,
500
+ removedCount: 0,
501
+ reclaimedBytes: 0,
502
+ unknownReclaimedByteCount: 0,
503
+ };
504
+ }
505
+
506
+ function emptyReleaseSessionCandidateRetentionReport(): ReleaseSessionCandidateRetentionReport {
507
+ return {
508
+ inspected: 0,
509
+ observedCount: 0,
510
+ observedBytes: 0,
511
+ unknownObservedByteCount: 0,
512
+ retainedCount: 0,
513
+ eligible: 0,
514
+ attempted: 0,
515
+ removedPaths: [],
516
+ reclaimedBytes: 0,
517
+ unknownReclaimedByteCount: 0,
518
+ orphanDirectoryCount: 0,
519
+ invalidSessionFiles: [],
520
+ byPhase: {},
521
+ errors: [],
522
+ truncated: false,
523
+ };
524
+ }
525
+
526
+ function candidatePhaseMetrics(
527
+ report: ReleaseSessionCandidateRetentionReport,
528
+ phase: string,
529
+ ): ReleaseSessionCandidatePhaseMetrics {
530
+ return report.byPhase[phase] ??= emptyReleaseSessionCandidatePhaseMetrics();
531
+ }
532
+
533
+ /**
534
+ * Physical retention only. ReleaseSession phase transitions and Candidate
535
+ * service retirement remain owned by standalone Recovery under its operation
536
+ * lock. Maintenance consumes durable phase evidence and the live Runtime owner
537
+ * projection, then applies the existing path-fenced Candidate removal.
538
+ */
539
+ function cleanupReleaseSessionCandidateLanes(
540
+ controllerHome: string,
541
+ input: {
542
+ maxEntries: number;
543
+ sequence: number;
544
+ removalBudget: RemovalBudget;
545
+ skippedByReason: Record<string, number>;
546
+ },
547
+ ): ReleaseSessionCandidateRetentionReport {
548
+ const report = emptyReleaseSessionCandidateRetentionReport();
549
+ const candidateRoot = resolve(dirname(controllerHome), 'candidate-runtime-lanes');
550
+ const inventory = listReleaseSessions(controllerHome, { maxEntries: input.maxEntries });
551
+ report.invalidSessionFiles = [...inventory.invalidSessionFiles].sort();
552
+ report.inspected += inventory.inspected;
553
+ report.truncated = inventory.truncated;
554
+ if (inventory.truncated) {
555
+ input.skippedByReason.release_session_candidate_inventory_truncated =
556
+ (input.skippedByReason.release_session_candidate_inventory_truncated ?? 0) + 1;
557
+ }
558
+ if (inventory.invalidSessionFiles.length > 0) {
559
+ input.skippedByReason.release_session_candidate_authority_invalid =
560
+ (input.skippedByReason.release_session_candidate_authority_invalid ?? 0) + inventory.invalidSessionFiles.length;
561
+ report.errors.push(...inventory.invalidSessionFiles.map((name) => `invalid ReleaseSession authority: ${name}`));
562
+ }
563
+
564
+ const measurementBudget = createScanBudget(input.maxEntries);
565
+ const knownCandidateHomes = new Set<string>();
566
+ const sessions = [...inventory.sessions].sort((left, right) => left.updatedAt.localeCompare(right.updatedAt));
567
+ if (sessions.length > 1) {
568
+ const offset = ((Math.trunc(input.sequence) % sessions.length) + sessions.length) % sessions.length;
569
+ sessions.push(...sessions.splice(0, offset));
570
+ }
571
+
572
+ for (const session of sessions) {
573
+ const candidateHome = resolve(session.candidate.controllerHome);
574
+ if (resolve(dirname(candidateHome)) !== candidateRoot || basename(candidateHome) !== session.sessionId) {
575
+ input.skippedByReason.release_session_candidate_path_invalid =
576
+ (input.skippedByReason.release_session_candidate_path_invalid ?? 0) + 1;
577
+ report.errors.push(`${session.sessionId}: RUNTIME_CANDIDATE_CLEANUP_PATH_INVALID`);
578
+ continue;
579
+ }
580
+ knownCandidateHomes.add(candidateHome);
581
+ if (!existsSync(candidateHome)) continue;
582
+
583
+ const phase = candidatePhaseMetrics(report, session.phase);
584
+ report.observedCount += 1;
585
+ phase.observedCount += 1;
586
+
587
+ let measuredBytes: number | undefined;
588
+ let measurementComplete = false;
589
+ if (measurementBudget.remaining > 0) {
590
+ const measurement = measureReclaimablePath(candidateHome, Math.min(256, measurementBudget.remaining));
591
+ measurementBudget.remaining = Math.max(0, measurementBudget.remaining - measurement.entries);
592
+ measurementBudget.inspected += measurement.entries;
593
+ measuredBytes = measurement.bytes;
594
+ measurementComplete = measurement.complete;
595
+ }
596
+ if (measurementComplete && measuredBytes !== undefined) {
597
+ report.observedBytes += measuredBytes;
598
+ phase.observedBytes += measuredBytes;
599
+ } else {
600
+ report.unknownObservedByteCount += 1;
601
+ phase.unknownObservedByteCount += 1;
602
+ }
603
+
604
+ if (!releaseSessionCandidateIsRetired(session)) {
605
+ report.retainedCount += 1;
606
+ phase.retainedCount += 1;
607
+ input.skippedByReason.release_session_candidate_resumable =
608
+ (input.skippedByReason.release_session_candidate_resumable ?? 0) + 1;
609
+ continue;
610
+ }
611
+
612
+ report.eligible += 1;
613
+ phase.reclaimableCount += 1;
614
+ try {
615
+ if (observeRuntimeStatus(candidateHome).running) {
616
+ report.retainedCount += 1;
617
+ phase.retainedCount += 1;
618
+ input.skippedByReason.release_session_candidate_active_owner =
619
+ (input.skippedByReason.release_session_candidate_active_owner ?? 0) + 1;
620
+ continue;
621
+ }
622
+ } catch (error) {
623
+ report.retainedCount += 1;
624
+ phase.retainedCount += 1;
625
+ report.errors.push(errorText(`${session.sessionId} Candidate Runtime observation`, error));
626
+ input.skippedByReason.release_session_candidate_owner_unknown =
627
+ (input.skippedByReason.release_session_candidate_owner_unknown ?? 0) + 1;
628
+ continue;
629
+ }
630
+
631
+ if (input.removalBudget.remaining <= 0) {
632
+ input.removalBudget.exhausted = true;
633
+ report.retainedCount += 1;
634
+ phase.retainedCount += 1;
635
+ input.skippedByReason.release_session_candidate_cleanup_budget_exhausted =
636
+ (input.skippedByReason.release_session_candidate_cleanup_budget_exhausted ?? 0) + 1;
637
+ continue;
638
+ }
639
+
640
+ report.attempted += 1;
641
+ input.removalBudget.remaining -= 1;
642
+ try {
643
+ removeRetiredCandidateExecutionLane(session.stable, session.candidate);
644
+ const relativePath = `candidate-runtime-lanes/${session.sessionId}`;
645
+ report.removedPaths.push(relativePath);
646
+ phase.removedCount += 1;
647
+ if (measurementComplete && measuredBytes !== undefined) {
648
+ report.reclaimedBytes += measuredBytes;
649
+ phase.reclaimedBytes += measuredBytes;
650
+ } else {
651
+ report.unknownReclaimedByteCount += 1;
652
+ phase.unknownReclaimedByteCount += 1;
653
+ }
654
+ } catch (error) {
655
+ report.retainedCount += 1;
656
+ phase.retainedCount += 1;
657
+ report.errors.push(errorText(`${session.sessionId} Candidate lane removal`, error));
658
+ }
659
+ }
660
+
661
+ // A directory without readable ReleaseSession authority is visible debt, not
662
+ // deletion authority. Keep it and report it so Recovery can reconcile it.
663
+ if (!inventory.truncated && existsSync(candidateRoot)) {
664
+ const rootBudget = createScanBudget(input.maxEntries);
665
+ visitDirectoryEntries(candidateRoot, rootBudget, report.errors, (entry) => {
666
+ if (!entry.isDirectory()) return;
667
+ const path = resolve(candidateRoot, entry.name);
668
+ if (knownCandidateHomes.has(path)) return;
669
+ report.observedCount += 1;
670
+ report.retainedCount += 1;
671
+ report.orphanDirectoryCount += 1;
672
+ report.unknownObservedByteCount += 1;
673
+ const phase = candidatePhaseMetrics(report, 'authority_missing');
674
+ phase.observedCount += 1;
675
+ phase.retainedCount += 1;
676
+ phase.unknownObservedByteCount += 1;
677
+ input.skippedByReason.release_session_candidate_authority_missing =
678
+ (input.skippedByReason.release_session_candidate_authority_missing ?? 0) + 1;
679
+ });
680
+ report.inspected += rootBudget.inspected;
681
+ if (rootBudget.exhausted) report.truncated = true;
682
+ }
683
+
684
+ report.inspected += measurementBudget.inspected;
685
+ report.removedPaths.sort();
686
+ report.errors.sort();
687
+ return report;
688
+ }
689
+
459
690
  function shouldProtectWorktreeReference(meta: AgentRunSnapshot, nowMs: number): boolean {
460
691
  if (meta.executionMode !== 'worktree' || meta.worktreeCleanedAt) return false;
461
692
  const status = typeof meta.status === 'string' ? meta.status.trim().toLowerCase() : '';
@@ -609,6 +840,11 @@ function cleanupOrphanWorktrees(
609
840
  const reclaim = emptyReclaimMetrics();
610
841
  const skippedByReason: Record<string, number> = {};
611
842
  const skip = (reason: string): void => { skippedByReason[reason] = (skippedByReason[reason] ?? 0) + 1; };
843
+ const ownedWorktreesByPath = new Map<string, OwnedResource>();
844
+ for (const resource of listOwnedResources(controllerHome, { kind: 'worktree', status: 'active' })) {
845
+ if (resource.cleanupCapable !== true || !resource.targetRef?.trim()) continue;
846
+ ownedWorktreesByPath.set(canonicalPath(resource.targetRef), resource);
847
+ }
612
848
  const repositoriesRoot = join(controllerHome, 'repositories');
613
849
  visitDirectoryEntries(repositoriesRoot, budget, errors, (repoEntry) => {
614
850
  if (!repoEntry.isDirectory()) return;
@@ -624,7 +860,25 @@ function cleanupOrphanWorktrees(
624
860
  skip(references.referenced.has(canonical) ? 'active_owner' : 'unknown_ownership');
625
861
  return;
626
862
  }
863
+ const ownedResource = ownedWorktreesByPath.get(canonical);
864
+ if (!ownedResource) {
865
+ skippedActive.push(relativePath);
866
+ skip('owned_resource_missing');
867
+ return;
868
+ }
627
869
  try {
870
+ try {
871
+ assertOwnedResourceCleanupTarget(controllerHome, {
872
+ resourceId: ownedResource.resourceId,
873
+ kind: 'worktree',
874
+ targetRef: path,
875
+ });
876
+ } catch (error) {
877
+ skippedActive.push(relativePath);
878
+ skip('owned_resource_identity_mismatch');
879
+ errors.push(errorText(`owned worktree cleanup fence ${relativePath}`, error));
880
+ return;
881
+ }
628
882
  if (nowMs - lstatSync(path).mtimeMs < ORPHAN_WORKTREE_TTL_MS) {
629
883
  skip('ttl_not_expired');
630
884
  return;
@@ -638,6 +892,7 @@ function cleanupOrphanWorktrees(
638
892
  const measurement = measureReclaimablePath(path);
639
893
  if (removeOrphanWorktreeDirectory(path, errors, relativePath)) {
640
894
  removed.push(relativePath);
895
+ markOwnedResourceCleaned(controllerHome, ownedResource.resourceId, 'forge:runtime-orphan-worktree-cleanup');
641
896
  if (measurement.complete) reclaim.reclaimedBytes += measurement.bytes;
642
897
  else reclaim.unknownReclaimedByteCount += 1;
643
898
  }
@@ -802,12 +1057,12 @@ function shouldPersistCleanupAudit(report: RuntimeCleanupReport): boolean {
802
1057
  || report.removedTemporaryPaths.length
803
1058
  || report.removedCleanupArtifactPaths.length
804
1059
  || report.removedReleasePaths.length
1060
+ || report.releaseSessionCandidates.removedPaths.length
805
1061
  || report.removedCodegraphLocatorPaths.length
806
1062
  || report.removedCodegraphCachePaths.length
807
1063
  || report.removedRepositoryNamespacePaths.length
808
1064
  || report.sqliteMaintenance?.vacuumed
809
1065
  || report.sqliteMaintenance?.skippedReason === 'database_busy'
810
- || report.retiredPlanBoundWorkAuthorities.length
811
1066
  || report.retiredOwnerlessWorkAuthorities.length,
812
1067
  );
813
1068
  if (hadMutations || report.errors.length) return true;
@@ -839,14 +1094,12 @@ export function cleanupControllerRuntimeState(
839
1094
  const errors: string[] = [];
840
1095
  const skippedByReason: Record<string, number> = {};
841
1096
  const sequence = options.periodicSequence ?? Math.floor(nowMs / 60_000);
1097
+ const removalCycleSequence = Math.floor(sequence / REMOVAL_PHASES.length);
842
1098
  const removalPhases = cleanupRemovalPhaseOrder(options.reason ?? 'manual', sequence);
843
1099
  const periodic = (options.reason ?? 'manual') === 'periodic';
844
- const retiredPlanBoundWorkAuthorities: string[] = [];
845
1100
  const retiredOwnerlessWorkAuthorities: string[] = [];
846
1101
  if (!periodic || removalPhases.includes('repository_namespaces')) try {
847
1102
  for (const repository of listRepositories(home, { includeRemoved: true })) {
848
- const retired = retireTerminalPlanBoundWorkAuthorities({ controllerHome: home, repoId: repository.repoId });
849
- retiredPlanBoundWorkAuthorities.push(...retired.map((workId) => `${repository.repoId}:${workId}`));
850
1103
  const ownerless = reconcileOwnerlessWorkAuthorities({
851
1104
  controllerHome: home,
852
1105
  repoId: repository.repoId,
@@ -870,6 +1123,7 @@ export function cleanupControllerRuntimeState(
870
1123
  let temporaryCleanup: ReturnType<typeof cleanupTemporaryStatePaths> | undefined;
871
1124
  let artifactRetention: ReturnType<typeof cleanupWorkPreservationArtifacts> | undefined;
872
1125
  let releaseRetention: ReturnType<typeof cleanupControllerReleaseHistory> | undefined;
1126
+ let releaseSessionCandidates: ReleaseSessionCandidateRetentionReport | undefined;
873
1127
  let codegraphRetention: ReturnType<typeof cleanupCodegraphCaches> | undefined;
874
1128
  let repositoryNamespaceRetention: ReturnType<typeof cleanupRetiredRepositoryNamespaces> | undefined;
875
1129
  const removedCodegraphLocatorPaths: string[] = [];
@@ -920,6 +1174,7 @@ export function cleanupControllerRuntimeState(
920
1174
  graceMs: options.cleanupArtifactRetentionGraceMs,
921
1175
  maxEntries,
922
1176
  maxRemovals: removalBudget.remaining,
1177
+ scanSequence: removalCycleSequence,
923
1178
  });
924
1179
  removalBudget.remaining = Math.max(0, removalBudget.remaining - artifactRetention.attempted);
925
1180
  if (artifactRetention.budgetExhausted) removalBudget.exhausted = true;
@@ -971,7 +1226,7 @@ export function cleanupControllerRuntimeState(
971
1226
  let protectedWorkIds: string[];
972
1227
  try {
973
1228
  protectedWorkIds = readWorkContractStore({ controllerHome: home, repoId: repository.repoId }).contracts
974
- .filter((contract) => !isTerminalWorkContractStatus(contract.status))
1229
+ .filter((contract) => !isTerminalSemanticWorkState(contract.semanticState))
975
1230
  .map((contract) => contract.workId);
976
1231
  } catch (error) {
977
1232
  const message = error instanceof Error ? error.message : String(error);
@@ -1082,6 +1337,14 @@ export function cleanupControllerRuntimeState(
1082
1337
  errors.push(...repositoryNamespaceRetention.errors.map((error) => `repository-namespace ${error}`));
1083
1338
  continue;
1084
1339
  }
1340
+ releaseSessionCandidates = cleanupReleaseSessionCandidateLanes(home, {
1341
+ maxEntries,
1342
+ sequence,
1343
+ removalBudget,
1344
+ skippedByReason,
1345
+ });
1346
+ errors.push(...releaseSessionCandidates.errors.map((error) => `release-session-candidate ${error}`));
1347
+
1085
1348
  releaseRetention = cleanupControllerReleaseHistory(home, {
1086
1349
  nowMs,
1087
1350
  graceMs: options.releaseRetentionGraceMs,
@@ -1103,8 +1366,9 @@ export function cleanupControllerRuntimeState(
1103
1366
  codegraphRetention ??= { policyVersion: CODEGRAPH_CACHE_RETENTION_POLICY_VERSION, removedPaths: [], attempted: 0, budgetExhausted: false, skippedByReason: {}, errors: [], inspected: 0, eligible: 0, retained: 0, reclaimedBytes: 0, unknownReclaimedByteCount: 0, observedBytes: 0, unknownObservedByteCount: 0, protected: 0, protectedOverCapacity: 0, truncated: false } as ReturnType<typeof cleanupCodegraphCaches>;
1104
1367
  repositoryNamespaceRetention ??= { policyVersion: 'repository-namespace-retention-v1', removedPaths: [], attempted: 0, budgetExhausted: false, skippedByReason: {}, errors: [], inspected: 0, eligible: 0, retained: 0, reclaimedBytes: 0, unknownReclaimedByteCount: 0 } as ReturnType<typeof cleanupRetiredRepositoryNamespaces>;
1105
1368
  releaseRetention ??= { removedPaths: [], removedBackupPaths: [], attempted: 0, budgetExhausted: false, skippedByReason: {}, errors: [], inspected: 0, eligible: 0, retained: 0, skipped: 0, reclaimedBytes: 0, unknownReclaimedByteCount: 0, reclaimedBackupBytes: 0, unknownReclaimedBackupByteCount: 0 } as ReturnType<typeof cleanupControllerReleaseHistory>;
1369
+ releaseSessionCandidates ??= emptyReleaseSessionCandidateRetentionReport();
1106
1370
  }
1107
- if (!worktrees || !dependencyCleanup || !temporaryCleanup || !artifactRetention || !codegraphRetention || !repositoryNamespaceRetention || !releaseRetention) {
1371
+ if (!worktrees || !dependencyCleanup || !temporaryCleanup || !artifactRetention || !codegraphRetention || !repositoryNamespaceRetention || !releaseRetention || !releaseSessionCandidates) {
1108
1372
  throw new Error('RUNTIME_CLEANUP_PHASE_INCOMPLETE');
1109
1373
  }
1110
1374
  const removedTemporaryPaths = temporaryCleanup.removed.sort();
@@ -1128,8 +1392,8 @@ export function cleanupControllerRuntimeState(
1128
1392
  } catch (error) {
1129
1393
  errors.push(errorText('SQLite maintenance', error));
1130
1394
  }
1131
- const inspectedPaths = referenceBudget.inspected + worktreeBudget.inspected + dependencyBudget.inspected + tempBudget.inspected + schedulerBudget.inspected + editSessionBudget.inspected + artifactRetention.inspected + codegraphLocatorInspected + codegraphRetention.inspected + repositoryNamespaceRetention.inspected + releaseRetention.inspected;
1132
- const budgetExhausted = referenceBudget.exhausted || worktreeBudget.exhausted || dependencyBudget.exhausted || tempBudget.exhausted || schedulerBudget.exhausted || editSessionBudget.exhausted || removalBudget.exhausted;
1395
+ const inspectedPaths = referenceBudget.inspected + worktreeBudget.inspected + dependencyBudget.inspected + tempBudget.inspected + schedulerBudget.inspected + editSessionBudget.inspected + artifactRetention.inspected + codegraphLocatorInspected + codegraphRetention.inspected + repositoryNamespaceRetention.inspected + releaseRetention.inspected + releaseSessionCandidates.inspected;
1396
+ const budgetExhausted = referenceBudget.exhausted || worktreeBudget.exhausted || dependencyBudget.exhausted || tempBudget.exhausted || schedulerBudget.exhausted || editSessionBudget.exhausted || removalBudget.exhausted || releaseSessionCandidates.truncated;
1133
1397
  if (pidFiles.skipped.length > 0 && removalBudget.exhausted) skippedByReason.cleanup_budget_exhausted = (skippedByReason.cleanup_budget_exhausted ?? 0) + pidFiles.skipped.length;
1134
1398
  if (pidFiles.skipped.length > 0 && !removalBudget.exhausted) skippedByReason.active_owner = (skippedByReason.active_owner ?? 0) + pidFiles.skipped.length;
1135
1399
  const physicalReclaimedByClass: Record<string, RuntimeCleanupLifecycleClassMetrics> = {
@@ -1158,6 +1422,11 @@ export function cleanupControllerRuntimeState(
1158
1422
  bytes: releaseRetention.reclaimedBackupBytes,
1159
1423
  unknownByteCount: releaseRetention.unknownReclaimedBackupByteCount,
1160
1424
  },
1425
+ release_session_candidate: {
1426
+ count: releaseSessionCandidates.removedPaths.length,
1427
+ bytes: releaseSessionCandidates.reclaimedBytes,
1428
+ unknownByteCount: releaseSessionCandidates.unknownReclaimedByteCount,
1429
+ },
1161
1430
  scheduler_occurrence_history: {
1162
1431
  count: removedScheduleOccurrencePaths.length + removedScheduleDecisionPaths.length,
1163
1432
  bytes: schedulerHistory.reclaimedBytes,
@@ -1199,8 +1468,8 @@ export function cleanupControllerRuntimeState(
1199
1468
  reclaimedBytes: Object.values(physicalReclaimedByClass).reduce((total, entry) => total + entry.bytes, 0),
1200
1469
  unknownReclaimedByteCount: Object.values(physicalReclaimedByClass).reduce((total, entry) => total + entry.unknownByteCount, 0),
1201
1470
  reclaimedByClass: physicalReclaimedByClass,
1202
- logicalRetiredCount: retiredPlanBoundWorkAuthorities.length + retiredOwnerlessWorkAuthorities.length,
1203
- logicalRetiredByClass: { work: retiredPlanBoundWorkAuthorities.length + retiredOwnerlessWorkAuthorities.length },
1471
+ logicalRetiredCount: retiredOwnerlessWorkAuthorities.length,
1472
+ logicalRetiredByClass: { work: retiredOwnerlessWorkAuthorities.length },
1204
1473
  protectedActiveCount: Object.values(protectedByReason).reduce((total, count) => total + count, 0),
1205
1474
  protectedByReason,
1206
1475
  blockerReasons,
@@ -1216,6 +1485,7 @@ export function cleanupControllerRuntimeState(
1216
1485
  removedTemporaryPaths,
1217
1486
  removedCleanupArtifactPaths,
1218
1487
  removedReleasePaths,
1488
+ releaseSessionCandidates,
1219
1489
  removedScheduleOccurrencePaths,
1220
1490
  removedScheduleDecisionPaths,
1221
1491
  removedEditSessionPaths,
@@ -1223,7 +1493,6 @@ export function cleanupControllerRuntimeState(
1223
1493
  removedCodegraphCachePaths,
1224
1494
  removedRepositoryNamespacePaths,
1225
1495
  sqliteMaintenance,
1226
- retiredPlanBoundWorkAuthorities: retiredPlanBoundWorkAuthorities.sort(),
1227
1496
  retiredOwnerlessWorkAuthorities: retiredOwnerlessWorkAuthorities.sort(),
1228
1497
  skippedActiveWorktrees: worktrees.skippedActive.sort(),
1229
1498
  inspectedPaths,
@@ -1233,11 +1502,11 @@ export function cleanupControllerRuntimeState(
1233
1502
  lifecycleMetrics,
1234
1503
  cycle: {
1235
1504
  scanned: inspectedPaths,
1236
- eligible: retiredPlanBoundWorkAuthorities.length + retiredOwnerlessWorkAuthorities.length + pidFiles.removed.length + worktrees.removed.length + dependencyCleanup.migrated.length + removedTemporaryPaths.length + artifactRetention.eligible + schedulerHistory.eligible + editSessionHistory.eligible + removedCodegraphLocatorPaths.length + codegraphRetention.eligible + repositoryNamespaceRetention.eligible + releaseRetention.eligible,
1237
- attempted: retiredPlanBoundWorkAuthorities.length + retiredOwnerlessWorkAuthorities.length + pidFiles.removed.length + worktrees.removed.length + dependencyCleanup.migrated.length + removedTemporaryPaths.length + artifactRetention.attempted + schedulerHistory.attempted + editSessionHistory.attempted + removedCodegraphLocatorPaths.length + codegraphRetention.attempted + repositoryNamespaceRetention.attempted + releaseRetention.attempted + errors.length,
1238
- removed: retiredPlanBoundWorkAuthorities.length + retiredOwnerlessWorkAuthorities.length + pidFiles.removed.length + worktrees.removed.length + dependencyCleanup.migrated.length + removedTemporaryPaths.length + removedCleanupArtifactPaths.length + removedScheduleOccurrencePaths.length + removedScheduleDecisionPaths.length + removedEditSessionPaths.length + removedCodegraphLocatorPaths.length + removedCodegraphCachePaths.length + removedRepositoryNamespacePaths.length + removedReleasePaths.length,
1239
- retained: pidFiles.skipped.length + worktrees.skippedActive.length + artifactRetention.retained + schedulerHistory.retained + editSessionHistory.retained + codegraphLocatorRetained + codegraphRetention.retained + repositoryNamespaceRetention.retained + releaseRetention.retained,
1240
- skipped: Math.max(0, inspectedPaths - pidFiles.removed.length - worktrees.removed.length - dependencyCleanup.migrated.length - removedTemporaryPaths.length - removedCleanupArtifactPaths.length - removedScheduleOccurrencePaths.length - removedScheduleDecisionPaths.length - removedEditSessionPaths.length - removedCodegraphLocatorPaths.length - removedCodegraphCachePaths.length - removedRepositoryNamespacePaths.length - removedReleasePaths.length - errors.length),
1505
+ eligible: retiredOwnerlessWorkAuthorities.length + pidFiles.removed.length + worktrees.removed.length + dependencyCleanup.migrated.length + removedTemporaryPaths.length + artifactRetention.eligible + schedulerHistory.eligible + editSessionHistory.eligible + removedCodegraphLocatorPaths.length + codegraphRetention.eligible + repositoryNamespaceRetention.eligible + releaseRetention.eligible + releaseSessionCandidates.eligible,
1506
+ attempted: retiredOwnerlessWorkAuthorities.length + pidFiles.removed.length + worktrees.removed.length + dependencyCleanup.migrated.length + removedTemporaryPaths.length + artifactRetention.attempted + schedulerHistory.attempted + editSessionHistory.attempted + removedCodegraphLocatorPaths.length + codegraphRetention.attempted + repositoryNamespaceRetention.attempted + releaseRetention.attempted + releaseSessionCandidates.attempted + errors.length,
1507
+ removed: retiredOwnerlessWorkAuthorities.length + pidFiles.removed.length + worktrees.removed.length + dependencyCleanup.migrated.length + removedTemporaryPaths.length + removedCleanupArtifactPaths.length + removedScheduleOccurrencePaths.length + removedScheduleDecisionPaths.length + removedEditSessionPaths.length + removedCodegraphLocatorPaths.length + removedCodegraphCachePaths.length + removedRepositoryNamespacePaths.length + removedReleasePaths.length + releaseSessionCandidates.removedPaths.length,
1508
+ retained: pidFiles.skipped.length + worktrees.skippedActive.length + artifactRetention.retained + schedulerHistory.retained + editSessionHistory.retained + codegraphLocatorRetained + codegraphRetention.retained + repositoryNamespaceRetention.retained + releaseRetention.retained + releaseSessionCandidates.retainedCount,
1509
+ skipped: Math.max(0, inspectedPaths - pidFiles.removed.length - worktrees.removed.length - dependencyCleanup.migrated.length - removedTemporaryPaths.length - removedCleanupArtifactPaths.length - removedScheduleOccurrencePaths.length - removedScheduleDecisionPaths.length - removedEditSessionPaths.length - removedCodegraphLocatorPaths.length - removedCodegraphCachePaths.length - removedRepositoryNamespacePaths.length - removedReleasePaths.length - releaseSessionCandidates.removedPaths.length - errors.length),
1241
1510
  failed: errors.length,
1242
1511
  truncated: budgetExhausted,
1243
1512
  budgetExhausted,
@@ -0,0 +1,80 @@
1
+ import { ensureForgeInstanceIdentity } from '../../../../packages/kernel/identity/api/index';
2
+ import type { RepositoryRecord } from '../../../cli/repositories/types';
3
+ import {
4
+ normalizeRemoteUrl,
5
+ portableProjectSourceFingerprint,
6
+ stablePortableProjectId,
7
+ } from '../../../cli/repositories/identity';
8
+ import { loadProjectEngineeringContract } from '../../context/project-engineering-contract';
9
+ import {
10
+ ensureProjectWorkspaceBinding,
11
+ type EnsureProjectWorkspaceBindingResult,
12
+ } from './workspace-store';
13
+
14
+ export type RepositoryProjectOnboardingResult =
15
+ | {
16
+ status: 'bound';
17
+ projectId: string;
18
+ workspaceId: string;
19
+ forgeInstanceId: string;
20
+ identitySource: 'project_contract' | 'canonical_remote';
21
+ createdWorkspace: boolean;
22
+ createdProject: boolean;
23
+ createdPlacement: boolean;
24
+ }
25
+ | {
26
+ status: 'unbound';
27
+ reason: 'portable_project_identity_unavailable';
28
+ };
29
+
30
+ /**
31
+ * Bind a repository to portable Project/Workspace semantics only when Work
32
+ * admission actually treats it as a project. Repository registration remains a
33
+ * node-local placement concern and never creates semantic identity by itself.
34
+ */
35
+ export function ensureRepositoryProjectOnboarding(input: {
36
+ controllerHome: string;
37
+ repository: RepositoryRecord;
38
+ sourceRevision?: string;
39
+ }): RepositoryProjectOnboardingResult {
40
+ const contract = loadProjectEngineeringContract({
41
+ repoRoot: input.repository.canonicalRoot,
42
+ sourceRevision: input.sourceRevision?.trim() || 'working-tree',
43
+ });
44
+ const declaredProjectId = contract.status === 'ready' ? contract.contract.projectId : undefined;
45
+ const canonicalRemote = input.repository.canonicalRemote ?? normalizeRemoteUrl(input.repository.remoteUrl);
46
+ if (!declaredProjectId && !canonicalRemote) {
47
+ return { status: 'unbound', reason: 'portable_project_identity_unavailable' };
48
+ }
49
+
50
+ const sourceFingerprint = canonicalRemote
51
+ ? portableProjectSourceFingerprint(canonicalRemote)
52
+ : undefined;
53
+ const fallbackProjectId = canonicalRemote
54
+ ? stablePortableProjectId(canonicalRemote)
55
+ : undefined;
56
+ const instance = ensureForgeInstanceIdentity({
57
+ controllerHome: input.controllerHome,
58
+ label: 'Forge Runtime',
59
+ });
60
+ const binding: EnsureProjectWorkspaceBindingResult = ensureProjectWorkspaceBinding({
61
+ controllerHome: input.controllerHome,
62
+ preferredProjectId: declaredProjectId,
63
+ fallbackProjectId,
64
+ sourceFingerprint,
65
+ displayName: input.repository.displayName,
66
+ forgeInstanceId: instance.instanceId,
67
+ repositoryId: input.repository.repoId,
68
+ });
69
+
70
+ return {
71
+ status: 'bound',
72
+ projectId: binding.project.projectId,
73
+ workspaceId: binding.project.workspaceId,
74
+ forgeInstanceId: binding.placement.forgeInstanceId,
75
+ identitySource: declaredProjectId ? 'project_contract' : 'canonical_remote',
76
+ createdWorkspace: binding.createdWorkspace,
77
+ createdProject: binding.createdProject,
78
+ createdPlacement: binding.createdPlacement,
79
+ };
80
+ }
@@ -18,6 +18,7 @@ import { readForgeInstanceIdentity } from '../../../../packages/kernel/identity/
18
18
  import type { WorkContract } from '../../../../packages/kernel/work/api/index';
19
19
  import { semanticScopeRefForWork } from '../../../../packages/kernel/work/api/index';
20
20
  import type { PlanContract } from '../facade/types';
21
+ import { SEMANTIC_SCOPE_KEY } from '../../../cli/repositories/controller-home';
21
22
  import type { Requirement } from '../persistence/requirement-store';
22
23
  import {
23
24
  ControlPlaneConflictError,
@@ -90,13 +91,15 @@ export interface WorkSemanticView {
90
91
  semanticScope: ReturnType<typeof semanticScopeRefForWork>;
91
92
  objective: string;
92
93
  acceptanceCriteria: string[];
93
- status: WorkContract['status'];
94
+ state: WorkContract['semanticState'];
94
95
  phase: WorkContract['phase'];
95
96
  workKind: WorkContract['workKind'];
96
97
  lifecycleRole?: WorkContract['lifecycleRole'];
97
98
  requirementId?: string;
98
99
  planId?: string;
99
100
  planStepId?: string;
101
+ semanticParentWorkId?: string;
102
+ dependsOnWorkIds?: string[];
100
103
  predecessorWorkId?: string;
101
104
  supersedes?: string[];
102
105
  supersededBy?: string;
@@ -199,13 +202,15 @@ export function projectWorkSemantic(work: WorkContract): WorkSemanticView {
199
202
  semanticScope: semanticScopeRefForWork(work),
200
203
  objective: work.objective,
201
204
  acceptanceCriteria: [...work.acceptanceCriteria],
202
- status: work.status,
205
+ state: work.semanticState,
203
206
  phase: work.phase,
204
207
  workKind: work.workKind,
205
208
  ...(work.lifecycleRole ? { lifecycleRole: work.lifecycleRole } : {}),
206
209
  ...(work.requirementId ? { requirementId: work.requirementId } : {}),
207
210
  ...(work.planId ? { planId: work.planId } : {}),
208
211
  ...(work.planStepId ? { planStepId: work.planStepId } : {}),
212
+ ...(work.semanticParentWorkId ? { semanticParentWorkId: work.semanticParentWorkId } : {}),
213
+ ...(work.dependsOnWorkIds?.length ? { dependsOnWorkIds: [...work.dependsOnWorkIds] } : {}),
209
214
  ...(work.predecessorWorkId ? { predecessorWorkId: work.predecessorWorkId } : {}),
210
215
  ...(work.supersedes ? { supersedes: [...work.supersedes] } : {}),
211
216
  ...(work.supersededBy ? { supersededBy: work.supersededBy } : {}),
@@ -311,9 +316,18 @@ function localRecordWithinTransaction(database: SqliteDatabase, input: { kind: S
311
316
  if (input.kind === 'workspace') return readControlPlaneRecordWithinTransaction(database, WORKSPACE_SEMANTIC_NAMESPACE, CONTROLLER_SCOPE, input.id);
312
317
  if (input.kind === 'project') return readControlPlaneRecordWithinTransaction(database, PROJECT_SEMANTIC_NAMESPACE, input.workspaceId, input.id);
313
318
  if (input.kind === 'requirement') return readControlPlaneRecordWithinTransaction(database, 'requirement', CONTROLLER_SCOPE, input.id);
314
- if (!input.repositoryId) return undefined;
315
- if (input.kind === 'plan') return readControlPlaneRecordWithinTransaction(database, 'plan_contract', input.repositoryId, input.id);
316
- if (input.kind === 'work') return readControlPlaneRecordWithinTransaction(database, 'work_contract', input.repositoryId, input.id);
319
+ if (input.kind === 'plan') {
320
+ const semantic = readControlPlaneRecordWithinTransaction(database, 'plan_contract', SEMANTIC_SCOPE_KEY, input.id);
321
+ return semantic ?? (input.repositoryId
322
+ ? readControlPlaneRecordWithinTransaction(database, 'plan_contract', input.repositoryId, input.id)
323
+ : undefined);
324
+ }
325
+ if (input.kind === 'work') {
326
+ const semantic = readControlPlaneRecordWithinTransaction(database, 'work_contract', SEMANTIC_SCOPE_KEY, input.id);
327
+ return semantic ?? (input.repositoryId
328
+ ? readControlPlaneRecordWithinTransaction(database, 'work_contract', input.repositoryId, input.id)
329
+ : undefined);
330
+ }
317
331
  return undefined;
318
332
  }
319
333