@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,2420 @@
1
+ import { execFile } from 'node:child_process';
2
+ import { readFile, readdir } from 'node:fs/promises';
3
+ import { basename, dirname, isAbsolute, join, posix, relative, resolve, sep } from 'node:path';
4
+ import process from 'node:process';
5
+ import { promisify } from 'node:util';
6
+ import { PROVIDER_CONTROL_HOST_RUN_ID_ENV, PROVIDER_CONTROL_HOST_TASK_ID_ENV, PROVIDER_LAUNCH_SOURCE_ENV, PROVIDER_LAUNCH_TOKEN_ENV } from '../../../scripts/lib/provider-run-contract.js';
7
+ import { PROVIDER_LINEAR_AUDIT_ENV_VAR } from './control/providerLinearWorkflowAudit.js';
8
+ import { resolveLiveLinearTrackedIssueById } from './control/linearDispatchSource.js';
9
+ import { sanitizeRunId } from '../persistence/sanitizeRunId.js';
10
+ import { logger } from '../logger.js';
11
+ import { PROVIDER_LINEAR_WORKER_PROOF_FILENAME, defaultExecRunner, loadProviderLinearWorkerContext, refreshProviderLinearWorkerProofSnapshot, transactProviderLinearWorkerChildLanes } from './providerLinearWorkerRunner.js';
12
+ import { isChildLaneParentDirtySuppressionCode, findDeterministicProviderMutationSuppression, resolveProviderLinearWorkerAttemptStartedAt } from './control/providerLinearWorkerTruth.js';
13
+ import { resolveProviderLinearAuditPath, summarizeProviderLinearAuditPath } from './control/providerLinearWorkflowAudit.js';
14
+ import { PROVIDER_LINEAR_CHILD_LANE_FILES_ENV, PROVIDER_LINEAR_CHILD_LANE_INSTRUCTIONS_ENV, PROVIDER_LINEAR_CHILD_LANE_PARENT_SNAPSHOT_BASE_SHA_ENV, PROVIDER_LINEAR_CHILD_LANE_PARENT_SNAPSHOT_CAPTURED_AT_ENV, PROVIDER_LINEAR_CHILD_LANE_PARENT_SNAPSHOT_ISSUE_STATE_ENV, PROVIDER_LINEAR_CHILD_LANE_PARENT_SNAPSHOT_ISSUE_STATE_TYPE_ENV, PROVIDER_LINEAR_CHILD_LANE_PARENT_SNAPSHOT_ISSUE_UPDATED_AT_ENV, PROVIDER_LINEAR_CHILD_LANE_PARENT_WORKSPACE_PATH_ENV, PROVIDER_LINEAR_CHILD_LANE_PHASES_ENV, PROVIDER_LINEAR_CHILD_LANE_PROOF_FILENAME, PROVIDER_LINEAR_CHILD_LANE_PURPOSE_ENV, PROVIDER_LINEAR_CHILD_LANE_STREAM_ENV } from './providerLinearChildLaneRunner.js';
15
+ import { formatProviderLinearChildLanePathSelectors, providerLinearChildLanePathMatchesSelectors, providerLinearChildLanePathSelectorsEqual, providerLinearChildLanePathSelectorsOverlap, resolveProviderLinearChildLaneScopeContract, resolveProviderLinearChildLaneSupportedPhases } from './providerLinearChildLanePhaseContract.js';
16
+ import { applyResolvedProgramInvocationEnvOverrides, resolveCodexOrchestratorBootstrapInvocation } from './utils/packageProgramResolver.js';
17
+ import { slugify } from './utils/strings.js';
18
+ import { parseTrailingJsonObject } from './utils/trailingJsonObject.js';
19
+ import { countGuardrailCommands, resolveGuardrailsRequiredForManifest, resolveGuardrailsRequiredSourceForManifest, stripNonApplicableGuardrailSummaryLines } from './run/manifest.js';
20
+ const execFileAsync = promisify(execFile);
21
+ const PROVIDER_LINEAR_CHILD_LANE_PIPELINE_ID = 'provider-linear-child-lane';
22
+ const PROVIDER_LINEAR_CHILD_LANE_MUTATION_REASON = 'Only the parent provider-linear-worker may mutate the issue lifecycle. Same-issue child lanes are bounded helpers that must return patch artifacts for parent review.';
23
+ export const PROVIDER_LINEAR_CHILD_LANE_PARALLEL_FIRST_CAP = 2;
24
+ const PROVIDER_LINEAR_CHILD_LANE_IN_FLIGHT_STALE_MS = 30 * 60 * 1000;
25
+ const PROVIDER_LINEAR_CHILD_LANE_LAUNCH_RECOVERY_POLL_INTERVAL_MS = 250;
26
+ const PROVIDER_LINEAR_CHILD_LANE_ENV_KEYS_TO_REMOVE = [
27
+ 'MCP_RUNNER_TASK_ID',
28
+ 'CODEX_ORCHESTRATOR_TASK_ID',
29
+ 'CODEX_ORCHESTRATOR_RUN_ID',
30
+ 'CODEX_ORCHESTRATOR_PIPELINE_ID',
31
+ 'CODEX_ORCHESTRATOR_MANIFEST_PATH',
32
+ 'CODEX_ORCHESTRATOR_RUN_DIR',
33
+ 'CODEX_ORCHESTRATOR_RUNTIME_MODE',
34
+ 'CODEX_ORCHESTRATOR_RUNTIME_MODE_ACTIVE',
35
+ 'CODEX_RUNTIME_MODE',
36
+ 'CODEX_ORCHESTRATOR_APPSERVER_SESSION_ID',
37
+ 'CODEX_THREAD_ID',
38
+ PROVIDER_CONTROL_HOST_TASK_ID_ENV,
39
+ PROVIDER_CONTROL_HOST_RUN_ID_ENV,
40
+ PROVIDER_LAUNCH_SOURCE_ENV,
41
+ PROVIDER_LAUNCH_TOKEN_ENV,
42
+ PROVIDER_LINEAR_AUDIT_ENV_VAR
43
+ ];
44
+ const PROVIDER_LINEAR_CHILD_LANE_OPTIONAL_ENV_KEYS = [
45
+ PROVIDER_LINEAR_CHILD_LANE_INSTRUCTIONS_ENV,
46
+ PROVIDER_LINEAR_CHILD_LANE_PARENT_SNAPSHOT_BASE_SHA_ENV,
47
+ PROVIDER_LINEAR_CHILD_LANE_PARENT_SNAPSHOT_CAPTURED_AT_ENV,
48
+ PROVIDER_LINEAR_CHILD_LANE_PARENT_SNAPSHOT_ISSUE_UPDATED_AT_ENV,
49
+ PROVIDER_LINEAR_CHILD_LANE_PARENT_SNAPSHOT_ISSUE_STATE_ENV,
50
+ PROVIDER_LINEAR_CHILD_LANE_PARENT_SNAPSHOT_ISSUE_STATE_TYPE_ENV
51
+ ];
52
+ const DEFAULT_DEPENDENCIES = {
53
+ execRunner: defaultExecRunner,
54
+ readDir: async (path) => await readdir(path, { withFileTypes: true }),
55
+ transactChildLanes: async (runDir, action) => await transactProviderLinearWorkerChildLanes(runDir, action),
56
+ readParentDirtyPaths: async (workspacePath) => {
57
+ const modified = await execFileAsync('git', ['-C', workspacePath, 'diff', '--name-only', '--relative', 'HEAD', '--'], {
58
+ maxBuffer: 10 * 1024 * 1024
59
+ });
60
+ const untracked = await execFileAsync('git', ['-C', workspacePath, 'ls-files', '--others', '--exclude-standard'], {
61
+ maxBuffer: 10 * 1024 * 1024
62
+ });
63
+ return normalizeScopeEntries([...modified.stdout.split(/\r?\n/u), ...untracked.stdout.split(/\r?\n/u)]);
64
+ },
65
+ refreshProofSnapshot: async (runDir, auditPath, env) => {
66
+ await refreshProviderLinearWorkerProofSnapshot(runDir, auditPath, undefined, undefined, env, {
67
+ emitProgressEvent: (message) => logger.warn(message)
68
+ });
69
+ },
70
+ readTrackedIssue: async ({ issueId, sourceSetup, env }) => {
71
+ const resolution = await resolveLiveLinearTrackedIssueById({
72
+ issueId,
73
+ sourceSetup,
74
+ env
75
+ });
76
+ return resolution.kind === 'ready' ? resolution.tracked_issue : null;
77
+ },
78
+ readParentHeadSha: async (workspacePath) => {
79
+ const result = await execFileAsync('git', ['-C', workspacePath, 'rev-parse', 'HEAD']);
80
+ return normalizeOptionalString(result.stdout);
81
+ },
82
+ applyPatchArtifact: async (workspacePath, patchPath) => {
83
+ await execFileAsync('git', ['-C', workspacePath, 'apply', '--3way', '--whitespace=nowarn', patchPath]);
84
+ },
85
+ readChildLaneProof: async (proofPath) => JSON.parse(await readFile(proofPath, 'utf8')),
86
+ now: () => new Date().toISOString(),
87
+ sleep: async (ms) => {
88
+ await new Promise((resolvePromise) => {
89
+ setTimeout(resolvePromise, ms);
90
+ });
91
+ },
92
+ warn: (message) => {
93
+ logger.warn(message);
94
+ }
95
+ };
96
+ async function refreshProviderLinearChildLaneProofSnapshotBestEffort(input) {
97
+ try {
98
+ await input.deps.refreshProofSnapshot(input.runDir, input.auditPath, input.env);
99
+ }
100
+ catch (error) {
101
+ input.deps.warn(`provider-linear-child-lane warning: failed to refresh proof snapshot ${input.warningContext}: ${error instanceof Error ? error.message : String(error)}`);
102
+ }
103
+ }
104
+ export async function runProviderLinearChildLaneShell(params, overrides = {}) {
105
+ const deps = { ...DEFAULT_DEPENDENCIES, ...overrides };
106
+ const env = params.env ?? process.env;
107
+ let context;
108
+ try {
109
+ context = await loadProviderLinearWorkerContext(env);
110
+ }
111
+ catch (error) {
112
+ return failureResult({
113
+ action: normalizeAction(params.action) ?? 'launch',
114
+ issueId: null,
115
+ issueIdentifier: null,
116
+ sourceSetup: null,
117
+ stream: null,
118
+ childRun: null,
119
+ childLane: null,
120
+ code: 'provider_worker_child_lane_context_missing',
121
+ message: error instanceof Error ? error.message : String(error),
122
+ status: 412
123
+ });
124
+ }
125
+ const sourceSetup = context.sourceSetup ?? null;
126
+ if (context.pipelineId !== 'provider-linear-worker') {
127
+ return failureResult({
128
+ action: normalizeAction(params.action) ?? 'launch',
129
+ issueId: context.issueId,
130
+ issueIdentifier: context.issueIdentifier,
131
+ sourceSetup,
132
+ stream: params.streamName ?? null,
133
+ childRun: null,
134
+ childLane: null,
135
+ code: 'provider_worker_child_lane_requires_provider_worker',
136
+ message: 'linear child-lane is only available inside provider-linear-worker runs.',
137
+ status: 409
138
+ });
139
+ }
140
+ if (!context.providerControlHostRecordedInManifest ||
141
+ !context.providerControlHostTaskId ||
142
+ !context.providerControlHostRunId ||
143
+ !context.providerControlHostMatchesManifest) {
144
+ const message = formatProviderWorkerChildLaneProvenanceInvalidMessage(context, env);
145
+ return failureResult({
146
+ action: normalizeAction(params.action) ?? 'launch',
147
+ issueId: context.issueId,
148
+ issueIdentifier: context.issueIdentifier,
149
+ sourceSetup,
150
+ stream: params.streamName ?? null,
151
+ childRun: null,
152
+ childLane: null,
153
+ code: 'provider_worker_child_lane_provenance_invalid',
154
+ message,
155
+ status: 412
156
+ });
157
+ }
158
+ const action = normalizeAction(params.action);
159
+ if (!action) {
160
+ return failureResult({
161
+ action: 'launch',
162
+ issueId: context.issueId,
163
+ issueIdentifier: context.issueIdentifier,
164
+ sourceSetup,
165
+ stream: params.streamName ?? null,
166
+ childRun: null,
167
+ childLane: null,
168
+ code: 'provider_worker_child_lane_action_invalid',
169
+ message: 'linear child-lane requires --action launch|accept|reject|invalidate.',
170
+ status: 422
171
+ });
172
+ }
173
+ try {
174
+ if (action === 'launch') {
175
+ return await launchChildLane({
176
+ ...params,
177
+ action,
178
+ env
179
+ }, context, deps, sourceSetup);
180
+ }
181
+ return await resolveChildLaneDecision({
182
+ ...params,
183
+ action,
184
+ env
185
+ }, context, deps, sourceSetup);
186
+ }
187
+ catch (error) {
188
+ return failureResult({
189
+ action,
190
+ issueId: context.issueId,
191
+ issueIdentifier: context.issueIdentifier,
192
+ sourceSetup,
193
+ stream: normalizeChildLaneStreamName(params.streamName) ?? params.streamName ?? null,
194
+ childRun: null,
195
+ childLane: null,
196
+ code: 'provider_worker_child_lane_unhandled_failure',
197
+ message: error instanceof Error ? error.message : String(error),
198
+ status: 502
199
+ });
200
+ }
201
+ }
202
+ async function launchChildLane(params, context, deps, sourceSetup) {
203
+ const stream = normalizeChildLaneStreamName(params.streamName);
204
+ if (!stream) {
205
+ return failureResult({
206
+ action: 'launch',
207
+ issueId: context.issueId,
208
+ issueIdentifier: context.issueIdentifier,
209
+ sourceSetup,
210
+ stream: params.streamName ?? null,
211
+ childRun: null,
212
+ childLane: null,
213
+ code: 'provider_worker_child_lane_stream_invalid',
214
+ message: 'Provider worker child lanes require a non-empty stream name after slug normalization.',
215
+ status: 422
216
+ });
217
+ }
218
+ const purpose = normalizeOptionalString(params.purpose);
219
+ let scope;
220
+ try {
221
+ scope = normalizeChildLaneScope(params.files ?? [], params.phases ?? [], context.repoRoot);
222
+ }
223
+ catch (error) {
224
+ const message = formatChildLaneScopeLaunchFailureMessage(error instanceof Error ? error.message : String(error));
225
+ return failureResult({
226
+ action: 'launch',
227
+ issueId: context.issueId,
228
+ issueIdentifier: context.issueIdentifier,
229
+ sourceSetup,
230
+ stream,
231
+ childRun: null,
232
+ childLane: null,
233
+ code: 'provider_worker_child_lane_scope_missing',
234
+ message,
235
+ status: 422
236
+ });
237
+ }
238
+ if (!purpose || !scope) {
239
+ return failureResult({
240
+ action: 'launch',
241
+ issueId: context.issueId,
242
+ issueIdentifier: context.issueIdentifier,
243
+ sourceSetup,
244
+ stream,
245
+ childRun: null,
246
+ childLane: null,
247
+ code: 'provider_worker_child_lane_scope_missing',
248
+ message: formatChildLaneScopeLaunchFailureMessage('Provider worker child lanes require --purpose and at least one declared file or supported phase scope.'),
249
+ status: 422
250
+ });
251
+ }
252
+ let dirtyScopeConflict;
253
+ try {
254
+ dirtyScopeConflict = await resolveParentDirtyScopeConflict(context.repoRoot, scope, deps);
255
+ }
256
+ catch (error) {
257
+ return failureResult({
258
+ action: 'launch',
259
+ issueId: context.issueId,
260
+ issueIdentifier: context.issueIdentifier,
261
+ sourceSetup,
262
+ stream,
263
+ childRun: null,
264
+ childLane: null,
265
+ code: 'provider_worker_child_lane_parent_dirty_check_failed',
266
+ message: `Failed to inspect parent workspace state before launching child lane: ${error instanceof Error ? error.message : String(error)}`,
267
+ status: 502
268
+ });
269
+ }
270
+ if (dirtyScopeConflict) {
271
+ const retrySuppression = await resolveSameAttemptParentDirtyRetrySuppression(context.runDir, context.issueId, params.env);
272
+ if (retrySuppression) {
273
+ return failureResult({
274
+ action: 'launch',
275
+ issueId: context.issueId,
276
+ issueIdentifier: context.issueIdentifier,
277
+ sourceSetup,
278
+ stream,
279
+ childRun: null,
280
+ childLane: null,
281
+ code: 'provider_worker_child_lane_parent_dirty_retry_suppressed',
282
+ message: `${dirtyScopeConflict} Same-attempt retry suppression is in effect: ${retrySuppression.instruction}`,
283
+ status: 409
284
+ });
285
+ }
286
+ return failureResult({
287
+ action: 'launch',
288
+ issueId: context.issueId,
289
+ issueIdentifier: context.issueIdentifier,
290
+ sourceSetup,
291
+ stream,
292
+ childRun: null,
293
+ childLane: null,
294
+ code: 'provider_worker_child_lane_parent_dirty',
295
+ message: dirtyScopeConflict,
296
+ status: 409
297
+ });
298
+ }
299
+ const parentSnapshot = await resolveParentSnapshot(context, params.env, deps);
300
+ const baseSha = await deps.readParentHeadSha(context.repoRoot);
301
+ const childTaskId = `${context.taskId}-${stream}`;
302
+ const childRunsRoot = resolveWorkspaceScopedArtifactDir(context.repoRoot, params.env.CODEX_ORCHESTRATOR_RUNS_DIR, '.runs');
303
+ const now = deps.now();
304
+ const launchReservation = buildReservedChildLaneRecord({
305
+ stream,
306
+ childRunsRoot,
307
+ childTaskId,
308
+ context,
309
+ purpose,
310
+ instructions: params.instructions ?? null,
311
+ scope,
312
+ sourceSetup,
313
+ parentSnapshot: {
314
+ ...parentSnapshot,
315
+ base_sha: baseSha
316
+ },
317
+ now
318
+ });
319
+ const reservation = await deps.transactChildLanes(context.runDir, async (records) => {
320
+ const conflicting = findPendingChildLaneConflict(records, stream, scope);
321
+ if (conflicting) {
322
+ return {
323
+ records,
324
+ result: { conflicting, capExhausted: [], reserved: null }
325
+ };
326
+ }
327
+ const countedLanes = selectChildLanesCountingTowardParallelFirstCap(records, now);
328
+ if (countedLanes.length >= PROVIDER_LINEAR_CHILD_LANE_PARALLEL_FIRST_CAP) {
329
+ return {
330
+ records,
331
+ result: { conflicting: null, capExhausted: countedLanes, reserved: null }
332
+ };
333
+ }
334
+ return {
335
+ records: [...records, launchReservation],
336
+ result: { conflicting: null, capExhausted: [], reserved: launchReservation }
337
+ };
338
+ });
339
+ if (reservation.conflicting) {
340
+ return failureResult({
341
+ action: 'launch',
342
+ issueId: context.issueId,
343
+ issueIdentifier: context.issueIdentifier,
344
+ sourceSetup,
345
+ stream,
346
+ childRun: null,
347
+ childLane: reservation.conflicting,
348
+ code: 'provider_worker_child_lane_scope_conflict',
349
+ message: describePendingChildLaneConflict(stream, reservation.conflicting),
350
+ status: 409
351
+ });
352
+ }
353
+ if (reservation.capExhausted.length > 0) {
354
+ return failureResult({
355
+ action: 'launch',
356
+ issueId: context.issueId,
357
+ issueIdentifier: context.issueIdentifier,
358
+ sourceSetup,
359
+ stream,
360
+ childRun: null,
361
+ childLane: null,
362
+ code: 'provider_worker_child_lane_cap_exhausted',
363
+ message: describeChildLaneCapExhaustion(reservation.capExhausted),
364
+ status: 409
365
+ });
366
+ }
367
+ const invocation = resolveCodexOrchestratorInvocation(params.env);
368
+ const args = [
369
+ ...invocation.argsPrefix,
370
+ 'start',
371
+ PROVIDER_LINEAR_CHILD_LANE_PIPELINE_ID,
372
+ '--task',
373
+ childTaskId,
374
+ '--parent-run',
375
+ context.runId,
376
+ '--issue-provider',
377
+ 'linear',
378
+ '--issue-id',
379
+ context.issueId,
380
+ '--issue-identifier',
381
+ context.issueIdentifier,
382
+ '--format',
383
+ 'json',
384
+ '--no-interactive'
385
+ ];
386
+ if (context.issueUpdatedAt) {
387
+ args.push('--issue-updated-at', context.issueUpdatedAt);
388
+ }
389
+ const runtimeMode = normalizeRuntimeMode(params.env.CODEX_ORCHESTRATOR_RUNTIME_MODE_ACTIVE ?? params.env.CODEX_ORCHESTRATOR_RUNTIME_MODE);
390
+ if (runtimeMode) {
391
+ args.push('--runtime-mode', runtimeMode);
392
+ }
393
+ const childStartEnv = buildProviderLinearChildLaneStartEnv(params.env, {
394
+ repoRoot: context.repoRoot,
395
+ taskId: childTaskId,
396
+ stream,
397
+ purpose,
398
+ instructions: params.instructions ?? null,
399
+ scope,
400
+ parentWorkspacePath: context.repoRoot,
401
+ parentSnapshot: {
402
+ ...parentSnapshot,
403
+ base_sha: baseSha
404
+ },
405
+ sourceSetup
406
+ });
407
+ applyResolvedProgramInvocationEnvOverrides(childStartEnv, invocation.envOverrides);
408
+ const execAbortController = new AbortController();
409
+ let execSettled = false;
410
+ const execPromise = deps.execRunner({
411
+ command: invocation.command,
412
+ args,
413
+ cwd: context.repoRoot,
414
+ env: childStartEnv,
415
+ mirrorOutput: false,
416
+ abortSignal: execAbortController.signal
417
+ });
418
+ void execPromise.then(() => {
419
+ execSettled = true;
420
+ }, () => {
421
+ execSettled = true;
422
+ });
423
+ let execResult = null;
424
+ let recoveredLaunch = null;
425
+ let launchError = null;
426
+ const recoveredLaunchPromise = waitForRecoveredChildLaneLaunchCandidate({
427
+ reservation: launchReservation,
428
+ context,
429
+ childRunsRoot,
430
+ deps,
431
+ isExecSettled: () => execSettled,
432
+ now
433
+ });
434
+ const advisoryRecoveredLaunchPromise = recoveredLaunchPromise.catch((error) => {
435
+ deps.warn(`provider-linear-child-lane warning: ignored launch-recovery scan failure while awaiting exec result: ${error instanceof Error ? error.message : String(error)}`);
436
+ return null;
437
+ });
438
+ try {
439
+ const launchOutcome = await Promise.race([
440
+ execPromise.then((result) => ({ kind: 'exec', result })),
441
+ advisoryRecoveredLaunchPromise.then((recovered) => ({ kind: 'recovered', recovered }))
442
+ ]);
443
+ if (launchOutcome.kind === 'recovered') {
444
+ if (launchOutcome.recovered) {
445
+ recoveredLaunch = launchOutcome.recovered;
446
+ if (!execSettled) {
447
+ execAbortController.abort(new Error(`Recovered child lane ${recoveredLaunch.childRun.run_id} from manifest/proof while the launcher reservation still reported ${launchReservation.run_id}.`));
448
+ }
449
+ }
450
+ }
451
+ else {
452
+ execResult = launchOutcome.result;
453
+ }
454
+ if (!execResult) {
455
+ try {
456
+ execResult = await execPromise;
457
+ }
458
+ catch (error) {
459
+ launchError = error;
460
+ }
461
+ }
462
+ }
463
+ catch (error) {
464
+ launchError = error;
465
+ }
466
+ if (!recoveredLaunch) {
467
+ recoveredLaunch = await advisoryRecoveredLaunchPromise;
468
+ }
469
+ if (launchError && !recoveredLaunch) {
470
+ await removeReservedChildLane(context.runDir, launchReservation, deps);
471
+ return failureResult({
472
+ action: 'launch',
473
+ issueId: context.issueId,
474
+ issueIdentifier: context.issueIdentifier,
475
+ sourceSetup,
476
+ stream,
477
+ childRun: null,
478
+ childLane: null,
479
+ code: 'provider_worker_child_lane_launch_failed',
480
+ message: launchError instanceof Error ? launchError.message : String(launchError),
481
+ status: 502
482
+ });
483
+ }
484
+ const childRun = recoveredLaunch?.childRun ??
485
+ (execResult
486
+ ? await parseProviderChildLaneRunResult(execResult.stdout, context.repoRoot, childStartEnv.CODEX_ORCHESTRATOR_RUNS_DIR ?? join(context.repoRoot, '.runs'), childTaskId)
487
+ : null);
488
+ if (!childRun) {
489
+ await removeReservedChildLane(context.runDir, launchReservation, deps);
490
+ const detail = execResult
491
+ ? [execResult.stderr.trim(), execResult.stdout.trim()].filter(Boolean)[0] ?? 'unknown child-lane output'
492
+ : 'unknown child-lane output';
493
+ return failureResult({
494
+ action: 'launch',
495
+ issueId: context.issueId,
496
+ issueIdentifier: context.issueIdentifier,
497
+ sourceSetup,
498
+ stream,
499
+ childRun: null,
500
+ childLane: null,
501
+ code: 'provider_worker_child_lane_output_invalid',
502
+ message: `Could not parse child lane output: ${detail}`,
503
+ status: 502
504
+ });
505
+ }
506
+ const proofPath = join(childRun.artifact_root, PROVIDER_LINEAR_CHILD_LANE_PROOF_FILENAME);
507
+ const childProof = recoveredLaunch?.proof ?? (await deps.readChildLaneProof(proofPath).catch(() => null));
508
+ if (childRun.status === 'succeeded' && (!childProof || !childProof.patch_artifact_path)) {
509
+ await removeReservedChildLane(context.runDir, launchReservation, deps);
510
+ return failureResult({
511
+ action: 'launch',
512
+ issueId: context.issueId,
513
+ issueIdentifier: context.issueIdentifier,
514
+ sourceSetup,
515
+ stream,
516
+ childRun,
517
+ childLane: null,
518
+ code: 'provider_worker_child_lane_proof_missing',
519
+ message: `Child lane ${stream} did not produce a readable proof bundle with a patch artifact.`,
520
+ status: 502
521
+ });
522
+ }
523
+ let recordedScope = recoveredLaunch?.childLane.scope ?? scope;
524
+ if (!recoveredLaunch && childProof?.scope) {
525
+ try {
526
+ const proofScope = resolveProviderLinearChildLaneScopeContract(childProof.scope);
527
+ if (!areChildLaneScopesEquivalent(scope, proofScope)) {
528
+ await removeReservedChildLane(context.runDir, launchReservation, deps);
529
+ return failureResult({
530
+ action: 'launch',
531
+ issueId: context.issueId,
532
+ issueIdentifier: context.issueIdentifier,
533
+ sourceSetup,
534
+ stream,
535
+ childRun,
536
+ childLane: null,
537
+ code: 'provider_worker_child_lane_proof_invalid',
538
+ message: 'Child lane proof scope does not match the parent-launched scope contract.',
539
+ status: 409
540
+ });
541
+ }
542
+ recordedScope = proofScope;
543
+ }
544
+ catch (error) {
545
+ await removeReservedChildLane(context.runDir, launchReservation, deps);
546
+ return failureResult({
547
+ action: 'launch',
548
+ issueId: context.issueId,
549
+ issueIdentifier: context.issueIdentifier,
550
+ sourceSetup,
551
+ stream,
552
+ childRun,
553
+ childLane: null,
554
+ code: 'provider_worker_child_lane_proof_invalid',
555
+ message: `Child lane ${stream} wrote an invalid proof scope contract: ${error instanceof Error ? error.message : String(error)}`,
556
+ status: 409
557
+ });
558
+ }
559
+ }
560
+ const childLane = recoveredLaunch?.childLane ?? (() => {
561
+ const zeroBytePatch = execResult?.exitCode === 0 && childRun.status === 'succeeded' && childProof?.patch_bytes === 0;
562
+ return {
563
+ stream,
564
+ pipeline_id: PROVIDER_LINEAR_CHILD_LANE_PIPELINE_ID,
565
+ task_id: childTaskId,
566
+ run_id: childRun.run_id,
567
+ status: childRun.status,
568
+ manifest_path: childRun.manifest_path,
569
+ artifact_root: childRun.artifact_root,
570
+ log_path: childRun.log_path,
571
+ summary: childRun.summary ?? normalizeOptionalString(childProof?.last_message),
572
+ guardrails_required: childRun.guardrails_required,
573
+ guardrails_required_source: childRun.guardrails_required_source,
574
+ guardrail_command_count: childRun.guardrail_command_count,
575
+ issue_id: context.issueId,
576
+ issue_identifier: context.issueIdentifier,
577
+ workspace_path: context.repoRoot,
578
+ source_setup: sourceSetup,
579
+ launched_at: launchReservation.launched_at,
580
+ purpose,
581
+ instructions: normalizeOptionalString(params.instructions),
582
+ scope: recordedScope,
583
+ parent_snapshot: childProof?.parent_snapshot ?? {
584
+ ...parentSnapshot,
585
+ base_sha: baseSha,
586
+ captured_at: deps.now()
587
+ },
588
+ lane_workspace_path: childProof?.lane_workspace_path ?? null,
589
+ patch_artifact_path: childProof?.patch_artifact_path ?? null,
590
+ patch_bytes: childProof?.patch_bytes ?? null,
591
+ decision: zeroBytePatch ? 'rejected' : 'pending',
592
+ in_flight_action: null,
593
+ in_flight_started_at: null,
594
+ decision_at: zeroBytePatch ? deps.now() : null,
595
+ decision_reason: zeroBytePatch ? buildNoOutputAdvisoryChildLaneDecisionReason(childRun) : null
596
+ };
597
+ })();
598
+ let recordedChildLaneForResult = childLane;
599
+ try {
600
+ const recorded = await deps.transactChildLanes(context.runDir, async (records) => {
601
+ const current = findChildLaneByIdentity(records, launchReservation);
602
+ if (!current) {
603
+ return {
604
+ records,
605
+ result: null
606
+ };
607
+ }
608
+ const recordedChildLane = mergeCompletedChildLaneWithParentDecision(current, childLane);
609
+ const next = replaceChildLaneRecord(records, current, recordedChildLane);
610
+ if (!next) {
611
+ return {
612
+ records,
613
+ result: null
614
+ };
615
+ }
616
+ return {
617
+ records: next,
618
+ result: recordedChildLane
619
+ };
620
+ });
621
+ if (!recorded) {
622
+ await removeReservedChildLane(context.runDir, launchReservation, deps);
623
+ return failureResult({
624
+ action: 'launch',
625
+ issueId: context.issueId,
626
+ issueIdentifier: context.issueIdentifier,
627
+ sourceSetup,
628
+ stream,
629
+ childRun,
630
+ childLane,
631
+ code: 'provider_worker_child_lane_record_failed',
632
+ message: 'Failed to replace the reserved child lane entry with the completed child run record.',
633
+ status: 502
634
+ });
635
+ }
636
+ recordedChildLaneForResult = recorded;
637
+ }
638
+ catch (error) {
639
+ await removeReservedChildLane(context.runDir, launchReservation, deps).catch(() => undefined);
640
+ return failureResult({
641
+ action: 'launch',
642
+ issueId: context.issueId,
643
+ issueIdentifier: context.issueIdentifier,
644
+ sourceSetup,
645
+ stream,
646
+ childRun,
647
+ childLane,
648
+ code: 'provider_worker_child_lane_record_failed',
649
+ message: `Failed to record child lane lineage: ${error instanceof Error ? error.message : String(error)}`,
650
+ status: 502
651
+ });
652
+ }
653
+ await refreshProviderLinearChildLaneProofSnapshotBestEffort({
654
+ deps,
655
+ runDir: context.runDir,
656
+ auditPath: params.env[PROVIDER_LINEAR_AUDIT_ENV_VAR] ?? null,
657
+ env: params.env,
658
+ warningContext: `after recording child lane ${stream}`
659
+ });
660
+ const launchExitedNonZero = recoveredLaunch ? false : execResult ? execResult.exitCode !== 0 : false;
661
+ if (launchExitedNonZero || childRun.status !== 'succeeded') {
662
+ const childFailureDetail = normalizeOptionalString(childProof?.last_message) ??
663
+ normalizeOptionalString(recordedChildLaneForResult.summary) ??
664
+ normalizeOptionalString(childRun.summary);
665
+ return failureResult({
666
+ action: 'launch',
667
+ issueId: context.issueId,
668
+ issueIdentifier: context.issueIdentifier,
669
+ sourceSetup,
670
+ stream,
671
+ childRun,
672
+ childLane: recordedChildLaneForResult,
673
+ code: 'provider_worker_child_lane_run_failed',
674
+ message: `Child lane ${stream} completed with status ${childRun.status}.${childFailureDetail ? ` ${childFailureDetail}` : ''} ${PROVIDER_LINEAR_CHILD_LANE_MUTATION_REASON}`,
675
+ status: 502
676
+ });
677
+ }
678
+ return {
679
+ ok: true,
680
+ operation: 'child-lane',
681
+ action: 'launched',
682
+ issue: {
683
+ id: context.issueId,
684
+ identifier: context.issueIdentifier
685
+ },
686
+ source_setup: sourceSetup,
687
+ stream,
688
+ child_run: childRun,
689
+ child_lane: recordedChildLaneForResult
690
+ };
691
+ }
692
+ async function resolveChildLaneDecision(params, context, deps, sourceSetup) {
693
+ const stream = normalizeChildLaneStreamName(params.streamName);
694
+ if (!stream) {
695
+ return failureResult({
696
+ action: params.action,
697
+ issueId: context.issueId,
698
+ issueIdentifier: context.issueIdentifier,
699
+ sourceSetup,
700
+ stream: params.streamName ?? null,
701
+ childRun: null,
702
+ childLane: null,
703
+ code: 'provider_worker_child_lane_stream_invalid',
704
+ message: 'Provider worker child lane decisions require --stream.',
705
+ status: 422
706
+ });
707
+ }
708
+ const childRunsRoot = resolveWorkspaceScopedArtifactDir(context.repoRoot, params.env.CODEX_ORCHESTRATOR_RUNS_DIR, '.runs');
709
+ if (params.action !== 'accept') {
710
+ const finalized = await finalizePendingChildLaneDecision({
711
+ action: params.action,
712
+ context,
713
+ childRunsRoot,
714
+ stream,
715
+ deps,
716
+ reason: normalizeOptionalString(params.reason),
717
+ now: deps.now()
718
+ });
719
+ if (finalized.kind !== 'updated') {
720
+ return childLaneDecisionFailureResult({
721
+ action: params.action,
722
+ context,
723
+ sourceSetup,
724
+ stream,
725
+ outcome: finalized
726
+ });
727
+ }
728
+ await refreshProviderLinearChildLaneProofSnapshotBestEffort({
729
+ deps,
730
+ runDir: context.runDir,
731
+ auditPath: params.env[PROVIDER_LINEAR_AUDIT_ENV_VAR] ?? null,
732
+ env: params.env,
733
+ warningContext: `after finalizing ${finalized.decision} child lane ${stream}`
734
+ });
735
+ return {
736
+ ok: true,
737
+ operation: 'child-lane',
738
+ action: finalized.decision === 'rejected' ? 'rejected' : 'invalidated',
739
+ issue: {
740
+ id: context.issueId,
741
+ identifier: context.issueIdentifier
742
+ },
743
+ source_setup: sourceSetup,
744
+ stream,
745
+ child_run: null,
746
+ child_lane: finalized.childLane
747
+ };
748
+ }
749
+ const claimed = await claimPendingChildLaneAcceptance({
750
+ context,
751
+ childRunsRoot,
752
+ stream,
753
+ deps,
754
+ now: deps.now()
755
+ });
756
+ if (claimed.kind !== 'claimed') {
757
+ return childLaneDecisionFailureResult({
758
+ action: 'accept',
759
+ context,
760
+ sourceSetup,
761
+ stream,
762
+ outcome: claimed
763
+ });
764
+ }
765
+ const target = claimed.childLane;
766
+ let currentHeadSha;
767
+ let currentIssue;
768
+ try {
769
+ currentHeadSha = await deps.readParentHeadSha(context.repoRoot);
770
+ currentIssue = await resolveParentSnapshot(context, params.env, deps);
771
+ }
772
+ catch (error) {
773
+ try {
774
+ await releaseClaimedChildLaneAcceptance(context.runDir, target, deps);
775
+ }
776
+ catch (releaseError) {
777
+ deps.warn(`provider-linear-child-lane warning: failed to release accept claim after snapshot read failure for ${stream}: ${releaseError instanceof Error ? releaseError.message : String(releaseError)}`);
778
+ }
779
+ throw error;
780
+ }
781
+ const staleReason = resolveChildLaneStaleReason(target, currentHeadSha, currentIssue);
782
+ if (staleReason) {
783
+ const invalidated = await finalizeClaimedChildLaneDecision({
784
+ context,
785
+ target,
786
+ decision: 'invalidated',
787
+ decisionReason: staleReason,
788
+ deps,
789
+ now: deps.now()
790
+ });
791
+ await refreshProviderLinearChildLaneProofSnapshotBestEffort({
792
+ deps,
793
+ runDir: context.runDir,
794
+ auditPath: params.env[PROVIDER_LINEAR_AUDIT_ENV_VAR] ?? null,
795
+ env: params.env,
796
+ warningContext: `after invalidating stale child lane ${stream}`
797
+ });
798
+ return failureResult({
799
+ action: 'accept',
800
+ issueId: context.issueId,
801
+ issueIdentifier: context.issueIdentifier,
802
+ sourceSetup,
803
+ stream,
804
+ childRun: null,
805
+ childLane: invalidated ?? target,
806
+ code: 'provider_worker_child_lane_stale',
807
+ message: staleReason,
808
+ status: 409
809
+ });
810
+ }
811
+ if (target.status !== 'succeeded' || !target.patch_artifact_path) {
812
+ await releaseClaimedChildLaneAcceptance(context.runDir, target, deps);
813
+ return failureResult({
814
+ action: 'accept',
815
+ issueId: context.issueId,
816
+ issueIdentifier: context.issueIdentifier,
817
+ sourceSetup,
818
+ stream,
819
+ childRun: null,
820
+ childLane: target,
821
+ code: 'provider_worker_child_lane_patch_missing',
822
+ message: 'Child lane has no accepted patch artifact to apply.',
823
+ status: 409
824
+ });
825
+ }
826
+ const artifactRoot = resolveAcceptedChildLaneArtifactRoot(context.repoRoot, childRunsRoot, target);
827
+ if (!artifactRoot) {
828
+ await releaseClaimedChildLaneAcceptance(context.runDir, target, deps);
829
+ return failureResult({
830
+ action: 'accept',
831
+ issueId: context.issueId,
832
+ issueIdentifier: context.issueIdentifier,
833
+ sourceSetup,
834
+ stream,
835
+ childRun: null,
836
+ childLane: target,
837
+ code: 'provider_worker_child_lane_patch_invalid',
838
+ message: 'Child lane artifact root must stay anchored to the expected workspace-local child run directory before parent acceptance.',
839
+ status: 409
840
+ });
841
+ }
842
+ const patchArtifactPath = resolveAcceptedPatchArtifactPath(context.repoRoot, target, artifactRoot);
843
+ if (!patchArtifactPath) {
844
+ await releaseClaimedChildLaneAcceptance(context.runDir, target, deps);
845
+ return failureResult({
846
+ action: 'accept',
847
+ issueId: context.issueId,
848
+ issueIdentifier: context.issueIdentifier,
849
+ sourceSetup,
850
+ stream,
851
+ childRun: null,
852
+ childLane: target,
853
+ code: 'provider_worker_child_lane_patch_invalid',
854
+ message: 'Child lane patch artifact must stay within the child lane artifact root before parent acceptance.',
855
+ status: 409
856
+ });
857
+ }
858
+ const proofPath = join(artifactRoot, PROVIDER_LINEAR_CHILD_LANE_PROOF_FILENAME);
859
+ const acceptedProof = await deps.readChildLaneProof(proofPath).catch(() => null);
860
+ let acceptedProofScope = null;
861
+ if (!acceptedProof) {
862
+ await releaseClaimedChildLaneAcceptance(context.runDir, target, deps);
863
+ return failureResult({
864
+ action: 'accept',
865
+ issueId: context.issueId,
866
+ issueIdentifier: context.issueIdentifier,
867
+ sourceSetup,
868
+ stream,
869
+ childRun: null,
870
+ childLane: target,
871
+ code: 'provider_worker_child_lane_proof_missing',
872
+ message: 'Child lane acceptance requires a readable proof bundle before parent apply.',
873
+ status: 409
874
+ });
875
+ }
876
+ if (acceptedProof) {
877
+ if (!acceptedProof.scope) {
878
+ await releaseClaimedChildLaneAcceptance(context.runDir, target, deps);
879
+ return failureResult({
880
+ action: 'accept',
881
+ issueId: context.issueId,
882
+ issueIdentifier: context.issueIdentifier,
883
+ sourceSetup,
884
+ stream,
885
+ childRun: null,
886
+ childLane: target,
887
+ code: 'provider_worker_child_lane_proof_invalid',
888
+ message: 'Child lane proof is missing scope contract metadata.',
889
+ status: 409
890
+ });
891
+ }
892
+ const proofViolation = resolveAcceptedChildLaneProofViolation(context.runId, target, acceptedProof, context.repoRoot, artifactRoot, patchArtifactPath);
893
+ if (proofViolation) {
894
+ await releaseClaimedChildLaneAcceptance(context.runDir, target, deps);
895
+ return failureResult({
896
+ action: 'accept',
897
+ issueId: context.issueId,
898
+ issueIdentifier: context.issueIdentifier,
899
+ sourceSetup,
900
+ stream,
901
+ childRun: null,
902
+ childLane: target,
903
+ code: 'provider_worker_child_lane_proof_invalid',
904
+ message: proofViolation,
905
+ status: 409
906
+ });
907
+ }
908
+ acceptedProofScope = acceptedProof.scope;
909
+ }
910
+ let patchChangedPaths;
911
+ try {
912
+ patchChangedPaths = await readPatchChangedPaths(patchArtifactPath);
913
+ }
914
+ catch (error) {
915
+ await releaseClaimedChildLaneAcceptance(context.runDir, target, deps);
916
+ return failureResult({
917
+ action: 'accept',
918
+ issueId: context.issueId,
919
+ issueIdentifier: context.issueIdentifier,
920
+ sourceSetup,
921
+ stream,
922
+ childRun: null,
923
+ childLane: target,
924
+ code: 'provider_worker_child_lane_patch_invalid',
925
+ message: `Child lane patch artifact could not be inspected before parent acceptance: ${error instanceof Error ? error.message : String(error)}`,
926
+ status: 409
927
+ });
928
+ }
929
+ const patchScopeViolation = resolveAcceptedPatchScopeViolation(target.scope, patchChangedPaths, acceptedProofScope);
930
+ if (patchScopeViolation) {
931
+ await releaseClaimedChildLaneAcceptance(context.runDir, target, deps);
932
+ return failureResult({
933
+ action: 'accept',
934
+ issueId: context.issueId,
935
+ issueIdentifier: context.issueIdentifier,
936
+ sourceSetup,
937
+ stream,
938
+ childRun: null,
939
+ childLane: target,
940
+ code: isProofScopeViolation(patchScopeViolation)
941
+ ? 'provider_worker_child_lane_proof_invalid'
942
+ : 'provider_worker_child_lane_patch_scope_invalid',
943
+ message: patchScopeViolation,
944
+ status: 409
945
+ });
946
+ }
947
+ let dirtyPatchConflict;
948
+ try {
949
+ dirtyPatchConflict = await resolveAcceptedPatchDirtyConflict(context.repoRoot, patchChangedPaths, deps);
950
+ }
951
+ catch (error) {
952
+ await releaseClaimedChildLaneAcceptance(context.runDir, target, deps);
953
+ return failureResult({
954
+ action: 'accept',
955
+ issueId: context.issueId,
956
+ issueIdentifier: context.issueIdentifier,
957
+ sourceSetup,
958
+ stream,
959
+ childRun: null,
960
+ childLane: target,
961
+ code: 'provider_worker_child_lane_parent_dirty_check_failed',
962
+ message: `Failed to inspect parent workspace state before accepting child lane: ${error instanceof Error ? error.message : String(error)}`,
963
+ status: 502
964
+ });
965
+ }
966
+ if (dirtyPatchConflict) {
967
+ await releaseClaimedChildLaneAcceptance(context.runDir, target, deps);
968
+ return failureResult({
969
+ action: 'accept',
970
+ issueId: context.issueId,
971
+ issueIdentifier: context.issueIdentifier,
972
+ sourceSetup,
973
+ stream,
974
+ childRun: null,
975
+ childLane: target,
976
+ code: 'provider_worker_child_lane_parent_dirty',
977
+ message: dirtyPatchConflict,
978
+ status: 409
979
+ });
980
+ }
981
+ try {
982
+ await deps.applyPatchArtifact(context.repoRoot, patchArtifactPath);
983
+ }
984
+ catch (error) {
985
+ await releaseClaimedChildLaneAcceptance(context.runDir, target, deps);
986
+ return failureResult({
987
+ action: 'accept',
988
+ issueId: context.issueId,
989
+ issueIdentifier: context.issueIdentifier,
990
+ sourceSetup,
991
+ stream,
992
+ childRun: null,
993
+ childLane: target,
994
+ code: 'provider_worker_child_lane_apply_failed',
995
+ message: error instanceof Error ? error.message : String(error),
996
+ status: 409
997
+ });
998
+ }
999
+ const accepted = await finalizeClaimedChildLaneDecision({
1000
+ context,
1001
+ target,
1002
+ decision: 'accepted',
1003
+ decisionReason: normalizeOptionalString(params.reason) ?? defaultDecisionReason('accept', target),
1004
+ deps,
1005
+ now: deps.now()
1006
+ });
1007
+ if (!accepted) {
1008
+ return failureResult({
1009
+ action: 'accept',
1010
+ issueId: context.issueId,
1011
+ issueIdentifier: context.issueIdentifier,
1012
+ sourceSetup,
1013
+ stream,
1014
+ childRun: null,
1015
+ childLane: target,
1016
+ code: 'provider_worker_child_lane_update_failed',
1017
+ message: `Failed to update child lane ${stream}.`,
1018
+ status: 502
1019
+ });
1020
+ }
1021
+ await refreshProviderLinearChildLaneProofSnapshotBestEffort({
1022
+ deps,
1023
+ runDir: context.runDir,
1024
+ auditPath: params.env[PROVIDER_LINEAR_AUDIT_ENV_VAR] ?? null,
1025
+ env: params.env,
1026
+ warningContext: `after accepting child lane ${stream}`
1027
+ });
1028
+ return {
1029
+ ok: true,
1030
+ operation: 'child-lane',
1031
+ action: 'accepted',
1032
+ issue: {
1033
+ id: context.issueId,
1034
+ identifier: context.issueIdentifier
1035
+ },
1036
+ source_setup: sourceSetup,
1037
+ stream,
1038
+ child_run: null,
1039
+ child_lane: accepted
1040
+ };
1041
+ }
1042
+ function childLaneDecisionFailureResult(input) {
1043
+ if (input.outcome.kind === 'not_found') {
1044
+ return failureResult({
1045
+ action: input.action,
1046
+ issueId: input.context.issueId,
1047
+ issueIdentifier: input.context.issueIdentifier,
1048
+ sourceSetup: input.sourceSetup,
1049
+ stream: input.stream,
1050
+ childRun: null,
1051
+ childLane: null,
1052
+ code: 'provider_worker_child_lane_not_found',
1053
+ message: `No pending child lane found for stream ${input.stream}.`,
1054
+ status: 404
1055
+ });
1056
+ }
1057
+ if (input.outcome.kind === 'provenance_invalid') {
1058
+ return failureResult({
1059
+ action: input.action,
1060
+ issueId: input.context.issueId,
1061
+ issueIdentifier: input.context.issueIdentifier,
1062
+ sourceSetup: input.sourceSetup,
1063
+ stream: input.stream,
1064
+ childRun: null,
1065
+ childLane: input.outcome.childLane,
1066
+ code: 'provider_worker_child_lane_provenance_invalid',
1067
+ message: input.outcome.message,
1068
+ status: 409
1069
+ });
1070
+ }
1071
+ if (input.outcome.kind === 'in_flight') {
1072
+ return failureResult({
1073
+ action: input.action,
1074
+ issueId: input.context.issueId,
1075
+ issueIdentifier: input.context.issueIdentifier,
1076
+ sourceSetup: input.sourceSetup,
1077
+ stream: input.stream,
1078
+ childRun: null,
1079
+ childLane: input.outcome.childLane,
1080
+ code: 'provider_worker_child_lane_decision_in_flight',
1081
+ message: `Pending child lane ${input.stream} already has an in-flight ${input.outcome.inFlightAction} decision; wait for that parent-owned decision to finish before retrying ${input.action}.`,
1082
+ status: 409
1083
+ });
1084
+ }
1085
+ return failureResult({
1086
+ action: input.action,
1087
+ issueId: input.context.issueId,
1088
+ issueIdentifier: input.context.issueIdentifier,
1089
+ sourceSetup: input.sourceSetup,
1090
+ stream: input.stream,
1091
+ childRun: null,
1092
+ childLane: input.outcome.childLane,
1093
+ code: 'provider_worker_child_lane_not_ready',
1094
+ message: `Pending child lane ${input.stream} is still launching and cannot be ${input.action === 'accept' ? 'accepted' : input.action === 'reject' ? 'rejected' : 'invalidated'} yet.`,
1095
+ status: 409
1096
+ });
1097
+ }
1098
+ async function resolveSameAttemptParentDirtyRetrySuppression(runDir, issueId, env) {
1099
+ const auditPath = resolveProviderLinearAuditPath(env);
1100
+ if (!auditPath) {
1101
+ return null;
1102
+ }
1103
+ let rawProof;
1104
+ try {
1105
+ rawProof = await readFile(join(runDir, PROVIDER_LINEAR_WORKER_PROOF_FILENAME), 'utf8');
1106
+ }
1107
+ catch {
1108
+ return null;
1109
+ }
1110
+ let parsedProof;
1111
+ try {
1112
+ parsedProof = JSON.parse(rawProof);
1113
+ }
1114
+ catch {
1115
+ return null;
1116
+ }
1117
+ const attemptStartedAt = resolveProviderLinearWorkerAttemptStartedAt(parsedProof);
1118
+ if (!attemptStartedAt) {
1119
+ return null;
1120
+ }
1121
+ let audit = null;
1122
+ try {
1123
+ audit = await summarizeProviderLinearAuditPath(auditPath);
1124
+ }
1125
+ catch (error) {
1126
+ const message = error instanceof Error ? error.message : String(error);
1127
+ logger.warn(`provider linear child-lane warning: failed to summarize provider-linear audit at ${auditPath}; proceeding without same-attempt retry suppression. error=${message}`);
1128
+ return null;
1129
+ }
1130
+ const suppression = findDeterministicProviderMutationSuppression(audit, 'child-lane', {
1131
+ recordedAtNotBefore: attemptStartedAt,
1132
+ action: 'launch',
1133
+ issueId
1134
+ });
1135
+ return suppression && isChildLaneParentDirtySuppressionCode(suppression.error_code)
1136
+ ? suppression
1137
+ : null;
1138
+ }
1139
+ async function finalizePendingChildLaneDecision(input) {
1140
+ const decision = mapActionToDecision(input.action);
1141
+ return await input.deps.transactChildLanes(input.context.runDir, async (records) => {
1142
+ const resolved = await resolvePendingChildLaneDecisionTarget({
1143
+ records,
1144
+ context: input.context,
1145
+ childRunsRoot: input.childRunsRoot,
1146
+ stream: input.stream,
1147
+ action: input.action,
1148
+ deps: input.deps,
1149
+ now: input.now
1150
+ });
1151
+ if (resolved.kind !== 'ready') {
1152
+ return { records: resolved.records, result: resolved.outcome };
1153
+ }
1154
+ const target = resolved.target;
1155
+ const updated = {
1156
+ ...target,
1157
+ decision,
1158
+ in_flight_action: null,
1159
+ in_flight_started_at: null,
1160
+ decision_at: input.now,
1161
+ decision_reason: input.reason ?? defaultDecisionReason(input.action, target)
1162
+ };
1163
+ const next = replaceChildLaneRecord(resolved.records, target, updated);
1164
+ if (!next) {
1165
+ return { records: resolved.records, result: { kind: 'not_found' } };
1166
+ }
1167
+ return {
1168
+ records: next,
1169
+ result: { kind: 'updated', childLane: updated, decision }
1170
+ };
1171
+ });
1172
+ }
1173
+ async function claimPendingChildLaneAcceptance(input) {
1174
+ return await input.deps.transactChildLanes(input.context.runDir, async (records) => {
1175
+ const resolved = await resolvePendingChildLaneDecisionTarget({
1176
+ records,
1177
+ context: input.context,
1178
+ childRunsRoot: input.childRunsRoot,
1179
+ stream: input.stream,
1180
+ action: 'accept',
1181
+ deps: input.deps,
1182
+ now: input.now
1183
+ });
1184
+ if (resolved.kind !== 'ready') {
1185
+ return { records: resolved.records, result: resolved.outcome };
1186
+ }
1187
+ const target = resolved.target;
1188
+ const claimed = {
1189
+ ...target,
1190
+ in_flight_action: 'accept',
1191
+ in_flight_started_at: input.now
1192
+ };
1193
+ const next = replaceChildLaneRecord(resolved.records, target, claimed);
1194
+ if (!next) {
1195
+ return { records: resolved.records, result: { kind: 'not_found' } };
1196
+ }
1197
+ return {
1198
+ records: next,
1199
+ result: { kind: 'claimed', childLane: claimed }
1200
+ };
1201
+ });
1202
+ }
1203
+ async function resolvePendingChildLaneDecisionTarget(input) {
1204
+ const target = findLatestPendingChildLane(input.records, input.stream);
1205
+ if (!target) {
1206
+ return { kind: 'blocked', outcome: { kind: 'not_found' }, records: input.records };
1207
+ }
1208
+ const preRepairBlocked = resolveChildLaneDecisionPreRepairBlockedOutcome(input.context, input.stream, target, input.now);
1209
+ if (preRepairBlocked) {
1210
+ return { kind: 'blocked', outcome: preRepairBlocked, records: input.records };
1211
+ }
1212
+ let records = input.records;
1213
+ let resolvedTarget = target;
1214
+ const repaired = await repairPendingLaunchingChildLaneDecisionTarget({
1215
+ records,
1216
+ target,
1217
+ context: input.context,
1218
+ childRunsRoot: input.childRunsRoot,
1219
+ action: input.action,
1220
+ deps: input.deps,
1221
+ now: input.now
1222
+ });
1223
+ if (repaired) {
1224
+ records = repaired.records;
1225
+ if (!repaired.target) {
1226
+ return { kind: 'blocked', outcome: { kind: 'not_found' }, records };
1227
+ }
1228
+ resolvedTarget = repaired.target;
1229
+ }
1230
+ const postRepairBlocked = resolveChildLaneDecisionPreRepairBlockedOutcome(input.context, input.stream, resolvedTarget, input.now);
1231
+ if (postRepairBlocked) {
1232
+ return { kind: 'blocked', outcome: postRepairBlocked, records };
1233
+ }
1234
+ const blocked = resolveChildLaneDecisionReadinessBlockedOutcome(resolvedTarget, input.action);
1235
+ if (blocked) {
1236
+ return { kind: 'blocked', outcome: blocked, records };
1237
+ }
1238
+ return { kind: 'ready', records, target: resolvedTarget };
1239
+ }
1240
+ function resolveChildLaneDecisionPreRepairBlockedOutcome(context, stream, target, now) {
1241
+ const provenanceViolation = resolveChildLaneDecisionProvenanceViolation(context, stream, target);
1242
+ if (provenanceViolation) {
1243
+ return {
1244
+ kind: 'provenance_invalid',
1245
+ childLane: target,
1246
+ message: provenanceViolation
1247
+ };
1248
+ }
1249
+ if (target.in_flight_action && !isStaleInFlightChildLane(target, now)) {
1250
+ return {
1251
+ kind: 'in_flight',
1252
+ childLane: target,
1253
+ inFlightAction: target.in_flight_action
1254
+ };
1255
+ }
1256
+ return null;
1257
+ }
1258
+ function resolveChildLaneDecisionReadinessBlockedOutcome(target, action) {
1259
+ if (action === 'accept' && target.status === 'launching') {
1260
+ return {
1261
+ kind: 'not_ready',
1262
+ childLane: target
1263
+ };
1264
+ }
1265
+ return null;
1266
+ }
1267
+ async function repairPendingLaunchingChildLaneDecisionTarget(input) {
1268
+ if (input.target.status !== 'launching' || !input.target.run_id.startsWith('launching-')) {
1269
+ return null;
1270
+ }
1271
+ const candidate = await findChildLaneReservationRepairCandidate({
1272
+ reservation: input.target,
1273
+ context: input.context,
1274
+ childRunsRoot: input.childRunsRoot,
1275
+ action: input.action,
1276
+ deps: input.deps,
1277
+ now: input.now
1278
+ });
1279
+ if (!candidate) {
1280
+ return null;
1281
+ }
1282
+ const repairedReservation = {
1283
+ ...input.target,
1284
+ decision: 'invalidated',
1285
+ in_flight_action: null,
1286
+ in_flight_started_at: null,
1287
+ decision_at: input.now,
1288
+ decision_reason: buildChildLaneReservationRepairDecisionReason(input.target, candidate)
1289
+ };
1290
+ const withRetiredReservation = replaceChildLaneRecord(input.records, input.target, repairedReservation);
1291
+ if (!withRetiredReservation) {
1292
+ return null;
1293
+ }
1294
+ const existingCandidate = withRetiredReservation.find((entry) => matchesChildLaneRecordIdentity(entry, candidate)) ?? null;
1295
+ if (existingCandidate && existingCandidate.decision !== 'pending') {
1296
+ return null;
1297
+ }
1298
+ const repairedTarget = existingCandidate
1299
+ ? mergeCompletedChildLaneWithParentDecision(existingCandidate, candidate)
1300
+ : candidate;
1301
+ const nextRecords = existingCandidate
1302
+ ? (replaceChildLaneRecord(withRetiredReservation, existingCandidate, repairedTarget) ?? withRetiredReservation)
1303
+ : [...withRetiredReservation.filter((entry) => !matchesChildLaneRecordIdentity(entry, repairedTarget)), repairedTarget];
1304
+ return {
1305
+ records: nextRecords,
1306
+ target: repairedTarget.decision === 'pending' ? repairedTarget : null
1307
+ };
1308
+ }
1309
+ async function releaseClaimedChildLaneAcceptance(runDir, target, deps) {
1310
+ await deps.transactChildLanes(runDir, async (records) => {
1311
+ const next = replaceChildLaneRecord(records, target, {
1312
+ ...target,
1313
+ in_flight_action: null,
1314
+ in_flight_started_at: null
1315
+ });
1316
+ return {
1317
+ records: next ?? records,
1318
+ result: undefined
1319
+ };
1320
+ });
1321
+ }
1322
+ async function finalizeClaimedChildLaneDecision(input) {
1323
+ return await input.deps.transactChildLanes(input.context.runDir, async (records) => {
1324
+ const next = replaceChildLaneRecord(records, input.target, {
1325
+ ...input.target,
1326
+ decision: input.decision,
1327
+ in_flight_action: null,
1328
+ in_flight_started_at: null,
1329
+ decision_at: input.now,
1330
+ decision_reason: input.decisionReason
1331
+ });
1332
+ if (!next) {
1333
+ return {
1334
+ records,
1335
+ result: null
1336
+ };
1337
+ }
1338
+ const updated = findChildLaneByIdentity(next, input.target);
1339
+ return {
1340
+ records: next,
1341
+ result: updated
1342
+ };
1343
+ });
1344
+ }
1345
+ function findLatestPendingChildLane(records, stream) {
1346
+ return [...records]
1347
+ .reverse()
1348
+ .find((entry) => entry.stream === stream && entry.decision === 'pending') ?? null;
1349
+ }
1350
+ function findChildLaneByIdentity(records, target) {
1351
+ return records.find((entry) => matchesChildLaneRecordIdentity(entry, target)) ?? null;
1352
+ }
1353
+ async function waitForRecoveredChildLaneLaunchCandidate(input) {
1354
+ const readRecoveredCandidate = async () => {
1355
+ try {
1356
+ return await findRecoveredChildLaneLaunchCandidate({
1357
+ reservation: input.reservation,
1358
+ context: input.context,
1359
+ childRunsRoot: input.childRunsRoot,
1360
+ deps: input.deps,
1361
+ now: input.now
1362
+ });
1363
+ }
1364
+ catch (error) {
1365
+ input.deps.warn(`provider-linear-child-lane warning: failed to scan for recovered child-lane launch candidate: ${error instanceof Error ? error.message : String(error)}`);
1366
+ return null;
1367
+ }
1368
+ };
1369
+ while (!input.isExecSettled()) {
1370
+ const candidate = await readRecoveredCandidate();
1371
+ if (candidate) {
1372
+ return candidate;
1373
+ }
1374
+ await input.deps.sleep(PROVIDER_LINEAR_CHILD_LANE_LAUNCH_RECOVERY_POLL_INTERVAL_MS);
1375
+ }
1376
+ return await readRecoveredCandidate();
1377
+ }
1378
+ async function findRecoveredChildLaneLaunchCandidate(input) {
1379
+ const childTaskCliRoot = join(input.childRunsRoot, input.reservation.task_id, 'cli');
1380
+ let entries;
1381
+ try {
1382
+ entries = await input.deps.readDir(childTaskCliRoot);
1383
+ }
1384
+ catch (error) {
1385
+ if (error?.code === 'ENOENT') {
1386
+ return null;
1387
+ }
1388
+ throw error;
1389
+ }
1390
+ const candidates = [];
1391
+ for (const entry of entries) {
1392
+ if (!entry.isDirectory() || entry.name === input.reservation.run_id) {
1393
+ continue;
1394
+ }
1395
+ const runId = (() => {
1396
+ try {
1397
+ return sanitizeRunId(entry.name);
1398
+ }
1399
+ catch {
1400
+ return null;
1401
+ }
1402
+ })();
1403
+ if (!runId) {
1404
+ continue;
1405
+ }
1406
+ const candidate = await readRecoveredChildLaneLaunchCandidate({
1407
+ reservation: input.reservation,
1408
+ context: input.context,
1409
+ childRunsRoot: input.childRunsRoot,
1410
+ deps: input.deps,
1411
+ now: input.now,
1412
+ runId
1413
+ }).catch(() => null);
1414
+ if (candidate) {
1415
+ candidates.push(candidate);
1416
+ }
1417
+ }
1418
+ // Fail closed when recovery is ambiguous; parent repair needs one exact child run candidate.
1419
+ return candidates.length === 1 ? candidates[0] : null;
1420
+ }
1421
+ async function readRecoveredChildLaneLaunchCandidate(input) {
1422
+ const artifactRoot = resolve(input.childRunsRoot, input.reservation.task_id, 'cli', input.runId);
1423
+ const manifestPath = join(artifactRoot, 'manifest.json');
1424
+ let rawManifest;
1425
+ try {
1426
+ rawManifest = JSON.parse(await readFile(manifestPath, 'utf8'));
1427
+ }
1428
+ catch {
1429
+ return null;
1430
+ }
1431
+ const childRun = parseProviderLinearChildLaneRunManifest({
1432
+ manifest: rawManifest,
1433
+ repoRoot: input.context.repoRoot,
1434
+ artifactRoot,
1435
+ manifestPath,
1436
+ taskId: input.reservation.task_id,
1437
+ runId: input.runId,
1438
+ parentRunId: input.context.runId,
1439
+ issueId: input.context.issueId,
1440
+ issueIdentifier: input.context.issueIdentifier
1441
+ });
1442
+ if (!childRun) {
1443
+ return null;
1444
+ }
1445
+ const proof = await input.deps.readChildLaneProof(join(artifactRoot, PROVIDER_LINEAR_CHILD_LANE_PROOF_FILENAME)).catch(() => null);
1446
+ if (!proof || !proof.scope || !proof.parent_snapshot) {
1447
+ return null;
1448
+ }
1449
+ const childLane = buildRepairedChildLaneRecord({
1450
+ reservation: input.reservation,
1451
+ childRun,
1452
+ proof,
1453
+ now: input.now
1454
+ });
1455
+ const proofViolation = resolveChildLaneReservationRepairProofViolation({
1456
+ reservation: input.reservation,
1457
+ childRun,
1458
+ candidate: childLane,
1459
+ proof,
1460
+ context: input.context,
1461
+ repoRoot: input.context.repoRoot,
1462
+ childRunsRoot: input.childRunsRoot,
1463
+ action: childRun.status === 'succeeded' ? 'accept' : 'reject'
1464
+ });
1465
+ if (proofViolation) {
1466
+ return null;
1467
+ }
1468
+ return {
1469
+ childRun,
1470
+ childLane,
1471
+ proof
1472
+ };
1473
+ }
1474
+ async function findChildLaneReservationRepairCandidate(input) {
1475
+ const childTaskCliRoot = join(input.childRunsRoot, input.reservation.task_id, 'cli');
1476
+ let entries;
1477
+ try {
1478
+ entries = await input.deps.readDir(childTaskCliRoot);
1479
+ }
1480
+ catch (error) {
1481
+ if (error?.code === 'ENOENT') {
1482
+ return null;
1483
+ }
1484
+ throw error;
1485
+ }
1486
+ const candidates = [];
1487
+ for (const entry of entries) {
1488
+ if (!entry.isDirectory() || entry.name === input.reservation.run_id) {
1489
+ continue;
1490
+ }
1491
+ const runId = (() => {
1492
+ try {
1493
+ return sanitizeRunId(entry.name);
1494
+ }
1495
+ catch {
1496
+ return null;
1497
+ }
1498
+ })();
1499
+ if (!runId) {
1500
+ continue;
1501
+ }
1502
+ const candidate = await readChildLaneReservationRepairCandidate({
1503
+ reservation: input.reservation,
1504
+ context: input.context,
1505
+ childRunsRoot: input.childRunsRoot,
1506
+ action: input.action,
1507
+ deps: input.deps,
1508
+ now: input.now,
1509
+ runId
1510
+ });
1511
+ if (candidate) {
1512
+ candidates.push(candidate);
1513
+ }
1514
+ }
1515
+ return candidates.length === 1 ? candidates[0] : null;
1516
+ }
1517
+ async function readChildLaneReservationRepairCandidate(input) {
1518
+ const artifactRoot = resolve(input.childRunsRoot, input.reservation.task_id, 'cli', input.runId);
1519
+ const manifestPath = join(artifactRoot, 'manifest.json');
1520
+ let rawManifest;
1521
+ try {
1522
+ rawManifest = JSON.parse(await readFile(manifestPath, 'utf8'));
1523
+ }
1524
+ catch {
1525
+ return null;
1526
+ }
1527
+ const childRun = parseProviderLinearChildLaneRunManifest({
1528
+ manifest: rawManifest,
1529
+ repoRoot: input.context.repoRoot,
1530
+ artifactRoot,
1531
+ manifestPath,
1532
+ taskId: input.reservation.task_id,
1533
+ runId: input.runId,
1534
+ parentRunId: input.context.runId,
1535
+ issueId: input.context.issueId,
1536
+ issueIdentifier: input.context.issueIdentifier
1537
+ });
1538
+ if (!childRun) {
1539
+ return null;
1540
+ }
1541
+ const proof = await input.deps.readChildLaneProof(join(artifactRoot, PROVIDER_LINEAR_CHILD_LANE_PROOF_FILENAME)).catch(() => null);
1542
+ if (!proof || !proof.scope || !proof.parent_snapshot) {
1543
+ return null;
1544
+ }
1545
+ const candidate = buildRepairedChildLaneRecord({
1546
+ reservation: input.reservation,
1547
+ childRun,
1548
+ proof,
1549
+ now: input.now
1550
+ });
1551
+ const proofViolation = resolveChildLaneReservationRepairProofViolation({
1552
+ reservation: input.reservation,
1553
+ childRun,
1554
+ candidate,
1555
+ proof,
1556
+ context: input.context,
1557
+ repoRoot: input.context.repoRoot,
1558
+ childRunsRoot: input.childRunsRoot,
1559
+ action: input.action
1560
+ });
1561
+ return proofViolation ? null : candidate;
1562
+ }
1563
+ function parseProviderLinearChildLaneRunManifest(input) {
1564
+ const manifestRunId = normalizeOptionalString(input.manifest.run_id);
1565
+ const manifestTaskId = normalizeOptionalString(input.manifest.task_id);
1566
+ const manifestPipelineId = normalizeOptionalString(input.manifest.pipeline_id);
1567
+ const manifestParentRunId = normalizeOptionalString(input.manifest.parent_run_id);
1568
+ const manifestIssueId = normalizeOptionalString(input.manifest.issue_id);
1569
+ const manifestIssueIdentifier = normalizeOptionalString(input.manifest.issue_identifier);
1570
+ const status = normalizeOptionalString(input.manifest.status);
1571
+ if (manifestRunId !== input.runId ||
1572
+ manifestTaskId !== input.taskId ||
1573
+ manifestPipelineId !== PROVIDER_LINEAR_CHILD_LANE_PIPELINE_ID ||
1574
+ manifestParentRunId !== input.parentRunId ||
1575
+ manifestIssueId !== input.issueId ||
1576
+ manifestIssueIdentifier !== input.issueIdentifier ||
1577
+ !status) {
1578
+ return null;
1579
+ }
1580
+ const recordedArtifactRoot = normalizeOptionalString(input.manifest.artifact_root);
1581
+ if (recordedArtifactRoot && resolveRunPath(input.repoRoot, recordedArtifactRoot) !== input.artifactRoot) {
1582
+ return null;
1583
+ }
1584
+ const recordedManifestPath = normalizeOptionalString(input.manifest.manifest_path) ?? normalizeOptionalString(input.manifest.manifest);
1585
+ if (recordedManifestPath && resolveRunPath(input.repoRoot, recordedManifestPath) !== input.manifestPath) {
1586
+ return null;
1587
+ }
1588
+ const recordedLogPath = normalizeOptionalString(input.manifest.log_path);
1589
+ const logPath = recordedLogPath ? resolveRunPath(input.repoRoot, recordedLogPath) : join(input.artifactRoot, 'run.log');
1590
+ if (recordedLogPath && !isPathWithinRoot(input.artifactRoot, logPath)) {
1591
+ return null;
1592
+ }
1593
+ return {
1594
+ run_id: input.runId,
1595
+ task_id: input.taskId,
1596
+ pipeline_id: PROVIDER_LINEAR_CHILD_LANE_PIPELINE_ID,
1597
+ status,
1598
+ artifact_root: input.artifactRoot,
1599
+ manifest_path: input.manifestPath,
1600
+ log_path: logPath,
1601
+ summary: stripNonApplicableGuardrailSummaryLines(input.manifest, normalizeOptionalString(input.manifest.summary)),
1602
+ guardrails_required: resolveGuardrailsRequiredForManifest(input.manifest),
1603
+ guardrails_required_source: resolveGuardrailsRequiredSourceForManifest(input.manifest),
1604
+ guardrail_command_count: countGuardrailCommands(input.manifest),
1605
+ runtime_mode_requested: normalizeOptionalString(input.manifest.runtime_mode_requested),
1606
+ runtime_mode: normalizeOptionalString(input.manifest.runtime_mode),
1607
+ runtime_provider: normalizeOptionalString(input.manifest.runtime_provider)
1608
+ };
1609
+ }
1610
+ function buildRepairedChildLaneRecord(input) {
1611
+ const zeroBytePatch = input.childRun.status === 'succeeded' && input.proof.patch_bytes === 0;
1612
+ return {
1613
+ stream: input.reservation.stream,
1614
+ pipeline_id: PROVIDER_LINEAR_CHILD_LANE_PIPELINE_ID,
1615
+ task_id: input.reservation.task_id,
1616
+ run_id: input.childRun.run_id,
1617
+ status: input.childRun.status,
1618
+ manifest_path: input.childRun.manifest_path,
1619
+ artifact_root: input.childRun.artifact_root,
1620
+ log_path: input.childRun.log_path,
1621
+ summary: input.childRun.summary,
1622
+ guardrails_required: input.childRun.guardrails_required,
1623
+ guardrails_required_source: input.childRun.guardrails_required_source,
1624
+ guardrail_command_count: input.childRun.guardrail_command_count,
1625
+ issue_id: input.reservation.issue_id,
1626
+ issue_identifier: input.reservation.issue_identifier,
1627
+ workspace_path: input.reservation.workspace_path,
1628
+ source_setup: input.reservation.source_setup,
1629
+ launched_at: input.reservation.launched_at,
1630
+ purpose: input.reservation.purpose,
1631
+ instructions: input.reservation.instructions,
1632
+ scope: input.reservation.scope,
1633
+ parent_snapshot: input.reservation.parent_snapshot,
1634
+ lane_workspace_path: normalizeOptionalString(input.proof.lane_workspace_path),
1635
+ patch_artifact_path: normalizeOptionalString(input.proof.patch_artifact_path),
1636
+ patch_bytes: Number.isFinite(input.proof.patch_bytes) ? input.proof.patch_bytes : null,
1637
+ decision: zeroBytePatch ? 'rejected' : 'pending',
1638
+ in_flight_action: null,
1639
+ in_flight_started_at: null,
1640
+ decision_at: zeroBytePatch ? input.now : null,
1641
+ decision_reason: zeroBytePatch ? buildNoOutputAdvisoryChildLaneDecisionReason(input.childRun) : null
1642
+ };
1643
+ }
1644
+ function resolveChildLaneReservationRecoveryTimingViolation(input) {
1645
+ const reservationLaunchedAt = normalizeOptionalString(input.reservation.launched_at);
1646
+ const proofCompletedAt = normalizeOptionalString(input.proof.updated_at) ?? normalizeOptionalString(input.proof.last_event_at);
1647
+ if (!reservationLaunchedAt || !proofCompletedAt) {
1648
+ return 'Child lane proof timing is missing; cannot repair or recover a launching reservation safely.';
1649
+ }
1650
+ const reservationLaunchedMs = Date.parse(reservationLaunchedAt);
1651
+ const proofCompletedMs = Date.parse(proofCompletedAt);
1652
+ if (!Number.isFinite(reservationLaunchedMs) || !Number.isFinite(proofCompletedMs)) {
1653
+ return 'Child lane proof timing is invalid; cannot repair or recover a launching reservation safely.';
1654
+ }
1655
+ if (proofCompletedMs < reservationLaunchedMs) {
1656
+ return 'Child lane proof completion predates the pending launching reservation.';
1657
+ }
1658
+ return null;
1659
+ }
1660
+ function resolveChildLaneReservationRepairProofViolation(input) {
1661
+ if (normalizeOptionalString(input.proof.purpose) !== normalizeOptionalString(input.reservation.purpose)) {
1662
+ return 'Child lane proof purpose does not match the pending launching reservation.';
1663
+ }
1664
+ if (normalizeOptionalString(input.proof.instructions) !== normalizeOptionalString(input.reservation.instructions)) {
1665
+ return 'Child lane proof instructions do not match the pending launching reservation.';
1666
+ }
1667
+ if (!areChildLaneScopesEquivalent(input.proof.scope, input.reservation.scope)) {
1668
+ return 'Child lane proof scope does not match the pending launching reservation.';
1669
+ }
1670
+ if (!areChildLaneParentSnapshotsEquivalent(input.proof.parent_snapshot, input.reservation.parent_snapshot)) {
1671
+ return 'Child lane proof parent snapshot does not match the pending launching reservation.';
1672
+ }
1673
+ if (normalizeOptionalString(input.proof.status) !== input.childRun.status) {
1674
+ return 'Child lane proof status does not match the child manifest status.';
1675
+ }
1676
+ const recoveryTimingViolation = resolveChildLaneReservationRecoveryTimingViolation({
1677
+ reservation: input.reservation,
1678
+ proof: input.proof
1679
+ });
1680
+ if (recoveryTimingViolation) {
1681
+ return recoveryTimingViolation;
1682
+ }
1683
+ const artifactRoot = resolveAcceptedChildLaneArtifactRoot(input.repoRoot, input.childRunsRoot, input.candidate);
1684
+ if (!artifactRoot) {
1685
+ return 'Child lane artifact root must stay anchored to the expected workspace-local child run directory before reservation repair.';
1686
+ }
1687
+ const proofLineageViolation = resolveChildLaneProofLineageViolation(input.context.runId, input.candidate, input.proof);
1688
+ if (proofLineageViolation) {
1689
+ return proofLineageViolation;
1690
+ }
1691
+ if (input.action !== 'accept') {
1692
+ return null;
1693
+ }
1694
+ const patchArtifactPath = resolveAcceptedPatchArtifactPath(input.repoRoot, input.candidate, artifactRoot);
1695
+ if (!patchArtifactPath) {
1696
+ return 'Child lane proof patch artifact path must stay within the child lane artifact root before reservation repair.';
1697
+ }
1698
+ return resolveAcceptedChildLaneProofViolation(input.context.runId, input.candidate, input.proof, input.repoRoot, artifactRoot, patchArtifactPath);
1699
+ }
1700
+ function mergeCompletedChildLaneWithParentDecision(current, completed) {
1701
+ if (current.decision === 'pending') {
1702
+ return {
1703
+ ...completed,
1704
+ in_flight_action: current.in_flight_action,
1705
+ in_flight_started_at: current.in_flight_started_at
1706
+ };
1707
+ }
1708
+ return {
1709
+ ...completed,
1710
+ decision: current.decision,
1711
+ in_flight_action: null,
1712
+ in_flight_started_at: null,
1713
+ decision_at: current.decision_at,
1714
+ decision_reason: current.decision_reason
1715
+ };
1716
+ }
1717
+ function replaceChildLaneRecord(records, target, replacement) {
1718
+ let replaced = false;
1719
+ const next = records.map((entry) => {
1720
+ if (replaced || !matchesChildLaneRecordIdentity(entry, target)) {
1721
+ return entry;
1722
+ }
1723
+ replaced = true;
1724
+ return replacement;
1725
+ });
1726
+ return replaced ? next : null;
1727
+ }
1728
+ function matchesChildLaneRecordIdentity(left, right) {
1729
+ return left.stream === right.stream && left.task_id === right.task_id && left.run_id === right.run_id;
1730
+ }
1731
+ function buildChildLaneReservationRepairDecisionReason(reservation, repaired) {
1732
+ return `Reconciled stale launching reservation ${reservation.run_id} to recovered child run ${repaired.run_id} after matching manifest/proof recovery.`;
1733
+ }
1734
+ function normalizeAction(value) {
1735
+ return value === 'launch' || value === 'accept' || value === 'reject' || value === 'invalidate'
1736
+ ? value
1737
+ : null;
1738
+ }
1739
+ function mapActionToDecision(action) {
1740
+ if (action === 'accept') {
1741
+ return 'accepted';
1742
+ }
1743
+ if (action === 'reject') {
1744
+ return 'rejected';
1745
+ }
1746
+ return 'invalidated';
1747
+ }
1748
+ function defaultDecisionReason(action, childLane) {
1749
+ if (action === 'accept') {
1750
+ return `Parent accepted patch artifact ${childLane.patch_artifact_path ?? '(missing patch path)'}.`;
1751
+ }
1752
+ if (action === 'reject') {
1753
+ return 'Parent rejected child lane output.';
1754
+ }
1755
+ return 'Parent invalidated child lane output.';
1756
+ }
1757
+ function buildReservedChildLaneRecord(input) {
1758
+ const reservationRunId = buildChildLaneReservationRunId();
1759
+ const artifactRoot = join(input.childRunsRoot, input.childTaskId, 'cli', reservationRunId);
1760
+ return {
1761
+ stream: input.stream,
1762
+ pipeline_id: PROVIDER_LINEAR_CHILD_LANE_PIPELINE_ID,
1763
+ task_id: input.childTaskId,
1764
+ run_id: reservationRunId,
1765
+ status: 'launching',
1766
+ manifest_path: join(artifactRoot, 'manifest.json'),
1767
+ artifact_root: artifactRoot,
1768
+ log_path: join(artifactRoot, 'run.log'),
1769
+ summary: 'Child lane reserved before child run startup.',
1770
+ issue_id: input.context.issueId,
1771
+ issue_identifier: input.context.issueIdentifier,
1772
+ workspace_path: input.context.repoRoot,
1773
+ source_setup: input.sourceSetup,
1774
+ launched_at: input.now,
1775
+ purpose: input.purpose,
1776
+ instructions: normalizeOptionalString(input.instructions),
1777
+ scope: input.scope,
1778
+ parent_snapshot: input.parentSnapshot,
1779
+ lane_workspace_path: null,
1780
+ patch_artifact_path: null,
1781
+ patch_bytes: null,
1782
+ decision: 'pending',
1783
+ in_flight_action: null,
1784
+ in_flight_started_at: null,
1785
+ decision_at: null,
1786
+ decision_reason: null
1787
+ };
1788
+ }
1789
+ function buildChildLaneReservationRunId() {
1790
+ return `launching-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
1791
+ }
1792
+ function findPendingChildLaneConflict(records, stream, scope) {
1793
+ return records.find((entry) => entry.decision === 'pending' &&
1794
+ (entry.stream === stream || scopesOverlap(entry.scope, scope))) ?? null;
1795
+ }
1796
+ function selectChildLanesCountingTowardParallelFirstCap(records, now) {
1797
+ return records.filter((entry) => !isStaleInFlightChildLane(entry, now) &&
1798
+ (entry.decision === 'pending' || entry.in_flight_action !== null));
1799
+ }
1800
+ function isStaleInFlightChildLane(entry, now) {
1801
+ if (!entry.in_flight_action) {
1802
+ return false;
1803
+ }
1804
+ const startedAt = normalizeOptionalString(entry.in_flight_started_at);
1805
+ if (!startedAt) {
1806
+ return true;
1807
+ }
1808
+ const startedMs = Date.parse(startedAt);
1809
+ const nowMs = Date.parse(now);
1810
+ if (!Number.isFinite(startedMs) || !Number.isFinite(nowMs)) {
1811
+ return true;
1812
+ }
1813
+ return nowMs - startedMs >= PROVIDER_LINEAR_CHILD_LANE_IN_FLIGHT_STALE_MS;
1814
+ }
1815
+ function describeChildLaneCapExhaustion(records) {
1816
+ const sample = records
1817
+ .slice(0, PROVIDER_LINEAR_CHILD_LANE_PARALLEL_FIRST_CAP)
1818
+ .map((entry) => `${entry.stream}:${entry.run_id}`)
1819
+ .join(', ');
1820
+ return `Same-issue child-lane cap exhausted: ${records.length}/${PROVIDER_LINEAR_CHILD_LANE_PARALLEL_FIRST_CAP} active, pending, or unaccepted lane(s) already count toward the parallel-first cap (${sample}). Do not launch another lane; record \`stay_serial\` with reason \`existing_child_lane_active\` and include \`cap_exhausted\` in the summary. This cap preserves provider admission constraints instead of bypassing them.`;
1821
+ }
1822
+ function describePendingChildLaneConflict(stream, conflict) {
1823
+ return conflict.stream === stream
1824
+ ? `Child lane stream ${stream} already has unresolved lane ${conflict.run_id}; accept, reject, or invalidate that lane before relaunching the same stream.`
1825
+ : `Child lane scope overlaps unresolved lane ${conflict.stream} (${conflict.run_id}); reject, accept, or invalidate that lane before launching another overlapping lane.`;
1826
+ }
1827
+ async function removeReservedChildLane(runDir, reserved, deps) {
1828
+ await deps.transactChildLanes(runDir, async (records) => ({
1829
+ records: removePendingChildLaneRecord(records, reserved),
1830
+ result: undefined
1831
+ }));
1832
+ }
1833
+ function removePendingChildLaneRecord(records, target) {
1834
+ return records.filter((entry) => !matchesChildLaneRecordIdentity(entry, target) || entry.decision !== 'pending');
1835
+ }
1836
+ function resolveChildLaneDecisionProvenanceViolation(context, stream, childLane) {
1837
+ const expectedTaskId = `${context.taskId}-${stream}`;
1838
+ if (childLane.pipeline_id !== PROVIDER_LINEAR_CHILD_LANE_PIPELINE_ID) {
1839
+ return `Pending child lane ${stream} must remain recorded as ${PROVIDER_LINEAR_CHILD_LANE_PIPELINE_ID}; recorded pipeline was ${childLane.pipeline_id}.`;
1840
+ }
1841
+ if (childLane.task_id !== expectedTaskId) {
1842
+ return `Pending child lane ${stream} must stay bound to task ${expectedTaskId}; recorded task was ${childLane.task_id}.`;
1843
+ }
1844
+ if (childLane.issue_id !== context.issueId || childLane.issue_identifier !== context.issueIdentifier) {
1845
+ return `Pending child lane ${stream} must stay bound to issue ${context.issueIdentifier}; recorded issue was ${childLane.issue_identifier} (${childLane.issue_id}).`;
1846
+ }
1847
+ return null;
1848
+ }
1849
+ function resolveAcceptedPatchArtifactPath(repoRoot, childLane, artifactRoot) {
1850
+ const patchArtifactPath = normalizeOptionalString(childLane.patch_artifact_path);
1851
+ if (!patchArtifactPath) {
1852
+ return null;
1853
+ }
1854
+ const resolvedPatchArtifactPath = resolveRunPath(repoRoot, patchArtifactPath);
1855
+ return isPathWithinRoot(artifactRoot, resolvedPatchArtifactPath) ? resolvedPatchArtifactPath : null;
1856
+ }
1857
+ function resolveAcceptedChildLaneArtifactRoot(repoRoot, childRunsRoot, childLane) {
1858
+ const taskId = normalizeOptionalString(childLane.task_id);
1859
+ const artifactRoot = normalizeOptionalString(childLane.artifact_root);
1860
+ const manifestPath = normalizeOptionalString(childLane.manifest_path);
1861
+ const runId = normalizeOptionalString(childLane.run_id);
1862
+ if (!taskId || !artifactRoot || !runId) {
1863
+ return null;
1864
+ }
1865
+ let safeRunId;
1866
+ try {
1867
+ safeRunId = sanitizeRunId(runId);
1868
+ }
1869
+ catch {
1870
+ return null;
1871
+ }
1872
+ const expectedArtifactRoot = resolve(childRunsRoot, taskId, 'cli', safeRunId);
1873
+ const resolvedArtifactRoot = resolveRunPath(repoRoot, artifactRoot);
1874
+ if (resolvedArtifactRoot !== expectedArtifactRoot) {
1875
+ return null;
1876
+ }
1877
+ if (manifestPath) {
1878
+ const resolvedManifestPath = resolveRunPath(repoRoot, manifestPath);
1879
+ if (resolvedManifestPath !== join(expectedArtifactRoot, 'manifest.json')) {
1880
+ return null;
1881
+ }
1882
+ }
1883
+ return expectedArtifactRoot;
1884
+ }
1885
+ async function readPatchChangedPaths(patchPath) {
1886
+ const rawPatch = await readFile(patchPath, 'utf8');
1887
+ const changedPaths = new Set();
1888
+ for (const line of rawPatch.split(/\r?\n/u)) {
1889
+ const parsed = parseGitDiffHeaderPaths(line);
1890
+ if (!parsed) {
1891
+ continue;
1892
+ }
1893
+ for (const candidate of parsed) {
1894
+ if (candidate === 'dev/null') {
1895
+ continue;
1896
+ }
1897
+ const normalized = normalizeScopeFileEntry(candidate);
1898
+ if (normalized) {
1899
+ changedPaths.add(normalized);
1900
+ }
1901
+ }
1902
+ }
1903
+ return [...changedPaths];
1904
+ }
1905
+ function parseGitDiffHeaderPaths(line) {
1906
+ if (!line.startsWith('diff --git ')) {
1907
+ return null;
1908
+ }
1909
+ const tokens = [];
1910
+ let index = 'diff --git '.length;
1911
+ while (index < line.length && tokens.length < 2) {
1912
+ while (line[index] === ' ') {
1913
+ index += 1;
1914
+ }
1915
+ if (index >= line.length) {
1916
+ break;
1917
+ }
1918
+ if (line[index] === '"') {
1919
+ let end = index + 1;
1920
+ let escaped = false;
1921
+ while (end < line.length) {
1922
+ const current = line[end];
1923
+ if (escaped) {
1924
+ escaped = false;
1925
+ }
1926
+ else if (current === '\\') {
1927
+ escaped = true;
1928
+ }
1929
+ else if (current === '"') {
1930
+ end += 1;
1931
+ break;
1932
+ }
1933
+ end += 1;
1934
+ }
1935
+ tokens.push(line.slice(index, end));
1936
+ index = end;
1937
+ continue;
1938
+ }
1939
+ let end = index;
1940
+ while (end < line.length && line[end] !== ' ') {
1941
+ end += 1;
1942
+ }
1943
+ tokens.push(line.slice(index, end));
1944
+ index = end;
1945
+ }
1946
+ if (tokens.length !== 2) {
1947
+ return null;
1948
+ }
1949
+ return tokens
1950
+ .map((token) => decodeGitDiffPathToken(token))
1951
+ .map((token) => (token.startsWith('a/') || token.startsWith('b/') ? token.slice(2) : token));
1952
+ }
1953
+ function decodeGitDiffPathToken(token) {
1954
+ if (!(token.startsWith('"') && token.endsWith('"'))) {
1955
+ return token;
1956
+ }
1957
+ const bytes = [];
1958
+ const raw = token.slice(1, -1);
1959
+ for (let index = 0; index < raw.length; index += 1) {
1960
+ const current = raw[index];
1961
+ if (current !== '\\') {
1962
+ bytes.push(...Buffer.from(current, 'utf8'));
1963
+ continue;
1964
+ }
1965
+ const next = raw[index + 1];
1966
+ if (next === undefined) {
1967
+ bytes.push('\\'.charCodeAt(0));
1968
+ continue;
1969
+ }
1970
+ if (/[0-7]{3}/u.test(raw.slice(index + 1, index + 4))) {
1971
+ bytes.push(parseInt(raw.slice(index + 1, index + 4), 8));
1972
+ index += 3;
1973
+ continue;
1974
+ }
1975
+ switch (next) {
1976
+ case '\\':
1977
+ case '"':
1978
+ bytes.push(next.charCodeAt(0));
1979
+ break;
1980
+ case 'n':
1981
+ bytes.push('\n'.charCodeAt(0));
1982
+ break;
1983
+ case 'r':
1984
+ bytes.push('\r'.charCodeAt(0));
1985
+ break;
1986
+ case 't':
1987
+ bytes.push('\t'.charCodeAt(0));
1988
+ break;
1989
+ default:
1990
+ bytes.push(next.charCodeAt(0));
1991
+ break;
1992
+ }
1993
+ index += 1;
1994
+ }
1995
+ return Buffer.from(bytes).toString('utf8');
1996
+ }
1997
+ function resolveAcceptedPatchScopeViolation(scope, patchChangedPaths, proofScope = null) {
1998
+ let expectedScope;
1999
+ try {
2000
+ expectedScope = resolveProviderLinearChildLaneScopeContract(scope);
2001
+ }
2002
+ catch (error) {
2003
+ return `Child lane parent ledger recorded an invalid scope contract: ${error instanceof Error ? error.message : String(error)}`;
2004
+ }
2005
+ const persistedScopeViolation = resolvePersistedScopeContractViolation('Child lane parent ledger', scope, expectedScope);
2006
+ if (persistedScopeViolation) {
2007
+ return persistedScopeViolation;
2008
+ }
2009
+ if (proofScope) {
2010
+ let expectedProofScope;
2011
+ try {
2012
+ expectedProofScope = resolveProviderLinearChildLaneScopeContract(proofScope);
2013
+ }
2014
+ catch (error) {
2015
+ return `Child lane proof bundle recorded an invalid scope contract: ${error instanceof Error ? error.message : String(error)}`;
2016
+ }
2017
+ const persistedProofViolation = resolvePersistedScopeContractViolation('Child lane proof bundle', proofScope, expectedProofScope);
2018
+ if (persistedProofViolation) {
2019
+ return persistedProofViolation;
2020
+ }
2021
+ if (!areChildLaneScopesEquivalent(expectedScope, expectedProofScope)) {
2022
+ return 'Child lane proof scope contract does not match the parent ledger scope contract.';
2023
+ }
2024
+ }
2025
+ if (patchChangedPaths.length === 0) {
2026
+ return 'Child lane patch does not declare any repo-relative file targets, so parent acceptance cannot verify the bounded scope.';
2027
+ }
2028
+ const outOfScopePaths = patchChangedPaths.filter((entry) => !providerLinearChildLanePathMatchesSelectors(entry, expectedScope.allowed_path_selectors ?? []));
2029
+ if (outOfScopePaths.length === 0) {
2030
+ return null;
2031
+ }
2032
+ return `Child lane patch touches files outside the declared scope contract (${outOfScopePaths.join(', ')}). Allowed selectors: ${formatProviderLinearChildLanePathSelectors(expectedScope.allowed_path_selectors ?? [])}.`;
2033
+ }
2034
+ async function resolveAcceptedPatchDirtyConflict(workspacePath, patchChangedPaths, deps) {
2035
+ const dirtyPaths = (await deps.readParentDirtyPaths(workspacePath)).filter((entry) => !isIgnoredParentArtifactPath(entry));
2036
+ if (dirtyPaths.length === 0) {
2037
+ return null;
2038
+ }
2039
+ const overlapping = patchChangedPaths.filter((entry) => dirtyPaths.includes(entry));
2040
+ if (overlapping.length === 0) {
2041
+ return null;
2042
+ }
2043
+ return `Parent workspace already has pending edits to files this child-lane patch would update (${overlapping.join(', ')}); clean, commit, or incorporate those parent edits before accepting the child-lane patch.`;
2044
+ }
2045
+ async function resolveParentSnapshot(context, env, deps) {
2046
+ const trackedIssue = await deps.readTrackedIssue({
2047
+ issueId: context.issueId,
2048
+ sourceSetup: context.sourceSetup,
2049
+ env
2050
+ });
2051
+ return {
2052
+ issue_updated_at: trackedIssue?.updated_at ?? context.issueUpdatedAt ?? null,
2053
+ issue_state: trackedIssue?.state ?? null,
2054
+ issue_state_type: trackedIssue?.state_type ?? null,
2055
+ captured_at: deps.now()
2056
+ };
2057
+ }
2058
+ function resolveChildLaneStaleReason(childLane, currentHeadSha, currentIssue) {
2059
+ if (childLane.parent_snapshot.base_sha && currentHeadSha && childLane.parent_snapshot.base_sha !== currentHeadSha) {
2060
+ return `Child lane ${childLane.stream} is stale because the parent workspace HEAD moved from ${childLane.parent_snapshot.base_sha} to ${currentHeadSha}.`;
2061
+ }
2062
+ if (childLane.parent_snapshot.issue_updated_at &&
2063
+ currentIssue.issue_updated_at &&
2064
+ childLane.parent_snapshot.issue_updated_at !== currentIssue.issue_updated_at) {
2065
+ return `Child lane ${childLane.stream} is stale because the issue updated_at changed from ${childLane.parent_snapshot.issue_updated_at} to ${currentIssue.issue_updated_at}.`;
2066
+ }
2067
+ if (childLane.parent_snapshot.issue_state &&
2068
+ currentIssue.issue_state &&
2069
+ childLane.parent_snapshot.issue_state !== currentIssue.issue_state) {
2070
+ return `Child lane ${childLane.stream} is stale because the issue state changed from ${childLane.parent_snapshot.issue_state} to ${currentIssue.issue_state}.`;
2071
+ }
2072
+ return null;
2073
+ }
2074
+ function normalizeChildLaneStreamName(value) {
2075
+ if (!value) {
2076
+ return null;
2077
+ }
2078
+ const normalized = slugify(value, '').toLowerCase();
2079
+ return normalized.length > 0 ? normalized : null;
2080
+ }
2081
+ function normalizeChildLaneScope(files, phases, repoRoot) {
2082
+ const normalizedFiles = normalizeScopeEntries(files, 'file', repoRoot);
2083
+ const normalizedPhases = normalizeScopeEntries(phases, 'phase');
2084
+ if (normalizedFiles.length === 0 && normalizedPhases.length === 0) {
2085
+ return null;
2086
+ }
2087
+ return resolveProviderLinearChildLaneScopeContract({
2088
+ files: normalizedFiles,
2089
+ phases: normalizedPhases
2090
+ });
2091
+ }
2092
+ function normalizeScopeEntries(values, kind = 'file', repoRoot) {
2093
+ return [
2094
+ ...new Set(values
2095
+ .map((value) => normalizeOptionalString(value))
2096
+ .map((value) => {
2097
+ if (!value) {
2098
+ return null;
2099
+ }
2100
+ return kind === 'file' ? normalizeScopeFileEntry(value, repoRoot) : normalizeScopePhaseEntry(value);
2101
+ })
2102
+ .filter((value) => value !== null))
2103
+ ];
2104
+ }
2105
+ function normalizeScopePhaseEntry(value) {
2106
+ const normalizedInput = normalizeOptionalString(value);
2107
+ if (!normalizedInput) {
2108
+ return null;
2109
+ }
2110
+ const normalized = normalizedInput.toLowerCase();
2111
+ return normalized.length > 0 ? normalized : null;
2112
+ }
2113
+ function normalizeScopeFileEntry(value, repoRoot) {
2114
+ const normalizedInput = normalizeOptionalString(value);
2115
+ if (!normalizedInput) {
2116
+ return null;
2117
+ }
2118
+ if (repoRoot && isAbsolute(normalizedInput)) {
2119
+ const absoluteCandidate = resolve(normalizedInput);
2120
+ if (!isPathWithinRoot(repoRoot, absoluteCandidate)) {
2121
+ return null;
2122
+ }
2123
+ const relativeToRoot = relative(repoRoot, absoluteCandidate);
2124
+ const relativePosix = posix.normalize(relativeToRoot.replaceAll('\\', '/'));
2125
+ return relativePosix === '' || relativePosix === '.'
2126
+ ? null
2127
+ : relativePosix;
2128
+ }
2129
+ const normalized = posix.normalize(normalizedInput.replaceAll('\\', '/'));
2130
+ const withoutCurrentDir = normalized.replace(/^(?:\.\/)+/u, '');
2131
+ const trimmed = withoutCurrentDir.replace(/\/+/gu, '/').replace(/\/$/u, '');
2132
+ if (trimmed === '' || trimmed === '.' || trimmed === '..' || trimmed.startsWith('../')) {
2133
+ return null;
2134
+ }
2135
+ return trimmed;
2136
+ }
2137
+ async function resolveParentDirtyScopeConflict(workspacePath, scope, deps) {
2138
+ const dirtyPaths = (await deps.readParentDirtyPaths(workspacePath)).filter((entry) => !isIgnoredParentArtifactPath(entry));
2139
+ if (dirtyPaths.length === 0) {
2140
+ return null;
2141
+ }
2142
+ const sample = dirtyPaths.slice(0, 5).join(', ');
2143
+ if (scope.phases.length > 0) {
2144
+ return `Parent workspace has pending changes (${sample}); phase-scoped child lanes launch from HEAD and therefore require a clean parent workspace baseline. Move workpad/temp scratch files such as .tmp/workpad.md outside the repo (for example /tmp), remove stale scratch artifacts, or narrow to a file-scoped lane after the parent-owned edits are clean.`;
2145
+ }
2146
+ const overlapping = scope.files.filter((entry) => dirtyPaths.includes(entry));
2147
+ if (overlapping.length === 0) {
2148
+ return null;
2149
+ }
2150
+ return `Parent workspace already has in-scope pending changes (${overlapping.join(', ')}); child lanes launch from HEAD and would miss those parent edits. Clean, commit, move scratch workpad/temp artifacts outside the repo (for example /tmp), or narrow the lane scope before launching it.`;
2151
+ }
2152
+ function isIgnoredParentArtifactPath(path) {
2153
+ return path === '.child-lanes' || path.startsWith('.child-lanes/') || path === '.tmp/workpad.md';
2154
+ }
2155
+ function formatChildLaneScopeLaunchFailureMessage(message) {
2156
+ const supportedPhases = resolveProviderLinearChildLaneSupportedPhases().join(', ');
2157
+ return `${message} Supported child-lane phases are: ${supportedPhases}. Do not use unsupported classification or analysis phases; use parent-owned source inspection, a supported file-scoped docs/tests lane, or a serial/no-go parallelization decision when no supported bounded slice exists.`;
2158
+ }
2159
+ function buildNoOutputAdvisoryChildLaneDecisionReason(childRun) {
2160
+ const summary = normalizeOptionalString(childRun.summary);
2161
+ return summary
2162
+ ? `No-output advisory: child lane produced a zero-byte patch. Use the child manifest/proof and summary "${summary}" as advisory evidence only; parent owns any implementation patch and final evidence path.`
2163
+ : 'No-output advisory: child lane produced a zero-byte patch. Use the child manifest/proof as advisory evidence only; parent owns any implementation patch and final evidence path.';
2164
+ }
2165
+ function scopesOverlap(left, right) {
2166
+ try {
2167
+ const resolvedLeft = resolveProviderLinearChildLaneScopeContract(left);
2168
+ const resolvedRight = resolveProviderLinearChildLaneScopeContract(right);
2169
+ return providerLinearChildLanePathSelectorsOverlap(resolvedLeft.allowed_path_selectors ?? [], resolvedRight.allowed_path_selectors ?? []);
2170
+ }
2171
+ catch {
2172
+ return (left.files.some((entry) => right.files.includes(entry)) ||
2173
+ left.phases.length > 0 ||
2174
+ right.phases.length > 0);
2175
+ }
2176
+ }
2177
+ function compareStringSets(left, right) {
2178
+ if (left.length !== right.length) {
2179
+ return false;
2180
+ }
2181
+ const sortedLeft = [...left].sort();
2182
+ const sortedRight = [...right].sort();
2183
+ return sortedLeft.every((value, index) => value === sortedRight[index]);
2184
+ }
2185
+ function areChildLaneScopesEquivalent(left, right) {
2186
+ return (compareStringSets(left.files, right.files) &&
2187
+ compareStringSets(left.phases, right.phases) &&
2188
+ normalizeOptionalString(left.phase_contract_version) === normalizeOptionalString(right.phase_contract_version) &&
2189
+ providerLinearChildLanePathSelectorsEqual(left.allowed_path_selectors ?? [], right.allowed_path_selectors ?? []));
2190
+ }
2191
+ function areChildLaneParentSnapshotsEquivalent(left, right) {
2192
+ return (normalizeOptionalString(left.base_sha) === normalizeOptionalString(right.base_sha) &&
2193
+ normalizeOptionalString(left.issue_updated_at) === normalizeOptionalString(right.issue_updated_at) &&
2194
+ normalizeOptionalString(left.issue_state) === normalizeOptionalString(right.issue_state) &&
2195
+ normalizeOptionalString(left.issue_state_type) === normalizeOptionalString(right.issue_state_type));
2196
+ }
2197
+ function resolvePersistedScopeContractViolation(sourceLabel, persistedScope, expectedScope) {
2198
+ const persistedVersion = normalizeOptionalString(persistedScope.phase_contract_version);
2199
+ const persistedSelectors = persistedScope.allowed_path_selectors ?? null;
2200
+ if (persistedScope.phases.length > 0 && (!persistedVersion || !persistedSelectors || persistedSelectors.length === 0)) {
2201
+ return `${sourceLabel} is missing persisted phase-scope contract metadata for phases (${expectedScope.phases.join(', ')}).`;
2202
+ }
2203
+ if (persistedVersion && persistedVersion !== expectedScope.phase_contract_version) {
2204
+ return `${sourceLabel} recorded scope contract version ${persistedVersion} but expected ${expectedScope.phase_contract_version}.`;
2205
+ }
2206
+ if (persistedSelectors &&
2207
+ !providerLinearChildLanePathSelectorsEqual(persistedSelectors, expectedScope.allowed_path_selectors ?? [])) {
2208
+ return `${sourceLabel} recorded path selectors (${formatProviderLinearChildLanePathSelectors(persistedSelectors)}) that do not match the expected selectors (${formatProviderLinearChildLanePathSelectors(expectedScope.allowed_path_selectors ?? [])}).`;
2209
+ }
2210
+ return null;
2211
+ }
2212
+ function resolveChildLaneProofLineageViolation(parentRunId, childLane, proof) {
2213
+ if (proof.task_id !== childLane.task_id ||
2214
+ proof.run_id !== childLane.run_id ||
2215
+ proof.parent_run_id !== parentRunId ||
2216
+ proof.stream !== childLane.stream ||
2217
+ proof.issue_id !== childLane.issue_id ||
2218
+ proof.issue_identifier !== childLane.issue_identifier) {
2219
+ return 'Child lane proof lineage does not match the parent ledger record.';
2220
+ }
2221
+ return null;
2222
+ }
2223
+ function resolveAcceptedChildLaneProofViolation(parentRunId, childLane, proof, repoRoot, artifactRoot, patchArtifactPath) {
2224
+ const lineageViolation = resolveChildLaneProofLineageViolation(parentRunId, childLane, proof);
2225
+ if (lineageViolation) {
2226
+ return lineageViolation;
2227
+ }
2228
+ const proofPatchArtifactPath = resolveAcceptedPatchArtifactPath(repoRoot, {
2229
+ ...childLane,
2230
+ patch_artifact_path: proof.patch_artifact_path
2231
+ }, artifactRoot);
2232
+ if (!proofPatchArtifactPath || proofPatchArtifactPath !== patchArtifactPath) {
2233
+ return 'Child lane proof patch artifact path does not match the parent-anchored patch artifact path.';
2234
+ }
2235
+ return null;
2236
+ }
2237
+ function isProofScopeViolation(message) {
2238
+ return (message.startsWith('Child lane proof bundle') ||
2239
+ message.startsWith('Child lane proof scope contract'));
2240
+ }
2241
+ function normalizeRuntimeMode(value) {
2242
+ if (typeof value !== 'string') {
2243
+ return null;
2244
+ }
2245
+ const normalized = value.trim().toLowerCase();
2246
+ return normalized === 'cli' || normalized === 'appserver' ? normalized : null;
2247
+ }
2248
+ function buildProviderLinearChildLaneStartEnv(env, input) {
2249
+ const sanitized = { ...process.env, ...env };
2250
+ for (const key of PROVIDER_LINEAR_CHILD_LANE_ENV_KEYS_TO_REMOVE) {
2251
+ delete sanitized[key];
2252
+ }
2253
+ for (const key of PROVIDER_LINEAR_CHILD_LANE_OPTIONAL_ENV_KEYS) {
2254
+ sanitized[key] = '';
2255
+ }
2256
+ delete sanitized.CO_LINEAR_WORKSPACE_ID;
2257
+ delete sanitized.CO_LINEAR_TEAM_ID;
2258
+ delete sanitized.CO_LINEAR_PROJECT_ID;
2259
+ sanitized.CODEX_ORCHESTRATOR_ROOT = input.repoRoot;
2260
+ sanitized.CODEX_ORCHESTRATOR_REPO_CONFIG_PATH =
2261
+ normalizeOptionalString(sanitized.CODEX_ORCHESTRATOR_REPO_CONFIG_PATH) ?? join(input.repoRoot, 'codex.orchestrator.json');
2262
+ sanitized.CODEX_ORCHESTRATOR_RUNS_DIR = resolveWorkspaceScopedArtifactDir(input.repoRoot, sanitized.CODEX_ORCHESTRATOR_RUNS_DIR, '.runs');
2263
+ sanitized.CODEX_ORCHESTRATOR_OUT_DIR = resolveWorkspaceScopedArtifactDir(input.repoRoot, sanitized.CODEX_ORCHESTRATOR_OUT_DIR, 'out');
2264
+ sanitized.MCP_RUNNER_TASK_ID = input.taskId;
2265
+ sanitized[PROVIDER_LINEAR_CHILD_LANE_STREAM_ENV] = input.stream;
2266
+ sanitized[PROVIDER_LINEAR_CHILD_LANE_PURPOSE_ENV] = input.purpose;
2267
+ sanitized[PROVIDER_LINEAR_CHILD_LANE_INSTRUCTIONS_ENV] = input.instructions ?? '';
2268
+ sanitized[PROVIDER_LINEAR_CHILD_LANE_FILES_ENV] = JSON.stringify(input.scope.files);
2269
+ sanitized[PROVIDER_LINEAR_CHILD_LANE_PHASES_ENV] = JSON.stringify(input.scope.phases);
2270
+ sanitized[PROVIDER_LINEAR_CHILD_LANE_PARENT_WORKSPACE_PATH_ENV] = input.parentWorkspacePath;
2271
+ sanitized[PROVIDER_LINEAR_CHILD_LANE_PARENT_SNAPSHOT_BASE_SHA_ENV] = input.parentSnapshot.base_sha ?? '';
2272
+ sanitized[PROVIDER_LINEAR_CHILD_LANE_PARENT_SNAPSHOT_CAPTURED_AT_ENV] = input.parentSnapshot.captured_at ?? '';
2273
+ sanitized[PROVIDER_LINEAR_CHILD_LANE_PARENT_SNAPSHOT_ISSUE_UPDATED_AT_ENV] = input.parentSnapshot.issue_updated_at ?? '';
2274
+ sanitized[PROVIDER_LINEAR_CHILD_LANE_PARENT_SNAPSHOT_ISSUE_STATE_ENV] = input.parentSnapshot.issue_state ?? '';
2275
+ sanitized[PROVIDER_LINEAR_CHILD_LANE_PARENT_SNAPSHOT_ISSUE_STATE_TYPE_ENV] = input.parentSnapshot.issue_state_type ?? '';
2276
+ if (input.sourceSetup?.provider === 'linear') {
2277
+ sanitized.CO_LINEAR_WORKSPACE_ID = input.sourceSetup.workspace_id ?? '';
2278
+ sanitized.CO_LINEAR_TEAM_ID = input.sourceSetup.team_id ?? '';
2279
+ sanitized.CO_LINEAR_PROJECT_ID = input.sourceSetup.project_id ?? '';
2280
+ }
2281
+ return sanitized;
2282
+ }
2283
+ function resolveCodexOrchestratorInvocation(env) {
2284
+ const invocation = resolveCodexOrchestratorBootstrapInvocation({ env, execPath: process.execPath });
2285
+ return { command: invocation.command, argsPrefix: invocation.args, envOverrides: invocation.envOverrides };
2286
+ }
2287
+ async function parseProviderChildLaneRunResult(raw, repoRoot, childRunsRoot, taskId) {
2288
+ const parsed = parseTrailingJsonObject(raw);
2289
+ if (!parsed) {
2290
+ return null;
2291
+ }
2292
+ const runId = normalizeOptionalString(parsed.run_id);
2293
+ const status = normalizeOptionalString(parsed.status);
2294
+ const artifactRoot = normalizeOptionalString(parsed.artifact_root);
2295
+ const manifestPath = normalizeOptionalString(parsed.manifest) ?? (artifactRoot ? join(artifactRoot, 'manifest.json') : null);
2296
+ if (!runId || !status || !artifactRoot || !manifestPath) {
2297
+ return null;
2298
+ }
2299
+ const safeRunId = (() => {
2300
+ try {
2301
+ return sanitizeRunId(runId);
2302
+ }
2303
+ catch {
2304
+ return null;
2305
+ }
2306
+ })();
2307
+ if (!safeRunId) {
2308
+ return null;
2309
+ }
2310
+ const expectedRunRoot = resolve(childRunsRoot, taskId, 'cli', safeRunId);
2311
+ const resolvedArtifactRoot = resolveRunPath(repoRoot, artifactRoot);
2312
+ const resolvedManifestPath = resolveRunPath(repoRoot, manifestPath);
2313
+ const resolvedLogPath = normalizeOptionalString(parsed.log_path);
2314
+ const normalizedLogPath = resolvedLogPath ? resolveRunPath(repoRoot, resolvedLogPath) : null;
2315
+ if (!isPathWithinRoot(expectedRunRoot, resolvedArtifactRoot) ||
2316
+ !isPathWithinRoot(expectedRunRoot, resolvedManifestPath) ||
2317
+ (normalizedLogPath && !isPathWithinRoot(expectedRunRoot, normalizedLogPath))) {
2318
+ return null;
2319
+ }
2320
+ let manifestRecord = null;
2321
+ try {
2322
+ const candidate = JSON.parse(await readFile(resolvedManifestPath, 'utf8'));
2323
+ if (candidate && typeof candidate === 'object' && !Array.isArray(candidate)) {
2324
+ manifestRecord = candidate;
2325
+ }
2326
+ }
2327
+ catch {
2328
+ manifestRecord = null;
2329
+ }
2330
+ const rawSummary = normalizeOptionalString(parsed.summary);
2331
+ const summary = manifestRecord
2332
+ ? stripNonApplicableGuardrailSummaryLines(manifestRecord, rawSummary)
2333
+ : rawSummary;
2334
+ return {
2335
+ run_id: safeRunId,
2336
+ task_id: taskId,
2337
+ pipeline_id: PROVIDER_LINEAR_CHILD_LANE_PIPELINE_ID,
2338
+ status,
2339
+ artifact_root: resolvedArtifactRoot,
2340
+ manifest_path: resolvedManifestPath,
2341
+ log_path: normalizedLogPath,
2342
+ summary,
2343
+ guardrails_required: manifestRecord ? resolveGuardrailsRequiredForManifest(manifestRecord) : null,
2344
+ guardrails_required_source: manifestRecord ? resolveGuardrailsRequiredSourceForManifest(manifestRecord) : null,
2345
+ guardrail_command_count: manifestRecord ? countGuardrailCommands(manifestRecord) : null,
2346
+ runtime_mode_requested: normalizeOptionalString(parsed.runtime_mode_requested),
2347
+ runtime_mode: normalizeOptionalString(parsed.runtime_mode),
2348
+ runtime_provider: normalizeOptionalString(parsed.runtime_provider)
2349
+ };
2350
+ }
2351
+ function resolveRunPath(repoRoot, value) {
2352
+ return isAbsolute(value) ? resolve(value) : resolve(repoRoot, value);
2353
+ }
2354
+ function resolveWorkspaceScopedArtifactDir(repoRoot, value, fallbackDirname) {
2355
+ const normalized = normalizeOptionalString(value);
2356
+ const fallback = join(repoRoot, fallbackDirname);
2357
+ if (!normalized) {
2358
+ return fallback;
2359
+ }
2360
+ const candidate = isAbsolute(normalized) ? resolve(normalized) : resolve(repoRoot, normalized);
2361
+ if (isPathWithinRoot(repoRoot, candidate)) {
2362
+ return candidate;
2363
+ }
2364
+ if (basename(dirname(repoRoot)) !== '.workspaces') {
2365
+ return fallback;
2366
+ }
2367
+ const sharedRoot = dirname(dirname(repoRoot));
2368
+ if (isPathWithinRoot(sharedRoot, candidate)) {
2369
+ return resolve(repoRoot, relative(sharedRoot, candidate));
2370
+ }
2371
+ return fallback;
2372
+ }
2373
+ function isPathWithinRoot(root, candidate) {
2374
+ const relativePath = relative(root, candidate);
2375
+ return relativePath === '' || (!relativePath.startsWith('..') && !relativePath.startsWith(`..${sep}`) && !isAbsolute(relativePath));
2376
+ }
2377
+ function failureResult(input) {
2378
+ return {
2379
+ ok: false,
2380
+ operation: 'child-lane',
2381
+ action: input.action,
2382
+ issue_id: input.issueId,
2383
+ issue_identifier: input.issueIdentifier,
2384
+ source_setup: input.sourceSetup,
2385
+ stream: input.stream,
2386
+ child_run: input.childRun,
2387
+ child_lane: input.childLane,
2388
+ error: {
2389
+ code: input.code,
2390
+ message: input.message,
2391
+ status: input.status
2392
+ }
2393
+ };
2394
+ }
2395
+ function formatProviderWorkerChildLaneProvenanceInvalidMessage(context, env) {
2396
+ const manifestLaunchSource = normalizeOptionalString(context.manifest.provider_launch_source) ??
2397
+ normalizeOptionalString(context.manifest.providerLaunchSource);
2398
+ const manifestTaskId = normalizeOptionalString(context.manifest.provider_control_host_task_id) ??
2399
+ normalizeOptionalString(context.manifest.providerControlHostTaskId);
2400
+ const manifestRunId = normalizeOptionalString(context.manifest.provider_control_host_run_id) ??
2401
+ normalizeOptionalString(context.manifest.providerControlHostRunId);
2402
+ const envLaunchSource = normalizeOptionalString(env[PROVIDER_LAUNCH_SOURCE_ENV]);
2403
+ const envTaskId = normalizeOptionalString(env[PROVIDER_CONTROL_HOST_TASK_ID_ENV]);
2404
+ const envRunId = normalizeOptionalString(env[PROVIDER_CONTROL_HOST_RUN_ID_ENV]);
2405
+ return [
2406
+ 'linear child-lane requires provider control-host provenance recorded on the parent provider-worker manifest and matching active environment.',
2407
+ 'Required manifest fields: provider_launch_source=control-host, provider_control_host_task_id, provider_control_host_run_id.',
2408
+ `Parent manifest: ${context.manifestPath}.`,
2409
+ `Manifest values: provider_launch_source=${manifestLaunchSource ?? 'missing'}, provider_control_host_task_id=${manifestTaskId ?? 'missing'}, provider_control_host_run_id=${manifestRunId ?? 'missing'}.`,
2410
+ `Active env values: ${PROVIDER_LAUNCH_SOURCE_ENV}=${envLaunchSource ?? 'missing'}, ${PROVIDER_CONTROL_HOST_TASK_ID_ENV}=${envTaskId ?? 'missing'}, ${PROVIDER_CONTROL_HOST_RUN_ID_ENV}=${envRunId ?? 'missing'}.`,
2411
+ `recorded=${String(context.providerControlHostRecordedInManifest)} matches=${String(context.providerControlHostMatchesManifest)}.`
2412
+ ].join(' ');
2413
+ }
2414
+ function normalizeOptionalString(value) {
2415
+ if (typeof value !== 'string') {
2416
+ return null;
2417
+ }
2418
+ const trimmed = value.trim();
2419
+ return trimmed.length > 0 ? trimmed : null;
2420
+ }