@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
@@ -2,12 +2,10 @@ import { resolve } from 'path';
2
2
  import type { RepositoryRecord } from '../../../cli/repositories/types';
3
3
  import { getRepository, resolveRepositorySelection, selectRepositoryCheckout } from '../../../cli/repositories/registry';
4
4
  import { repositoryGitStatus } from '../../../cli/repositories/structured-git';
5
- import { appendWorkEvidence, getWorkContract, promoteWorkToRepositoryChange, updateWorkContract } from '../../../../packages/kernel/work/api/index';
6
- import { controllerSessionPrincipalId, getControllerSession } from '../../../../packages/kernel/controller/api/index';
7
- import { isTerminalWorkContractStatus } from '../facade/types';
5
+ import { appendWorkEvidence, getWorkContract, recordWorkEvidenceState, semanticWorkState } from '../../../../packages/kernel/work/api/index';
8
6
  import { currentPermissionSnapshotVersion } from './validation';
9
7
  import { listWorkHandles, readWorkHandle, transitionWorkHandle, writeWorkHandle, type WorkHandleState } from './work-handle-store';
10
- import { inspectDirectCanonicalPreMutationReconciliation } from './direct-canonical-work-reconciliation';
8
+ import { gitIsAncestor } from './work-execution-support';
11
9
 
12
10
  export interface RepositoryWorkHandleControllerIdentity {
13
11
  sessionId: string;
@@ -46,10 +44,11 @@ export function assertCanonicalRepositoryMutationWorkHandleAvailable(input: {
46
44
  handle.workId,
47
45
  );
48
46
  // A stale physical handle cannot outlive canonical Work lifecycle authority.
49
- // Missing WorkContract evidence remains fail-closed for legacy/unreconciled
50
- // handles; only an explicit terminal status or completion receipt releases
51
- // durable canonical writer ownership.
52
- return !contract || (!isTerminalWorkContractStatus(contract.status) && !contract.completionReceipt);
47
+ // Delivery receipts are mechanical evidence only; an explicitly open Work
48
+ // continues to own its concrete mutation surface until semantic completion
49
+ // or cancellation releases that authority.
50
+ if (!contract) return false;
51
+ return semanticWorkState(contract) === 'open';
53
52
  })
54
53
  .sort((left, right) => left.workId.localeCompare(right.workId));
55
54
  if (owners.length === 0) return;
@@ -86,8 +85,9 @@ function resolveRepositoryWorkHandlePlacement(input: {
86
85
  }
87
86
 
88
87
  /**
89
- * Canonical compatibility repair for a goal-workloop Work whose durable
90
- * WorkContract exists but whose WorkHandle has not yet been materialized.
88
+ * Materialize concrete repository-mutation ownership for an optional semantic
89
+ * Work attribution. Thin Work does not classify execution kind; checkout/CAS
90
+ * placement and the WorkHandle resource fence own mutation safety.
91
91
  * Transport layers provide only the authenticated Controller identity.
92
92
  */
93
93
  export function ensureRepositoryWorkHandle(input: {
@@ -95,28 +95,35 @@ export function ensureRepositoryWorkHandle(input: {
95
95
  repository: RepositoryRecord;
96
96
  workId: string;
97
97
  identity: RepositoryWorkHandleControllerIdentity;
98
+ checkoutId?: string;
98
99
  allowEffectWork?: boolean;
99
100
  }): WorkHandleState | undefined {
100
101
  const existing = readWorkHandle(input.controllerHome, input.repository.repoId, input.workId);
101
- if (existing) return existing;
102
+ if (existing) {
103
+ if (input.checkoutId?.trim() && existing.checkoutId !== input.checkoutId.trim()) {
104
+ throw new Error(`WORK_HANDLE_PLACEMENT_CHECKOUT_MISMATCH: ${input.workId}`);
105
+ }
106
+ return existing;
107
+ }
102
108
  const contract = getWorkContract(
103
109
  { controllerHome: input.controllerHome, repoId: input.repository.repoId },
104
110
  input.workId,
105
111
  );
106
- const supportedKind = contract?.workKind === 'repository_change'
107
- || contract?.workKind === 'completed_no_change'
108
- || (input.allowEffectWork === true && (contract?.workKind === 'local_effect' || contract?.workKind === 'remote_effect'));
109
- if (!contract || !supportedKind || contract.mode !== 'goal_workloop' || !contract.checkoutId) {
110
- return undefined;
111
- }
112
+ // allowEffectWork is retained only for source compatibility while old
113
+ // repository callers cut over. workKind is no longer an execution authority.
114
+ void input.allowEffectWork;
115
+ const checkoutId = input.checkoutId?.trim() || contract?.checkoutId?.trim();
116
+ if (!contract || !checkoutId) return undefined;
112
117
  // Callers may already be scoped to the Work checkout. Re-read the unselected
113
118
  // registry record so WorkHandle source/delivery authority never mistakes an
114
- // isolated execution worktree for the canonical source checkout.
119
+ // isolated execution worktree for the canonical source checkout. Legacy
120
+ // WorkContract checkout/worktree fields remain migration-era placement hints;
121
+ // new Thin Work receives its concrete checkout from the repository target.
115
122
  const placement = resolveRepositoryWorkHandlePlacement({
116
123
  controllerHome: input.controllerHome,
117
124
  repositoryId: input.repository.repoId,
118
- checkoutId: contract.checkoutId,
119
- worktreeRef: contract.worktreeRef,
125
+ checkoutId,
126
+ worktreeRef: contract.checkoutId === checkoutId ? contract.worktreeRef : undefined,
120
127
  });
121
128
  const { registeredRepository, checkout, status, branch, managedWorktree } = placement;
122
129
  const sourceCheckoutId = registeredRepository.activeCheckoutId;
@@ -130,7 +137,7 @@ export function ensureRepositoryWorkHandle(input: {
130
137
  sessionId: input.identity.sessionId,
131
138
  principalId: input.identity.principalId,
132
139
  repositoryId: input.repository.repoId,
133
- checkoutId: contract.checkoutId,
140
+ checkoutId,
134
141
  worktreePath: checkout.canonicalRoot,
135
142
  branch,
136
143
  sourceCheckoutId,
@@ -164,7 +171,7 @@ export function reconcileRepositoryWorkHandlePlacement(input: {
164
171
  const existing = readWorkHandle(input.controllerHome, input.repositoryId, input.workId);
165
172
  if (!existing || existing.managedWorktree) return existing;
166
173
  const contract = getWorkContract({ controllerHome: input.controllerHome, repoId: input.repositoryId }, input.workId);
167
- if (!contract || contract.workKind !== 'repository_change' || contract.mode !== 'goal_workloop' || !contract.checkoutId) return existing;
174
+ if (!contract || !contract.checkoutId) return existing;
168
175
  if (contract.checkoutId !== existing.checkoutId) throw new Error(`WORK_HANDLE_PLACEMENT_CHECKOUT_MISMATCH: ${input.workId}`);
169
176
  const placement = resolveRepositoryWorkHandlePlacement({ controllerHome: input.controllerHome, repositoryId: input.repositoryId, checkoutId: contract.checkoutId, worktreeRef: contract.worktreeRef });
170
177
  if (!placement.managedWorktree) return existing;
@@ -174,58 +181,160 @@ export function reconcileRepositoryWorkHandlePlacement(input: {
174
181
  return writeWorkHandle(input.controllerHome, { ...existing, sourceCheckoutId: placement.registeredRepository.activeCheckoutId, managedWorktree: true });
175
182
  }
176
183
 
177
- function alignRepositoryMutationBase(input: {
184
+ export function assertManagedRepositoryMutationAuthority(input: {
185
+ repository: RepositoryRecord;
186
+ handle: WorkHandleState;
187
+ }): void {
188
+ if (!input.handle.managedWorktree) return;
189
+ if (input.handle.state !== 'prepared' && input.handle.state !== 'editing') {
190
+ throw new Error(`WORK_REPOSITORY_MUTATION_LIFECYCLE_INVALID: ${input.handle.workId}:${input.handle.state}`);
191
+ }
192
+ if (input.repository.activeCheckoutId !== input.handle.checkoutId) {
193
+ throw new Error(`WORK_REPOSITORY_MUTATION_CHECKOUT_MISMATCH: expected ${input.handle.checkoutId}, found ${input.repository.activeCheckoutId}`);
194
+ }
195
+ const status = repositoryGitStatus(input.repository);
196
+ if (status.branch !== input.handle.branch) {
197
+ throw new Error(`WORK_REPOSITORY_MUTATION_BRANCH_CHANGED: expected ${input.handle.branch}, found ${status.branch ?? 'detached'}`);
198
+ }
199
+ if (!input.handle.expectedHead || status.head !== input.handle.expectedHead) {
200
+ throw new Error(`WORK_REPOSITORY_MUTATION_HEAD_CHANGED: expected ${input.handle.expectedHead ?? 'missing'}, found ${status.head ?? 'missing'}`);
201
+ }
202
+ }
203
+
204
+ export function rearmFailedPreservedWorkHandle(input: {
178
205
  controllerHome: string;
179
206
  repository: RepositoryRecord;
180
207
  workId: string;
181
208
  contract: NonNullable<ReturnType<typeof getWorkContract>>;
182
209
  handle: WorkHandleState;
183
- freshlyMaterialized: boolean;
210
+ principalId: string;
211
+ sessionId: string;
184
212
  }): WorkHandleState {
185
- if (input.handle.managedWorktree || input.handle.state !== 'prepared') return input.handle;
186
- if (input.contract.phase !== 'implementation') {
187
- throw new Error(`WORK_DIRECT_PRE_MUTATION_PHASE_INVALID: ${input.workId}:${input.contract.phase}`);
213
+ const { handle } = input;
214
+ if (!handle.managedWorktree || handle.state !== 'failed') return handle;
215
+ const validationRecoverable = handle.finalization.validation === 'pending'
216
+ || handle.finalization.validation === 'failed';
217
+ if (!validationRecoverable
218
+ || handle.finalization.commit !== 'pending'
219
+ || handle.finalization.merge !== 'pending'
220
+ || handle.finalization.branchCleanup !== 'pending'
221
+ || handle.finalization.worktreeCleanup !== 'pending'
222
+ || handle.cleanupReceipt
223
+ || input.contract.completionReceipt
224
+ || input.contract.completionOutcome) {
225
+ return handle;
226
+ }
227
+ if (handle.principalId !== input.principalId) {
228
+ throw new Error(`WORK_REPOSITORY_MUTATION_PRINCIPAL_MISMATCH: ${input.workId}`);
188
229
  }
189
- if (!input.contract.checkoutId) throw new Error(`WORK_REPOSITORY_MUTATION_CHECKOUT_REQUIRED: ${input.workId}`);
190
-
191
230
  const placement = resolveRepositoryWorkHandlePlacement({
192
231
  controllerHome: input.controllerHome,
193
232
  repositoryId: input.repository.repoId,
194
- checkoutId: input.contract.checkoutId,
195
- worktreeRef: input.contract.worktreeRef,
233
+ checkoutId: handle.checkoutId,
234
+ worktreeRef: handle.worktreePath,
235
+ });
236
+ if (!placement.managedWorktree || placement.registeredCheckout.lifecycle !== 'active') {
237
+ throw new Error(`WORK_REPOSITORY_MUTATION_FAILED_CHECKOUT_NOT_ACTIVE: ${input.workId}`);
238
+ }
239
+ if (resolve(placement.checkout.canonicalRoot) !== resolve(handle.worktreePath)
240
+ || placement.branch !== handle.branch
241
+ || (handle.expectedHead && placement.status.head !== handle.expectedHead)) {
242
+ throw new Error(`WORK_REPOSITORY_MUTATION_FAILED_CHECKOUT_OWNERSHIP_MISMATCH: ${input.workId}`);
243
+ }
244
+ if (input.contract.evidenceState === 'valid') {
245
+ recordWorkEvidenceState(
246
+ { controllerHome: input.controllerHome, repoId: input.repository.repoId },
247
+ input.workId,
248
+ 'stale',
249
+ );
250
+ }
251
+ const next = writeWorkHandle(input.controllerHome, {
252
+ ...handle,
253
+ principalId: input.principalId,
254
+ sessionId: input.sessionId,
255
+ state: 'editing',
256
+ validationRun: undefined,
257
+ validatedInputFingerprint: undefined,
258
+ failureReason: undefined,
259
+ finalization: { ...handle.finalization, validation: 'pending' },
260
+ updatedAt: new Date().toISOString(),
196
261
  });
197
- // A managed checkout has its own source lineage and does not participate in
198
- // shared-canonical target-base alignment.
199
- if (placement.managedWorktree) return input.handle;
262
+ appendWorkEvidence(
263
+ { controllerHome: input.controllerHome, repoId: input.repository.repoId },
264
+ input.workId,
265
+ {
266
+ title: 'failed retained Work re-armed for same-Work mutation',
267
+ summary: `Re-armed preserved managed checkout ${handle.checkoutId} after proving the Work remained open, commit/merge/cleanup had not started, and exact checkout/path/branch/HEAD ownership still matched.`,
268
+ detailLevel: 'summary',
269
+ },
270
+ );
271
+ return next;
272
+ }
273
+
274
+ function rearmRetainedMergedWorkForMutation(input: {
275
+ controllerHome: string;
276
+ repository: RepositoryRecord;
277
+ workId: string;
278
+ contract: NonNullable<ReturnType<typeof getWorkContract>>;
279
+ handle: WorkHandleState;
280
+ }): WorkHandleState {
281
+ const { handle } = input;
282
+ if (!handle.managedWorktree || handle.state !== 'merged') return handle;
283
+ const retained = handle.terminalResourceDisposition;
284
+ if (retained?.mode !== 'retained_by_request' || retained.retainWorktree !== true || retained.retainBranch !== true) return handle;
285
+ if (semanticWorkState(input.contract) !== 'open') throw new Error(`WORK_RETAINED_REARM_SEMANTIC_STATE_INVALID: ${input.workId}`);
286
+ if (!handle.expectedHead?.trim()) throw new Error(`WORK_RETAINED_REARM_EXPECTED_HEAD_REQUIRED: ${input.workId}`);
200
287
 
201
- const targetBranch = input.handle.deliveryTargetBranch ?? placement.branch;
202
- const inspection = inspectDirectCanonicalPreMutationReconciliation({
203
- handle: input.handle,
204
- root: placement.checkout.canonicalRoot,
205
- targetBranch,
206
- status: placement.status,
207
- freshlyMaterialized: input.freshlyMaterialized,
288
+ const placement = resolveRepositoryWorkHandlePlacement({
289
+ controllerHome: input.controllerHome,
290
+ repositoryId: input.repository.repoId,
291
+ checkoutId: handle.checkoutId,
292
+ worktreeRef: input.contract.worktreeRef,
208
293
  });
209
- if (inspection.reason === 'no_target_advance') return input.handle;
210
- if (!inspection.alignable || !inspection.targetHead) {
211
- throw new Error(`WORK_DIRECT_PRE_MUTATION_RECONCILIATION_BLOCKED: ${inspection.reason}`);
294
+ if (!placement.managedWorktree || placement.registeredCheckout.lifecycle !== 'active') {
295
+ throw new Error(`WORK_RETAINED_REARM_CHECKOUT_NOT_ACTIVE: ${input.workId}`);
296
+ }
297
+ if (resolve(placement.checkout.canonicalRoot) !== resolve(handle.worktreePath) || placement.branch !== handle.branch) {
298
+ throw new Error(`WORK_RETAINED_REARM_OWNERSHIP_MISMATCH: ${input.workId}`);
299
+ }
300
+ if (!placement.status.clean) throw new Error(`WORK_RETAINED_REARM_WORKTREE_DIRTY: ${input.workId}`);
301
+ if (placement.status.head !== handle.expectedHead) {
302
+ throw new Error(`WORK_RETAINED_REARM_HEAD_CHANGED: expected ${handle.expectedHead}, found ${placement.status.head ?? 'missing'}`);
303
+ }
304
+ const sourceCheckout = selectRepositoryCheckout(
305
+ placement.registeredRepository,
306
+ handle.sourceCheckoutId ?? placement.registeredRepository.activeCheckoutId,
307
+ { allowArchived: true },
308
+ );
309
+ const targetBranch = handle.deliveryTargetBranch?.trim();
310
+ if (!targetBranch || !gitIsAncestor(sourceCheckout.canonicalRoot, handle.expectedHead, targetBranch)) {
311
+ throw new Error(`WORK_RETAINED_REARM_TARGET_CONTAINMENT_REQUIRED: ${input.workId}`);
212
312
  }
213
313
 
214
- const aligned = transitionWorkHandle(input.controllerHome, input.handle, input.handle.state, {
215
- deliveryBaseCommit: inspection.targetHead,
216
- expectedHead: inspection.targetHead,
314
+ const evidenceState = input.contract.evidenceState === 'valid' || input.contract.evidenceState === 'stale' ? 'stale' : 'partial';
315
+ if (input.contract.evidenceState !== evidenceState) recordWorkEvidenceState(
316
+ { controllerHome: input.controllerHome, repoId: input.repository.repoId }, input.workId, evidenceState,
317
+ );
318
+ const next = writeWorkHandle(input.controllerHome, {
319
+ ...handle,
320
+ state: 'editing',
321
+ terminalResourceDisposition: undefined,
322
+ validatedInputFingerprint: undefined,
323
+ validationRun: undefined,
324
+ cleanupReceipt: undefined,
217
325
  failureReason: undefined,
326
+ finalization: { validation: 'pending', commit: 'pending', merge: 'pending', branchCleanup: 'pending', worktreeCleanup: 'pending' },
218
327
  });
219
328
  appendWorkEvidence(
220
329
  { controllerHome: input.controllerHome, repoId: input.repository.repoId },
221
330
  input.workId,
222
331
  {
223
- title: 'direct canonical pre-mutation target base aligned',
224
- summary: `Before the first Work-owned repository mutation, canonical target ${targetBranch} advanced linearly ${inspection.previousDeliveryBase} -> ${inspection.targetHead} while the shared checkout remained clean. Forge advanced only deliveryBaseCommit/expectedHead; the Work remains prepared until the mutation surface proves that repository mutation actually started.`,
332
+ title: 'retained merged Work re-armed for same-Work mutation',
333
+ summary: `Re-armed retained merged Work at ${handle.expectedHead} only after proving semantic Work remains open, retained branch/worktree ownership, clean exact checkout identity, and target containment on ${targetBranch}. Prior validation/delivery authority is stale; no new Work was created.`,
225
334
  detailLevel: 'summary',
226
335
  },
227
336
  );
228
- return aligned;
337
+ return next;
229
338
  }
230
339
 
231
340
  export function markRepositoryMutationStarted(input: {
@@ -236,9 +345,7 @@ export function markRepositoryMutationStarted(input: {
236
345
  }): WorkHandleState | undefined {
237
346
  const store = { controllerHome: input.controllerHome, repoId: input.repository.repoId };
238
347
  const contract = getWorkContract(store, input.workId);
239
- if (contract?.workKind === 'local_effect' || contract?.workKind === 'remote_effect') {
240
- promoteWorkToRepositoryChange(store, input.workId);
241
- }
348
+ if (!contract) return undefined;
242
349
  const handle = readWorkHandle(input.controllerHome, input.repository.repoId, input.workId);
243
350
  if (!handle || handle.managedWorktree || handle.state !== 'prepared') return handle;
244
351
  const boundWorkId = handle.workContractId ?? handle.workId;
@@ -253,40 +360,30 @@ export function markRepositoryMutationStarted(input: {
253
360
  }
254
361
 
255
362
  /**
256
- * Upgrades an effect-only Work before the first governed repository mutation
257
- * and materializes the existing repository delivery authority. The durable
258
- * ControllerSession is the ownership source; the MCP transport session is not
259
- * allowed to become a second mutation authority.
363
+ * Materializes repository delivery authority for an optional semantic Work.
364
+ * Work is not a controller mutex or an execution-kind gate: authenticated caller
365
+ * identity is provenance while checkout/head/CAS/resource fences own mutation safety.
260
366
  */
261
367
  export function ensureRepositoryMutationWorkHandle(input: {
262
368
  controllerHome: string;
263
369
  repository: RepositoryRecord;
264
370
  workId: string;
265
371
  principalId: string;
372
+ sessionId?: string;
266
373
  deferEffectPromotion?: boolean;
267
374
  }): { handle: WorkHandleState; promotedFrom?: 'local_effect' | 'remote_effect' } {
268
375
  const store = { controllerHome: input.controllerHome, repoId: input.repository.repoId };
269
- let contract = getWorkContract(store, input.workId);
376
+ const contract = getWorkContract(store, input.workId);
270
377
  if (!contract) throw new Error(`WORK_NOT_FOUND: ${input.workId}`);
271
- if (isTerminalWorkContractStatus(contract.status) || contract.completionReceipt) {
378
+ if (semanticWorkState(contract) !== 'open') {
272
379
  throw new Error(`WORK_REPOSITORY_MUTATION_TERMINAL: ${input.workId}`);
273
380
  }
274
381
  const principalId = input.principalId.trim();
275
- if (!principalId) throw new Error(`WORK_CONTROLLER_AUTHENTICATED_PRINCIPAL_REQUIRED: ${input.workId}`);
276
- const owner = getControllerSession(store, input.workId);
277
- if (!owner) throw new Error(`WORK_CONTROLLER_CLAIM_REQUIRED: ${input.workId}`);
278
- if (controllerSessionPrincipalId(owner) !== principalId) {
279
- throw new Error(`WORK_CONTROLLER_OWNERSHIP_MISMATCH: ${input.workId}`);
280
- }
382
+ if (!principalId) throw new Error(`WORK_AUTHENTICATED_PRINCIPAL_REQUIRED: ${input.workId}`);
383
+ const provenanceSessionId = input.sessionId?.trim() || `sessionless:${principalId}`;
281
384
 
282
- let mutationCheckoutId = contract.checkoutId;
283
- if (!mutationCheckoutId) {
284
- if (contract.worktreeRef?.trim()) {
285
- throw new Error(`WORK_REPOSITORY_MUTATION_CHECKOUT_REQUIRED: ${input.workId}`);
286
- }
287
- mutationCheckoutId = input.repository.activeCheckoutId;
288
- contract = updateWorkContract(store, input.workId, { checkoutId: mutationCheckoutId });
289
- }
385
+ const mutationCheckoutId = contract.checkoutId?.trim() || input.repository.activeCheckoutId;
386
+ if (!mutationCheckoutId) throw new Error(`WORK_REPOSITORY_MUTATION_CHECKOUT_REQUIRED: ${input.workId}`);
290
387
  assertCanonicalRepositoryMutationWorkHandleAvailable({
291
388
  controllerHome: input.controllerHome,
292
389
  repositoryId: input.repository.repoId,
@@ -294,54 +391,36 @@ export function ensureRepositoryMutationWorkHandle(input: {
294
391
  workId: input.workId,
295
392
  });
296
393
 
297
- let promotedFrom: 'local_effect' | 'remote_effect' | undefined;
298
- if (contract.workKind === 'local_effect' || contract.workKind === 'remote_effect') {
299
- promotedFrom = contract.workKind;
300
- if (input.deferEffectPromotion !== true) {
301
- contract = promoteWorkToRepositoryChange(store, input.workId);
302
- }
303
- }
304
- if (contract.workKind !== 'repository_change' && input.deferEffectPromotion !== true) {
305
- throw new Error(`WORK_REPOSITORY_MUTATION_KIND_INVALID: ${input.workId}:${contract.workKind}`);
306
- }
394
+ // deferEffectPromotion is a compatibility input from the retired Work-kind
395
+ // lifecycle. Repository mutation is now admitted by the concrete target fence.
396
+ void input.deferEffectPromotion;
307
397
 
308
- const existingHandle = readWorkHandle(input.controllerHome, input.repository.repoId, input.workId);
309
398
  let handle = ensureRepositoryWorkHandle({
310
399
  controllerHome: input.controllerHome,
311
400
  repository: input.repository,
312
401
  workId: input.workId,
313
- identity: { sessionId: owner.sessionId, principalId },
314
- allowEffectWork: input.deferEffectPromotion === true,
402
+ identity: { sessionId: provenanceSessionId, principalId },
403
+ checkoutId: mutationCheckoutId,
404
+ allowEffectWork: true,
315
405
  });
316
406
  if (!handle) throw new Error(`WORK_REPOSITORY_MUTATION_HANDLE_REQUIRED: ${input.workId}`);
317
- handle = alignRepositoryMutationBase({
407
+ handle = rearmFailedPreservedWorkHandle({
318
408
  controllerHome: input.controllerHome,
319
409
  repository: input.repository,
320
410
  workId: input.workId,
321
411
  contract,
322
412
  handle,
323
- freshlyMaterialized: !existingHandle,
413
+ principalId,
414
+ sessionId: provenanceSessionId,
324
415
  });
325
- return { handle, ...(promotedFrom ? { promotedFrom } : {}) };
326
- }
327
-
328
- /**
329
- * Rebinds the durable WorkHandle to the Controller session that has already
330
- * been admitted by the ControllerSession authority. The compare-and-swap
331
- * revision on the read handle preserves fail-closed concurrent ownership.
332
- */
333
- export function rebindRepositoryWorkHandleControllerIdentity(input: {
334
- controllerHome: string;
335
- repositoryId: string;
336
- workId: string;
337
- identity: RepositoryWorkHandleControllerIdentity;
338
- }): WorkHandleState | undefined {
339
- const existing = readWorkHandle(input.controllerHome, input.repositoryId, input.workId);
340
- if (!existing) return undefined;
341
- if (existing.principalId === input.identity.principalId && existing.sessionId === input.identity.sessionId) return existing;
342
- return writeWorkHandle(input.controllerHome, {
343
- ...existing,
344
- principalId: input.identity.principalId,
345
- sessionId: input.identity.sessionId,
416
+ handle = rearmRetainedMergedWorkForMutation({
417
+ controllerHome: input.controllerHome,
418
+ repository: input.repository,
419
+ workId: input.workId,
420
+ contract,
421
+ handle,
346
422
  });
423
+ assertManagedRepositoryMutationAuthority({ repository: input.repository, handle });
424
+ return { handle };
347
425
  }
426
+
@@ -1,7 +1,7 @@
1
1
  import { randomUUID } from 'crypto';
2
2
  import { existsSync } from 'fs';
3
3
  import { join } from 'path';
4
- import { repositoryControllerRoot } from '../../../cli/repositories/controller-home';
4
+ import { scopedOperationRoot } from '../../../cli/repositories/controller-home';
5
5
  import { readJsonFile, sanitizeFileComponent } from '../../shared/json-files';
6
6
  import type { ProcessCheckExecutionIdentity } from '../../evidence/process-check-execution';
7
7
  import { listControlPlaneRecords, mutateControlPlaneRecord, readOrImportControlPlaneRecord, writeControlPlaneRecord } from '../persistence/sqlite-store';
@@ -227,7 +227,7 @@ export function resolveWorkDeliveryTargetBranch(
227
227
  }
228
228
 
229
229
  function workHandlePath(controllerHome: string, handle: Pick<WorkHandleState, 'repositoryId' | 'workId'>): string {
230
- return join(repositoryControllerRoot(controllerHome, handle.repositoryId), 'work-handles', `${sanitizeFileComponent(handle.workId)}.json`);
230
+ return join(scopedOperationRoot(controllerHome, handle.repositoryId), 'work-handles', `${sanitizeFileComponent(handle.workId)}.json`);
231
231
  }
232
232
 
233
233
  function now(): string {
@@ -376,6 +376,23 @@ export function writeWorkHandle(controllerHome: string, handle: WorkHandleState)
376
376
  return { ...record.value, recordRevision: record.revision };
377
377
  }
378
378
 
379
+ /**
380
+ * Refresh legacy controller identity fields as provenance only. Repository
381
+ * mutation authority remains WorkHandle CAS plus concrete checkout/resource fences.
382
+ */
383
+ export function rebindWorkHandleControllerIdentity(
384
+ controllerHome: string,
385
+ handle: WorkHandleState,
386
+ identity: { principalId: string; sessionId: string },
387
+ ): WorkHandleState {
388
+ if (handle.principalId === identity.principalId && handle.sessionId === identity.sessionId) return handle;
389
+ return writeWorkHandle(controllerHome, {
390
+ ...handle,
391
+ principalId: identity.principalId,
392
+ sessionId: identity.sessionId,
393
+ });
394
+ }
395
+
379
396
  const TRANSITIONS: Record<WorkHandleStateName, readonly WorkHandleStateName[]> = {
380
397
  prepared: ['editing', 'validating', 'committed', 'failed', 'failed_terminal_cleanup'],
381
398
  editing: ['validating', 'committed', 'merged', 'failed', 'failed_terminal_cleanup'],
@@ -404,47 +421,6 @@ export function transitionWorkHandle(
404
421
  });
405
422
  }
406
423
 
407
- export interface WorkHandleSuccessorAdoption {
408
- candidateHead: string;
409
- targetHead: string;
410
- }
411
-
412
- /**
413
- * Explicit WorkHandle authority transition for a conflict-repaired managed
414
- * candidate. Git lineage/scope/cleanliness must be proven by the finalizer
415
- * before this transition is called. Adopting a rewritten candidate never
416
- * transfers validation implicitly: the new source identity must obtain exact
417
- * verification/review authority before delivery can resume.
418
- */
419
- export function adoptWorkHandleSuccessorCandidate(
420
- controllerHome: string,
421
- handle: WorkHandleState,
422
- adoption: WorkHandleSuccessorAdoption,
423
- ): WorkHandleState {
424
- const candidateHead = adoption.candidateHead.trim();
425
- const targetHead = adoption.targetHead.trim();
426
- if (!handle.managedWorktree) throw new Error('WORK_SUCCESSOR_ADOPTION_MANAGED_CHECKOUT_REQUIRED');
427
- if (!candidateHead || !targetHead) throw new Error('WORK_SUCCESSOR_ADOPTION_REVISION_REQUIRED');
428
- if (candidateHead === handle.expectedHead) throw new Error('WORK_SUCCESSOR_ADOPTION_NO_CHANGE');
429
- return transitionWorkHandle(controllerHome, handle, 'validating', {
430
- deliveryBaseCommit: targetHead,
431
- expectedHead: candidateHead,
432
- failureReason: undefined,
433
- finalization: {
434
- ...handle.finalization,
435
- validation: 'pending',
436
- commit: 'done',
437
- merge: 'pending',
438
- branchCleanup: 'pending',
439
- worktreeCleanup: 'pending',
440
- failureCode: undefined, lastError: undefined,
441
- },
442
- validationRun: undefined,
443
- validatedInputFingerprint: undefined,
444
- cleanupReceipt: undefined,
445
- });
446
- }
447
-
448
424
  export function markWorkHandleFailed(controllerHome: string, handle: WorkHandleState, reason: string): WorkHandleState {
449
425
  return writeWorkHandle(controllerHome, {
450
426
  ...handle,
@@ -1,3 +1,4 @@
1
+ import { commandExecutionScopeKey, type RepositoryCommandScopeTarget } from '../../../cli/repositories/command-scope';
1
2
  import type { RepositoryRecord } from '../../../cli/repositories/types';
2
3
  import { repositoryGitStatus } from '../../../cli/repositories/structured-git';
3
4
  import type { ResolvedExecutionIdentity } from './execution-identity';
@@ -30,7 +31,7 @@ export interface WorkHeadSettlementResult {
30
31
  */
31
32
  export function settleWorkHandleExpectedHeadAfterRepositoryCommand(input: {
32
33
  controllerHome: string;
33
- repository: RepositoryRecord;
34
+ repository: RepositoryCommandScopeTarget;
34
35
  executionIdentity: ResolvedExecutionIdentity;
35
36
  workId?: string;
36
37
  ok?: boolean;
@@ -42,33 +43,65 @@ export function settleWorkHandleExpectedHeadAfterRepositoryCommand(input: {
42
43
  if (input.ok !== true || input.cancelled === true || input.timedOut === true) {
43
44
  return { settled: false, reason: 'command_not_successful' };
44
45
  }
45
- const handle = readWorkHandle(input.controllerHome, input.repository.repoId, workId);
46
- if (!handle) return { settled: false, reason: 'work_handle_missing' };
47
- if (
48
- handle.repositoryId !== input.executionIdentity.repositoryId
49
- || handle.checkoutId !== input.executionIdentity.checkoutId
50
- || handle.workId !== input.executionIdentity.workId
51
- || handle.branch !== input.executionIdentity.branch
52
- || (input.executionIdentity.expectedHead !== undefined && handle.expectedHead !== input.executionIdentity.expectedHead)
53
- ) return { settled: false, reason: 'identity_mismatch' };
54
- if (handle.state === 'merged' || handle.state === 'cleaned' || handle.state === 'failed_terminal_cleanup') {
46
+ const originalHandle = readWorkHandle(input.controllerHome, commandExecutionScopeKey(input.repository), workId);
47
+ if (!originalHandle) return { settled: false, reason: 'work_handle_missing' };
48
+ const sameStaticExecutionIdentity = (handle: typeof originalHandle): boolean => (
49
+ handle.repositoryId === input.executionIdentity.repositoryId
50
+ && handle.checkoutId === input.executionIdentity.checkoutId
51
+ && handle.workId === input.executionIdentity.workId
52
+ && handle.branch === input.executionIdentity.branch
53
+ );
54
+ if (!sameStaticExecutionIdentity(originalHandle)) return { settled: false, reason: 'identity_mismatch' };
55
+ if (originalHandle.state === 'merged' || originalHandle.state === 'cleaned' || originalHandle.state === 'failed_terminal_cleanup') {
55
56
  return { settled: false, reason: 'terminal_handle' };
56
57
  }
57
- const status = repositoryGitStatus(input.repository);
58
- if (!status.branch || status.branch !== handle.branch) {
59
- return { settled: false, reason: 'branch_changed', previousHead: handle.expectedHead, currentHead: status.head ?? undefined };
58
+ // A Work head settlement only runs for a Work-bound (repository) command, so
59
+ // the scope target is a registered repository record at this point.
60
+ const status = repositoryGitStatus(input.repository as RepositoryRecord);
61
+ if (!status.branch || status.branch !== originalHandle.branch) {
62
+ return { settled: false, reason: 'branch_changed', previousHead: originalHandle.expectedHead, currentHead: status.head ?? undefined };
60
63
  }
61
64
  const currentHead = status.head?.trim();
62
- if (!currentHead) return { settled: false, reason: 'head_unavailable', previousHead: handle.expectedHead };
63
- if (currentHead === handle.expectedHead) {
64
- return { settled: false, reason: 'head_unchanged', previousHead: handle.expectedHead, currentHead };
65
+ if (!currentHead) return { settled: false, reason: 'head_unavailable', previousHead: originalHandle.expectedHead };
66
+ const originalAuthorityHead = input.executionIdentity.expectedHead;
67
+ if (originalHandle.expectedHead === currentHead) {
68
+ if (originalAuthorityHead !== undefined && originalAuthorityHead !== currentHead) {
69
+ return { settled: true, reason: 'settled', previousHead: originalAuthorityHead, currentHead };
70
+ }
71
+ return { settled: false, reason: 'head_unchanged', previousHead: originalHandle.expectedHead, currentHead };
72
+ }
73
+ if (originalAuthorityHead !== undefined && originalHandle.expectedHead !== originalAuthorityHead) {
74
+ return { settled: false, reason: 'identity_mismatch', previousHead: originalHandle.expectedHead, currentHead };
75
+ }
76
+ try {
77
+ transitionWorkHandle(input.controllerHome, originalHandle, originalHandle.state, { expectedHead: currentHead });
78
+ return { settled: true, reason: 'settled', previousHead: originalHandle.expectedHead, currentHead };
79
+ } catch (error) {
80
+ if (!(error instanceof Error) || !error.message.includes('CONTROL_PLANE_REVISION_CONFLICT')) throw error;
81
+ }
82
+
83
+ // One concurrent lifecycle write is allowed to win the first CAS. Re-read the
84
+ // exact Work authority and converge only when identity/branch are unchanged.
85
+ const refreshedHandle = readWorkHandle(input.controllerHome, commandExecutionScopeKey(input.repository), workId);
86
+ if (!refreshedHandle) return { settled: false, reason: 'work_handle_missing', previousHead: originalHandle.expectedHead, currentHead };
87
+ if (!sameStaticExecutionIdentity(refreshedHandle)) {
88
+ return { settled: false, reason: 'identity_mismatch', previousHead: refreshedHandle.expectedHead, currentHead };
89
+ }
90
+ if (refreshedHandle.expectedHead !== currentHead && originalAuthorityHead !== undefined && refreshedHandle.expectedHead !== originalAuthorityHead) {
91
+ return { settled: false, reason: 'identity_mismatch', previousHead: refreshedHandle.expectedHead, currentHead };
92
+ }
93
+ if (refreshedHandle.state === 'merged' || refreshedHandle.state === 'cleaned' || refreshedHandle.state === 'failed_terminal_cleanup') {
94
+ return { settled: false, reason: 'terminal_handle', previousHead: refreshedHandle.expectedHead, currentHead };
95
+ }
96
+ if (refreshedHandle.expectedHead === currentHead) {
97
+ return { settled: true, reason: 'settled', previousHead: originalHandle.expectedHead, currentHead };
65
98
  }
66
99
  try {
67
- transitionWorkHandle(input.controllerHome, handle, handle.state, { expectedHead: currentHead });
68
- return { settled: true, reason: 'settled', previousHead: handle.expectedHead, currentHead };
100
+ transitionWorkHandle(input.controllerHome, refreshedHandle, refreshedHandle.state, { expectedHead: currentHead });
101
+ return { settled: true, reason: 'settled', previousHead: refreshedHandle.expectedHead, currentHead };
69
102
  } catch (error) {
70
103
  if (error instanceof Error && error.message.includes('CONTROL_PLANE_REVISION_CONFLICT')) {
71
- return { settled: false, reason: 'concurrent_lifecycle_write', previousHead: handle.expectedHead, currentHead };
104
+ return { settled: false, reason: 'concurrent_lifecycle_write', previousHead: refreshedHandle.expectedHead, currentHead };
72
105
  }
73
106
  throw error;
74
107
  }