@moretea-labs/forge 1.7.1 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (685) hide show
  1. package/AGENTS.md +58 -62
  2. package/CHANGELOG.md +39 -0
  3. package/CLAUDE.md +42 -62
  4. package/README.md +2 -2
  5. package/SKILL.md +0 -1
  6. package/THIRD_PARTY_NOTICES.md +5 -2
  7. package/adapters/browser/index.ts +2 -0
  8. package/adapters/chatgpt/browser-delivery-host.ts +71 -0
  9. package/adapters/chatgpt/browser-delivery-runtime.ts +783 -0
  10. package/adapters/chatgpt/controller-binding-store.ts +55 -0
  11. package/adapters/chatgpt/controller-host.ts +119 -0
  12. package/adapters/chatgpt/controller-round-host.ts +78 -0
  13. package/adapters/chatgpt/controller-round-settlement-store.ts +45 -0
  14. package/adapters/chatgpt/provider-delivery.ts +113 -0
  15. package/adapters/chatgpt/work-conversation-binding-store.ts +192 -0
  16. package/adapters/chatgpt/wsl-bridge-delivery-host.ts +63 -0
  17. package/adapters/computer/desktop-operator-contract.ts +7 -0
  18. package/adapters/computer/desktop-operator-discovery.ts +201 -0
  19. package/adapters/computer/desktop-operator-negotiation.ts +174 -0
  20. package/adapters/computer/desktop-operator-provider.ts +312 -0
  21. package/adapters/computer/index.ts +1 -0
  22. package/adapters/computer/interaction-target-authority.ts +944 -0
  23. package/adapters/controller-process/binding-store.ts +34 -0
  24. package/adapters/controller-process/controller-host.ts +26 -0
  25. package/adapters/mcp/access-mode.ts +132 -0
  26. package/adapters/mcp/audit.ts +32 -0
  27. package/adapters/mcp/auth.ts +407 -0
  28. package/adapters/mcp/controller-round-compatibility.ts +184 -0
  29. package/adapters/mcp/frozen-client-semantic-compatibility.ts +292 -0
  30. package/adapters/mcp/instructions.ts +36 -0
  31. package/adapters/mcp/legacy-context.ts +18 -0
  32. package/adapters/mcp/multi-repository.ts +437 -0
  33. package/adapters/mcp/oauth.ts +391 -0
  34. package/adapters/mcp/paths.ts +140 -0
  35. package/adapters/mcp/policy.ts +232 -0
  36. package/adapters/mcp/proxy-env.ts +62 -0
  37. package/adapters/mcp/readiness-projection.ts +24 -0
  38. package/adapters/mcp/redaction.ts +21 -0
  39. package/adapters/mcp/repo.ts +24 -0
  40. package/adapters/mcp/runtime-gateway/artifact-adapter.ts +52 -0
  41. package/adapters/mcp/runtime-gateway/context-adapter.ts +829 -0
  42. package/adapters/mcp/runtime-gateway/controller-authority-adapter.ts +191 -0
  43. package/adapters/mcp/runtime-gateway/engineering-preconditions.ts +147 -0
  44. package/adapters/mcp/runtime-gateway/execution-control-adapter.ts +28 -0
  45. package/adapters/mcp/runtime-gateway/execution-tools.ts +207 -0
  46. package/adapters/mcp/runtime-gateway/filesystem-adapter.ts +38 -0
  47. package/adapters/mcp/runtime-gateway/gateway-execution-adapter.ts +411 -0
  48. package/adapters/mcp/runtime-gateway/legacy-ios-tool-adapter.ts +105 -0
  49. package/adapters/mcp/runtime-gateway/maintenance-adapter.ts +44 -0
  50. package/adapters/mcp/runtime-gateway/model-adapter.ts +63 -0
  51. package/adapters/mcp/runtime-gateway/persisted-check-process.ts +3 -0
  52. package/adapters/mcp/runtime-gateway/plugin-adapter.ts +308 -0
  53. package/adapters/mcp/runtime-gateway/process-tools.ts +289 -0
  54. package/adapters/mcp/runtime-gateway/protected-computer-adapter.ts +76 -0
  55. package/adapters/mcp/runtime-gateway/recovery-adapter.ts +268 -0
  56. package/adapters/mcp/runtime-gateway/recovery-client-adapter.ts +70 -0
  57. package/adapters/mcp/runtime-gateway/recovery-tool-contract.ts +99 -0
  58. package/adapters/mcp/runtime-gateway/repository-compat-adapter.ts +110 -0
  59. package/adapters/mcp/runtime-gateway/result-adapter.ts +108 -0
  60. package/adapters/mcp/runtime-gateway/router.ts +728 -0
  61. package/adapters/mcp/runtime-gateway/runtime-observation-adapter.ts +1251 -0
  62. package/adapters/mcp/runtime-gateway/runtime-tool-definitions.ts +634 -0
  63. package/adapters/mcp/runtime-gateway/runtime-tool-shared.ts +27 -0
  64. package/adapters/mcp/runtime-gateway/runtime-tools.ts +68 -0
  65. package/adapters/mcp/runtime-gateway/scheduler-adapter.ts +186 -0
  66. package/adapters/mcp/runtime-gateway/shared-adapter.ts +25 -0
  67. package/adapters/mcp/runtime-gateway/status-inbox-adapter.ts +870 -0
  68. package/adapters/mcp/runtime-gateway/work-adapter.ts +3186 -0
  69. package/adapters/mcp/runtime-gateway/work-compat-adapter.ts +502 -0
  70. package/adapters/mcp/runtime-gateway/work-validation-reconciler.ts +1 -0
  71. package/adapters/mcp/server.ts +1048 -0
  72. package/adapters/mcp/setup.ts +791 -0
  73. package/adapters/mcp/tool-capability-cache.ts +87 -0
  74. package/adapters/mcp/tool-mapping/access-tools.ts +387 -0
  75. package/adapters/mcp/tool-mapping/legacy-tool-service.ts +5265 -0
  76. package/adapters/mcp/tool-mapping/post-finalize-work-attribution.ts +150 -0
  77. package/adapters/mcp/tool-mapping/repository-tools.ts +1691 -0
  78. package/adapters/mcp/tool-mapping/tools.ts +9 -0
  79. package/adapters/mcp/tool-mapping/umbrella-tools.ts +117 -0
  80. package/adapters/mcp/toolset-names.ts +74 -0
  81. package/adapters/mcp/toolset-selection.ts +41 -0
  82. package/adapters/mcp/toolset.ts +336 -0
  83. package/adapters/mcp/transports/http.ts +1456 -0
  84. package/adapters/mcp/transports/session-registry.ts +513 -0
  85. package/adapters/mcp/transports/stdio.ts +8 -0
  86. package/adapters/mcp/tunnels/openai-secure-tunnel.ts +139 -0
  87. package/adapters/mcp/types.ts +41 -0
  88. package/assets/AGENTS.md +2 -16
  89. package/assets/CLAUDE.md +2 -16
  90. package/assets/hooks/AGENTS.md +3 -14
  91. package/assets/hooks/CLAUDE.md +3 -14
  92. package/assets/hooks/hook-input.sh +9 -2
  93. package/assets/hooks/lib/workflow-state.sh +28 -10
  94. package/assets/hooks/prompt-guard.sh +63 -37
  95. package/assets/hooks/security-sentinel.sh +2 -1
  96. package/assets/hooks/session-start-context.sh +7 -5
  97. package/assets/hooks/stop-orchestrator.sh +13 -3
  98. package/assets/initializer-question-pack.v4.json +11 -7
  99. package/assets/partials/05-workflow.partial.md +18 -73
  100. package/assets/partials/07-footer.partial.md +1 -1
  101. package/assets/partials-agents/02-operating-mode.partial.md +1 -2
  102. package/assets/partials-agents/04-task-protocol.partial.md +14 -59
  103. package/assets/partials-agents/06-quality-safety.partial.md +11 -16
  104. package/assets/partials-agents/08-deep-docs.partial.md +1 -2
  105. package/assets/plan-map.json +11 -11
  106. package/assets/plugin-registry.v1.json +9 -3
  107. package/assets/plugin-trust-policy.v1.json +6 -0
  108. package/assets/recovery/ForgeRecovery.ps1 +100 -0
  109. package/assets/recovery/forge-wsl-rescue +271 -0
  110. package/assets/reference-configs/development-protocol.md +11 -15
  111. package/assets/reference-configs/document-generation.md +1 -1
  112. package/assets/reference-configs/global-working-rules.md +9 -1
  113. package/assets/reference-configs/harness-overview.md +22 -112
  114. package/assets/reference-configs/hook-operations.md +1 -1
  115. package/assets/reference-configs/sprint-contracts.md +2 -2
  116. package/assets/skill-version.json +2 -2
  117. package/assets/templates/helpers/architecture-event.ts +3 -34
  118. package/assets/templates/helpers/architecture-queue.sh +61 -10
  119. package/assets/templates/helpers/archive-workflow.sh +90 -180
  120. package/assets/templates/helpers/capability-config.ts +8 -11
  121. package/assets/templates/helpers/capability-resolver.ts +37 -19
  122. package/assets/templates/helpers/capture-plan.sh +2 -2
  123. package/assets/templates/helpers/check-architecture-sync.sh +1 -9
  124. package/assets/templates/helpers/check-task-sync.sh +82 -11
  125. package/assets/templates/helpers/check-task-workflow.sh +1 -3
  126. package/assets/templates/helpers/context-contract-sync.sh +1 -12
  127. package/assets/templates/helpers/contract-worktree.sh +26 -24
  128. package/assets/templates/helpers/ensure-task-workflow.sh +6 -8
  129. package/assets/templates/helpers/inspect-project-state.ts +1 -1
  130. package/assets/templates/helpers/migrate-project-template.sh +1 -1
  131. package/assets/templates/helpers/migrate-workflow-docs.ts +53 -239
  132. package/assets/templates/helpers/new-plan.sh +2 -2
  133. package/assets/templates/helpers/plan-to-todo.sh +3 -31
  134. package/assets/templates/helpers/sprint-backlog.sh +1 -1
  135. package/assets/templates/helpers/switch-plan.sh +1 -1
  136. package/assets/templates/helpers/workflow-contract.ts +1 -0
  137. package/assets/workflow-contract.v1.json +63 -171
  138. package/assets/workflows/xiaohongshu/xiaohongshu.collect-metrics.v1.draft.json +118 -0
  139. package/assets/workflows/xiaohongshu/xiaohongshu.publish-image-note.v1.draft.json +316 -0
  140. package/assets/workflows/xiaohongshu/xiaohongshu.publish-long-text.v1.draft.json +324 -0
  141. package/docs/architecture/CURRENT.md +148 -13
  142. package/docs/architecture/EVOLUTION.md +13 -0
  143. package/docs/architecture/decisions/20260801-controller-home-sqlite-state.md +2 -1
  144. package/docs/architecture/decisions/20260831-independent-windows-wsl-host-rescue.md +59 -0
  145. package/docs/architecture/decisions/20260904-ios-device-migration-baseline.md +120 -0
  146. package/docs/architecture/decisions/20260904-repository-runtime-data-boundary.md +42 -0
  147. package/docs/architecture/decisions/20260907-assistant-learning-loop.md +35 -0
  148. package/docs/architecture/decisions/20260907-controller-round-transition-policy.md +296 -0
  149. package/docs/architecture/decisions/20260907-maintenance-diagnosis-bounded-read.md +39 -0
  150. package/docs/architecture/domains/verification.md +7 -0
  151. package/docs/architecture/domains/workflow-engine.md +1 -1
  152. package/docs/architecture/index.md +3 -3
  153. package/docs/architecture/modules/controller-runtime/transport-lifecycle.md +19 -8
  154. package/docs/architecture/requests/2026-09-04-computer-plugin-workflow-taxonomy.md +124 -0
  155. package/docs/forge-chatgpt-mcp-setup.md +5 -3
  156. package/docs/forge-plugin-management.md +20 -4
  157. package/docs/forge-runtime-self-healing-loop.md +2 -0
  158. package/docs/operations/benchmark-cross-version-freeze.md +38 -0
  159. package/docs/operations/controller-browser-plugin.md +3 -1
  160. package/docs/operations/homebrew.md +2 -2
  161. package/docs/operations/platform-support.md +16 -8
  162. package/docs/operations/platform-support.zh-CN.md +2 -2
  163. package/docs/operations/standalone-disaster-recovery.md +26 -1
  164. package/docs/operations/uu-remote-rescue.md +41 -0
  165. package/docs/operations/windows-wsl-host-rescue.md +133 -0
  166. package/docs/public-usage-guide.md +1 -1
  167. package/docs/public-usage-guide.zh-CN.md +1 -1
  168. package/docs/tutorials/01-install-and-start.md +1 -1
  169. package/docs/tutorials/01-install-and-start.zh-CN.md +1 -1
  170. package/docs/tutorials/02-connect-chatgpt.md +4 -4
  171. package/docs/tutorials/02-connect-chatgpt.zh-CN.md +4 -4
  172. package/docs/wiki/Implementation.md +1 -1
  173. package/package.json +23 -14
  174. package/packages/kernel/controller/api/index.ts +2 -0
  175. package/packages/kernel/controller/application/controller-round-service.ts +29 -0
  176. package/packages/kernel/controller/application/controller-service.ts +30 -0
  177. package/packages/kernel/controller/domain/controller-round-transition-policy.ts +308 -0
  178. package/packages/kernel/controller/domain/controller-round.ts +107 -0
  179. package/packages/kernel/controller/domain/execution-quality.ts +133 -0
  180. package/packages/kernel/controller/domain/types.ts +56 -0
  181. package/packages/kernel/controller/index.ts +1 -0
  182. package/packages/kernel/controller/infrastructure/controller-binding-store.ts +84 -0
  183. package/packages/kernel/controller/infrastructure/controller-round-store.ts +1384 -0
  184. package/packages/kernel/controller/infrastructure/controller-session-store.ts +578 -0
  185. package/packages/kernel/controller/ports/controller-host.ts +16 -0
  186. package/packages/kernel/goal/api/index.ts +1 -0
  187. package/packages/kernel/goal/domain/types.ts +40 -0
  188. package/packages/kernel/goal/index.ts +1 -0
  189. package/packages/kernel/identity/api/index.ts +5 -0
  190. package/packages/kernel/identity/application/identity-service.ts +67 -0
  191. package/packages/kernel/identity/domain/scope.ts +63 -0
  192. package/packages/kernel/identity/domain/semantic-sync.ts +81 -0
  193. package/packages/kernel/identity/domain/types.ts +44 -0
  194. package/packages/kernel/identity/domain/workspace.ts +56 -0
  195. package/packages/kernel/identity/index.ts +1 -0
  196. package/packages/kernel/identity/infrastructure/identity-store.ts +75 -0
  197. package/packages/kernel/memory/api/index.ts +5 -0
  198. package/packages/kernel/memory/application/experience-service.ts +118 -0
  199. package/packages/kernel/memory/application/outcome-service.ts +77 -0
  200. package/packages/kernel/memory/domain/experience.ts +103 -0
  201. package/packages/kernel/memory/domain/operational-prior.ts +92 -0
  202. package/packages/kernel/memory/index.ts +1 -0
  203. package/packages/kernel/progression/api/index.ts +2 -0
  204. package/packages/kernel/progression/application/projector.ts +211 -0
  205. package/packages/kernel/progression/domain/types.ts +116 -0
  206. package/packages/kernel/progression/index.ts +1 -0
  207. package/packages/kernel/scheduler/api/index.ts +6 -0
  208. package/packages/kernel/scheduler/application/continuation-service.ts +212 -0
  209. package/packages/kernel/scheduler/application/eligibility.ts +252 -0
  210. package/packages/kernel/scheduler/application/schedule-service.ts +24 -0
  211. package/packages/kernel/scheduler/application/settlement.ts +197 -0
  212. package/packages/kernel/scheduler/domain/continuation.ts +38 -0
  213. package/packages/kernel/scheduler/domain/schedule.ts +149 -0
  214. package/packages/kernel/scheduler/index.ts +1 -0
  215. package/packages/kernel/scheduler/infrastructure/continuation-dispatch-store.ts +38 -0
  216. package/packages/kernel/scheduler/infrastructure/schedule-store.ts +785 -0
  217. package/packages/kernel/work/api/index.ts +15 -0
  218. package/packages/kernel/work/application/work-service.ts +148 -0
  219. package/packages/kernel/work/domain/admission-policy.ts +34 -0
  220. package/packages/kernel/work/domain/check-receipt.ts +43 -0
  221. package/packages/kernel/work/domain/context-closure-receipt.ts +32 -0
  222. package/packages/kernel/work/domain/engineering-contracts.ts +157 -0
  223. package/packages/kernel/work/domain/engineering-design.ts +281 -0
  224. package/packages/kernel/work/domain/engineering-profile.ts +242 -0
  225. package/packages/kernel/work/domain/execution-concurrency.ts +254 -0
  226. package/packages/kernel/work/domain/execution-snapshot.ts +33 -0
  227. package/packages/kernel/work/domain/implementation-review.ts +510 -0
  228. package/packages/kernel/work/domain/project-engineering-contract.ts +202 -0
  229. package/packages/kernel/work/domain/repository-completion-receipt.ts +73 -0
  230. package/packages/kernel/work/domain/state-machine.ts +259 -0
  231. package/packages/kernel/work/domain/types.ts +528 -0
  232. package/packages/kernel/work/index.ts +1 -0
  233. package/packages/kernel/work/infrastructure/work-contract-store.ts +1876 -0
  234. package/packages/kernel/work/ports/work-contract-store.ts +18 -0
  235. package/packages/plugin-runtime/browser/index.ts +3 -0
  236. package/packages/plugin-runtime/browser/provider-registry.ts +110 -0
  237. package/packages/plugin-runtime/browser/runtime-contract.ts +150 -0
  238. package/packages/plugin-runtime/browser/session-authority.ts +61 -0
  239. package/packages/plugin-runtime/computer/index.ts +6 -0
  240. package/packages/plugin-runtime/computer/provider-error.ts +26 -0
  241. package/packages/plugin-runtime/computer/provider-registration.ts +52 -0
  242. package/packages/plugin-runtime/computer/provider-registry.ts +63 -0
  243. package/packages/plugin-runtime/computer/provider.ts +19 -0
  244. package/packages/plugin-runtime/computer/target-authority.ts +190 -0
  245. package/packages/plugin-runtime/computer/target-persistence.ts +54 -0
  246. package/packages/plugin-runtime/external/index.ts +1 -0
  247. package/packages/plugin-runtime/external/unix-jsonl-transport.ts +457 -0
  248. package/packages/plugin-runtime/index.ts +3 -0
  249. package/packages/protocols/browser/index.ts +1 -0
  250. package/packages/protocols/browser/session.ts +98 -0
  251. package/packages/protocols/computer/contract.ts +199 -0
  252. package/packages/protocols/computer/index.ts +1 -0
  253. package/packages/protocols/failure/contract.ts +158 -0
  254. package/packages/protocols/failure/index.ts +1 -0
  255. package/packages/protocols/handoff/index.ts +1 -0
  256. package/packages/protocols/handoff/status.ts +22 -0
  257. package/packages/protocols/mcp/execution-context.ts +11 -0
  258. package/packages/protocols/mcp/index.ts +2 -0
  259. package/packages/protocols/mcp/tool-contract.ts +42 -0
  260. package/packages/workflow-runtime/api/index.ts +2 -0
  261. package/packages/workflow-runtime/application/interpreter.ts +342 -0
  262. package/packages/workflow-runtime/domain/workflow-asset.ts +223 -0
  263. package/packages/workflow-runtime/index.ts +1 -0
  264. package/scripts/assemble-template.ts +1 -1
  265. package/scripts/benchmark-computer-hotpath.ts +255 -0
  266. package/scripts/benchmark-controller-round2.ts +54 -2
  267. package/scripts/benchmark-ios-agent-device.ts +3 -6
  268. package/scripts/benchmark-mcp-transport.ts +3 -4
  269. package/scripts/benchmark-operational-memory-activation.ts +235 -0
  270. package/scripts/benchmark-operational-shadow.ts +28 -0
  271. package/scripts/bootstrap-runtime-maintenance-recovery.sh +4 -1
  272. package/scripts/canary-chatgpt-provider-delivery.ts +97 -0
  273. package/scripts/canary-controller-semantic-wait.ts +195 -0
  274. package/scripts/canary-global-hook.sh +2 -2
  275. package/scripts/check-mcp-compatibility.ts +173 -7
  276. package/scripts/check-platform-support.mjs +28 -2
  277. package/scripts/check-public-docs.sh +1 -1
  278. package/scripts/check-release-readiness.sh +1 -1
  279. package/scripts/check-repository-hygiene.mjs +92 -0
  280. package/scripts/check-runtime-architecture.mjs +1206 -95
  281. package/scripts/check-source-duplication.mjs +9 -1
  282. package/scripts/check-tarball-install-smoke.sh +98 -15
  283. package/scripts/controller-ngrok-rotation.sh +5 -4
  284. package/scripts/create-project-dirs.sh +10 -74
  285. package/scripts/forge-local-recovery-helper.mjs +204 -0
  286. package/scripts/forge-uu-remote-rescue-helper.d.mts +31 -0
  287. package/scripts/forge-uu-remote-rescue-helper.mjs +409 -0
  288. package/scripts/forge-windows-host-recovery-helper.mjs +136 -0
  289. package/scripts/hook-shim.sh +2 -2
  290. package/scripts/init-project.sh +12 -70
  291. package/scripts/install-desktop-operator-registration.ts +4 -2
  292. package/scripts/install-independent-windows-wsl-recovery.ts +125 -0
  293. package/scripts/install-standalone-recovery.ts +122 -10
  294. package/scripts/install-uu-remote-rescue-registration.ts +74 -0
  295. package/scripts/install-windows-host-recovery-registration.ts +22 -0
  296. package/scripts/lib/controller-home-env.sh +6 -3
  297. package/scripts/lib/project-init-lib.sh +39 -582
  298. package/scripts/migrate-chatgpt-automation-schedules.ts +2 -2
  299. package/scripts/migrate-windows-wsl-controller-home.ts +306 -0
  300. package/scripts/open-source-audit-allowlist.txt +12 -1
  301. package/scripts/portability-bindings.mjs +70 -0
  302. package/scripts/run-bounded-command.mjs +55 -0
  303. package/scripts/run-bun-test-file.ts +22 -6
  304. package/scripts/run-governed-gate.ts +4 -1
  305. package/scripts/smoke-mcp-http-runtime.ts +1 -1
  306. package/scripts/smoke-runtime-recovery.ts +34 -1
  307. package/scripts/smoke-schedule-engine.ts +1 -1
  308. package/scripts/stage-runtime-release.ts +6 -1
  309. package/scripts/test-governance.ts +51 -2
  310. package/src/cli/agent-jobs/job-manager.ts +10 -1
  311. package/src/cli/chatgpt-browser/bind-server.ts +2 -1
  312. package/src/cli/chatgpt-browser/binding.ts +20 -10
  313. package/src/cli/chatgpt-browser/bridge-extension.ts +75 -0
  314. package/src/cli/chatgpt-browser/bridge-provider.ts +376 -11
  315. package/src/cli/chatgpt-browser/engine.ts +10 -11
  316. package/src/cli/chatgpt-browser/native-provider.ts +24 -83
  317. package/src/cli/chatgpt-browser/oracle-provider.ts +5 -3
  318. package/src/cli/chatgpt-browser/types.ts +1 -0
  319. package/src/cli/commands/bootstrap-control.ts +334 -0
  320. package/src/cli/commands/brain-assistant.ts +38 -0
  321. package/src/cli/commands/brain.ts +193 -40
  322. package/src/cli/commands/chatgpt.ts +127 -0
  323. package/src/cli/commands/computer.ts +437 -0
  324. package/src/cli/commands/doctor.ts +18 -1
  325. package/src/cli/commands/init-hook.ts +71 -61
  326. package/src/cli/commands/init.ts +3 -1
  327. package/src/cli/commands/mcp.ts +16 -10
  328. package/src/cli/commands/plugin.ts +38 -12
  329. package/src/cli/commands/recovery.ts +493 -80
  330. package/src/cli/commands/runtime.ts +9 -4
  331. package/src/cli/commands/setup-profile.ts +89 -39
  332. package/src/cli/commands/status.ts +2 -1
  333. package/src/cli/controller/check-runner.ts +487 -98
  334. package/src/cli/controller/context/types.ts +7 -1
  335. package/src/cli/controller/context-pack.ts +23 -3
  336. package/src/cli/controller/issue-store.ts +1 -1
  337. package/src/cli/controller/systemd-user.ts +110 -0
  338. package/src/cli/controller/types.ts +10 -70
  339. package/src/cli/controller/worklog.ts +67 -13
  340. package/src/cli/editing/edit-operation-contract.ts +92 -0
  341. package/src/cli/editing/edit-session.ts +289 -13
  342. package/src/cli/github/plugin.ts +17 -12
  343. package/src/cli/hook/route-registry.ts +3 -5
  344. package/src/cli/hook/runtime.ts +49 -3
  345. package/src/cli/index.ts +3 -0
  346. package/src/cli/local-bridge/connector-freshness.ts +2 -2
  347. package/src/cli/local-bridge/console-automations.ts +2 -2
  348. package/src/cli/local-bridge/facade-api.ts +41 -14
  349. package/src/cli/local-bridge/job-store.ts +1 -1
  350. package/src/cli/local-bridge/server.ts +24 -27
  351. package/src/cli/mcp/access-mode.ts +2 -132
  352. package/src/cli/mcp/access-tools.ts +2 -387
  353. package/src/cli/mcp/audit.ts +2 -32
  354. package/src/cli/mcp/auth.ts +2 -404
  355. package/src/cli/mcp/instructions.ts +2 -34
  356. package/src/cli/mcp/legacy-context.ts +2 -16
  357. package/src/cli/mcp/legacy-tool-service.ts +2 -5308
  358. package/src/cli/mcp/multi-repository.ts +2 -436
  359. package/src/cli/mcp/oauth.ts +2 -375
  360. package/src/cli/mcp/openai-secure-tunnel.ts +2 -0
  361. package/src/cli/mcp/paths.ts +2 -140
  362. package/src/cli/mcp/policy.ts +2 -232
  363. package/src/cli/mcp/post-finalize-work-attribution.ts +2 -150
  364. package/src/cli/mcp/proxy-env.ts +2 -62
  365. package/src/cli/mcp/readiness-projection.ts +2 -24
  366. package/src/cli/mcp/redaction.ts +2 -21
  367. package/src/cli/mcp/repo.ts +2 -24
  368. package/src/cli/mcp/repository-tools.ts +2 -1585
  369. package/src/cli/mcp/server.ts +2 -951
  370. package/src/cli/mcp/setup.ts +2 -737
  371. package/src/cli/mcp/tool-capability-cache.ts +2 -87
  372. package/src/cli/mcp/tool-contract.ts +2 -14
  373. package/src/cli/mcp/tools.ts +2 -9
  374. package/src/cli/mcp/toolset-names.ts +2 -70
  375. package/src/cli/mcp/toolset-selection.ts +2 -41
  376. package/src/cli/mcp/toolset.ts +2 -336
  377. package/src/cli/mcp/transports/AGENTS.md +1 -10
  378. package/src/cli/mcp/transports/CLAUDE.md +1 -10
  379. package/src/cli/mcp/transports/http.ts +2 -1414
  380. package/src/cli/mcp/transports/session-registry.ts +2 -490
  381. package/src/cli/mcp/transports/stdio.ts +2 -8
  382. package/src/cli/mcp/types.ts +2 -41
  383. package/src/cli/mcp/umbrella-tools.ts +2 -117
  384. package/src/cli/repositories/command-executor.ts +64 -18
  385. package/src/cli/repositories/command-scope.ts +117 -1
  386. package/src/cli/repositories/controller-home.ts +119 -1
  387. package/src/cli/repositories/identity.ts +13 -0
  388. package/src/cli/repositories/registry.ts +68 -49
  389. package/src/cli/repositories/repository-snapshot.ts +53 -7
  390. package/src/cli/repositories/runtime-storage.ts +27 -2
  391. package/src/cli/repositories/safe-patch.ts +34 -38
  392. package/src/cli/repositories/selected-path-actions.ts +22 -2
  393. package/src/cli/repositories/structured-git.ts +105 -25
  394. package/src/cli/runtime/helper-runner.ts +7 -0
  395. package/src/cli/runtime-invocation.ts +8 -1
  396. package/src/cli/tools/codegraph.ts +44 -25
  397. package/src/core/adoption/manifest-templates.ts +1 -1
  398. package/src/core/adoption/plan.ts +3 -26
  399. package/src/core/adoption/workflow-contract-plan.ts +17 -9
  400. package/src/effects/process-runner.ts +8 -14
  401. package/src/runtime/context/assistant-context.ts +154 -0
  402. package/src/runtime/context/assistant-work-context.ts +147 -0
  403. package/src/runtime/context/codegraph-cache-boundary.ts +255 -0
  404. package/src/runtime/context/codegraph-read-provider.ts +55 -22
  405. package/src/runtime/context/codegraph-sidecar.cjs +8 -1
  406. package/src/runtime/context/context-closure.ts +268 -0
  407. package/src/runtime/context/context-plane.ts +211 -0
  408. package/src/runtime/context/project-engineering-contract.ts +60 -0
  409. package/src/runtime/control-plane/bootstrap/capability-provider.ts +74 -0
  410. package/src/runtime/control-plane/bootstrap/control-api.ts +57 -0
  411. package/src/runtime/control-plane/bootstrap/index.ts +5 -0
  412. package/src/runtime/control-plane/bootstrap/state-machine.ts +141 -0
  413. package/src/runtime/control-plane/bootstrap/store.ts +21 -0
  414. package/src/runtime/control-plane/bootstrap/types.ts +87 -0
  415. package/src/runtime/control-plane/cleanup-artifact-retention.ts +328 -0
  416. package/src/runtime/control-plane/codegraph-cache-retention.ts +164 -0
  417. package/src/runtime/control-plane/concurrency/work-execution-concurrency.ts +320 -0
  418. package/src/runtime/control-plane/execution/content-equivalent-commit-authority.ts +169 -0
  419. package/src/runtime/control-plane/execution/controller-authority-recovery.ts +350 -0
  420. package/src/runtime/control-plane/execution/direct-canonical-work-reconciliation.ts +85 -0
  421. package/src/runtime/control-plane/execution/direct-edit-work-completion.ts +417 -100
  422. package/src/runtime/control-plane/execution/edit-validation-coordinator.ts +103 -15
  423. package/src/runtime/control-plane/execution/implementation-review-content.ts +95 -0
  424. package/src/runtime/control-plane/execution/repository-work-attribution.ts +2 -2
  425. package/src/runtime/control-plane/execution/retained-work-resume.ts +336 -6
  426. package/src/runtime/control-plane/execution/validation.ts +28 -3
  427. package/src/runtime/control-plane/execution/work-authority-reconciler.ts +116 -0
  428. package/src/runtime/control-plane/execution/work-completion-authority.ts +44 -2
  429. package/src/runtime/control-plane/execution/work-evidence-policy.ts +34 -3
  430. package/src/runtime/control-plane/execution/work-execution-support.ts +42 -22
  431. package/src/runtime/control-plane/execution/work-finalization-service.ts +1103 -166
  432. package/src/runtime/control-plane/execution/work-handle-authority.ts +267 -16
  433. package/src/runtime/control-plane/execution/work-handle-store.ts +77 -0
  434. package/src/runtime/control-plane/execution/work-head-settlement.ts +75 -0
  435. package/src/runtime/control-plane/execution/work-lifecycle-audit.ts +145 -23
  436. package/src/runtime/control-plane/execution/work-operation-service.ts +49 -13
  437. package/src/runtime/control-plane/execution/work-preparation-service.ts +31 -15
  438. package/src/runtime/control-plane/execution/work-remote-delivery.ts +1 -1
  439. package/src/runtime/control-plane/execution/work-task-receipt.ts +20 -1
  440. package/src/runtime/control-plane/execution/work-terminal-cleanup.ts +407 -76
  441. package/src/runtime/control-plane/execution/work-validation-reconciler.ts +88 -18
  442. package/src/runtime/control-plane/execution/work-verification-context.ts +1 -1
  443. package/src/runtime/control-plane/execution/work-verification-service.ts +258 -4
  444. package/src/runtime/control-plane/execution/work-verification-snapshot.ts +200 -15
  445. package/src/runtime/control-plane/facade/capability-registry.ts +21 -10
  446. package/src/runtime/control-plane/facade/controller-round-relay.ts +3 -1118
  447. package/src/runtime/control-plane/facade/controller-session-store.ts +2 -488
  448. package/src/runtime/control-plane/facade/goal-workloop-access.ts +6 -3
  449. package/src/runtime/control-plane/facade/goal-workloop.ts +972 -137
  450. package/src/runtime/control-plane/facade/handoff-inbox-application.ts +158 -0
  451. package/src/runtime/control-plane/facade/handoff-inbox-store.ts +10 -0
  452. package/src/runtime/control-plane/facade/index.ts +4 -2
  453. package/src/runtime/control-plane/facade/operation-digest.ts +22 -58
  454. package/src/runtime/control-plane/facade/plan-contract-store.ts +1004 -38
  455. package/src/runtime/control-plane/facade/repository-work-admission.ts +19 -1
  456. package/src/runtime/control-plane/facade/requirement-authority.ts +218 -0
  457. package/src/runtime/control-plane/facade/requirement-board.ts +6 -1
  458. package/src/runtime/control-plane/facade/rh-work-operation-contract.ts +48 -0
  459. package/src/runtime/control-plane/facade/semantic-admission.ts +8 -16
  460. package/src/runtime/control-plane/facade/suggested-actions.ts +4 -1
  461. package/src/runtime/control-plane/facade/types.ts +189 -532
  462. package/src/runtime/control-plane/facade/work-admission-policy.ts +84 -35
  463. package/src/runtime/control-plane/facade/work-contract-store.ts +2 -1043
  464. package/src/runtime/control-plane/facade/work-implementation-review.ts +2 -0
  465. package/src/runtime/control-plane/facade/work-state-machine.ts +2 -250
  466. package/src/runtime/control-plane/generated-cache-retention.ts +239 -18
  467. package/src/runtime/control-plane/global-scheduler/durable-admission.ts +12 -1
  468. package/src/runtime/control-plane/global-scheduler/maintenance.ts +76 -13
  469. package/src/runtime/control-plane/global-scheduler/periodic-cleanup-entry.ts +55 -0
  470. package/src/runtime/control-plane/global-scheduler/periodic-cleanup-process.ts +98 -0
  471. package/src/runtime/control-plane/global-scheduler/reconciliation.ts +1 -1
  472. package/src/runtime/control-plane/global-scheduler/scheduler-worker-entry.ts +10 -0
  473. package/src/runtime/control-plane/global-scheduler/scheduler.ts +173 -81
  474. package/src/runtime/control-plane/global-scheduler/worker-launch.ts +18 -6
  475. package/src/runtime/control-plane/launcher/chatgpt-round-continuation.ts +397 -0
  476. package/src/runtime/control-plane/launcher/chatgpt-work-binding-store.ts +2 -177
  477. package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +301 -560
  478. package/src/runtime/control-plane/launcher/provider-mcp-bootstrap.ts +20 -4
  479. package/src/runtime/control-plane/launcher/thin-launcher.ts +50 -4
  480. package/src/runtime/control-plane/lifecycle-retention-metrics.ts +60 -0
  481. package/src/runtime/control-plane/persistence/experience-store.ts +169 -0
  482. package/src/runtime/control-plane/persistence/operational-prior-store.ts +348 -0
  483. package/src/runtime/control-plane/persistence/requirement-store.ts +30 -22
  484. package/src/runtime/control-plane/persistence/sqlite-store.ts +545 -76
  485. package/src/runtime/control-plane/persistence/workflow-content-store.ts +98 -0
  486. package/src/runtime/control-plane/persistence/workflow-registry-store.ts +186 -0
  487. package/src/runtime/control-plane/persistence/workflow-run-store.ts +123 -0
  488. package/src/runtime/control-plane/release-retention.ts +56 -16
  489. package/src/runtime/control-plane/repository-namespace-retention.ts +208 -0
  490. package/src/runtime/control-plane/routing/route-policy.ts +19 -0
  491. package/src/runtime/control-plane/runtime-cleanup.ts +574 -37
  492. package/src/runtime/control-plane/runtime-generation.ts +6 -0
  493. package/src/runtime/control-plane/workspace/semantic-sync-service.ts +465 -0
  494. package/src/runtime/control-plane/workspace/workspace-store.ts +80 -0
  495. package/src/runtime/diagnostics/incident-repair.ts +406 -0
  496. package/src/runtime/diagnostics/mcp-timing.ts +125 -6
  497. package/src/runtime/diagnostics/performance.ts +6 -14
  498. package/src/runtime/diagnostics/read-only-tool.ts +1 -1
  499. package/src/runtime/evidence/artifact-store.ts +65 -2
  500. package/src/runtime/evidence/operational-shadow.ts +38 -0
  501. package/src/runtime/evidence/process-check-receipt.ts +5 -43
  502. package/src/runtime/evidence/sensitive-output.ts +4 -4
  503. package/src/runtime/execution/jobs/receipt-recovery.ts +1 -1
  504. package/src/runtime/execution/jobs/store.ts +121 -2
  505. package/src/runtime/execution/managed-workspace.ts +55 -5
  506. package/src/runtime/execution/process-runtime/canary.ts +19 -5
  507. package/src/runtime/execution/process-runtime/check-classification.ts +48 -0
  508. package/src/runtime/execution/process-runtime/check-facade.ts +23 -9
  509. package/src/runtime/execution/process-runtime/check-receipt.ts +1 -1
  510. package/src/runtime/execution/process-runtime/check-result-retention.ts +132 -0
  511. package/src/runtime/execution/process-runtime/check-result.ts +73 -2
  512. package/src/runtime/execution/process-runtime/check-runner-sidecar.ts +42 -3
  513. package/src/runtime/execution/process-runtime/check-storage.ts +187 -0
  514. package/src/runtime/execution/process-runtime/command-facade.ts +38 -87
  515. package/src/runtime/execution/process-runtime/index.ts +1 -0
  516. package/src/runtime/execution/process-runtime/interactive-admission.ts +2 -1
  517. package/src/runtime/execution/process-runtime/lightweight-managed.ts +32 -1
  518. package/src/runtime/execution/process-runtime/persisted-check.ts +128 -21
  519. package/src/runtime/execution/process-runtime/resource-claims.ts +60 -3
  520. package/src/runtime/execution/process-runtime/runtime.ts +132 -15
  521. package/src/runtime/execution/process-runtime/types.ts +22 -0
  522. package/src/runtime/execution/workers/executor.ts +16 -13
  523. package/src/runtime/execution/workers/worker-entry.ts +1 -1
  524. package/src/runtime/gateway/mcp/execution-tools.ts +2 -207
  525. package/src/runtime/gateway/mcp/legacy-ios-tool-adapter.ts +2 -61
  526. package/src/runtime/gateway/mcp/persisted-check-process.ts +2 -3
  527. package/src/runtime/gateway/mcp/process-tools.ts +2 -289
  528. package/src/runtime/gateway/mcp/router.ts +2 -1125
  529. package/src/runtime/gateway/mcp/runtime-tool-definitions.ts +2 -565
  530. package/src/runtime/gateway/mcp/runtime-tools.ts +2 -6651
  531. package/src/runtime/gateway/mcp/work-validation-reconciler.ts +2 -1
  532. package/src/runtime/maintenance/cleanup.ts +38 -24
  533. package/src/runtime/platform/browser-product-discovery.ts +174 -0
  534. package/src/runtime/platform/computer-platform.ts +14 -0
  535. package/src/runtime/platform/executable-discovery.ts +54 -0
  536. package/src/runtime/platform/fetch-http-server.ts +90 -0
  537. package/src/runtime/platform/service-manager.ts +138 -0
  538. package/src/runtime/platform/windows-host-discovery.ts +118 -0
  539. package/src/runtime/platform/windows-recovery-deployment.ts +67 -0
  540. package/src/runtime/plugins/action-application.ts +135 -0
  541. package/src/runtime/plugins/app-store-connect-adapter.ts +9 -21
  542. package/src/runtime/plugins/browser-adapter.ts +140 -100
  543. package/src/runtime/plugins/browser-automation-service.ts +15 -36
  544. package/src/runtime/plugins/browser-macos-bridge.ts +69 -21
  545. package/src/runtime/plugins/browser-manifest-surface.ts +30 -6
  546. package/src/runtime/plugins/browser-native-session-service.ts +1 -1
  547. package/src/runtime/plugins/browser-provider-registry.ts +2 -109
  548. package/src/runtime/plugins/browser-registration.ts +16 -0
  549. package/src/runtime/plugins/browser-runtime-contract.ts +2 -154
  550. package/src/runtime/plugins/browser-runtime.ts +41 -9
  551. package/src/runtime/plugins/browser-session-authority.ts +101 -291
  552. package/src/runtime/plugins/browser-session-legacy-migration.ts +203 -0
  553. package/src/runtime/plugins/browser-session-store.ts +229 -36
  554. package/src/runtime/plugins/browser-session-types.ts +2 -98
  555. package/src/runtime/plugins/capability-authorization-grants.ts +17 -0
  556. package/src/runtime/plugins/catalog-trust.ts +82 -0
  557. package/src/runtime/plugins/computer-registration.ts +839 -0
  558. package/src/runtime/plugins/config-store.ts +119 -0
  559. package/src/runtime/plugins/desktop-operator-external-policy.ts +932 -0
  560. package/src/runtime/plugins/desktop-operator-registration.ts +111 -8
  561. package/src/runtime/plugins/errors.ts +8 -1
  562. package/src/runtime/plugins/external-adapter.ts +45 -322
  563. package/src/runtime/plugins/external-provider-policy.ts +48 -0
  564. package/src/runtime/plugins/external-registration.ts +9 -1
  565. package/src/runtime/plugins/external-unix-socket-probe.cjs +9 -3
  566. package/src/runtime/plugins/external-unix-socket.ts +64 -193
  567. package/src/runtime/plugins/first-party-external-registration.ts +163 -0
  568. package/src/runtime/plugins/first-party-registry.ts +3 -1
  569. package/src/runtime/plugins/github-adapter.ts +1 -2
  570. package/src/runtime/plugins/gmail-adapter.ts +6 -6
  571. package/src/runtime/plugins/google-calendar-adapter.ts +6 -6
  572. package/src/runtime/plugins/google-shared.ts +31 -46
  573. package/src/runtime/plugins/google-tasks-adapter.ts +6 -6
  574. package/src/runtime/plugins/ios-adapter.ts +1 -2
  575. package/src/runtime/plugins/local-system-adapter.ts +180 -0
  576. package/src/runtime/plugins/macos-capability-broker.ts +15 -105
  577. package/src/runtime/plugins/resend-adapter.ts +15 -24
  578. package/src/runtime/plugins/store.ts +493 -51
  579. package/src/runtime/plugins/types.ts +8 -1
  580. package/src/runtime/plugins/uu-remote-rescue-registration.ts +155 -0
  581. package/src/runtime/plugins/windows-host-recovery-install.ts +68 -0
  582. package/src/runtime/plugins/windows-host-recovery-registration.ts +85 -0
  583. package/src/runtime/plugins/xiaohongshu-publish.ts +86 -430
  584. package/src/runtime/projections/controller-context.ts +12 -6
  585. package/src/runtime/projections/git-status-sampler.ts +73 -22
  586. package/src/runtime/projections/materialized-view.ts +14 -8
  587. package/src/runtime/recovery/capability-action-application.ts +228 -0
  588. package/src/runtime/recovery/index.ts +3 -0
  589. package/src/runtime/recovery/lifecycle-inventory.ts +338 -0
  590. package/src/runtime/recovery/local-jobs-repair.ts +14 -14
  591. package/src/runtime/recovery/maintenance-executor.ts +358 -76
  592. package/src/runtime/recovery/quarantine-retention.ts +256 -0
  593. package/src/runtime/release/identity.ts +6 -0
  594. package/src/runtime/resources/leases/store.ts +1 -1
  595. package/src/runtime/root/active-execution-power-assertion.ts +139 -0
  596. package/src/runtime/root/assistant-learning-loop.ts +45 -0
  597. package/src/runtime/root/browser-session-composition.ts +59 -0
  598. package/src/runtime/root/computer-composition.ts +191 -0
  599. package/src/runtime/root/computer-target-composition.ts +16 -0
  600. package/src/runtime/root/computer-target-persistence.ts +39 -0
  601. package/src/runtime/root/controller-round-composition.ts +107 -0
  602. package/src/runtime/root/controller-services.ts +2 -0
  603. package/src/runtime/root/entry.ts +4 -3
  604. package/src/runtime/root/gateway-adapter.ts +3 -3
  605. package/src/runtime/root/local-bridge.ts +5 -2
  606. package/src/runtime/root/mcp-transport.ts +5 -5
  607. package/src/runtime/root/package-connector-service.ts +108 -56
  608. package/src/runtime/root/package-runtime-release.ts +86 -18
  609. package/src/runtime/root/package-runtime-service.ts +63 -86
  610. package/src/runtime/root/release-execution-canary.ts +71 -0
  611. package/src/runtime/root/release-loader.ts +68 -0
  612. package/src/runtime/root/release-manifest.ts +106 -2
  613. package/src/runtime/root/release-materialize.ts +103 -4
  614. package/src/runtime/root/release-store.ts +31 -2
  615. package/src/runtime/root/runtime.ts +240 -25
  616. package/src/runtime/root/scheduled-controller-composition.ts +51 -0
  617. package/src/runtime/root/scheduler.ts +12 -4
  618. package/src/runtime/root/service-runner.ts +1 -1
  619. package/src/runtime/root/service.ts +41 -16
  620. package/src/runtime/root/status.ts +1 -0
  621. package/src/runtime/root/types.ts +24 -1
  622. package/src/runtime/shared/local-bridge-surface.ts +1 -1
  623. package/src/runtime/shared/process-environment.ts +19 -4
  624. package/src/runtime/shared/storage-capacity.ts +68 -0
  625. package/src/runtime/standalone-recovery/controller-home-migration.ts +1116 -0
  626. package/src/runtime/standalone-recovery/core.ts +984 -230
  627. package/src/runtime/standalone-recovery/entry.ts +182 -51
  628. package/src/runtime/standalone-recovery/independent-host-rescue.ts +172 -0
  629. package/src/runtime/standalone-recovery/installer.ts +212 -104
  630. package/src/runtime/standalone-recovery/mcp-server.ts +243 -0
  631. package/src/runtime/standalone-recovery/mutation-identity-contract.ts +21 -0
  632. package/src/runtime/standalone-recovery/operation-lock.ts +160 -0
  633. package/src/runtime/standalone-recovery/performance.ts +135 -0
  634. package/src/runtime/standalone-recovery/release.ts +5 -0
  635. package/src/runtime/watchdog/workflow-watchdog.ts +1 -1
  636. package/src/runtime/workflow/schedules/chatgpt-automation-migration.ts +1 -1
  637. package/src/runtime/workflow/schedules/engine.ts +191 -343
  638. package/src/runtime/workflow/schedules/pending-activation.ts +1 -1
  639. package/src/runtime/workflow/schedules/settlement.ts +2 -191
  640. package/src/runtime/workflow/schedules/store.ts +2 -607
  641. package/src/runtime/workflow/schedules/types.ts +2 -127
  642. package/src/runtime/workflow/schedules/work-continuation.ts +180 -15
  643. package/src/runtime/workflows/first-party/xiaohongshu.ts +122 -0
  644. package/src/runtime/workflows/runtime.ts +486 -0
  645. package/src/testing/test-governance.ts +90 -29
  646. package/assets/templates/helpers/archive-architecture-request.sh +0 -244
  647. package/docs/architecture/history/README.md +0 -7
  648. package/docs/architecture/history/chatgpt-handoff-facade.md +0 -397
  649. package/docs/architecture/history/global-hook-runtime.md +0 -166
  650. package/docs/architecture/history/ios-semantic-automation-provider-v2.md +0 -170
  651. package/docs/architecture/requests/archive/2026/20260528-154740-ai-hooks-ai-hooks-hook-input-sh.md +0 -59
  652. package/docs/architecture/requests/archive/2026/20260528-154816-assets-hooks-assets-hooks-hook-input-sh.md +0 -59
  653. package/docs/architecture/requests/archive/2026/20260528-161851-ai-harness-workflow-contract-json-ai-harness-workflow-contract-json.md +0 -59
  654. package/docs/architecture/requests/archive/2026/20260528-161853-scripts-check-task-workflow-sh-scripts-check-task-workflow-sh.md +0 -59
  655. package/docs/architecture/requests/archive/2026/20260528-161911-assets-workflow-contract-v1-json-assets-workflow-contract-v1-json.md +0 -59
  656. package/docs/architecture/requests/archive/2026/20260528-222416-ai-hooks-ai-hooks-hook-input-sh.md +0 -59
  657. package/docs/architecture/requests/archive/2026/20260528-222444-ai-hooks-ai-hooks-pre-edit-guard-sh.md +0 -59
  658. package/docs/architecture/requests/archive/2026/20260528-222457-ai-hooks-ai-hooks-pre-edit-guard-sh.md +0 -59
  659. package/docs/architecture/requests/archive/2026/20260528-222648-ai-hooks-ai-hooks-pre-edit-guard-sh.md +0 -59
  660. package/docs/architecture/requests/archive/2026/20260528-222705-ai-hooks-ai-hooks-worktree-guard-sh.md +0 -59
  661. package/docs/architecture/requests/archive/2026/20260528-222726-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -59
  662. package/docs/architecture/requests/archive/2026/20260528-222727-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -59
  663. package/docs/architecture/requests/archive/2026/20260528-224736-ai-hooks-ai-hooks-hook-input-sh.md +0 -59
  664. package/docs/architecture/requests/archive/2026/20260528-233259-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -59
  665. package/docs/architecture/requests/archive/2026/20260528-233335-assets-hooks-assets-hooks-prompt-guard-sh.md +0 -59
  666. package/docs/architecture/requests/archive/2026/20260528-233456-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -59
  667. package/docs/architecture/requests/archive/2026/20260528-233457-assets-hooks-assets-hooks-prompt-guard-sh.md +0 -59
  668. package/docs/architecture/requests/archive/2026/20260528-233637-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -59
  669. package/docs/architecture/requests/archive/2026/20260528-233638-assets-hooks-assets-hooks-prompt-guard-sh.md +0 -59
  670. package/docs/architecture/requests/archive/2026/20260529-000322-root-package-json.md +0 -59
  671. package/docs/architecture/requests/archive/2026/20260529-004238-ai-hooks-ai-hooks-lib-workflow-state-sh.md +0 -59
  672. package/docs/architecture/requests/archive/2026/20260529-020654-ai-harness-policy-json-ai-harness-policy-json.md +0 -63
  673. package/docs/architecture/requests/archive/2026/20260529-094236-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -60
  674. package/docs/architecture/requests/archive/2026/20260529-094323-assets-hooks-assets-hooks-prompt-guard-sh.md +0 -60
  675. package/docs/architecture/requests/archive/2026/20260529-094331-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -60
  676. package/docs/architecture/requests/archive/2026/20260529-094339-assets-hooks-assets-hooks-prompt-guard-sh.md +0 -60
  677. package/docs/architecture/requests/archive/2026/20260529-094430-assets-hooks-assets-hooks-session-start-context-sh.md +0 -60
  678. package/docs/architecture/requests/archive/2026/20260529-094446-ai-hooks-ai-hooks-session-start-context-sh.md +0 -60
  679. package/docs/architecture/requests/archive/2026/20260613-002040-runtime-harness-hook-adapters.md +0 -68
  680. package/docs/architecture/requests/archive/2026/root.md +0 -68
  681. package/docs/architecture/requests/archive/2026/runtime-harness-hook-adapters.md +0 -76
  682. package/docs/architecture/requests/archive/2026/verification-evals-checks.md +0 -68
  683. package/docs/architecture/requests/archive/2026/workflow-engine-contract-assets.md +0 -69
  684. package/scripts/archive-architecture-request.sh +0 -4
  685. package/scripts/run-skill-evals.ts +0 -1022
@@ -10,8 +10,27 @@ import {
10
10
  } from 'fs';
11
11
  import { join, relative, resolve } from 'path';
12
12
  import { ensureControllerHome } from '../../cli/repositories/controller-home';
13
+ import { cleanupTerminalEditSessionRecords } from '../../cli/editing/edit-session';
14
+ import { listRepositories } from '../../cli/repositories/registry';
15
+ import { managedPathInside, managedWorktreeStorageRoot } from '../../cli/repositories/worktree-storage';
16
+ import { migrateManagedWorkspacePhysicalDependenciesToCanonical } from '../execution/managed-workspace';
17
+ import { cleanupStaleCodegraphLocators } from '../context/codegraph-cache-boundary';
18
+ import { listActiveLeases } from '../resources/leases/store';
19
+ import { cleanupScheduleOccurrenceHistory } from '../../../packages/kernel/scheduler/api/index';
20
+ import { isTerminalWorkContractStatus, readWorkContractStore } from '../../../packages/kernel/work/api/index';
13
21
  import { appendJsonLine, readJsonFile, writeJsonAtomic } from '../shared/json-files';
14
22
  import { cleanupControllerReleaseHistory } from './release-retention';
23
+ import { cleanupWorkPreservationArtifacts } from './cleanup-artifact-retention';
24
+ import { cleanupCodegraphCaches, CODEGRAPH_CACHE_RETENTION_POLICY_VERSION } from './codegraph-cache-retention';
25
+ import { cleanupRetiredRepositoryNamespaces } from './repository-namespace-retention';
26
+ import { maintainControlPlaneDatabase, type ControlPlaneDatabaseMaintenanceReport } from './persistence/sqlite-store';
27
+ import { cleanupExpiredExperiences } from './persistence/experience-store';
28
+ import { retireTerminalPlanBoundWorkAuthorities } from './facade/plan-contract-store';
29
+ import { reconcileOwnerlessWorkAuthorities } from './execution/work-authority-reconciler';
30
+ import {
31
+ measureReclaimablePath,
32
+ RUNTIME_LIFECYCLE_RETENTION_POLICY_VERSION,
33
+ } from './lifecycle-retention-metrics';
15
34
 
16
35
  function numericSetting(value: string | undefined, fallback: number, minimum: number): number {
17
36
  const parsed = Number(value);
@@ -129,27 +148,81 @@ export interface RuntimeCleanupOptions {
129
148
  maxEntries?: number;
130
149
  /** Global removal budget for one cycle; automatic cleanup defaults to 50. */
131
150
  maxRemovals?: number;
151
+ /** Scheduler cleanup generation used to rotate removal priority without adding durable state. */
152
+ periodicSequence?: number;
132
153
  /** Minimum age before an unreferenced finalized release/backup can be reclaimed. */
133
154
  releaseRetentionGraceMs?: number;
134
155
  /** Minimum age before an abandoned runtime .staging-* directory can be reclaimed. */
135
156
  stagingReleaseRetentionGraceMs?: number;
157
+ /** Minimum age before a proven-redundant terminal Work preservation bundle can be reclaimed. */
158
+ cleanupArtifactRetentionGraceMs?: number;
159
+ /** Maximum age for terminal EditSession artifacts once no active Work owns them. */
160
+ editSessionRetentionMs?: number;
161
+ /** Count cap for newest terminal EditSession artifacts retained for local review/debugging. */
162
+ editSessionMaxRetained?: number;
163
+ /** Grace period before a non-Plan Work with no exact durable owner loses execution authority. */
164
+ ownerlessWorkAuthorityGraceMs?: number;
165
+ /** Minimum age before an unprotected Forge-owned CodeGraph cache can be rebuilt on demand and reclaimed. */
166
+ codegraphCacheRetentionMs?: number;
167
+ /** Grace before a removed repository may shed only explicit disposable Controller Home children. */
168
+ repositoryNamespaceRetentionMs?: number;
169
+ /** Minimum reclaimable SQLite free-page bytes before physical VACUUM is eligible. */
170
+ sqliteVacuumMinReclaimableBytes?: number;
171
+ /** Minimum reclaimable SQLite free-page ratio before physical VACUUM is eligible. */
172
+ sqliteVacuumMinReclaimableRatio?: number;
136
173
  inspectProcess?: (pid: number) => RuntimeProcessSnapshot;
137
174
  }
138
175
 
176
+ export interface RuntimeCleanupLifecycleClassMetrics {
177
+ count: number;
178
+ bytes: number;
179
+ unknownByteCount: number;
180
+ }
181
+
182
+ export interface RuntimeCleanupLifecycleMetrics {
183
+ /** Physical disposable resources actually reclaimed by this cleanup authority. */
184
+ reclaimedCount: number;
185
+ reclaimedBytes: number;
186
+ unknownReclaimedByteCount: number;
187
+ reclaimedByClass: Record<string, RuntimeCleanupLifecycleClassMetrics>;
188
+ /** Semantic/execution authority records retired in place rather than physically deleted. */
189
+ logicalRetiredCount: number;
190
+ logicalRetiredByClass: Record<string, number>;
191
+ protectedActiveCount: number;
192
+ protectedByReason: Record<string, number>;
193
+ blockerReasons: Record<string, number>;
194
+ }
195
+
139
196
  export interface RuntimeCleanupReport {
197
+ policyVersion: typeof RUNTIME_LIFECYCLE_RETENTION_POLICY_VERSION;
140
198
  at: string;
141
199
  reason: 'startup' | 'periodic' | 'manual';
142
200
  removedPidFiles: string[];
143
201
  skippedPidFiles: string[];
144
202
  removedWorktrees: string[];
203
+ migratedDependencyPaths: string[];
145
204
  removedTemporaryPaths: string[];
205
+ removedCleanupArtifactPaths: string[];
146
206
  removedReleasePaths: string[];
207
+ removedScheduleOccurrencePaths: string[];
208
+ removedScheduleDecisionPaths: string[];
209
+ removedEditSessionPaths: string[];
210
+ removedCodegraphLocatorPaths: string[];
211
+ removedCodegraphCachePaths: string[];
212
+ removedRepositoryNamespacePaths: string[];
213
+ /** Physical SQLite checkpoint/compaction receipt; row lifecycle remains domain-owned. */
214
+ sqliteMaintenance?: ControlPlaneDatabaseMaintenanceReport;
215
+ /** Historical non-terminal Work whose owning Plan was already terminal. Records remain for retention/audit. */
216
+ retiredPlanBoundWorkAuthorities: string[];
217
+ /** Work retired only after exact per-Work liveness proved no durable continuation owner remains. */
218
+ retiredOwnerlessWorkAuthorities: string[];
147
219
  skippedActiveWorktrees: string[];
148
220
  inspectedPaths: number;
149
221
  budgetExhausted: boolean;
150
222
  errors: string[];
151
223
  logPath: string;
152
224
  cycle: CleanupCycleSummary;
225
+ lifecycleMetrics: RuntimeCleanupLifecycleMetrics;
153
226
  }
154
227
 
155
228
  export interface CleanupCycleSummary {
@@ -180,6 +253,33 @@ interface RemovalBudget {
180
253
  exhausted: boolean;
181
254
  }
182
255
 
256
+ interface MutableReclaimMetrics {
257
+ reclaimedBytes: number;
258
+ unknownReclaimedByteCount: number;
259
+ }
260
+
261
+ function emptyReclaimMetrics(): MutableReclaimMetrics {
262
+ return { reclaimedBytes: 0, unknownReclaimedByteCount: 0 };
263
+ }
264
+
265
+ function addReclaimMeasurement(metrics: MutableReclaimMetrics, path: string): void {
266
+ const measurement = measureReclaimablePath(path);
267
+ if (measurement.complete) metrics.reclaimedBytes += measurement.bytes;
268
+ else metrics.unknownReclaimedByteCount += 1;
269
+ }
270
+
271
+ type RemovalPhase = 'worktrees' | 'temporary' | 'artifacts' | 'scheduler' | 'edit_sessions' | 'caches' | 'repository_namespaces' | 'releases';
272
+ const REMOVAL_PHASES: readonly RemovalPhase[] = ['worktrees', 'temporary', 'artifacts', 'scheduler', 'edit_sessions', 'caches', 'repository_namespaces', 'releases'];
273
+
274
+ export function cleanupRemovalPhaseOrder(reason: RuntimeCleanupReport['reason'], sequence = 0): RemovalPhase[] {
275
+ if (reason !== 'periodic') return [...REMOVAL_PHASES];
276
+ const offset = ((Math.trunc(sequence) % REMOVAL_PHASES.length) + REMOVAL_PHASES.length) % REMOVAL_PHASES.length;
277
+ // Periodic maintenance is a bounded shard, not a reordered full sweep.
278
+ // Eight one-minute generations cover every removal class once while startup/manual
279
+ // cleanup retains the complete all-phase contract.
280
+ return [REMOVAL_PHASES[offset]!];
281
+ }
282
+
183
283
  interface WorktreeReferences {
184
284
  referenced: Set<string>;
185
285
  unsafeRepositories: Set<string>;
@@ -271,9 +371,10 @@ function cleanupDaemonPidFile(
271
371
  options: RuntimeCleanupOptions,
272
372
  errors: string[],
273
373
  removalBudget: RemovalBudget,
274
- ): { removed: string[]; skipped: string[] } {
374
+ ): { removed: string[]; skipped: string[]; reclaim: MutableReclaimMetrics } {
375
+ const reclaim = emptyReclaimMetrics();
275
376
  const pidPath = join(controllerHome, 'daemon', 'controller.pid');
276
- if (!existsSync(pidPath)) return { removed: [], skipped: [] };
377
+ if (!existsSync(pidPath)) return { removed: [], skipped: [], reclaim };
277
378
  let parsedPid: number | undefined;
278
379
  try {
279
380
  const candidate = Number.parseInt(readFileSync(pidPath, 'utf8').trim(), 10);
@@ -284,32 +385,33 @@ function cleanupDaemonPidFile(
284
385
 
285
386
  if (removalBudget.remaining <= 0) {
286
387
  removalBudget.exhausted = true;
287
- return { removed: [], skipped: [relativeHomePath(controllerHome, pidPath)] };
388
+ return { removed: [], skipped: [relativeHomePath(controllerHome, pidPath)], reclaim };
288
389
  }
289
390
 
290
391
  if (parsedPid) {
291
392
  const snapshot = (options.inspectProcess ?? inspectProcessDefault)(parsedPid);
292
393
  if (snapshot.alive) {
293
394
  if (parsedPid === options.protectedControllerPid || expectedDaemonCommand(controllerHome, snapshot.commandLine)) {
294
- return { removed: [], skipped: [relativeHomePath(controllerHome, pidPath)] };
395
+ return { removed: [], skipped: [relativeHomePath(controllerHome, pidPath)], reclaim };
295
396
  }
296
397
  if (!snapshot.commandLine) {
297
398
  errors.push(`daemon/controller.pid: live PID ${parsedPid} command identity is unavailable`);
298
- return { removed: [], skipped: [relativeHomePath(controllerHome, pidPath)] };
399
+ return { removed: [], skipped: [relativeHomePath(controllerHome, pidPath)], reclaim };
299
400
  }
300
401
  // PID reuse or an unrelated live process: remove only the stale reference.
301
402
  // Never signal a process whose daemon identity is not proven.
302
403
  }
303
404
  }
304
405
 
406
+ addReclaimMeasurement(reclaim, pidPath);
305
407
  try {
306
408
  removalBudget.remaining -= 1;
307
409
  rmSync(pidPath, { force: true });
308
410
  updateDaemonStateForStalePid(controllerHome, parsedPid, nowIso);
309
- return { removed: [relativeHomePath(controllerHome, pidPath)], skipped: [] };
411
+ return { removed: [relativeHomePath(controllerHome, pidPath)], skipped: [], reclaim };
310
412
  } catch (error) {
311
413
  errors.push(errorText('daemon/controller.pid removal failed', error));
312
- return { removed: [], skipped: [] };
414
+ return { removed: [], skipped: [], reclaim: emptyReclaimMetrics() };
313
415
  }
314
416
  }
315
417
 
@@ -501,9 +603,10 @@ function cleanupOrphanWorktrees(
501
603
  nowMs: number,
502
604
  errors: string[],
503
605
  removalBudget: RemovalBudget,
504
- ): { removed: string[]; skippedActive: string[]; skippedByReason: Record<string, number> } {
606
+ ): { removed: string[]; skippedActive: string[]; skippedByReason: Record<string, number>; reclaim: MutableReclaimMetrics } {
505
607
  const removed: string[] = [];
506
608
  const skippedActive: string[] = [];
609
+ const reclaim = emptyReclaimMetrics();
507
610
  const skippedByReason: Record<string, number> = {};
508
611
  const skip = (reason: string): void => { skippedByReason[reason] = (skippedByReason[reason] ?? 0) + 1; };
509
612
  const repositoriesRoot = join(controllerHome, 'repositories');
@@ -532,15 +635,74 @@ function cleanupOrphanWorktrees(
532
635
  return;
533
636
  }
534
637
  removalBudget.remaining -= 1;
638
+ const measurement = measureReclaimablePath(path);
535
639
  if (removeOrphanWorktreeDirectory(path, errors, relativePath)) {
536
640
  removed.push(relativePath);
641
+ if (measurement.complete) reclaim.reclaimedBytes += measurement.bytes;
642
+ else reclaim.unknownReclaimedByteCount += 1;
537
643
  }
538
644
  } catch (error) {
539
645
  errors.push(errorText(`worktree cleanup ${relativePath}`, error));
540
646
  }
541
647
  });
542
648
  });
543
- return { removed, skippedActive, skippedByReason };
649
+ return { removed, skippedActive, skippedByReason, reclaim };
650
+ }
651
+
652
+ function cleanupManagedWorktreeDependencyCopies(
653
+ controllerHome: string,
654
+ budget: ScanBudget,
655
+ errors: string[],
656
+ removalBudget: RemovalBudget,
657
+ ): { migrated: string[]; skippedByReason: Record<string, number> } {
658
+ const migrated: string[] = [];
659
+ const skippedByReason: Record<string, number> = {};
660
+ const skip = (reason: string): void => { skippedByReason[reason] = (skippedByReason[reason] ?? 0) + 1; };
661
+ let repositories;
662
+ try {
663
+ repositories = listRepositories(controllerHome, { includeRemoved: true });
664
+ } catch (error) {
665
+ errors.push(errorText('managed dependency repository inventory', error));
666
+ return { migrated, skippedByReason };
667
+ }
668
+ let storageRoot: string;
669
+ try {
670
+ storageRoot = managedWorktreeStorageRoot(controllerHome, repositories);
671
+ } catch (error) {
672
+ errors.push(errorText('managed dependency storage authority', error));
673
+ return { migrated, skippedByReason };
674
+ }
675
+ for (const repository of repositories) {
676
+ const activeLeases = listActiveLeases(controllerHome, repository.repoId);
677
+ for (const checkout of repository.checkouts) {
678
+ if (budget.remaining <= 0) { budget.exhausted = true; return { migrated, skippedByReason }; }
679
+ budget.remaining -= 1;
680
+ budget.inspected += 1;
681
+ if (!checkout.worktree || checkout.lifecycle === 'removed' || checkout.lifecycle === 'archived') continue;
682
+ const root = checkout.canonicalRoot;
683
+ if (!existsSync(root) || !managedPathInside(storageRoot, root)) { skip('dependency_outside_managed_authority'); continue; }
684
+ const dependencyPath = join(root, 'node_modules');
685
+ if (!existsSync(dependencyPath)) continue;
686
+ let dependencyStats;
687
+ try { dependencyStats = lstatSync(dependencyPath); } catch (error) { errors.push(errorText(`managed dependency stat ${root}`, error)); continue; }
688
+ if (dependencyStats.isSymbolicLink()) continue;
689
+ if (!dependencyStats.isDirectory()) { skip('dependency_path_not_directory'); continue; }
690
+ if (activeLeases.some((lease) => lease.checkoutId === checkout.checkoutId || lease.resourceKey === `workspace:${checkout.checkoutId}`)) {
691
+ skip('dependency_active_owner');
692
+ continue;
693
+ }
694
+ if (removalBudget.remaining <= 0) { removalBudget.exhausted = true; skip('cleanup_budget_exhausted'); continue; }
695
+ try {
696
+ const result = migrateManagedWorkspacePhysicalDependenciesToCanonical(root);
697
+ if (!result) { skip('dependency_not_reusable'); continue; }
698
+ removalBudget.remaining -= 1;
699
+ migrated.push(relativeHomePath(controllerHome, dependencyPath));
700
+ } catch (error) {
701
+ errors.push(errorText(`managed dependency migration ${root}`, error));
702
+ }
703
+ }
704
+ }
705
+ return { migrated, skippedByReason };
544
706
  }
545
707
 
546
708
  function worktreeContentPath(relativePath: string): boolean {
@@ -557,6 +719,7 @@ function removeStaleTempEntry(
557
719
  errors: string[],
558
720
  removalBudget: RemovalBudget,
559
721
  skippedByReason: Record<string, number>,
722
+ reclaim: MutableReclaimMetrics,
560
723
  ): void {
561
724
  if (nowMs - mtimeMs < TEMP_STATE_TTL_MS) {
562
725
  skippedByReason.ttl_not_expired = (skippedByReason.ttl_not_expired ?? 0) + 1;
@@ -567,10 +730,13 @@ function removeStaleTempEntry(
567
730
  skippedByReason.cleanup_budget_exhausted = (skippedByReason.cleanup_budget_exhausted ?? 0) + 1;
568
731
  return;
569
732
  }
733
+ const measurement = measureReclaimablePath(path);
570
734
  try {
571
735
  removalBudget.remaining -= 1;
572
736
  rmSync(path, { recursive: isDirectory, force: true });
573
737
  removed.push(relativePath);
738
+ if (measurement.complete) reclaim.reclaimedBytes += measurement.bytes;
739
+ else reclaim.unknownReclaimedByteCount += 1;
574
740
  } catch (error) {
575
741
  errors.push(errorText(`temp-state cleanup ${relativePath}`, error));
576
742
  }
@@ -583,8 +749,9 @@ function cleanupTemporaryStatePaths(
583
749
  errors: string[],
584
750
  removalBudget: RemovalBudget,
585
751
  skippedByReason: Record<string, number>,
586
- ): string[] {
752
+ ): { removed: string[]; reclaim: MutableReclaimMetrics } {
587
753
  const removed: string[] = [];
754
+ const reclaim = emptyReclaimMetrics();
588
755
  const visit = (directory: string, depth: number, leafOnly = false): void => {
589
756
  if (budget.exhausted || depth > TEMP_SCAN_MAX_DEPTH) return;
590
757
  visitDirectoryEntries(directory, budget, errors, (entry) => {
@@ -602,7 +769,7 @@ function cleanupTemporaryStatePaths(
602
769
  }
603
770
 
604
771
  if (entry.name.endsWith('.tmp')) {
605
- removeStaleTempEntry(path, relativePath, entry.isDirectory(), stats.mtimeMs, nowMs, removed, errors, removalBudget, skippedByReason);
772
+ removeStaleTempEntry(path, relativePath, entry.isDirectory(), stats.mtimeMs, nowMs, removed, errors, removalBudget, skippedByReason, reclaim);
606
773
  return;
607
774
  }
608
775
 
@@ -622,7 +789,7 @@ function cleanupTemporaryStatePaths(
622
789
  // burn its entire budget walking historical job records.
623
790
  visit(join(controllerHome, 'daemon'), 0);
624
791
  visit(join(controllerHome, 'repositories'), 0);
625
- return removed;
792
+ return { removed, reclaim };
626
793
  }
627
794
 
628
795
  function shouldPersistCleanupAudit(report: RuntimeCleanupReport): boolean {
@@ -631,8 +798,17 @@ function shouldPersistCleanupAudit(report: RuntimeCleanupReport): boolean {
631
798
  const hadMutations = Boolean(
632
799
  report.removedPidFiles.length
633
800
  || report.removedWorktrees.length
801
+ || report.migratedDependencyPaths.length
634
802
  || report.removedTemporaryPaths.length
635
- || report.removedReleasePaths.length,
803
+ || report.removedCleanupArtifactPaths.length
804
+ || report.removedReleasePaths.length
805
+ || report.removedCodegraphLocatorPaths.length
806
+ || report.removedCodegraphCachePaths.length
807
+ || report.removedRepositoryNamespacePaths.length
808
+ || report.sqliteMaintenance?.vacuumed
809
+ || report.sqliteMaintenance?.skippedReason === 'database_busy'
810
+ || report.retiredPlanBoundWorkAuthorities.length
811
+ || report.retiredOwnerlessWorkAuthorities.length,
636
812
  );
637
813
  if (hadMutations || report.errors.length) return true;
638
814
  // Startup/manual may record defensive skips (live PID protected, budget).
@@ -656,51 +832,412 @@ export function cleanupControllerRuntimeState(
656
832
  // worktree reference collection or orphan worktree removal.
657
833
  const referenceBudget = createScanBudget(maxEntries);
658
834
  const worktreeBudget = createScanBudget(maxEntries);
835
+ const dependencyBudget = createScanBudget(maxEntries);
659
836
  const tempBudget = createScanBudget(maxEntries);
837
+ const schedulerBudget = createScanBudget(maxEntries);
838
+ const editSessionBudget = createScanBudget(maxEntries);
660
839
  const errors: string[] = [];
661
840
  const skippedByReason: Record<string, number> = {};
841
+ const sequence = options.periodicSequence ?? Math.floor(nowMs / 60_000);
842
+ const removalPhases = cleanupRemovalPhaseOrder(options.reason ?? 'manual', sequence);
843
+ const periodic = (options.reason ?? 'manual') === 'periodic';
844
+ const retiredPlanBoundWorkAuthorities: string[] = [];
845
+ const retiredOwnerlessWorkAuthorities: string[] = [];
846
+ if (!periodic || removalPhases.includes('repository_namespaces')) try {
847
+ for (const repository of listRepositories(home, { includeRemoved: true })) {
848
+ const retired = retireTerminalPlanBoundWorkAuthorities({ controllerHome: home, repoId: repository.repoId });
849
+ retiredPlanBoundWorkAuthorities.push(...retired.map((workId) => `${repository.repoId}:${workId}`));
850
+ const ownerless = reconcileOwnerlessWorkAuthorities({
851
+ controllerHome: home,
852
+ repoId: repository.repoId,
853
+ nowMs,
854
+ graceMs: options.ownerlessWorkAuthorityGraceMs,
855
+ });
856
+ retiredOwnerlessWorkAuthorities.push(...ownerless.workIds.map((workId) => `${repository.repoId}:${workId}`));
857
+ Object.entries(ownerless.skippedByReason).forEach(([key, value]) => {
858
+ skippedByReason[`ownerless_work_${key}`] = (skippedByReason[`ownerless_work_${key}`] ?? 0) + value;
859
+ });
860
+ }
861
+ } catch (error) {
862
+ errors.push(errorText('Work authority reconciliation', error));
863
+ }
662
864
  const pidFiles = cleanupDaemonPidFile(home, nowIso, options, errors, removalBudget);
663
- const references = collectReferencedWorktrees(home, referenceBudget, errors, nowMs);
664
- const worktrees = cleanupOrphanWorktrees(home, references, worktreeBudget, nowMs, errors, removalBudget);
665
- Object.entries(worktrees.skippedByReason).forEach(([key, value]) => { skippedByReason[key] = (skippedByReason[key] ?? 0) + value; });
666
- const removedTemporaryPaths = cleanupTemporaryStatePaths(home, tempBudget, nowMs, errors, removalBudget, skippedByReason).sort();
667
- const releaseRetention = cleanupControllerReleaseHistory(home, {
668
- nowMs,
669
- graceMs: options.releaseRetentionGraceMs,
670
- stagingGraceMs: options.stagingReleaseRetentionGraceMs,
671
- maxRemovals: removalBudget.remaining,
672
- });
673
- removalBudget.remaining = Math.max(0, removalBudget.remaining - releaseRetention.attempted);
674
- if (releaseRetention.budgetExhausted) removalBudget.exhausted = true;
675
- Object.entries(releaseRetention.skippedByReason).forEach(([key, value]) => {
676
- skippedByReason[key] = (skippedByReason[key] ?? 0) + value;
677
- });
678
- errors.push(...releaseRetention.errors);
679
- const removedReleasePaths = releaseRetention.removedPaths;
680
- const inspectedPaths = referenceBudget.inspected + worktreeBudget.inspected + tempBudget.inspected + releaseRetention.inspected;
681
- const budgetExhausted = referenceBudget.exhausted || worktreeBudget.exhausted || tempBudget.exhausted || removalBudget.exhausted;
865
+ const references: WorktreeReferences = (!periodic || removalPhases.includes('worktrees'))
866
+ ? collectReferencedWorktrees(home, referenceBudget, errors, nowMs)
867
+ : { referenced: new Set<string>(), unsafeRepositories: new Set<string>(), complete: true };
868
+ let worktrees: ReturnType<typeof cleanupOrphanWorktrees> | undefined;
869
+ let dependencyCleanup: ReturnType<typeof cleanupManagedWorktreeDependencyCopies> | undefined;
870
+ let temporaryCleanup: ReturnType<typeof cleanupTemporaryStatePaths> | undefined;
871
+ let artifactRetention: ReturnType<typeof cleanupWorkPreservationArtifacts> | undefined;
872
+ let releaseRetention: ReturnType<typeof cleanupControllerReleaseHistory> | undefined;
873
+ let codegraphRetention: ReturnType<typeof cleanupCodegraphCaches> | undefined;
874
+ let repositoryNamespaceRetention: ReturnType<typeof cleanupRetiredRepositoryNamespaces> | undefined;
875
+ const removedCodegraphLocatorPaths: string[] = [];
876
+ let codegraphLocatorInspected = 0;
877
+ let codegraphLocatorRetained = 0;
878
+ const schedulerHistory = {
879
+ removedOccurrencePaths: [] as string[],
880
+ removedDecisionPaths: [] as string[],
881
+ reclaimedBytes: 0,
882
+ unknownReclaimedByteCount: 0,
883
+ inspected: 0,
884
+ eligible: 0,
885
+ attempted: 0,
886
+ retained: 0,
887
+ errors: [] as string[],
888
+ };
889
+ const editSessionHistory = {
890
+ removedPaths: [] as string[],
891
+ reclaimedBytes: 0,
892
+ unknownReclaimedByteCount: 0,
893
+ inspected: 0,
894
+ eligible: 0,
895
+ attempted: 0,
896
+ retained: 0,
897
+ errors: [] as string[],
898
+ };
899
+ for (const phase of removalPhases) {
900
+ if (phase === 'worktrees') {
901
+ dependencyCleanup = cleanupManagedWorktreeDependencyCopies(home, dependencyBudget, errors, removalBudget);
902
+ Object.entries(dependencyCleanup.skippedByReason).forEach(([key, value]) => { skippedByReason[key] = (skippedByReason[key] ?? 0) + value; });
903
+ worktrees = cleanupOrphanWorktrees(home, references, worktreeBudget, nowMs, errors, removalBudget);
904
+ Object.entries(worktrees.skippedByReason).forEach(([key, value]) => { skippedByReason[key] = (skippedByReason[key] ?? 0) + value; });
905
+ continue;
906
+ }
907
+ if (phase === 'temporary') {
908
+ temporaryCleanup = cleanupTemporaryStatePaths(home, tempBudget, nowMs, errors, removalBudget, skippedByReason);
909
+ continue;
910
+ }
911
+ if (phase === 'artifacts') {
912
+ if (removalBudget.remaining > 0) {
913
+ try {
914
+ const removed = cleanupExpiredExperiences(home, new Date(nowMs).toISOString(), Math.min(100, removalBudget.remaining));
915
+ removalBudget.remaining -= removed;
916
+ } catch (error) { errors.push(`experience-retention: ${error instanceof Error ? error.message : 'failed'}`); }
917
+ }
918
+ artifactRetention = cleanupWorkPreservationArtifacts(home, {
919
+ nowMs,
920
+ graceMs: options.cleanupArtifactRetentionGraceMs,
921
+ maxEntries,
922
+ maxRemovals: removalBudget.remaining,
923
+ });
924
+ removalBudget.remaining = Math.max(0, removalBudget.remaining - artifactRetention.attempted);
925
+ if (artifactRetention.budgetExhausted) removalBudget.exhausted = true;
926
+ Object.entries(artifactRetention.skippedByReason).forEach(([key, value]) => {
927
+ skippedByReason[`cleanup_artifact_${key}`] = (skippedByReason[`cleanup_artifact_${key}`] ?? 0) + value;
928
+ });
929
+ errors.push(...artifactRetention.errors.map((error) => `cleanup-artifact ${error}`));
930
+ continue;
931
+ }
932
+ if (phase === 'scheduler') {
933
+ for (const repository of listRepositories(home, { includeRemoved: true })) {
934
+ if (schedulerBudget.remaining <= 0 || removalBudget.remaining <= 0) {
935
+ if (schedulerBudget.remaining <= 0) schedulerBudget.exhausted = true;
936
+ if (removalBudget.remaining <= 0) removalBudget.exhausted = true;
937
+ break;
938
+ }
939
+ const retained = cleanupScheduleOccurrenceHistory(home, repository.repoId, {
940
+ maxEntries: schedulerBudget.remaining,
941
+ maxRemovals: removalBudget.remaining,
942
+ });
943
+ schedulerBudget.remaining = Math.max(0, schedulerBudget.remaining - retained.inspected);
944
+ schedulerBudget.inspected += retained.inspected;
945
+ if (retained.budgetExhausted && schedulerBudget.remaining <= 0) schedulerBudget.exhausted = true;
946
+ removalBudget.remaining = Math.max(0, removalBudget.remaining - retained.attempted);
947
+ if (retained.budgetExhausted && removalBudget.remaining <= 0) removalBudget.exhausted = true;
948
+ schedulerHistory.inspected += retained.inspected;
949
+ schedulerHistory.eligible += retained.eligible;
950
+ schedulerHistory.attempted += retained.attempted;
951
+ schedulerHistory.retained += retained.retained;
952
+ schedulerHistory.reclaimedBytes += retained.reclaimedBytes;
953
+ schedulerHistory.unknownReclaimedByteCount += retained.unknownReclaimedByteCount;
954
+ schedulerHistory.removedOccurrencePaths.push(...retained.removedOccurrencePaths.map((path) => `repositories/${repository.repoId}/schedules/${path}`));
955
+ schedulerHistory.removedDecisionPaths.push(...retained.removedDecisionPaths.map((path) => `repositories/${repository.repoId}/schedules/${path}`));
956
+ Object.entries(retained.skippedByReason).forEach(([key, value]) => {
957
+ skippedByReason[`scheduler_${key}`] = (skippedByReason[`scheduler_${key}`] ?? 0) + value;
958
+ });
959
+ schedulerHistory.errors.push(...retained.errors.map((error) => `${repository.repoId}:${error}`));
960
+ }
961
+ errors.push(...schedulerHistory.errors.map((error) => `scheduler-history ${error}`));
962
+ continue;
963
+ }
964
+ if (phase === 'edit_sessions') {
965
+ for (const repository of listRepositories(home, { includeRemoved: true })) {
966
+ if (editSessionBudget.remaining <= 0 || removalBudget.remaining <= 0) {
967
+ if (editSessionBudget.remaining <= 0) editSessionBudget.exhausted = true;
968
+ if (removalBudget.remaining <= 0) removalBudget.exhausted = true;
969
+ break;
970
+ }
971
+ let protectedWorkIds: string[];
972
+ try {
973
+ protectedWorkIds = readWorkContractStore({ controllerHome: home, repoId: repository.repoId }).contracts
974
+ .filter((contract) => !isTerminalWorkContractStatus(contract.status))
975
+ .map((contract) => contract.workId);
976
+ } catch (error) {
977
+ const message = error instanceof Error ? error.message : String(error);
978
+ skippedByReason.edit_session_work_authority_unavailable = (skippedByReason.edit_session_work_authority_unavailable ?? 0) + 1;
979
+ editSessionHistory.errors.push(`${repository.repoId}:work_authority_unavailable:${message}`);
980
+ continue;
981
+ }
982
+ const retained = cleanupTerminalEditSessionRecords(repository.canonicalRoot, {
983
+ nowMs,
984
+ retentionMs: options.editSessionRetentionMs,
985
+ maxRetained: options.editSessionMaxRetained,
986
+ maxEntries: editSessionBudget.remaining,
987
+ maxRemovals: removalBudget.remaining,
988
+ sequence,
989
+ protectedWorkIds,
990
+ });
991
+ editSessionBudget.remaining = Math.max(0, editSessionBudget.remaining - retained.inspected);
992
+ editSessionBudget.inspected += retained.inspected;
993
+ if (retained.budgetExhausted && editSessionBudget.remaining <= 0) editSessionBudget.exhausted = true;
994
+ removalBudget.remaining = Math.max(0, removalBudget.remaining - retained.attempted);
995
+ if (retained.budgetExhausted && removalBudget.remaining <= 0) removalBudget.exhausted = true;
996
+ editSessionHistory.inspected += retained.inspected;
997
+ editSessionHistory.eligible += retained.eligible;
998
+ editSessionHistory.attempted += retained.attempted;
999
+ editSessionHistory.retained += retained.retained;
1000
+ editSessionHistory.reclaimedBytes += retained.reclaimedBytes;
1001
+ editSessionHistory.unknownReclaimedByteCount += retained.unknownReclaimedByteCount;
1002
+ editSessionHistory.removedPaths.push(...retained.removedSessionIds.map((sessionId) => `repositories/${repository.repoId}/edit-sessions/${sessionId}`));
1003
+ Object.entries(retained.skippedByReason).forEach(([key, value]) => {
1004
+ skippedByReason[`edit_session_${key}`] = (skippedByReason[`edit_session_${key}`] ?? 0) + value;
1005
+ });
1006
+ editSessionHistory.errors.push(...retained.errors.map((error) => `${repository.repoId}:${error}`));
1007
+ }
1008
+ errors.push(...editSessionHistory.errors.map((error) => `edit-session-history ${error}`));
1009
+ continue;
1010
+ }
1011
+ if (phase === 'caches') {
1012
+ const registered = listRepositories(home, { includeRemoved: true });
1013
+ const repositoryRoots = new Set<string>();
1014
+ for (const repository of registered) {
1015
+ repositoryRoots.add(resolve(repository.canonicalRoot));
1016
+ repositoryRoots.add(resolve(repository.localRoot));
1017
+ for (const checkout of repository.checkouts) {
1018
+ repositoryRoots.add(resolve(checkout.canonicalRoot));
1019
+ repositoryRoots.add(resolve(checkout.localRoot));
1020
+ }
1021
+ }
1022
+ const protectedRepositoryRoots = new Set<string>();
1023
+ let locatorScanRemaining = maxEntries;
1024
+ for (const repositoryRoot of [...repositoryRoots].sort()) {
1025
+ if (!existsSync(repositoryRoot)) continue;
1026
+ if (locatorScanRemaining <= 0) {
1027
+ protectedRepositoryRoots.add(repositoryRoot);
1028
+ skippedByReason.codegraph_locator_scan_budget_exhausted = (skippedByReason.codegraph_locator_scan_budget_exhausted ?? 0) + 1;
1029
+ continue;
1030
+ }
1031
+ const locatorReport = cleanupStaleCodegraphLocators(
1032
+ repositoryRoot,
1033
+ home,
1034
+ locatorScanRemaining,
1035
+ removalBudget.remaining,
1036
+ );
1037
+ locatorScanRemaining = Math.max(0, locatorScanRemaining - locatorReport.inspected);
1038
+ removalBudget.remaining = Math.max(0, removalBudget.remaining - locatorReport.attempted);
1039
+ if (locatorReport.budgetExhausted && removalBudget.remaining <= 0) removalBudget.exhausted = true;
1040
+ codegraphLocatorInspected += locatorReport.inspected;
1041
+ codegraphLocatorRetained += Math.max(0, locatorReport.inspected - locatorReport.removed.length);
1042
+ removedCodegraphLocatorPaths.push(...locatorReport.removed.map((name) => join(repositoryRoot, name)));
1043
+ Object.entries(locatorReport.skippedByReason).forEach(([key, value]) => {
1044
+ skippedByReason[`codegraph_locator_${key}`] = (skippedByReason[`codegraph_locator_${key}`] ?? 0) + value;
1045
+ });
1046
+ const protectionUncertain = locatorReport.budgetExhausted
1047
+ || locatorReport.errors.length > 0
1048
+ || (locatorReport.skippedByReason.locator_identity_unproven ?? 0) > 0;
1049
+ if (locatorReport.active.length > 0 || protectionUncertain) protectedRepositoryRoots.add(repositoryRoot);
1050
+ if (locatorReport.budgetExhausted) {
1051
+ skippedByReason.codegraph_locator_scan_budget_exhausted = (skippedByReason.codegraph_locator_scan_budget_exhausted ?? 0) + 1;
1052
+ }
1053
+ errors.push(...locatorReport.errors.map((error) => `codegraph-locator ${repositoryRoot}: ${error}`));
1054
+ }
1055
+ codegraphRetention = cleanupCodegraphCaches(home, {
1056
+ nowMs,
1057
+ retentionMs: options.codegraphCacheRetentionMs,
1058
+ maxEntries,
1059
+ maxRemovals: removalBudget.remaining,
1060
+ protectedRepositoryRoots: [...protectedRepositoryRoots],
1061
+ });
1062
+ removalBudget.remaining = Math.max(0, removalBudget.remaining - codegraphRetention.attempted);
1063
+ if (codegraphRetention.budgetExhausted) removalBudget.exhausted = true;
1064
+ Object.entries(codegraphRetention.skippedByReason).forEach(([key, value]) => {
1065
+ skippedByReason[`codegraph_cache_${key}`] = (skippedByReason[`codegraph_cache_${key}`] ?? 0) + value;
1066
+ });
1067
+ errors.push(...codegraphRetention.errors.map((error) => `codegraph-cache ${error}`));
1068
+ continue;
1069
+ }
1070
+ if (phase === 'repository_namespaces') {
1071
+ repositoryNamespaceRetention = cleanupRetiredRepositoryNamespaces(home, {
1072
+ nowMs,
1073
+ graceMs: options.repositoryNamespaceRetentionMs,
1074
+ maxEntries,
1075
+ maxRemovals: removalBudget.remaining,
1076
+ });
1077
+ removalBudget.remaining = Math.max(0, removalBudget.remaining - repositoryNamespaceRetention.attempted);
1078
+ if (repositoryNamespaceRetention.budgetExhausted && removalBudget.remaining <= 0) removalBudget.exhausted = true;
1079
+ Object.entries(repositoryNamespaceRetention.skippedByReason).forEach(([key, value]) => {
1080
+ skippedByReason[`repository_namespace_${key}`] = (skippedByReason[`repository_namespace_${key}`] ?? 0) + value;
1081
+ });
1082
+ errors.push(...repositoryNamespaceRetention.errors.map((error) => `repository-namespace ${error}`));
1083
+ continue;
1084
+ }
1085
+ releaseRetention = cleanupControllerReleaseHistory(home, {
1086
+ nowMs,
1087
+ graceMs: options.releaseRetentionGraceMs,
1088
+ stagingGraceMs: options.stagingReleaseRetentionGraceMs,
1089
+ maxRemovals: removalBudget.remaining,
1090
+ });
1091
+ removalBudget.remaining = Math.max(0, removalBudget.remaining - releaseRetention.attempted);
1092
+ if (releaseRetention.budgetExhausted) removalBudget.exhausted = true;
1093
+ Object.entries(releaseRetention.skippedByReason).forEach(([key, value]) => {
1094
+ skippedByReason[key] = (skippedByReason[key] ?? 0) + value;
1095
+ });
1096
+ errors.push(...releaseRetention.errors);
1097
+ }
1098
+ if (periodic) {
1099
+ worktrees ??= { removed: [], skippedActive: [], skippedByReason: {}, reclaim: emptyReclaimMetrics() } as ReturnType<typeof cleanupOrphanWorktrees>;
1100
+ dependencyCleanup ??= { migrated: [], skippedByReason: {} } as ReturnType<typeof cleanupManagedWorktreeDependencyCopies>;
1101
+ temporaryCleanup ??= { removed: [], reclaim: emptyReclaimMetrics() } as ReturnType<typeof cleanupTemporaryStatePaths>;
1102
+ artifactRetention ??= { removedPaths: [], attempted: 0, budgetExhausted: false, skippedByReason: {}, errors: [], inspected: 0, eligible: 0, retained: 0, skipped: 0, reclaimedBytes: 0, unknownReclaimedByteCount: 0 } as ReturnType<typeof cleanupWorkPreservationArtifacts>;
1103
+ codegraphRetention ??= { policyVersion: CODEGRAPH_CACHE_RETENTION_POLICY_VERSION, removedPaths: [], attempted: 0, budgetExhausted: false, skippedByReason: {}, errors: [], inspected: 0, eligible: 0, retained: 0, reclaimedBytes: 0, unknownReclaimedByteCount: 0, observedBytes: 0, unknownObservedByteCount: 0, protected: 0, protectedOverCapacity: 0, truncated: false } as ReturnType<typeof cleanupCodegraphCaches>;
1104
+ repositoryNamespaceRetention ??= { policyVersion: 'repository-namespace-retention-v1', removedPaths: [], attempted: 0, budgetExhausted: false, skippedByReason: {}, errors: [], inspected: 0, eligible: 0, retained: 0, reclaimedBytes: 0, unknownReclaimedByteCount: 0 } as ReturnType<typeof cleanupRetiredRepositoryNamespaces>;
1105
+ releaseRetention ??= { removedPaths: [], removedBackupPaths: [], attempted: 0, budgetExhausted: false, skippedByReason: {}, errors: [], inspected: 0, eligible: 0, retained: 0, skipped: 0, reclaimedBytes: 0, unknownReclaimedByteCount: 0, reclaimedBackupBytes: 0, unknownReclaimedBackupByteCount: 0 } as ReturnType<typeof cleanupControllerReleaseHistory>;
1106
+ }
1107
+ if (!worktrees || !dependencyCleanup || !temporaryCleanup || !artifactRetention || !codegraphRetention || !repositoryNamespaceRetention || !releaseRetention) {
1108
+ throw new Error('RUNTIME_CLEANUP_PHASE_INCOMPLETE');
1109
+ }
1110
+ const removedTemporaryPaths = temporaryCleanup.removed.sort();
1111
+ const removedCleanupArtifactPaths = artifactRetention.removedPaths.sort();
1112
+ const removedReleasePaths = releaseRetention.removedPaths.sort();
1113
+ const removedScheduleOccurrencePaths = schedulerHistory.removedOccurrencePaths.sort();
1114
+ const removedScheduleDecisionPaths = schedulerHistory.removedDecisionPaths.sort();
1115
+ const removedEditSessionPaths = editSessionHistory.removedPaths.sort();
1116
+ removedCodegraphLocatorPaths.sort();
1117
+ const removedCodegraphCachePaths = codegraphRetention.removedPaths.sort();
1118
+ const removedRepositoryNamespacePaths = repositoryNamespaceRetention.removedPaths.sort();
1119
+ let sqliteMaintenance: ControlPlaneDatabaseMaintenanceReport | undefined;
1120
+ if (!periodic || removalPhases.includes('releases')) try {
1121
+ sqliteMaintenance = maintainControlPlaneDatabase(home, {
1122
+ minimumReclaimableBytes: options.sqliteVacuumMinReclaimableBytes,
1123
+ minimumReclaimableRatio: options.sqliteVacuumMinReclaimableRatio,
1124
+ });
1125
+ if (sqliteMaintenance.skippedReason === 'database_busy') {
1126
+ skippedByReason.sqlite_maintenance_busy = (skippedByReason.sqlite_maintenance_busy ?? 0) + 1;
1127
+ }
1128
+ } catch (error) {
1129
+ errors.push(errorText('SQLite maintenance', error));
1130
+ }
1131
+ const inspectedPaths = referenceBudget.inspected + worktreeBudget.inspected + dependencyBudget.inspected + tempBudget.inspected + schedulerBudget.inspected + editSessionBudget.inspected + artifactRetention.inspected + codegraphLocatorInspected + codegraphRetention.inspected + repositoryNamespaceRetention.inspected + releaseRetention.inspected;
1132
+ const budgetExhausted = referenceBudget.exhausted || worktreeBudget.exhausted || dependencyBudget.exhausted || tempBudget.exhausted || schedulerBudget.exhausted || editSessionBudget.exhausted || removalBudget.exhausted;
682
1133
  if (pidFiles.skipped.length > 0 && removalBudget.exhausted) skippedByReason.cleanup_budget_exhausted = (skippedByReason.cleanup_budget_exhausted ?? 0) + pidFiles.skipped.length;
683
1134
  if (pidFiles.skipped.length > 0 && !removalBudget.exhausted) skippedByReason.active_owner = (skippedByReason.active_owner ?? 0) + pidFiles.skipped.length;
1135
+ const physicalReclaimedByClass: Record<string, RuntimeCleanupLifecycleClassMetrics> = {
1136
+ managed_workspace_checkout: {
1137
+ count: worktrees.removed.length,
1138
+ bytes: worktrees.reclaim.reclaimedBytes,
1139
+ unknownByteCount: worktrees.reclaim.unknownReclaimedByteCount,
1140
+ },
1141
+ runtime_temp: {
1142
+ count: pidFiles.removed.length + removedTemporaryPaths.length + removedCodegraphLocatorPaths.length,
1143
+ bytes: pidFiles.reclaim.reclaimedBytes + temporaryCleanup.reclaim.reclaimedBytes,
1144
+ unknownByteCount: pidFiles.reclaim.unknownReclaimedByteCount + temporaryCleanup.reclaim.unknownReclaimedByteCount + removedCodegraphLocatorPaths.length,
1145
+ },
1146
+ work: {
1147
+ count: removedCleanupArtifactPaths.length,
1148
+ bytes: artifactRetention.reclaimedBytes,
1149
+ unknownByteCount: artifactRetention.unknownReclaimedByteCount,
1150
+ },
1151
+ release_artifact: {
1152
+ count: Math.max(0, removedReleasePaths.length - releaseRetention.removedBackupPaths.length),
1153
+ bytes: Math.max(0, releaseRetention.reclaimedBytes - releaseRetention.reclaimedBackupBytes),
1154
+ unknownByteCount: Math.max(0, releaseRetention.unknownReclaimedByteCount - releaseRetention.unknownReclaimedBackupByteCount),
1155
+ },
1156
+ recovery_backup: {
1157
+ count: releaseRetention.removedBackupPaths.length,
1158
+ bytes: releaseRetention.reclaimedBackupBytes,
1159
+ unknownByteCount: releaseRetention.unknownReclaimedBackupByteCount,
1160
+ },
1161
+ scheduler_occurrence_history: {
1162
+ count: removedScheduleOccurrencePaths.length + removedScheduleDecisionPaths.length,
1163
+ bytes: schedulerHistory.reclaimedBytes,
1164
+ unknownByteCount: schedulerHistory.unknownReclaimedByteCount,
1165
+ },
1166
+ edit_session: {
1167
+ count: removedEditSessionPaths.length,
1168
+ bytes: editSessionHistory.reclaimedBytes,
1169
+ unknownByteCount: editSessionHistory.unknownReclaimedByteCount,
1170
+ },
1171
+ codegraph_cache: {
1172
+ count: removedCodegraphCachePaths.length,
1173
+ bytes: codegraphRetention.reclaimedBytes,
1174
+ unknownByteCount: codegraphRetention.unknownReclaimedByteCount,
1175
+ },
1176
+ repository_controller_home_namespace: {
1177
+ count: removedRepositoryNamespacePaths.length,
1178
+ bytes: repositoryNamespaceRetention.reclaimedBytes,
1179
+ unknownByteCount: repositoryNamespaceRetention.unknownReclaimedByteCount,
1180
+ },
1181
+ sqlite_control_plane: {
1182
+ count: sqliteMaintenance?.vacuumed ? 1 : 0,
1183
+ bytes: sqliteMaintenance?.reclaimedBytes ?? 0,
1184
+ unknownByteCount: 0,
1185
+ },
1186
+ };
1187
+ const protectedByReason = Object.fromEntries(
1188
+ Object.entries(skippedByReason)
1189
+ .filter(([reason, count]) => count > 0 && (reason.includes('active') || reason.includes('authority') || reason.includes('protected')))
1190
+ .sort(([left], [right]) => left.localeCompare(right)),
1191
+ );
1192
+ const blockerReasons = Object.fromEntries(
1193
+ Object.entries(skippedByReason)
1194
+ .filter(([reason, count]) => count > 0 && (reason.includes('unknown') || reason.includes('budget') || reason.includes('unsafe') || reason.includes('unavailable') || reason.includes('busy')))
1195
+ .sort(([left], [right]) => left.localeCompare(right)),
1196
+ );
1197
+ const lifecycleMetrics: RuntimeCleanupLifecycleMetrics = {
1198
+ reclaimedCount: Object.values(physicalReclaimedByClass).reduce((total, entry) => total + entry.count, 0),
1199
+ reclaimedBytes: Object.values(physicalReclaimedByClass).reduce((total, entry) => total + entry.bytes, 0),
1200
+ unknownReclaimedByteCount: Object.values(physicalReclaimedByClass).reduce((total, entry) => total + entry.unknownByteCount, 0),
1201
+ reclaimedByClass: physicalReclaimedByClass,
1202
+ logicalRetiredCount: retiredPlanBoundWorkAuthorities.length + retiredOwnerlessWorkAuthorities.length,
1203
+ logicalRetiredByClass: { work: retiredPlanBoundWorkAuthorities.length + retiredOwnerlessWorkAuthorities.length },
1204
+ protectedActiveCount: Object.values(protectedByReason).reduce((total, count) => total + count, 0),
1205
+ protectedByReason,
1206
+ blockerReasons,
1207
+ };
684
1208
  const report: RuntimeCleanupReport = {
1209
+ policyVersion: RUNTIME_LIFECYCLE_RETENTION_POLICY_VERSION,
685
1210
  at: nowIso,
686
1211
  reason: options.reason ?? 'manual',
687
1212
  removedPidFiles: pidFiles.removed.sort(),
688
1213
  skippedPidFiles: pidFiles.skipped.sort(),
689
1214
  removedWorktrees: worktrees.removed.sort(),
1215
+ migratedDependencyPaths: dependencyCleanup.migrated.sort(),
690
1216
  removedTemporaryPaths,
1217
+ removedCleanupArtifactPaths,
691
1218
  removedReleasePaths,
1219
+ removedScheduleOccurrencePaths,
1220
+ removedScheduleDecisionPaths,
1221
+ removedEditSessionPaths,
1222
+ removedCodegraphLocatorPaths,
1223
+ removedCodegraphCachePaths,
1224
+ removedRepositoryNamespacePaths,
1225
+ sqliteMaintenance,
1226
+ retiredPlanBoundWorkAuthorities: retiredPlanBoundWorkAuthorities.sort(),
1227
+ retiredOwnerlessWorkAuthorities: retiredOwnerlessWorkAuthorities.sort(),
692
1228
  skippedActiveWorktrees: worktrees.skippedActive.sort(),
693
1229
  inspectedPaths,
694
1230
  budgetExhausted,
695
1231
  errors: errors.sort(),
696
1232
  logPath: runtimeCleanupLogPath(home),
1233
+ lifecycleMetrics,
697
1234
  cycle: {
698
1235
  scanned: inspectedPaths,
699
- eligible: pidFiles.removed.length + worktrees.removed.length + removedTemporaryPaths.length + releaseRetention.eligible,
700
- attempted: pidFiles.removed.length + worktrees.removed.length + removedTemporaryPaths.length + releaseRetention.attempted + errors.length,
701
- removed: pidFiles.removed.length + worktrees.removed.length + removedTemporaryPaths.length + removedReleasePaths.length,
702
- retained: pidFiles.skipped.length + worktrees.skippedActive.length + releaseRetention.retained,
703
- skipped: Math.max(0, inspectedPaths - pidFiles.removed.length - worktrees.removed.length - removedTemporaryPaths.length - removedReleasePaths.length - errors.length),
1236
+ eligible: retiredPlanBoundWorkAuthorities.length + retiredOwnerlessWorkAuthorities.length + pidFiles.removed.length + worktrees.removed.length + dependencyCleanup.migrated.length + removedTemporaryPaths.length + artifactRetention.eligible + schedulerHistory.eligible + editSessionHistory.eligible + removedCodegraphLocatorPaths.length + codegraphRetention.eligible + repositoryNamespaceRetention.eligible + releaseRetention.eligible,
1237
+ attempted: retiredPlanBoundWorkAuthorities.length + retiredOwnerlessWorkAuthorities.length + pidFiles.removed.length + worktrees.removed.length + dependencyCleanup.migrated.length + removedTemporaryPaths.length + artifactRetention.attempted + schedulerHistory.attempted + editSessionHistory.attempted + removedCodegraphLocatorPaths.length + codegraphRetention.attempted + repositoryNamespaceRetention.attempted + releaseRetention.attempted + errors.length,
1238
+ removed: retiredPlanBoundWorkAuthorities.length + retiredOwnerlessWorkAuthorities.length + pidFiles.removed.length + worktrees.removed.length + dependencyCleanup.migrated.length + removedTemporaryPaths.length + removedCleanupArtifactPaths.length + removedScheduleOccurrencePaths.length + removedScheduleDecisionPaths.length + removedEditSessionPaths.length + removedCodegraphLocatorPaths.length + removedCodegraphCachePaths.length + removedRepositoryNamespacePaths.length + removedReleasePaths.length,
1239
+ retained: pidFiles.skipped.length + worktrees.skippedActive.length + artifactRetention.retained + schedulerHistory.retained + editSessionHistory.retained + codegraphLocatorRetained + codegraphRetention.retained + repositoryNamespaceRetention.retained + releaseRetention.retained,
1240
+ skipped: Math.max(0, inspectedPaths - pidFiles.removed.length - worktrees.removed.length - dependencyCleanup.migrated.length - removedTemporaryPaths.length - removedCleanupArtifactPaths.length - removedScheduleOccurrencePaths.length - removedScheduleDecisionPaths.length - removedEditSessionPaths.length - removedCodegraphLocatorPaths.length - removedCodegraphCachePaths.length - removedRepositoryNamespacePaths.length - removedReleasePaths.length - errors.length),
704
1241
  failed: errors.length,
705
1242
  truncated: budgetExhausted,
706
1243
  budgetExhausted,