@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,1068 @@
1
+ import { readdir, readFile, stat } from 'node:fs/promises';
2
+ import { dirname, isAbsolute, relative, resolve, sep } from 'node:path';
3
+ import { readProviderLinearParallelizationSnapshots, summarizeProviderLinearAuditPath } from './providerLinearWorkflowAudit.js';
4
+ const DEFAULT_THRESHOLDS = {
5
+ staleRefreshAfterMs: 5 * 60 * 1000,
6
+ staleHeartbeatAfterMs: 10 * 60 * 1000,
7
+ staleRetryAfterMs: 10 * 60 * 1000,
8
+ staleClaimQueueAfterMs: 30 * 60 * 1000,
9
+ claimToStartDegradedAfterMs: 5 * 60 * 1000,
10
+ startToHeartbeatDegradedAfterMs: 2 * 60 * 1000,
11
+ linearHeadroomLowRatio: 0.05,
12
+ childLaneCap: 2
13
+ };
14
+ const PROVIDER_LINEAR_CHILD_LANE_IN_FLIGHT_STALE_MS = 30 * 60 * 1000;
15
+ const STATUS_DATASET_NAMES = new Set([
16
+ 'co-status-dataset.json',
17
+ 'operator-dashboard-dataset.json',
18
+ 'operator-dashboard.json',
19
+ 'status-dataset.json',
20
+ 'ui-data.json'
21
+ ]);
22
+ const POLLING_HEALTH_NAMES = new Set([
23
+ 'provider-polling-health.json',
24
+ 'control-polling-health.json',
25
+ 'polling-health.json'
26
+ ]);
27
+ const LINEAR_BUDGET_NAMES = new Set([
28
+ 'linear-budget-state.json',
29
+ 'linear-budget-status.json',
30
+ 'linear-budget.json'
31
+ ]);
32
+ const SKIPPED_SCAN_DIRS = new Set([
33
+ '.git',
34
+ '.next',
35
+ '.turbo',
36
+ 'dist',
37
+ 'node_modules'
38
+ ]);
39
+ const QUEUED_CLAIM_STATES = new Set([
40
+ 'accepted',
41
+ 'starting',
42
+ 'resuming'
43
+ ]);
44
+ const ACTIVE_CLAIM_STATES = new Set([
45
+ ...QUEUED_CLAIM_STATES,
46
+ 'running'
47
+ ]);
48
+ const TERMINAL_MANIFEST_STATUSES = new Set([
49
+ 'cancelled',
50
+ 'canceled',
51
+ 'completed',
52
+ 'failed',
53
+ 'succeeded'
54
+ ]);
55
+ export async function evaluateProviderControlHostFreshnessGauge(options = {}) {
56
+ const thresholds = normalizeThresholds(options.thresholds);
57
+ const nowMs = normalizeNowMs(options.now);
58
+ const generatedAt = new Date(nowMs).toISOString();
59
+ const sources = await discoverProviderControlHostFreshnessGaugeSources(options);
60
+ const findings = [];
61
+ const artifacts = await readGaugeArtifacts(sources, findings);
62
+ const statusDataset = selectLatestJsonArtifact(artifacts.statusDatasets);
63
+ const intakeState = selectLatestJsonArtifact(artifacts.providerIntakeStates);
64
+ const manifests = artifacts.providerManifests;
65
+ const proofs = artifacts.providerProofs.map((proof) => ({
66
+ ...proof,
67
+ manifest: findManifestForProof(proof, manifests)
68
+ }));
69
+ const pollingHealth = selectPollingHealthArtifact({
70
+ explicit: artifacts.pollingHealth,
71
+ intakeState,
72
+ statusDataset
73
+ });
74
+ const linearBudget = selectLinearBudgetArtifact({
75
+ explicit: artifacts.linearBudgetState,
76
+ pollingHealth,
77
+ statusDataset,
78
+ proofs
79
+ });
80
+ const metrics = {
81
+ claim_queue_age_ms: evaluateClaimQueueAge(intakeState, nowMs, thresholds, findings),
82
+ last_successful_refresh_age_ms: evaluateRefreshAge({ intakeState, pollingHealth, statusDataset }, nowMs, thresholds, findings),
83
+ polling_health: evaluatePollingHealth(pollingHealth, thresholds, findings),
84
+ claim_to_start_latency_ms: evaluateClaimToStartLatency(intakeState, manifests, nowMs, thresholds, findings),
85
+ start_to_first_heartbeat_latency_ms: evaluateStartToHeartbeatLatency(proofs, nowMs, thresholds, findings),
86
+ active_heartbeat_age_ms: evaluateActiveHeartbeatAge(intakeState, proofs, nowMs, thresholds, findings),
87
+ terminal_reconciliation_lag_ms: evaluateTerminalReconciliationLag(intakeState, proofs, nowMs, findings),
88
+ retry_backoff_age_ms: evaluateRetryBackoffAge({ intakeState, statusDataset }, nowMs, thresholds, findings),
89
+ child_lane_cap_pressure: evaluateChildLaneCapPressure(proofs, nowMs, thresholds, findings),
90
+ stale_source_verdict: buildUnknownVerdictMetric()
91
+ };
92
+ evaluateLinearBudget(linearBudget, thresholds, findings);
93
+ evaluateWorkerAuditHealth(artifacts.workerAudits, findings);
94
+ if (!hasCoreFreshnessSources(sources)) {
95
+ const auxiliarySourcePath = firstAuxiliarySourcePath(sources);
96
+ findings.push({
97
+ code: auxiliarySourcePath ? 'missing_core_freshness_artifacts' : 'no_provider_control_host_artifacts',
98
+ verdict: 'unknown',
99
+ message: auxiliarySourcePath
100
+ ? 'Auxiliary provider/control-host artifacts were discovered, but no core freshness source was available.'
101
+ : 'No provider/control-host freshness artifacts were discovered.',
102
+ source_path: auxiliarySourcePath ?? sources.artifact_root,
103
+ source_field: null
104
+ });
105
+ }
106
+ const verdict = resolveOverallVerdict(findings);
107
+ metrics.stale_source_verdict = {
108
+ value: verdict,
109
+ unit: null,
110
+ verdict,
111
+ source_path: firstStaleSourcePath(findings),
112
+ source_field: null,
113
+ reason: findings.length === 0 ? 'no stale or contradictory sources detected' : 'see findings'
114
+ };
115
+ const strictFailed = options.strict === true && (verdict === 'stale' || verdict === 'contradictory');
116
+ return {
117
+ schema_version: 1,
118
+ generated_at: generatedAt,
119
+ read_only: true,
120
+ verdict,
121
+ strict_failed: strictFailed,
122
+ thresholds,
123
+ sources,
124
+ metrics,
125
+ findings
126
+ };
127
+ }
128
+ async function discoverProviderControlHostFreshnessGaugeSources(options) {
129
+ const artifactRoot = options.artifactRoot ? resolve(options.artifactRoot) : null;
130
+ const sources = {
131
+ artifact_root: artifactRoot,
132
+ provider_intake_state: normalizePathList(options.paths?.provider_intake_state),
133
+ provider_manifests: normalizePathList(options.paths?.provider_manifests),
134
+ provider_proofs: normalizePathList(options.paths?.provider_proofs),
135
+ worker_audit_jsonl: normalizePathList(options.paths?.worker_audit_jsonl),
136
+ control_endpoint_metadata: normalizePathList(options.paths?.control_endpoint_metadata),
137
+ status_datasets: normalizePathList(options.paths?.status_datasets),
138
+ polling_health: normalizePathList(options.paths?.polling_health),
139
+ linear_budget_state: normalizePathList(options.paths?.linear_budget_state)
140
+ };
141
+ if (!artifactRoot) {
142
+ return sources;
143
+ }
144
+ const discovered = await scanArtifactRoot(artifactRoot, options.maxDepth ?? 8);
145
+ appendUnique(sources.provider_intake_state, discovered.provider_intake_state);
146
+ appendUnique(sources.provider_manifests, discovered.provider_manifests);
147
+ appendUnique(sources.provider_proofs, discovered.provider_proofs);
148
+ appendUnique(sources.worker_audit_jsonl, discovered.worker_audit_jsonl);
149
+ appendUnique(sources.control_endpoint_metadata, discovered.control_endpoint_metadata);
150
+ appendUnique(sources.status_datasets, discovered.status_datasets);
151
+ appendUnique(sources.polling_health, discovered.polling_health);
152
+ appendUnique(sources.linear_budget_state, discovered.linear_budget_state);
153
+ return sources;
154
+ }
155
+ async function scanArtifactRoot(artifactRoot, maxDepth) {
156
+ const sources = {
157
+ provider_intake_state: [],
158
+ provider_manifests: [],
159
+ provider_proofs: [],
160
+ worker_audit_jsonl: [],
161
+ control_endpoint_metadata: [],
162
+ status_datasets: [],
163
+ polling_health: [],
164
+ linear_budget_state: []
165
+ };
166
+ await scanDirectory(artifactRoot, 0, Math.max(0, maxDepth), sources);
167
+ return sources;
168
+ }
169
+ async function scanDirectory(directory, depth, maxDepth, sources) {
170
+ let entries;
171
+ try {
172
+ entries = await readdir(directory, { withFileTypes: true });
173
+ }
174
+ catch {
175
+ return;
176
+ }
177
+ for (const entry of entries) {
178
+ if (entry.isDirectory()) {
179
+ if (depth >= maxDepth || SKIPPED_SCAN_DIRS.has(entry.name)) {
180
+ continue;
181
+ }
182
+ await scanDirectory(resolve(directory, entry.name), depth + 1, maxDepth, sources);
183
+ continue;
184
+ }
185
+ if (!entry.isFile()) {
186
+ continue;
187
+ }
188
+ const path = resolve(directory, entry.name);
189
+ switch (entry.name) {
190
+ case 'provider-intake-state.json':
191
+ sources.provider_intake_state.push(path);
192
+ break;
193
+ case 'manifest.json':
194
+ sources.provider_manifests.push(path);
195
+ break;
196
+ case 'provider-linear-worker-proof.json':
197
+ sources.provider_proofs.push(path);
198
+ break;
199
+ case 'provider-linear-worker-linear-audit.jsonl':
200
+ sources.worker_audit_jsonl.push(path);
201
+ break;
202
+ case 'control_endpoint.json':
203
+ sources.control_endpoint_metadata.push(path);
204
+ break;
205
+ default:
206
+ if (STATUS_DATASET_NAMES.has(entry.name)) {
207
+ sources.status_datasets.push(path);
208
+ }
209
+ else if (POLLING_HEALTH_NAMES.has(entry.name)) {
210
+ sources.polling_health.push(path);
211
+ }
212
+ else if (LINEAR_BUDGET_NAMES.has(entry.name)) {
213
+ sources.linear_budget_state.push(path);
214
+ }
215
+ }
216
+ }
217
+ }
218
+ async function readGaugeArtifacts(sources, findings) {
219
+ const providerIntakeStates = await readJsonArtifacts(sources.provider_intake_state, findings);
220
+ const latestProviderIntakeState = selectLatestJsonArtifact(providerIntakeStates);
221
+ const claimLinkedSources = await discoverClaimLinkedRunArtifactSources(latestProviderIntakeState ? [latestProviderIntakeState] : [], sources.artifact_root);
222
+ appendUnique(sources.provider_manifests, claimLinkedSources.provider_manifests);
223
+ appendUnique(sources.provider_proofs, claimLinkedSources.provider_proofs);
224
+ const [rawManifests, rawProofs, workerAudits, controlEndpointMetadata, pollingHealth, statusDatasets, linearBudgetState] = await Promise.all([
225
+ readJsonArtifacts(sources.provider_manifests, findings),
226
+ readJsonArtifacts(sources.provider_proofs, findings),
227
+ readWorkerAuditArtifacts(sources.worker_audit_jsonl, findings),
228
+ readJsonArtifacts(sources.control_endpoint_metadata, findings),
229
+ readJsonArtifacts(sources.polling_health, findings),
230
+ readJsonArtifacts(sources.status_datasets, findings),
231
+ readJsonArtifacts(sources.linear_budget_state, findings)
232
+ ]);
233
+ const providerManifests = rawManifests.flatMap((artifact) => {
234
+ const value = asRecord(artifact.value);
235
+ return value ? [{ path: artifact.path, runDir: dirname(artifact.path), value }] : [];
236
+ });
237
+ const providerProofs = rawProofs.flatMap((artifact) => {
238
+ const value = asRecord(artifact.value);
239
+ return value ? [{ path: artifact.path, runDir: dirname(artifact.path), value, manifest: null }] : [];
240
+ });
241
+ return {
242
+ providerIntakeStates,
243
+ providerManifests,
244
+ providerProofs,
245
+ workerAudits,
246
+ controlEndpointMetadata,
247
+ pollingHealth,
248
+ statusDatasets,
249
+ linearBudgetState
250
+ };
251
+ }
252
+ async function discoverClaimLinkedRunArtifactSources(providerIntakeStates, artifactRoot) {
253
+ const provider_manifests = [];
254
+ const provider_proofs = [];
255
+ for (const artifact of providerIntakeStates) {
256
+ const claims = asRecord(artifact.value)?.claims;
257
+ if (!Array.isArray(claims)) {
258
+ continue;
259
+ }
260
+ for (const rawClaim of claims) {
261
+ const claim = asRecord(rawClaim);
262
+ if (!claim || !ACTIVE_CLAIM_STATES.has(readState(claim))) {
263
+ continue;
264
+ }
265
+ const manifestPath = normalizeOptionalString(claim?.run_manifest_path);
266
+ if (!manifestPath) {
267
+ continue;
268
+ }
269
+ const resolvedManifestPath = await firstReadablePath(resolveClaimLinkedRunManifestPathCandidates({
270
+ artifact,
271
+ artifactRoot,
272
+ manifestPath
273
+ }));
274
+ if (!resolvedManifestPath) {
275
+ continue;
276
+ }
277
+ provider_manifests.push(resolvedManifestPath);
278
+ const proofPath = resolve(dirname(resolvedManifestPath), 'provider-linear-worker-proof.json');
279
+ if (await isReadableFile(proofPath)) {
280
+ provider_proofs.push(proofPath);
281
+ }
282
+ }
283
+ }
284
+ return {
285
+ provider_manifests,
286
+ provider_proofs
287
+ };
288
+ }
289
+ function resolveClaimLinkedRunManifestPathCandidates(input) {
290
+ if (isAbsolute(input.manifestPath)) {
291
+ return [input.manifestPath];
292
+ }
293
+ const bases = [
294
+ dirname(input.artifact.path),
295
+ input.artifactRoot,
296
+ findRepoRootFromRunsPath(input.artifact.path),
297
+ input.artifactRoot ? findRepoRootFromRunsPath(input.artifactRoot) : null
298
+ ];
299
+ return Array.from(new Set(bases.flatMap((base) => (base ? [resolve(base, input.manifestPath)] : []))));
300
+ }
301
+ function findRepoRootFromRunsPath(path) {
302
+ const parts = resolve(path).split(sep);
303
+ const runsIndex = parts.lastIndexOf('.runs');
304
+ if (runsIndex <= 0) {
305
+ return null;
306
+ }
307
+ return parts.slice(0, runsIndex).join(sep) || sep;
308
+ }
309
+ async function firstReadablePath(candidates) {
310
+ for (const candidate of candidates) {
311
+ if (await isReadableFile(candidate)) {
312
+ return candidate;
313
+ }
314
+ }
315
+ return null;
316
+ }
317
+ async function isReadableFile(path) {
318
+ try {
319
+ return (await stat(path)).isFile();
320
+ }
321
+ catch {
322
+ return false;
323
+ }
324
+ }
325
+ async function readJsonArtifacts(paths, findings) {
326
+ const artifacts = [];
327
+ for (const path of paths) {
328
+ try {
329
+ const raw = await readFile(path, 'utf8');
330
+ artifacts.push({ path, value: JSON.parse(raw) });
331
+ }
332
+ catch (error) {
333
+ findings.push({
334
+ code: 'artifact_unreadable',
335
+ verdict: 'unknown',
336
+ message: `Artifact could not be read or parsed: ${describeError(error)}`,
337
+ source_path: path,
338
+ source_field: null
339
+ });
340
+ }
341
+ }
342
+ return artifacts;
343
+ }
344
+ async function readWorkerAuditArtifacts(paths, findings) {
345
+ const artifacts = [];
346
+ for (const path of paths) {
347
+ let raw;
348
+ try {
349
+ raw = await readFile(path, 'utf8');
350
+ }
351
+ catch (error) {
352
+ findings.push({
353
+ code: 'worker_audit_unreadable',
354
+ verdict: 'unknown',
355
+ message: `Worker audit JSONL could not be read: ${describeError(error)}`,
356
+ source_path: path,
357
+ source_field: null
358
+ });
359
+ continue;
360
+ }
361
+ const lines = raw.split(/\r?\n/u).filter((line) => line.trim().length > 0);
362
+ const malformedLineCount = lines.filter((line) => {
363
+ try {
364
+ JSON.parse(line);
365
+ return false;
366
+ }
367
+ catch {
368
+ return true;
369
+ }
370
+ }).length;
371
+ if (malformedLineCount > 0) {
372
+ findings.push({
373
+ code: 'worker_audit_jsonl_malformed',
374
+ verdict: 'unknown',
375
+ message: `Worker audit JSONL has ${malformedLineCount} malformed line(s).`,
376
+ source_path: path,
377
+ source_field: null
378
+ });
379
+ }
380
+ artifacts.push({
381
+ path,
382
+ summary: await summarizeProviderLinearAuditPath(path),
383
+ lineCount: lines.length,
384
+ malformedLineCount
385
+ });
386
+ }
387
+ return artifacts;
388
+ }
389
+ function evaluateClaimQueueAge(intakeState, nowMs, thresholds, findings) {
390
+ const claims = collectClaims(intakeState);
391
+ const queuedClaims = claims.filter((claim) => QUEUED_CLAIM_STATES.has(readState(claim)));
392
+ const candidates = queuedClaims.flatMap((claim) => {
393
+ const acceptedAt = timestampMs(claim.accepted_at ?? claim.updated_at);
394
+ return acceptedAt === null ? [] : [{ claim, acceptedAt, ageMs: Math.max(0, nowMs - acceptedAt) }];
395
+ });
396
+ if (candidates.length === 0) {
397
+ return metric(null, 'ms', 'unknown', intakeState?.path ?? null, 'claims[].accepted_at', 'no queued claims observed');
398
+ }
399
+ const oldest = candidates.reduce((winner, candidate) => candidate.ageMs > winner.ageMs ? candidate : winner);
400
+ if (oldest.ageMs > thresholds.staleClaimQueueAfterMs) {
401
+ findings.push({
402
+ code: 'claim_queue_stale',
403
+ verdict: 'stale',
404
+ message: `Oldest queued provider claim is ${oldest.ageMs}ms old.`,
405
+ source_path: intakeState?.path ?? null,
406
+ source_field: 'claims[].accepted_at'
407
+ });
408
+ }
409
+ return metric(oldest.ageMs, 'ms', oldest.ageMs > thresholds.staleClaimQueueAfterMs ? 'stale' : 'healthy', intakeState?.path ?? null, 'claims[].accepted_at', null);
410
+ }
411
+ function evaluateRefreshAge(input, nowMs, thresholds, findings) {
412
+ const observedRefreshCandidates = [
413
+ timestampCandidate(input.pollingHealth, 'last_success_at'),
414
+ timestampCandidate(input.intakeState, 'polling.last_success_at'),
415
+ timestampCandidate(input.statusDataset, 'polling.last_success_at')
416
+ ].filter((candidate) => candidate !== null);
417
+ const candidates = observedRefreshCandidates.length > 0
418
+ ? observedRefreshCandidates
419
+ : [timestampCandidate(input.statusDataset, 'generated_at')].filter((candidate) => candidate !== null);
420
+ const latest = selectLatestTimestampCandidate(candidates);
421
+ if (!latest) {
422
+ const missingRefreshSource = firstRefreshTimestampSource(input);
423
+ if (missingRefreshSource) {
424
+ findings.push({
425
+ code: 'refresh_timestamp_missing',
426
+ verdict: 'unknown',
427
+ message: 'No successful provider/control-host refresh timestamp was observed.',
428
+ source_path: missingRefreshSource.path,
429
+ source_field: missingRefreshSource.field
430
+ });
431
+ }
432
+ return metric(null, 'ms', 'unknown', missingRefreshSource?.path ?? null, missingRefreshSource?.field ?? null, 'no refresh timestamp observed');
433
+ }
434
+ const age = Math.max(0, nowMs - latest.timestampMs);
435
+ if (age > thresholds.staleRefreshAfterMs) {
436
+ findings.push({
437
+ code: 'stale_refresh',
438
+ verdict: 'stale',
439
+ message: `Last successful provider/control-host refresh is ${age}ms old.`,
440
+ source_path: latest.path,
441
+ source_field: latest.field
442
+ });
443
+ }
444
+ return metric(age, 'ms', age > thresholds.staleRefreshAfterMs ? 'stale' : 'healthy', latest.path, latest.field, null);
445
+ }
446
+ function evaluatePollingHealth(pollingHealth, _thresholds, findings) {
447
+ const polling = asRecord(pollingHealth?.value);
448
+ if (!polling) {
449
+ return metric(null, null, 'unknown', null, null, 'no polling health artifact observed');
450
+ }
451
+ if (polling.stuck === true || polling.restart_required === true) {
452
+ findings.push({
453
+ code: 'polling_stuck',
454
+ verdict: 'stale',
455
+ message: 'Provider polling health reports a stuck/restart-required state.',
456
+ source_path: pollingHealth?.path ?? null,
457
+ source_field: polling.stuck === true ? 'stuck' : 'restart_required'
458
+ });
459
+ return metric('stuck', null, 'stale', pollingHealth?.path ?? null, null, normalizeOptionalString(polling.reason));
460
+ }
461
+ if (polling.last_error && !polling.last_success_at) {
462
+ findings.push({
463
+ code: 'polling_error_without_success',
464
+ verdict: 'degraded',
465
+ message: 'Provider polling reports an error and no successful refresh.',
466
+ source_path: pollingHealth?.path ?? null,
467
+ source_field: 'last_error'
468
+ });
469
+ return metric('error', null, 'degraded', pollingHealth?.path ?? null, 'last_error', normalizeOptionalString(polling.last_error));
470
+ }
471
+ return metric('ok', null, 'healthy', pollingHealth?.path ?? null, null, null);
472
+ }
473
+ function evaluateClaimToStartLatency(intakeState, manifests, _nowMs, thresholds, findings) {
474
+ const claims = collectClaims(intakeState).filter(isActiveClaim);
475
+ const candidates = claims.flatMap((claim) => {
476
+ const acceptedAt = timestampMs(claim.accepted_at);
477
+ const runId = normalizeOptionalString(claim.run_id);
478
+ const manifest = runId ? findLatestManifestForRunId(manifests, runId) : null;
479
+ const startedAt = timestampMs(claim.launch_started_at) ??
480
+ timestampMs(manifest?.value.started_at) ??
481
+ timestampMs(manifest?.value.startedAt);
482
+ return acceptedAt !== null && startedAt !== null
483
+ ? [{ latencyMs: Math.max(0, startedAt - acceptedAt), manifest }]
484
+ : [];
485
+ });
486
+ if (candidates.length === 0) {
487
+ return metric(null, 'ms', 'unknown', intakeState?.path ?? null, 'claims[].launch_started_at', 'no claim-to-start pair observed');
488
+ }
489
+ const slowest = candidates.reduce((winner, candidate) => candidate.latencyMs > winner.latencyMs ? candidate : winner);
490
+ if (slowest.latencyMs > thresholds.claimToStartDegradedAfterMs) {
491
+ findings.push({
492
+ code: 'claim_to_start_latency_degraded',
493
+ verdict: 'degraded',
494
+ message: `Provider claim-to-start latency is ${slowest.latencyMs}ms.`,
495
+ source_path: slowest.manifest?.path ?? intakeState?.path ?? null,
496
+ source_field: 'claims[].accepted_at'
497
+ });
498
+ }
499
+ return metric(slowest.latencyMs, 'ms', slowest.latencyMs > thresholds.claimToStartDegradedAfterMs ? 'degraded' : 'healthy', slowest.manifest?.path ?? intakeState?.path ?? null, 'claims[].accepted_at', null);
500
+ }
501
+ function evaluateStartToHeartbeatLatency(proofs, _nowMs, thresholds, findings) {
502
+ const candidates = proofs.flatMap((proof) => {
503
+ if (!isActiveProof(proof)) {
504
+ return [];
505
+ }
506
+ const startedAt = timestampMs(proof.value.attempt_started_at) ??
507
+ timestampMs(proof.value.current_turn_started_at) ??
508
+ timestampMs(proof.manifest?.value.started_at) ??
509
+ timestampMs(proof.manifest?.value.startedAt);
510
+ const heartbeatAt = firstHeartbeatTimestampMs(proof);
511
+ return startedAt !== null && heartbeatAt !== null
512
+ ? [{ latencyMs: Math.max(0, heartbeatAt - startedAt), proof }]
513
+ : [];
514
+ });
515
+ if (candidates.length === 0) {
516
+ return metric(null, 'ms', 'unknown', null, null, 'no start-to-heartbeat pair observed');
517
+ }
518
+ const slowest = candidates.reduce((winner, candidate) => candidate.latencyMs > winner.latencyMs ? candidate : winner);
519
+ if (slowest.latencyMs > thresholds.startToHeartbeatDegradedAfterMs) {
520
+ findings.push({
521
+ code: 'start_to_first_heartbeat_latency_degraded',
522
+ verdict: 'degraded',
523
+ message: `Provider start-to-first-heartbeat latency is ${slowest.latencyMs}ms.`,
524
+ source_path: slowest.proof.path,
525
+ source_field: 'first_heartbeat_at'
526
+ });
527
+ }
528
+ return metric(slowest.latencyMs, 'ms', slowest.latencyMs > thresholds.startToHeartbeatDegradedAfterMs ? 'degraded' : 'healthy', slowest.proof.path, 'first_heartbeat_at', null);
529
+ }
530
+ function evaluateActiveHeartbeatAge(intakeState, proofs, nowMs, thresholds, findings) {
531
+ const activeProofs = proofs.filter(isActiveProof);
532
+ const missingProofClaims = collectClaims(intakeState)
533
+ .filter((claim) => readState(claim) === 'running')
534
+ .filter((claim) => {
535
+ const runId = normalizeOptionalString(claim.run_id);
536
+ return !runId || !activeProofs.some((proof) => resolveProofRunId(proof) === runId);
537
+ });
538
+ if (missingProofClaims.length > 0) {
539
+ findings.push({
540
+ code: 'active_worker_proof_missing',
541
+ verdict: 'unknown',
542
+ message: 'Provider intake has a running claim without matching active provider-worker proof evidence.',
543
+ source_path: intakeState?.path ?? null,
544
+ source_field: 'claims[].run_id'
545
+ });
546
+ }
547
+ const candidates = activeProofs.flatMap((proof) => {
548
+ if (!isActiveProof(proof)) {
549
+ return [];
550
+ }
551
+ const heartbeatAt = latestTimestampMs(timestampMs(proof.value.updated_at), timestampMs(proof.value.last_event_at), firstTimestampMs(proof.value.current_turn_activity, 'recorded_at'), timestampMs(proof.manifest?.value.heartbeat_at), timestampMs(proof.manifest?.value.updated_at));
552
+ return heartbeatAt === null ? [] : [{ ageMs: Math.max(0, nowMs - heartbeatAt), proof }];
553
+ });
554
+ if (candidates.length === 0) {
555
+ return metric(null, 'ms', 'unknown', missingProofClaims.length > 0 ? intakeState?.path ?? null : null, missingProofClaims.length > 0 ? 'claims[].run_id' : null, missingProofClaims.length > 0
556
+ ? 'running claim has no matching active provider proof'
557
+ : 'no active provider proof observed');
558
+ }
559
+ const stalest = candidates.reduce((winner, candidate) => candidate.ageMs > winner.ageMs ? candidate : winner);
560
+ if (stalest.ageMs > thresholds.staleHeartbeatAfterMs) {
561
+ findings.push({
562
+ code: 'active_heartbeat_stale',
563
+ verdict: 'stale',
564
+ message: `Active provider worker heartbeat is ${stalest.ageMs}ms old.`,
565
+ source_path: stalest.proof.path,
566
+ source_field: 'updated_at'
567
+ });
568
+ }
569
+ return metric(stalest.ageMs, 'ms', stalest.ageMs > thresholds.staleHeartbeatAfterMs ? 'stale' : 'healthy', stalest.proof.path, 'updated_at', null);
570
+ }
571
+ function evaluateTerminalReconciliationLag(intakeState, proofs, nowMs, findings) {
572
+ const claims = collectClaims(intakeState);
573
+ const activeClaims = claims.filter((claim) => ACTIVE_CLAIM_STATES.has(readState(claim)));
574
+ const unreconcilableTerminalProofs = [];
575
+ const candidates = proofs.flatMap((proof) => {
576
+ if (!isTerminalProof(proof)) {
577
+ return [];
578
+ }
579
+ const runId = normalizeOptionalString(proof.manifest?.value.run_id) ?? normalizeOptionalString(proof.value.run_id);
580
+ if (!runId) {
581
+ if (activeClaims.length > 0) {
582
+ unreconcilableTerminalProofs.push(proof);
583
+ findings.push({
584
+ code: 'terminal_proof_missing_run_id',
585
+ verdict: 'unknown',
586
+ message: 'Terminal provider proof/manifest cannot be reconciled against active claims because run_id is missing.',
587
+ source_path: proof.path,
588
+ source_field: 'run_id'
589
+ });
590
+ }
591
+ return [];
592
+ }
593
+ const matchingClaim = activeClaims.find((claim) => {
594
+ const claimRunId = normalizeOptionalString(claim.run_id);
595
+ return claimRunId === runId;
596
+ });
597
+ if (!matchingClaim) {
598
+ return [];
599
+ }
600
+ const terminalAt = latestTimestampMs(timestampMs(proof.manifest?.value.completed_at), timestampMs(proof.manifest?.value.updated_at), timestampMs(proof.value.updated_at), timestampMs(proof.value.last_event_at));
601
+ return [{ lagMs: terminalAt === null ? null : Math.max(0, nowMs - terminalAt), proof }];
602
+ });
603
+ if (candidates.length === 0) {
604
+ const unreconcilableTerminalProof = unreconcilableTerminalProofs[0];
605
+ if (unreconcilableTerminalProof) {
606
+ return metric(null, 'ms', 'unknown', unreconcilableTerminalProof.path, 'run_id', 'terminal proof/manifest missing run_id while active claims exist');
607
+ }
608
+ return metric(0, 'ms', 'healthy', intakeState?.path ?? null, null, null);
609
+ }
610
+ const worst = candidates.reduce((winner, candidate) => (candidate.lagMs ?? 0) > (winner.lagMs ?? 0) ? candidate : winner);
611
+ findings.push({
612
+ code: 'terminal_proof_with_active_claim',
613
+ verdict: 'contradictory',
614
+ message: worst.lagMs === null
615
+ ? 'Terminal provider proof/manifest still has an active intake claim; terminal timestamp is unavailable.'
616
+ : `Terminal provider proof/manifest still has an active intake claim after ${worst.lagMs}ms.`,
617
+ source_path: worst.proof.path,
618
+ source_field: 'owner_status'
619
+ });
620
+ return metric(worst.lagMs, 'ms', 'contradictory', worst.proof.path, 'owner_status', 'terminal proof/manifest with active claim');
621
+ }
622
+ function evaluateRetryBackoffAge(input, nowMs, thresholds, findings) {
623
+ const retryCandidates = [
624
+ ...collectClaims(input.intakeState)
625
+ .filter((claim) => claim.retry_queued === true || timestampMs(claim.retry_due_at) !== null)
626
+ .flatMap((claim) => {
627
+ const dueAt = timestampMs(claim.retry_due_at);
628
+ return dueAt === null ? [] : [{ dueAt, sourcePath: input.intakeState?.path ?? null, field: 'claims[].retry_due_at' }];
629
+ }),
630
+ ...collectStatusRetrying(input.statusDataset).flatMap((retry) => {
631
+ const dueAt = timestampMs(retry.due_at);
632
+ return dueAt === null ? [] : [{ dueAt, sourcePath: input.statusDataset?.path ?? null, field: 'retrying[].due_at' }];
633
+ })
634
+ ];
635
+ if (retryCandidates.length === 0) {
636
+ return metric(null, 'ms', 'unknown', null, null, 'no retry/backoff evidence observed');
637
+ }
638
+ const oldest = retryCandidates.reduce((winner, candidate) => candidate.dueAt < winner.dueAt ? candidate : winner);
639
+ const overdueAge = Math.max(0, nowMs - oldest.dueAt);
640
+ if (overdueAge > thresholds.staleRetryAfterMs) {
641
+ findings.push({
642
+ code: 'retry_queue_stale',
643
+ verdict: 'stale',
644
+ message: `Retry/backoff queue is overdue by ${overdueAge}ms.`,
645
+ source_path: oldest.sourcePath,
646
+ source_field: oldest.field
647
+ });
648
+ }
649
+ return metric(overdueAge, 'ms', overdueAge > thresholds.staleRetryAfterMs ? 'stale' : 'healthy', oldest.sourcePath, oldest.field, null);
650
+ }
651
+ function evaluateChildLaneCapPressure(proofs, nowMs, thresholds, findings) {
652
+ const activeProofs = proofs.filter(isActiveProof);
653
+ const lanes = activeProofs.flatMap((proof) => collectArrayRecords(proof.value.child_lanes).map((lane) => ({ lane, proof })));
654
+ const activeByParent = new Map();
655
+ for (const { lane, proof } of lanes) {
656
+ if (!isActiveChildLane(lane, nowMs)) {
657
+ continue;
658
+ }
659
+ const parentKey = childLaneParentKey(proof);
660
+ const bucket = activeByParent.get(parentKey);
661
+ activeByParent.set(parentKey, {
662
+ count: (bucket?.count ?? 0) + 1,
663
+ proof: bucket?.proof ?? proof
664
+ });
665
+ }
666
+ const buckets = [...activeByParent.values()];
667
+ if (buckets.length === 0) {
668
+ return metric(0, 'ratio', 'healthy', activeProofs[0]?.path ?? proofs[0]?.path ?? null, 'child_lanes', null);
669
+ }
670
+ const busiest = buckets.reduce((winner, bucket) => bucket.count > winner.count ? bucket : winner);
671
+ const pressure = thresholds.childLaneCap > 0 ? busiest.count / thresholds.childLaneCap : busiest.count;
672
+ if (pressure >= 1) {
673
+ findings.push({
674
+ code: 'child_lane_cap_pressure',
675
+ verdict: 'degraded',
676
+ message: `Child-lane cap pressure is ${busiest.count}/${thresholds.childLaneCap} for one parent run.`,
677
+ source_path: busiest.proof.path,
678
+ source_field: 'child_lanes'
679
+ });
680
+ }
681
+ return metric(pressure, 'ratio', pressure >= 1 ? 'degraded' : 'healthy', busiest.proof.path, 'child_lanes', `${busiest.count}/${thresholds.childLaneCap} active, pending, or unaccepted child lanes for one parent run`);
682
+ }
683
+ function evaluateLinearBudget(linearBudget, thresholds, findings) {
684
+ const budget = asRecord(linearBudget?.value);
685
+ if (!budget) {
686
+ return;
687
+ }
688
+ const suppression = normalizeOptionalString(budget.suppression);
689
+ if (budget.cooldown_active === true || (suppression !== null && suppression !== 'none')) {
690
+ findings.push({
691
+ code: 'linear_budget_suppressed',
692
+ verdict: 'degraded',
693
+ message: 'Linear shared-budget state reports active cooldown or suppression.',
694
+ source_path: linearBudget?.path ?? null,
695
+ source_field: budget.cooldown_active === true ? 'cooldown_active' : 'suppression'
696
+ });
697
+ return;
698
+ }
699
+ const lowBucket = ['requests', 'endpoint_requests', 'complexity', 'endpoint_complexity']
700
+ .map((field) => ({ field, bucket: asRecord(budget[field]) }))
701
+ .find(({ bucket }) => {
702
+ const limit = finiteNumber(bucket?.limit);
703
+ const remaining = finiteNumber(bucket?.remaining);
704
+ if (limit === null || limit <= 0 || remaining === null) {
705
+ return false;
706
+ }
707
+ return remaining / limit <= thresholds.linearHeadroomLowRatio;
708
+ });
709
+ if (lowBucket) {
710
+ findings.push({
711
+ code: 'linear_headroom_low',
712
+ verdict: 'degraded',
713
+ message: 'Linear shared-budget headroom is low.',
714
+ source_path: linearBudget?.path ?? null,
715
+ source_field: `${lowBucket.field}.remaining`
716
+ });
717
+ }
718
+ }
719
+ function firstRefreshTimestampSource(input) {
720
+ if (input.pollingHealth) {
721
+ return { path: input.pollingHealth.path, field: 'last_success_at' };
722
+ }
723
+ if (input.intakeState) {
724
+ return { path: input.intakeState.path, field: 'polling.last_success_at' };
725
+ }
726
+ if (input.statusDataset) {
727
+ return { path: input.statusDataset.path, field: 'polling.last_success_at' };
728
+ }
729
+ return null;
730
+ }
731
+ function looksLikeLinearBudget(value) {
732
+ const budget = asRecord(value);
733
+ if (!budget) {
734
+ return false;
735
+ }
736
+ if (budget.cooldown_active !== undefined ||
737
+ budget.suppression !== undefined ||
738
+ budget.retry_after_seconds !== undefined ||
739
+ budget.retryAfterSeconds !== undefined) {
740
+ return true;
741
+ }
742
+ return ['requests', 'endpoint_requests', 'complexity', 'endpoint_complexity']
743
+ .some((field) => asRecord(budget[field]) !== null);
744
+ }
745
+ function evaluateWorkerAuditHealth(workerAudits, findings) {
746
+ for (const audit of workerAudits) {
747
+ if (audit.lineCount > 0 && audit.summary.attempted_count === 0 && audit.malformedLineCount === 0) {
748
+ findings.push({
749
+ code: 'worker_audit_jsonl_unrecognized',
750
+ verdict: 'unknown',
751
+ message: 'Worker audit JSONL has entries, but none match the provider Linear audit contract.',
752
+ source_path: audit.path,
753
+ source_field: null
754
+ });
755
+ }
756
+ if (audit.summary.failure_count > 0 && audit.summary.success_count === 0) {
757
+ findings.push({
758
+ code: 'worker_audit_all_failed',
759
+ verdict: 'degraded',
760
+ message: 'Worker audit JSONL records only failed Linear helper operations.',
761
+ source_path: audit.path,
762
+ source_field: 'ok'
763
+ });
764
+ }
765
+ if (audit.summary.parallelization_entries.some((entry) => entry.ok) &&
766
+ readProviderLinearParallelizationSnapshots(audit.summary).length === 0) {
767
+ findings.push({
768
+ code: 'worker_audit_parallelization_unusable',
769
+ verdict: 'degraded',
770
+ message: 'Worker audit JSONL has successful parallelization entries that cannot be normalized.',
771
+ source_path: audit.path,
772
+ source_field: 'parallelization'
773
+ });
774
+ }
775
+ }
776
+ }
777
+ function selectPollingHealthArtifact(input) {
778
+ return (selectLatestJsonArtifact(input.explicit) ??
779
+ nestedJsonArtifact(input.intakeState, 'polling') ??
780
+ nestedJsonArtifact(input.statusDataset, 'polling'));
781
+ }
782
+ function selectLinearBudgetArtifact(input) {
783
+ const proofBudgets = input.proofs.flatMap((proof) => {
784
+ const artifact = nestedJsonArtifact({ path: proof.path, value: proof.value }, 'linear_budget');
785
+ return artifact ? [artifact] : [];
786
+ });
787
+ return (selectLatestJsonArtifact(input.explicit) ??
788
+ nestedJsonArtifact(input.pollingHealth, 'linear_budget') ??
789
+ selectStatusDatasetLinearBudgetArtifact(input.statusDataset) ??
790
+ selectLatestJsonArtifact(proofBudgets));
791
+ }
792
+ function selectStatusDatasetLinearBudgetArtifact(statusDataset) {
793
+ const combinedLinearBudget = nestedJsonArtifact(statusDataset, 'rate_limits.linear_budget');
794
+ if (combinedLinearBudget) {
795
+ return combinedLinearBudget;
796
+ }
797
+ const pollingLinearBudget = nestedJsonArtifact(statusDataset, 'polling.linear_budget');
798
+ if (pollingLinearBudget) {
799
+ return pollingLinearBudget;
800
+ }
801
+ const rateLimits = nestedJsonArtifact(statusDataset, 'rate_limits');
802
+ if (looksLikeLinearBudget(rateLimits?.value)) {
803
+ return rateLimits;
804
+ }
805
+ return null;
806
+ }
807
+ function findManifestForProof(proof, manifests) {
808
+ const proofRunId = normalizeOptionalString(proof.value.run_id);
809
+ if (proofRunId) {
810
+ const runMatches = manifests.filter((manifest) => normalizeOptionalString(manifest.value.run_id) === proofRunId);
811
+ const directoryMatches = runMatches.filter((manifest) => manifest.runDir === proof.runDir);
812
+ return selectLatestManifestArtifact(directoryMatches) ?? selectLatestManifestArtifact(runMatches);
813
+ }
814
+ return selectLatestManifestArtifact(manifests.filter((manifest) => manifest.runDir === proof.runDir));
815
+ }
816
+ function findLatestManifestForRunId(manifests, runId) {
817
+ return selectLatestManifestArtifact(manifests.filter((manifest) => normalizeOptionalString(manifest.value.run_id) === runId));
818
+ }
819
+ function resolveProofRunId(proof) {
820
+ return normalizeOptionalString(proof.manifest?.value.run_id) ?? normalizeOptionalString(proof.value.run_id);
821
+ }
822
+ function collectClaims(intakeState) {
823
+ const value = asRecord(intakeState?.value);
824
+ return collectArrayRecords(value?.claims);
825
+ }
826
+ function isActiveClaim(claim) {
827
+ return ACTIVE_CLAIM_STATES.has(readState(claim));
828
+ }
829
+ function collectStatusRetrying(statusDataset) {
830
+ const value = asRecord(statusDataset?.value);
831
+ return collectArrayRecords(value?.retrying);
832
+ }
833
+ function isActiveProof(proof) {
834
+ if (isTerminalProof(proof)) {
835
+ return false;
836
+ }
837
+ const manifestStatus = normalizeOptionalString(proof.manifest?.value.status)?.toLowerCase() ?? null;
838
+ if (manifestStatus && TERMINAL_MANIFEST_STATUSES.has(manifestStatus)) {
839
+ return false;
840
+ }
841
+ return true;
842
+ }
843
+ function isTerminalProof(proof) {
844
+ const manifestStatus = normalizeOptionalString(proof.manifest?.value.status)?.toLowerCase() ?? null;
845
+ if (manifestStatus && TERMINAL_MANIFEST_STATUSES.has(manifestStatus)) {
846
+ return true;
847
+ }
848
+ const ownerPhase = normalizeOptionalString(proof.value.owner_phase);
849
+ const ownerStatus = normalizeOptionalString(proof.value.owner_status);
850
+ return ownerPhase === 'ended' && (ownerStatus === 'succeeded' || ownerStatus === 'failed');
851
+ }
852
+ function firstHeartbeatTimestampMs(proof) {
853
+ return earliestTimestampMs(timestampMs(proof.value.first_heartbeat_at), timestampMs(proof.value.firstHeartbeatAt), timestampMs(proof.value.first_activity_at), timestampMs(proof.value.firstActivityAt), timestampMs(proof.value.first_event_at), timestampMs(proof.value.firstEventAt), timestampMs(proof.manifest?.value.first_heartbeat_at), timestampMs(proof.manifest?.value.firstHeartbeatAt), timestampMs(proof.manifest?.value.first_activity_at), timestampMs(proof.manifest?.value.firstActivityAt));
854
+ }
855
+ function isActiveChildLane(lane, nowMs) {
856
+ if (lane.in_flight_action) {
857
+ const startedAt = timestampMs(lane.in_flight_started_at);
858
+ return startedAt !== null && nowMs - startedAt < PROVIDER_LINEAR_CHILD_LANE_IN_FLIGHT_STALE_MS;
859
+ }
860
+ const decision = normalizeOptionalString(lane.decision);
861
+ return decision === 'pending';
862
+ }
863
+ function childLaneParentKey(proof) {
864
+ return (normalizeOptionalString(proof.value.parent_run_id) ??
865
+ normalizeOptionalString(proof.value.parentRunId) ??
866
+ normalizeOptionalString(proof.value.run_id) ??
867
+ normalizeOptionalString(proof.manifest?.value.parent_run_id) ??
868
+ normalizeOptionalString(proof.manifest?.value.run_id) ??
869
+ proof.runDir);
870
+ }
871
+ function readState(record) {
872
+ return normalizeOptionalString(record.state)?.toLowerCase() ?? 'unknown';
873
+ }
874
+ function selectLatestJsonArtifact(artifacts) {
875
+ if (artifacts.length === 0) {
876
+ return null;
877
+ }
878
+ return [...artifacts].sort(compareJsonArtifactsByFreshness).at(-1) ?? null;
879
+ }
880
+ function selectLatestManifestArtifact(manifests) {
881
+ return [...manifests].sort(compareJsonArtifactsByFreshness).at(-1) ?? null;
882
+ }
883
+ function compareJsonArtifactsByFreshness(left, right) {
884
+ const leftTs = artifactTimestampMs(left) ?? Number.NEGATIVE_INFINITY;
885
+ const rightTs = artifactTimestampMs(right) ?? Number.NEGATIVE_INFINITY;
886
+ if (leftTs !== rightTs) {
887
+ return leftTs - rightTs;
888
+ }
889
+ return left.path.localeCompare(right.path);
890
+ }
891
+ function artifactTimestampMs(artifact) {
892
+ const value = asRecord(artifact.value);
893
+ return latestTimestampMs(timestampMs(value?.updated_at), timestampMs(value?.generated_at), timestampMs(value?.observed_at), timestampMs(value?.recorded_at), timestampMs(value?.last_success_at), timestampMs(value?.lastSuccessAt), timestampMs(value?.last_completed_at), timestampMs(value?.lastCompletedAt));
894
+ }
895
+ function nestedJsonArtifact(artifact, fieldPath) {
896
+ if (!artifact) {
897
+ return null;
898
+ }
899
+ const value = readPath(artifact.value, fieldPath);
900
+ return value && typeof value === 'object' ? { path: artifact.path, value } : null;
901
+ }
902
+ function timestampCandidate(artifact, fieldPath) {
903
+ const timestamp = timestampMs(readPath(artifact?.value, fieldPath));
904
+ return timestamp === null ? null : { timestampMs: timestamp, path: artifact?.path ?? null, field: fieldPath };
905
+ }
906
+ function selectLatestTimestampCandidate(candidates) {
907
+ return candidates.length === 0
908
+ ? null
909
+ : candidates.reduce((winner, candidate) => candidate.timestampMs > winner.timestampMs ? candidate : winner);
910
+ }
911
+ function metric(value, unit, verdict, sourcePath, sourceField, reason) {
912
+ return {
913
+ value,
914
+ unit,
915
+ verdict,
916
+ source_path: sourcePath,
917
+ source_field: sourceField,
918
+ reason
919
+ };
920
+ }
921
+ function buildUnknownVerdictMetric() {
922
+ return metric(null, null, 'unknown', null, null, 'verdict not evaluated yet');
923
+ }
924
+ function resolveOverallVerdict(findings) {
925
+ if (findings.some((finding) => finding.verdict === 'contradictory')) {
926
+ return 'contradictory';
927
+ }
928
+ if (findings.some((finding) => finding.verdict === 'stale')) {
929
+ return 'stale';
930
+ }
931
+ if (findings.some((finding) => finding.verdict === 'degraded')) {
932
+ return 'degraded';
933
+ }
934
+ if (findings.some((finding) => finding.verdict === 'unknown')) {
935
+ return 'unknown';
936
+ }
937
+ return 'healthy';
938
+ }
939
+ function firstStaleSourcePath(findings) {
940
+ return findings.find((finding) => finding.verdict === 'contradictory' || finding.verdict === 'stale')?.source_path ?? null;
941
+ }
942
+ function normalizeThresholds(input) {
943
+ return {
944
+ ...DEFAULT_THRESHOLDS,
945
+ ...Object.fromEntries(Object.entries(input ?? {}).flatMap(([key, value]) => typeof value === 'number' && Number.isFinite(value) && value >= 0 ? [[key, value]] : []))
946
+ };
947
+ }
948
+ function normalizePathList(paths) {
949
+ return Array.isArray(paths) ? paths.map((path) => resolve(path)) : [];
950
+ }
951
+ function appendUnique(target, values) {
952
+ const seen = new Set(target);
953
+ for (const value of values) {
954
+ if (!seen.has(value)) {
955
+ target.push(value);
956
+ seen.add(value);
957
+ }
958
+ }
959
+ }
960
+ function normalizeNowMs(value) {
961
+ if (value instanceof Date) {
962
+ const timestamp = value.getTime();
963
+ if (!Number.isFinite(timestamp)) {
964
+ throw new Error(`Invalid now value: ${String(value)}.`);
965
+ }
966
+ return timestamp;
967
+ }
968
+ if (typeof value === 'number') {
969
+ if (!Number.isFinite(value)) {
970
+ throw new Error(`Invalid now value: ${String(value)}.`);
971
+ }
972
+ return value;
973
+ }
974
+ if (typeof value === 'string' && value.trim().length > 0) {
975
+ const parsed = Date.parse(value);
976
+ if (!Number.isFinite(parsed)) {
977
+ throw new Error(`Invalid now value: ${value}.`);
978
+ }
979
+ return parsed;
980
+ }
981
+ return Date.now();
982
+ }
983
+ function timestampMs(value) {
984
+ const string = normalizeOptionalString(value);
985
+ if (!string) {
986
+ return null;
987
+ }
988
+ const parsed = Date.parse(string);
989
+ return Number.isFinite(parsed) ? parsed : null;
990
+ }
991
+ function firstTimestampMs(record, field) {
992
+ return timestampMs(asRecord(record)?.[field]);
993
+ }
994
+ function latestTimestampMs(...values) {
995
+ const finite = values.filter((value) => typeof value === 'number' && Number.isFinite(value));
996
+ return finite.length === 0 ? null : Math.max(...finite);
997
+ }
998
+ function earliestTimestampMs(...values) {
999
+ const finite = values.filter((value) => typeof value === 'number' && Number.isFinite(value));
1000
+ return finite.length === 0 ? null : Math.min(...finite);
1001
+ }
1002
+ function finiteNumber(value) {
1003
+ return typeof value === 'number' && Number.isFinite(value) ? value : null;
1004
+ }
1005
+ function normalizeOptionalString(value) {
1006
+ if (typeof value !== 'string') {
1007
+ return null;
1008
+ }
1009
+ const trimmed = value.trim();
1010
+ return trimmed.length > 0 ? trimmed : null;
1011
+ }
1012
+ function asRecord(value) {
1013
+ return value !== null && typeof value === 'object' && !Array.isArray(value)
1014
+ ? value
1015
+ : null;
1016
+ }
1017
+ function collectArrayRecords(value) {
1018
+ return Array.isArray(value)
1019
+ ? value.filter((entry) => asRecord(entry) !== null)
1020
+ : [];
1021
+ }
1022
+ function hasCoreFreshnessSources(sources) {
1023
+ return [
1024
+ sources.provider_intake_state,
1025
+ sources.provider_proofs,
1026
+ sources.status_datasets,
1027
+ sources.polling_health
1028
+ ].some((entries) => entries.length > 0);
1029
+ }
1030
+ function firstAuxiliarySourcePath(sources) {
1031
+ return sources.provider_manifests[0] ?? sources.worker_audit_jsonl[0] ?? sources.linear_budget_state[0] ?? null;
1032
+ }
1033
+ function readPath(value, fieldPath) {
1034
+ return fieldPath.split('.').reduce((current, key) => asRecord(current)?.[key], value);
1035
+ }
1036
+ function describeError(error) {
1037
+ return error instanceof Error ? error.message : String(error);
1038
+ }
1039
+ export function formatProviderControlHostFreshnessGaugeText(report) {
1040
+ const root = report.sources.artifact_root ?? 'explicit paths';
1041
+ const lines = [
1042
+ `Provider/control-host freshness gauge: ${report.verdict}`,
1043
+ `Generated: ${report.generated_at}`,
1044
+ `Artifact root: ${root}`
1045
+ ];
1046
+ for (const finding of report.findings) {
1047
+ const path = finding.source_path ? ` (${relativeOrOriginal(process.cwd(), finding.source_path)})` : '';
1048
+ lines.push(`- ${finding.verdict}: ${finding.code}${path} - ${finding.message}`);
1049
+ }
1050
+ return lines.join('\n');
1051
+ }
1052
+ function relativeOrOriginal(from, path) {
1053
+ const relativePath = relative(from, path);
1054
+ return relativePath && !relativePath.startsWith('..') ? relativePath : path;
1055
+ }
1056
+ export async function assertProviderControlHostFreshnessArtifactRoot(path) {
1057
+ const resolvedPath = resolve(path);
1058
+ let stats;
1059
+ try {
1060
+ stats = await stat(resolvedPath);
1061
+ }
1062
+ catch {
1063
+ throw new Error(`Artifact root does not exist: ${path}`);
1064
+ }
1065
+ if (!stats.isDirectory()) {
1066
+ throw new Error(`Artifact root must be a directory: ${path}`);
1067
+ }
1068
+ }