@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
@@ -1,9 +1,9 @@
1
1
  import { readForgeInstanceIdentity } from '../../../../packages/kernel/identity/api/index';
2
2
  import { resolveProjectForRepositoryPlacement } from '../workspace/workspace-store';
3
3
  import type { ScopeRef } from '../../../../packages/kernel/identity/api/index';
4
- import type { ExperienceRecord, ExperienceStorePort, OutcomeObservation, OutcomeObservationStorePort } from '../../../../packages/kernel/memory/api/index';
5
- import { getWorkContract, isTerminalWorkContractStatus, type WorkContract } from '../../../../packages/kernel/work/api/index';
6
- import { controllerSessionAuthorityMatches, getControllerRoundRelay, getControllerSession } from '../../../../packages/kernel/controller/api/index';
4
+ import { recordExperience, recordOutcomeObservation, type ExperienceRecord, type ExperienceStorePort, type OutcomeObservation, type OutcomeObservationStorePort } from '../../../../packages/kernel/memory/api/index';
5
+ import { getWorkContract, isTerminalSemanticWorkState, type WorkContract } from '../../../../packages/kernel/work/api/index';
6
+ import { getControllerRoundRelay } from '../../../../packages/kernel/controller/api/index';
7
7
  import { readExecutionArtifact } from '../../evidence/artifact-store';
8
8
  import { readExecutionEvidence } from '../../evidence/evidence-store';
9
9
  import { assertControlPlaneMetadataPayload } from './metadata-payload-policy';
@@ -12,14 +12,45 @@ import { deleteControlPlaneRecordWithinTransaction, listControlPlaneRecords, lis
12
12
 
13
13
  export const EXPERIENCE_NAMESPACE = 'assistant_experience';
14
14
  export const OUTCOME_OBSERVATION_NAMESPACE = 'assistant_outcome_observation';
15
- export interface ExperienceWriteIdentity { workId: string; controllerId: string; authorityId: string }
15
+ export interface ExperienceWriteIdentity {
16
+ workId: string;
17
+ /** Legacy provenance only; never execution or write authority. */
18
+ controllerId?: string;
19
+ /** Legacy provenance only; never execution or write authority. */
20
+ authorityId?: string;
21
+ }
22
+ export interface ClosedRoundLearningAuthority { workId: string; sourceRoundId: string }
23
+
24
+ interface ExperienceStoreOptions {
25
+ controllerHome: string;
26
+ repoId: string;
27
+ identity?: ExperienceWriteIdentity;
28
+ closedRoundAuthority?: ClosedRoundLearningAuthority;
29
+ now?: () => string;
30
+ }
31
+
32
+ function resolvedProjectForWork(work: WorkContract, controllerHome?: string) {
33
+ if (!controllerHome) return undefined;
34
+ const instance = readForgeInstanceIdentity(controllerHome);
35
+ if (!instance) return undefined;
36
+ const declaredProject = work.scopeRef?.kind === 'project'
37
+ ? work.scopeRef.id
38
+ : work.engineeringContext?.projectContractReceipt?.projectId;
39
+ return resolveProjectForRepositoryPlacement({
40
+ controllerHome,
41
+ forgeInstanceId: instance.instanceId,
42
+ repositoryId: work.repoId,
43
+ checkoutId: work.checkoutId,
44
+ projectId: declaredProject,
45
+ });
46
+ }
16
47
 
17
48
  export function experienceScopesForWork(work: WorkContract, controllerHome?: string): ScopeRef[] {
18
49
  const scopes: ScopeRef[] = [{ schemaVersion: 1, kind: 'work', id: work.workId }];
19
- const declaredProject = work.scopeRef?.kind === 'project' ? work.scopeRef.id : work.engineeringContext?.projectContractReceipt?.projectId;
20
- const instance = controllerHome ? readForgeInstanceIdentity(controllerHome) : undefined;
21
- const projectId = controllerHome && instance ? resolveProjectForRepositoryPlacement({ controllerHome,
22
- forgeInstanceId: instance.instanceId, repositoryId: work.repoId, checkoutId: work.checkoutId, projectId: declaredProject })?.projectId ?? declaredProject : declaredProject;
50
+ const declaredProject = work.scopeRef?.kind === 'project'
51
+ ? work.scopeRef.id
52
+ : work.engineeringContext?.projectContractReceipt?.projectId;
53
+ const projectId = resolvedProjectForWork(work, controllerHome)?.projectId ?? declaredProject;
23
54
  if (projectId) scopes.push({ schemaVersion: 1, kind: 'project', id: projectId });
24
55
  if (work.requirementId) scopes.push({ schemaVersion: 1, kind: 'requirement', id: work.requirementId });
25
56
  if (work.planId) scopes.push({ schemaVersion: 1, kind: 'plan', id: work.planId });
@@ -28,23 +59,62 @@ export function experienceScopesForWork(work: WorkContract, controllerHome?: str
28
59
  return scopes;
29
60
  }
30
61
 
31
- function matchesScope(work: WorkContract, scope: ScopeRef, controllerHome: string): boolean {
62
+ /**
63
+ * Cognitive recall may include portable Workspace guidance shared by sibling
64
+ * Projects. Raw Controller/Experience writes deliberately remain limited to
65
+ * experienceScopesForWork so project-local observations cannot bypass
66
+ * evidence-backed promotion into cross-project memory.
67
+ */
68
+ export function cognitiveScopesForWork(work: WorkContract, controllerHome?: string): ScopeRef[] {
69
+ const scopes = experienceScopesForWork(work, controllerHome);
70
+ const workspaceId = resolvedProjectForWork(work, controllerHome)?.workspaceId;
71
+ if (workspaceId && !scopes.some(scope => scope.kind === 'workspace' && scope.id === workspaceId)) {
72
+ scopes.push({ schemaVersion: 1, kind: 'workspace', id: workspaceId });
73
+ }
74
+ return scopes;
75
+ }
76
+
77
+ function matchesExperienceScope(work: WorkContract, scope: ScopeRef, controllerHome: string): boolean {
32
78
  return experienceScopesForWork(work, controllerHome).some(candidate => candidate.kind === scope.kind && candidate.id === scope.id);
33
79
  }
34
80
 
35
- function canonicalWorkflowEvidenceAvailable(input: { controllerHome: string; repoId: string }, ref: string, scope: ScopeRef, sourceWorkId: string): boolean {
81
+ function matchesCognitiveScope(work: WorkContract, scope: ScopeRef, controllerHome: string): boolean {
82
+ return cognitiveScopesForWork(work, controllerHome).some(candidate => candidate.kind === scope.kind && candidate.id === scope.id);
83
+ }
84
+
85
+ function isLegacyOutputLocatorMiss(error: unknown, kind: 'artifact' | 'evidence'): boolean {
86
+ const message = error instanceof Error ? error.message : String(error);
87
+ return kind === 'artifact'
88
+ ? message.startsWith('ARTIFACT_LOCATOR_NOT_FOUND:')
89
+ : message.startsWith('EVIDENCE_LOCATOR_NOT_FOUND:');
90
+ }
91
+
92
+ export function canonicalWorkflowEvidenceAvailable(input: { controllerHome: string; repoId: string }, ref: string, scope: ScopeRef, sourceWorkId: string): boolean {
36
93
  try {
37
94
  const source = getWorkContract(input, sourceWorkId);
38
- if (!source || !matchesScope(source, scope, input.controllerHome)) return false;
95
+ if (!source || !matchesCognitiveScope(source, scope, input.controllerHome)) return false;
39
96
  const linked = source.evidenceRefs.find(item => item.evidenceId === ref || item.artifactId === ref);
40
97
  if (linked) {
41
98
  if (ref.startsWith('ART-')) {
42
- const artifact = readExecutionArtifact(input.controllerHome, input.repoId, ref, 16 * 1024);
99
+ let artifact;
100
+ try {
101
+ artifact = readExecutionArtifact(input.controllerHome, ref, 16 * 1024);
102
+ } catch (error) {
103
+ if (!isLegacyOutputLocatorMiss(error, 'artifact')) throw error;
104
+ artifact = readExecutionArtifact(input.controllerHome, ref, 16 * 1024, { legacyRepoId: input.repoId });
105
+ }
43
106
  return !artifact.truncated && artifact.artifact.kind === 'evidence';
44
107
  }
45
- if (ref.startsWith('EVD-')) return readExecutionEvidence(input.controllerHome, input.repoId, ref).evidenceId === ref;
108
+ if (ref.startsWith('EVD-')) {
109
+ try { return readExecutionEvidence(input.controllerHome, ref).evidenceId === ref; }
110
+ catch (error) {
111
+ if (!isLegacyOutputLocatorMiss(error, 'evidence')) throw error;
112
+ return readExecutionEvidence(input.controllerHome, ref, { legacyRepoId: input.repoId }).evidenceId === ref;
113
+ }
114
+ }
46
115
  }
47
116
  if (source.checkRefs.some(check => check.receipt?.receiptId === ref && ['passed', 'failed'].includes(check.receipt.status))) return true;
117
+ if (source.engineeringContext?.blockerDispositions?.some(disposition => disposition.receiptId === ref)) return true;
48
118
  if (ref.startsWith('workflow-run-') || ref.startsWith('workflow-publication-')) {
49
119
  const runs = listControlPlaneRecords<WorkflowRunRecord>(input.controllerHome, { namespace: WORKFLOW_RUN_NAMESPACE, scope: sourceWorkId, limit: 1000 });
50
120
  return runs.some(row => row.value.evidenceRef === ref || row.value.publicationReceipt?.receiptId === ref);
@@ -57,23 +127,58 @@ function canonicalWorkflowEvidenceAvailable(input: { controllerHome: string; rep
57
127
  } catch { return false; }
58
128
  }
59
129
 
60
- function assertMemoryWriteAuthority(input: { controllerHome: string; repoId: string; identity?: ExperienceWriteIdentity }, scope: ScopeRef, sourceWorkId: string, sourceRoundId: string): void {
130
+ export function workExperienceProvenance(work: Pick<WorkContract, 'workId' | 'semanticRevision'>): string {
131
+ const revision = Number(work.semanticRevision);
132
+ return `work:${work.workId}:r${Number.isSafeInteger(revision) && revision > 0 ? revision : 'legacy'}`;
133
+ }
134
+
135
+ export function assertMemoryWriteAuthority(input: { controllerHome: string; repoId: string; identity?: ExperienceWriteIdentity }, scope: ScopeRef, sourceWorkId: string, sourceRoundId: string): void {
61
136
  const identity = input.identity;
62
- if (!identity) throw new Error('EXPERIENCE_CONTROLLER_REQUIRED');
63
- const current = getWorkContract(input, identity.workId), source = getWorkContract(input, sourceWorkId);
64
- if (!current || isTerminalWorkContractStatus(current.status) || !source || !matchesScope(current, scope, input.controllerHome) || !matchesScope(source, scope, input.controllerHome)) throw new Error('EXPERIENCE_WORK_SCOPE_MISMATCH');
65
- const owner = getControllerSession(input, identity.workId);
66
- if (!owner || owner.controllerId !== identity.controllerId) throw new Error('EXPERIENCE_CONTROLLER_NOT_OWNER');
67
- const relay = getControllerRoundRelay(input, identity.workId);
68
- if (relay) {
69
- if (relay.status !== 'claimed' || relay.authorityId !== identity.authorityId || relay.claimGeneration !== owner.claimGeneration
70
- || sourceRoundId !== `${relay.relayScopeId}:${relay.roundCount}`) throw new Error('EXPERIENCE_ROUND_AUTHORITY_MISMATCH');
71
- } else if (!controllerSessionAuthorityMatches(owner, identity.authorityId)
72
- || sourceRoundId !== `${identity.workId}:${owner.claimGeneration}`) throw new Error('EXPERIENCE_CLAIM_AUTHORITY_MISMATCH');
137
+ if (!identity?.workId?.trim()) throw new Error('EXPERIENCE_WORK_IDENTITY_REQUIRED');
138
+ const current = getWorkContract(input, identity.workId);
139
+ const source = getWorkContract(input, sourceWorkId);
140
+ if (!current || isTerminalSemanticWorkState(current.semanticState) || !source
141
+ || current.workId !== source.workId
142
+ || !matchesExperienceScope(current, scope, input.controllerHome)
143
+ || !matchesExperienceScope(source, scope, input.controllerHome)) {
144
+ throw new Error('EXPERIENCE_WORK_SCOPE_MISMATCH');
145
+ }
146
+ if (sourceRoundId !== workExperienceProvenance(source)) {
147
+ throw new Error('EXPERIENCE_WORK_PROVENANCE_MISMATCH');
148
+ }
149
+ }
150
+
151
+ function assertClosedRoundLearningWriteAuthority(
152
+ input: Pick<ExperienceStoreOptions, 'controllerHome' | 'repoId' | 'closedRoundAuthority'>,
153
+ scope: ScopeRef,
154
+ sourceWorkId: string,
155
+ sourceRoundId: string,
156
+ ): void {
157
+ const authority = input.closedRoundAuthority;
158
+ if (!authority || authority.workId !== sourceWorkId || authority.sourceRoundId !== sourceRoundId) {
159
+ throw new Error('EXPERIENCE_CLOSED_ROUND_AUTHORITY_MISMATCH');
160
+ }
161
+ const work = getWorkContract(input, authority.workId);
162
+ if (!work || isTerminalSemanticWorkState(work.semanticState) || !matchesExperienceScope(work, scope, input.controllerHome)) {
163
+ throw new Error('EXPERIENCE_CLOSED_ROUND_WORK_SCOPE_MISMATCH');
164
+ }
165
+ const relay = getControllerRoundRelay(input, authority.workId);
166
+ if (!relay?.observationWindow?.some(observation => observation.roundRef === sourceRoundId)) {
167
+ throw new Error('EXPERIENCE_CLOSED_ROUND_NOT_OBSERVED');
168
+ }
169
+ }
170
+
171
+ function assertExperienceStoreWriteAuthority(input: ExperienceStoreOptions, scope: ScopeRef, sourceWorkId: string, sourceRoundId: string): void {
172
+ if (input.identity && input.closedRoundAuthority) throw new Error('EXPERIENCE_WRITE_AUTHORITY_AMBIGUOUS');
173
+ if (input.closedRoundAuthority) {
174
+ assertClosedRoundLearningWriteAuthority(input, scope, sourceWorkId, sourceRoundId);
175
+ return;
176
+ }
177
+ assertMemoryWriteAuthority(input, scope, sourceWorkId, sourceRoundId);
73
178
  }
74
179
 
75
180
  /** One SQLite writer; nested domain operations share the same transaction. */
76
- export function controllerExperienceStore(input: { controllerHome: string; repoId: string; identity?: ExperienceWriteIdentity; now?: () => string }): ExperienceStorePort {
181
+ export function controllerExperienceStore(input: ExperienceStoreOptions): ExperienceStorePort {
77
182
  let transaction: SqliteDatabase | undefined;
78
183
  const key = (scope: ScopeRef) => `${scope.kind}:${scope.id}`;
79
184
  const work = (id: string) => getWorkContract(input, id);
@@ -86,7 +191,7 @@ export function controllerExperienceStore(input: { controllerHome: string; repoI
86
191
  });
87
192
  },
88
193
  assertWriteAuthority(scope, sourceWorkId, sourceRoundId) {
89
- assertMemoryWriteAuthority(input, scope, sourceWorkId, sourceRoundId);
194
+ assertExperienceStoreWriteAuthority(input, scope, sourceWorkId, sourceRoundId);
90
195
  },
91
196
  evidenceAvailable(ref, scope, sourceWorkId) {
92
197
  return canonicalWorkflowEvidenceAvailable(input, ref, scope, sourceWorkId);
@@ -113,7 +218,21 @@ export function controllerExperienceStore(input: { controllerHome: string; repoI
113
218
  };
114
219
  }
115
220
 
116
- export function controllerOutcomeObservationStore(input: { controllerHome: string; repoId: string; identity?: ExperienceWriteIdentity; now?: () => string }): OutcomeObservationStorePort {
221
+ export function recordClosedRoundExperience(input: {
222
+ controllerHome: string;
223
+ repoId: string;
224
+ authority: ClosedRoundLearningAuthority;
225
+ record: ExperienceRecord;
226
+ now?: string;
227
+ }): ExperienceRecord {
228
+ return recordExperience(
229
+ controllerExperienceStore({ controllerHome: input.controllerHome, repoId: input.repoId, closedRoundAuthority: input.authority }),
230
+ input.record,
231
+ input.now,
232
+ );
233
+ }
234
+
235
+ export function controllerOutcomeObservationStore(input: ExperienceStoreOptions): OutcomeObservationStorePort {
117
236
  let transaction: SqliteDatabase | undefined;
118
237
  const key = (scope: ScopeRef) => `${scope.kind}:${scope.id}`;
119
238
  return {
@@ -124,7 +243,7 @@ export function controllerOutcomeObservationStore(input: { controllerHome: strin
124
243
  try { return operation(); } finally { transaction = undefined; }
125
244
  });
126
245
  },
127
- assertWriteAuthority(scope, sourceWorkId, sourceRoundId) { assertMemoryWriteAuthority(input, scope, sourceWorkId, sourceRoundId); },
246
+ assertWriteAuthority(scope, sourceWorkId, sourceRoundId) { assertExperienceStoreWriteAuthority(input, scope, sourceWorkId, sourceRoundId); },
128
247
  evidenceAvailable(ref, scope, sourceWorkId) { return canonicalWorkflowEvidenceAvailable(input, ref, scope, sourceWorkId); },
129
248
  read(scope, id) {
130
249
  const row = transaction ? readControlPlaneRecordWithinTransaction<OutcomeObservation>(transaction, OUTCOME_OBSERVATION_NAMESPACE, key(scope), id)
@@ -146,6 +265,20 @@ export function controllerOutcomeObservationStore(input: { controllerHome: strin
146
265
  };
147
266
  }
148
267
 
268
+ export function recordClosedRoundOutcomeObservation(input: {
269
+ controllerHome: string;
270
+ repoId: string;
271
+ authority: ClosedRoundLearningAuthority;
272
+ observation: OutcomeObservation;
273
+ now?: string;
274
+ }): OutcomeObservation {
275
+ return recordOutcomeObservation(
276
+ controllerOutcomeObservationStore({ controllerHome: input.controllerHome, repoId: input.repoId, closedRoundAuthority: input.authority }),
277
+ input.observation,
278
+ input.now,
279
+ );
280
+ }
281
+
149
282
  /** Called by central maintenance, never by recall. A 30-day terminal grace preserves diagnosis. */
150
283
  export function cleanupExpiredExperiences(controllerHome: string, now = new Date().toISOString(), limit = 100): number {
151
284
  const at = Date.parse(now);
@@ -1,5 +1,6 @@
1
1
  import {
2
2
  listControlPlaneRecords,
3
+ listControlPlaneRecordsWithinTransaction,
3
4
  readControlPlaneRecord,
4
5
  readControlPlaneRecordWithinTransaction,
5
6
  withControlPlaneTransaction,
@@ -7,8 +8,8 @@ import {
7
8
  type ControlPlaneRecord,
8
9
  type SqliteDatabase,
9
10
  } from './sqlite-store';
10
- import { isRepositoryCompletionReceipt, type WorkContract } from '../facade/types';
11
11
  import { REQUIREMENT_STATE_TRANSITIONS, type RequirementState } from '../../../../packages/kernel/goal/api/index';
12
+ import type { ScopeRef } from '../../../../packages/kernel/identity/api/index';
12
13
  export { REQUIREMENT_STATES, type RequirementState } from '../../../../packages/kernel/goal/api/index';
13
14
 
14
15
  export interface Requirement {
@@ -30,6 +31,10 @@ export interface Requirement {
30
31
  planIds: string[];
31
32
  acceptedAt: string;
32
33
  };
34
+ /** Semantic authored-context revision. Legacy rows normalize to semantic revision 1 until first thin semantic write. */
35
+ semanticRevision?: number;
36
+ /** Timestamp of the authored semantic content; mechanical Requirement updates must not change it. */
37
+ semanticUpdatedAt?: string;
33
38
  revision: number;
34
39
  createdAt: string;
35
40
  updatedAt: string;
@@ -48,9 +53,41 @@ export interface CreateRequirementInput {
48
53
  outcomeStatement: string;
49
54
  acceptanceCriteria?: string[];
50
55
  requiredDeliveryReferences?: string[];
56
+ /** Authority-derived provenance only; raw transports must not pass arbitrary audit refs. */
57
+ auditRefs?: string[];
58
+ }
59
+
60
+ export type SemanticRequirementState = 'open' | 'completed' | 'cancelled';
61
+
62
+ export interface RequirementSemanticView {
63
+ requirementId: string;
64
+ revision: number;
65
+ semanticScope: ScopeRef;
66
+ title: string;
67
+ outcomeStatement: string;
68
+ acceptanceCriteria: string[];
69
+ requiredDeliveryReferences: string[];
70
+ state: SemanticRequirementState;
71
+ createdAt: string;
72
+ updatedAt: string;
73
+ }
74
+
75
+ export interface RequirementRevisionRecord extends RequirementSemanticView {
76
+ schemaVersion: 1;
77
+ recordedAt: string;
78
+ }
79
+
80
+ export interface ReviseRequirementSemanticInput {
81
+ expectedRevision: number;
82
+ title?: string;
83
+ outcomeStatement?: string;
84
+ acceptanceCriteria?: string[];
85
+ requiredDeliveryReferences?: string[];
86
+ state?: SemanticRequirementState;
51
87
  }
52
88
 
53
89
  const NAMESPACE = 'requirement';
90
+ const REVISION_NAMESPACE = 'requirement_revision';
54
91
  const SCOPE = 'controller';
55
92
  const SCHEMA_VERSION = 1;
56
93
 
@@ -68,6 +105,36 @@ function bounded(values: readonly string[] | undefined, limit: number, maxLength
68
105
  return (values ?? []).map((value) => String(value).trim()).filter(Boolean).slice(0, limit).map((value) => value.slice(0, maxLength));
69
106
  }
70
107
 
108
+ export function currentRequirementSemanticRevision(requirement: Requirement): number {
109
+ const semantic = Number(requirement.semanticRevision);
110
+ return Number.isInteger(semantic) && semantic > 0 ? semantic : 1;
111
+ }
112
+
113
+ export function semanticRequirementState(requirement: Pick<Requirement, 'state'>): SemanticRequirementState {
114
+ if (requirement.state === 'done') return 'completed';
115
+ if (requirement.state === 'cancelled') return 'cancelled';
116
+ return 'open';
117
+ }
118
+
119
+ export function requirementSemanticView(requirement: Requirement): RequirementSemanticView {
120
+ return {
121
+ requirementId: requirement.requirementId,
122
+ revision: currentRequirementSemanticRevision(requirement),
123
+ semanticScope: { schemaVersion: 1, kind: 'requirement', id: requirement.requirementId },
124
+ title: requirement.title,
125
+ outcomeStatement: requirement.outcomeStatement,
126
+ acceptanceCriteria: [...requirement.acceptanceCriteria],
127
+ requiredDeliveryReferences: [...requirement.requiredDeliveryReferences],
128
+ state: semanticRequirementState(requirement),
129
+ createdAt: requirement.createdAt,
130
+ updatedAt: requirement.semanticUpdatedAt ?? requirement.createdAt,
131
+ };
132
+ }
133
+
134
+ function requirementRevisionKey(requirementId: string, revision: number): string {
135
+ return `${id(requirementId)}:r${revision}`;
136
+ }
137
+
71
138
  export function isLegacyMachineRequirementWait(requirement: Pick<Requirement, 'state' | 'attentionSummary'>): boolean {
72
139
  return requirement.state === 'waiting_for_user'
73
140
  && /^Work .+ delivered machine-valid evidence \(.+\); ChatGPT\/user semantic acceptance is still required\.$/.test(requirement.attentionSummary ?? '');
@@ -95,6 +162,98 @@ export function listRequirements(
95
162
  });
96
163
  }
97
164
 
165
+ /** Exact historical lookup, independent of global revision-list limits. */
166
+ export function getRequirementRevisionRecord(
167
+ options: RequirementStoreOptions,
168
+ requirementId: string,
169
+ revision: number,
170
+ ): RequirementRevisionRecord | undefined {
171
+ if (!Number.isInteger(revision) || revision < 1) return undefined;
172
+ const record = readControlPlaneRecord<RequirementRevisionRecord>(
173
+ options.controllerHome, REVISION_NAMESPACE, SCOPE, requirementRevisionKey(requirementId, revision),
174
+ )?.value;
175
+ return record ? {
176
+ ...record,
177
+ semanticScope: record.semanticScope ?? { schemaVersion: 1, kind: 'requirement', id: record.requirementId },
178
+ } : undefined;
179
+ }
180
+
181
+ export function listRequirementRevisionRecords(
182
+ options: RequirementStoreOptions,
183
+ requirementId?: string,
184
+ limit = 200,
185
+ ): RequirementRevisionRecord[] {
186
+ const normalizedId = requirementId ? id(requirementId) : undefined;
187
+ return listControlPlaneRecords<RequirementRevisionRecord>(options.controllerHome, {
188
+ namespace: REVISION_NAMESPACE,
189
+ scope: SCOPE,
190
+ limit: Math.max(1, Math.min(Math.trunc(limit), 1000)),
191
+ }).map((record) => record.value)
192
+ .filter((record) => !normalizedId || record.requirementId === normalizedId)
193
+ .map((record) => ({
194
+ ...record,
195
+ semanticScope: record.semanticScope ?? ({ schemaVersion: 1, kind: 'requirement', id: record.requirementId } as const),
196
+ }))
197
+ .sort((left, right) => right.revision - left.revision);
198
+ }
199
+
200
+ export function reviseRequirementSemantic(
201
+ options: RequirementStoreOptions,
202
+ requirementIdInput: string,
203
+ input: ReviseRequirementSemanticInput,
204
+ ): Requirement {
205
+ const requirementId = id(requirementIdInput);
206
+ if (!Number.isInteger(input.expectedRevision) || input.expectedRevision < 1) throw new Error('REQUIREMENT_EXPECTED_REVISION_INVALID');
207
+ return withControlPlaneTransaction(options.controllerHome, (database) => {
208
+ const current = readWithin(database, requirementId);
209
+ if (!current) throw new Error(`REQUIREMENT_NOT_FOUND: ${requirementId}`);
210
+ const semanticRevision = currentRequirementSemanticRevision(current.value);
211
+ if (semanticRevision !== input.expectedRevision) {
212
+ throw new Error(`REQUIREMENT_REVISION_CONFLICT:${requirementId}:expected=${input.expectedRevision}:actual=${semanticRevision}`);
213
+ }
214
+ const at = nowIso(options);
215
+ const revisionKey = requirementRevisionKey(requirementId, semanticRevision);
216
+ if (!readControlPlaneRecordWithinTransaction<RequirementRevisionRecord>(database, REVISION_NAMESPACE, SCOPE, revisionKey)) {
217
+ const archived: RequirementRevisionRecord = { schemaVersion: 1, ...requirementSemanticView(current.value), recordedAt: at };
218
+ writeControlPlaneRecordWithinTransaction(database, {
219
+ namespace: REVISION_NAMESPACE, scope: SCOPE, key: revisionKey, schemaVersion: 1,
220
+ value: archived, action: 'requirement_semantic_revision_archived', expectedRevision: null,
221
+ });
222
+ }
223
+ const requestedState = input.state;
224
+ if (requestedState === 'open' && (current.value.state === 'done' || current.value.state === 'cancelled')) {
225
+ throw new Error(`REQUIREMENT_SEMANTIC_REOPEN_FORBIDDEN:${requirementId}:${current.value.state}`);
226
+ }
227
+ const legacyState: RequirementState = requestedState === 'completed'
228
+ ? 'done'
229
+ : requestedState === 'cancelled'
230
+ ? 'cancelled'
231
+ : requestedState === 'open'
232
+ ? 'active'
233
+ : current.value.state;
234
+ const title = input.title === undefined ? current.value.title : String(input.title).trim().slice(0, 500);
235
+ const outcomeStatement = input.outcomeStatement === undefined ? current.value.outcomeStatement : String(input.outcomeStatement).trim().slice(0, 2_000);
236
+ if (!title || !outcomeStatement) throw new Error('REQUIREMENT_CONTENT_REQUIRED');
237
+ const updated: Requirement = {
238
+ ...current.value,
239
+ title,
240
+ outcomeStatement,
241
+ acceptanceCriteria: input.acceptanceCriteria === undefined ? [...current.value.acceptanceCriteria] : bounded(input.acceptanceCriteria, 50),
242
+ requiredDeliveryReferences: input.requiredDeliveryReferences === undefined ? [...current.value.requiredDeliveryReferences] : bounded(input.requiredDeliveryReferences, 50),
243
+ state: legacyState,
244
+ ...(requestedState ? { needsAttention: false, attentionSummary: undefined } : {}),
245
+ semanticRevision: semanticRevision + 1,
246
+ semanticUpdatedAt: at,
247
+ revision: current.value.revision + 1,
248
+ updatedAt: at,
249
+ };
250
+ return writeControlPlaneRecordWithinTransaction(database, {
251
+ namespace: NAMESPACE, scope: SCOPE, key: requirementId, schemaVersion: SCHEMA_VERSION,
252
+ value: updated, action: 'requirement_semantic_revised', expectedRevision: current.revision,
253
+ }).value;
254
+ });
255
+ }
256
+
98
257
  export function createRequirement(
99
258
  options: RequirementStoreOptions,
100
259
  input: CreateRequirementInput,
@@ -109,16 +268,29 @@ export function createRequirement(
109
268
  outcomeStatement: String(input.outcomeStatement ?? '').trim().slice(0, 2_000),
110
269
  acceptanceCriteria: bounded(input.acceptanceCriteria, 50),
111
270
  requiredDeliveryReferences: bounded(input.requiredDeliveryReferences, 50),
271
+ auditRefs: bounded(input.auditRefs, 50),
112
272
  state: 'planned',
113
273
  needsAttention: false,
274
+ semanticRevision: 1,
275
+ semanticUpdatedAt: at,
114
276
  revision: 1,
115
277
  createdAt: at,
116
278
  updatedAt: at,
117
- auditRefs: [],
118
279
  };
119
280
  if (!requirement.title || !requirement.outcomeStatement) throw new Error('REQUIREMENT_CONTENT_REQUIRED');
120
281
  withControlPlaneTransaction(options.controllerHome, (database) => {
121
282
  if (readWithin(database, requirementId)) throw new Error(`REQUIREMENT_ALREADY_EXISTS: ${requirementId}`);
283
+ const exclusiveCandidateRefs = requirement.auditRefs.filter(ref => ref.startsWith('cognitive-requirement-candidate:'));
284
+ if (exclusiveCandidateRefs.length > 0) {
285
+ const existing = listControlPlaneRecordsWithinTransaction<Requirement>(database, {
286
+ namespace: NAMESPACE,
287
+ scope: SCOPE,
288
+ limit: 1000,
289
+ });
290
+ if (existing.length >= 1000) throw new Error('REQUIREMENT_CANDIDATE_BINDING_LOOKUP_LIMIT');
291
+ const alreadyBound = existing.find(record => exclusiveCandidateRefs.some(ref => record.value.auditRefs.includes(ref)));
292
+ if (alreadyBound) throw new Error('REQUIREMENT_CANDIDATE_ALREADY_PROMOTED');
293
+ }
122
294
  writeControlPlaneRecordWithinTransaction(database, {
123
295
  namespace: NAMESPACE,
124
296
  scope: SCOPE,
@@ -132,6 +304,48 @@ export function createRequirement(
132
304
  return requirement;
133
305
  }
134
306
 
307
+ export function bindRequirementCandidateAuditRef(
308
+ options: RequirementStoreOptions,
309
+ requirementIdInput: string,
310
+ candidateAuditRefInput: string,
311
+ ): Requirement {
312
+ const requirementId = id(requirementIdInput);
313
+ const candidateAuditRef = String(candidateAuditRefInput ?? '').trim().slice(0, 500);
314
+ if (!candidateAuditRef.startsWith('cognitive-requirement-candidate:')) {
315
+ throw new Error('REQUIREMENT_CANDIDATE_AUDIT_REF_INVALID');
316
+ }
317
+ return withControlPlaneTransaction(options.controllerHome, (database) => {
318
+ const records = listControlPlaneRecordsWithinTransaction<Requirement>(database, {
319
+ namespace: NAMESPACE,
320
+ scope: SCOPE,
321
+ limit: 1000,
322
+ });
323
+ if (records.length >= 1000) throw new Error('REQUIREMENT_CANDIDATE_BINDING_LOOKUP_LIMIT');
324
+ const bound = records.find(record => record.value.auditRefs.includes(candidateAuditRef));
325
+ if (bound && bound.value.requirementId !== requirementId) {
326
+ throw new Error('REQUIREMENT_CANDIDATE_ALREADY_PROMOTED');
327
+ }
328
+ const current = readWithin(database, requirementId);
329
+ if (!current) throw new Error(`REQUIREMENT_NOT_FOUND: ${requirementId}`);
330
+ if (current.value.auditRefs.includes(candidateAuditRef)) return current.value;
331
+ const updated: Requirement = {
332
+ ...current.value,
333
+ auditRefs: [...new Set([...current.value.auditRefs, candidateAuditRef])].slice(-50),
334
+ revision: current.value.revision + 1,
335
+ updatedAt: nowIso(options),
336
+ };
337
+ return writeControlPlaneRecordWithinTransaction(database, {
338
+ namespace: NAMESPACE,
339
+ scope: SCOPE,
340
+ key: requirementId,
341
+ schemaVersion: SCHEMA_VERSION,
342
+ value: updated,
343
+ action: 'requirement_candidate_promoted',
344
+ expectedRevision: current.revision,
345
+ }).value;
346
+ });
347
+ }
348
+
135
349
  export function updateRequirement(
136
350
  options: RequirementStoreOptions,
137
351
  input: {
@@ -167,75 +381,3 @@ export function updateRequirement(
167
381
  }).value;
168
382
  });
169
383
  }
170
-
171
- export interface RequirementCompletionInput {
172
- requirementId: string;
173
- work: Pick<WorkContract,
174
- | 'workId'
175
- | 'requirementId'
176
- | 'status'
177
- | 'phase'
178
- | 'evidenceState'
179
- | 'completionOutcome'
180
- | 'completionReceipt'
181
- >;
182
- }
183
-
184
- /**
185
- * Project machine-complete Work delivery evidence into a Requirement without
186
- * asserting Requirement-level semantic acceptance. A Work is only one Plan-step
187
- * execution fact; it must not move the whole Requirement to waiting_for_user
188
- * while sibling/current Plan slices still exist. Requirement acceptance is a
189
- * separate lifecycle decision after current Plan/Work authority converges.
190
- *
191
- * The legacy function name is retained for compatibility with completion
192
- * callers. Its authority is evidence projection only, not semantic completion.
193
- */
194
- export function completeRequirementFromWork(
195
- options: RequirementStoreOptions,
196
- input: RequirementCompletionInput,
197
- ): Requirement {
198
- const requirementId = id(input.requirementId);
199
- const current = readRequirement(options, requirementId);
200
- if (!current) throw new Error(`REQUIREMENT_NOT_FOUND: ${requirementId}`);
201
- if (current.value.state === 'done') return current.value;
202
- if (current.value.state === 'cancelled') throw new Error('REQUIREMENT_CANCELLED');
203
-
204
- const work = input.work;
205
- if (work.requirementId !== requirementId) throw new Error('REQUIREMENT_WORK_IDENTITY_MISMATCH');
206
- if (work.status !== 'completed') throw new Error('REQUIREMENT_WORK_NOT_COMPLETED');
207
- if (work.phase !== 'cleanup') throw new Error('REQUIREMENT_WORK_CLEANUP_REQUIRED');
208
- if (work.evidenceState !== 'valid') throw new Error('REQUIREMENT_WORK_EVIDENCE_NOT_VALID');
209
- if (!work.completionOutcome) throw new Error('REQUIREMENT_WORK_COMPLETION_OUTCOME_REQUIRED');
210
- if (work.completionOutcome === 'superseded') throw new Error('REQUIREMENT_WORK_OUTCOME_NOT_COMPLETED');
211
-
212
- const receipt = work.completionReceipt;
213
- if (!receipt) throw new Error('REQUIREMENT_WORK_COMPLETION_RECEIPT_REQUIRED');
214
- if (receipt.workId !== work.workId) throw new Error('REQUIREMENT_WORK_RECEIPT_IDENTITY_MISMATCH');
215
- if (!isRepositoryCompletionReceipt(receipt)) throw new Error('REQUIREMENT_WORK_REPOSITORY_RECEIPT_REQUIRED');
216
- if (receipt.delivery.kind === 'superseded' || receipt.delivery.status !== 'integrated' || !receipt.delivery.reachable) throw new Error('REQUIREMENT_WORK_DELIVERY_NOT_PROVEN');
217
- if (!['complete', 'maintenance_warning'].includes(receipt.cleanup.status) || receipt.cleanup.blockers.length > 0) throw new Error('REQUIREMENT_WORK_CLEANUP_NOT_PROVEN');
218
-
219
- if (current.value.auditRefs.includes(receipt.receiptId)) return current.value;
220
- return updateRequirement(options, {
221
- requirementId,
222
- action: 'requirement_delivery_evidence_recorded',
223
- mutate: (latest) => {
224
- // Preserve concurrent terminal or genuinely user-blocked semantic state.
225
- // Older V2 builds generated waiting_for_user from a single Work receipt;
226
- // recognize that exact compatibility message and repair it back to active.
227
- if (latest.state === 'done') return latest;
228
- if (latest.state === 'cancelled') throw new Error('REQUIREMENT_CANCELLED');
229
- const legacyMachineWait = latest.state === 'waiting_for_user'
230
- && /^Work .+ delivered machine-valid evidence \(.+\); ChatGPT\/user semantic acceptance is still required\.$/.test(latest.attentionSummary ?? '');
231
- const preserveSemanticWait = latest.state === 'waiting_for_user' && !legacyMachineWait;
232
- return {
233
- ...latest,
234
- state: preserveSemanticWait ? 'waiting_for_user' : 'active',
235
- needsAttention: preserveSemanticWait ? latest.needsAttention : false,
236
- attentionSummary: preserveSemanticWait ? latest.attentionSummary : undefined,
237
- auditRefs: Array.from(new Set([...latest.auditRefs, receipt.receiptId])).slice(-50),
238
- };
239
- },
240
- });
241
- }