@knpkv/control-center 0.3.0 → 0.5.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 (346) hide show
  1. package/README.md +70 -17
  2. package/dist/client/.vite/manifest.json +223 -178
  3. package/dist/client/assets/{ActiveWorkPage-DJQgGZeV.js → ActiveWorkPage-g2-Jyavo.js} +2 -2
  4. package/dist/client/assets/{ActiveWorkPage-DJQgGZeV.js.map → ActiveWorkPage-g2-Jyavo.js.map} +1 -1
  5. package/dist/client/assets/AgentPage-B6GQdZAs.css +1 -0
  6. package/dist/client/assets/AgentPage-DmVsEe13.js +6 -0
  7. package/dist/client/assets/AgentPage-DmVsEe13.js.map +1 -0
  8. package/dist/client/assets/AtlassianOAuthCallbackPage-C8u9ItMj.js +2 -0
  9. package/dist/client/assets/{AtlassianOAuthCallbackPage-D1F1xE_2.js.map → AtlassianOAuthCallbackPage-C8u9ItMj.js.map} +1 -1
  10. package/dist/client/assets/AuthorizedSharePage-CVBJ1NTm.js +2 -0
  11. package/dist/client/assets/AuthorizedSharePage-CVBJ1NTm.js.map +1 -0
  12. package/dist/client/assets/BrowserCrypto-3BoTVFdl.js +2 -0
  13. package/dist/client/assets/{BrowserCrypto-DVWR7DFd.js.map → BrowserCrypto-3BoTVFdl.js.map} +1 -1
  14. package/dist/client/assets/BrowserSessionHydrator-CpZnNm4X.js +2 -0
  15. package/dist/client/assets/BrowserSessionHydrator-CpZnNm4X.js.map +1 -0
  16. package/dist/client/assets/CommandSearch-DUeRRbV2.js +2 -0
  17. package/dist/client/assets/{CommandSearch-CP_QCbkm.js.map → CommandSearch-DUeRRbV2.js.map} +1 -1
  18. package/dist/client/assets/ItemsPage-BF2ZkSzh.js +2 -0
  19. package/dist/client/assets/{ItemsPage-BGFUkRL2.js.map → ItemsPage-BF2ZkSzh.js.map} +1 -1
  20. package/dist/client/assets/{PairPage-DIgzx0K2.js → PairPage-CkaZltHd.js} +2 -2
  21. package/dist/client/assets/{PairPage-DIgzx0K2.js.map → PairPage-CkaZltHd.js.map} +1 -1
  22. package/dist/client/assets/PortfolioOverview-CEUHJmGC.js +2 -0
  23. package/dist/client/assets/PortfolioOverview-CEUHJmGC.js.map +1 -0
  24. package/dist/client/assets/PullRequestReviewPanel-D1IpvHe2.js +6 -0
  25. package/dist/client/assets/PullRequestReviewPanel-D1IpvHe2.js.map +1 -0
  26. package/dist/client/assets/ReleaseRoute-BuQybrsg.js +2 -0
  27. package/dist/client/assets/{ReleaseRoute-DXJ8Jg60.js.map → ReleaseRoute-BuQybrsg.js.map} +1 -1
  28. package/dist/client/assets/ReleaseWorkset-BclY0Nvj.js +2 -0
  29. package/dist/client/assets/ReleaseWorkset-BclY0Nvj.js.map +1 -0
  30. package/dist/client/assets/ServicesPage-hw5Ee69-.js +2 -0
  31. package/dist/client/assets/ServicesPage-hw5Ee69-.js.map +1 -0
  32. package/dist/client/assets/TimelinePage-Cj3V98uI.js +2 -0
  33. package/dist/client/assets/TimelinePage-Cj3V98uI.js.map +1 -0
  34. package/dist/client/assets/WorkspaceEntityLink-C_rc8lxi.js +2 -0
  35. package/dist/client/assets/{WorkspaceEntityLink-AdZ_T-Wk.js.map → WorkspaceEntityLink-C_rc8lxi.js.map} +1 -1
  36. package/dist/client/assets/WorkspaceEntityRoute-DLLT6fY0.css +1 -0
  37. package/dist/client/assets/WorkspaceEntityRoute-kbnrQ_lY.js +14 -0
  38. package/dist/client/assets/WorkspaceEntityRoute-kbnrQ_lY.js.map +1 -0
  39. package/dist/client/assets/WorkspaceHomeLink-DeYYLEsH.js +2 -0
  40. package/dist/client/assets/{WorkspaceHomeLink-XbKSPths.js.map → WorkspaceHomeLink-DeYYLEsH.js.map} +1 -1
  41. package/dist/client/assets/{WorkspacePullRequestDetails-BErJ5bk8.js → WorkspacePullRequestDetails-CizqydjN.js} +3 -3
  42. package/dist/client/assets/WorkspacePullRequestDetails-CizqydjN.js.map +1 -0
  43. package/dist/client/assets/{WorkspaceReleaseLayout-cfboC5Qh.js → WorkspaceReleaseLayout-CXAQUhkh.js} +2 -2
  44. package/dist/client/assets/{WorkspaceReleaseLayout-cfboC5Qh.js.map → WorkspaceReleaseLayout-CXAQUhkh.js.map} +1 -1
  45. package/dist/client/assets/{WorkspaceRichText-D1M637Ff.js → WorkspaceRichText-CCOciILO.js} +2 -2
  46. package/dist/client/assets/WorkspaceRichText-CCOciILO.js.map +1 -0
  47. package/dist/client/assets/WorkspaceSettingsPage-GoBfQzBx.css +1 -0
  48. package/dist/client/assets/WorkspaceSettingsPage-JG-pN_CA.js +2 -0
  49. package/dist/client/assets/WorkspaceSettingsPage-JG-pN_CA.js.map +1 -0
  50. package/dist/client/assets/agent-api-Dl9TuGOJ.js +19 -0
  51. package/dist/client/assets/agent-api-Dl9TuGOJ.js.map +1 -0
  52. package/dist/client/assets/atlassianOAuthSetupIntentStorage-DE4ySCTb.js +2 -0
  53. package/dist/client/assets/atlassianOAuthSetupIntentStorage-DE4ySCTb.js.map +1 -0
  54. package/dist/client/assets/authenticatedMutationClient-DdowMjyo.js +2 -0
  55. package/dist/client/assets/{authenticatedMutationClient-Ccwguc3i.js.map → authenticatedMutationClient-DdowMjyo.js.map} +1 -1
  56. package/dist/client/assets/authorizedShareTransport-CnclcYai.js +2 -0
  57. package/dist/client/assets/{authorizedShareTransport-DZHgFEkh.js.map → authorizedShareTransport-CnclcYai.js.map} +1 -1
  58. package/dist/client/assets/client-Dq_XQE_l.js +5 -0
  59. package/dist/client/assets/client-Dq_XQE_l.js.map +1 -0
  60. package/dist/client/assets/confluenceTasks-DtKq8_eU.js +5 -0
  61. package/dist/client/assets/confluenceTasks-DtKq8_eU.js.map +1 -0
  62. package/dist/client/assets/connectionTestTransport-CPK98z7H.js +2 -0
  63. package/dist/client/assets/connectionTestTransport-CPK98z7H.js.map +1 -0
  64. package/dist/client/assets/index-zVjlBm9l.js +11 -0
  65. package/dist/client/assets/index-zVjlBm9l.js.map +1 -0
  66. package/dist/client/assets/{patterns-5N-j-AD2-BwypFm-e.js → patterns-5N-j-AD2-DLfaGePK.js} +2 -2
  67. package/dist/client/assets/{patterns-5N-j-AD2-BwypFm-e.js.map → patterns-5N-j-AD2-DLfaGePK.js.map} +1 -1
  68. package/dist/client/assets/{presentPortfolio-D3ZIcnqt.js → presentPortfolio-DLEq-vEz.js} +2 -2
  69. package/dist/client/assets/presentPortfolio-DLEq-vEz.js.map +1 -0
  70. package/dist/client/assets/{presentWorkspaceItems-Bmh4oEbH.js → presentWorkspaceItems-BOY3FbhO.js} +2 -2
  71. package/dist/client/assets/{presentWorkspaceItems-Bmh4oEbH.js.map → presentWorkspaceItems-BOY3FbhO.js.map} +1 -1
  72. package/dist/client/assets/{pullRequestReviewFailures-S74M-fOk.js → pullRequestReviewFailures-CyjTVnSX.js} +2 -2
  73. package/dist/client/assets/{pullRequestReviewFailures-S74M-fOk.js.map → pullRequestReviewFailures-CyjTVnSX.js.map} +1 -1
  74. package/dist/client/assets/pullRequestReviewThreadReplay-CXHspFTr.js +2 -0
  75. package/dist/client/assets/pullRequestReviewThreadReplay-CXHspFTr.js.map +1 -0
  76. package/dist/client/assets/releaseAgentTransport-DaO4svPu.js +2 -0
  77. package/dist/client/assets/releaseAgentTransport-DaO4svPu.js.map +1 -0
  78. package/dist/client/assets/releaseRoutes-B4ciNOJj.js +2 -0
  79. package/dist/client/assets/{releaseRoutes-BCuIdZyA.js.map → releaseRoutes-B4ciNOJj.js.map} +1 -1
  80. package/dist/client/assets/serviceOnboarding-D0FmodRi.js +2 -0
  81. package/dist/client/assets/{serviceOnboarding-Jg_0yNjf.js.map → serviceOnboarding-D0FmodRi.js.map} +1 -1
  82. package/dist/client/assets/{useWorkspaceDefaultLanding-CzlDdEF-.js → useWorkspaceDefaultLanding-BaQdg0sY.js} +3 -3
  83. package/dist/client/assets/{useWorkspaceDefaultLanding-CzlDdEF-.js.map → useWorkspaceDefaultLanding-BaQdg0sY.js.map} +1 -1
  84. package/dist/client/assets/{useWorkspaceItems-Cd3MPke2.js → useWorkspaceItems-B-7JHtm0.js} +2 -2
  85. package/dist/client/assets/{useWorkspaceItems-Cd3MPke2.js.map → useWorkspaceItems-B-7JHtm0.js.map} +1 -1
  86. package/dist/client/assets/workspaceEntityRoutes-DqqDa0AB.js +2 -0
  87. package/dist/client/assets/workspaceEntityRoutes-DqqDa0AB.js.map +1 -0
  88. package/dist/client/assets/workspaceScrollCapture-BYNfR2wo.js +2 -0
  89. package/dist/client/assets/workspaceScrollCapture-BYNfR2wo.js.map +1 -0
  90. package/dist/client/assets/workspaceSettingsTransport-Br4lBmvS.js +2 -0
  91. package/dist/client/assets/{workspaceSettingsTransport-CZWYL5T7.js.map → workspaceSettingsTransport-Br4lBmvS.js.map} +1 -1
  92. package/dist/client/build-graph.json +115 -0
  93. package/dist/client/index.html +1 -1
  94. package/dist/server/api/agent.d.ts +575 -44
  95. package/dist/server/api/agent.d.ts.map +1 -1
  96. package/dist/server/api/deliveryGraph.d.ts +474 -454
  97. package/dist/server/api/deliveryGraph.d.ts.map +1 -1
  98. package/dist/server/api/index.d.ts +2 -2
  99. package/dist/server/api/index.d.ts.map +1 -1
  100. package/dist/server/api/index.js +4 -4
  101. package/dist/server/api/liveEvents.d.ts +20 -0
  102. package/dist/server/api/liveEvents.d.ts.map +1 -1
  103. package/dist/server/api/portfolio.d.ts +23 -0
  104. package/dist/server/api/portfolio.d.ts.map +1 -1
  105. package/dist/server/api/session.d.ts +23 -1
  106. package/dist/server/api/session.d.ts.map +1 -1
  107. package/dist/server/api/shares.d.ts +4 -2
  108. package/dist/server/api/shares.d.ts.map +1 -1
  109. package/dist/server/assets/{BindConfig-DIsf2Rnh.js → BindConfig-DAASchDn.js} +2405 -322
  110. package/dist/server/assets/BindConfig-DAASchDn.js.map +1 -0
  111. package/dist/server/assets/{CodePipelineStateDecoder-CVf1A2zG.js → CodePipelineStateDecoder-CNiFRgSi.js} +2 -2
  112. package/dist/server/assets/{CodePipelineStateDecoder-CVf1A2zG.js.map → CodePipelineStateDecoder-CNiFRgSi.js.map} +1 -1
  113. package/dist/server/assets/{agent-CyZ40zs1.js → agent-xQhAQXly.js} +181 -11
  114. package/dist/server/assets/agent-xQhAQXly.js.map +1 -0
  115. package/dist/server/assets/{controlCenterApi-ZUX3Y-LE.js → controlCenterApi-DNXK7MT1.js} +6 -5
  116. package/dist/server/assets/controlCenterApi-DNXK7MT1.js.map +1 -0
  117. package/dist/server/assets/{descriptor-CKtTnhef.js → descriptor-CCvNzSZL.js} +10 -10
  118. package/dist/server/assets/{descriptor-CKtTnhef.js.map → descriptor-CCvNzSZL.js.map} +1 -1
  119. package/dist/server/assets/{failures-mgYDkUZy.js → failures-CesHLYbN.js} +2 -2
  120. package/dist/server/assets/{failures-mgYDkUZy.js.map → failures-CesHLYbN.js.map} +1 -1
  121. package/dist/server/assets/{firstPartyServices-D7b8BOek.js → firstPartyServices-Cdzjcs2H.js} +2 -2
  122. package/dist/server/assets/{firstPartyServices-D7b8BOek.js.map → firstPartyServices-Cdzjcs2H.js.map} +1 -1
  123. package/dist/server/assets/{manualPluginSynchronization-DFlhKvav.js → manualPluginSynchronization-DFIeUHP9.js} +6 -5
  124. package/dist/server/assets/manualPluginSynchronization-DFIeUHP9.js.map +1 -0
  125. package/dist/server/assets/{plugins-D__oMDpI.js → plugins-DiPrfzV8.js} +2 -2
  126. package/dist/server/assets/{plugins-D__oMDpI.js.map → plugins-DiPrfzV8.js.map} +1 -1
  127. package/dist/server/assets/{readiness-BhA-Nr9c.js → readiness-31Mqc-9H.js} +3 -3
  128. package/dist/server/assets/{readiness-BhA-Nr9c.js.map → readiness-31Mqc-9H.js.map} +1 -1
  129. package/dist/server/assets/{relationshipInferenceMaterialization-DYBcaWhQ.js → relationshipInferenceMaterialization-Dyix96px.js} +1158 -169
  130. package/dist/server/assets/relationshipInferenceMaterialization-Dyix96px.js.map +1 -0
  131. package/dist/server/assets/{workspaceSettings-BE713Oe8.js → workspaceSettings-sv8h_h2P.js} +2787 -2700
  132. package/dist/server/assets/workspaceSettings-sv8h_h2P.js.map +1 -0
  133. package/dist/server/build-graph.json +144 -4
  134. package/dist/server/domain/actors.d.ts +12 -12
  135. package/dist/server/domain/confluenceTasks.d.ts +27 -0
  136. package/dist/server/domain/confluenceTasks.d.ts.map +1 -0
  137. package/dist/server/domain/deliveryGraph.d.ts +51 -49
  138. package/dist/server/domain/deliveryGraph.d.ts.map +1 -1
  139. package/dist/server/domain/governedAction/bindings.d.ts +26 -12
  140. package/dist/server/domain/governedAction/bindings.d.ts.map +1 -1
  141. package/dist/server/domain/governedAction/lifecycle.d.ts +8 -8
  142. package/dist/server/domain/governedAction/model.d.ts +45 -18
  143. package/dist/server/domain/governedAction/model.d.ts.map +1 -1
  144. package/dist/server/domain/governedAction/stateMachine.d.ts +34 -34
  145. package/dist/server/domain/index.js +6 -6
  146. package/dist/server/domain/normalizedIssue.d.ts +1 -1
  147. package/dist/server/domain/normalizedPage.d.ts +1 -0
  148. package/dist/server/domain/normalizedPage.d.ts.map +1 -1
  149. package/dist/server/domain/prReview.d.ts +38 -0
  150. package/dist/server/domain/prReview.d.ts.map +1 -1
  151. package/dist/server/domain/prReviewReconciliation.d.ts +56 -0
  152. package/dist/server/domain/prReviewReconciliation.d.ts.map +1 -0
  153. package/dist/server/domain/prReviewRevision.d.ts +1 -0
  154. package/dist/server/domain/prReviewRevision.d.ts.map +1 -1
  155. package/dist/server/domain/readiness/model.d.ts +3 -3
  156. package/dist/server/domain/release.d.ts +3 -3
  157. package/dist/server/domain/releasePipelineApproval.d.ts +31 -0
  158. package/dist/server/domain/releasePipelineApproval.d.ts.map +1 -0
  159. package/dist/server/domain/releasePublication.d.ts +4 -0
  160. package/dist/server/domain/releasePublication.d.ts.map +1 -0
  161. package/dist/server/index.js +8 -8
  162. package/dist/server/server/agent/AgentJobWorker.d.ts +10 -1
  163. package/dist/server/server/agent/AgentJobWorker.d.ts.map +1 -1
  164. package/dist/server/server/agent/ReleaseAgentPrompt.d.ts.map +1 -1
  165. package/dist/server/server/agent/internal/AgentJobTaskExecutor.d.ts +4 -3
  166. package/dist/server/server/agent/internal/AgentJobTaskExecutor.d.ts.map +1 -1
  167. package/dist/server/server/agent/internal/PrReviewSandboxSession.d.ts +17 -1
  168. package/dist/server/server/agent/internal/PrReviewSandboxSession.d.ts.map +1 -1
  169. package/dist/server/server/agent/internal/PrReviewTaskExecutor.d.ts +76 -2
  170. package/dist/server/server/agent/internal/PrReviewTaskExecutor.d.ts.map +1 -1
  171. package/dist/server/server/agent/internal/PrReviewTelemetry.d.ts +27 -0
  172. package/dist/server/server/agent/internal/PrReviewTelemetry.d.ts.map +1 -0
  173. package/dist/server/server/api/ApplicationServices.d.ts +39 -5
  174. package/dist/server/server/api/ApplicationServices.d.ts.map +1 -1
  175. package/dist/server/server/api/Handlers.d.ts +1 -1
  176. package/dist/server/server/api/Handlers.d.ts.map +1 -1
  177. package/dist/server/server/api/RequestBoundary.d.ts.map +1 -1
  178. package/dist/server/server/application/GovernedReviewSuggestionPublicationGateway.d.ts.map +1 -1
  179. package/dist/server/server/application/ReviewSuggestionPublicationGateway.d.ts +4 -0
  180. package/dist/server/server/application/ReviewSuggestionPublicationGateway.d.ts.map +1 -1
  181. package/dist/server/server/application/deliveryGraphInspection.d.ts.map +1 -1
  182. package/dist/server/server/application/index.d.ts +1 -0
  183. package/dist/server/server/application/index.d.ts.map +1 -1
  184. package/dist/server/server/application/liveEvents.d.ts.map +1 -1
  185. package/dist/server/server/application/normalizedPluginPageMaterialization.d.ts.map +1 -1
  186. package/dist/server/server/application/pipelineExecutionProjection.d.ts +7 -6
  187. package/dist/server/server/application/pipelineExecutionProjection.d.ts.map +1 -1
  188. package/dist/server/server/application/portfolioSnapshots.d.ts +2018 -4
  189. package/dist/server/server/application/portfolioSnapshots.d.ts.map +1 -1
  190. package/dist/server/server/application/pullRequestReviews.d.ts.map +1 -1
  191. package/dist/server/server/application/releaseAgent.d.ts +11 -3
  192. package/dist/server/server/application/releaseAgent.d.ts.map +1 -1
  193. package/dist/server/server/application/releasePublicationIntent.d.ts +7 -0
  194. package/dist/server/server/application/releasePublicationIntent.d.ts.map +1 -0
  195. package/dist/server/server/application/releasePublicationMetadata.d.ts +61 -0
  196. package/dist/server/server/application/releasePublicationMetadata.d.ts.map +1 -0
  197. package/dist/server/server/application/releasePublicationSubmissions.d.ts +3730 -0
  198. package/dist/server/server/application/releasePublicationSubmissions.d.ts.map +1 -0
  199. package/dist/server/server/application/releaseRunbookHydration.d.ts +2310 -0
  200. package/dist/server/server/application/releaseRunbookHydration.d.ts.map +1 -0
  201. package/dist/server/server/application/releaseSynchronization.d.ts.map +1 -1
  202. package/dist/server/server/cli.js +8 -8
  203. package/dist/server/server/cli.js.map +1 -1
  204. package/dist/server/server/governance/governedActionDigests.d.ts +236 -218
  205. package/dist/server/server/governance/governedActionDigests.d.ts.map +1 -1
  206. package/dist/server/server/governance/internal/GovernedActionExecutionEngine.d.ts +3 -4
  207. package/dist/server/server/governance/internal/GovernedActionExecutionEngine.d.ts.map +1 -1
  208. package/dist/server/server/governance/internal/execution-store/begin.d.ts.map +1 -1
  209. package/dist/server/server/governance/internal/execution-store/dispatch-inbox.d.ts +1 -1
  210. package/dist/server/server/governance/internal/execution-store/dispatch-outcome.d.ts +8 -8
  211. package/dist/server/server/governance/internal/execution-store/provider-outcome-fold.d.ts +2 -2
  212. package/dist/server/server/governance/internal/execution-store/reconciliation-inbox.d.ts +1 -1
  213. package/dist/server/server/governance/internal/execution-store/recovery-claim.d.ts +37 -30
  214. package/dist/server/server/governance/internal/execution-store/recovery-claim.d.ts.map +1 -1
  215. package/dist/server/server/index.js +5 -5
  216. package/dist/server/server/internal/codepipeline-state-probe.js +1 -1
  217. package/dist/server/server/persistence/Database.d.ts +1 -1
  218. package/dist/server/server/persistence/Database.d.ts.map +1 -1
  219. package/dist/server/server/persistence/Persistence.d.ts +1549 -577
  220. package/dist/server/server/persistence/Persistence.d.ts.map +1 -1
  221. package/dist/server/server/persistence/backup/BackupArchive.d.ts.map +1 -1
  222. package/dist/server/server/persistence/object-store/BlobPublisher.d.ts.map +1 -1
  223. package/dist/server/server/persistence/object-store/PinnedDirectory.d.ts +2 -2
  224. package/dist/server/server/persistence/object-store/PinnedDirectory.d.ts.map +1 -1
  225. package/dist/server/server/persistence/repositories/agentJobModels.d.ts +345 -8
  226. package/dist/server/server/persistence/repositories/agentJobModels.d.ts.map +1 -1
  227. package/dist/server/server/persistence/repositories/agentJobRepository.d.ts +654 -192
  228. package/dist/server/server/persistence/repositories/agentJobRepository.d.ts.map +1 -1
  229. package/dist/server/server/persistence/repositories/delivery-graph/contract.d.ts +148 -138
  230. package/dist/server/server/persistence/repositories/delivery-graph/contract.d.ts.map +1 -1
  231. package/dist/server/server/persistence/repositories/delivery-graph/decode.d.ts +27 -25
  232. package/dist/server/server/persistence/repositories/delivery-graph/decode.d.ts.map +1 -1
  233. package/dist/server/server/persistence/repositories/delivery-graph/read.d.ts +117 -111
  234. package/dist/server/server/persistence/repositories/delivery-graph/read.d.ts.map +1 -1
  235. package/dist/server/server/persistence/repositories/delivery-graph/rows.d.ts +28 -27
  236. package/dist/server/server/persistence/repositories/delivery-graph/rows.d.ts.map +1 -1
  237. package/dist/server/server/persistence/repositories/delivery-graph/write.d.ts +50 -48
  238. package/dist/server/server/persistence/repositories/delivery-graph/write.d.ts.map +1 -1
  239. package/dist/server/server/persistence/repositories/deliveryGraphRepository.d.ts +117 -111
  240. package/dist/server/server/persistence/repositories/deliveryGraphRepository.d.ts.map +1 -1
  241. package/dist/server/server/persistence/repositories/governed-action/codec.d.ts +259 -234
  242. package/dist/server/server/persistence/repositories/governed-action/codec.d.ts.map +1 -1
  243. package/dist/server/server/persistence/repositories/governed-action/contract.d.ts +68 -46
  244. package/dist/server/server/persistence/repositories/governed-action/contract.d.ts.map +1 -1
  245. package/dist/server/server/persistence/repositories/governed-action/read.d.ts +668 -190
  246. package/dist/server/server/persistence/repositories/governed-action/read.d.ts.map +1 -1
  247. package/dist/server/server/persistence/repositories/governed-action/transaction.d.ts +680 -206
  248. package/dist/server/server/persistence/repositories/governed-action/transaction.d.ts.map +1 -1
  249. package/dist/server/server/persistence/repositories/governed-action/write-preparation.d.ts +38 -31
  250. package/dist/server/server/persistence/repositories/governed-action/write-preparation.d.ts.map +1 -1
  251. package/dist/server/server/persistence/repositories/governed-action/write-replay.d.ts +46 -32
  252. package/dist/server/server/persistence/repositories/governed-action/write-replay.d.ts.map +1 -1
  253. package/dist/server/server/persistence/repositories/governed-action/write.d.ts +46 -32
  254. package/dist/server/server/persistence/repositories/governed-action/write.d.ts.map +1 -1
  255. package/dist/server/server/persistence/repositories/governedActionRepository.d.ts +678 -205
  256. package/dist/server/server/persistence/repositories/governedActionRepository.d.ts.map +1 -1
  257. package/dist/server/server/persistence/repositories/internal/reviewSuggestionRevisions.d.ts +85 -4
  258. package/dist/server/server/persistence/repositories/internal/reviewSuggestionRevisions.d.ts.map +1 -1
  259. package/dist/server/server/persistence/repositories/models.d.ts +9 -9
  260. package/dist/server/server/persistence/repositories/peopleRepository.d.ts +36 -36
  261. package/dist/server/server/persistence/repositories/providerAccountRepository.d.ts +1 -1
  262. package/dist/server/server/persistence/repositories/readiness/assessments.d.ts +6 -6
  263. package/dist/server/server/persistence/repositories/readiness/contract.d.ts +450 -450
  264. package/dist/server/server/persistence/repositories/readiness/queue.d.ts +14 -14
  265. package/dist/server/server/persistence/repositories/readinessRepository.d.ts +7 -7
  266. package/dist/server/server/persistence/repositories/releaseRepository.d.ts +18 -18
  267. package/dist/server/server/persistence/repositories/retentionRepository.d.ts.map +1 -1
  268. package/dist/server/server/persistence/repositories/timelineRepository.d.ts +4 -4
  269. package/dist/server/server/plugins/atlassian/AtlassianOAuthGrants.d.ts.map +1 -1
  270. package/dist/server/server/plugins/atlassian/AtlassianOAuthScopes.d.ts +9 -0
  271. package/dist/server/server/plugins/atlassian/AtlassianOAuthScopes.d.ts.map +1 -0
  272. package/dist/server/server/plugins/atlassian/AtlassianProfiles.d.ts.map +1 -1
  273. package/dist/server/server/plugins/codecommit/CodeCommitPluginDefinition.d.ts.map +1 -1
  274. package/dist/server/server/plugins/jira/JiraReadPlugin.d.ts +2 -2
  275. package/dist/server/server/plugins/jira/JiraReadPlugin.d.ts.map +1 -1
  276. package/dist/server/server/plugins/jira/JiraReadProvider.d.ts.map +1 -1
  277. package/dist/server/server/plugins/jira/JiraReleaseVersionLimits.d.ts +8 -0
  278. package/dist/server/server/plugins/jira/JiraReleaseVersionLimits.d.ts.map +1 -0
  279. package/dist/server/server/plugins/jira/index.d.ts +1 -1
  280. package/dist/server/server/plugins/jira/index.d.ts.map +1 -1
  281. package/dist/server/server/runtime/Bootstrap.d.ts +1 -1
  282. package/dist/server/server/runtime/Bootstrap.d.ts.map +1 -1
  283. package/dist/server/server/runtime/ControlCenterServer.d.ts +3 -3
  284. package/dist/server/server/runtime/ControlCenterServer.d.ts.map +1 -1
  285. package/dist/server/server/runtime/PrReviewWorkerStartup.d.ts +11 -1
  286. package/dist/server/server/runtime/PrReviewWorkerStartup.d.ts.map +1 -1
  287. package/dist/server/server/runtime/RetentionStartup.d.ts.map +1 -1
  288. package/dist/server/server/runtime/ServerLifecycle.d.ts.map +1 -1
  289. package/dist/server/server/secrets/SecretStore.d.ts.map +1 -1
  290. package/package.json +10 -9
  291. package/dist/client/assets/AgentPage-DGL93TJU.js +0 -3
  292. package/dist/client/assets/AgentPage-DGL93TJU.js.map +0 -1
  293. package/dist/client/assets/AgentPage-DVSgQgJa.css +0 -1
  294. package/dist/client/assets/AtlassianOAuthCallbackPage-D1F1xE_2.js +0 -2
  295. package/dist/client/assets/AuthorizedSharePage-DCQUFY2I.js +0 -2
  296. package/dist/client/assets/AuthorizedSharePage-DCQUFY2I.js.map +0 -1
  297. package/dist/client/assets/BrowserCrypto-DVWR7DFd.js +0 -2
  298. package/dist/client/assets/BrowserSessionHydrator-DE46feEX.js +0 -2
  299. package/dist/client/assets/BrowserSessionHydrator-DE46feEX.js.map +0 -1
  300. package/dist/client/assets/CommandSearch-CP_QCbkm.js +0 -2
  301. package/dist/client/assets/ItemsPage-BGFUkRL2.js +0 -2
  302. package/dist/client/assets/PortfolioOverview-D45rk8Hl.js +0 -2
  303. package/dist/client/assets/PortfolioOverview-D45rk8Hl.js.map +0 -1
  304. package/dist/client/assets/PullRequestReviewPanel-CqPtjhVW.js +0 -6
  305. package/dist/client/assets/PullRequestReviewPanel-CqPtjhVW.js.map +0 -1
  306. package/dist/client/assets/ReleaseRoute-DXJ8Jg60.js +0 -2
  307. package/dist/client/assets/ReleaseWorkset-Dtzalmji.js +0 -2
  308. package/dist/client/assets/ReleaseWorkset-Dtzalmji.js.map +0 -1
  309. package/dist/client/assets/ServicesPage-DGcUjd2H.js +0 -2
  310. package/dist/client/assets/ServicesPage-DGcUjd2H.js.map +0 -1
  311. package/dist/client/assets/TimelinePage-Bq1RTQlP.js +0 -2
  312. package/dist/client/assets/TimelinePage-Bq1RTQlP.js.map +0 -1
  313. package/dist/client/assets/WorkspaceEntityLink-AdZ_T-Wk.js +0 -2
  314. package/dist/client/assets/WorkspaceEntityRoute-9iMOV64J.css +0 -1
  315. package/dist/client/assets/WorkspaceEntityRoute-Bxxnc8us.js +0 -3
  316. package/dist/client/assets/WorkspaceEntityRoute-Bxxnc8us.js.map +0 -1
  317. package/dist/client/assets/WorkspaceHomeLink-XbKSPths.js +0 -2
  318. package/dist/client/assets/WorkspacePullRequestDetails-BErJ5bk8.js.map +0 -1
  319. package/dist/client/assets/WorkspaceRichText-D1M637Ff.js.map +0 -1
  320. package/dist/client/assets/WorkspaceSettingsPage-Fy7Wx8Y2.js +0 -2
  321. package/dist/client/assets/WorkspaceSettingsPage-Fy7Wx8Y2.js.map +0 -1
  322. package/dist/client/assets/WorkspaceSettingsPage-P6yfac0b.css +0 -1
  323. package/dist/client/assets/agent-api-QVqt4a0O.js +0 -19
  324. package/dist/client/assets/agent-api-QVqt4a0O.js.map +0 -1
  325. package/dist/client/assets/authenticatedMutationClient-Ccwguc3i.js +0 -2
  326. package/dist/client/assets/authorizedShareTransport-DZHgFEkh.js +0 -2
  327. package/dist/client/assets/client-D27unen8.js +0 -5
  328. package/dist/client/assets/client-D27unen8.js.map +0 -1
  329. package/dist/client/assets/connectionTestTransport-BQ55d6Me.js +0 -2
  330. package/dist/client/assets/connectionTestTransport-BQ55d6Me.js.map +0 -1
  331. package/dist/client/assets/index-j5ze816l.js +0 -11
  332. package/dist/client/assets/index-j5ze816l.js.map +0 -1
  333. package/dist/client/assets/presentPortfolio-D3ZIcnqt.js.map +0 -1
  334. package/dist/client/assets/pullRequestReviewThreadReplay-oljKM7Xz.js +0 -2
  335. package/dist/client/assets/pullRequestReviewThreadReplay-oljKM7Xz.js.map +0 -1
  336. package/dist/client/assets/releaseRoutes-BCuIdZyA.js +0 -2
  337. package/dist/client/assets/serviceOnboarding-Jg_0yNjf.js +0 -2
  338. package/dist/client/assets/workspaceScrollCapture-CJ4QUptr.js +0 -2
  339. package/dist/client/assets/workspaceScrollCapture-CJ4QUptr.js.map +0 -1
  340. package/dist/client/assets/workspaceSettingsTransport-CZWYL5T7.js +0 -2
  341. package/dist/server/assets/BindConfig-DIsf2Rnh.js.map +0 -1
  342. package/dist/server/assets/agent-CyZ40zs1.js.map +0 -1
  343. package/dist/server/assets/controlCenterApi-ZUX3Y-LE.js.map +0 -1
  344. package/dist/server/assets/manualPluginSynchronization-DFlhKvav.js.map +0 -1
  345. package/dist/server/assets/relationshipInferenceMaterialization-DYBcaWhQ.js.map +0 -1
  346. package/dist/server/assets/workspaceSettings-BE713Oe8.js.map +0 -1
@@ -1,15 +1,16 @@
1
- import { $ as GovernedActionEnvelopeMaterialV1, $n as ReadinessAssessment, Ai as PrReviewSuggestion, C as RelationshipRepairReview, Ct as DeliveryEntityService, D as advanceGovernedActionLifecycle, E as GovernedActionProviderLineage, Et as DeliveryRelationship, F as GovernedActionTransitionDigest, Fi as PrReviewSuggestionId, Fn as Person, Ft as LedgerRevision, G as governedActionAuthorizationMatchesTransition, In as PersonAvatar, J as GovernedActionAttemptDigest, K as governedActionAuthorizationMismatches, L as GovernedActionTransitionV1, Ln as PersonSourceIdentity, M as GovernedActionState, Mt as EvidenceValue, N as GovernedActionTransitionCause, O as GovernedActionCommandDigest, Oi as PrReviewReport, Ot as EvidenceClaim, P as GovernedActionTransitionCommand, Q as GovernedActionEnvelopeDigest, Qn as ReadinessArtifactRevision, Qr as Freshness, R as GovernedActionUnknownOutcome, Rn as Role, Rt as RelationshipEndpointKind, S as RelationshipRepairRationale, St as DeliveryEntityProjection, T as GovernedActionLifecycleHeadV1, Tr as ReleaseReadinessAssessment, Tt as DeliveryNode, Un as EnvironmentReadinessAssessment, Vn as derivePersonInitials, W as governedActionAuthorityMismatches, X as GovernedActionAuthorizationDigest, Y as GovernedActionAttemptV1, Z as GovernedActionAuthorizationV1, _t as PortfolioInvalidatedEventV1, a as WorkspaceSettingsSections, ai as PrReviewSuggestionEdit, b as RelationshipRepairProposal, br as ReadinessRuleVersion, c as isGovernedWorkspaceSettingsSection, ci as PrReviewSuggestionRevision, ct as GovernedActionPolicyDigest, di as PrReviewSuggestionRevisionPageSize, ei as PluginHealth, er as ReadinessCandidateDigest, et as GovernedActionEnvelopeV1, fi as PrReviewSuggestionRevisionSequence, hi as hasSamePrReviewTechnicalClaim, hn as Release, ht as DomainEventMetadataV1, ii as PrReviewSuggestionAgentAuthor, it as GovernedActionIdempotencyKey, jn as Actor, k as GovernedActionCommandId, ki as PrReviewSubject, kt as EvidenceItem, l as TimelineActorKind, li as PrReviewSuggestionRevisionAuthor, lt as GovernedActionPolicyEvaluationDigest, mi as PrReviewSuggestionValidated, mt as DomainEventCorrelationId, nr as ReadinessDerivationVersion, nt as GovernedActionEvidenceSet, o as WorkspaceSettingsV1, q as governedActionPermissionGrants, r as GovernedWorkspaceSettingsSections, rt as GovernedActionEvidenceSetDigest, s as changedWorkspaceSettingsSections, si as PrReviewSuggestionRequiresRevalidation, t as DEFAULT_WORKSPACE_SETTINGS, ui as PrReviewSuggestionRevisionPage, ut as GovernedActionPolicyEvaluationV1, v as RelationshipRepairApplication, vr as ReadinessRuleId, vt as PortfolioInvalidatedPayloadV1, w as RelationshipRepairReviewDecision, wr as ReadinessVerdict, wt as DeliveryEntityStatusGroup, x as RelationshipRepairProposalOrigin, xt as DeliveryEntityKind, y as RelationshipRepairDisposition, zn as RoleAssignment } from "./workspaceSettings-BE713Oe8.js";
2
- import { $ as SourceRevision, At as SessionId, Ct as RelationshipId, Dt as ReviewCommandArtifactId, Et as ReleaseId, K as MaximumPluginPayloadBytes, Mt as WorkspaceId, N as NormalizedPluginEventV1, Nt as WorkspaceSettingsMutationId, Ot as ReviewSuggestionPublicationReservationId, Q as Revision$1, S as PluginProviderOperationId, St as ReadinessAssessmentId, Tt as RelationshipRepairReviewId, X as NormalizationSchemaVersion, Y as hasMaximumPluginJsonBytes, Z as ProviderId, _t as JobId, at as DomainEventId, bt as PrReviewSuggestionRevisionId, c as SemanticVersion, ct as EventCursor, dt as FollowedResourceId, et as SourceUrl, ft as GovernedActionAttemptId, g as PluginActionPayloadDigest, gt as GraphNodeId, h as PluginActionDispatchResultV1, ht as GovernedActionTransitionId, it as AgentThreadId, jt as ShareId, kt as RoleAssignmentId, lt as EvidenceClaimId, mt as GovernedActionId, n as NegotiatedPluginDescriptorV1, nt as UtcTimestamp, o as PluginDescriptorV1, ot as EntityId, pt as GovernedActionAuthorizationId, rt as AgentId, st as EnvironmentId, tt as VendorImmutableId, ut as EvidenceId, vt as PersonId, wt as RelationshipRepairProposalId, xt as ProviderAccountId, y as PluginActionReconciliationKey, yt as PluginConnectionId } from "./descriptor-CKtTnhef.js";
3
- import { V as ReviewAgentProfile } from "./agent-CyZ40zs1.js";
4
- import { a as ReleaseReadinessCandidateMaterial, c as normalizeReadinessRuleMaterial, i as ReadinessRuleMaterial, l as normalizeReleaseReadinessCandidateMaterial, n as summarizeEnvironmentReadiness, r as EnvironmentReadinessCandidateMaterial, s as normalizeEnvironmentReadinessCandidateMaterial, u as AuthorizedShareGrant } from "./readiness-BhA-Nr9c.js";
5
- import { d as PluginUnsupportedCapabilityFailure, o as PluginMalformedResponseFailure } from "./failures-mgYDkUZy.js";
1
+ import { $n as PrReviewSuggestionEdit, A as DeliveryNode, Ai as PortfolioInvalidatedPayloadV1, Ar as PrReviewSuggestionId, B as LedgerRevision, Bi as RoleAssignment, Br as GovernedActionCommandId, C as RelationshipRepairReview, Cr as PrReviewReport, D as DeliveryEntityProjection, Di as DomainEventMetadataV1, E as DeliveryEntityKind, Ei as DomainEventCorrelationId, Fr as reconcilePrReviewReports, Gr as GovernedActionTransitionCommand, Hi as derivePersonInitials, Ii as Person, Ir as GovernedActionLifecycleHeadV1, Jn as PluginHealth, Jr as GovernedActionTransitionV1, Jt as ReadinessCandidateDigest, Kn as Freshness, Kr as GovernedActionTransitionDigest, Kt as ReadinessArtifactRevision, L as EvidenceValue, Li as PersonAvatar, Lr as GovernedActionProviderLineage, Lt as EnvironmentReadinessAssessment, Mi as Actor, N as EvidenceClaim, O as DeliveryEntityService, P as EvidenceItem, Qn as PrReviewSuggestionAgentAuthor, Ri as PersonSourceIdentity, Rr as advanceGovernedActionLifecycle, S as RelationshipRepairRationale, Tr as PrReviewSuggestion, U as RelationshipEndpointKind, Ur as GovernedActionState, Wr as GovernedActionTransitionCause, Xt as ReadinessDerivationVersion, Yr as GovernedActionUnknownOutcome, a as WorkspaceSettingsSections, ai as GovernedActionAttemptDigest, ar as PrReviewSuggestionRevisionPageSize, b as RelationshipRepairProposal, bi as GovernedActionPolicyEvaluationDigest, bt as Release, c as isGovernedWorkspaceSettingsSection, ci as GovernedActionAuthorizationV1, cr as PrReviewSuggestionValidated, di as GovernedActionEnvelopeV1, fn as ReadinessRuleId, hi as GovernedActionIdempotencyKey, ii as governedActionPermissionGrants, ir as PrReviewSuggestionRevisionPage, j as DeliveryRelationship, k as DeliveryEntityStatusGroup, ki as PortfolioInvalidatedEventV1, l as TimelineActorKind, li as GovernedActionEnvelopeDigest, lr as hasSamePrReviewTechnicalClaim, mi as GovernedActionEvidenceSetDigest, mn as ReadinessRuleVersion, ni as governedActionAuthorizationMatchesTransition, nr as PrReviewSuggestionRevision, o as WorkspaceSettingsV1, oi as GovernedActionAttemptV1, or as PrReviewSuggestionRevisionSequence, pi as GovernedActionEvidenceSet, qt as ReadinessAssessment, r as GovernedWorkspaceSettingsSections, ri as governedActionAuthorizationMismatches, rr as PrReviewSuggestionRevisionAuthor, s as changedWorkspaceSettingsSections, si as GovernedActionAuthorizationDigest, t as DEFAULT_WORKSPACE_SETTINGS, ti as governedActionAuthorityMismatches, tr as PrReviewSuggestionRequiresRevalidation, ui as GovernedActionEnvelopeMaterialV1, v as RelationshipRepairApplication, vn as ReadinessVerdict, w as RelationshipRepairReviewDecision, wr as PrReviewSubject, x as RelationshipRepairProposalOrigin, xi as GovernedActionPolicyEvaluationV1, y as RelationshipRepairDisposition, yi as GovernedActionPolicyDigest, yn as ReleaseReadinessAssessment, zi as Role, zr as GovernedActionCommandDigest } from "./workspaceSettings-sv8h_h2P.js";
2
+ import { $ as SourceRevision, At as ShareId, Ct as RelationshipRepairProposalId, Dt as ReviewSuggestionPublicationReservationId, Et as ReviewCommandArtifactId, K as MaximumPluginPayloadBytes, Mt as WorkspaceSettingsMutationId, N as NormalizedPluginEventV1, Nt as UtcTimestamp, Ot as RoleAssignmentId, Q as Revision$1, S as PluginProviderOperationId, St as RelationshipId, Tt as ReleaseId, X as NormalizationSchemaVersion, Y as hasMaximumPluginJsonBytes, Z as ProviderId, _t as PersonId, at as EntityId, bt as ProviderAccountId, c as SemanticVersion, ct as EvidenceClaimId, dt as GovernedActionAttemptId, et as SourceUrl, ft as GovernedActionAuthorizationId, g as PluginActionPayloadDigest, gt as JobId, h as PluginActionDispatchResultV1, ht as GraphNodeId, it as DomainEventId, jt as WorkspaceId, kt as SessionId, lt as EvidenceId, mt as GovernedActionTransitionId, n as NegotiatedPluginDescriptorV1, nt as AgentId, o as PluginDescriptorV1, ot as EnvironmentId, pt as GovernedActionId, rt as AgentThreadId, st as EventCursor, tt as VendorImmutableId, ut as FollowedResourceId, vt as PluginConnectionId, wt as RelationshipRepairReviewId, xt as ReadinessAssessmentId, y as PluginActionReconciliationKey, yt as PrReviewSuggestionRevisionId } from "./descriptor-CCvNzSZL.js";
3
+ import { U as ReviewAgentProfile, q as ReviewSuggestionPublicationOperation } from "./agent-xQhAQXly.js";
4
+ import { a as ReleaseReadinessCandidateMaterial, c as normalizeReadinessRuleMaterial, i as ReadinessRuleMaterial, l as normalizeReleaseReadinessCandidateMaterial, n as summarizeEnvironmentReadiness, r as EnvironmentReadinessCandidateMaterial, s as normalizeEnvironmentReadinessCandidateMaterial, u as AuthorizedShareGrant } from "./readiness-31Mqc-9H.js";
5
+ import { d as PluginUnsupportedCapabilityFailure, o as PluginMalformedResponseFailure } from "./failures-CesHLYbN.js";
6
6
  import { AgentContextFingerprint, AgentProviderError, AgentProviderId, AgentRuntimeEvent, AgentSessionRef, MAXIMUM_AGENT_RUNTIME_EVENT_BYTES } from "@knpkv/ai-runtime";
7
7
  import * as Effect$1 from "effect/Effect";
8
8
  import * as Schema$1 from "effect/Schema";
9
- import { Cause, Context, Crypto, Effect, FileSystem, Layer, Option, Path, Predicate, Result, Schema, Semaphore, Stream } from "effect";
10
9
  import * as DateTime$1 from "effect/DateTime";
10
+ import { Cause, Context, Crypto, Effect, FileSystem, Layer, Option, Path, Predicate, Result, Schema, Semaphore, Stream } from "effect";
11
11
  import * as Encoding$1 from "effect/Encoding";
12
12
  import * as Result$1 from "effect/Result";
13
+ import * as SchemaGetter from "effect/SchemaGetter";
13
14
  import * as Context$1 from "effect/Context";
14
15
  import * as Layer$1 from "effect/Layer";
15
16
  import * as Option$1 from "effect/Option";
@@ -221,7 +222,7 @@ var schema_default = {
221
222
  {
222
223
  "type": "table",
223
224
  "name": "agent_review_suggestion_publications",
224
- "sql": "CREATE TABLE agent_review_suggestion_publications (\n workspace_id TEXT NOT NULL,\n job_id TEXT NOT NULL,\n suggestion_id TEXT NOT NULL CHECK(\n length(suggestion_id) = 71 AND suggestion_id GLOB 'sha256:*'\n AND substr(suggestion_id, 8) NOT GLOB '*[^0-9a-f]*'\n ),\n revision_id TEXT NOT NULL CHECK(\n length(revision_id) = 71 AND revision_id GLOB 'sha256:*'\n AND substr(revision_id, 8) NOT GLOB '*[^0-9a-f]*'\n ),\n content_digest TEXT NOT NULL CHECK(\n length(content_digest) = 71 AND content_digest GLOB 'sha256:*'\n AND substr(content_digest, 8) NOT GLOB '*[^0-9a-f]*'\n ),\n state TEXT NOT NULL CHECK(state IN ('reserved', 'published')),\n publication_id TEXT,\n reservation_id TEXT NOT NULL,\n reservation_acquired_at TEXT NOT NULL,\n reserved_at TEXT NOT NULL,\n published_at TEXT,\n PRIMARY KEY (workspace_id, job_id, suggestion_id, revision_id),\n FOREIGN KEY (workspace_id, job_id)\n REFERENCES agent_jobs(workspace_id, job_id)\n ON DELETE RESTRICT,\n CHECK(reserved_at <= reservation_acquired_at),\n CHECK(\n (state = 'reserved' AND (\n (publication_id IS NULL AND published_at IS NULL) OR\n (publication_id IS NOT NULL AND published_at IS NOT NULL AND reserved_at <= published_at)\n )) OR\n (state = 'published' AND publication_id IS NOT NULL AND published_at IS NOT NULL\n AND reserved_at <= published_at)\n )\n )"
225
+ "sql": "CREATE TABLE agent_review_suggestion_publications (\n workspace_id TEXT NOT NULL,\n job_id TEXT NOT NULL,\n suggestion_id TEXT NOT NULL CHECK(\n length(suggestion_id) = 71 AND suggestion_id GLOB 'sha256:*'\n AND substr(suggestion_id, 8) NOT GLOB '*[^0-9a-f]*'\n ),\n revision_id TEXT NOT NULL CHECK(\n length(revision_id) = 71 AND revision_id GLOB 'sha256:*'\n AND substr(revision_id, 8) NOT GLOB '*[^0-9a-f]*'\n ),\n content_digest TEXT NOT NULL CHECK(\n length(content_digest) = 71 AND content_digest GLOB 'sha256:*'\n AND substr(content_digest, 8) NOT GLOB '*[^0-9a-f]*'\n ),\n state TEXT NOT NULL CHECK(state IN ('reserved', 'published')),\n publication_id TEXT,\n comment_id TEXT CHECK(comment_id IS NULL OR length(comment_id) BETWEEN 1 AND 512),\n previous_content_digest TEXT CHECK(previous_content_digest IS NULL OR (length(previous_content_digest) = 71 AND previous_content_digest GLOB 'sha256:*' AND substr(previous_content_digest, 8) NOT GLOB '*[^0-9a-f]*')),\n previous_publication_id TEXT CHECK(previous_publication_id IS NULL OR length(previous_publication_id) BETWEEN 1 AND 512),\n previous_published_at TEXT,\n reservation_id TEXT NOT NULL,\n reservation_acquired_at TEXT NOT NULL,\n reserved_at TEXT NOT NULL,\n published_at TEXT,\n CHECK((previous_content_digest IS NULL AND previous_publication_id IS NULL AND previous_published_at IS NULL) OR (previous_content_digest IS NOT NULL AND previous_publication_id IS NOT NULL AND previous_published_at IS NOT NULL AND state = 'reserved')),\n PRIMARY KEY (workspace_id, job_id, suggestion_id, revision_id),\n FOREIGN KEY (workspace_id, job_id)\n REFERENCES agent_jobs(workspace_id, job_id)\n ON DELETE RESTRICT,\n CHECK(reserved_at <= reservation_acquired_at),\n CHECK(\n (state = 'reserved' AND (\n (publication_id IS NULL AND published_at IS NULL) OR\n (publication_id IS NOT NULL AND published_at IS NOT NULL AND reserved_at <= published_at)\n )) OR\n (state = 'published' AND publication_id IS NOT NULL AND published_at IS NOT NULL\n AND reserved_at <= published_at)\n )\n )"
225
226
  },
226
227
  {
227
228
  "type": "table",
@@ -328,6 +329,11 @@ var schema_default = {
328
329
  "name": "governed_action_denial_policy_evaluations",
329
330
  "sql": "CREATE TABLE governed_action_denial_policy_evaluations (\n workspace_id TEXT NOT NULL,\n action_id TEXT NOT NULL,\n transition_id TEXT NOT NULL,\n policy_evaluation_digest TEXT NOT NULL,\n PRIMARY KEY (workspace_id, action_id, transition_id),\n UNIQUE (workspace_id, action_id, policy_evaluation_digest),\n FOREIGN KEY (workspace_id, action_id, transition_id)\n REFERENCES governed_action_transitions(workspace_id, action_id, transition_id),\n FOREIGN KEY (workspace_id, action_id, policy_evaluation_digest)\n REFERENCES governed_action_policy_evaluations(workspace_id, action_id, evaluation_digest)\n )"
330
331
  },
332
+ {
333
+ "type": "table",
334
+ "name": "governed_action_entity_targets",
335
+ "sql": "CREATE TABLE governed_action_entity_targets (\n workspace_id TEXT NOT NULL,\n action_id TEXT NOT NULL,\n plugin_connection_id TEXT NOT NULL,\n provider_id TEXT NOT NULL CHECK(provider_id IN (\n 'codecommit', 'codepipeline', 'jira', 'confluence', 'clockify'\n )),\n entity_id TEXT NOT NULL,\n PRIMARY KEY (workspace_id, action_id),\n FOREIGN KEY (workspace_id, action_id)\n REFERENCES governed_actions(workspace_id, action_id)\n ON DELETE RESTRICT,\n FOREIGN KEY (workspace_id, entity_id, plugin_connection_id, provider_id)\n REFERENCES entities(workspace_id, entity_id, plugin_connection_id, provider_id)\n ON DELETE RESTRICT\n )"
336
+ },
331
337
  {
332
338
  "type": "table",
333
339
  "name": "governed_action_execution_leases",
@@ -368,6 +374,16 @@ var schema_default = {
368
374
  "name": "governed_action_recovery_claims",
369
375
  "sql": "CREATE TABLE governed_action_recovery_claims (\n workspace_id TEXT NOT NULL,\n action_id TEXT NOT NULL,\n claim_sequence INTEGER NOT NULL CHECK(claim_sequence >= 1),\n claim_token_digest TEXT NOT NULL CHECK(\n length(claim_token_digest) = 64 AND claim_token_digest NOT GLOB '*[^0-9a-f]*'\n ),\n claimed_at TEXT NOT NULL,\n lease_expires_at TEXT NOT NULL,\n PRIMARY KEY (workspace_id, action_id, claim_sequence),\n UNIQUE (claim_token_digest),\n UNIQUE (workspace_id, action_id, claim_token_digest),\n FOREIGN KEY (workspace_id, action_id)\n REFERENCES governed_action_execution_leases(workspace_id, action_id),\n CHECK(claimed_at < lease_expires_at)\n )"
370
376
  },
377
+ {
378
+ "type": "table",
379
+ "name": "governed_action_release_publication_slots",
380
+ "sql": "CREATE TABLE governed_action_release_publication_slots (\n workspace_id TEXT NOT NULL,\n action_id TEXT NOT NULL,\n provider_id TEXT NOT NULL CHECK(provider_id = 'confluence'),\n release_id TEXT NOT NULL CHECK(length(release_id) = 36),\n predecessor_action_id TEXT CHECK(\n predecessor_action_id IS NULL OR length(predecessor_action_id) = 36\n ),\n PRIMARY KEY (workspace_id, action_id),\n FOREIGN KEY (workspace_id, action_id)\n REFERENCES governed_action_release_publications(workspace_id, action_id)\n ON DELETE RESTRICT\n )"
381
+ },
382
+ {
383
+ "type": "table",
384
+ "name": "governed_action_release_publications",
385
+ "sql": "CREATE TABLE governed_action_release_publications (\n workspace_id TEXT NOT NULL,\n action_id TEXT NOT NULL,\n provider_id TEXT NOT NULL CHECK(provider_id IN (\n 'codecommit', 'codepipeline', 'jira', 'confluence', 'clockify'\n )),\n release_id TEXT NOT NULL CHECK(length(release_id) = 36),\n predecessor_action_id TEXT CHECK(\n predecessor_action_id IS NULL OR length(predecessor_action_id) = 36\n ),\n PRIMARY KEY (workspace_id, action_id),\n FOREIGN KEY (workspace_id, action_id)\n REFERENCES governed_actions(workspace_id, action_id)\n ON DELETE RESTRICT,\n FOREIGN KEY (workspace_id, release_id)\n REFERENCES releases(workspace_id, release_id)\n ON DELETE RESTRICT\n )"
386
+ },
371
387
  {
372
388
  "type": "table",
373
389
  "name": "governed_action_target_dimensions",
@@ -381,7 +397,7 @@ var schema_default = {
381
397
  {
382
398
  "type": "table",
383
399
  "name": "governed_actions",
384
- "sql": "CREATE TABLE governed_actions (\n workspace_id TEXT NOT NULL,\n action_id TEXT NOT NULL,\n plugin_connection_id TEXT NOT NULL,\n provider_id TEXT NOT NULL CHECK(provider_id IN (\n 'codecommit', 'codepipeline', 'jira', 'confluence', 'clockify'\n )),\n target_entity_id TEXT NOT NULL,\n idempotency_key TEXT NOT NULL CHECK(length(idempotency_key) BETWEEN 1 AND 512),\n envelope_digest TEXT NOT NULL CHECK(\n length(envelope_digest) = 71 AND envelope_digest GLOB 'sha256:*'\n AND substr(envelope_digest, 8) NOT GLOB '*[^0-9a-f]*'\n ),\n envelope_json TEXT NOT NULL CHECK(length(envelope_json) BETWEEN 2 AND 1048576),\n state TEXT CHECK(state IN (\n 'proposed', 'authorized', 'denied', 'expired', 'cancelled', 'started',\n 'cancel-requested', 'cancel-requested-unknown', 'succeeded', 'failed', 'unknown'\n )),\n lineage_json TEXT CHECK(lineage_json IS NULL OR length(lineage_json) BETWEEN 2 AND 65536),\n lineage_kind TEXT CHECK(lineage_kind IS NULL OR lineage_kind IN (\n 'none', 'accepted', 'reconcilable', 'manual', 'terminal'\n )),\n provider_operation_id TEXT CHECK(\n provider_operation_id IS NULL OR length(provider_operation_id) BETWEEN 1 AND 512\n ),\n reconciliation_key TEXT CHECK(\n reconciliation_key IS NULL OR length(reconciliation_key) BETWEEN 1 AND 512\n ),\n terminal_status TEXT CHECK(\n terminal_status IS NULL OR terminal_status IN ('succeeded', 'failed', 'cancelled')\n ),\n head_transition_id TEXT,\n head_sequence INTEGER CHECK(head_sequence IS NULL OR head_sequence >= 1),\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL,\n PRIMARY KEY (workspace_id, action_id),\n UNIQUE (workspace_id, plugin_connection_id, idempotency_key),\n UNIQUE (workspace_id, action_id, envelope_digest),\n FOREIGN KEY (workspace_id) REFERENCES workspaces(workspace_id),\n FOREIGN KEY (workspace_id, plugin_connection_id, provider_id)\n REFERENCES plugin_connections(workspace_id, plugin_connection_id, provider_id),\n FOREIGN KEY (workspace_id, target_entity_id, plugin_connection_id, provider_id)\n REFERENCES entities(workspace_id, entity_id, plugin_connection_id, provider_id),\n CHECK(created_at <= updated_at),\n CHECK(\n (state IS NULL AND lineage_json IS NULL AND lineage_kind IS NULL\n AND provider_operation_id IS NULL AND reconciliation_key IS NULL AND terminal_status IS NULL\n AND head_transition_id IS NULL AND head_sequence IS NULL) OR\n (state IS NOT NULL AND lineage_json IS NOT NULL AND lineage_kind IS NOT NULL\n AND head_transition_id IS NOT NULL AND head_sequence IS NOT NULL)\n ),\n CHECK(\n lineage_kind IS NULL OR\n (lineage_kind = 'none' AND provider_operation_id IS NULL\n AND reconciliation_key IS NULL AND terminal_status IS NULL) OR\n (lineage_kind = 'accepted' AND provider_operation_id IS NOT NULL\n AND reconciliation_key IS NOT NULL AND terminal_status IS NULL) OR\n (lineage_kind = 'reconcilable' AND reconciliation_key IS NOT NULL\n AND terminal_status IS NULL) OR\n (lineage_kind = 'manual' AND reconciliation_key IS NULL AND terminal_status IS NULL) OR\n (lineage_kind = 'terminal' AND provider_operation_id IS NOT NULL\n AND reconciliation_key IS NULL AND terminal_status IS NOT NULL)\n ),\n CHECK(\n state IS NULL OR\n (state IN ('proposed', 'authorized', 'denied', 'expired') AND lineage_kind = 'none') OR\n (state = 'cancelled' AND (\n lineage_kind = 'none' OR (lineage_kind = 'terminal' AND terminal_status = 'cancelled')\n )) OR\n (state IN ('started', 'cancel-requested') AND lineage_kind IN ('none', 'accepted')) OR\n (state IN ('unknown', 'cancel-requested-unknown')\n AND lineage_kind IN ('reconcilable', 'manual')) OR\n (state = 'succeeded' AND lineage_kind = 'terminal' AND terminal_status = 'succeeded') OR\n (state = 'failed' AND lineage_kind = 'terminal' AND terminal_status = 'failed')\n )\n )"
400
+ "sql": "CREATE TABLE governed_actions (\n workspace_id TEXT NOT NULL,\n action_id TEXT NOT NULL,\n plugin_connection_id TEXT NOT NULL,\n provider_id TEXT NOT NULL CHECK(provider_id IN (\n 'codecommit', 'codepipeline', 'jira', 'confluence', 'clockify'\n )),\n target_entity_id TEXT NOT NULL,\n idempotency_key TEXT NOT NULL CHECK(length(idempotency_key) BETWEEN 1 AND 512),\n envelope_digest TEXT NOT NULL CHECK(\n length(envelope_digest) = 71 AND envelope_digest GLOB 'sha256:*'\n AND substr(envelope_digest, 8) NOT GLOB '*[^0-9a-f]*'\n ),\n envelope_json TEXT NOT NULL CHECK(length(envelope_json) BETWEEN 2 AND 1048576),\n state TEXT CHECK(state IN (\n 'proposed', 'authorized', 'denied', 'expired', 'cancelled', 'started',\n 'cancel-requested', 'cancel-requested-unknown', 'succeeded', 'failed', 'unknown'\n )),\n lineage_json TEXT CHECK(lineage_json IS NULL OR length(lineage_json) BETWEEN 2 AND 65536),\n lineage_kind TEXT CHECK(lineage_kind IS NULL OR lineage_kind IN (\n 'none', 'accepted', 'reconcilable', 'manual', 'terminal'\n )),\n provider_operation_id TEXT CHECK(\n provider_operation_id IS NULL OR length(provider_operation_id) BETWEEN 1 AND 512\n ),\n reconciliation_key TEXT CHECK(\n reconciliation_key IS NULL OR length(reconciliation_key) BETWEEN 1 AND 512\n ),\n terminal_status TEXT CHECK(\n terminal_status IS NULL OR terminal_status IN ('succeeded', 'failed', 'cancelled')\n ),\n head_transition_id TEXT,\n head_sequence INTEGER CHECK(head_sequence IS NULL OR head_sequence >= 1),\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL,\n PRIMARY KEY (workspace_id, action_id),\n UNIQUE (workspace_id, plugin_connection_id, idempotency_key),\n UNIQUE (workspace_id, action_id, envelope_digest),\n FOREIGN KEY (workspace_id) REFERENCES workspaces(workspace_id),\n FOREIGN KEY (workspace_id, plugin_connection_id, provider_id)\n REFERENCES plugin_connections(workspace_id, plugin_connection_id, provider_id),\n CHECK(created_at <= updated_at),\n CHECK(\n (state IS NULL AND lineage_json IS NULL AND lineage_kind IS NULL\n AND provider_operation_id IS NULL AND reconciliation_key IS NULL AND terminal_status IS NULL\n AND head_transition_id IS NULL AND head_sequence IS NULL) OR\n (state IS NOT NULL AND lineage_json IS NOT NULL AND lineage_kind IS NOT NULL\n AND head_transition_id IS NOT NULL AND head_sequence IS NOT NULL)\n ),\n CHECK(\n lineage_kind IS NULL OR\n (lineage_kind = 'none' AND provider_operation_id IS NULL\n AND reconciliation_key IS NULL AND terminal_status IS NULL) OR\n (lineage_kind = 'accepted' AND provider_operation_id IS NOT NULL\n AND reconciliation_key IS NOT NULL AND terminal_status IS NULL) OR\n (lineage_kind = 'reconcilable' AND reconciliation_key IS NOT NULL\n AND terminal_status IS NULL) OR\n (lineage_kind = 'manual' AND reconciliation_key IS NULL AND terminal_status IS NULL) OR\n (lineage_kind = 'terminal' AND provider_operation_id IS NOT NULL\n AND reconciliation_key IS NULL AND terminal_status IS NOT NULL)\n ),\n CHECK(\n state IS NULL OR\n (state IN ('proposed', 'authorized', 'denied', 'expired') AND lineage_kind = 'none') OR\n (state = 'cancelled' AND (\n lineage_kind = 'none' OR (lineage_kind = 'terminal' AND terminal_status = 'cancelled')\n )) OR\n (state IN ('started', 'cancel-requested') AND lineage_kind IN ('none', 'accepted')) OR\n (state IN ('unknown', 'cancel-requested-unknown')\n AND lineage_kind IN ('reconcilable', 'manual')) OR\n (state = 'succeeded' AND lineage_kind = 'terminal' AND terminal_status = 'succeeded') OR\n (state = 'failed' AND lineage_kind = 'terminal' AND terminal_status = 'failed')\n )\n )"
385
401
  },
386
402
  {
387
403
  "type": "table",
@@ -656,7 +672,7 @@ var schema_default = {
656
672
  {
657
673
  "type": "index",
658
674
  "name": "agent_thread_events_review_result_idx",
659
- "sql": "CREATE UNIQUE INDEX agent_thread_events_review_result_idx\n ON agent_thread_events(workspace_id, job_id)\n WHERE event_kind = 'review-report'"
675
+ "sql": "CREATE INDEX agent_thread_events_review_result_idx\n ON agent_thread_events(workspace_id, job_id, event_sequence DESC)\n WHERE event_kind = 'review-report'"
660
676
  },
661
677
  {
662
678
  "type": "index",
@@ -778,6 +794,16 @@ var schema_default = {
778
794
  "name": "governed_action_recovery_claim_expiry_idx",
779
795
  "sql": "CREATE INDEX governed_action_recovery_claim_expiry_idx\n ON governed_action_recovery_claims(lease_expires_at, workspace_id, action_id, claim_sequence)"
780
796
  },
797
+ {
798
+ "type": "index",
799
+ "name": "governed_action_release_publication_slots_unique_idx",
800
+ "sql": "CREATE UNIQUE INDEX governed_action_release_publication_slots_unique_idx\n ON governed_action_release_publication_slots(\n workspace_id, provider_id, release_id, COALESCE(predecessor_action_id, '')\n )"
801
+ },
802
+ {
803
+ "type": "index",
804
+ "name": "governed_action_release_publications_lookup_idx",
805
+ "sql": "CREATE INDEX governed_action_release_publications_lookup_idx\n ON governed_action_release_publications(\n workspace_id, provider_id, release_id, action_id DESC\n )"
806
+ },
781
807
  {
782
808
  "type": "index",
783
809
  "name": "governed_action_target_dimensions_lookup_idx",
@@ -1203,6 +1229,21 @@ var schema_default = {
1203
1229
  "name": "governed_action_denial_policy_exact_owner",
1204
1230
  "sql": "CREATE TRIGGER governed_action_denial_policy_exact_owner\n BEFORE INSERT ON governed_action_denial_policy_evaluations\n WHEN NOT EXISTS (\n SELECT 1\n FROM governed_action_transitions transition_record\n JOIN governed_action_policy_evaluations evaluation\n ON evaluation.workspace_id = NEW.workspace_id\n AND evaluation.action_id = NEW.action_id\n AND evaluation.evaluation_digest = NEW.policy_evaluation_digest\n WHERE transition_record.workspace_id = NEW.workspace_id\n AND transition_record.action_id = NEW.action_id\n AND transition_record.transition_id = NEW.transition_id\n AND transition_record.command_tag = 'deny'\n AND evaluation.decision = 'denied'\n AND evaluation.evaluated_at <= transition_record.occurred_at\n AND NOT EXISTS (\n SELECT 1\n FROM audit_events audit\n WHERE audit.workspace_id = transition_record.workspace_id\n AND audit.action_id = transition_record.action_id\n AND audit.transition_id = transition_record.transition_id\n )\n )\n BEGIN\n SELECT RAISE(ABORT, 'denial policy evaluation must belong to its exact deny transition');\n END"
1205
1231
  },
1232
+ {
1233
+ "type": "trigger",
1234
+ "name": "governed_action_entity_targets_exact",
1235
+ "sql": "CREATE TRIGGER governed_action_entity_targets_exact\n BEFORE INSERT ON governed_action_entity_targets\n WHEN NOT EXISTS (\n SELECT 1 FROM governed_actions action\n WHERE action.workspace_id = NEW.workspace_id\n AND action.action_id = NEW.action_id\n AND action.plugin_connection_id = NEW.plugin_connection_id\n AND action.provider_id = NEW.provider_id\n AND action.target_entity_id = NEW.entity_id\n AND json_type(action.envelope_json, '$.releasePublication') IS NULL\n )\n BEGIN\n SELECT RAISE(ABORT, 'governed action entity target must match the immutable envelope');\n END"
1236
+ },
1237
+ {
1238
+ "type": "trigger",
1239
+ "name": "governed_action_entity_targets_no_delete",
1240
+ "sql": "CREATE TRIGGER governed_action_entity_targets_no_delete\n BEFORE DELETE ON governed_action_entity_targets\n BEGIN\n SELECT RAISE(ABORT, 'governed action entity targets are immutable');\n END"
1241
+ },
1242
+ {
1243
+ "type": "trigger",
1244
+ "name": "governed_action_entity_targets_no_update",
1245
+ "sql": "CREATE TRIGGER governed_action_entity_targets_no_update\n BEFORE UPDATE ON governed_action_entity_targets\n BEGIN\n SELECT RAISE(ABORT, 'governed action entity targets are immutable');\n END"
1246
+ },
1206
1247
  {
1207
1248
  "type": "trigger",
1208
1249
  "name": "governed_action_execution_lease_exact_start",
@@ -1338,6 +1379,36 @@ var schema_default = {
1338
1379
  "name": "governed_action_recovery_claims_no_update",
1339
1380
  "sql": "CREATE TRIGGER governed_action_recovery_claims_no_update\n BEFORE UPDATE ON governed_action_recovery_claims\n BEGIN\n SELECT RAISE(ABORT, 'governed_action_recovery_claims is immutable');\n END"
1340
1381
  },
1382
+ {
1383
+ "type": "trigger",
1384
+ "name": "governed_action_release_publication_slots_exact",
1385
+ "sql": "CREATE TRIGGER governed_action_release_publication_slots_exact\n BEFORE INSERT ON governed_action_release_publication_slots\n WHEN NOT EXISTS (\n SELECT 1 FROM governed_action_release_publications publication\n WHERE publication.workspace_id = NEW.workspace_id\n AND publication.action_id = NEW.action_id\n AND publication.provider_id = NEW.provider_id\n AND publication.release_id = NEW.release_id\n AND publication.predecessor_action_id IS NEW.predecessor_action_id\n )\n BEGIN\n SELECT RAISE(ABORT, 'governed action release publication slot must match immutable publication history');\n END"
1386
+ },
1387
+ {
1388
+ "type": "trigger",
1389
+ "name": "governed_action_release_publication_slots_release",
1390
+ "sql": "CREATE TRIGGER governed_action_release_publication_slots_release\n AFTER UPDATE OF state ON governed_actions\n WHEN NEW.state IN ('denied', 'expired', 'cancelled', 'failed')\n BEGIN\n DELETE FROM governed_action_release_publication_slots\n WHERE workspace_id = NEW.workspace_id AND action_id = NEW.action_id;\n END"
1391
+ },
1392
+ {
1393
+ "type": "trigger",
1394
+ "name": "governed_action_release_publications_exact",
1395
+ "sql": "CREATE TRIGGER governed_action_release_publications_exact\n BEFORE INSERT ON governed_action_release_publications\n WHEN NOT EXISTS (\n SELECT 1 FROM governed_actions action\n WHERE action.workspace_id = NEW.workspace_id\n AND action.action_id = NEW.action_id\n AND action.provider_id = NEW.provider_id\n AND json_extract(action.envelope_json, '$.releasePublication.releaseId') = NEW.release_id\n AND json_extract(action.envelope_json, '$.releasePublication.predecessorPublicationActionId') IS NEW.predecessor_action_id\n )\n BEGIN\n SELECT RAISE(ABORT, 'governed action release publication must match the immutable envelope');\n END"
1396
+ },
1397
+ {
1398
+ "type": "trigger",
1399
+ "name": "governed_action_release_publications_no_delete",
1400
+ "sql": "CREATE TRIGGER governed_action_release_publications_no_delete\n BEFORE DELETE ON governed_action_release_publications\n BEGIN\n SELECT RAISE(ABORT, 'governed action release publications are immutable');\n END"
1401
+ },
1402
+ {
1403
+ "type": "trigger",
1404
+ "name": "governed_action_release_publications_no_update",
1405
+ "sql": "CREATE TRIGGER governed_action_release_publications_no_update\n BEFORE UPDATE ON governed_action_release_publications\n BEGIN\n SELECT RAISE(ABORT, 'governed action release publications are immutable');\n END"
1406
+ },
1407
+ {
1408
+ "type": "trigger",
1409
+ "name": "governed_action_target_authority_exact",
1410
+ "sql": "CREATE TRIGGER governed_action_target_authority_exact\n BEFORE INSERT ON governed_actions\n WHEN NOT EXISTS (\n SELECT 1 FROM entities entity\n WHERE entity.workspace_id = NEW.workspace_id\n AND entity.entity_id = NEW.target_entity_id\n AND entity.plugin_connection_id = NEW.plugin_connection_id\n AND entity.provider_id = NEW.provider_id\n ) AND NOT (\n json_valid(NEW.envelope_json)\n AND json_extract(NEW.envelope_json, '$.releasePublication.releaseId') = NEW.target_entity_id\n AND (\n (\n NEW.provider_id = 'jira'\n AND json_extract(NEW.envelope_json, '$.proposal.request.actionKind') = 'create-release-version'\n AND json_extract(NEW.envelope_json, '$.proposal.request.target.entityType') = 'jira.project-version'\n ) OR (\n NEW.provider_id = 'confluence'\n AND (\n (\n json_extract(NEW.envelope_json, '$.proposal.request.actionKind') = 'create-page'\n AND json_extract(NEW.envelope_json, '$.proposal.request.target.entityType') = 'release-page'\n ) OR (\n json_extract(NEW.envelope_json, '$.proposal.request.actionKind') = 'update-page'\n AND json_extract(NEW.envelope_json, '$.proposal.request.target.entityType') = 'page'\n )\n )\n )\n )\n AND EXISTS (\n SELECT 1 FROM releases release\n WHERE release.workspace_id = NEW.workspace_id\n AND release.release_id = NEW.target_entity_id\n )\n )\n BEGIN\n SELECT RAISE(ABORT, 'governed action target must be an exact entity or supported release publication');\n END"
1411
+ },
1341
1412
  {
1342
1413
  "type": "trigger",
1343
1414
  "name": "governed_action_target_dimensions_exact",
@@ -1868,13 +1939,13 @@ var configureAndVerifyPragmas = Effect.fn("Database.configureAndVerifyPragmas")(
1868
1939
  yield* sql`PRAGMA foreign_keys = ON`;
1869
1940
  yield* sql`PRAGMA journal_mode = WAL`;
1870
1941
  yield* sql`PRAGMA busy_timeout = 5000`;
1871
- }).pipe(Effect.catchCause(() => new DatabaseInitializationError({ operation: "configure" })));
1942
+ }).pipe(Effect.mapError(() => new DatabaseInitializationError({ operation: "configure" })));
1872
1943
  yield* Effect.gen(function* () {
1873
1944
  const foreignKeys = yield* sql`PRAGMA foreign_keys`.pipe(Effect.flatMap((rows) => decodeRows$4(ForeignKeysPragmaRow, rows)));
1874
1945
  const journalMode = yield* sql`PRAGMA journal_mode`.pipe(Effect.flatMap((rows) => decodeRows$4(JournalModePragmaRow, rows)));
1875
1946
  const busyTimeout = yield* sql`PRAGMA busy_timeout`.pipe(Effect.flatMap((rows) => decodeRows$4(BusyTimeoutPragmaRow, rows)));
1876
1947
  if (foreignKeys.length !== 1 || foreignKeys[0]?.foreignKeys !== 1 || journalMode.length !== 1 || journalMode[0]?.journalMode.toLowerCase() !== "wal" || busyTimeout.length !== 1 || busyTimeout[0]?.timeout !== 5e3) return yield* Effect.fail("SQLite pragmas did not retain their required values");
1877
- }).pipe(Effect.catchCause(() => new DatabaseInitializationError({ operation: "verify-pragmas" })));
1948
+ }).pipe(Effect.mapError(() => new DatabaseInitializationError({ operation: "verify-pragmas" })));
1878
1949
  });
1879
1950
  /** Run the startup SQLite integrity boundary. @internal */
1880
1951
  var verifyDatabaseIntegrity = Effect.fn("Database.verifyIntegrity")(function* (sql) {
@@ -1885,7 +1956,7 @@ var verifyDatabaseIntegrity = Effect.fn("Database.verifyIntegrity")(function* (s
1885
1956
  }).pipe(Effect.mapError(() => new DatabaseInitializationError({ operation: "verify-integrity" })));
1886
1957
  });
1887
1958
  var checkpointBeforeSchemaChange = Effect.fn("Database.checkpointBeforeSchemaChange")(function* (sql) {
1888
- yield* sql`PRAGMA wal_checkpoint(TRUNCATE)`.pipe(Effect.catchCause(() => new SchemaWriteBarrierError({ phase: "acquire" })));
1959
+ yield* sql`PRAGMA wal_checkpoint(TRUNCATE)`.pipe(Effect.mapError(() => new SchemaWriteBarrierError({ phase: "acquire" })));
1889
1960
  });
1890
1961
  var verifyCheckpointStayedQuiescent = Effect.fn("Database.verifyCheckpointStayedQuiescent")(function* (databaseFile) {
1891
1962
  const fileSystem = yield* FileSystem.FileSystem;
@@ -1894,10 +1965,11 @@ var verifyCheckpointStayedQuiescent = Effect.fn("Database.verifyCheckpointStayed
1894
1965
  const info = yield* fileSystem.stat(walFile).pipe(Effect.mapError(() => new SchemaWriteBarrierError({ phase: "verify" })));
1895
1966
  if (info.type !== "File" || info.size !== 0n) return yield* new SchemaWriteBarrierError({ phase: "verify" });
1896
1967
  });
1897
- /** Convert schema transaction defects and interruption into a redacted typed failure. */
1968
+ /** Convert transaction defects into a redacted failure while preserving cancellation. */
1898
1969
  var sandboxSchemaTransaction = (transaction) => transaction.pipe(Effect.catchCause((cause) => {
1970
+ if (Cause.hasInterrupts(cause)) return Effect.failCause(cause);
1899
1971
  const typedFailure = Cause.findErrorOption(cause);
1900
- if (Cause.hasDies(cause) || Cause.hasInterrupts(cause) || Option.isNone(typedFailure)) return Effect.fail(new SchemaWriteBarrierError({ phase: "verify" }));
1972
+ if (Cause.hasDies(cause) || Option.isNone(typedFailure)) return Effect.fail(new SchemaWriteBarrierError({ phase: "verify" }));
1901
1973
  return Effect.fail(typedFailure.value);
1902
1974
  }));
1903
1975
  /** Hold SQLite's reserved writer transaction across one fresh-schema operation. */
@@ -1909,8 +1981,10 @@ var makeClientLayer = (busyTimeoutMilliseconds, databaseUrl, maxConnections) =>
1909
1981
  transformResultNames: snakeToCamel,
1910
1982
  url: databaseUrl
1911
1983
  };
1912
- return LibsqlClient.layer(clientConfig).pipe(Layer.catchCause(() => Layer.effectContext(Effect.fail(new DatabaseInitializationError({ operation: "connect" })))));
1984
+ return LibsqlClient.layer(clientConfig).pipe(Layer.catchCause(handleDatabaseConnectionCause));
1913
1985
  };
1986
+ /** Redact client construction defects while retaining every original interruption reason. @internal */
1987
+ var handleDatabaseConnectionCause = (cause) => Cause.hasInterrupts(cause) ? Layer.effectContext(Effect.failCause(Cause.fromReasons(cause.reasons.filter(Cause.isInterruptReason)))) : Layer.effectContext(Effect.fail(new DatabaseInitializationError({ operation: "connect" })));
1914
1988
  var initializeDatabase = Effect.fn("Database.initializeDatabase")(function* (config) {
1915
1989
  yield* schemaLock.withPermit(Effect.scoped(Effect.gen(function* () {
1916
1990
  const context = yield* Layer.build(makeClientLayer(config.busyTimeoutMilliseconds, config.databaseUrl, 1));
@@ -2451,6 +2525,10 @@ var MAXIMUM_AGENT_ATTEMPT_OUTPUT_BYTES = 1048576;
2451
2525
  var MAXIMUM_AGENT_JOB_PROMPT_LENGTH = 5e3;
2452
2526
  /** Maximum thread events returned by one replay page. */
2453
2527
  var MAXIMUM_AGENT_THREAD_EVENT_PAGE_SIZE = 128;
2528
+ /** One explicit extension is bounded to the selected profile's original budget. */
2529
+ var MAXIMUM_REVIEW_BUDGET_EXTENSION_COUNT = 1;
2530
+ /** Hard upper bound for one immutable review, including its single extension. */
2531
+ var MAXIMUM_REVIEW_BUDGET_MILLIS = 36e5;
2454
2532
  /** Positive sequence assigned to attempts within one durable job. */
2455
2533
  var AgentAttemptSequence = Schema$1.Int.check(Schema$1.isBetween({
2456
2534
  minimum: 1,
@@ -2481,7 +2559,18 @@ var ReleaseChatAgentJobTask = Schema$1.TaggedStruct("release-chat", {});
2481
2559
  var PrReviewAgentJobTaskFields = {
2482
2560
  pluginConnectionId: PluginConnectionId,
2483
2561
  subject: PrReviewSubject,
2484
- reviewProfile: ReviewAgentProfile
2562
+ reviewProfile: ReviewAgentProfile,
2563
+ intent: Schema$1.optionalKey(Schema$1.Literals([
2564
+ "full-review",
2565
+ "suggestion-edit",
2566
+ "suggestion-revalidation"
2567
+ ])),
2568
+ target: Schema$1.optionalKey(Schema$1.Struct({
2569
+ sourceJobId: JobId,
2570
+ suggestionId: PrReviewSuggestionId,
2571
+ selectedRevisionId: PrReviewSuggestionRevisionId,
2572
+ history: PrReviewSuggestionRevisionPage
2573
+ }))
2485
2574
  };
2486
2575
  /** Read-only review request bound to one immutable pull request head. */
2487
2576
  var EnqueuePrReviewAgentJobTask = Schema$1.TaggedStruct("pr-review", PrReviewAgentJobTaskFields);
@@ -2497,6 +2586,7 @@ var PrReviewThreadRunSummary = Schema$1.Struct({
2497
2586
  state: Schema$1.Literals([
2498
2587
  "cancelled",
2499
2588
  "failed",
2589
+ "interrupted",
2500
2590
  "succeeded",
2501
2591
  "unknown"
2502
2592
  ]),
@@ -2579,6 +2669,14 @@ var ClaimedAgentJob = Schema$1.Struct({
2579
2669
  access: Schema$1.Literals(["read-only", "workspace-write"]),
2580
2670
  prompt: AgentJobPrompt,
2581
2671
  context: AgentContextSnapshotRecord,
2672
+ reviewBudgetMillis: Schema$1.optionalKey(Schema$1.Int.check(Schema$1.isBetween({
2673
+ minimum: 1,
2674
+ maximum: 36e5
2675
+ }))),
2676
+ reviewBudgetExtensionCount: Schema$1.optionalKey(Schema$1.Int.check(Schema$1.isBetween({
2677
+ minimum: 0,
2678
+ maximum: 1
2679
+ }))),
2582
2680
  sessionRef: Schema$1.NullOr(AgentSessionRef),
2583
2681
  cancellationRequested: Schema$1.Boolean
2584
2682
  });
@@ -2614,8 +2712,53 @@ var CompleteAgentReviewInput = Schema$1.Struct({
2614
2712
  report: Schema$1.Unknown,
2615
2713
  completedAt: UtcTimestamp
2616
2714
  });
2715
+ /** Startup transition for review attempts whose owning process disappeared. */
2716
+ var InterruptRunningReviewsInput = Schema$1.Struct({
2717
+ workspaceId: WorkspaceId,
2718
+ interruptedAt: UtcTimestamp,
2719
+ preservedAttempts: Schema$1.optionalKey(Schema$1.Array(Schema$1.Struct({
2720
+ jobId: JobId,
2721
+ attemptSequence: AgentAttemptSequence
2722
+ })))
2723
+ });
2724
+ /** Durable identity used to match a live Review Sandbox to one immutable attempt. */
2725
+ var RunningPrReviewAttempt = Schema$1.Struct({
2726
+ jobId: JobId,
2727
+ attemptSequence: AgentAttemptSequence,
2728
+ attemptId: Schema$1.String.check(Schema$1.isPattern(/^[a-f0-9]{12}$/u)),
2729
+ sessionRef: Schema$1.NullOr(AgentSessionRef)
2730
+ });
2731
+ /** Startup handoff for a live server-private Review Sandbox. */
2732
+ var AttachRunningPrReviewSessionInput = Schema$1.Struct({
2733
+ workspaceId: WorkspaceId,
2734
+ jobId: JobId,
2735
+ attemptSequence: AgentAttemptSequence,
2736
+ sessionRef: AgentSessionRef
2737
+ });
2738
+ /** Persist the latest validated report while an immutable review is still running. */
2739
+ var RecordAgentReviewProgressInput = Schema$1.Struct({
2740
+ workspaceId: WorkspaceId,
2741
+ jobId: JobId,
2742
+ attemptSequence: AgentAttemptSequence,
2743
+ leaseToken: AgentLeaseToken,
2744
+ report: Schema$1.Unknown,
2745
+ occurredAt: UtcTimestamp
2746
+ });
2747
+ /** Read the effective budget of one claimed immutable review. */
2748
+ var ReadReviewBudgetInput = Schema$1.Struct({
2749
+ workspaceId: WorkspaceId,
2750
+ jobId: JobId,
2751
+ task: AgentJobTask
2752
+ });
2617
2753
  /** Digest binding one durable publication reservation to the exact confirmed body. */
2618
2754
  var ReviewSuggestionPublicationDigest = Schema$1.String.check(Schema$1.isPattern(/^sha256:[0-9a-f]{64}$/u, { expected: "a lowercase SHA-256 digest" })).pipe(Schema$1.brand("ReviewSuggestionPublicationDigest"));
2755
+ /** Provider comment identity retained for governed lifecycle operations. */
2756
+ var ReviewSuggestionPublicationCommentId = Schema$1.String.check(Schema$1.isTrimmed(), Schema$1.isNonEmpty(), Schema$1.isMaxLength(512)).pipe(Schema$1.brand("ReviewSuggestionPublicationCommentId"));
2757
+ /** Provider receipt coordinate decoded to the persisted comment identity. */
2758
+ var ReviewSuggestionPublicationCommentLocator = Schema$1.TemplateLiteral([Schema$1.Literal("comment:"), ReviewSuggestionPublicationCommentId]).pipe(Schema$1.decodeTo(ReviewSuggestionPublicationCommentId, {
2759
+ decode: SchemaGetter.transform((locator) => locator.slice(8)),
2760
+ encode: SchemaGetter.transform((commentId) => `comment:${commentId}`)
2761
+ }));
2619
2762
  /** Atomic pre-provider reservation for one suggestion and exact confirmed body. */
2620
2763
  var ReserveReviewSuggestionPublicationInput = Schema$1.Struct({
2621
2764
  workspaceId: WorkspaceId,
@@ -2623,21 +2766,25 @@ var ReserveReviewSuggestionPublicationInput = Schema$1.Struct({
2623
2766
  suggestionId: PrReviewSuggestionId,
2624
2767
  revisionId: PrReviewSuggestionRevisionId,
2625
2768
  contentDigest: ReviewSuggestionPublicationDigest,
2769
+ operation: Schema$1.optionalKey(ReviewSuggestionPublicationOperation),
2770
+ commentId: Schema$1.optionalKey(ReviewSuggestionPublicationCommentId),
2626
2771
  reservationId: ReviewSuggestionPublicationReservationId,
2627
2772
  reservedAt: UtcTimestamp
2628
2773
  });
2629
2774
  /** Durable result of reserving an exact publication body. */
2630
2775
  var ReviewSuggestionPublicationReservation = Schema$1.Union([
2631
- Schema$1.TaggedStruct("acquired", {}),
2632
- Schema$1.TaggedStruct("in-progress", {}),
2776
+ Schema$1.TaggedStruct("acquired", { commentId: Schema$1.optionalKey(ReviewSuggestionPublicationCommentId) }),
2777
+ Schema$1.TaggedStruct("in-progress", { commentId: Schema$1.optionalKey(ReviewSuggestionPublicationCommentId) }),
2633
2778
  Schema$1.TaggedStruct("recoverable", {
2634
2779
  publicationId: GovernedActionId,
2635
2780
  publishedAt: UtcTimestamp,
2636
- reservationId: ReviewSuggestionPublicationReservationId
2781
+ reservationId: ReviewSuggestionPublicationReservationId,
2782
+ commentId: Schema$1.optionalKey(ReviewSuggestionPublicationCommentId)
2637
2783
  }),
2638
2784
  Schema$1.TaggedStruct("published", {
2639
2785
  publicationId: GovernedActionId,
2640
- publishedAt: UtcTimestamp
2786
+ publishedAt: UtcTimestamp,
2787
+ commentId: Schema$1.optionalKey(ReviewSuggestionPublicationCommentId)
2641
2788
  })
2642
2789
  ]);
2643
2790
  /** Release one exact reservation after a confirmed provider no-write outcome. */
@@ -2656,16 +2803,36 @@ var RecordReviewSuggestionPublicationInput = Schema$1.Struct({
2656
2803
  suggestionId: PrReviewSuggestionId,
2657
2804
  revisionId: PrReviewSuggestionRevisionId,
2658
2805
  contentDigest: ReviewSuggestionPublicationDigest,
2806
+ operation: Schema$1.optionalKey(ReviewSuggestionPublicationOperation),
2659
2807
  reservationId: ReviewSuggestionPublicationReservationId,
2660
2808
  publicationId: GovernedActionId,
2809
+ commentId: Schema$1.optionalKey(ReviewSuggestionPublicationCommentId),
2661
2810
  publishedAt: UtcTimestamp,
2662
2811
  finalize: Schema$1.optionalKey(Schema$1.Boolean)
2663
2812
  });
2813
+ /** Lookup for the latest durable publication target of one exact suggestion. */
2814
+ var ReadReviewSuggestionPublicationInput = Schema$1.Struct({
2815
+ workspaceId: WorkspaceId,
2816
+ jobId: JobId,
2817
+ suggestionId: PrReviewSuggestionId,
2818
+ revisionId: PrReviewSuggestionRevisionId
2819
+ });
2820
+ var ReadReviewSuggestionPublication = Schema$1.Struct({
2821
+ state: Schema$1.Literal("published"),
2822
+ publicationId: GovernedActionId,
2823
+ commentId: ReviewSuggestionPublicationCommentId
2824
+ });
2664
2825
  /** Workspace-scoped lookup for one durable review result. */
2665
2826
  var AgentReviewResultInput = Schema$1.Struct({
2666
2827
  workspaceId: WorkspaceId,
2667
2828
  jobId: JobId
2668
2829
  });
2830
+ /** Request one operator-authorized extension of a running review's budget. */
2831
+ var ExtendReviewBudgetInput = Schema$1.Struct({
2832
+ workspaceId: WorkspaceId,
2833
+ jobId: JobId,
2834
+ extendedAt: UtcTimestamp
2835
+ });
2669
2836
  /** Sanitized durable review result attributable to one terminal attempt. */
2670
2837
  var AgentReviewResultRecord = Schema$1.Struct({
2671
2838
  workspaceId: WorkspaceId,
@@ -2683,6 +2850,11 @@ var ReadReviewSuggestionRevisionsInput = Schema$1.Struct({
2683
2850
  limit: PrReviewSuggestionRevisionPageSize
2684
2851
  });
2685
2852
  /** Complete compare-and-append command for one immutable suggestion edit. */
2853
+ var ReviewSuggestionRevisionLeaseFence = Schema$1.Struct({
2854
+ jobId: JobId,
2855
+ attemptSequence: AgentAttemptSequence,
2856
+ leaseToken: AgentLeaseToken
2857
+ });
2686
2858
  var AppendReviewSuggestionRevisionInput = Schema$1.Struct({
2687
2859
  workspaceId: WorkspaceId,
2688
2860
  jobId: JobId,
@@ -2690,16 +2862,27 @@ var AppendReviewSuggestionRevisionInput = Schema$1.Struct({
2690
2862
  expectedRevisionId: PrReviewSuggestionRevisionId,
2691
2863
  expectedSequence: PrReviewSuggestionRevisionSequence,
2692
2864
  edit: PrReviewSuggestionEdit,
2693
- state: Schema$1.optionalKey(Schema$1.Literal("dismissed")),
2865
+ state: Schema$1.optionalKey(Schema$1.Literals(["dismissed", "stale"])),
2866
+ dismissalReason: Schema$1.optionalKey(PrReviewSuggestion.fields.dismissalReason),
2867
+ validation: Schema$1.optionalKey(Schema$1.Literal("validated")),
2694
2868
  author: PrReviewSuggestionRevisionAuthor,
2695
- createdAt: UtcTimestamp
2869
+ createdAt: UtcTimestamp,
2870
+ leaseFence: Schema$1.optionalKey(ReviewSuggestionRevisionLeaseFence)
2871
+ });
2872
+ /** Atomic targeted completion: append the source revision and terminalize the worker job together. */
2873
+ var CompleteTargetedReviewInput = Schema$1.Struct({
2874
+ source: AppendReviewSuggestionRevisionInput,
2875
+ target: CompleteAgentReviewInput
2696
2876
  });
2697
2877
  /** Exact immutable subject used to recover its newest durable review job. */
2698
2878
  var LatestAgentReviewInput = Schema$1.Struct({
2699
2879
  workspaceId: WorkspaceId,
2700
2880
  pluginConnectionId: PluginConnectionId,
2701
2881
  subject: PrReviewSubject,
2702
- jobId: Schema$1.optionalKey(JobId)
2882
+ excludeJobId: Schema$1.optionalKey(JobId),
2883
+ excludeSubjectRevision: Schema$1.optionalKey(Schema$1.String),
2884
+ jobId: Schema$1.optionalKey(JobId),
2885
+ allowDifferentHead: Schema$1.optionalKey(Schema$1.Boolean)
2703
2886
  });
2704
2887
  /** Cursor-bounded lookup for the durable thread behind a stable pull request. */
2705
2888
  var PrReviewThreadSubject = Schema$1.Struct({
@@ -2741,16 +2924,26 @@ var LatestAgentReviewRecord = Schema$1.Struct({
2741
2924
  threadId: AgentThreadId,
2742
2925
  providerId: AgentProviderId,
2743
2926
  model: AgentModel,
2744
- state: AgentJobState,
2927
+ state: Schema$1.Union([AgentJobState, Schema$1.Literal("interrupted")]),
2745
2928
  createdAt: UtcTimestamp,
2746
2929
  terminalAt: Schema$1.NullOr(UtcTimestamp),
2930
+ startedAt: Schema$1.optionalKey(Schema$1.NullOr(UtcTimestamp)),
2931
+ reviewBudgetMillis: Schema$1.optionalKey(Schema$1.Int.check(Schema$1.isBetween({
2932
+ minimum: 1,
2933
+ maximum: 36e5
2934
+ }))),
2935
+ reviewBudgetExtensionCount: Schema$1.optionalKey(Schema$1.Int.check(Schema$1.isBetween({
2936
+ minimum: 0,
2937
+ maximum: 1
2938
+ }))),
2939
+ taskIntent: Schema$1.optionalKey(Schema$1.NullOr(Schema$1.Literals(["suggestion-edit", "suggestion-revalidation"]))),
2747
2940
  report: Schema$1.NullOr(PrReviewReport),
2748
2941
  reviewProfile: ReviewAgentProfile,
2749
2942
  activity: Schema$1.Struct({
2750
2943
  events: Schema$1.Array(Schema$1.String.check(Schema$1.isNonEmpty(), Schema$1.isMaxLength(MAXIMUM_AGENT_ATTEMPT_OUTPUT_BYTES))).check(Schema$1.isMaxLength(128)),
2751
2944
  truncated: Schema$1.Boolean
2752
2945
  })
2753
- }).check(Schema$1.makeFilter(({ report, state }) => state === "succeeded" === (report !== null), { expected: "only succeeded review jobs to carry a report" }));
2946
+ }).check(Schema$1.makeFilter(({ report, state }) => report === null || state === "succeeded" || state === "failed" || state === "cancelled" || state === "interrupted", { expected: "only terminal review jobs to carry a report" }));
2754
2947
  /** One immutable event in a release thread. */
2755
2948
  var AgentThreadEvent = Schema$1.Struct({
2756
2949
  workspaceId: WorkspaceId,
@@ -2860,10 +3053,15 @@ var makeBlobPublisher = (fs, path, cryptoService) => {
2860
3053
  }).pipe(Effect.result);
2861
3054
  if (Result.isFailure(opened)) return openFailure(opened.failure);
2862
3055
  yield* Effect.addFinalizer(() => fs.remove(temporary, { force: true }).pipe(Effect.ignore));
3056
+ yield* directory.assertIdentity;
2863
3057
  yield* restore(opened.success.writeAll(bytes)).pipe(Effect.mapError((cause) => blobStoreIoError("write temporary blob", cause)));
2864
3058
  yield* restore(opened.success.sync).pipe(Effect.mapError((cause) => blobStoreIoError("sync temporary blob", cause)));
3059
+ yield* directory.assertIdentity;
2865
3060
  const linked = yield* (mode === "replace" ? fs.rename(temporary, destination) : fs.link(temporary, destination)).pipe(Effect.result);
2866
- if (Result.isSuccess(linked) && commit !== void 0) yield* commit(destination);
3061
+ if (Result.isSuccess(linked)) {
3062
+ yield* directory.assertIdentity;
3063
+ if (commit !== void 0) yield* commit(destination);
3064
+ }
2867
3065
  return linkResult(linked);
2868
3066
  })));
2869
3067
  if (outcome._tag === "LinkResult") return outcome.linked;
@@ -2875,11 +3073,15 @@ var makeBlobPublisher = (fs, path, cryptoService) => {
2875
3073
  //#endregion
2876
3074
  //#region src/server/persistence/object-store/PinnedDirectory.ts
2877
3075
  var descriptorAliases = (path, descriptor) => [path.join("/proc/self/fd", String(descriptor)), path.join("/dev/fd", String(descriptor))];
3076
+ var sameIdentity = (left, right) => left.dev === right.dev && Option.isSome(left.ino) && Option.isSome(right.ino) && left.ino.value === right.ino.value;
3077
+ var sameDescriptorAlias = (alias, opened) => alias.type === opened.type && Option.isSome(alias.ino) && Option.isSome(opened.ino) && alias.ino.value === opened.ino.value;
2878
3078
  /** Resolve a verified alias for the exact object already held by a descriptor. */
2879
- var resolveDescriptorAlias = Effect.fn("BlobStore.resolveDescriptorAlias")(function* (fs, path, descriptor, expectedPath, operation) {
3079
+ var resolveDescriptorAlias = Effect.fn("BlobStore.resolveDescriptorAlias")(function* (fs, path, descriptor, openedInfo, expectedPath, operation) {
2880
3080
  for (const alias of descriptorAliases(path, descriptor)) {
2881
- const resolved = yield* fs.realPath(alias).pipe(Effect.result);
2882
- if (Result.isSuccess(resolved) && resolved.success === expectedPath) return alias;
3081
+ const aliasInfo = yield* fs.stat(alias).pipe(Effect.result);
3082
+ const expectedInfo = yield* fs.stat(expectedPath).pipe(Effect.result);
3083
+ const canonicalExpected = yield* fs.realPath(expectedPath).pipe(Effect.result);
3084
+ if (Result.isSuccess(aliasInfo) && Result.isSuccess(expectedInfo) && Result.isSuccess(canonicalExpected) && canonicalExpected.success === expectedPath && sameDescriptorAlias(aliasInfo.success, openedInfo) && sameIdentity(openedInfo, expectedInfo.success)) return alias;
2883
3085
  }
2884
3086
  return yield* new BlobContainmentError({
2885
3087
  operation,
@@ -2892,11 +3094,21 @@ var resolveDescriptorAlias = Effect.fn("BlobStore.resolveDescriptorAlias")(funct
2892
3094
  */
2893
3095
  var pinDirectory = Effect.fn("BlobStore.pinDirectory")(function* (fs, path, directory) {
2894
3096
  const handle = yield* fs.open(directory, { flag: "r" }).pipe(Effect.mapError((cause) => blobStoreIoError("pin object directory", cause)));
2895
- const alias = yield* resolveDescriptorAlias(fs, path, handle.fd, directory, "publish blob");
2896
- const assertIdentity = fs.realPath(alias).pipe(Effect.result, Effect.flatMap((current) => Result.isSuccess(current) && current.success === directory ? Effect.void : new BlobContainmentError({
3097
+ const openedInfo = yield* handle.stat.pipe(Effect.mapError((cause) => blobStoreIoError("inspect pinned object directory", cause)));
3098
+ const alias = yield* resolveDescriptorAlias(fs, path, handle.fd, openedInfo, directory, "publish blob");
3099
+ const traversedAlias = yield* fs.stat(`${alias}${path.sep}.`).pipe(Effect.result);
3100
+ if (Result.isFailure(traversedAlias) || !sameIdentity(openedInfo, traversedAlias.success)) return yield* new BlobContainmentError({
2897
3101
  operation: "publish blob",
2898
- message: "pinned object directory identity changed"
2899
- })));
3102
+ message: "platform cannot address children through the pinned directory descriptor"
3103
+ });
3104
+ const assertIdentity = Effect.gen(function* () {
3105
+ const current = yield* handle.stat.pipe(Effect.result);
3106
+ const pathInfo = yield* fs.stat(directory).pipe(Effect.result);
3107
+ if (Result.isFailure(current) || Result.isFailure(pathInfo) || !sameIdentity(openedInfo, current.success) || !sameIdentity(openedInfo, pathInfo.success)) return yield* new BlobContainmentError({
3108
+ operation: "publish blob",
3109
+ message: "pinned object directory identity changed"
3110
+ });
3111
+ });
2900
3112
  return {
2901
3113
  path: alias,
2902
3114
  sync: handle.sync.pipe(Effect.mapError((cause) => blobStoreIoError("sync pinned object directory", cause))),
@@ -2926,8 +3138,8 @@ var makeOpenedBlobReader = (fs, path) => {
2926
3138
  return yield* blobStoreIoError(operation, opened.failure);
2927
3139
  }
2928
3140
  const file = opened.success;
2929
- yield* resolveDescriptorAlias(fs, path, file.fd, reference.filePath, operation);
2930
3141
  const openedInfo = yield* file.stat.pipe(Effect.mapError((cause) => blobStoreIoError(operation, cause)));
3142
+ yield* resolveDescriptorAlias(fs, path, file.fd, openedInfo, reference.filePath, operation);
2931
3143
  if (openedInfo.type !== "File" || (openedInfo.mode & 63) !== 0) return yield* new BlobContainmentError({
2932
3144
  operation,
2933
3145
  message: "opened blob is not a supported regular file"
@@ -3602,6 +3814,58 @@ var ContentStore = class ContentStore extends Context.Service()("@knpkv/control-
3602
3814
  static layer = Layer.effect(ContentStore, makeContentStore);
3603
3815
  };
3604
3816
  //#endregion
3817
+ //#region src/domain/prReviewReconciliation.ts
3818
+ /** Pure cross-head reconciliation for immutable PR-review suggestions. @module */
3819
+ /** Validate a report's explicit host transition set against the two immutable heads. */
3820
+ var validatePrReviewReportTransitions = (previous, current, declared) => {
3821
+ const expected = reconcilePrReviewReports(previous, current);
3822
+ const expectedById = new Map(expected.map((transition) => [transition.suggestionId, transition]));
3823
+ const declaredById = /* @__PURE__ */ new Map();
3824
+ for (const transition of declared) {
3825
+ if (!expectedById.has(transition.suggestionId)) return {
3826
+ _tag: "failure",
3827
+ failure: {
3828
+ _tag: "unknown-id",
3829
+ suggestionId: transition.suggestionId
3830
+ }
3831
+ };
3832
+ if (declaredById.has(transition.suggestionId)) return {
3833
+ _tag: "failure",
3834
+ failure: {
3835
+ _tag: "duplicate-id",
3836
+ suggestionId: transition.suggestionId
3837
+ }
3838
+ };
3839
+ declaredById.set(transition.suggestionId, transition);
3840
+ }
3841
+ for (const [suggestionId, expectedTransition] of expectedById) {
3842
+ const actual = declaredById.get(suggestionId);
3843
+ if (actual === void 0) return {
3844
+ _tag: "failure",
3845
+ failure: {
3846
+ _tag: "missing-transition",
3847
+ suggestionId
3848
+ }
3849
+ };
3850
+ if (actual.transition !== expectedTransition.transition || actual.previousState !== expectedTransition.previousState || actual.currentState !== expectedTransition.currentState || actual.previousDismissalReason !== expectedTransition.previousDismissalReason || actual.previousHead !== expectedTransition.previousHead || actual.currentHead !== expectedTransition.currentHead) return {
3851
+ _tag: "failure",
3852
+ failure: {
3853
+ _tag: "contradictory-transition",
3854
+ suggestionId,
3855
+ expected: expectedTransition.transition,
3856
+ actual: actual.transition
3857
+ }
3858
+ };
3859
+ }
3860
+ return {
3861
+ _tag: "success",
3862
+ transitions: expected.map(({ suggestionId, transition: kind }) => ({
3863
+ suggestionId,
3864
+ kind
3865
+ }))
3866
+ };
3867
+ };
3868
+ //#endregion
3605
3869
  //#region src/server/persistence/repositories/internal/reviewSuggestionRevisions.ts
3606
3870
  var REVISION_ID_NAMESPACE = "review-suggestion-revision/v1";
3607
3871
  var PersistedDigest$1 = Schema$1.String.check(Schema$1.isPattern(/^sha256:[0-9a-f]{64}$/u, { expected: "a lowercase SHA-256 digest" }));
@@ -3775,68 +4039,91 @@ var makeReviewSuggestionRevisionOperations = (dependencies) => {
3775
4039
  nextBeforeSequence: hasMore ? revisions.at(-1)?.sequence ?? null : null
3776
4040
  }).pipe(Effect$1.mapError(() => operationFailure("agent-job.review-revision-page-invalid")));
3777
4041
  });
3778
- return {
3779
- append: Effect$1.fn("ReviewSuggestionRevisions.append")(function* (input) {
3780
- const request = yield* Schema$1.decodeUnknownEffect(Schema$1.toType(AppendReviewSuggestionRevisionInput))(input);
3781
- return yield* database.transaction(Effect$1.gen(function* () {
3782
- const current = yield* currentRevision(request.workspaceId, request.jobId, request.suggestionId);
3783
- if ((yield* deriveRevisionId(request.jobId, request.suggestionId, request.expectedSequence)) !== request.expectedRevisionId) return yield* new AgentJobInputError({
3784
- workspaceId: request.workspaceId,
3785
- jobId: request.jobId,
3786
- reason: "revision-identity-mismatch"
3787
- });
3788
- if (current.revisionId !== request.expectedRevisionId || current.sequence !== request.expectedSequence) return yield* new RevisionConflictError({
4042
+ const appendInTransaction = Effect$1.fn("ReviewSuggestionRevisions.appendInTransaction")(function* (input) {
4043
+ const request = yield* Schema$1.decodeUnknownEffect(Schema$1.toType(AppendReviewSuggestionRevisionInput))(input);
4044
+ return yield* Effect$1.gen(function* () {
4045
+ if (request.leaseFence !== void 0) {
4046
+ if ((yield* sql`SELECT 1
4047
+ FROM agent_jobs job
4048
+ JOIN agent_job_leases lease
4049
+ ON lease.workspace_id = job.workspace_id
4050
+ AND lease.job_id = job.job_id
4051
+ AND lease.attempt_sequence = ${request.leaseFence.attemptSequence}
4052
+ AND lease.lease_token = ${request.leaseFence.leaseToken}
4053
+ WHERE job.workspace_id = ${request.workspaceId}
4054
+ AND job.job_id = ${request.leaseFence.jobId}
4055
+ AND job.state = 'running'
4056
+ AND job.cancel_requested_at IS NULL
4057
+ AND lease.lease_expires_at > ${Schema$1.encodeSync(PrReviewSuggestionRevision.fields.createdAt)(request.createdAt)}
4058
+ LIMIT 1`).length !== 1) return yield* new AgentJobInputError({
3789
4059
  workspaceId: request.workspaceId,
3790
- recordKind: "agent-review-suggestion-revision",
3791
- recordKey: revisionRecordKey(request.jobId, request.suggestionId),
3792
- expectedRevision: request.expectedSequence,
3793
- actualRevision: current.sequence
4060
+ jobId: request.leaseFence.jobId,
4061
+ reason: "cancellation-requested"
3794
4062
  });
3795
- const currentEdit = yield* Schema$1.decodeUnknownEffect(Schema$1.toType(PrReviewSuggestionEdit))(current.suggestion).pipe(Effect$1.mapError(() => recordFailure(request.workspaceId, request.jobId, request.suggestionId, "agent-review-current-edit-invalid")));
3796
- if ((yield* Schema$1.encodeUnknownEffect(Schema$1.fromJsonString(PrReviewSuggestionEdit))(currentEdit).pipe(Effect$1.mapError(() => operationFailure("agent-job.encode-current-review-edit")))) === (yield* Schema$1.encodeUnknownEffect(Schema$1.fromJsonString(PrReviewSuggestionEdit))(request.edit).pipe(Effect$1.mapError(() => operationFailure("agent-job.encode-requested-review-edit")))) && request.state === void 0) return current;
3797
- if ((yield* sql`SELECT 1
4063
+ }
4064
+ const current = yield* currentRevision(request.workspaceId, request.jobId, request.suggestionId);
4065
+ if ((yield* deriveRevisionId(request.jobId, request.suggestionId, request.expectedSequence)) !== request.expectedRevisionId) return yield* new AgentJobInputError({
4066
+ workspaceId: request.workspaceId,
4067
+ jobId: request.jobId,
4068
+ reason: "revision-identity-mismatch"
4069
+ });
4070
+ if (current.revisionId !== request.expectedRevisionId || current.sequence !== request.expectedSequence) return yield* new RevisionConflictError({
4071
+ workspaceId: request.workspaceId,
4072
+ recordKind: "agent-review-suggestion-revision",
4073
+ recordKey: revisionRecordKey(request.jobId, request.suggestionId),
4074
+ expectedRevision: request.expectedSequence,
4075
+ actualRevision: current.sequence
4076
+ });
4077
+ const currentEdit = yield* Schema$1.decodeUnknownEffect(Schema$1.toType(PrReviewSuggestionEdit))(current.suggestion).pipe(Effect$1.mapError(() => recordFailure(request.workspaceId, request.jobId, request.suggestionId, "agent-review-current-edit-invalid")));
4078
+ if ((yield* Schema$1.encodeUnknownEffect(Schema$1.fromJsonString(PrReviewSuggestionEdit))(currentEdit).pipe(Effect$1.mapError(() => operationFailure("agent-job.encode-current-review-edit")))) === (yield* Schema$1.encodeUnknownEffect(Schema$1.fromJsonString(PrReviewSuggestionEdit))(request.edit).pipe(Effect$1.mapError(() => operationFailure("agent-job.encode-requested-review-edit")))) && request.state === void 0 && request.validation === void 0) return current;
4079
+ if ((yield* sql`SELECT 1
3798
4080
  FROM agent_review_suggestion_publications
3799
4081
  WHERE workspace_id = ${request.workspaceId}
3800
4082
  AND job_id = ${request.jobId}
3801
4083
  AND suggestion_id = ${request.suggestionId}
3802
4084
  LIMIT 1`).length > 0) return yield* new AgentJobInputError({
3803
- workspaceId: request.workspaceId,
3804
- jobId: request.jobId,
3805
- reason: "invalid-transition"
3806
- });
3807
- if (current.suggestion.state !== "draft" || request.edit.replacement !== void 0 && request.edit.replacement.reviewedHead !== current.subject.headRevision || DateTime$1.Order(request.createdAt, current.createdAt) < 0) return yield* new AgentJobInputError({
3808
- workspaceId: request.workspaceId,
3809
- jobId: request.jobId,
3810
- reason: "invalid-transition"
3811
- });
3812
- const sequence = PrReviewSuggestionRevisionSequence.make(current.sequence + 1);
3813
- const revisionId = yield* deriveRevisionId(request.jobId, request.suggestionId, sequence);
3814
- const validation = hasSamePrReviewTechnicalClaim(currentEdit, request.edit) ? current.validation : PrReviewSuggestionRequiresRevalidation.make({
3815
- reviewedHead: current.subject.headRevision,
3816
- sourceRevisionId: current.revisionId,
3817
- reason: request.author._tag === "agent" ? "agent-edit-not-validated" : "technical-claim-edited"
3818
- });
3819
- const suggestion = yield* Schema$1.decodeUnknownEffect(Schema$1.toType(PrReviewSuggestion))({
3820
- suggestionId: request.suggestionId,
3821
- state: request.state ?? current.suggestion.state,
3822
- ...request.edit
3823
- }).pipe(Effect$1.mapError(() => operationFailure("agent-job.review-revision-suggestion-invalid")));
3824
- const revision = yield* Effect$1.try({
3825
- try: () => PrReviewSuggestionRevision.make({
3826
- revisionId,
3827
- sequence,
3828
- predecessorRevisionId: current.revisionId,
3829
- sourceJobId: request.jobId,
3830
- subject: current.subject,
3831
- suggestion,
3832
- validation,
3833
- author: request.author,
3834
- createdAt: request.createdAt
3835
- }),
3836
- catch: () => operationFailure("agent-job.review-revision-invalid")
3837
- });
3838
- const encoded = yield* encodeRevision(request.workspaceId, revision);
3839
- yield* sql`INSERT INTO agent_review_suggestion_revisions (
4085
+ workspaceId: request.workspaceId,
4086
+ jobId: request.jobId,
4087
+ reason: "invalid-transition"
4088
+ });
4089
+ if (current.suggestion.state !== "draft" && !(request.state === "stale" && current.suggestion.state === "published") || request.state === "dismissed" && request.dismissalReason === void 0 || request.state !== "dismissed" && request.dismissalReason !== void 0 || request.edit.replacement !== void 0 && request.edit.replacement.reviewedHead !== current.subject.headRevision || DateTime$1.Order(request.createdAt, current.createdAt) < 0) return yield* new AgentJobInputError({
4090
+ workspaceId: request.workspaceId,
4091
+ jobId: request.jobId,
4092
+ reason: "invalid-transition"
4093
+ });
4094
+ const sequence = PrReviewSuggestionRevisionSequence.make(current.sequence + 1);
4095
+ const revisionId = yield* deriveRevisionId(request.jobId, request.suggestionId, sequence);
4096
+ const validation = request.validation === "validated" && request.author._tag === "agent" ? PrReviewSuggestionValidated.make({
4097
+ reviewedHead: current.subject.headRevision,
4098
+ validatingJobId: request.author.jobId,
4099
+ sourceRevisionId: current.revisionId
4100
+ }) : hasSamePrReviewTechnicalClaim(currentEdit, request.edit) ? current.validation : PrReviewSuggestionRequiresRevalidation.make({
4101
+ reviewedHead: current.subject.headRevision,
4102
+ sourceRevisionId: current.revisionId,
4103
+ reason: request.author._tag === "agent" ? "agent-edit-not-validated" : "technical-claim-edited"
4104
+ });
4105
+ const suggestion = yield* Schema$1.decodeUnknownEffect(Schema$1.toType(PrReviewSuggestion))({
4106
+ suggestionId: request.suggestionId,
4107
+ state: request.state ?? current.suggestion.state,
4108
+ ...request.dismissalReason === void 0 ? {} : { dismissalReason: request.dismissalReason },
4109
+ ...request.edit
4110
+ }).pipe(Effect$1.mapError(() => operationFailure("agent-job.review-revision-suggestion-invalid")));
4111
+ const revision = yield* Effect$1.try({
4112
+ try: () => PrReviewSuggestionRevision.make({
4113
+ revisionId,
4114
+ sequence,
4115
+ predecessorRevisionId: current.revisionId,
4116
+ sourceJobId: request.jobId,
4117
+ subject: current.subject,
4118
+ suggestion,
4119
+ validation,
4120
+ author: request.author,
4121
+ createdAt: request.createdAt
4122
+ }),
4123
+ catch: () => operationFailure("agent-job.review-revision-invalid")
4124
+ });
4125
+ const encoded = yield* encodeRevision(request.workspaceId, revision);
4126
+ yield* sql`INSERT INTO agent_review_suggestion_revisions (
3840
4127
  workspace_id, source_job_id, suggestion_id, revision_sequence,
3841
4128
  revision_id, predecessor_revision_id, revision_json,
3842
4129
  revision_digest, created_at
@@ -3846,27 +4133,32 @@ var makeReviewSuggestionRevisionOperations = (dependencies) => {
3846
4133
  ${encoded.json}, ${encoded.digest},
3847
4134
  ${Schema$1.encodeSync(PrReviewSuggestionRevision.fields.createdAt)(request.createdAt)}
3848
4135
  )`;
3849
- const job = yield* getJob(request.workspaceId, request.jobId);
3850
- yield* appendThreadEvent({
3851
- workspaceId: request.workspaceId,
3852
- threadId: job.threadId,
3853
- jobId: request.jobId,
3854
- attemptSequence: null,
3855
- eventKind: "review-suggestion-revised",
3856
- payload: {
3857
- suggestionId: request.suggestionId,
3858
- revisionId,
3859
- sequence,
3860
- authorKind: request.author._tag,
3861
- validationState: validation._tag,
3862
- suggestionState: suggestion.state
3863
- },
3864
- payloadSchema: ReviewSuggestionRevisedPayload,
3865
- occurredAt: request.createdAt
3866
- });
3867
- return revision;
3868
- }));
4136
+ const job = yield* getJob(request.workspaceId, request.jobId);
4137
+ yield* appendThreadEvent({
4138
+ workspaceId: request.workspaceId,
4139
+ threadId: job.threadId,
4140
+ jobId: request.jobId,
4141
+ attemptSequence: null,
4142
+ eventKind: "review-suggestion-revised",
4143
+ payload: {
4144
+ suggestionId: request.suggestionId,
4145
+ revisionId,
4146
+ sequence,
4147
+ authorKind: request.author._tag,
4148
+ validationState: validation._tag,
4149
+ suggestionState: suggestion.state
4150
+ },
4151
+ payloadSchema: ReviewSuggestionRevisedPayload,
4152
+ occurredAt: request.createdAt
4153
+ });
4154
+ return revision;
4155
+ });
4156
+ });
4157
+ return {
4158
+ append: Effect$1.fn("ReviewSuggestionRevisions.append")(function* (input) {
4159
+ return yield* database.transaction(appendInTransaction(input));
3869
4160
  }),
4161
+ appendInTransaction,
3870
4162
  read
3871
4163
  };
3872
4164
  };
@@ -3904,10 +4196,16 @@ var PersistedJobQueuedPayload = Schema$1.Struct({
3904
4196
  model: EnqueueAgentJobInput.fields.model,
3905
4197
  providerId: EnqueueAgentJobInput.fields.providerId,
3906
4198
  subjectRevision: EnqueueAgentJobInput.fields.subjectRevision,
3907
- task: AgentJobTask
4199
+ task: AgentJobTask,
4200
+ reviewBudgetMillis: Schema$1.optionalKey(Schema$1.Int.check(Schema$1.isBetween({
4201
+ minimum: 1,
4202
+ maximum: 36e5
4203
+ }))),
4204
+ reviewBudgetExtensionCount: Schema$1.optionalKey(Schema$1.Literal(1))
3908
4205
  });
3909
4206
  var CancellationRequestedPayload = Schema$1.Struct({ requestedAt: UtcTimestamp });
3910
4207
  var ProviderFailurePayload = Schema$1.Struct({ error: AgentProviderError });
4208
+ var PROCESS_RESTART_INTERRUPTION_MESSAGE = "Review interrupted because the Control Center process restarted.";
3911
4209
  var ReviewSuggestionPublishedPayload = Schema$1.Struct({
3912
4210
  suggestionId: RecordReviewSuggestionPublicationInput.fields.suggestionId,
3913
4211
  revisionId: RecordReviewSuggestionPublicationInput.fields.revisionId,
@@ -3918,6 +4216,10 @@ var ReviewSuggestionPublicationRow = Schema$1.Struct({
3918
4216
  contentDigest: ReviewSuggestionPublicationDigest,
3919
4217
  state: Schema$1.Literals(["reserved", "published"]),
3920
4218
  publicationId: Schema$1.NullOr(GovernedActionId),
4219
+ commentId: Schema$1.NullOr(ReviewSuggestionPublicationCommentId),
4220
+ previousContentDigest: Schema$1.NullOr(ReviewSuggestionPublicationDigest),
4221
+ previousPublicationId: Schema$1.NullOr(GovernedActionId),
4222
+ previousPublishedAt: Schema$1.NullOr(UtcTimestamp),
3921
4223
  reservationAcquiredAt: UtcTimestamp,
3922
4224
  reservationId: ReviewSuggestionPublicationReservationId,
3923
4225
  reservedAt: UtcTimestamp,
@@ -4069,6 +4371,11 @@ var makeAgentJobRepository = Effect$1.gen(function* () {
4069
4371
  json
4070
4372
  };
4071
4373
  });
4374
+ const sanitizeAgentReviewReport = (report) => (() => {
4375
+ const { transitions: _agentOwnedTransitions, ...agentOwnedReport } = report;
4376
+ return PrReviewReport.make(agentOwnedReport);
4377
+ })();
4378
+ const isAgentOwnedSuggestionState = (state) => state === "draft" || state === "resolved";
4072
4379
  const decodeTaskContext = Effect$1.fn("AgentJobRepository.decodeTaskContext")(function* (workspaceId, jobId, taskContextJson, taskContextDigest) {
4073
4380
  const bytes = yield* bytesFromText(taskContextJson);
4074
4381
  if ((yield* digestBytes(bytes)) !== taskContextDigest) return yield* persistedRecordError(workspaceId, "agent-job", jobId, "agent-job-task-context-integrity-invalid");
@@ -4255,6 +4562,49 @@ var makeAgentJobRepository = Effect$1.gen(function* () {
4255
4562
  case "job-completed": return yield* decodeRuntimePayload(workspaceId, row, payload);
4256
4563
  }
4257
4564
  });
4565
+ const reviewBudgetState = Effect$1.fn("AgentJobRepository.reviewBudgetState")(function* (workspaceId, jobId, task) {
4566
+ if (task._tag !== "pr-review") return {
4567
+ reviewBudgetMillis: void 0,
4568
+ reviewBudgetExtensionCount: 0
4569
+ };
4570
+ const rows = yield* sql`SELECT
4571
+ workspace_id AS workspaceId, thread_id AS threadId,
4572
+ event_sequence AS eventSequence, job_id AS jobId,
4573
+ attempt_sequence AS attemptSequence, event_kind AS eventKind,
4574
+ payload_json AS payloadJson, payload_digest AS payloadDigest,
4575
+ payload_byte_length AS payloadByteLength, occurred_at AS occurredAt
4576
+ FROM agent_thread_events
4577
+ WHERE workspace_id = ${workspaceId}
4578
+ AND job_id = ${jobId}
4579
+ AND event_kind = 'job-queued'
4580
+ ORDER BY event_sequence`.pipe(mapPersistenceOperation("agent-job.review-budget"));
4581
+ let reviewBudgetMillis = task.reviewProfile.budgetMillis;
4582
+ let reviewBudgetExtensionCount = 0;
4583
+ for (const unknownRow of rows) {
4584
+ const row = Schema$1.decodeUnknownResult(ThreadEventRow)(unknownRow);
4585
+ if (Result$1.isFailure(row)) return yield* persistedRecordError(workspaceId, "agent-review-budget", jobId, "agent-review-budget-event-schema-invalid");
4586
+ const bytes = yield* bytesFromText(row.success.payloadJson);
4587
+ const actualDigest = yield* digestBytes(bytes);
4588
+ if (bytes.length !== row.success.payloadByteLength || actualDigest !== row.success.payloadDigest) return yield* persistedRecordError(workspaceId, "agent-review-budget", jobId, "agent-review-budget-event-integrity-invalid");
4589
+ const parsed = Schema$1.decodeUnknownResult(Schema$1.UnknownFromJsonString)(row.success.payloadJson);
4590
+ if (Result$1.isFailure(parsed)) return yield* persistedRecordError(workspaceId, "agent-review-budget", jobId, "agent-review-budget-event-json-invalid");
4591
+ const decoded = Schema$1.decodeUnknownResult(PersistedJobQueuedPayload)(parsed.success);
4592
+ if (Result$1.isFailure(decoded)) {
4593
+ const legacy = Schema$1.decodeUnknownResult(JobQueuedPayload)(parsed.success);
4594
+ if (Result$1.isFailure(legacy)) return yield* persistedRecordError(workspaceId, "agent-review-budget", jobId, "agent-review-budget-event-invalid");
4595
+ continue;
4596
+ }
4597
+ if (decoded.success.task._tag !== "pr-review") continue;
4598
+ if (decoded.success.reviewBudgetMillis !== void 0) {
4599
+ reviewBudgetMillis = decoded.success.reviewBudgetMillis;
4600
+ reviewBudgetExtensionCount = decoded.success.reviewBudgetExtensionCount ?? 1;
4601
+ }
4602
+ }
4603
+ return {
4604
+ reviewBudgetMillis,
4605
+ reviewBudgetExtensionCount
4606
+ };
4607
+ });
4258
4608
  const reviewContextSnapshot = Effect$1.fn("AgentJobRepository.reviewContextSnapshot")(function* (workspaceId, threadId) {
4259
4609
  const rendered = renderAgentReviewContextEventsQuery({
4260
4610
  workspaceId,
@@ -4320,12 +4670,14 @@ var makeAgentJobRepository = Effect$1.gen(function* () {
4320
4670
  });
4321
4671
  break;
4322
4672
  }
4323
- case "job-failed":
4673
+ case "job-failed": {
4674
+ const failure = yield* Schema$1.decodeUnknownEffect(ProviderFailurePayload)(payload);
4324
4675
  runs.set(row.jobId, {
4325
4676
  ...current,
4326
- state: "failed"
4677
+ state: failure.error.message === "Review interrupted because the Control Center process restarted." ? "interrupted" : "failed"
4327
4678
  });
4328
4679
  break;
4680
+ }
4329
4681
  case "cancel-requested":
4330
4682
  if (row.jobState === "cancelled") runs.set(row.jobId, {
4331
4683
  ...current,
@@ -4416,14 +4768,16 @@ var makeAgentJobRepository = Effect$1.gen(function* () {
4416
4768
  FROM agent_thread_events
4417
4769
  WHERE workspace_id = ${request.workspaceId}
4418
4770
  AND job_id = ${request.jobId}
4419
- AND event_kind = 'review-report'`.pipe(mapPersistenceOperation("agent-job.review-result"));
4771
+ AND event_kind = 'review-report'
4772
+ ORDER BY event_sequence DESC
4773
+ LIMIT 1`.pipe(mapPersistenceOperation("agent-job.review-result"));
4420
4774
  if (rows.length === 0) return yield* new RecordNotFoundError({
4421
4775
  workspaceId: request.workspaceId,
4422
4776
  recordKind: "agent-review-result",
4423
4777
  recordKey: request.jobId
4424
4778
  });
4425
4779
  const row = Schema$1.decodeUnknownResult(ThreadEventRow)(rows[0]);
4426
- if (rows.length !== 1 || Result$1.isFailure(row) || row.success.attemptSequence === null) return yield* persistedRecordError(request.workspaceId, "agent-review-result", request.jobId, "agent-review-result-schema-invalid");
4780
+ if (Result$1.isFailure(row) || row.success.attemptSequence === null) return yield* persistedRecordError(request.workspaceId, "agent-review-result", request.jobId, "agent-review-result-schema-invalid");
4427
4781
  const report = yield* decodeEventPayload(request.workspaceId, row.success);
4428
4782
  const decodedReport = Schema$1.decodeUnknownResult(PrReviewReport)(report);
4429
4783
  if (Result$1.isFailure(decodedReport)) return yield* persistedRecordError(request.workspaceId, "agent-review-result", request.jobId, "agent-review-result-payload-invalid");
@@ -4508,14 +4862,16 @@ var makeAgentJobRepository = Effect$1.gen(function* () {
4508
4862
  FROM agent_thread_events
4509
4863
  WHERE workspace_id = ${request.workspaceId}
4510
4864
  AND job_id = ${request.jobId}
4511
- AND event_kind = 'review-report'`.pipe(mapPersistenceOperation("agent-job.original-review-result"));
4865
+ AND event_kind = 'review-report'
4866
+ ORDER BY event_sequence ASC
4867
+ LIMIT 1`.pipe(mapPersistenceOperation("agent-job.original-review-result"));
4512
4868
  if (rows.length === 0) return yield* new RecordNotFoundError({
4513
4869
  workspaceId: request.workspaceId,
4514
4870
  recordKind: "agent-review-result",
4515
4871
  recordKey: request.jobId
4516
4872
  });
4517
4873
  const row = Schema$1.decodeUnknownResult(ThreadEventRow)(rows[0]);
4518
- if (rows.length !== 1 || Result$1.isFailure(row) || row.success.attemptSequence === null) return yield* persistedRecordError(request.workspaceId, "agent-review-result", request.jobId, "agent-review-original-result-schema-invalid");
4874
+ if (Result$1.isFailure(row) || row.success.attemptSequence === null) return yield* persistedRecordError(request.workspaceId, "agent-review-result", request.jobId, "agent-review-original-result-schema-invalid");
4519
4875
  const report = Schema$1.decodeUnknownResult(PrReviewReport)(yield* decodeEventPayload(request.workspaceId, row.success));
4520
4876
  if (Result$1.isFailure(report)) return yield* persistedRecordError(request.workspaceId, "agent-review-result", request.jobId, "agent-review-original-result-payload-invalid");
4521
4877
  return yield* Schema$1.decodeUnknownEffect(Schema$1.toType(AgentReviewResultRecord))({
@@ -4526,6 +4882,34 @@ var makeAgentJobRepository = Effect$1.gen(function* () {
4526
4882
  completedAt: row.success.occurredAt
4527
4883
  });
4528
4884
  });
4885
+ const findPreviousReviewReport = Effect$1.fn("AgentJobRepository.findPreviousReviewReport")(function* (input) {
4886
+ const subjectJson = yield* Schema$1.encodeUnknownEffect(Schema$1.fromJsonString(PrReviewSubject))(input.subject).pipe(Effect$1.mapError(() => new PersistenceOperationError({ operation: "agent-job.previous-review-subject" })));
4887
+ const taskContextPrefix = `{"_tag":"pr-review","pluginConnectionId":"${input.pluginConnectionId}","subject":${subjectJson},"reviewProfile":`;
4888
+ const identityPrefix = taskContextPrefix.slice(0, taskContextPrefix.indexOf("\"baseRevision\""));
4889
+ const rendered = renderLatestAgentReviewQuery({
4890
+ workspaceId: input.workspaceId,
4891
+ taskContextPrefix: identityPrefix,
4892
+ excludeTargeted: true,
4893
+ excludeJobId: input.excludeJobId,
4894
+ excludeSubjectRevision: input.subject.headRevision,
4895
+ limit: 32
4896
+ });
4897
+ const rows = yield* sql.unsafe(rendered.sql, [...rendered.params]).pipe(mapPersistenceOperation("agent-job.previous-review"));
4898
+ for (const rawRow of rows) {
4899
+ const row = Schema$1.decodeUnknownResult(LatestReviewRow)(rawRow);
4900
+ if (Result$1.isFailure(row)) return yield* persistedRecordError(input.workspaceId, "agent-review", input.subject.pullRequestId, "agent-review-previous-schema-invalid");
4901
+ if (row.success.state !== "succeeded" && row.success.state !== "failed" && row.success.state !== "cancelled") continue;
4902
+ const result = yield* readReviewResult({
4903
+ workspaceId: input.workspaceId,
4904
+ jobId: row.success.jobId
4905
+ }).pipe(Effect$1.catchTag("RecordNotFoundError", () => Effect$1.succeed(null)));
4906
+ if (result !== null && result.report !== null) return Option$1.some({
4907
+ jobId: row.success.jobId,
4908
+ report: result.report
4909
+ });
4910
+ }
4911
+ return Option$1.none();
4912
+ });
4529
4913
  const decodeThreadEventRows = Effect$1.fn("AgentJobRepository.decodeThreadEventRows")(function* (workspaceId, threadId, rows) {
4530
4914
  const decodedRows = yield* Schema$1.decodeUnknownEffect(Schema$1.Array(ReplayThreadEventRow))(rows).pipe(Effect$1.mapError(() => persistedRecordError(workspaceId, "agent-thread", threadId, "agent-thread-event-schema-invalid")));
4531
4915
  const tasksByJob = /* @__PURE__ */ new Map();
@@ -4619,10 +5003,94 @@ var makeAgentJobRepository = Effect$1.gen(function* () {
4619
5003
  });
4620
5004
  return current;
4621
5005
  });
5006
+ const currentPublishedReviewSuggestion = Effect$1.fn("AgentJobRepository.currentPublishedReviewSuggestion")(function* (input) {
5007
+ const current = (yield* reviewSuggestionRevisions.read({
5008
+ workspaceId: input.workspaceId,
5009
+ jobId: input.jobId,
5010
+ suggestionId: input.suggestionId,
5011
+ beforeSequence: null,
5012
+ limit: PrReviewSuggestionRevisionPageSize.make(1)
5013
+ })).current;
5014
+ if (current.revisionId !== input.revisionId || current.suggestion.state !== "published" || current.validation._tag !== "validated") return yield* new AgentJobInputError({
5015
+ workspaceId: input.workspaceId,
5016
+ jobId: input.jobId,
5017
+ reason: "invalid-transition"
5018
+ });
5019
+ return current;
5020
+ });
4622
5021
  return {
4623
5022
  appendReviewSuggestionRevision: Effect$1.fn("AgentJobRepository.appendReviewSuggestionRevision")(function* (input) {
4624
5023
  return yield* reviewSuggestionRevisions.append(input).pipe(mapPersistenceOperation("agent-job.append-review-suggestion-revision"));
4625
5024
  }),
5025
+ completeTargetedReview: Effect$1.fn("AgentJobRepository.completeTargetedReview")(function* (input) {
5026
+ const request = yield* Schema$1.decodeUnknownEffect(Schema$1.toType(CompleteTargetedReviewInput))(input);
5027
+ const report = yield* Schema$1.decodeUnknownEffect(Schema$1.toType(PrReviewReport))(request.target.report).pipe(Effect$1.mapError(() => new AgentJobInputError({
5028
+ workspaceId: request.target.workspaceId,
5029
+ jobId: request.target.jobId,
5030
+ reason: "invalid-result"
5031
+ })));
5032
+ const encodedReport = yield* encodeReviewReport(report).pipe(Effect$1.mapError(() => new AgentJobInputError({
5033
+ workspaceId: request.target.workspaceId,
5034
+ jobId: request.target.jobId,
5035
+ reason: "invalid-result"
5036
+ })));
5037
+ return yield* database.transaction(Effect$1.gen(function* () {
5038
+ const job = yield* getJob(request.target.workspaceId, request.target.jobId);
5039
+ if (job.state === "cancel-requested") return yield* new AgentJobInputError({
5040
+ workspaceId: request.target.workspaceId,
5041
+ jobId: request.target.jobId,
5042
+ reason: "cancellation-requested"
5043
+ });
5044
+ if (job.state !== "running" || job.task._tag !== "pr-review" || job.subjectRevision !== job.task.subject.headRevision || !PrReviewSubjectEquivalence(job.task.subject, report.subject)) return yield* new AgentJobInputError({
5045
+ workspaceId: request.target.workspaceId,
5046
+ jobId: request.target.jobId,
5047
+ reason: "task-mismatch"
5048
+ });
5049
+ yield* validateLease({
5050
+ workspaceId: request.target.workspaceId,
5051
+ jobId: request.target.jobId,
5052
+ attemptSequence: request.target.attemptSequence,
5053
+ leaseToken: request.target.leaseToken,
5054
+ observedAt: request.target.completedAt
5055
+ });
5056
+ const revision = yield* reviewSuggestionRevisions.appendInTransaction(request.source);
5057
+ const eventSequence = yield* reserveEventSequence(request.target.workspaceId, job.threadId);
5058
+ yield* sql`INSERT INTO agent_thread_events (
5059
+ workspace_id, thread_id, event_sequence, job_id, attempt_sequence,
5060
+ event_kind, payload_json, payload_digest, payload_byte_length, occurred_at
5061
+ ) VALUES (
5062
+ ${request.target.workspaceId}, ${job.threadId}, ${eventSequence},
5063
+ ${request.target.jobId}, ${request.target.attemptSequence}, 'review-report',
5064
+ ${encodedReport.json}, ${encodedReport.digest}, ${encodedReport.bytes.length},
5065
+ ${encodeTimestamp$11(request.target.completedAt)}
5066
+ )`;
5067
+ yield* appendThreadEvent({
5068
+ workspaceId: request.target.workspaceId,
5069
+ threadId: job.threadId,
5070
+ jobId: request.target.jobId,
5071
+ attemptSequence: request.target.attemptSequence,
5072
+ eventKind: "job-completed",
5073
+ payload: {
5074
+ _tag: "completed",
5075
+ outcome: "success",
5076
+ sessionRef: null
5077
+ },
5078
+ payloadSchema: AgentRuntimeEvent,
5079
+ occurredAt: request.target.completedAt
5080
+ });
5081
+ yield* completeAttempt({
5082
+ workspaceId: request.target.workspaceId,
5083
+ jobId: request.target.jobId,
5084
+ attemptSequence: request.target.attemptSequence,
5085
+ completedAt: request.target.completedAt,
5086
+ outcome: "success",
5087
+ state: "succeeded",
5088
+ sessionRef: null,
5089
+ errorJson: null
5090
+ });
5091
+ return revision;
5092
+ })).pipe(mapPersistenceOperation("agent-job.complete-targeted-review"));
5093
+ }),
4626
5094
  enqueue: Effect$1.fn("AgentJobRepository.enqueue")(function* (input) {
4627
5095
  const request = yield* Schema$1.decodeUnknownEffect(Schema$1.toType(EnqueueAgentJobInput))(input);
4628
5096
  if (request.task._tag === "pr-review" && (request.access !== "read-only" || request.subjectRevision !== request.task.subject.headRevision)) return yield* new AgentJobInputError({
@@ -4739,6 +5207,7 @@ var makeAgentJobRepository = Effect$1.gen(function* () {
4739
5207
  fingerprint: claimed.success.contextFingerprint,
4740
5208
  task
4741
5209
  });
5210
+ const reviewBudget = yield* reviewBudgetState(request.workspaceId, candidate.jobId, task);
4742
5211
  const contextPayload = yield* encodePayload(AgentContextSnapshotRecord, context);
4743
5212
  let sessionRef = null;
4744
5213
  if (candidate.attemptSequence > 0) {
@@ -4787,6 +5256,8 @@ var makeAgentJobRepository = Effect$1.gen(function* () {
4787
5256
  access: claimed.success.access,
4788
5257
  prompt: claimed.success.prompt,
4789
5258
  context,
5259
+ ...reviewBudget.reviewBudgetMillis === void 0 ? {} : { reviewBudgetMillis: reviewBudget.reviewBudgetMillis },
5260
+ reviewBudgetExtensionCount: reviewBudget.reviewBudgetExtensionCount,
4790
5261
  sessionRef,
4791
5262
  cancellationRequested: claimed.success.state === "cancel-requested"
4792
5263
  });
@@ -4942,18 +5413,64 @@ var makeAgentJobRepository = Effect$1.gen(function* () {
4942
5413
  return persistedEvent;
4943
5414
  })).pipe(mapPersistenceOperation("agent-job.append-event"));
4944
5415
  }),
5416
+ recordReviewProgress: Effect$1.fnUntraced(function* (input) {
5417
+ const request = yield* Schema$1.decodeUnknownEffect(Schema$1.toType(RecordAgentReviewProgressInput))(input);
5418
+ const agentReport = yield* Schema$1.decodeUnknownEffect(Schema$1.toType(PrReviewReport))(request.report).pipe(Effect$1.mapError(() => new AgentJobInputError({
5419
+ workspaceId: request.workspaceId,
5420
+ jobId: request.jobId,
5421
+ reason: "invalid-result"
5422
+ })));
5423
+ if (!agentReport.suggestions.every(({ state }) => isAgentOwnedSuggestionState(state))) return yield* new AgentJobInputError({
5424
+ workspaceId: request.workspaceId,
5425
+ jobId: request.jobId,
5426
+ reason: "invalid-result"
5427
+ });
5428
+ const report = sanitizeAgentReviewReport(agentReport);
5429
+ return yield* database.transaction(Effect$1.gen(function* () {
5430
+ const job = yield* getJob(request.workspaceId, request.jobId);
5431
+ if (job.state !== "running" && job.state !== "cancel-requested" || job.task._tag !== "pr-review" || !PrReviewSubjectEquivalence(job.task.subject, report.subject)) return yield* new AgentJobInputError({
5432
+ workspaceId: request.workspaceId,
5433
+ jobId: request.jobId,
5434
+ reason: "task-mismatch"
5435
+ });
5436
+ yield* validateLease({
5437
+ workspaceId: request.workspaceId,
5438
+ jobId: request.jobId,
5439
+ attemptSequence: request.attemptSequence,
5440
+ leaseToken: request.leaseToken,
5441
+ observedAt: request.occurredAt
5442
+ });
5443
+ yield* appendThreadEvent({
5444
+ workspaceId: request.workspaceId,
5445
+ threadId: job.threadId,
5446
+ jobId: request.jobId,
5447
+ attemptSequence: request.attemptSequence,
5448
+ eventKind: "review-report",
5449
+ payload: report,
5450
+ payloadSchema: PrReviewReport,
5451
+ occurredAt: request.occurredAt
5452
+ });
5453
+ return yield* Schema$1.decodeUnknownEffect(Schema$1.toType(AgentReviewResultRecord))({
5454
+ workspaceId: request.workspaceId,
5455
+ jobId: request.jobId,
5456
+ attemptSequence: request.attemptSequence,
5457
+ report,
5458
+ completedAt: request.occurredAt
5459
+ });
5460
+ })).pipe(mapPersistenceOperation("agent-job.record-review-progress"));
5461
+ }, Effect$1.withTracerEnabled(false)),
4945
5462
  completeReview: Effect$1.fnUntraced(function* (input) {
4946
5463
  const request = yield* Schema$1.decodeUnknownEffect(Schema$1.toType(CompleteAgentReviewInput))(input);
4947
- const report = yield* Schema$1.decodeUnknownEffect(Schema$1.toType(PrReviewReport))(request.report).pipe(Effect$1.mapError(() => new AgentJobInputError({
5464
+ const agentReport = yield* Schema$1.decodeUnknownEffect(Schema$1.toType(PrReviewReport))(request.report).pipe(Effect$1.mapError(() => new AgentJobInputError({
4948
5465
  workspaceId: request.workspaceId,
4949
5466
  jobId: request.jobId,
4950
5467
  reason: "invalid-result"
4951
5468
  })));
4952
- const encodedReport = yield* encodeReviewReport(report).pipe(Effect$1.mapError(() => new AgentJobInputError({
5469
+ if (!agentReport.suggestions.every(({ state }) => isAgentOwnedSuggestionState(state))) return yield* new AgentJobInputError({
4953
5470
  workspaceId: request.workspaceId,
4954
5471
  jobId: request.jobId,
4955
5472
  reason: "invalid-result"
4956
- })));
5473
+ });
4957
5474
  return yield* database.transaction(Effect$1.gen(function* () {
4958
5475
  const job = yield* getJob(request.workspaceId, request.jobId);
4959
5476
  if (job.state === "cancel-requested") return yield* new AgentJobInputError({
@@ -4961,11 +5478,66 @@ var makeAgentJobRepository = Effect$1.gen(function* () {
4961
5478
  jobId: request.jobId,
4962
5479
  reason: "cancellation-requested"
4963
5480
  });
4964
- if (job.state !== "running" || job.task._tag !== "pr-review" || job.subjectRevision !== job.task.subject.headRevision || !PrReviewSubjectEquivalence(job.task.subject, report.subject)) return yield* new AgentJobInputError({
5481
+ if (job.state !== "running" || job.task._tag !== "pr-review" || job.subjectRevision !== job.task.subject.headRevision || !PrReviewSubjectEquivalence(job.task.subject, agentReport.subject)) return yield* new AgentJobInputError({
4965
5482
  workspaceId: request.workspaceId,
4966
5483
  jobId: request.jobId,
4967
5484
  reason: "task-mismatch"
4968
5485
  });
5486
+ const previous = yield* findPreviousReviewReport({
5487
+ workspaceId: request.workspaceId,
5488
+ pluginConnectionId: job.task.pluginConnectionId,
5489
+ subject: job.task.subject,
5490
+ excludeJobId: request.jobId
5491
+ });
5492
+ const previousReport = Option$1.isSome(previous) ? previous.value.report : PrReviewReport.make({
5493
+ ...agentReport,
5494
+ suggestions: [],
5495
+ transitions: []
5496
+ });
5497
+ if (Option$1.isSome(previous)) for (const suggestion of previous.value.report.suggestions) {
5498
+ if (suggestion.state !== "draft" && suggestion.state !== "published" && suggestion.state !== "reopened") continue;
5499
+ const currentRevision = yield* reviewSuggestionRevisions.read({
5500
+ workspaceId: request.workspaceId,
5501
+ jobId: previous.value.jobId,
5502
+ suggestionId: suggestion.suggestionId,
5503
+ beforeSequence: null,
5504
+ limit: PrReviewSuggestionRevisionPageSize.make(1)
5505
+ });
5506
+ if (currentRevision.current.suggestion.state !== "draft" && currentRevision.current.suggestion.state !== "published") continue;
5507
+ yield* reviewSuggestionRevisions.appendInTransaction({
5508
+ workspaceId: request.workspaceId,
5509
+ jobId: previous.value.jobId,
5510
+ suggestionId: suggestion.suggestionId,
5511
+ expectedRevisionId: currentRevision.current.revisionId,
5512
+ expectedSequence: currentRevision.current.sequence,
5513
+ edit: Schema$1.decodeUnknownSync(PrReviewSuggestionEdit)(currentRevision.current.suggestion),
5514
+ state: "stale",
5515
+ author: PrReviewSuggestionAgentAuthor.make({
5516
+ jobId: request.jobId,
5517
+ providerId: job.providerId,
5518
+ model: job.model,
5519
+ runtimeMetadata: null
5520
+ }),
5521
+ createdAt: request.completedAt
5522
+ });
5523
+ }
5524
+ const expectedTransitions = reconcilePrReviewReports(previousReport, agentReport);
5525
+ if (agentReport.transitions !== void 0) {
5526
+ if (validatePrReviewReportTransitions(previousReport, agentReport, agentReport.transitions)._tag === "failure") return yield* new AgentJobInputError({
5527
+ workspaceId: request.workspaceId,
5528
+ jobId: request.jobId,
5529
+ reason: "invalid-result"
5530
+ });
5531
+ }
5532
+ const report = PrReviewReport.make({
5533
+ ...agentReport,
5534
+ transitions: expectedTransitions
5535
+ });
5536
+ const encodedReport = yield* encodeReviewReport(report).pipe(Effect$1.mapError(() => new AgentJobInputError({
5537
+ workspaceId: request.workspaceId,
5538
+ jobId: request.jobId,
5539
+ reason: "invalid-result"
5540
+ })));
4969
5541
  yield* validateLease({
4970
5542
  workspaceId: request.workspaceId,
4971
5543
  jobId: request.jobId,
@@ -5016,12 +5588,43 @@ var makeAgentJobRepository = Effect$1.gen(function* () {
5016
5588
  });
5017
5589
  })).pipe(mapPersistenceOperation("agent-job.complete-review"));
5018
5590
  }, Effect$1.withTracerEnabled(false)),
5591
+ readReviewSuggestionPublication: Effect$1.fn("AgentJobRepository.readReviewSuggestionPublication")(function* (input) {
5592
+ const request = yield* Schema$1.decodeUnknownEffect(Schema$1.toType(ReadReviewSuggestionPublicationInput))(input);
5593
+ const rows = yield* sql`SELECT
5594
+ revision_id AS revisionId, content_digest AS contentDigest, state,
5595
+ publication_id AS publicationId, comment_id AS commentId,
5596
+ previous_content_digest AS previousContentDigest,
5597
+ previous_publication_id AS previousPublicationId,
5598
+ previous_published_at AS previousPublishedAt,
5599
+ reservation_id AS reservationId,
5600
+ reservation_acquired_at AS reservationAcquiredAt, reserved_at AS reservedAt,
5601
+ published_at AS publishedAt
5602
+ FROM agent_review_suggestion_publications
5603
+ WHERE workspace_id = ${request.workspaceId}
5604
+ AND job_id = ${request.jobId}
5605
+ AND suggestion_id = ${request.suggestionId}
5606
+ AND revision_id = ${request.revisionId}`;
5607
+ if (rows.length === 0) return null;
5608
+ const decoded = Schema$1.decodeUnknownResult(ReviewSuggestionPublicationRow)(rows[0]);
5609
+ if (Result$1.isFailure(decoded)) return yield* persistedRecordError(request.workspaceId, "agent-review-suggestion-publication", `${request.jobId}:${request.suggestionId}:${request.revisionId}`, "agent-review-suggestion-publication-schema-invalid");
5610
+ const row = decoded.success;
5611
+ if (row.state !== "published" || row.publicationId === null || row.commentId === null) return null;
5612
+ return yield* Schema$1.decodeUnknownEffect(ReadReviewSuggestionPublication)({
5613
+ state: row.state,
5614
+ publicationId: row.publicationId,
5615
+ commentId: row.commentId
5616
+ });
5617
+ }),
5019
5618
  reserveReviewSuggestionPublication: Effect$1.fn("AgentJobRepository.reserveReviewSuggestionPublication")(function* (input) {
5020
5619
  const request = yield* Schema$1.decodeUnknownEffect(Schema$1.toType(ReserveReviewSuggestionPublicationInput))(input);
5021
5620
  return yield* database.transaction(Effect$1.gen(function* () {
5621
+ const operation = request.operation ?? "create";
5022
5622
  const existingRows = yield* sql`SELECT
5023
5623
  revision_id AS revisionId, content_digest AS contentDigest, state,
5024
- publication_id AS publicationId, reservation_id AS reservationId,
5624
+ publication_id AS publicationId, comment_id AS commentId,
5625
+ previous_content_digest AS previousContentDigest,
5626
+ previous_publication_id AS previousPublicationId,
5627
+ previous_published_at AS previousPublishedAt, reservation_id AS reservationId,
5025
5628
  reservation_acquired_at AS reservationAcquiredAt, reserved_at AS reservedAt,
5026
5629
  published_at AS publishedAt
5027
5630
  FROM agent_review_suggestion_publications
@@ -5031,23 +5634,54 @@ var makeAgentJobRepository = Effect$1.gen(function* () {
5031
5634
  AND revision_id = ${request.revisionId}`;
5032
5635
  if (existingRows.length > 0) {
5033
5636
  const existing = yield* Schema$1.decodeUnknownEffect(ReviewSuggestionPublicationRow)(existingRows[0]);
5034
- if (existing.contentDigest !== request.contentDigest) return yield* new AgentJobInputError({
5035
- workspaceId: request.workspaceId,
5036
- jobId: request.jobId,
5037
- reason: "invalid-transition"
5038
- });
5637
+ if (existing.contentDigest !== request.contentDigest) {
5638
+ if (operation !== "create" && existing.state === "published" && existing.publicationId !== null && existing.publishedAt !== null && existing.commentId !== null && existing.commentId === request.commentId) {
5639
+ yield* currentPublishedReviewSuggestion(request);
5640
+ yield* sql`UPDATE agent_review_suggestion_publications
5641
+ SET content_digest = ${request.contentDigest},
5642
+ state = 'reserved',
5643
+ publication_id = NULL,
5644
+ previous_content_digest = ${existing.contentDigest},
5645
+ previous_publication_id = ${existing.publicationId},
5646
+ previous_published_at = ${encodeTimestamp$11(existing.publishedAt)},
5647
+ reservation_id = ${request.reservationId},
5648
+ reservation_acquired_at = ${encodeTimestamp$11(request.reservedAt)},
5649
+ published_at = NULL
5650
+ WHERE workspace_id = ${request.workspaceId}
5651
+ AND job_id = ${request.jobId}
5652
+ AND suggestion_id = ${request.suggestionId}
5653
+ AND revision_id = ${request.revisionId}
5654
+ AND state = 'published'
5655
+ AND content_digest = ${existing.contentDigest}
5656
+ AND comment_id = ${request.commentId}`;
5657
+ return ReviewSuggestionPublicationReservation.make({
5658
+ _tag: (yield* readChanges(sql)) === 1 ? "acquired" : "in-progress",
5659
+ commentId: existing.commentId
5660
+ });
5661
+ }
5662
+ return yield* new AgentJobInputError({
5663
+ workspaceId: request.workspaceId,
5664
+ jobId: request.jobId,
5665
+ reason: "invalid-transition"
5666
+ });
5667
+ }
5039
5668
  return existing.state === "published" && existing.publicationId !== null && existing.publishedAt !== null ? ReviewSuggestionPublicationReservation.make({
5040
5669
  _tag: "published",
5041
5670
  publicationId: existing.publicationId,
5042
- publishedAt: existing.publishedAt
5671
+ publishedAt: existing.publishedAt,
5672
+ ...existing.commentId === null ? {} : { commentId: existing.commentId }
5043
5673
  }) : existing.publicationId !== null && existing.publishedAt !== null ? ReviewSuggestionPublicationReservation.make({
5044
5674
  _tag: "recoverable",
5045
5675
  publicationId: existing.publicationId,
5046
5676
  publishedAt: existing.publishedAt,
5047
- reservationId: existing.reservationId
5677
+ reservationId: existing.reservationId,
5678
+ ...existing.commentId === null ? {} : { commentId: existing.commentId }
5048
5679
  }) : yield* Effect$1.gen(function* () {
5049
5680
  const recoveryEligibleAt = DateTime$1.add(existing.reservationAcquiredAt, { minutes: REVIEW_SUGGESTION_PUBLICATION_RESERVATION_LIFETIME_MINUTES });
5050
- if (DateTime$1.Order(request.reservedAt, recoveryEligibleAt) < 0) return ReviewSuggestionPublicationReservation.make({ _tag: "in-progress" });
5681
+ if (DateTime$1.Order(request.reservedAt, recoveryEligibleAt) < 0) return ReviewSuggestionPublicationReservation.make({
5682
+ _tag: "in-progress",
5683
+ ...existing.commentId === null ? {} : { commentId: existing.commentId }
5684
+ });
5051
5685
  yield* sql`UPDATE agent_review_suggestion_publications
5052
5686
  SET reservation_id = ${request.reservationId},
5053
5687
  reservation_acquired_at = ${encodeTimestamp$11(request.reservedAt)}
@@ -5060,24 +5694,37 @@ var makeAgentJobRepository = Effect$1.gen(function* () {
5060
5694
  AND publication_id IS NULL
5061
5695
  AND reservation_id = ${existing.reservationId}
5062
5696
  AND reservation_acquired_at = ${encodeTimestamp$11(existing.reservationAcquiredAt)}`;
5063
- return ReviewSuggestionPublicationReservation.make({ _tag: (yield* readChanges(sql)) === 1 ? "acquired" : "in-progress" });
5697
+ return ReviewSuggestionPublicationReservation.make({
5698
+ _tag: (yield* readChanges(sql)) === 1 ? "acquired" : "in-progress",
5699
+ ...existing.commentId === null ? {} : { commentId: existing.commentId }
5700
+ });
5064
5701
  });
5065
5702
  }
5703
+ if (operation !== "create") return yield* new AgentJobInputError({
5704
+ workspaceId: request.workspaceId,
5705
+ jobId: request.jobId,
5706
+ reason: "invalid-transition"
5707
+ });
5066
5708
  yield* currentPublishableReviewSuggestion(request);
5067
5709
  const inserted = yield* sql`INSERT INTO agent_review_suggestion_publications (
5068
5710
  workspace_id, job_id, suggestion_id, revision_id, content_digest, state,
5069
- publication_id, reservation_id, reservation_acquired_at,
5070
- reserved_at, published_at
5711
+ publication_id, comment_id, reservation_id, reservation_acquired_at,
5712
+ reserved_at, published_at, previous_content_digest,
5713
+ previous_publication_id, previous_published_at
5071
5714
  ) VALUES (
5072
5715
  ${request.workspaceId}, ${request.jobId}, ${request.suggestionId},
5073
5716
  ${request.revisionId}, ${request.contentDigest}, 'reserved', NULL,
5717
+ NULL,
5074
5718
  ${request.reservationId}, ${encodeTimestamp$11(request.reservedAt)},
5075
- ${encodeTimestamp$11(request.reservedAt)}, NULL
5719
+ ${encodeTimestamp$11(request.reservedAt)}, NULL, NULL, NULL, NULL
5076
5720
  ) ON CONFLICT DO NOTHING
5077
5721
  RETURNING suggestion_id AS suggestionId`;
5078
5722
  const rows = yield* sql`SELECT
5079
5723
  revision_id AS revisionId, content_digest AS contentDigest, state,
5080
- publication_id AS publicationId, reservation_id AS reservationId,
5724
+ publication_id AS publicationId, comment_id AS commentId,
5725
+ previous_content_digest AS previousContentDigest,
5726
+ previous_publication_id AS previousPublicationId,
5727
+ previous_published_at AS previousPublishedAt, reservation_id AS reservationId,
5081
5728
  reservation_acquired_at AS reservationAcquiredAt, reserved_at AS reservedAt,
5082
5729
  published_at AS publishedAt
5083
5730
  FROM agent_review_suggestion_publications
@@ -5094,26 +5741,47 @@ var makeAgentJobRepository = Effect$1.gen(function* () {
5094
5741
  return row.success.state === "published" && row.success.publicationId !== null && row.success.publishedAt !== null ? ReviewSuggestionPublicationReservation.make({
5095
5742
  _tag: "published",
5096
5743
  publicationId: row.success.publicationId,
5097
- publishedAt: row.success.publishedAt
5744
+ publishedAt: row.success.publishedAt,
5745
+ ...row.success.commentId === null ? {} : { commentId: row.success.commentId }
5098
5746
  }) : row.success.publicationId !== null && row.success.publishedAt !== null ? ReviewSuggestionPublicationReservation.make({
5099
5747
  _tag: "recoverable",
5100
5748
  publicationId: row.success.publicationId,
5101
5749
  publishedAt: row.success.publishedAt,
5102
- reservationId: row.success.reservationId
5750
+ reservationId: row.success.reservationId,
5751
+ ...row.success.commentId === null ? {} : { commentId: row.success.commentId }
5103
5752
  }) : ReviewSuggestionPublicationReservation.make({ _tag: inserted.length === 1 ? "acquired" : "in-progress" });
5104
5753
  })).pipe(mapPersistenceOperation("agent-job.reserve-review-suggestion-publication"));
5105
5754
  }),
5106
5755
  releaseReviewSuggestionPublication: Effect$1.fn("AgentJobRepository.releaseReviewSuggestionPublication")(function* (input) {
5107
5756
  const request = yield* Schema$1.decodeUnknownEffect(Schema$1.toType(ReleaseReviewSuggestionPublicationInput))(input);
5108
- yield* sql`DELETE FROM agent_review_suggestion_publications
5109
- WHERE workspace_id = ${request.workspaceId}
5110
- AND job_id = ${request.jobId}
5111
- AND suggestion_id = ${request.suggestionId}
5112
- AND revision_id = ${request.revisionId}
5113
- AND content_digest = ${request.contentDigest}
5114
- AND state = 'reserved'
5115
- AND publication_id IS NULL
5116
- AND reservation_id = ${request.reservationId}`.pipe(mapPersistenceOperation("agent-job.release-review-suggestion-publication"));
5757
+ yield* database.transaction(Effect$1.gen(function* () {
5758
+ yield* sql`UPDATE agent_review_suggestion_publications
5759
+ SET content_digest = previous_content_digest,
5760
+ state = 'published',
5761
+ publication_id = previous_publication_id,
5762
+ previous_content_digest = NULL,
5763
+ previous_publication_id = NULL,
5764
+ previous_published_at = NULL,
5765
+ published_at = previous_published_at
5766
+ WHERE workspace_id = ${request.workspaceId}
5767
+ AND job_id = ${request.jobId}
5768
+ AND suggestion_id = ${request.suggestionId}
5769
+ AND revision_id = ${request.revisionId}
5770
+ AND content_digest = ${request.contentDigest}
5771
+ AND state = 'reserved'
5772
+ AND publication_id IS NULL
5773
+ AND previous_content_digest IS NOT NULL
5774
+ AND reservation_id = ${request.reservationId}`;
5775
+ if ((yield* readChanges(sql)) === 0) yield* sql`DELETE FROM agent_review_suggestion_publications
5776
+ WHERE workspace_id = ${request.workspaceId}
5777
+ AND job_id = ${request.jobId}
5778
+ AND suggestion_id = ${request.suggestionId}
5779
+ AND revision_id = ${request.revisionId}
5780
+ AND content_digest = ${request.contentDigest}
5781
+ AND state = 'reserved'
5782
+ AND publication_id IS NULL
5783
+ AND reservation_id = ${request.reservationId}`;
5784
+ })).pipe(mapPersistenceOperation("agent-job.release-review-suggestion-publication"));
5117
5785
  }),
5118
5786
  recordReviewSuggestionPublication: Effect$1.fn("AgentJobRepository.recordReviewSuggestionPublication")(function* (input) {
5119
5787
  const request = yield* Schema$1.decodeUnknownEffect(Schema$1.toType(RecordReviewSuggestionPublicationInput))(input);
@@ -5121,7 +5789,10 @@ var makeAgentJobRepository = Effect$1.gen(function* () {
5121
5789
  const job = yield* getJob(request.workspaceId, request.jobId);
5122
5790
  const publicationRows = yield* sql`SELECT
5123
5791
  revision_id AS revisionId, content_digest AS contentDigest, state,
5124
- publication_id AS publicationId, reservation_id AS reservationId,
5792
+ publication_id AS publicationId, comment_id AS commentId,
5793
+ previous_content_digest AS previousContentDigest,
5794
+ previous_publication_id AS previousPublicationId,
5795
+ previous_published_at AS previousPublishedAt, reservation_id AS reservationId,
5125
5796
  reservation_acquired_at AS reservationAcquiredAt, reserved_at AS reservedAt,
5126
5797
  published_at AS publishedAt
5127
5798
  FROM agent_review_suggestion_publications
@@ -5136,7 +5807,7 @@ var makeAgentJobRepository = Effect$1.gen(function* () {
5136
5807
  reason: "invalid-transition"
5137
5808
  });
5138
5809
  if (publication.success.state === "published") {
5139
- if (publication.success.contentDigest === request.contentDigest && publication.success.publicationId === request.publicationId) return;
5810
+ if (publication.success.contentDigest === request.contentDigest && publication.success.publicationId === request.publicationId && (request.commentId === void 0 || publication.success.commentId === request.commentId)) return;
5140
5811
  return yield* new AgentJobInputError({
5141
5812
  workspaceId: request.workspaceId,
5142
5813
  jobId: request.jobId,
@@ -5148,9 +5819,18 @@ var makeAgentJobRepository = Effect$1.gen(function* () {
5148
5819
  jobId: request.jobId,
5149
5820
  reason: "invalid-transition"
5150
5821
  });
5822
+ if (request.commentId !== void 0 && publication.success.commentId !== null && publication.success.commentId !== request.commentId) return yield* new AgentJobInputError({
5823
+ workspaceId: request.workspaceId,
5824
+ jobId: request.jobId,
5825
+ reason: "invalid-transition"
5826
+ });
5151
5827
  if (request.finalize === false) {
5152
5828
  yield* sql`UPDATE agent_review_suggestion_publications
5153
5829
  SET publication_id = ${request.publicationId},
5830
+ comment_id = COALESCE(${request.commentId ?? null}, comment_id),
5831
+ previous_content_digest = NULL,
5832
+ previous_publication_id = NULL,
5833
+ previous_published_at = NULL,
5154
5834
  published_at = ${encodeTimestamp$11(request.publishedAt)}
5155
5835
  WHERE workspace_id = ${request.workspaceId}
5156
5836
  AND job_id = ${request.jobId}
@@ -5178,10 +5858,15 @@ var makeAgentJobRepository = Effect$1.gen(function* () {
5178
5858
  workspaceId: request.workspaceId,
5179
5859
  jobId: request.jobId
5180
5860
  });
5181
- yield* currentPublishableReviewSuggestion(request);
5861
+ if ((request.operation ?? "create") === "create") yield* currentPublishableReviewSuggestion(request);
5862
+ else yield* currentPublishedReviewSuggestion(request);
5182
5863
  yield* sql`UPDATE agent_review_suggestion_publications
5183
5864
  SET state = 'published',
5184
5865
  publication_id = ${request.publicationId},
5866
+ comment_id = COALESCE(${request.commentId ?? null}, comment_id),
5867
+ previous_content_digest = NULL,
5868
+ previous_publication_id = NULL,
5869
+ previous_published_at = NULL,
5185
5870
  published_at = ${encodeTimestamp$11(request.publishedAt)}
5186
5871
  WHERE workspace_id = ${request.workspaceId}
5187
5872
  AND job_id = ${request.jobId}
@@ -5260,6 +5945,181 @@ var makeAgentJobRepository = Effect$1.gen(function* () {
5260
5945
  return persistedEvent;
5261
5946
  })).pipe(mapPersistenceOperation("agent-job.fail-attempt"));
5262
5947
  }),
5948
+ listRunningPrReviewAttempts: Effect$1.fn("AgentJobRepository.listRunningPrReviewAttempts")(function* (workspaceId) {
5949
+ const rows = yield* sql`SELECT
5950
+ job.job_id AS jobId, attempt.attempt_sequence AS attemptSequence,
5951
+ job.provider_id AS providerId, attempt.session_ref AS sessionRef
5952
+ FROM agent_jobs job
5953
+ JOIN agent_job_attempts attempt
5954
+ ON attempt.workspace_id = job.workspace_id
5955
+ AND attempt.job_id = job.job_id
5956
+ WHERE job.workspace_id = ${workspaceId}
5957
+ AND job.state IN ('running', 'cancel-requested')
5958
+ AND attempt.completed_at IS NULL
5959
+ ORDER BY job.job_id, attempt.attempt_sequence`;
5960
+ const attempts = [];
5961
+ for (const row of rows) {
5962
+ const jobId = yield* Schema$1.decodeUnknownEffect(JobId)(row.jobId).pipe(Effect$1.mapError(() => new PersistenceOperationError({ operation: "agent-job.running-review-job-id" })));
5963
+ const attemptSequence = yield* Schema$1.decodeUnknownEffect(AgentAttemptSequence)(row.attemptSequence).pipe(Effect$1.mapError(() => new PersistenceOperationError({ operation: "agent-job.running-review-attempt-sequence" })));
5964
+ const providerId = yield* Schema$1.decodeUnknownEffect(Schema$1.String)(row.providerId).pipe(Effect$1.mapError(() => new PersistenceOperationError({ operation: "agent-job.running-review-provider-id" })));
5965
+ if ((yield* getJob(workspaceId, jobId)).task._tag !== "pr-review") continue;
5966
+ const digest = yield* cryptoService.digest("SHA-256", yield* bytesFromText(`${providerId}:${jobId}:${String(attemptSequence)}`)).pipe(Effect$1.mapError(() => new PersistenceOperationError({ operation: "agent-job.running-review-attempt-id" })));
5967
+ const attempt = Schema$1.decodeUnknownResult(RunningPrReviewAttempt)({
5968
+ jobId,
5969
+ attemptSequence,
5970
+ attemptId: Encoding$1.encodeHex(digest).slice(0, 12),
5971
+ sessionRef: row.sessionRef
5972
+ });
5973
+ if (Result$1.isFailure(attempt)) return yield* new PersistenceOperationError({ operation: "agent-job.running-review-attempt-invalid" });
5974
+ attempts.push(attempt.success);
5975
+ }
5976
+ return attempts;
5977
+ }),
5978
+ attachRunningPrReviewSession: Effect$1.fn("AgentJobRepository.attachRunningPrReviewSession")(function* (input) {
5979
+ const request = yield* Schema$1.decodeUnknownEffect(Schema$1.toType(AttachRunningPrReviewSessionInput))(input);
5980
+ yield* sql`UPDATE agent_job_attempts
5981
+ SET session_ref = ${request.sessionRef}
5982
+ WHERE workspace_id = ${request.workspaceId}
5983
+ AND job_id = ${request.jobId}
5984
+ AND attempt_sequence = ${request.attemptSequence}
5985
+ AND completed_at IS NULL
5986
+ AND EXISTS (
5987
+ SELECT 1 FROM agent_jobs job
5988
+ WHERE job.workspace_id = agent_job_attempts.workspace_id
5989
+ AND job.job_id = agent_job_attempts.job_id
5990
+ AND job.state IN ('running', 'cancel-requested')
5991
+ )`;
5992
+ }),
5993
+ interruptRunningReviews: Effect$1.fn("AgentJobRepository.interruptRunningReviews")(function* (input) {
5994
+ const request = yield* Schema$1.decodeUnknownEffect(Schema$1.toType(InterruptRunningReviewsInput))(input);
5995
+ return yield* database.transaction(Effect$1.gen(function* () {
5996
+ const rows = yield* sql`SELECT job_id AS jobId
5997
+ FROM agent_jobs
5998
+ WHERE workspace_id = ${request.workspaceId}
5999
+ AND state IN ('running', 'cancel-requested')`;
6000
+ let interrupted = 0;
6001
+ for (const row of rows) {
6002
+ const jobId = yield* Schema$1.decodeUnknownEffect(JobId)(row.jobId).pipe(Effect$1.mapError(() => new PersistenceOperationError({ operation: "agent-job.interrupt-job-id" })));
6003
+ const job = yield* getJob(request.workspaceId, jobId);
6004
+ if (job.task._tag !== "pr-review") continue;
6005
+ const attemptRows = yield* sql`SELECT attempt_sequence AS attemptSequence
6006
+ FROM agent_job_attempts
6007
+ WHERE workspace_id = ${request.workspaceId}
6008
+ AND job_id = ${jobId}
6009
+ AND completed_at IS NULL
6010
+ ORDER BY attempt_sequence DESC
6011
+ LIMIT 1`;
6012
+ const attempt = Schema$1.decodeUnknownResult(Schema$1.Struct({ attemptSequence: AgentAttemptSequence }))(attemptRows[0]);
6013
+ if (Result$1.isFailure(attempt)) continue;
6014
+ if (request.preservedAttempts?.some((preserved) => preserved.jobId === jobId && preserved.attemptSequence === attempt.success.attemptSequence)) continue;
6015
+ const existing = yield* readReviewResult({
6016
+ workspaceId: request.workspaceId,
6017
+ jobId
6018
+ }).pipe(Effect$1.result);
6019
+ if (Result$1.isFailure(existing) && existing.failure._tag !== "RecordNotFoundError") return yield* existing.failure;
6020
+ const report = Result$1.isSuccess(existing) ? {
6021
+ ...existing.success.report,
6022
+ completion: {
6023
+ status: "unable-to-conclude",
6024
+ reason: PROCESS_RESTART_INTERRUPTION_MESSAGE
6025
+ }
6026
+ } : {
6027
+ schemaVersion: 3,
6028
+ subject: job.task.subject,
6029
+ completion: {
6030
+ status: "unable-to-conclude",
6031
+ reason: PROCESS_RESTART_INTERRUPTION_MESSAGE
6032
+ },
6033
+ suggestions: [],
6034
+ notes: []
6035
+ };
6036
+ yield* appendThreadEvent({
6037
+ workspaceId: request.workspaceId,
6038
+ threadId: job.threadId,
6039
+ jobId,
6040
+ attemptSequence: attempt.success.attemptSequence,
6041
+ eventKind: "review-report",
6042
+ payload: report,
6043
+ payloadSchema: PrReviewReport,
6044
+ occurredAt: request.interruptedAt
6045
+ });
6046
+ const error = new AgentProviderError({
6047
+ providerId: job.providerId,
6048
+ phase: "execution",
6049
+ message: PROCESS_RESTART_INTERRUPTION_MESSAGE,
6050
+ retryable: false
6051
+ });
6052
+ const encodedFailure = yield* encodePayload(ProviderFailurePayload, { error });
6053
+ yield* appendThreadEvent({
6054
+ workspaceId: request.workspaceId,
6055
+ threadId: job.threadId,
6056
+ jobId,
6057
+ attemptSequence: attempt.success.attemptSequence,
6058
+ eventKind: "job-failed",
6059
+ payload: { error },
6060
+ payloadSchema: ProviderFailurePayload,
6061
+ occurredAt: request.interruptedAt
6062
+ });
6063
+ yield* completeAttempt({
6064
+ workspaceId: request.workspaceId,
6065
+ jobId,
6066
+ attemptSequence: attempt.success.attemptSequence,
6067
+ completedAt: request.interruptedAt,
6068
+ outcome: "failed",
6069
+ state: "failed",
6070
+ sessionRef: null,
6071
+ errorJson: encodedFailure.json
6072
+ });
6073
+ interrupted += 1;
6074
+ }
6075
+ return { interrupted };
6076
+ })).pipe(mapPersistenceOperation("agent-job.interrupt-running-reviews"));
6077
+ }),
6078
+ reviewBudget: Effect$1.fn("AgentJobRepository.reviewBudget")(function* (input) {
6079
+ const request = yield* Schema$1.decodeUnknownEffect(Schema$1.toType(ReadReviewBudgetInput))(input);
6080
+ return yield* reviewBudgetState(request.workspaceId, request.jobId, request.task);
6081
+ }),
6082
+ extendReviewBudget: Effect$1.fn("AgentJobRepository.extendReviewBudget")(function* (input) {
6083
+ const request = yield* Schema$1.decodeUnknownEffect(Schema$1.toType(ExtendReviewBudgetInput))(input);
6084
+ return yield* database.transaction(Effect$1.gen(function* () {
6085
+ const job = yield* getJob(request.workspaceId, request.jobId);
6086
+ if (job.task._tag !== "pr-review" || job.state !== "running") return yield* new AgentJobInputError({
6087
+ workspaceId: request.workspaceId,
6088
+ jobId: request.jobId,
6089
+ reason: "invalid-transition"
6090
+ });
6091
+ const current = yield* reviewBudgetState(request.workspaceId, request.jobId, job.task);
6092
+ if (current.reviewBudgetExtensionCount >= 1 || current.reviewBudgetMillis === void 0 || current.reviewBudgetMillis + job.task.reviewProfile.budgetMillis > 36e5) return yield* new AgentJobInputError({
6093
+ workspaceId: request.workspaceId,
6094
+ jobId: request.jobId,
6095
+ reason: "invalid-transition"
6096
+ });
6097
+ const reviewBudgetMillis = current.reviewBudgetMillis + job.task.reviewProfile.budgetMillis;
6098
+ yield* appendThreadEvent({
6099
+ workspaceId: request.workspaceId,
6100
+ threadId: job.threadId,
6101
+ jobId: request.jobId,
6102
+ attemptSequence: null,
6103
+ eventKind: "job-queued",
6104
+ payload: {
6105
+ access: job.access,
6106
+ contextFingerprint: job.contextFingerprint,
6107
+ model: job.model,
6108
+ providerId: job.providerId,
6109
+ subjectRevision: job.subjectRevision,
6110
+ task: job.task,
6111
+ reviewBudgetMillis,
6112
+ reviewBudgetExtensionCount: 1
6113
+ },
6114
+ payloadSchema: PersistedJobQueuedPayload,
6115
+ occurredAt: request.extendedAt
6116
+ });
6117
+ return {
6118
+ reviewBudgetMillis,
6119
+ reviewBudgetExtensionCount: 1
6120
+ };
6121
+ })).pipe(mapPersistenceOperation("agent-job.extend-review-budget"));
6122
+ }),
5263
6123
  requestCancellation: Effect$1.fn("AgentJobRepository.requestCancellation")(function* (input) {
5264
6124
  const request = yield* Schema$1.decodeUnknownEffect(Schema$1.toType(RequestAgentCancellationInput))(input);
5265
6125
  yield* database.transaction(Effect$1.gen(function* () {
@@ -5299,10 +6159,13 @@ var makeAgentJobRepository = Effect$1.gen(function* () {
5299
6159
  const request = yield* Schema$1.decodeUnknownEffect(Schema$1.toType(LatestAgentReviewInput))(input);
5300
6160
  const subjectJson = yield* Schema$1.encodeUnknownEffect(Schema$1.fromJsonString(PrReviewSubject))(request.subject).pipe(Effect$1.mapError(() => new PersistenceOperationError({ operation: "agent-job.latest-review-subject" })));
5301
6161
  const taskContextPrefix = `{"_tag":"pr-review","pluginConnectionId":"${request.pluginConnectionId}","subject":${subjectJson},"reviewProfile":`;
6162
+ const identityPrefix = taskContextPrefix.slice(0, taskContextPrefix.indexOf("\"baseRevision\""));
5302
6163
  const rendered = renderLatestAgentReviewQuery({
5303
6164
  workspaceId: request.workspaceId,
5304
- subjectRevision: request.subject.headRevision,
5305
- taskContextPrefix,
6165
+ ...request.excludeJobId === void 0 ? {} : { excludeJobId: request.excludeJobId },
6166
+ ...request.allowDifferentHead === true ? {} : { subjectRevision: request.subject.headRevision },
6167
+ taskContextPrefix: request.allowDifferentHead === true ? identityPrefix : taskContextPrefix,
6168
+ excludeTargeted: true,
5306
6169
  ...request.jobId === void 0 ? {} : { jobId: request.jobId }
5307
6170
  });
5308
6171
  const rows = yield* sql.unsafe(rendered.sql, [...rendered.params]).pipe(mapPersistenceOperation("agent-job.latest-review"));
@@ -5310,11 +6173,28 @@ var makeAgentJobRepository = Effect$1.gen(function* () {
5310
6173
  const row = Schema$1.decodeUnknownResult(LatestReviewRow)(rows[0]);
5311
6174
  if (rows.length !== 1 || Result$1.isFailure(row)) return yield* persistedRecordError(request.workspaceId, "agent-review", request.subject.pullRequestId, "agent-review-latest-schema-invalid");
5312
6175
  const task = yield* decodeTaskContext(request.workspaceId, row.success.jobId, row.success.taskContextJson, row.success.taskContextDigest);
5313
- if (task._tag !== "pr-review" || task.pluginConnectionId !== request.pluginConnectionId || !PrReviewSubjectEquivalence(task.subject, request.subject)) return yield* persistedRecordError(request.workspaceId, "agent-review", request.subject.pullRequestId, "agent-review-subject-mismatch");
5314
- const report = row.success.state === "succeeded" ? (yield* readReviewResult({
6176
+ let interrupted = false;
6177
+ if (row.success.state === "failed") {
6178
+ const interruptionRows = yield* sql`SELECT COUNT(*) AS interrupted
6179
+ FROM agent_thread_events
6180
+ WHERE workspace_id = ${request.workspaceId}
6181
+ AND job_id = ${row.success.jobId}
6182
+ AND event_kind = 'job-failed'
6183
+ AND payload_json LIKE ${`%${PROCESS_RESTART_INTERRUPTION_MESSAGE}%`}`.pipe(mapPersistenceOperation("agent-job.latest-review-interruption"));
6184
+ interrupted = Number(interruptionRows[0]?.interrupted ?? 0) > 0;
6185
+ }
6186
+ if (task._tag !== "pr-review" || task.pluginConnectionId !== request.pluginConnectionId || (request.allowDifferentHead === true ? task.subject.providerId !== request.subject.providerId || task.subject.repository !== request.subject.repository || task.subject.pullRequestId !== request.subject.pullRequestId : !PrReviewSubjectEquivalence(task.subject, request.subject))) return yield* persistedRecordError(request.workspaceId, "agent-review", request.subject.pullRequestId, "agent-review-subject-mismatch");
6187
+ const reviewBudget = yield* reviewBudgetState(request.workspaceId, row.success.jobId, task);
6188
+ const startedRows = yield* sql`SELECT MAX(started_at) AS startedAt
6189
+ FROM agent_job_attempts
6190
+ WHERE workspace_id = ${request.workspaceId} AND job_id = ${row.success.jobId}`.pipe(mapPersistenceOperation("agent-job.latest-review-started-at"));
6191
+ const startedAt = Schema$1.decodeUnknownResult(Schema$1.Struct({ startedAt: Schema$1.NullOr(UtcTimestamp) }))(startedRows[0]);
6192
+ if (startedRows.length !== 1 || Result$1.isFailure(startedAt)) return yield* persistedRecordError(request.workspaceId, "agent-review", request.subject.pullRequestId, "agent-review-started-at-schema-invalid");
6193
+ const reviewResult = row.success.state === "succeeded" || row.success.state === "failed" || row.success.state === "cancelled" ? yield* readReviewResult({
5315
6194
  workspaceId: request.workspaceId,
5316
6195
  jobId: row.success.jobId
5317
- })).report : null;
6196
+ }).pipe(Effect$1.catchTag("RecordNotFoundError", () => Effect$1.succeed(null))) : null;
6197
+ const report = reviewResult === null ? null : reviewResult.report;
5318
6198
  const activityRows = yield* sql`SELECT
5319
6199
  workspace_id AS workspaceId, thread_id AS threadId,
5320
6200
  event_sequence AS eventSequence, job_id AS jobId,
@@ -5338,6 +6218,11 @@ var makeAgentJobRepository = Effect$1.gen(function* () {
5338
6218
  }
5339
6219
  const record = yield* Schema$1.decodeUnknownEffect(Schema$1.toType(LatestAgentReviewRecord))({
5340
6220
  ...row.success,
6221
+ state: interrupted ? "interrupted" : row.success.state,
6222
+ startedAt: startedAt.success.startedAt,
6223
+ ...reviewBudget.reviewBudgetMillis === void 0 ? {} : { reviewBudgetMillis: reviewBudget.reviewBudgetMillis },
6224
+ reviewBudgetExtensionCount: reviewBudget.reviewBudgetExtensionCount,
6225
+ taskIntent: task.intent ?? null,
5341
6226
  report,
5342
6227
  reviewProfile: task.reviewProfile,
5343
6228
  activity: {
@@ -8443,6 +9328,12 @@ var GovernedActionTargetReadInput = Schema$1.Struct({
8443
9328
  maximum: 100
8444
9329
  }))
8445
9330
  });
9331
+ /** Bounded batched lookup for the latest successful publications of exact releases. */
9332
+ var GovernedActionReleasePublicationReadInput = Schema$1.Struct({
9333
+ workspaceId: WorkspaceId,
9334
+ providerId: Schema$1.Literal("confluence"),
9335
+ releaseIds: Schema$1.Array(ReleaseId).check(Schema$1.isMinLength(1), Schema$1.isMaxLength(200), Schema$1.isUnique())
9336
+ });
8446
9337
  Schema$1.Struct({
8447
9338
  envelope: GovernedActionEnvelopeV1,
8448
9339
  head: GovernedActionLifecycleHeadV1,
@@ -9252,6 +10143,10 @@ var GovernedActionTargetCandidateIdentity = Schema$1.Struct({
9252
10143
  actionId: GovernedActionId,
9253
10144
  sortAt: UtcTimestamp
9254
10145
  });
10146
+ var GovernedActionReleasePublicationCandidate = Schema$1.Struct({
10147
+ actionId: GovernedActionId,
10148
+ releaseId: ReleaseId
10149
+ });
9255
10150
  var malformed = (request, recordKind, diagnosticCode, recordKey = request.actionId) => governedActionRecordError({
9256
10151
  workspaceId: request.workspaceId,
9257
10152
  recordKind,
@@ -9561,6 +10456,61 @@ var makeGovernedActionRead = Effect$1.gen(function* () {
9561
10456
  cursor = identities[identities.length - 1] ?? null;
9562
10457
  }
9563
10458
  return selectLatestTerminalByTarget(request, candidates);
10459
+ }),
10460
+ readLatestTerminalReleasePublications: Effect$1.fn("GovernedActionReader.readLatestTerminalReleasePublications")(function* (request) {
10461
+ const releaseIdsJson = JSON.stringify(request.releaseIds);
10462
+ const rows = yield* sql`WITH requested_release_ids AS (
10463
+ SELECT value AS releaseId
10464
+ FROM json_each(${releaseIdsJson})
10465
+ ),
10466
+ ranked_publications AS (
10467
+ SELECT
10468
+ publication.action_id AS actionId,
10469
+ publication.release_id AS releaseId,
10470
+ ROW_NUMBER() OVER (
10471
+ PARTITION BY publication.release_id
10472
+ ORDER BY action.updated_at DESC, action.action_id DESC
10473
+ ) AS candidateRank
10474
+ FROM governed_action_release_publications AS publication
10475
+ JOIN governed_actions AS action
10476
+ ON action.workspace_id = publication.workspace_id
10477
+ AND action.action_id = publication.action_id
10478
+ JOIN governed_action_target_dimensions AS dimensions
10479
+ ON dimensions.workspace_id = action.workspace_id
10480
+ AND dimensions.action_id = action.action_id
10481
+ JOIN requested_release_ids AS requested
10482
+ ON requested.releaseId = publication.release_id
10483
+ WHERE publication.workspace_id = ${request.workspaceId}
10484
+ AND publication.provider_id = ${request.providerId}
10485
+ AND action.state IN (
10486
+ 'proposed', 'authorized', 'started', 'cancel-requested',
10487
+ 'unknown', 'cancel-requested-unknown', 'succeeded'
10488
+ )
10489
+ AND dimensions.action_kind IN ('create-page', 'update-page')
10490
+ )
10491
+ SELECT actionId, releaseId
10492
+ FROM ranked_publications
10493
+ WHERE candidateRank = 1
10494
+ ORDER BY releaseId`;
10495
+ const candidates = yield* Schema$1.decodeUnknownEffect(Schema$1.Array(GovernedActionReleasePublicationCandidate).check(Schema$1.isMaxLength(request.releaseIds.length)))(rows).pipe(Effect$1.mapError(() => new PersistedRecordError({
10496
+ workspaceId: request.workspaceId,
10497
+ recordKind: "governed-action",
10498
+ recordKey: request.workspaceId,
10499
+ diagnosticCode: "governed-action-schema-invalid"
10500
+ })));
10501
+ return yield* Effect$1.forEach(candidates, ({ actionId, releaseId }) => read({
10502
+ workspaceId: request.workspaceId,
10503
+ actionId
10504
+ }).pipe(Effect$1.flatMap((record) => {
10505
+ const publication = record.envelope.releasePublication;
10506
+ const actionKind = record.envelope.proposal.request.actionKind;
10507
+ return publication !== void 0 && publication.releaseId === releaseId && record.envelope.providerId === request.providerId && (actionKind === "create-page" || actionKind === "update-page") && (record.head.state === "proposed" || record.head.state === "authorized" || record.head.state === "started" || record.head.state === "cancel-requested" || record.head.state === "unknown" || record.head.state === "cancel-requested-unknown" || record.head.state === "succeeded" && record.head.lineage._tag === "terminal" && record.head.lineage.receipt.status === "succeeded") ? Effect$1.succeed(record) : Effect$1.fail(new PersistedRecordError({
10508
+ workspaceId: request.workspaceId,
10509
+ recordKind: "governed-action",
10510
+ recordKey: actionId,
10511
+ diagnosticCode: "governed-action-identity-mismatch"
10512
+ }));
10513
+ })));
9564
10514
  })
9565
10515
  };
9566
10516
  });
@@ -9596,11 +10546,13 @@ var makeGovernedActionTransaction = Effect$1.gen(function* () {
9596
10546
  const read = (request) => reader.read(request).pipe(Effect$1.provideService(Crypto$1.Crypto, cryptoService));
9597
10547
  const readByIdempotencyKey = (request) => reader.readByIdempotencyKey(request).pipe(Effect$1.provideService(Crypto$1.Crypto, cryptoService));
9598
10548
  const readLatestTerminalByTarget = (request) => reader.readLatestTerminalByTarget(request).pipe(Effect$1.provideService(Crypto$1.Crypto, cryptoService));
10549
+ const readLatestTerminalReleasePublications = (request) => reader.readLatestTerminalReleasePublications(request).pipe(Effect$1.provideService(Crypto$1.Crypto, cryptoService));
9599
10550
  return {
9600
10551
  capture,
9601
10552
  read,
9602
10553
  readByIdempotencyKey,
9603
10554
  readLatestTerminalByTarget,
10555
+ readLatestTerminalReleasePublications,
9604
10556
  transact
9605
10557
  };
9606
10558
  });
@@ -10066,6 +11018,28 @@ var makeGovernedActionTransactionWrite = Effect$1.gen(function* () {
10066
11018
  ${input.envelope.proposal.request.actionKind},
10067
11019
  ${input.envelope.proposal.request.expectedRevision}
10068
11020
  )`;
11021
+ if (input.envelope.releasePublication !== void 0) {
11022
+ yield* sql`INSERT INTO governed_action_release_publications (
11023
+ workspace_id, action_id, provider_id, release_id, predecessor_action_id
11024
+ ) VALUES (
11025
+ ${input.envelope.workspaceId}, ${input.envelope.actionId},
11026
+ ${input.envelope.providerId}, ${input.envelope.releasePublication.releaseId},
11027
+ ${input.envelope.releasePublication.predecessorPublicationActionId ?? null}
11028
+ )`;
11029
+ if (input.envelope.providerId === "confluence") yield* sql`INSERT INTO governed_action_release_publication_slots (
11030
+ workspace_id, action_id, provider_id, release_id, predecessor_action_id
11031
+ ) VALUES (
11032
+ ${input.envelope.workspaceId}, ${input.envelope.actionId},
11033
+ ${input.envelope.providerId}, ${input.envelope.releasePublication.releaseId},
11034
+ ${input.envelope.releasePublication.predecessorPublicationActionId ?? null}
11035
+ )`;
11036
+ } else yield* sql`INSERT INTO governed_action_entity_targets (
11037
+ workspace_id, action_id, plugin_connection_id, provider_id, entity_id
11038
+ ) VALUES (
11039
+ ${input.envelope.workspaceId}, ${input.envelope.actionId},
11040
+ ${input.envelope.pluginConnectionId}, ${input.envelope.providerId},
11041
+ ${input.envelope.targetEntityId}
11042
+ )`;
10069
11043
  } else {
10070
11044
  yield* verifyRootIdentity(input, envelopeJson, root).pipe(captureMalformedGovernedActionRow(root));
10071
11045
  if (input.command._tag === "propose") return yield* inputError("conflicting-action-identity");
@@ -10198,6 +11172,13 @@ var makeGovernedActionRepository = Effect$1.gen(function* () {
10198
11172
  reason: "invalid-request"
10199
11173
  })));
10200
11174
  return yield* transaction.transact("governed-action.read-latest-terminal-by-target", transaction.readLatestTerminalByTarget(request));
11175
+ }),
11176
+ readLatestTerminalReleasePublications: Effect$1.fn("GovernedActionRepository.readLatestTerminalReleasePublications")(function* (input) {
11177
+ const request = yield* Schema$1.decodeUnknownEffect(Schema$1.toType(GovernedActionReleasePublicationReadInput))(input).pipe(Effect$1.mapError(() => new GovernedActionInputError({
11178
+ operation: "read",
11179
+ reason: "invalid-request"
11180
+ })));
11181
+ return yield* transaction.transact("governed-action.read-latest-terminal-release-publications", transaction.readLatestTerminalReleasePublications(request));
10201
11182
  })
10202
11183
  };
10203
11184
  });
@@ -16155,13 +17136,11 @@ var makeRetentionRepository = Effect$1.gen(function* () {
16155
17136
  SELECT 1 FROM agent_review_suggestion_revisions revision
16156
17137
  WHERE revision.workspace_id = job.workspace_id
16157
17138
  AND revision.source_job_id = job.job_id
16158
- AND revision.created_at > ${cutoffAt}
16159
17139
  )
16160
17140
  AND NOT EXISTS (
16161
17141
  SELECT 1 FROM agent_thread_events event
16162
17142
  WHERE event.workspace_id = job.workspace_id
16163
17143
  AND event.job_id = job.job_id
16164
- AND event.occurred_at > ${cutoffAt}
16165
17144
  )
16166
17145
  AND NOT EXISTS (
16167
17146
  SELECT 1 FROM domain_events event
@@ -16178,12 +17157,6 @@ var makeRetentionRepository = Effect$1.gen(function* () {
16178
17157
  yield* Effect$1.forEach(jobIds, (jobId) => sql`INSERT INTO retention_cleanup_claims (
16179
17158
  workspace_id, run_id, retention_class, record_key
16180
17159
  ) VALUES (${workspaceId}, ${run.runId}, 'agent-content', ${jobId})`, { discard: true });
16181
- yield* sql`DELETE FROM agent_review_suggestion_revisions
16182
- WHERE workspace_id = ${workspaceId}
16183
- AND source_job_id IN ${sql.in(jobIds)}`;
16184
- yield* sql`DELETE FROM agent_thread_events
16185
- WHERE workspace_id = ${workspaceId}
16186
- AND job_id IN ${sql.in(jobIds)}`;
16187
17160
  yield* sql`DELETE FROM agent_job_leases
16188
17161
  WHERE workspace_id = ${workspaceId}
16189
17162
  AND job_id IN ${sql.in(jobIds)}`;
@@ -16891,13 +17864,24 @@ var makePersistence = Effect.gen(function* () {
16891
17864
  appendReviewSuggestionRevision: (...args) => publicOperation("agent-job.append-review-suggestion-revision", agentJobs.appendReviewSuggestionRevision(...args)),
16892
17865
  claimNext: (...args) => publicOperation("agent-job.claim-next", agentJobs.claimNext(...args)),
16893
17866
  completeReview: (...args) => publicOperation("agent-job.complete-review", agentJobs.completeReview(...args)),
17867
+ recordReviewProgress: (...args) => publicOperation("agent-job.record-review-progress", agentJobs.recordReviewProgress(...args)),
16894
17868
  enqueue: (...args) => publicOperation("agent-job.enqueue", agentJobs.enqueue(...args)),
16895
17869
  failAttempt: (...args) => publicOperation("agent-job.fail-attempt", agentJobs.failAttempt(...args)),
16896
17870
  latestReview: (...args) => publicOperation("agent-job.latest-review", agentJobs.latestReview(...args)),
17871
+ latestReviewForPullRequest: (...args) => publicOperation("agent-job.latest-review-for-pull-request", agentJobs.latestReview({
17872
+ ...args[0],
17873
+ allowDifferentHead: true
17874
+ })),
17875
+ listRunningPrReviewAttempts: (...args) => publicOperation("agent-job.list-running-pr-review-attempts", agentJobs.listRunningPrReviewAttempts(...args)),
17876
+ attachRunningPrReviewSession: (...args) => publicOperation("agent-job.attach-running-pr-review-session", agentJobs.attachRunningPrReviewSession(...args)),
17877
+ readReviewSuggestionPublication: (...args) => publicOperation("agent-job.read-review-suggestion-publication", agentJobs.readReviewSuggestionPublication(...args)),
16897
17878
  releaseReviewSuggestionPublication: (...args) => publicOperation("agent-job.release-review-suggestion-publication", agentJobs.releaseReviewSuggestionPublication(...args)),
16898
17879
  reserveReviewSuggestionPublication: (...args) => publicOperation("agent-job.reserve-review-suggestion-publication", agentJobs.reserveReviewSuggestionPublication(...args)),
16899
17880
  recordReviewSuggestionPublication: (...args) => publicOperation("agent-job.record-review-suggestion-publication", agentJobs.recordReviewSuggestionPublication(...args)),
17881
+ reviewBudget: (...args) => publicOperation("agent-job.review-budget", agentJobs.reviewBudget(...args)),
16900
17882
  requestCancellation: (...args) => publicOperation("agent-job.request-cancellation", agentJobs.requestCancellation(...args)),
17883
+ extendReviewBudget: (...args) => publicOperation("agent-job.extend-review-budget", agentJobs.extendReviewBudget(...args)),
17884
+ interruptRunningReviews: (...args) => publicOperation("agent-job.interrupt-running-reviews", agentJobs.interruptRunningReviews(...args)),
16901
17885
  reviewThreadAfter: (...args) => publicOperation("agent-job.review-thread-after", agentJobs.reviewThreadAfter(...args)),
16902
17886
  reviewThreadBefore: (...args) => publicOperation("agent-job.review-thread-before", agentJobs.reviewThreadBefore(...args)),
16903
17887
  reviewThreadTail: (...args) => publicOperation("agent-job.review-thread-tail", agentJobs.reviewThreadTail(...args)),
@@ -16946,7 +17930,8 @@ var makePersistence = Effect.gen(function* () {
16946
17930
  commit: (...args) => publicOperation("governed-action.commit", governedActions.commit(...args)),
16947
17931
  read: (...args) => publicOperation("governed-action.read", governedActions.read(...args)),
16948
17932
  readByIdempotencyKey: (...args) => publicOperation("governed-action.read-by-idempotency-key", governedActions.readByIdempotencyKey(...args)),
16949
- readLatestTerminalByTarget: (...args) => publicOperation("governed-action.read-latest-terminal-by-target", governedActions.readLatestTerminalByTarget(...args))
17933
+ readLatestTerminalByTarget: (...args) => publicOperation("governed-action.read-latest-terminal-by-target", governedActions.readLatestTerminalByTarget(...args)),
17934
+ readLatestTerminalReleasePublications: (...args) => publicOperation("governed-action.read-latest-terminal-release-publications", governedActions.readLatestTerminalReleasePublications(...args))
16950
17935
  },
16951
17936
  people: {
16952
17937
  createPerson: (...args) => publicOperation("people.create-person", people.createPerson(...args)),
@@ -17124,10 +18109,6 @@ var AuthorizedShares = class extends Context$1.Service()("@knpkv/control-center/
17124
18109
  var DeliveryGraphInspection = class extends Context$1.Service()("@knpkv/control-center/server/api/DeliveryGraphInspection") {};
17125
18110
  /** Authenticated mutation boundary for durable relationship-repair proposals. */
17126
18111
  var RelationshipRepairProposals = class extends Context$1.Service()("@knpkv/control-center/server/api/RelationshipRepairProposals") {};
17127
- /**
17128
- * Release-aware conversational boundary. Implementations own context projection,
17129
- * provider selection, prompt hardening, cancellation, and provider error redaction.
17130
- */
17131
18112
  var ReleaseAgentTurns = class extends Context$1.Service()("@knpkv/control-center/server/api/ReleaseAgentTurns") {};
17132
18113
  /**
17133
18114
  * Provider-neutral durable release-agent boundary. Implementations derive job,
@@ -17174,7 +18155,14 @@ var RawConfluencePage = Schema$1.Struct({
17174
18155
  var RawConfluenceDraftPage = Schema$1.Struct({
17175
18156
  id: boundedString(512),
17176
18157
  status: Schema$1.Literal("draft"),
17177
- spaceId: boundedString(512)
18158
+ title: boundedString(500),
18159
+ spaceId: boundedString(512),
18160
+ parentId: Schema$1.optionalKey(Schema$1.NullOr(boundedString(512))),
18161
+ ownerId: Schema$1.optionalKey(Schema$1.NullOr(boundedString(512))),
18162
+ body: Schema$1.Struct({ atlas_doc_format: Schema$1.Struct({
18163
+ representation: Schema$1.optionalKey(Schema$1.Literal("atlas_doc_format")),
18164
+ value: Schema$1.String.check(Schema$1.isMaxLength(1048576))
18165
+ }) })
17178
18166
  });
17179
18167
  /** One bounded page of current pages from exactly one configured space. @internal */
17180
18168
  var RawConfluenceSpacePage = Schema$1.Struct({
@@ -17303,6 +18291,7 @@ var ConfluencePageAttributesV1 = Schema$1.Struct({
17303
18291
  maximum: 2
17304
18292
  }))
17305
18293
  })),
18294
+ taskUpdatesSafe: Schema$1.optionalKey(Schema$1.Boolean),
17306
18295
  contentState: Schema$1.optionalKey(Schema$1.Literals(["loaded", "lazy"]))
17307
18296
  }).check(hasMaximumPluginJsonBytes(MaximumPluginPayloadBytes));
17308
18297
  //#endregion
@@ -18115,6 +19104,6 @@ var reconcileRelationshipInferencePolicy = Effect$1.fn("RelationshipInferenceMat
18115
19104
  return receipt;
18116
19105
  });
18117
19106
  //#endregion
18118
- export { negotiatePluginDescriptorV1 as $, databaseLayer as $n, AppendReviewSuggestionRevisionInput as $t, PullRequestReviews as A, PersonRecord as An, SchemaWriteBarrierError as Ar, BlobStoreInputError as At, persistenceLayerFromDatabase as B, QuarantinedRecordMetadata as Bn, AgentJobTask as Bt, CodePipelineReads as C, ContentBlobDigest as Cn, WorkspaceSettingsNoChangesError as Cr, ProjectionRow as Ct, MediaReads as D, EntityRecord as Dn, BackupManifestError as Dr, BlobContainmentError as Dt, LiveEvents as E, EntityKind as En, BackupLimitError as Er, AgentJobRepository as Et, TimelineReads as F, ProviderFamily as Fn, AgentContextSnapshotRecord as Ft, authorizeWorkspaceSettingsGovernanceRequest as G, VendorResourceId as Gn, AgentReviewResultRecord as Gt, ReviewCommandArtifactMetadata as H, ReleaseSnapshotRecord as Hn, AgentLeaseOwner as Ht, WorkspaceSettingsAdministration as I, ProviderFamilyMatchesProvider as In, AgentEventCursor as It, digestEnvironmentReadinessCandidate as J, providerFamilyForProvider as Jn, AgentReviewThreadHistoryInput as Jt, governedHumanMutationPolicyAllows as K, WorkspaceName as Kn, AgentReviewThreadAfterInput as Kt, PluginConnection as L, QuarantineDiagnosticSummary as Ln, AgentJobInputError as Lt, ReleaseAgentJobs as M, PluginConnectionRecord as Mn, BlobTooLargeError as Mt, ReleaseAgentTurns as N, ProviderAccountDisplayName as Nn, BlobUnexpectedEofError as Nt, PluginAdministration as O, FollowedResourceDisplayName as On, BackupSqlError as Or, BlobIntegrityError as Ot, TimelineExportAudits as P, ProviderAccountRecord as Pn, AgentAttemptSequence as Pt, hasPluginCapability as Q, Database as Qn, AppendAgentEventInput as Qt, Persistence as R, QuarantineReasonCode as Rn, AgentJobPrompt as Rt, AuthorizedShares as S, QuarantineRepository as Sn, WorkspaceSettingsMutationConflictError as Sr, EvidenceRow as St, DeliveryGraphInspection as T, ContentBlobStorageClass as Tn, BackupIntegrityError as Tr, DeliveryGraphWriteBatch as Tt, ReviewCommandArtifactRepository as U, RoleAssignmentRecord as Un, AgentLeaseToken as Ut, ReviewCommandArtifactHandle as V, RecordRevision as Vn, AgentJobTaskTag as Vt, WorkspaceSettingsRepository as W, VendorAccountId as Wn, AgentReviewResultInput as Wt, digestReleaseReadinessCandidate as X, mapPersistenceOperation as Xn, AgentThreadEvent as Xt, digestReadinessRule as Y, BlobClassification as Yn, AgentReviewThreadTailInput as Yt, HOST_PLUGIN_CAPABILITY_VERSIONS as Z, readChanges as Zn, AgentThreadEventPageSize as Zt, ApplicationConflict as _, ReviewSuggestionPublicationDigest as _n, ReproducibleContentUnavailableError as _r, makeGovernedActionEnvelope as _t, firstPartySyncStreamKey as a, EnqueueAgentJobTask as an, PersistenceConfig as ar, makeGovernedActionTransactionWrite as at, ApplicationResourceNotFound as b, SecretRef as bn, SourceIdentityMismatchError as br, makeDeliveryGraphDecoders as bt, RawConfluenceAttachmentPage as c, MAXIMUM_AGENT_ATTEMPT_OUTPUT_BYTES as cn, DatabaseInitializationError as cr, canonicalizeGovernedActionJson as ct, RawConfluencePage as d, PrReviewThreadContextSnapshot as dn, PersistenceConfigError as dr, digestGovernedActionPayload as dt, ClaimAgentJobInput as en, validateExistingControlCenterDatabase as er, PluginPageId as et, RawConfluenceSpacePage as f, PrReviewThreadSubject as fn, PersistenceOperationError as fr, digestGovernedActionPolicyDefinition as ft, RawConfluenceWatcherPage as g, ReserveReviewSuggestionPublicationInput as gn, RecordNotFoundError as gr, encodeGovernedActionUnknownOutcome as gt, RawConfluenceVersionPage as h, ReleaseReviewSuggestionPublicationInput as hn, RecordAlreadyExistsError as hr, encodeGovernedActionDispatchOutcome as ht, DomainEventWakeups as i, EnqueueAgentJobInput as in, LocalDatabaseUrl as ir, StoredPluginConfigurationKey as it, RelationshipRepairProposals as j, PluginConnectionDisplayName as jn, BlobDigest as jr, BlobStoreIoError as jt, PortfolioSnapshots as k, FollowedResourceRecord as kn, BackupStorageError as kr, BlobNotFoundError as kt, RawConfluenceCurrentUser as l, MAXIMUM_AGENT_JOB_PROMPT_LENGTH as ln, MAXIMUM_PERSISTENCE_RECORD_KEY_LENGTH as lr, digestCanonicalGovernedActionJson as lt, RawConfluenceVersion as m, RecordReviewSuggestionPublicationInput as mn, QuarantineWriteError as mr, digestGovernedActionTransitionCommand as mt, reconcileRelationshipInferencePolicy as n, CompleteAgentReviewInput as nn, validateCurrentSchema as nr, PluginStreamKey as nt, supportsFirstPartySynchronization as o, LatestAgentReviewInput as on, decodePersistenceConfig as or, makeGovernedActionTransaction as ot, RawConfluenceUsers as p, ReadReviewSuggestionRevisionsInput as pn, PluginConnectionLimitError as pr, digestGovernedActionPolicyEvaluation as pt, ReadinessDigestError as q, WorkspaceRecord as qn, AgentReviewThreadBeforeInput as qt, appendPortfolioInvalidation as r, EMPTY_PR_REVIEW_THREAD_CONTEXT as rn, BlobRoot as rr, StoredPluginConfiguration as rt, ConfluencePageAttributesV1 as s, LatestAgentReviewRecord as sn, ContentMetadataMismatchError as sr, GovernedActionDigestError as st, materializeRelationshipInference as t, ClaimedAgentJob as tn, CURRENT_SCHEMA_VERSION as tr, PluginRecordKey as tt, RawConfluenceDraftPage as u, MAXIMUM_AGENT_THREAD_EVENT_PAGE_SIZE as un, PersistedRecordError as ur, digestGovernedActionEvidenceSet as ut, ApplicationInvalidRequest as v, ReviewSuggestionPublicationReservation as vn, RevisionConflictError as vr, verifyGovernedActionEnvelope as vt, CompleteDiffReads as w, ContentBlobMetadata as wn, BackupInputError as wr, decodeRows$3 as wt, ApplicationServiceUnavailable as x, makePersistedRowQuarantine as xn, WorkspaceSettingsGovernanceError as xr, ClaimRow as xt, ApplicationRateLimited as y, blobPath as yn, SecretReferenceScopeConflictError as yr, GovernedActionCommitInput as yt, persistenceLayer as z, QuarantineRecordKind as zn, AgentJobState as zt };
19107
+ export { negotiatePluginDescriptorV1 as $, QuarantineReasonCode as $n, AppendAgentEventInput as $t, PullRequestReviews as A, ReviewSuggestionPublicationDigest as An, RecordAlreadyExistsError as Ar, BlobNotFoundError as At, persistenceLayerFromDatabase as B, ContentBlobStorageClass as Bn, BackupIntegrityError as Br, AgentJobState as Bt, CodePipelineReads as C, ReadReviewSuggestionRevisionsInput as Cn, DatabaseInitializationError as Cr, ProjectionRow as Ct, MediaReads as D, ReserveReviewSuggestionPublicationInput as Dn, PersistenceOperationError as Dr, PROCESS_RESTART_INTERRUPTION_MESSAGE as Dt, LiveEvents as E, ReleaseReviewSuggestionPublicationInput as En, PersistenceConfigError as Er, AgentJobRepository as Et, TimelineReads as F, SecretRef as Fn, SourceIdentityMismatchError as Fr, AgentAttemptSequence as Ft, authorizeWorkspaceSettingsGovernanceRequest as G, PersonRecord as Gn, SchemaWriteBarrierError as Gr, AgentReviewResultInput as Gt, ReviewCommandArtifactMetadata as H, EntityRecord as Hn, BackupManifestError as Hr, AgentJobTaskTag as Ht, WorkspaceSettingsAdministration as I, makePersistedRowQuarantine as In, WorkspaceSettingsGovernanceError as Ir, AgentContextSnapshotRecord as It, digestEnvironmentReadinessCandidate as J, ProviderAccountDisplayName as Jn, AgentReviewThreadBeforeInput as Jt, governedHumanMutationPolicyAllows as K, PluginConnectionDisplayName as Kn, BlobDigest as Kr, AgentReviewResultRecord as Kt, PluginConnection as L, QuarantineRepository as Ln, WorkspaceSettingsMutationConflictError as Lr, AgentEventCursor as Lt, ReleaseAgentJobs as M, ReviewSuggestionRevisionLeaseFence as Mn, ReproducibleContentUnavailableError as Mr, BlobStoreIoError as Mt, ReleaseAgentTurns as N, RunningPrReviewAttempt as Nn, RevisionConflictError as Nr, BlobTooLargeError as Nt, PluginAdministration as O, ReviewSuggestionPublicationCommentId as On, PluginConnectionLimitError as Or, BlobContainmentError as Ot, TimelineExportAudits as P, blobPath as Pn, SecretReferenceScopeConflictError as Pr, BlobUnexpectedEofError as Pt, hasPluginCapability as Q, QuarantineDiagnosticSummary as Qn, AgentThreadEventPageSize as Qt, Persistence as R, ContentBlobDigest as Rn, WorkspaceSettingsNoChangesError as Rr, AgentJobInputError as Rt, AuthorizedShares as S, ReadReviewSuggestionPublicationInput as Sn, ContentMetadataMismatchError as Sr, EvidenceRow as St, DeliveryGraphInspection as T, RecordReviewSuggestionPublicationInput as Tn, PersistedRecordError as Tr, DeliveryGraphWriteBatch as Tt, ReviewCommandArtifactRepository as U, FollowedResourceDisplayName as Un, BackupSqlError as Ur, AgentLeaseOwner as Ut, ReviewCommandArtifactHandle as V, EntityKind as Vn, BackupLimitError as Vr, AgentJobTask as Vt, WorkspaceSettingsRepository as W, FollowedResourceRecord as Wn, BackupStorageError as Wr, AgentLeaseToken as Wt, digestReleaseReadinessCandidate as X, ProviderFamily as Xn, AgentReviewThreadTailInput as Xt, digestReadinessRule as Y, ProviderAccountRecord as Yn, AgentReviewThreadHistoryInput as Yt, HOST_PLUGIN_CAPABILITY_VERSIONS as Z, ProviderFamilyMatchesProvider as Zn, AgentThreadEvent as Zt, ApplicationConflict as _, MAXIMUM_REVIEW_BUDGET_MILLIS as _n, validateCurrentSchema as _r, makeGovernedActionEnvelope as _t, firstPartySyncStreamKey as a, CompleteTargetedReviewInput as an, VendorAccountId as ar, makeGovernedActionTransactionWrite as at, ApplicationResourceNotFound as b, ReadReviewBudgetInput as bn, PersistenceConfig as br, makeDeliveryGraphDecoders as bt, RawConfluenceAttachmentPage as c, EnqueueAgentJobTask as cn, WorkspaceRecord as cr, canonicalizeGovernedActionJson as ct, RawConfluencePage as d, LatestAgentReviewInput as dn, mapPersistenceOperation as dr, digestGovernedActionPayload as dt, AppendReviewSuggestionRevisionInput as en, QuarantineRecordKind as er, PluginPageId as et, RawConfluenceSpacePage as f, LatestAgentReviewRecord as fn, readChanges as fr, digestGovernedActionPolicyDefinition as ft, RawConfluenceWatcherPage as g, MAXIMUM_REVIEW_BUDGET_EXTENSION_COUNT as gn, CURRENT_SCHEMA_VERSION as gr, encodeGovernedActionUnknownOutcome as gt, RawConfluenceVersionPage as h, MAXIMUM_AGENT_THREAD_EVENT_PAGE_SIZE as hn, validateExistingControlCenterDatabase as hr, encodeGovernedActionDispatchOutcome as ht, DomainEventWakeups as i, CompleteAgentReviewInput as in, RoleAssignmentRecord as ir, StoredPluginConfigurationKey as it, RelationshipRepairProposals as j, ReviewSuggestionPublicationReservation as jn, RecordNotFoundError as jr, BlobStoreInputError as jt, PortfolioSnapshots as k, ReviewSuggestionPublicationCommentLocator as kn, QuarantineWriteError as kr, BlobIntegrityError as kt, RawConfluenceCurrentUser as l, ExtendReviewBudgetInput as ln, providerFamilyForProvider as lr, digestCanonicalGovernedActionJson as lt, RawConfluenceVersion as m, MAXIMUM_AGENT_JOB_PROMPT_LENGTH as mn, databaseLayer as mr, digestGovernedActionTransitionCommand as mt, reconcileRelationshipInferencePolicy as n, ClaimAgentJobInput as nn, RecordRevision as nr, PluginStreamKey as nt, supportsFirstPartySynchronization as o, EMPTY_PR_REVIEW_THREAD_CONTEXT as on, VendorResourceId as or, makeGovernedActionTransaction as ot, RawConfluenceUsers as p, MAXIMUM_AGENT_ATTEMPT_OUTPUT_BYTES as pn, Database as pr, digestGovernedActionPolicyEvaluation as pt, ReadinessDigestError as q, PluginConnectionRecord as qn, AgentReviewThreadAfterInput as qt, appendPortfolioInvalidation as r, ClaimedAgentJob as rn, ReleaseSnapshotRecord as rr, StoredPluginConfiguration as rt, ConfluencePageAttributesV1 as s, EnqueueAgentJobInput as sn, WorkspaceName as sr, GovernedActionDigestError as st, materializeRelationshipInference as t, AttachRunningPrReviewSessionInput as tn, QuarantinedRecordMetadata as tr, PluginRecordKey as tt, RawConfluenceDraftPage as u, InterruptRunningReviewsInput as un, BlobClassification as ur, digestGovernedActionEvidenceSet as ut, ApplicationInvalidRequest as v, PrReviewThreadContextSnapshot as vn, BlobRoot as vr, verifyGovernedActionEnvelope as vt, CompleteDiffReads as w, RecordAgentReviewProgressInput as wn, MAXIMUM_PERSISTENCE_RECORD_KEY_LENGTH as wr, decodeRows$3 as wt, ApplicationServiceUnavailable as x, ReadReviewSuggestionPublication as xn, decodePersistenceConfig as xr, ClaimRow as xt, ApplicationRateLimited as y, PrReviewThreadSubject as yn, LocalDatabaseUrl as yr, GovernedActionCommitInput as yt, persistenceLayer as z, ContentBlobMetadata as zn, BackupInputError as zr, AgentJobPrompt as zt };
18119
19108
 
18120
- //# sourceMappingURL=relationshipInferenceMaterialization-DYBcaWhQ.js.map
19109
+ //# sourceMappingURL=relationshipInferenceMaterialization-Dyix96px.js.map