@kbediako/codex-orchestrator 0.1.38 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (311) hide show
  1. package/.agents/plugins/marketplace.json +20 -0
  2. package/README.md +46 -317
  3. package/bin/codex-orchestrator.js +161 -0
  4. package/codex.orchestrator.json +149 -13
  5. package/dist/bin/codex-orchestrator.js +797 -1154
  6. package/dist/orchestrator/src/cli/adapters/CommandBuilder.js +50 -0
  7. package/dist/orchestrator/src/cli/adapters/CommandPlanner.js +22 -4
  8. package/dist/orchestrator/src/cli/adapters/CommandReviewer.js +3 -3
  9. package/dist/orchestrator/src/cli/adapters/CommandTester.js +2 -2
  10. package/dist/orchestrator/src/cli/adapters/cloudFailureDiagnostics.js +295 -11
  11. package/dist/orchestrator/src/cli/coStatusAttachCliShell.js +402 -0
  12. package/dist/orchestrator/src/cli/coStatusCliShell.js +451 -0
  13. package/dist/orchestrator/src/cli/coStatusOperatorAutopilotCliShell.js +120 -0
  14. package/dist/orchestrator/src/cli/codexCliShell.js +119 -0
  15. package/dist/orchestrator/src/cli/codexDefaultsSetup.js +265 -36
  16. package/dist/orchestrator/src/cli/config/delegationConfig.js +317 -5
  17. package/dist/orchestrator/src/cli/config/repoConfigPolicy.js +2 -3
  18. package/dist/orchestrator/src/cli/config/userConfig.js +28 -13
  19. package/dist/orchestrator/src/cli/control/authenticatedControlRouteGate.js +69 -0
  20. package/dist/orchestrator/src/cli/control/authenticatedRouteComposition.js +267 -0
  21. package/dist/orchestrator/src/cli/control/authenticatedRouteController.js +5 -0
  22. package/dist/orchestrator/src/cli/control/authenticatedRouteDispatcher.js +41 -0
  23. package/dist/orchestrator/src/cli/control/compatibilityIssuePresenter.js +1035 -0
  24. package/dist/orchestrator/src/cli/control/confirmationApproveController.js +62 -0
  25. package/dist/orchestrator/src/cli/control/confirmationCreateController.js +69 -0
  26. package/dist/orchestrator/src/cli/control/confirmationIssueConsumeController.js +43 -0
  27. package/dist/orchestrator/src/cli/control/confirmationListController.js +22 -0
  28. package/dist/orchestrator/src/cli/control/confirmationValidateController.js +58 -0
  29. package/dist/orchestrator/src/cli/control/confirmations.js +25 -3
  30. package/dist/orchestrator/src/cli/control/controlActionCancelConfirmation.js +65 -0
  31. package/dist/orchestrator/src/cli/control/controlActionController.js +77 -0
  32. package/dist/orchestrator/src/cli/control/controlActionControllerSequencing.js +161 -0
  33. package/dist/orchestrator/src/cli/control/controlActionExecution.js +142 -0
  34. package/dist/orchestrator/src/cli/control/controlActionFinalization.js +43 -0
  35. package/dist/orchestrator/src/cli/control/controlActionOutcome.js +60 -0
  36. package/dist/orchestrator/src/cli/control/controlActionPreflight.js +476 -0
  37. package/dist/orchestrator/src/cli/control/controlAuthenticatedRouteHandoff.js +57 -0
  38. package/dist/orchestrator/src/cli/control/controlBootstrapAssembly.js +39 -0
  39. package/dist/orchestrator/src/cli/control/controlBootstrapMetadataPersistence.js +16 -0
  40. package/dist/orchestrator/src/cli/control/controlEventTransport.js +49 -0
  41. package/dist/orchestrator/src/cli/control/controlExpiryLifecycle.js +102 -0
  42. package/dist/orchestrator/src/cli/control/controlHostOwnership.js +480 -0
  43. package/dist/orchestrator/src/cli/control/controlHostSupervision.js +630 -0
  44. package/dist/orchestrator/src/cli/control/controlOversightFacade.js +8 -0
  45. package/dist/orchestrator/src/cli/control/controlOversightReadContract.js +1 -0
  46. package/dist/orchestrator/src/cli/control/controlOversightReadService.js +16 -0
  47. package/dist/orchestrator/src/cli/control/controlOversightUpdateContract.js +1 -0
  48. package/dist/orchestrator/src/cli/control/controlPersistenceFiles.js +6 -0
  49. package/dist/orchestrator/src/cli/control/controlQuestionChildResolution.js +18 -0
  50. package/dist/orchestrator/src/cli/control/controlRequestContext.js +42 -0
  51. package/dist/orchestrator/src/cli/control/controlRequestController.js +9 -0
  52. package/dist/orchestrator/src/cli/control/controlRequestPredispatch.js +17 -0
  53. package/dist/orchestrator/src/cli/control/controlRequestRouteDispatch.js +44 -0
  54. package/dist/orchestrator/src/cli/control/controlRuntime.js +1003 -0
  55. package/dist/orchestrator/src/cli/control/controlServer.js +23 -1456
  56. package/dist/orchestrator/src/cli/control/controlServerAuditAndErrorHelpers.js +115 -0
  57. package/dist/orchestrator/src/cli/control/controlServerAuthenticatedRouteBranch.js +29 -0
  58. package/dist/orchestrator/src/cli/control/controlServerBootstrapLifecycle.js +30 -0
  59. package/dist/orchestrator/src/cli/control/controlServerBootstrapStartSequence.js +21 -0
  60. package/dist/orchestrator/src/cli/control/controlServerOwnedRuntimeLifecycle.js +67 -0
  61. package/dist/orchestrator/src/cli/control/controlServerPublicLifecycle.js +756 -0
  62. package/dist/orchestrator/src/cli/control/controlServerPublicRouteHelpers.js +86 -0
  63. package/dist/orchestrator/src/cli/control/controlServerReadyInstanceLifecycle.js +25 -0
  64. package/dist/orchestrator/src/cli/control/controlServerReadyInstanceStartup.js +18 -0
  65. package/dist/orchestrator/src/cli/control/controlServerRequestBodyHelpers.js +37 -0
  66. package/dist/orchestrator/src/cli/control/controlServerRequestShell.js +40 -0
  67. package/dist/orchestrator/src/cli/control/controlServerRequestShellBinding.js +17 -0
  68. package/dist/orchestrator/src/cli/control/controlServerSeedLoading.js +27 -0
  69. package/dist/orchestrator/src/cli/control/controlServerSeededRuntimeAssembly.js +186 -0
  70. package/dist/orchestrator/src/cli/control/controlServerStartupInputPreparation.js +31 -0
  71. package/dist/orchestrator/src/cli/control/controlServerStartupSequence.js +49 -0
  72. package/dist/orchestrator/src/cli/control/controlState.js +233 -2
  73. package/dist/orchestrator/src/cli/control/controlStatusDashboard.js +1904 -0
  74. package/dist/orchestrator/src/cli/control/controlTelegramBridgeBootstrapLifecycle.js +22 -0
  75. package/dist/orchestrator/src/cli/control/controlTelegramBridgeLifecycle.js +67 -0
  76. package/dist/orchestrator/src/cli/control/controlTelegramBridgeOversightFacadeFactory.js +8 -0
  77. package/dist/orchestrator/src/cli/control/controlTelegramCommandController.js +49 -0
  78. package/dist/orchestrator/src/cli/control/controlTelegramDispatchRead.js +40 -0
  79. package/dist/orchestrator/src/cli/control/controlTelegramPollingController.js +89 -0
  80. package/dist/orchestrator/src/cli/control/controlTelegramProjectionNotificationController.js +29 -0
  81. package/dist/orchestrator/src/cli/control/controlTelegramPushState.js +63 -0
  82. package/dist/orchestrator/src/cli/control/controlTelegramQuestionRead.js +13 -0
  83. package/dist/orchestrator/src/cli/control/controlTelegramReadController.js +216 -0
  84. package/dist/orchestrator/src/cli/control/controlTelegramUpdateHandler.js +63 -0
  85. package/dist/orchestrator/src/cli/control/controlWatcher.js +73 -5
  86. package/dist/orchestrator/src/cli/control/delegationRegisterController.js +35 -0
  87. package/dist/orchestrator/src/cli/control/dynamicToolBridgePolicy.js +139 -0
  88. package/dist/orchestrator/src/cli/control/eventsSseController.js +12 -0
  89. package/dist/orchestrator/src/cli/control/linearBudgetState.js +1789 -0
  90. package/dist/orchestrator/src/cli/control/linearDispatchSource.js +1137 -0
  91. package/dist/orchestrator/src/cli/control/linearGraphqlClient.js +150 -0
  92. package/dist/orchestrator/src/cli/control/linearRateLimit.js +102 -0
  93. package/dist/orchestrator/src/cli/control/linearWebhookController.js +499 -0
  94. package/dist/orchestrator/src/cli/control/liveLinearAdvisoryRuntime.js +70 -0
  95. package/dist/orchestrator/src/cli/control/observabilityApiController.js +173 -0
  96. package/dist/orchestrator/src/cli/control/observabilityReadModel.js +500 -0
  97. package/dist/orchestrator/src/cli/control/observabilitySurface.js +284 -0
  98. package/dist/orchestrator/src/cli/control/observabilityUpdateNotifier.js +22 -0
  99. package/dist/orchestrator/src/cli/control/operatorDashboardPresenter.js +252 -0
  100. package/dist/orchestrator/src/cli/control/providerAgentCapacity.js +70 -0
  101. package/dist/orchestrator/src/cli/control/providerControlHostFreshnessGauge.js +1068 -0
  102. package/dist/orchestrator/src/cli/control/providerIntakeState.js +473 -0
  103. package/dist/orchestrator/src/cli/control/providerIssueHandoff.js +6811 -0
  104. package/dist/orchestrator/src/cli/control/providerIssueObservability.js +1348 -0
  105. package/dist/orchestrator/src/cli/control/providerIssueRetryQueue.js +84 -0
  106. package/dist/orchestrator/src/cli/control/providerLinearRuntimeProof.js +588 -0
  107. package/dist/orchestrator/src/cli/control/providerLinearScreenshotProof.js +473 -0
  108. package/dist/orchestrator/src/cli/control/providerLinearWorkerTruth.js +383 -0
  109. package/dist/orchestrator/src/cli/control/providerLinearWorkflowAudit.js +254 -0
  110. package/dist/orchestrator/src/cli/control/providerLinearWorkflowFacade.js +5573 -0
  111. package/dist/orchestrator/src/cli/control/providerLinearWorkflowStates.js +115 -0
  112. package/dist/orchestrator/src/cli/control/providerMergeCloseout.js +1868 -0
  113. package/dist/orchestrator/src/cli/control/providerOperatorAutopilot.js +1580 -0
  114. package/dist/orchestrator/src/cli/control/providerOperatorAutopilotLifecycle.js +154 -0
  115. package/dist/orchestrator/src/cli/control/providerOperatorAutopilotLocalRolloutExecution.js +1006 -0
  116. package/dist/orchestrator/src/cli/control/providerPollingHealth.js +435 -0
  117. package/dist/orchestrator/src/cli/control/providerTerminalCleanup.js +516 -0
  118. package/dist/orchestrator/src/cli/control/providerWorkerHosts.js +191 -0
  119. package/dist/orchestrator/src/cli/control/providerWorkflowConfigStore.js +515 -0
  120. package/dist/orchestrator/src/cli/control/questionChildResolutionAdapter.js +361 -0
  121. package/dist/orchestrator/src/cli/control/questionQueueController.js +181 -0
  122. package/dist/orchestrator/src/cli/control/questionReadRetryDeduplication.js +9 -0
  123. package/dist/orchestrator/src/cli/control/questionReadSequence.js +10 -0
  124. package/dist/orchestrator/src/cli/control/securityViolationController.js +27 -0
  125. package/dist/orchestrator/src/cli/control/selectedRunProjection.js +1885 -0
  126. package/dist/orchestrator/src/cli/control/telegramOversightApiClient.js +48 -0
  127. package/dist/orchestrator/src/cli/control/telegramOversightBridge.js +180 -0
  128. package/dist/orchestrator/src/cli/control/telegramOversightBridgeProjectionDeliveryQueue.js +25 -0
  129. package/dist/orchestrator/src/cli/control/telegramOversightBridgeRuntimeLifecycle.js +45 -0
  130. package/dist/orchestrator/src/cli/control/telegramOversightBridgeStateStore.js +77 -0
  131. package/dist/orchestrator/src/cli/control/telegramOversightControlActionApiClient.js +45 -0
  132. package/dist/orchestrator/src/cli/control/trackerDispatchPilot.js +439 -0
  133. package/dist/orchestrator/src/cli/control/uiDataController.js +34 -0
  134. package/dist/orchestrator/src/cli/control/uiSessionController.js +100 -0
  135. package/dist/orchestrator/src/cli/controlHostCliShell.js +860 -0
  136. package/dist/orchestrator/src/cli/controlHostFreshnessGaugeCliShell.js +129 -0
  137. package/dist/orchestrator/src/cli/controlHostSupervisionCliShell.js +2127 -0
  138. package/dist/orchestrator/src/cli/delegationCliShell.js +62 -0
  139. package/dist/orchestrator/src/cli/delegationServer.js +567 -678
  140. package/dist/orchestrator/src/cli/delegationServerCliShell.js +52 -0
  141. package/dist/orchestrator/src/cli/delegationServerQuestionFlowShell.js +228 -0
  142. package/dist/orchestrator/src/cli/delegationServerToolDispatchShell.js +411 -0
  143. package/dist/orchestrator/src/cli/delegationServerTransport.js +274 -0
  144. package/dist/orchestrator/src/cli/delegationSetup.js +51 -171
  145. package/dist/orchestrator/src/cli/devtoolsCliShell.js +34 -0
  146. package/dist/orchestrator/src/cli/doctor.js +678 -164
  147. package/dist/orchestrator/src/cli/doctorCliRequestShell.js +72 -0
  148. package/dist/orchestrator/src/cli/doctorCliShell.js +138 -0
  149. package/dist/orchestrator/src/cli/doctorUsage.js +119 -15
  150. package/dist/orchestrator/src/cli/exec/experience.js +16 -2
  151. package/dist/orchestrator/src/cli/exec/summary.js +3 -0
  152. package/dist/orchestrator/src/cli/execCliShell.js +51 -0
  153. package/dist/orchestrator/src/cli/flowCliRequestShell.js +44 -0
  154. package/dist/orchestrator/src/cli/flowCliShell.js +239 -0
  155. package/dist/orchestrator/src/cli/frontendTestCliRequestShell.js +80 -0
  156. package/dist/orchestrator/src/cli/frontendTestCliShell.js +41 -0
  157. package/dist/orchestrator/src/cli/init.js +95 -1
  158. package/dist/orchestrator/src/cli/initCliShell.js +50 -0
  159. package/dist/orchestrator/src/cli/linearCliShell.js +1200 -0
  160. package/dist/orchestrator/src/cli/mcpEnableCliShell.js +132 -0
  161. package/dist/orchestrator/src/cli/metrics/metricsAggregator.js +3 -2
  162. package/dist/orchestrator/src/cli/metrics/metricsRecorder.js +56 -0
  163. package/dist/orchestrator/src/cli/orchestrator.js +66 -1376
  164. package/dist/orchestrator/src/cli/planCliShell.js +19 -0
  165. package/dist/orchestrator/src/cli/prCliShell.js +41 -0
  166. package/dist/orchestrator/src/cli/providerLinearChildLanePhaseContract.js +204 -0
  167. package/dist/orchestrator/src/cli/providerLinearChildLaneRunner.js +1835 -0
  168. package/dist/orchestrator/src/cli/providerLinearChildLaneShell.js +2420 -0
  169. package/dist/orchestrator/src/cli/providerLinearChildStreamShell.js +385 -0
  170. package/dist/orchestrator/src/cli/providerLinearWorkerRunner.js +6834 -0
  171. package/dist/orchestrator/src/cli/resumeCliShell.js +14 -0
  172. package/dist/orchestrator/src/cli/reviewCliLaunchShell.js +72 -0
  173. package/dist/orchestrator/src/cli/rlm/alignment.js +3 -3
  174. package/dist/orchestrator/src/cli/rlm/context.js +94 -7
  175. package/dist/orchestrator/src/cli/rlm/rlmCodexRuntimeShell.js +546 -0
  176. package/dist/orchestrator/src/cli/rlm/symbolic.js +4 -2
  177. package/dist/orchestrator/src/cli/rlmCliRequestShell.js +42 -0
  178. package/dist/orchestrator/src/cli/rlmCompletionCliShell.js +46 -0
  179. package/dist/orchestrator/src/cli/rlmLaunchCliShell.js +51 -0
  180. package/dist/orchestrator/src/cli/rlmRunner.js +83 -523
  181. package/dist/orchestrator/src/cli/run/blockMemory.js +500 -0
  182. package/dist/orchestrator/src/cli/run/manifest.js +410 -73
  183. package/dist/orchestrator/src/cli/run/manifestPersister.js +45 -14
  184. package/dist/orchestrator/src/cli/run/runMemoryController.js +216 -0
  185. package/dist/orchestrator/src/cli/run/source0.js +690 -0
  186. package/dist/orchestrator/src/cli/run/workspacePath.js +101 -0
  187. package/dist/orchestrator/src/cli/runtime/mode.js +2 -1
  188. package/dist/orchestrator/src/cli/runtime/provider.js +39 -2
  189. package/dist/orchestrator/src/cli/selfCheckCliShell.js +12 -0
  190. package/dist/orchestrator/src/cli/services/commandRunner.js +698 -18
  191. package/dist/orchestrator/src/cli/services/execRuntime.js +66 -1
  192. package/dist/orchestrator/src/cli/services/orchestratorAutoScoutEvidenceRecorder.js +71 -0
  193. package/dist/orchestrator/src/cli/services/orchestratorCloudBranchResolution.js +8 -0
  194. package/dist/orchestrator/src/cli/services/orchestratorCloudEnvironmentResolution.js +22 -0
  195. package/dist/orchestrator/src/cli/services/orchestratorCloudExecutionLifecycleShell.js +39 -0
  196. package/dist/orchestrator/src/cli/services/orchestratorCloudPromptBuilder.js +37 -0
  197. package/dist/orchestrator/src/cli/services/orchestratorCloudRouteFallbackContract.js +45 -0
  198. package/dist/orchestrator/src/cli/services/orchestratorCloudRouteShell.js +36 -0
  199. package/dist/orchestrator/src/cli/services/orchestratorCloudTargetExecutor.js +277 -0
  200. package/dist/orchestrator/src/cli/services/orchestratorControlPlaneLifecycle.js +98 -0
  201. package/dist/orchestrator/src/cli/services/orchestratorControlPlaneLifecycleShell.js +54 -0
  202. package/dist/orchestrator/src/cli/services/orchestratorExecutionLifecycle.js +112 -0
  203. package/dist/orchestrator/src/cli/services/orchestratorExecutionModePolicy.js +27 -0
  204. package/dist/orchestrator/src/cli/services/orchestratorExecutionRouteAdapterShell.js +59 -0
  205. package/dist/orchestrator/src/cli/services/orchestratorExecutionRouteDecisionShell.js +57 -0
  206. package/dist/orchestrator/src/cli/services/orchestratorExecutionRouteState.js +21 -0
  207. package/dist/orchestrator/src/cli/services/orchestratorExecutionRouter.js +2 -0
  208. package/dist/orchestrator/src/cli/services/orchestratorLocalPipelineExecutor.js +149 -0
  209. package/dist/orchestrator/src/cli/services/orchestratorLocalRouteShell.js +63 -0
  210. package/dist/orchestrator/src/cli/services/orchestratorPlanShell.js +54 -0
  211. package/dist/orchestrator/src/cli/services/orchestratorPlanTargetTracker.js +16 -0
  212. package/dist/orchestrator/src/cli/services/orchestratorResumePreparationShell.js +84 -0
  213. package/dist/orchestrator/src/cli/services/orchestratorResumeTokenValidation.js +15 -0
  214. package/dist/orchestrator/src/cli/services/orchestratorRunLifecycleCompletion.js +31 -0
  215. package/dist/orchestrator/src/cli/services/orchestratorRunLifecycleExecutionRegistration.js +37 -0
  216. package/dist/orchestrator/src/cli/services/orchestratorRunLifecycleOrchestrationShell.js +83 -0
  217. package/dist/orchestrator/src/cli/services/orchestratorRunLifecycleTaskManagerShell.js +37 -0
  218. package/dist/orchestrator/src/cli/services/orchestratorRuntimeManifestMutation.js +20 -0
  219. package/dist/orchestrator/src/cli/services/orchestratorStartPreparationShell.js +56 -0
  220. package/dist/orchestrator/src/cli/services/orchestratorStatusShell.js +70 -0
  221. package/dist/orchestrator/src/cli/services/pipelineResolver.js +7 -3
  222. package/dist/orchestrator/src/cli/services/plannerMemory.js +119 -0
  223. package/dist/orchestrator/src/cli/services/runPreparation.js +7 -3
  224. package/dist/orchestrator/src/cli/services/runSummaryWriter.js +9 -0
  225. package/dist/orchestrator/src/cli/setupBootstrapShell.js +114 -0
  226. package/dist/orchestrator/src/cli/setupCliShell.js +51 -0
  227. package/dist/orchestrator/src/cli/skillsCliShell.js +56 -0
  228. package/dist/orchestrator/src/cli/startCliRequestShell.js +53 -0
  229. package/dist/orchestrator/src/cli/startCliShell.js +68 -0
  230. package/dist/orchestrator/src/cli/statusCliShell.js +22 -0
  231. package/dist/orchestrator/src/cli/utils/authProvenanceFingerprint.js +27 -0
  232. package/dist/orchestrator/src/cli/utils/cloudPreflight.js +285 -7
  233. package/dist/orchestrator/src/cli/utils/codexFeatures.js +60 -0
  234. package/dist/orchestrator/src/cli/utils/delegationConfigParser.js +250 -0
  235. package/dist/orchestrator/src/cli/utils/delegationMcpHealth.js +1382 -0
  236. package/dist/orchestrator/src/cli/utils/devtools.js +2 -54
  237. package/dist/orchestrator/src/cli/utils/mcpServerEntry.js +53 -0
  238. package/dist/orchestrator/src/cli/utils/packageProgramResolver.js +151 -0
  239. package/dist/orchestrator/src/cli/utils/providerOverrideEnv.js +71 -0
  240. package/dist/orchestrator/src/cli/utils/trailingJsonObject.js +59 -0
  241. package/dist/orchestrator/src/learning/crystalizer.js +2 -2
  242. package/dist/orchestrator/src/manager.js +74 -4
  243. package/dist/orchestrator/src/persistence/ExperienceStore.js +233 -49
  244. package/dist/orchestrator/src/persistence/TaskStateStore.js +6 -6
  245. package/dist/orchestrator/src/persistence/lockFile.js +70 -4
  246. package/dist/orchestrator/src/persistence/sanitizeIdentifier.js +39 -0
  247. package/dist/orchestrator/src/sync/createCloudSyncWorker.js +3 -2
  248. package/dist/orchestrator/src/utils/atomicWrite.js +17 -2
  249. package/dist/packages/orchestrator/src/exec/unified-exec.js +99 -6
  250. package/dist/packages/orchestrator/src/instructions/promptPacks.js +150 -19
  251. package/dist/packages/sdk-node/src/orchestrator.js +137 -13
  252. package/dist/packages/shared/config/designConfig.js +8 -1
  253. package/dist/packages/shared/streams/stdio.js +1 -1
  254. package/dist/scripts/design/pipeline/permit.js +15 -0
  255. package/dist/scripts/lib/docs-catalog.js +399 -0
  256. package/dist/scripts/lib/docs-helpers.js +87 -5
  257. package/dist/scripts/lib/pr-watch-merge.js +1088 -80
  258. package/dist/scripts/lib/provider-run-contract.js +26 -0
  259. package/dist/scripts/lib/review-command-intent-classification.js +532 -0
  260. package/dist/scripts/lib/review-command-probe-classification.js +385 -0
  261. package/dist/scripts/lib/review-execution-boundary-preflight.js +279 -0
  262. package/dist/scripts/lib/review-execution-runtime.js +753 -0
  263. package/dist/scripts/lib/review-execution-state.js +1144 -0
  264. package/dist/scripts/lib/review-execution-telemetry.js +215 -0
  265. package/dist/scripts/lib/review-inspection-target-parsing.js +78 -0
  266. package/dist/scripts/lib/review-launch-attempt.js +601 -0
  267. package/dist/scripts/lib/review-meta-surface-boundary-analysis.js +300 -0
  268. package/dist/scripts/lib/review-meta-surface-normalization.js +746 -0
  269. package/dist/scripts/lib/review-non-interactive-handoff.js +61 -0
  270. package/dist/scripts/lib/review-prompt-context.js +376 -0
  271. package/dist/scripts/lib/review-scope-advisory.js +286 -0
  272. package/dist/scripts/lib/review-scope-paths.js +123 -0
  273. package/dist/scripts/lib/review-shell-command-parser.js +389 -0
  274. package/dist/scripts/lib/review-shell-env-interpreter.js +340 -0
  275. package/dist/scripts/lib/run-manifests.js +192 -36
  276. package/dist/scripts/lib/spark-policy-classifier.js +593 -0
  277. package/dist/scripts/run-review.js +507 -1777
  278. package/docs/README.md +43 -20
  279. package/docs/book/README.md +19 -0
  280. package/docs/book/codex-cli-0124-adoption.md +68 -0
  281. package/docs/book/local-hook-impact.md +73 -0
  282. package/docs/book/operations.md +60 -0
  283. package/docs/book/public-posture.md +34 -0
  284. package/docs/book/setup.md +91 -0
  285. package/docs/book/skills.md +11 -0
  286. package/docs/guides/codex-version-policy.md +104 -0
  287. package/docs/public/downstream-setup.md +113 -0
  288. package/docs/public/provider-onboarding.md +173 -0
  289. package/package.json +23 -10
  290. package/plugins/codex-orchestrator/.codex-plugin/plugin.json +30 -0
  291. package/plugins/codex-orchestrator/.mcp.json +13 -0
  292. package/plugins/codex-orchestrator/launcher.mjs +361 -0
  293. package/schemas/manifest.json +411 -0
  294. package/skills/README.md +26 -0
  295. package/skills/collab-subagents-first/SKILL.md +1 -1
  296. package/skills/delegation-usage/DELEGATION_GUIDE.md +30 -12
  297. package/skills/delegation-usage/SKILL.md +25 -14
  298. package/skills/land/SKILL.md +77 -0
  299. package/skills/linear/SKILL.md +255 -0
  300. package/skills/release/SKILL.md +47 -3
  301. package/skills/standalone-review/SKILL.md +6 -1
  302. package/templates/README.md +4 -2
  303. package/templates/codex/.codex/agents/awaiter-high.toml +2 -2
  304. package/templates/codex/.codex/agents/worker-complex.toml +1 -1
  305. package/templates/codex/.codex/config.toml +3 -4
  306. package/templates/codex/.codex/providers/README.md +13 -0
  307. package/templates/codex/.codex/providers/control.example.json +18 -0
  308. package/templates/codex/.codex/providers/provider.env.example +15 -0
  309. package/templates/codex/AGENTS.md +15 -8
  310. package/templates/codex/mcp-client.json +5 -1
  311. package/docs/assets/setup.gif +0 -0
@@ -0,0 +1,1348 @@
1
+ import { readProviderLinearParallelizationSnapshot } from './providerLinearWorkflowAudit.js';
2
+ import { classifyProviderLinearWorkflowState, normalizeProviderLinearWorkflowState } from './providerLinearWorkflowStates.js';
3
+ import { normalizeProviderWorkerHostName } from './providerWorkerHosts.js';
4
+ import { stripNonApplicableGuardrailSummaryLines } from '../run/manifest.js';
5
+ const PROVIDER_SEMANTIC_STALL_THRESHOLD_MS = 15 * 60 * 1000;
6
+ const PROVIDER_LINEAR_CHILD_LANE_PIPELINE_ID = 'provider-linear-child-lane';
7
+ export function deriveProviderIntakeClaimFreshness(input) {
8
+ const claim = input.claim ?? null;
9
+ if (!claim) {
10
+ return null;
11
+ }
12
+ if (normalizeProviderLinearWorkflowState(claim.state) === 'stale') {
13
+ return 'stale';
14
+ }
15
+ const reason = normalizeOptionalString(claim.reason);
16
+ const rehydratedAt = normalizeOptionalString(input.rehydrated_at);
17
+ if ((reason && reason.includes('rehydrated')) ||
18
+ (rehydratedAt &&
19
+ normalizeOptionalString(claim.updated_at) &&
20
+ compareIsoTimestamp(claim.updated_at ?? null, rehydratedAt) <= 0)) {
21
+ return 'rehydrated';
22
+ }
23
+ return 'fresh';
24
+ }
25
+ export function buildProviderIssueDebugSnapshot(input) {
26
+ const trackedIssue = input.tracked_issue ?? null;
27
+ const claim = input.claim ?? null;
28
+ const proof = input.proof ?? null;
29
+ const latestAudit = selectLatestProviderLinearAuditEntry(proof?.linear_audit);
30
+ const parallelization = resolveProviderParallelizationSnapshot(proof);
31
+ const trackedWorkflowState = trackedIssue ? classifyProviderLinearWorkflowState(trackedIssue) : null;
32
+ const claimWorkflowState = !trackedIssue ? resolveClaimWorkflowStateClassification(claim) : null;
33
+ const reworkResetUpdatedAt = resolveReworkResetUpdatedAt({
34
+ trackedIssue,
35
+ claim,
36
+ trackedWorkflowState,
37
+ claimWorkflowState
38
+ });
39
+ const visibleReviewPromotion = isPullRequestLifecycleSupersededByReworkReset(claim?.review_promotion ?? null, reworkResetUpdatedAt)
40
+ ? null
41
+ : claim?.review_promotion ?? null;
42
+ const visibleMergeCloseout = isPullRequestLifecycleSupersededByReworkReset(claim?.merge_closeout ?? null, reworkResetUpdatedAt)
43
+ ? null
44
+ : claim?.merge_closeout ?? null;
45
+ const progress = deriveProviderLinearWorkerProgressSnapshot({
46
+ tracked_issue: trackedIssue,
47
+ claim,
48
+ proof
49
+ });
50
+ const pullRequest = buildProviderDebugPullRequestSnapshot({
51
+ reviewPromotion: visibleReviewPromotion,
52
+ mergeCloseout: visibleMergeCloseout,
53
+ preferReviewPromotion: trackedWorkflowState?.isHandoff === true || claimWorkflowState?.isHandoff === true
54
+ });
55
+ if (!trackedIssue && !claim && !proof && !latestAudit && !pullRequest && !progress) {
56
+ return null;
57
+ }
58
+ const claimFreshness = deriveProviderIntakeClaimFreshness({
59
+ claim,
60
+ rehydrated_at: input.rehydrated_at
61
+ });
62
+ const claimIsRehydrated = claimFreshness === 'rehydrated';
63
+ return {
64
+ live_linear_state: {
65
+ state: normalizeOptionalString(trackedIssue?.state),
66
+ state_type: normalizeOptionalString(trackedIssue?.state_type),
67
+ updated_at: normalizeOptionalString(trackedIssue?.updated_at)
68
+ },
69
+ claim: claim
70
+ ? {
71
+ state: normalizeOptionalString(claim.state),
72
+ reason: normalizeOptionalString(claim.reason),
73
+ updated_at: normalizeOptionalString(claim.updated_at),
74
+ run_id: normalizeOptionalString(claim.run_id),
75
+ issue_state: normalizeOptionalString(claim.issue_state),
76
+ issue_state_type: normalizeOptionalString(claim.issue_state_type),
77
+ issue_updated_at: normalizeOptionalString(claim.issue_updated_at),
78
+ worker_host: normalizeProviderWorkerHostName(claim.worker_host),
79
+ launch_source: normalizeOptionalString(claim.launch_source),
80
+ launch_started_at: normalizeOptionalString(claim.launch_started_at),
81
+ retry: buildProviderClaimRetrySnapshot(claim),
82
+ freshness: claimFreshness,
83
+ is_rehydrated: claimIsRehydrated,
84
+ rehydrated_at: normalizeOptionalString(input.rehydrated_at)
85
+ }
86
+ : null,
87
+ worker: proof
88
+ ? {
89
+ owner_phase: normalizeOptionalString(proof.owner_phase),
90
+ owner_status: normalizeOptionalString(proof.owner_status),
91
+ pid: normalizeOptionalString(proof.pid),
92
+ worker_host: normalizeProviderWorkerHostName(proof.worker_host),
93
+ thread_id: normalizeOptionalString(proof.thread_id),
94
+ latest_session_id: normalizeOptionalString(proof.latest_session_id),
95
+ turn_count: normalizeOptionalInteger(proof.turn_count),
96
+ resident_logical_session_id: normalizeOptionalString(proof.resident_session?.logical_session_id),
97
+ resident_logical_turn_count: normalizeOptionalInteger(proof.resident_session?.logical_turn_count),
98
+ resident_restart_count: normalizeOptionalInteger(proof.resident_session?.restart_count),
99
+ resident_continuity_state: normalizeOptionalString(proof.resident_session?.continuity_state),
100
+ resident_source_run_id: normalizeOptionalString(proof.resident_session?.source_run_id),
101
+ resident_source_end_reason: normalizeOptionalString(proof.resident_session?.source_end_reason),
102
+ last_event: normalizeOptionalString(proof.last_event),
103
+ last_message: normalizeOptionalString(proof.last_message),
104
+ last_event_at: normalizeOptionalString(proof.last_event_at),
105
+ current_turn_activity: proof.current_turn_activity
106
+ ? {
107
+ event: normalizeOptionalString(proof.current_turn_activity.event),
108
+ message_or_payload: normalizeOptionalString(proof.current_turn_activity.message_or_payload),
109
+ recorded_at: normalizeOptionalString(proof.current_turn_activity.recorded_at),
110
+ source: normalizeOptionalString(proof.current_turn_activity.source),
111
+ turn_id: normalizeOptionalString(proof.current_turn_activity.turn_id),
112
+ session_id: normalizeOptionalString(proof.current_turn_activity.session_id)
113
+ }
114
+ : null,
115
+ updated_at: normalizeOptionalString(proof.updated_at)
116
+ }
117
+ : null,
118
+ parallelization: parallelization
119
+ ? {
120
+ decision: parallelization.decision,
121
+ reason: parallelization.reason,
122
+ summary: parallelization.summary,
123
+ recorded_at: parallelization.recorded_at,
124
+ child_lane_count: parallelization.child_lane_count
125
+ }
126
+ : null,
127
+ pull_request: pullRequest,
128
+ progress,
129
+ last_audit_operation: latestAudit
130
+ ? {
131
+ recorded_at: latestAudit.recorded_at,
132
+ operation: latestAudit.operation,
133
+ ok: latestAudit.ok,
134
+ action: normalizeOptionalString(latestAudit.action),
135
+ state: normalizeOptionalString(latestAudit.state),
136
+ error_code: normalizeOptionalString(latestAudit.error_code),
137
+ error_message: normalizeOptionalString(latestAudit.error_message)
138
+ }
139
+ : null,
140
+ last_semantic_progress_at: latestIsoTimestamp(progress?.last_semantic_progress_at ?? null, latestAudit?.recorded_at ?? null),
141
+ stall_classification: progress?.stall_classification ?? null,
142
+ stall_reason: progress?.stall_reason ?? null,
143
+ recovery_recommendation: progress?.recovery_recommendation ?? null
144
+ };
145
+ }
146
+ function buildProviderClaimRetrySnapshot(claim) {
147
+ if (!claim) {
148
+ return null;
149
+ }
150
+ const active = claim.retry_queued === true;
151
+ const attempt = normalizeOptionalInteger(claim.retry_attempt);
152
+ const dueAt = normalizeOptionalString(claim.retry_due_at);
153
+ const error = normalizeOptionalString(claim.retry_error);
154
+ if (!active && attempt === null && dueAt === null && error === null) {
155
+ return null;
156
+ }
157
+ return {
158
+ active,
159
+ attempt,
160
+ due_at: dueAt,
161
+ error
162
+ };
163
+ }
164
+ function resolveProviderParallelizationSnapshot(proof) {
165
+ const currentTurnStartedAt = normalizeOptionalString(proof?.current_turn_started_at);
166
+ const currentTurnChildLanes = Array.isArray(proof?.child_lanes)
167
+ ? !currentTurnStartedAt
168
+ ? proof.child_lanes
169
+ : proof.child_lanes.filter((childLane) => compareIsoTimestamp(childLane.launched_at ?? null, currentTurnStartedAt) >= 0)
170
+ : null;
171
+ const hydrated = proof?.parallelization ?? null;
172
+ if (hydrated) {
173
+ if (!currentTurnStartedAt ||
174
+ compareIsoTimestamp(normalizeOptionalString(hydrated.recorded_at), currentTurnStartedAt) >= 0) {
175
+ return {
176
+ ...hydrated,
177
+ child_lane_count: currentTurnChildLanes !== null
178
+ ? currentTurnChildLanes.length
179
+ : normalizeOptionalInteger(hydrated.child_lane_count)
180
+ };
181
+ }
182
+ }
183
+ const fromAudit = readProviderLinearParallelizationSnapshot(proof?.linear_audit, {
184
+ issueId: normalizeOptionalString(proof?.issue_id),
185
+ recordedAtNotBefore: currentTurnStartedAt
186
+ });
187
+ if (!fromAudit) {
188
+ return null;
189
+ }
190
+ return {
191
+ ...fromAudit,
192
+ child_lane_count: currentTurnChildLanes !== null ? currentTurnChildLanes.length : null
193
+ };
194
+ }
195
+ export function deriveProviderLinearWorkerProgressSnapshot(input) {
196
+ const trackedIssue = input.tracked_issue ?? null;
197
+ const claim = input.claim ?? null;
198
+ const proof = input.proof ?? null;
199
+ const now = input.now ?? (() => new Date().toISOString());
200
+ const latestAudit = selectLatestProviderLinearAuditEntry(proof?.linear_audit);
201
+ const activeChildLane = selectActiveChildLane(proof?.child_lanes ?? null);
202
+ const activeChildStream = selectActiveChildStream(proof?.child_streams ?? null);
203
+ const trackedWorkflowState = trackedIssue ? classifyProviderLinearWorkflowState(trackedIssue) : null;
204
+ const claimWorkflowState = !trackedIssue ? resolveClaimWorkflowStateClassification(claim) : null;
205
+ const reworkResetUpdatedAt = resolveReworkResetUpdatedAt({
206
+ trackedIssue,
207
+ claim,
208
+ trackedWorkflowState,
209
+ claimWorkflowState
210
+ });
211
+ const reviewPromotion = isPullRequestLifecycleSupersededByReworkReset(claim?.review_promotion ?? null, reworkResetUpdatedAt)
212
+ ? null
213
+ : claim?.review_promotion ?? null;
214
+ const mergeCloseout = isPullRequestLifecycleSupersededByReworkReset(claim?.merge_closeout ?? null, reworkResetUpdatedAt)
215
+ ? null
216
+ : claim?.merge_closeout ?? null;
217
+ const ownerPhase = normalizeOptionalString(proof?.owner_phase);
218
+ const ownerStatus = normalizeOptionalString(proof?.owner_status);
219
+ const endReason = normalizeOptionalString(proof?.end_reason);
220
+ const claimState = normalizeProviderLinearWorkflowState(claim?.state);
221
+ const workflowStateName = normalizeProviderLinearWorkflowState(normalizeOptionalString(trackedIssue?.state) ?? normalizeOptionalString(claim?.issue_state));
222
+ const currentTurnStartedAt = normalizeOptionalString(proof?.current_turn_started_at);
223
+ const latestChildProgressAt = latestIsoTimestamp(selectLatestChildLaneProgressAt(proof?.child_lanes ?? null, currentTurnStartedAt), selectLatestChildStreamProgressAt(proof?.child_streams ?? null, currentTurnStartedAt));
224
+ const latestChildSummaryCandidate = selectLatestChildProgressSummaryCandidate(proof, currentTurnStartedAt);
225
+ const mergeCloseoutProgress = mergeCloseout ? deriveMergeCloseoutProgressSnapshot(mergeCloseout) : null;
226
+ const trackedTerminalWorkflowUpdatedAt = trackedWorkflowState?.isTerminal ? normalizeOptionalString(trackedIssue?.updated_at) : null;
227
+ const claimTerminalWorkflowIssueUpdatedAt = claimWorkflowState?.isTerminal ? normalizeOptionalString(claim?.issue_updated_at) : null;
228
+ const terminalWorkflowIssueFreshnessAt = latestIsoTimestamp(trackedTerminalWorkflowUpdatedAt, claimTerminalWorkflowIssueUpdatedAt);
229
+ const terminalWorkflowUpdatedAt = latestIsoTimestamp(terminalWorkflowIssueFreshnessAt, claimWorkflowState?.isTerminal ? normalizeOptionalString(claim?.updated_at) : null);
230
+ const mergeCloseoutIssueUpdatedAt = normalizeOptionalString(mergeCloseout?.issue_updated_at);
231
+ const terminalWorkflowSupersedesMergeCloseout = Boolean(mergeCloseoutProgress &&
232
+ mergeCloseoutProgress.status !== 'failed' &&
233
+ terminalWorkflowIssueFreshnessAt &&
234
+ ((!mergeCloseoutIssueUpdatedAt &&
235
+ trackedTerminalWorkflowUpdatedAt) ||
236
+ (!mergeCloseoutIssueUpdatedAt &&
237
+ claimTerminalWorkflowIssueUpdatedAt &&
238
+ compareIsoTimestamp(claimTerminalWorkflowIssueUpdatedAt, mergeCloseoutProgress.last_semantic_progress_at) >= 0) ||
239
+ (mergeCloseoutIssueUpdatedAt &&
240
+ compareIsoTimestamp(terminalWorkflowIssueFreshnessAt, mergeCloseoutIssueUpdatedAt) >= 0)));
241
+ const lastSemanticProgressAt = latestIsoTimestamp(normalizeOptionalString(proof?.current_turn_activity?.recorded_at), normalizeOptionalString(proof?.last_event_at), latestAudit?.recorded_at ?? null, latestChildProgressAt, normalizeOptionalString(proof?.attempt_started_at));
242
+ const workerProgressSuppressedByStaleClaim = claimState === 'stale'
243
+ && hasAuthoritativeWorkerProgressSignal({
244
+ proof,
245
+ ownerPhase,
246
+ ownerStatus,
247
+ endReason,
248
+ lastSemanticProgressAt
249
+ });
250
+ const claimTerminalWorkflowSupersedesWorkerProgress = Boolean(claimWorkflowState?.isTerminal
251
+ && (!lastSemanticProgressAt
252
+ || (claimTerminalWorkflowIssueUpdatedAt
253
+ && compareIsoTimestamp(claimTerminalWorkflowIssueUpdatedAt, lastSemanticProgressAt) >= 0)));
254
+ const terminalWorkflowIsNewerThanWorkerProgress = Boolean(((trackedWorkflowState?.isTerminal
255
+ && trackedTerminalWorkflowUpdatedAt
256
+ && compareIsoTimestamp(trackedTerminalWorkflowUpdatedAt, lastSemanticProgressAt) >= 0)
257
+ || claimTerminalWorkflowSupersedesWorkerProgress));
258
+ if (ownerStatus === 'failed' || ownerPhase === 'turn_failed') {
259
+ return {
260
+ phase: ownerPhase === 'turn_failed' ? 'turn_failed' : 'failed',
261
+ kind: 'worker',
262
+ status: 'failed',
263
+ summary: selectProofPreferredMessage(proof) ??
264
+ 'Provider worker failed.',
265
+ last_semantic_progress_at: lastSemanticProgressAt,
266
+ stall_classification: 'failed',
267
+ stall_reason: normalizeOptionalString(proof?.last_event) ?? normalizeOptionalString(ownerPhase),
268
+ recovery_recommendation: 'inspect_worker_logs'
269
+ };
270
+ }
271
+ if (reviewPromotion &&
272
+ workflowStateName === 'merging' &&
273
+ !mergeCloseout &&
274
+ !workerProgressSuppressedByStaleClaim) {
275
+ return derivePendingMergeCloseoutProgressSnapshot(reviewPromotion);
276
+ }
277
+ if (reviewPromotion &&
278
+ (trackedWorkflowState?.isHandoff || claimWorkflowState?.isHandoff) &&
279
+ !workerProgressSuppressedByStaleClaim) {
280
+ return deriveReviewPromotionProgressSnapshot(reviewPromotion);
281
+ }
282
+ if (mergeCloseoutProgress
283
+ && !workerProgressSuppressedByStaleClaim
284
+ && !terminalWorkflowSupersedesMergeCloseout) {
285
+ return mergeCloseoutProgress;
286
+ }
287
+ if (ownerPhase === 'ended' && ownerStatus === 'succeeded') {
288
+ if (endReason === 'max_turns_reached_issue_still_active') {
289
+ return {
290
+ phase: 'inactive',
291
+ kind: 'worker',
292
+ status: 'stalled',
293
+ summary: selectProofPreferredMessage(proof) ??
294
+ 'Provider worker exhausted max turns while the issue remained active.',
295
+ last_semantic_progress_at: lastSemanticProgressAt,
296
+ stall_classification: 'stalled',
297
+ stall_reason: endReason,
298
+ recovery_recommendation: 'inspect_worker_logs'
299
+ };
300
+ }
301
+ return {
302
+ phase: trackedWorkflowState?.isHandoff ? 'review_handoff' : 'completed',
303
+ kind: trackedWorkflowState?.isHandoff || terminalWorkflowIsNewerThanWorkerProgress
304
+ ? 'workflow'
305
+ : 'worker',
306
+ status: 'completed',
307
+ summary: selectProofPreferredMessage(proof) ??
308
+ (terminalWorkflowIsNewerThanWorkerProgress
309
+ ? 'Issue is complete.'
310
+ : 'Provider worker completed successfully.'),
311
+ last_semantic_progress_at: latestIsoTimestamp(lastSemanticProgressAt, terminalWorkflowIsNewerThanWorkerProgress ? terminalWorkflowUpdatedAt : null),
312
+ stall_classification: 'completed',
313
+ stall_reason: null,
314
+ recovery_recommendation: 'no_action'
315
+ };
316
+ }
317
+ if (activeChildLane) {
318
+ const childLaneSummary = normalizeProviderChildLaneProgressSummary(activeChildLane) ??
319
+ `Waiting on child lane ${activeChildLane.stream ?? activeChildLane.task_id ?? activeChildLane.run_id ?? 'unknown'}.`;
320
+ return {
321
+ phase: 'child_lane',
322
+ kind: 'child_lane',
323
+ status: 'waiting',
324
+ summary: childLaneSummary,
325
+ summary_recorded_at: childLaneSummaryRecordedAt(activeChildLane),
326
+ last_semantic_progress_at: latestIsoTimestamp(childLaneSummaryRecordedAt(activeChildLane), normalizeOptionalString(activeChildLane.decision_at), normalizeOptionalString(activeChildLane.launched_at), latestAudit?.recorded_at ?? null, normalizeOptionalString(proof?.last_event_at), normalizeOptionalString(proof?.attempt_started_at)),
327
+ stall_classification: 'waiting_on_child_lane',
328
+ stall_reason: `child_lane:${normalizeOptionalString(activeChildLane.stream) ?? 'pending'}`,
329
+ recovery_recommendation: 'inspect_child_lane'
330
+ };
331
+ }
332
+ if (activeChildStream) {
333
+ const childStreamSummary = normalizeOptionalString(activeChildStream.summary) ??
334
+ `Waiting on child stream ${activeChildStream.stream ?? activeChildStream.task_id ?? activeChildStream.run_id ?? 'unknown'}.`;
335
+ return {
336
+ phase: 'child_stream',
337
+ kind: 'child_stream',
338
+ status: 'waiting',
339
+ summary: childStreamSummary,
340
+ last_semantic_progress_at: latestIsoTimestamp(normalizeOptionalString(activeChildStream.launched_at), latestAudit?.recorded_at ?? null, normalizeOptionalString(proof?.last_event_at), normalizeOptionalString(proof?.attempt_started_at)),
341
+ stall_classification: 'waiting_on_child_stream',
342
+ stall_reason: `child_stream:${normalizeOptionalString(activeChildStream.stream) ?? 'active'}`,
343
+ recovery_recommendation: 'inspect_child_stream'
344
+ };
345
+ }
346
+ if (trackedWorkflowState?.isHandoff) {
347
+ return {
348
+ phase: 'review_handoff',
349
+ kind: 'workflow',
350
+ status: 'completed',
351
+ summary: 'Issue is in review handoff.',
352
+ last_semantic_progress_at: lastSemanticProgressAt,
353
+ stall_classification: 'completed',
354
+ stall_reason: null,
355
+ recovery_recommendation: 'no_action'
356
+ };
357
+ }
358
+ if (trackedWorkflowState?.isTerminal || claimTerminalWorkflowSupersedesWorkerProgress) {
359
+ return {
360
+ phase: 'completed',
361
+ kind: 'workflow',
362
+ status: 'completed',
363
+ summary: 'Issue is complete.',
364
+ last_semantic_progress_at: latestIsoTimestamp(lastSemanticProgressAt, terminalWorkflowUpdatedAt),
365
+ stall_classification: 'completed',
366
+ stall_reason: null,
367
+ recovery_recommendation: 'no_action'
368
+ };
369
+ }
370
+ if (ownerPhase || proof) {
371
+ const phase = normalizeProofProgressPhase(ownerPhase);
372
+ const authoritativeWorkerProgress = resolveAuthoritativeWorkerProgress({
373
+ proof,
374
+ currentTurnStartedAt,
375
+ latestChildSummaryCandidate,
376
+ lastSemanticProgressAt,
377
+ phase
378
+ });
379
+ const summary = authoritativeWorkerProgress.summary ?? defaultProgressSummaryForPhase(phase);
380
+ if (isSemanticallyStalled(lastSemanticProgressAt, now())) {
381
+ return {
382
+ phase,
383
+ kind: 'worker',
384
+ status: 'stalled',
385
+ summary,
386
+ summary_recorded_at: authoritativeWorkerProgress.summary_recorded_at,
387
+ message_recorded_at: authoritativeWorkerProgress.message_recorded_at,
388
+ source_updated_at: authoritativeWorkerProgress.source_updated_at,
389
+ selected_event: authoritativeWorkerProgress.event,
390
+ event_source: authoritativeWorkerProgress.source,
391
+ event_candidates: authoritativeWorkerProgress.candidates,
392
+ last_semantic_progress_at: lastSemanticProgressAt,
393
+ stall_classification: 'stalled',
394
+ stall_reason: lastSemanticProgressAt
395
+ ? `no_semantic_progress_since:${lastSemanticProgressAt}`
396
+ : 'no_semantic_progress_recorded',
397
+ recovery_recommendation: 'inspect_worker_logs'
398
+ };
399
+ }
400
+ return {
401
+ phase,
402
+ kind: 'worker',
403
+ status: 'progressing',
404
+ summary,
405
+ summary_recorded_at: authoritativeWorkerProgress.summary_recorded_at,
406
+ message_recorded_at: authoritativeWorkerProgress.message_recorded_at,
407
+ source_updated_at: authoritativeWorkerProgress.source_updated_at,
408
+ selected_event: authoritativeWorkerProgress.event,
409
+ event_source: authoritativeWorkerProgress.source,
410
+ event_candidates: authoritativeWorkerProgress.candidates,
411
+ last_semantic_progress_at: lastSemanticProgressAt,
412
+ stall_classification: 'progressing',
413
+ stall_reason: null,
414
+ recovery_recommendation: 'continue_waiting'
415
+ };
416
+ }
417
+ if (trackedWorkflowState?.isActive) {
418
+ return {
419
+ phase: 'unknown',
420
+ kind: 'workflow',
421
+ status: 'progressing',
422
+ summary: 'Issue is active but worker progress has not been observed yet.',
423
+ last_semantic_progress_at: latestAudit?.recorded_at ?? null,
424
+ stall_classification: 'progressing',
425
+ stall_reason: null,
426
+ recovery_recommendation: 'continue_waiting'
427
+ };
428
+ }
429
+ return null;
430
+ }
431
+ function resolveReworkResetUpdatedAt(input) {
432
+ const trackedIssueIsRework = input.trackedWorkflowState?.normalizedState === 'rework';
433
+ const canUseClaimReworkTruth = !input.trackedIssue || trackedIssueIsRework;
434
+ const claimWorkflowState = canUseClaimReworkTruth
435
+ ? input.claimWorkflowState ?? resolveClaimWorkflowStateClassification(input.claim)
436
+ : null;
437
+ return latestIsoTimestamp(trackedIssueIsRework
438
+ ? normalizeOptionalString(input.trackedIssue?.updated_at)
439
+ : null, claimWorkflowState?.normalizedState === 'rework'
440
+ ? normalizeOptionalString(input.claim?.issue_updated_at)
441
+ : null);
442
+ }
443
+ function isPullRequestLifecycleSupersededByReworkReset(record, reworkResetUpdatedAt) {
444
+ if (!record || !reworkResetUpdatedAt) {
445
+ return false;
446
+ }
447
+ const semanticLifecycleUpdatedAt = latestIsoTimestamp(normalizeOptionalString(record.issue_updated_at), normalizeOptionalString(record.linear_transition?.issue_updated_at), normalizeOptionalString(record.issue_updated_at));
448
+ const lifecycleUpdatedAt = semanticLifecycleUpdatedAt ?? normalizeOptionalString(record.recorded_at);
449
+ if (!lifecycleUpdatedAt) {
450
+ return false;
451
+ }
452
+ const reworkResetComparison = compareIsoTimestamp(reworkResetUpdatedAt, lifecycleUpdatedAt);
453
+ if (reworkResetComparison === 0 &&
454
+ isPullRequestLifecycleCurrentReworkTransition(record)) {
455
+ return false;
456
+ }
457
+ return reworkResetComparison >= 0;
458
+ }
459
+ function isPullRequestLifecycleCurrentReworkTransition(record) {
460
+ const lifecycle = record;
461
+ const transition = lifecycle.linear_transition;
462
+ return [
463
+ normalizeOptionalString(lifecycle.issue_state),
464
+ normalizeOptionalString(transition?.target_state),
465
+ normalizeOptionalString(transition?.issue_state)
466
+ ].some((state) => normalizeProviderLinearWorkflowState(state) === 'rework');
467
+ }
468
+ function resolveClaimWorkflowStateClassification(claim) {
469
+ const state = normalizeOptionalString(claim?.issue_state);
470
+ const stateType = normalizeOptionalString(claim?.issue_state_type);
471
+ if (!state && !stateType) {
472
+ return null;
473
+ }
474
+ return classifyProviderLinearWorkflowState({
475
+ state,
476
+ state_type: stateType
477
+ });
478
+ }
479
+ function resolveAuthoritativeWorkerProgress(input) {
480
+ const childCandidates = collectCurrentTurnChildProgressSummaryCandidates(input.proof, normalizeOptionalString(input.currentTurnStartedAt));
481
+ if (childCandidates.length === 0 && input.latestChildSummaryCandidate) {
482
+ childCandidates.push({
483
+ source: input.latestChildSummaryCandidate.source,
484
+ event: input.latestChildSummaryCandidate.event,
485
+ summary: input.latestChildSummaryCandidate.summary,
486
+ message_recorded_at: input.latestChildSummaryCandidate.recorded_at,
487
+ source_updated_at: input.latestChildSummaryCandidate.recorded_at,
488
+ derived: true
489
+ });
490
+ }
491
+ const candidates = [
492
+ buildCurrentTurnActivityProgressCandidate(input.proof),
493
+ buildLegacyProofMessageProgressCandidate(input.proof),
494
+ ...childCandidates,
495
+ buildGenericPhaseFallbackProgressCandidate(input.phase, input.lastSemanticProgressAt)
496
+ ].filter((candidate) => Boolean(candidate));
497
+ const winner = selectBestProviderLinearWorkerProgressCandidate(candidates);
498
+ if (!winner) {
499
+ return {
500
+ event: null,
501
+ source: null,
502
+ summary: null,
503
+ summary_recorded_at: null,
504
+ message_recorded_at: null,
505
+ source_updated_at: null,
506
+ candidates: []
507
+ };
508
+ }
509
+ return {
510
+ event: winner.event,
511
+ source: winner.source,
512
+ summary: winner.summary,
513
+ summary_recorded_at: winner.message_recorded_at,
514
+ message_recorded_at: winner.message_recorded_at,
515
+ source_updated_at: winner.source_updated_at,
516
+ candidates: candidates.map((candidate) => ({
517
+ source: candidate.source,
518
+ event: candidate.event,
519
+ summary: candidate.summary,
520
+ message_recorded_at: candidate.message_recorded_at,
521
+ source_updated_at: candidate.source_updated_at,
522
+ derived: candidate.derived,
523
+ accepted: candidate === winner,
524
+ rejection_reason: candidate === winner ? null : explainProviderLinearWorkerProgressCandidateRejection(candidate, winner)
525
+ }))
526
+ };
527
+ }
528
+ function selectProofPreferredMessage(proof) {
529
+ return (normalizeOptionalString(proof?.current_turn_activity?.message_or_payload) ??
530
+ normalizeOptionalString(proof?.last_message));
531
+ }
532
+ function buildCurrentTurnActivityProgressCandidate(proof) {
533
+ const activity = proof?.current_turn_activity ?? null;
534
+ if (!activity) {
535
+ return null;
536
+ }
537
+ const summary = normalizeOptionalString(activity.message_or_payload);
538
+ const event = normalizeOptionalString(activity.event);
539
+ const recordedAt = normalizeOptionalString(activity.recorded_at);
540
+ if (!summary && !event) {
541
+ return null;
542
+ }
543
+ const source = normalizeOptionalString(activity.source) === 'session_log_hydration'
544
+ ? 'canonical_session_log_hydration'
545
+ : 'canonical_stdout_jsonl';
546
+ return {
547
+ source,
548
+ event,
549
+ summary,
550
+ message_recorded_at: summary ? recordedAt : null,
551
+ source_updated_at: recordedAt,
552
+ derived: false
553
+ };
554
+ }
555
+ function buildLegacyProofMessageProgressCandidate(proof) {
556
+ const summary = normalizeOptionalString(proof?.last_message);
557
+ const event = normalizeOptionalString(proof?.last_event);
558
+ if (!summary && !event) {
559
+ return null;
560
+ }
561
+ return {
562
+ source: summary ? 'legacy_proof_last_message' : 'legacy_proof_fields',
563
+ event,
564
+ summary,
565
+ // Legacy proof does not preserve an authoritative last-message timestamp.
566
+ // `last_event_at` can advance on non-message events (for example token_count),
567
+ // so treating it as message freshness can incorrectly outrank canonical activity.
568
+ message_recorded_at: null,
569
+ source_updated_at: latestIsoTimestamp(normalizeOptionalString(proof?.last_event_at), normalizeOptionalString(proof?.updated_at)),
570
+ derived: false
571
+ };
572
+ }
573
+ function buildGenericPhaseFallbackProgressCandidate(phase, lastSemanticProgressAt) {
574
+ return {
575
+ source: 'generic_phase_fallback',
576
+ event: phase,
577
+ summary: defaultProgressSummaryForPhase(phase),
578
+ message_recorded_at: null,
579
+ source_updated_at: lastSemanticProgressAt,
580
+ derived: true
581
+ };
582
+ }
583
+ function collectCurrentTurnChildProgressSummaryCandidates(proof, currentTurnStartedAt) {
584
+ return [
585
+ ...selectCurrentTurnChildLanes(proof?.child_lanes ?? null, currentTurnStartedAt)
586
+ .filter(isCurrentProgressChildLaneSummaryEligible)
587
+ .flatMap((childLane) => {
588
+ const summary = normalizeProviderChildLaneProgressSummary(childLane);
589
+ const summaryRecordedAt = childLaneSummaryRecordedAt(childLane);
590
+ return summary
591
+ ? [
592
+ {
593
+ source: 'child_lane_summary',
594
+ event: null,
595
+ summary,
596
+ message_recorded_at: summaryRecordedAt,
597
+ source_updated_at: summaryRecordedAt,
598
+ derived: true
599
+ }
600
+ ]
601
+ : [];
602
+ }),
603
+ ...selectCurrentTurnChildStreams(proof?.child_streams ?? null, currentTurnStartedAt).flatMap((childStream) => {
604
+ const summary = normalizeOptionalString(childStream.summary);
605
+ return summary
606
+ ? [
607
+ {
608
+ source: 'child_stream_summary',
609
+ event: null,
610
+ summary,
611
+ message_recorded_at: latestIsoTimestamp(normalizeOptionalString(childStream.recorded_at), normalizeOptionalString(childStream.launched_at)),
612
+ source_updated_at: latestIsoTimestamp(normalizeOptionalString(childStream.recorded_at), normalizeOptionalString(childStream.launched_at)),
613
+ derived: true
614
+ }
615
+ ]
616
+ : [];
617
+ })
618
+ ];
619
+ }
620
+ function selectBestProviderLinearWorkerProgressCandidate(candidates) {
621
+ return candidates.reduce((current, candidate) => {
622
+ if (!current) {
623
+ return candidate;
624
+ }
625
+ return compareProviderLinearWorkerProgressCandidatePriority(candidate, current) > 0
626
+ ? candidate
627
+ : current;
628
+ }, null);
629
+ }
630
+ function compareProviderLinearWorkerProgressCandidatePriority(left, right) {
631
+ const signalComparison = scoreProviderLinearWorkerProgressCandidate(left) -
632
+ scoreProviderLinearWorkerProgressCandidate(right);
633
+ if (signalComparison !== 0) {
634
+ return signalComparison;
635
+ }
636
+ if (left.message_recorded_at && right.message_recorded_at) {
637
+ const messageFreshnessComparison = compareIsoTimestamp(left.message_recorded_at, right.message_recorded_at);
638
+ if (messageFreshnessComparison !== 0) {
639
+ return messageFreshnessComparison;
640
+ }
641
+ }
642
+ const sourceComparison = providerLinearWorkerProgressCandidateSourcePriority(left.source) -
643
+ providerLinearWorkerProgressCandidateSourcePriority(right.source);
644
+ if (sourceComparison !== 0) {
645
+ return sourceComparison;
646
+ }
647
+ return compareIsoTimestamp(left.source_updated_at, right.source_updated_at);
648
+ }
649
+ function scoreProviderLinearWorkerProgressCandidate(candidate) {
650
+ if (isHighSignalProviderProgressSummary(candidate.summary)) {
651
+ return 3;
652
+ }
653
+ return candidate.summary || candidate.event ? 1 : 0;
654
+ }
655
+ function providerLinearWorkerProgressCandidateSourcePriority(source) {
656
+ switch (source) {
657
+ case 'canonical_stdout_jsonl':
658
+ return 60;
659
+ case 'canonical_session_log_hydration':
660
+ return 50;
661
+ case 'legacy_proof_fields':
662
+ case 'legacy_proof_last_message':
663
+ return 40;
664
+ case 'child_lane_summary':
665
+ return 30;
666
+ case 'child_stream_summary':
667
+ return 20;
668
+ case 'generic_phase_fallback':
669
+ return 0;
670
+ default:
671
+ return 0;
672
+ }
673
+ }
674
+ function explainProviderLinearWorkerProgressCandidateRejection(candidate, winner) {
675
+ if (scoreProviderLinearWorkerProgressCandidate(candidate) <
676
+ scoreProviderLinearWorkerProgressCandidate(winner)) {
677
+ return 'lower_signal_than_winner';
678
+ }
679
+ if (candidate.message_recorded_at && winner.message_recorded_at) {
680
+ const messageFreshnessComparison = compareIsoTimestamp(candidate.message_recorded_at, winner.message_recorded_at);
681
+ if (messageFreshnessComparison < 0) {
682
+ return 'older_than_winner';
683
+ }
684
+ }
685
+ if (providerLinearWorkerProgressCandidateSourcePriority(candidate.source) <
686
+ providerLinearWorkerProgressCandidateSourcePriority(winner.source)) {
687
+ return 'less_authoritative_than_winner';
688
+ }
689
+ if (compareIsoTimestamp(candidate.source_updated_at, winner.source_updated_at) < 0) {
690
+ return 'older_than_winner';
691
+ }
692
+ return 'ranked_below_winner';
693
+ }
694
+ export function selectLatestProviderLinearAuditEntry(audit) {
695
+ const entries = Object.values(audit?.latest_by_operation ?? {}).filter((entry) => Boolean(entry));
696
+ if (entries.length === 0) {
697
+ return null;
698
+ }
699
+ return entries.sort((left, right) => compareIsoTimestamp(right.recorded_at, left.recorded_at))[0] ?? null;
700
+ }
701
+ function hasAuthoritativeWorkerProgressSignal(input) {
702
+ if (!input.proof) {
703
+ return false;
704
+ }
705
+ return Boolean(input.ownerPhase
706
+ || input.ownerStatus
707
+ || input.endReason
708
+ || input.lastSemanticProgressAt
709
+ || normalizeOptionalString(input.proof.current_turn_activity?.event)
710
+ || normalizeOptionalString(input.proof.current_turn_activity?.message_or_payload)
711
+ || normalizeOptionalString(input.proof.last_event)
712
+ || normalizeOptionalString(input.proof.last_message));
713
+ }
714
+ function deriveMergeCloseoutProgressSnapshot(mergeCloseout) {
715
+ const mergeStatus = normalizeOptionalString(mergeCloseout.status);
716
+ const snapshot = mergeCloseout.snapshot ?? null;
717
+ const sharedRoot = mergeCloseout.shared_root ?? null;
718
+ const checksPending = normalizeOptionalInteger(snapshot?.required_checks_pending) ??
719
+ normalizeOptionalInteger(snapshot?.checks_pending);
720
+ const checksFailed = normalizeOptionalInteger(snapshot?.required_checks_failed) ??
721
+ normalizeOptionalInteger(snapshot?.checks_failed);
722
+ const unresolvedThreadCount = normalizeOptionalInteger(snapshot?.unresolved_thread_count);
723
+ const actionRequiredReasons = normalizeStringArray(snapshot?.action_required_reasons);
724
+ const gateReasons = normalizeStringArray(snapshot?.gate_reasons);
725
+ const snapshotState = normalizeOptionalString(snapshot?.state);
726
+ const snapshotShowsMerged = mergeStatus === 'merged' ||
727
+ Boolean(normalizeOptionalString(snapshot?.merged_at)) ||
728
+ snapshotState === 'MERGED';
729
+ const lastSemanticProgressAt = latestIsoTimestamp(normalizeOptionalString(mergeCloseout.recorded_at), normalizeOptionalString(snapshot?.updated_at), normalizeOptionalString(snapshot?.merged_at));
730
+ const summary = normalizeOptionalString(mergeCloseout.summary) ??
731
+ 'Merge closeout status updated.';
732
+ const reviewBlockerReason = resolveMergeCloseoutReviewBlockerReason({
733
+ unresolvedThreadCount,
734
+ actionRequiredReasons
735
+ });
736
+ const checksFailedReason = resolveMergeCloseoutChecksFailedReason({
737
+ checksFailed,
738
+ actionRequiredReasons
739
+ });
740
+ if (snapshotShowsMerged) {
741
+ if (normalizeOptionalString(sharedRoot?.status) === 'failed') {
742
+ return {
743
+ phase: 'failed',
744
+ kind: 'merge_closeout',
745
+ status: 'failed',
746
+ summary,
747
+ last_semantic_progress_at: lastSemanticProgressAt,
748
+ stall_classification: 'failed',
749
+ stall_reason: normalizeOptionalString(sharedRoot?.reason) ?? 'shared_root_reconciliation_failed',
750
+ recovery_recommendation: 'inspect_merge_closeout'
751
+ };
752
+ }
753
+ if (normalizeOptionalString(sharedRoot?.status) === 'skipped') {
754
+ return {
755
+ phase: 'pending_shared_root_reconciliation',
756
+ kind: 'merge_closeout',
757
+ status: 'stalled',
758
+ summary,
759
+ last_semantic_progress_at: lastSemanticProgressAt,
760
+ stall_classification: 'stalled',
761
+ stall_reason: normalizeOptionalString(sharedRoot?.reason) ?? 'pending_shared_root_reconciliation',
762
+ recovery_recommendation: 'inspect_merge_closeout'
763
+ };
764
+ }
765
+ return {
766
+ phase: 'completed',
767
+ kind: 'merge_closeout',
768
+ status: 'completed',
769
+ summary,
770
+ last_semantic_progress_at: lastSemanticProgressAt,
771
+ stall_classification: 'completed',
772
+ stall_reason: null,
773
+ recovery_recommendation: 'no_action'
774
+ };
775
+ }
776
+ if (mergeStatus === 'merge_failed' || mergeStatus === 'transition_failed') {
777
+ return {
778
+ phase: 'failed',
779
+ kind: 'merge_closeout',
780
+ status: 'failed',
781
+ summary,
782
+ last_semantic_progress_at: lastSemanticProgressAt,
783
+ stall_classification: 'failed',
784
+ stall_reason: normalizeOptionalString(mergeCloseout.reason) ?? mergeStatus,
785
+ recovery_recommendation: 'inspect_merge_closeout'
786
+ };
787
+ }
788
+ if (hasPendingBranchRecovery(mergeCloseout)) {
789
+ return {
790
+ phase: 'watching_merge',
791
+ kind: 'merge_closeout',
792
+ status: 'progressing',
793
+ summary,
794
+ last_semantic_progress_at: lastSemanticProgressAt,
795
+ stall_classification: 'progressing',
796
+ stall_reason: null,
797
+ recovery_recommendation: 'continue_waiting'
798
+ };
799
+ }
800
+ if (reviewBlockerReason
801
+ || (unresolvedThreadCount ?? 0) > 0) {
802
+ return {
803
+ phase: 'waiting_on_review',
804
+ kind: 'merge_closeout',
805
+ status: 'waiting',
806
+ summary,
807
+ last_semantic_progress_at: lastSemanticProgressAt,
808
+ stall_classification: 'waiting_on_review',
809
+ stall_reason: reviewBlockerReason,
810
+ recovery_recommendation: 'address_review_feedback'
811
+ };
812
+ }
813
+ if (checksFailedReason) {
814
+ return {
815
+ phase: 'waiting_on_checks',
816
+ kind: 'merge_closeout',
817
+ status: 'stalled',
818
+ summary,
819
+ last_semantic_progress_at: lastSemanticProgressAt,
820
+ stall_classification: 'stalled',
821
+ stall_reason: checksFailedReason,
822
+ recovery_recommendation: 'inspect_merge_closeout'
823
+ };
824
+ }
825
+ if (mergeStatus === 'action_required' || actionRequiredReasons.length > 0) {
826
+ return {
827
+ phase: 'watching_merge',
828
+ kind: 'merge_closeout',
829
+ status: 'stalled',
830
+ summary,
831
+ last_semantic_progress_at: lastSemanticProgressAt,
832
+ stall_classification: 'stalled',
833
+ stall_reason: actionRequiredReasons[0] ?? normalizeOptionalString(mergeCloseout.reason) ?? 'merge_action_required',
834
+ recovery_recommendation: 'inspect_merge_closeout'
835
+ };
836
+ }
837
+ if ((checksPending ?? 0) > 0) {
838
+ return {
839
+ phase: 'waiting_on_checks',
840
+ kind: 'merge_closeout',
841
+ status: 'waiting',
842
+ summary,
843
+ last_semantic_progress_at: lastSemanticProgressAt,
844
+ stall_classification: 'waiting_on_checks',
845
+ stall_reason: gateReasons[0] ?? 'checks_pending',
846
+ recovery_recommendation: 'wait_for_checks'
847
+ };
848
+ }
849
+ if (snapshot?.ready_to_merge === true) {
850
+ return {
851
+ phase: 'attempting_merge',
852
+ kind: 'merge_closeout',
853
+ status: 'progressing',
854
+ summary,
855
+ last_semantic_progress_at: lastSemanticProgressAt,
856
+ stall_classification: 'progressing',
857
+ stall_reason: null,
858
+ recovery_recommendation: 'continue_waiting'
859
+ };
860
+ }
861
+ return {
862
+ phase: mergeStatus === 'action_required' ? 'waiting_on_review' : 'watching_merge',
863
+ kind: 'merge_closeout',
864
+ status: mergeStatus === 'action_required' ? 'waiting' : 'progressing',
865
+ summary,
866
+ last_semantic_progress_at: lastSemanticProgressAt,
867
+ stall_classification: mergeStatus === 'action_required' ? 'waiting_on_review' : 'progressing',
868
+ stall_reason: normalizeOptionalString(mergeCloseout.reason),
869
+ recovery_recommendation: mergeStatus === 'action_required' ? 'address_review_feedback' : 'continue_waiting'
870
+ };
871
+ }
872
+ function deriveReviewPromotionProgressSnapshot(reviewPromotion) {
873
+ const promotionStatus = normalizeOptionalString(reviewPromotion.status);
874
+ const snapshot = reviewPromotion.snapshot ?? null;
875
+ const checksPending = normalizeOptionalInteger(snapshot?.required_checks_pending) ??
876
+ normalizeOptionalInteger(snapshot?.checks_pending);
877
+ const checksFailed = normalizeOptionalInteger(snapshot?.required_checks_failed) ??
878
+ normalizeOptionalInteger(snapshot?.checks_failed);
879
+ const unresolvedThreadCount = normalizeOptionalInteger(snapshot?.unresolved_thread_count);
880
+ const actionRequiredReasons = normalizeStringArray(snapshot?.action_required_reasons);
881
+ const gateReasons = normalizeStringArray(snapshot?.gate_reasons);
882
+ const lastSemanticProgressAt = latestIsoTimestamp(normalizeOptionalString(reviewPromotion.recorded_at), normalizeOptionalString(snapshot?.updated_at), normalizeOptionalString(reviewPromotion.linear_transition?.attempted_at));
883
+ const summary = normalizeOptionalString(reviewPromotion.summary) ??
884
+ 'Review-handoff promotion status updated.';
885
+ const reviewBlockerReason = resolveMergeCloseoutReviewBlockerReason({
886
+ unresolvedThreadCount,
887
+ actionRequiredReasons
888
+ });
889
+ const checksFailedReason = resolveMergeCloseoutChecksFailedReason({
890
+ checksFailed,
891
+ actionRequiredReasons
892
+ });
893
+ if (promotionStatus === 'promoted') {
894
+ return {
895
+ phase: 'review_handoff',
896
+ kind: 'workflow',
897
+ status: 'completed',
898
+ summary,
899
+ last_semantic_progress_at: lastSemanticProgressAt,
900
+ stall_classification: 'completed',
901
+ stall_reason: null,
902
+ recovery_recommendation: 'no_action'
903
+ };
904
+ }
905
+ if (promotionStatus === 'transition_failed' || promotionStatus === 'promotion_failed') {
906
+ return {
907
+ phase: 'failed',
908
+ kind: 'workflow',
909
+ status: 'failed',
910
+ summary,
911
+ last_semantic_progress_at: lastSemanticProgressAt,
912
+ stall_classification: 'failed',
913
+ stall_reason: normalizeOptionalString(reviewPromotion.reason) ?? promotionStatus,
914
+ recovery_recommendation: 'inspect_merge_closeout'
915
+ };
916
+ }
917
+ if (hasPendingBranchRecovery(reviewPromotion)) {
918
+ return {
919
+ phase: 'review_handoff',
920
+ kind: 'workflow',
921
+ status: 'progressing',
922
+ summary,
923
+ last_semantic_progress_at: lastSemanticProgressAt,
924
+ stall_classification: 'progressing',
925
+ stall_reason: null,
926
+ recovery_recommendation: 'continue_waiting'
927
+ };
928
+ }
929
+ if (reviewBlockerReason
930
+ || (unresolvedThreadCount ?? 0) > 0) {
931
+ return {
932
+ phase: 'waiting_on_review',
933
+ kind: 'workflow',
934
+ status: 'waiting',
935
+ summary,
936
+ last_semantic_progress_at: lastSemanticProgressAt,
937
+ stall_classification: 'waiting_on_review',
938
+ stall_reason: reviewBlockerReason,
939
+ recovery_recommendation: 'address_review_feedback'
940
+ };
941
+ }
942
+ if (checksFailedReason) {
943
+ return {
944
+ phase: 'waiting_on_checks',
945
+ kind: 'workflow',
946
+ status: 'stalled',
947
+ summary,
948
+ last_semantic_progress_at: lastSemanticProgressAt,
949
+ stall_classification: 'stalled',
950
+ stall_reason: checksFailedReason,
951
+ recovery_recommendation: 'inspect_merge_closeout'
952
+ };
953
+ }
954
+ if ((checksPending ?? 0) > 0) {
955
+ return {
956
+ phase: 'waiting_on_checks',
957
+ kind: 'workflow',
958
+ status: 'waiting',
959
+ summary,
960
+ last_semantic_progress_at: lastSemanticProgressAt,
961
+ stall_classification: 'waiting_on_checks',
962
+ stall_reason: gateReasons[0] ?? 'checks_pending',
963
+ recovery_recommendation: 'wait_for_checks'
964
+ };
965
+ }
966
+ if (promotionStatus === 'action_required' || actionRequiredReasons.length > 0) {
967
+ return {
968
+ phase: 'review_handoff',
969
+ kind: 'workflow',
970
+ status: 'stalled',
971
+ summary,
972
+ last_semantic_progress_at: lastSemanticProgressAt,
973
+ stall_classification: 'stalled',
974
+ stall_reason: actionRequiredReasons[0] ??
975
+ normalizeOptionalString(reviewPromotion.reason) ??
976
+ 'review_handoff_promotion_blocked',
977
+ recovery_recommendation: 'inspect_merge_closeout'
978
+ };
979
+ }
980
+ return {
981
+ phase: 'review_handoff',
982
+ kind: 'workflow',
983
+ status: promotionStatus === 'watching' ? 'waiting' : 'progressing',
984
+ summary,
985
+ last_semantic_progress_at: lastSemanticProgressAt,
986
+ stall_classification: promotionStatus === 'watching' ? 'waiting_on_review' : 'progressing',
987
+ stall_reason: normalizeOptionalString(reviewPromotion.reason),
988
+ recovery_recommendation: promotionStatus === 'watching' ? 'continue_waiting' : 'continue_waiting'
989
+ };
990
+ }
991
+ function derivePendingMergeCloseoutProgressSnapshot(reviewPromotion) {
992
+ const snapshot = reviewPromotion.snapshot ?? null;
993
+ const lastSemanticProgressAt = latestIsoTimestamp(normalizeOptionalString(reviewPromotion.recorded_at), normalizeOptionalString(snapshot?.updated_at), normalizeOptionalString(reviewPromotion.linear_transition?.attempted_at));
994
+ const summary = normalizeOptionalString(reviewPromotion.summary);
995
+ return {
996
+ phase: 'watching_merge',
997
+ kind: 'workflow',
998
+ status: 'progressing',
999
+ summary: summary
1000
+ ? `${summary} Waiting for merge closeout to start.`
1001
+ : 'Review handoff was promoted to Merging; waiting for merge closeout to start.',
1002
+ last_semantic_progress_at: lastSemanticProgressAt,
1003
+ stall_classification: 'progressing',
1004
+ stall_reason: null,
1005
+ recovery_recommendation: 'continue_waiting'
1006
+ };
1007
+ }
1008
+ function hasPendingBranchRecovery(record) {
1009
+ return (normalizeOptionalString(record.reason) === 'branch_refresh_requested'
1010
+ && record.branch_recovery?.ok === true
1011
+ && Boolean(normalizeOptionalString(record.branch_recovery.recovery_reason)));
1012
+ }
1013
+ function resolveMergeCloseoutReviewBlockerReason(input) {
1014
+ const reviewReason = input.actionRequiredReasons.find((reason) => isMergeCloseoutReviewBlockerReason(reason));
1015
+ if (reviewReason) {
1016
+ return reviewReason;
1017
+ }
1018
+ if ((input.unresolvedThreadCount ?? 0) > 0) {
1019
+ return 'unresolved_review_threads';
1020
+ }
1021
+ return null;
1022
+ }
1023
+ function resolveMergeCloseoutChecksFailedReason(input) {
1024
+ const failedChecksReason = input.actionRequiredReasons.find((reason) => isMergeCloseoutChecksFailedReason(reason));
1025
+ if (failedChecksReason) {
1026
+ return failedChecksReason;
1027
+ }
1028
+ if ((input.checksFailed ?? 0) > 0) {
1029
+ return 'checks_failed';
1030
+ }
1031
+ return null;
1032
+ }
1033
+ function isMergeCloseoutReviewBlockerReason(reason) {
1034
+ return (reason === 'changes_requested' ||
1035
+ reason === 'review_required' ||
1036
+ reason.startsWith('review=') ||
1037
+ reason.startsWith('unresolved_threads=') ||
1038
+ reason.startsWith('unacknowledged_bot_feedback='));
1039
+ }
1040
+ function isMergeCloseoutChecksFailedReason(reason) {
1041
+ return reason.startsWith('required_checks_failed=') || reason.startsWith('checks_failed=');
1042
+ }
1043
+ function buildProviderDebugPullRequestSnapshot(input) {
1044
+ const selectedRecord = input.preferReviewPromotion && input.reviewPromotion
1045
+ ? input.reviewPromotion
1046
+ : input.mergeCloseout ?? input.reviewPromotion;
1047
+ if (!selectedRecord) {
1048
+ return null;
1049
+ }
1050
+ const snapshot = selectedRecord.snapshot ?? null;
1051
+ return {
1052
+ review_promotion_status: normalizeOptionalString(input.reviewPromotion?.status),
1053
+ attached_pr_urls: normalizeStringArray(selectedRecord.attached_pr_urls),
1054
+ ignored_historical_pr_urls: normalizeStringArray(selectedRecord.ignored_historical_pr_urls),
1055
+ ignored_closed_unmerged_pr_urls: normalizeStringArray(selectedRecord.ignored_closed_unmerged_pr_urls),
1056
+ conflicting_attached_pr_urls: normalizeStringArray(selectedRecord.conflicting_attached_pr_urls),
1057
+ url: normalizeOptionalString(selectedRecord.pr?.url),
1058
+ owner: normalizeOptionalString(selectedRecord.pr?.owner),
1059
+ repo: normalizeOptionalString(selectedRecord.pr?.repo),
1060
+ number: normalizeOptionalInteger(selectedRecord.pr?.number),
1061
+ merge_closeout_status: normalizeOptionalString(input.mergeCloseout?.status),
1062
+ reason: normalizeOptionalString(selectedRecord.reason),
1063
+ summary: normalizeOptionalString(selectedRecord.summary),
1064
+ shared_root_status: normalizeOptionalString(input.mergeCloseout?.shared_root?.status),
1065
+ shared_root_reason: normalizeOptionalString(input.mergeCloseout?.shared_root?.reason),
1066
+ shared_root_before_status: normalizeOptionalString(input.mergeCloseout?.shared_root?.before_status),
1067
+ shared_root_after_status: normalizeOptionalString(input.mergeCloseout?.shared_root?.after_status),
1068
+ ready_to_merge: typeof snapshot?.ready_to_merge === 'boolean' ? snapshot.ready_to_merge : null,
1069
+ review_decision: normalizeOptionalString(snapshot?.review_decision),
1070
+ merge_state_status: normalizeOptionalString(snapshot?.merge_state_status),
1071
+ unresolved_thread_count: normalizeOptionalInteger(snapshot?.unresolved_thread_count),
1072
+ checks_pending: normalizeOptionalInteger(snapshot?.checks_pending),
1073
+ checks_failed: normalizeOptionalInteger(snapshot?.checks_failed),
1074
+ required_checks_pending: normalizeOptionalInteger(snapshot?.required_checks_pending),
1075
+ required_checks_failed: normalizeOptionalInteger(snapshot?.required_checks_failed),
1076
+ gate_reasons: normalizeStringArray(snapshot?.gate_reasons),
1077
+ action_required_reasons: normalizeStringArray(snapshot?.action_required_reasons),
1078
+ updated_at: normalizeOptionalString(snapshot?.updated_at),
1079
+ merged_at: normalizeOptionalString(snapshot?.merged_at),
1080
+ branch_recovery: selectedRecord.branch_recovery
1081
+ ? {
1082
+ attempted_at: normalizeOptionalString(selectedRecord.branch_recovery.attempted_at),
1083
+ head_oid: normalizeOptionalString(selectedRecord.branch_recovery.head_oid),
1084
+ recovery_reason: normalizeOptionalString(selectedRecord.branch_recovery.recovery_reason),
1085
+ command: normalizeOptionalString(selectedRecord.branch_recovery.command),
1086
+ args: normalizeStringArray(selectedRecord.branch_recovery.args),
1087
+ exit_code: normalizeOptionalInteger(selectedRecord.branch_recovery.exit_code),
1088
+ ok: typeof selectedRecord.branch_recovery.ok === 'boolean'
1089
+ ? selectedRecord.branch_recovery.ok
1090
+ : null,
1091
+ stdout: normalizeOptionalString(selectedRecord.branch_recovery.stdout),
1092
+ stderr: normalizeOptionalString(selectedRecord.branch_recovery.stderr),
1093
+ failure_kind: normalizeOptionalString(selectedRecord.branch_recovery.failure_kind)
1094
+ }
1095
+ : null
1096
+ };
1097
+ }
1098
+ function normalizeProofProgressPhase(ownerPhase) {
1099
+ switch (ownerPhase) {
1100
+ case 'bootstrapping':
1101
+ return 'bootstrapping';
1102
+ case 'turn_running':
1103
+ return 'turn_running';
1104
+ case 'turn_completed':
1105
+ return 'turn_completed';
1106
+ case 'turn_failed':
1107
+ return 'turn_failed';
1108
+ case 'ended':
1109
+ return 'completed';
1110
+ default:
1111
+ return ownerPhase ? 'unknown' : 'unknown';
1112
+ }
1113
+ }
1114
+ function defaultProgressSummaryForPhase(phase) {
1115
+ switch (phase) {
1116
+ case 'bootstrapping':
1117
+ return 'Provider worker is bootstrapping.';
1118
+ case 'turn_running':
1119
+ return 'Provider worker turn is active.';
1120
+ case 'turn_completed':
1121
+ return 'Provider worker completed a turn and is evaluating next steps.';
1122
+ case 'turn_failed':
1123
+ return 'Provider worker turn failed.';
1124
+ case 'pending_shared_root_reconciliation':
1125
+ return 'Shared-root reconciliation is pending after merge closeout.';
1126
+ case 'completed':
1127
+ return 'Provider worker completed successfully.';
1128
+ default:
1129
+ return 'Provider worker progress updated.';
1130
+ }
1131
+ }
1132
+ function selectLatestChildProgressSummaryCandidate(proof, currentTurnStartedAt = null) {
1133
+ const childSummaries = [
1134
+ ...selectCurrentTurnChildLanes(proof?.child_lanes ?? null, currentTurnStartedAt)
1135
+ .filter(isCurrentProgressChildLaneSummaryEligible)
1136
+ .flatMap((childLane) => {
1137
+ const summary = normalizeProviderChildLaneProgressSummary(childLane);
1138
+ return summary
1139
+ ? [
1140
+ {
1141
+ source: 'child_lane_summary',
1142
+ event: null,
1143
+ summary,
1144
+ recorded_at: childLaneSummaryRecordedAt(childLane)
1145
+ }
1146
+ ]
1147
+ : [];
1148
+ }),
1149
+ ...selectCurrentTurnChildStreams(proof?.child_streams ?? null, currentTurnStartedAt).flatMap((childStream) => {
1150
+ const summary = normalizeOptionalString(childStream.summary);
1151
+ return summary
1152
+ ? [
1153
+ {
1154
+ source: 'child_stream_summary',
1155
+ event: null,
1156
+ summary,
1157
+ recorded_at: latestIsoTimestamp(normalizeOptionalString(childStream.recorded_at), normalizeOptionalString(childStream.launched_at))
1158
+ }
1159
+ ]
1160
+ : [];
1161
+ })
1162
+ ];
1163
+ if (childSummaries.length === 0) {
1164
+ return null;
1165
+ }
1166
+ return childSummaries.sort((left, right) => compareIsoTimestamp(right.recorded_at, left.recorded_at))[0]
1167
+ ?? null;
1168
+ }
1169
+ function selectLatestChildStreamProgressAt(childStreams, currentTurnStartedAt = null) {
1170
+ const currentTurnChildStreams = selectCurrentTurnChildStreams(childStreams, currentTurnStartedAt);
1171
+ if (currentTurnChildStreams.length === 0) {
1172
+ return null;
1173
+ }
1174
+ return currentTurnChildStreams
1175
+ .map((childStream) => latestIsoTimestamp(normalizeOptionalString(childStream.recorded_at), normalizeOptionalString(childStream.launched_at)))
1176
+ .sort((left, right) => compareIsoTimestamp(right, left))[0] ?? null;
1177
+ }
1178
+ function selectCurrentTurnChildStreams(childStreams, currentTurnStartedAt) {
1179
+ if (!Array.isArray(childStreams)) {
1180
+ return [];
1181
+ }
1182
+ if (!currentTurnStartedAt) {
1183
+ return childStreams;
1184
+ }
1185
+ return childStreams.filter((childStream) => compareIsoTimestamp(childStream.launched_at ?? null, currentTurnStartedAt) >= 0);
1186
+ }
1187
+ function selectActiveChildStream(childStreams) {
1188
+ const active = (childStreams ?? []).filter((stream) => isActiveChildStreamStatus(stream.status));
1189
+ if (active.length === 0) {
1190
+ return null;
1191
+ }
1192
+ return [...active].sort((left, right) => compareIsoTimestamp(right.launched_at ?? null, left.launched_at ?? null))[0] ?? null;
1193
+ }
1194
+ function selectLatestChildLaneProgressAt(childLanes, currentTurnStartedAt = null) {
1195
+ const latestLane = selectLatestChildLaneRecord(selectCurrentTurnChildLanes(childLanes, currentTurnStartedAt));
1196
+ return latestIsoTimestamp(childLaneSummaryRecordedAt(latestLane ?? {}), normalizeOptionalString(latestLane?.decision_at), normalizeOptionalString(latestLane?.launched_at));
1197
+ }
1198
+ function isCurrentProgressChildLaneSummaryEligible(childLane) {
1199
+ const decision = normalizeOptionalString(childLane.decision);
1200
+ return decision !== 'accepted' && decision !== 'rejected' && decision !== 'invalidated';
1201
+ }
1202
+ function childLaneSummaryRecordedAt(childLane) {
1203
+ return normalizeOptionalString(childLane.summary_recorded_at) ?? normalizeOptionalString(childLane.launched_at);
1204
+ }
1205
+ function normalizeProviderChildLaneProgressSummary(childLane) {
1206
+ const summary = normalizeOptionalString(childLane.summary);
1207
+ if (!summary) {
1208
+ return null;
1209
+ }
1210
+ const pipelineId = normalizeOptionalString(childLane.pipeline_id);
1211
+ if (pipelineId !== null && pipelineId !== PROVIDER_LINEAR_CHILD_LANE_PIPELINE_ID) {
1212
+ return summary;
1213
+ }
1214
+ const guardrailCommandCount = normalizeOptionalInteger(childLane.guardrail_command_count);
1215
+ if (guardrailCommandCount !== null && guardrailCommandCount > 0) {
1216
+ return summary;
1217
+ }
1218
+ const guardrailsRequiredSource = normalizeGuardrailsRequiredSource(childLane.guardrails_required_source);
1219
+ if (typeof childLane.guardrails_required !== 'boolean' &&
1220
+ guardrailsRequiredSource === null &&
1221
+ guardrailCommandCount === null) {
1222
+ return summary;
1223
+ }
1224
+ return stripNonApplicableGuardrailSummaryLines({
1225
+ pipeline_id: pipelineId ?? PROVIDER_LINEAR_CHILD_LANE_PIPELINE_ID,
1226
+ guardrails_required: childLane.guardrails_required === true,
1227
+ guardrails_required_source: guardrailsRequiredSource,
1228
+ commands: []
1229
+ }, summary);
1230
+ }
1231
+ function childLaneProgressRecordedAt(childLane) {
1232
+ return latestIsoTimestamp(childLaneSummaryRecordedAt(childLane), normalizeOptionalString(childLane.decision_at), normalizeOptionalString(childLane.launched_at));
1233
+ }
1234
+ function selectActiveChildLane(childLanes) {
1235
+ const active = (childLanes ?? []).filter((lane) => normalizeOptionalString(lane.decision) === 'pending' || Boolean(normalizeOptionalString(lane.in_flight_action)));
1236
+ if (active.length === 0) {
1237
+ return null;
1238
+ }
1239
+ return [...active].sort((left, right) => compareIsoTimestamp(childLaneProgressRecordedAt(right), childLaneProgressRecordedAt(left)))[0] ?? null;
1240
+ }
1241
+ function selectCurrentTurnChildLanes(childLanes, currentTurnStartedAt) {
1242
+ if (!Array.isArray(childLanes)) {
1243
+ return [];
1244
+ }
1245
+ if (!currentTurnStartedAt) {
1246
+ return childLanes;
1247
+ }
1248
+ return childLanes.filter((childLane) => compareIsoTimestamp(childLane.launched_at ?? null, currentTurnStartedAt) >= 0);
1249
+ }
1250
+ function selectLatestChildLaneRecord(childLanes) {
1251
+ const lanes = childLanes ?? [];
1252
+ if (lanes.length === 0) {
1253
+ return null;
1254
+ }
1255
+ return [...lanes]
1256
+ .sort((left, right) => compareIsoTimestamp(childLaneProgressRecordedAt(right), childLaneProgressRecordedAt(left)))[0] ?? null;
1257
+ }
1258
+ function isActiveChildStreamStatus(value) {
1259
+ const normalized = normalizeProviderLinearWorkflowState(value);
1260
+ return Boolean(normalized &&
1261
+ normalized !== 'succeeded' &&
1262
+ normalized !== 'failed' &&
1263
+ normalized !== 'cancelled' &&
1264
+ normalized !== 'canceled' &&
1265
+ normalized !== 'completed');
1266
+ }
1267
+ function isSemanticallyStalled(lastSemanticProgressAt, now) {
1268
+ const lastProgressMs = safeParseTimestamp(lastSemanticProgressAt);
1269
+ const nowMs = safeParseTimestamp(now);
1270
+ if (!Number.isFinite(lastProgressMs) || !Number.isFinite(nowMs)) {
1271
+ return false;
1272
+ }
1273
+ return nowMs - lastProgressMs >= PROVIDER_SEMANTIC_STALL_THRESHOLD_MS;
1274
+ }
1275
+ export function isHighSignalProviderProgressSummary(value) {
1276
+ if (!value) {
1277
+ return false;
1278
+ }
1279
+ return !GENERIC_PROVIDER_PROGRESS_SUMMARIES.has(value.trim().toLowerCase());
1280
+ }
1281
+ const GENERIC_PROVIDER_PROGRESS_SUMMARIES = new Set([
1282
+ 'provider worker is bootstrapping.',
1283
+ 'provider worker is bootstrapping',
1284
+ 'provider worker turn is active.',
1285
+ 'provider worker turn is active',
1286
+ 'provider worker completed a turn and is evaluating next steps.',
1287
+ 'provider worker completed a turn and is evaluating next steps',
1288
+ 'provider worker turn failed.',
1289
+ 'provider worker turn failed',
1290
+ 'provider worker progress updated.',
1291
+ 'provider worker progress updated',
1292
+ 'turn active.',
1293
+ 'turn active',
1294
+ 'turn is still running.',
1295
+ 'turn is still running'
1296
+ ]);
1297
+ function latestIsoTimestamp(...values) {
1298
+ const normalized = values
1299
+ .map((value) => normalizeOptionalString(value))
1300
+ .filter((value) => value !== null)
1301
+ .sort(compareIsoTimestamp);
1302
+ return normalized[normalized.length - 1] ?? null;
1303
+ }
1304
+ function compareIsoTimestamp(left, right) {
1305
+ const leftMs = safeParseTimestamp(left);
1306
+ const rightMs = safeParseTimestamp(right);
1307
+ if (!Number.isFinite(leftMs) && !Number.isFinite(rightMs)) {
1308
+ return 0;
1309
+ }
1310
+ if (!Number.isFinite(leftMs)) {
1311
+ return -1;
1312
+ }
1313
+ if (!Number.isFinite(rightMs)) {
1314
+ return 1;
1315
+ }
1316
+ return leftMs - rightMs;
1317
+ }
1318
+ function safeParseTimestamp(value) {
1319
+ const normalized = normalizeOptionalString(value);
1320
+ if (!normalized) {
1321
+ return Number.NaN;
1322
+ }
1323
+ return Date.parse(normalized);
1324
+ }
1325
+ function normalizeOptionalInteger(value) {
1326
+ if (typeof value === 'number' && Number.isFinite(value)) {
1327
+ return Math.trunc(value);
1328
+ }
1329
+ return null;
1330
+ }
1331
+ function normalizeGuardrailsRequiredSource(value) {
1332
+ return value === 'explicit' || value === 'stage_detection' ? value : null;
1333
+ }
1334
+ function normalizeStringArray(value) {
1335
+ if (!Array.isArray(value)) {
1336
+ return [];
1337
+ }
1338
+ return value
1339
+ .map((entry) => normalizeOptionalString(entry))
1340
+ .filter((entry) => entry !== null);
1341
+ }
1342
+ function normalizeOptionalString(value) {
1343
+ if (typeof value !== 'string') {
1344
+ return null;
1345
+ }
1346
+ const trimmed = value.trim();
1347
+ return trimmed.length > 0 ? trimmed : null;
1348
+ }