@claudexor/orchestrator 4.8.2 → 5.0.2

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 (228) hide show
  1. package/dist/account-pool.d.ts +4 -1
  2. package/dist/account-pool.d.ts.map +1 -1
  3. package/dist/account-pool.js +25 -19
  4. package/dist/account-pool.js.map +1 -1
  5. package/dist/account-resolution.d.ts +1 -4
  6. package/dist/account-resolution.d.ts.map +1 -1
  7. package/dist/account-resolution.js +19 -42
  8. package/dist/account-resolution.js.map +1 -1
  9. package/dist/attemptOutputMarkers.d.ts +7 -0
  10. package/dist/attemptOutputMarkers.d.ts.map +1 -1
  11. package/dist/attemptOutputMarkers.js +1 -1
  12. package/dist/attemptOutputMarkers.js.map +1 -1
  13. package/dist/attemptTelemetry.d.ts +4 -1
  14. package/dist/attemptTelemetry.d.ts.map +1 -1
  15. package/dist/attemptTelemetry.js +9 -26
  16. package/dist/attemptTelemetry.js.map +1 -1
  17. package/dist/candidateEvidence.d.ts +29 -9
  18. package/dist/candidateEvidence.d.ts.map +1 -1
  19. package/dist/candidateEvidence.js +68 -16
  20. package/dist/candidateEvidence.js.map +1 -1
  21. package/dist/candidateOutputs.d.ts +44 -22
  22. package/dist/candidateOutputs.d.ts.map +1 -1
  23. package/dist/candidateOutputs.js +116 -72
  24. package/dist/candidateOutputs.js.map +1 -1
  25. package/dist/candidateReview.d.ts.map +1 -1
  26. package/dist/candidateReview.js +44 -8
  27. package/dist/candidateReview.js.map +1 -1
  28. package/dist/candidateTerminals.d.ts +1 -0
  29. package/dist/candidateTerminals.d.ts.map +1 -1
  30. package/dist/candidateTerminals.js +38 -15
  31. package/dist/candidateTerminals.js.map +1 -1
  32. package/dist/candidateWorkProduct.d.ts +2 -1
  33. package/dist/candidateWorkProduct.d.ts.map +1 -1
  34. package/dist/candidateWorkProduct.js +6 -3
  35. package/dist/candidateWorkProduct.js.map +1 -1
  36. package/dist/captureRefusal.d.ts +41 -3
  37. package/dist/captureRefusal.d.ts.map +1 -1
  38. package/dist/captureRefusal.js +168 -25
  39. package/dist/captureRefusal.js.map +1 -1
  40. package/dist/continuation-chain.test-support.d.ts +473 -0
  41. package/dist/continuation-chain.test-support.d.ts.map +1 -0
  42. package/dist/continuation-chain.test-support.js +206 -0
  43. package/dist/continuation-chain.test-support.js.map +1 -0
  44. package/dist/continuation-custody.d.ts +4 -1
  45. package/dist/continuation-custody.d.ts.map +1 -1
  46. package/dist/continuation-custody.js +71 -29
  47. package/dist/continuation-custody.js.map +1 -1
  48. package/dist/continuation-evidence-io.d.ts +30 -4
  49. package/dist/continuation-evidence-io.d.ts.map +1 -1
  50. package/dist/continuation-evidence-io.js +162 -46
  51. package/dist/continuation-evidence-io.js.map +1 -1
  52. package/dist/continuation-evidence.d.ts +40 -3
  53. package/dist/continuation-evidence.d.ts.map +1 -1
  54. package/dist/continuation-evidence.js +85 -11
  55. package/dist/continuation-evidence.js.map +1 -1
  56. package/dist/continuation-input.d.ts +10 -1
  57. package/dist/continuation-input.d.ts.map +1 -1
  58. package/dist/continuation-input.js +21 -20
  59. package/dist/continuation-input.js.map +1 -1
  60. package/dist/continuation-later.d.ts +30 -0
  61. package/dist/continuation-later.d.ts.map +1 -0
  62. package/dist/continuation-later.js +108 -0
  63. package/dist/continuation-later.js.map +1 -0
  64. package/dist/continue-from.d.ts +4 -3
  65. package/dist/continue-from.d.ts.map +1 -1
  66. package/dist/continue-from.js +62 -26
  67. package/dist/continue-from.js.map +1 -1
  68. package/dist/continuity-notice.d.ts +3 -1
  69. package/dist/continuity-notice.d.ts.map +1 -1
  70. package/dist/continuity-notice.js +3 -1
  71. package/dist/continuity-notice.js.map +1 -1
  72. package/dist/continuity-terminal.d.ts +16 -0
  73. package/dist/continuity-terminal.d.ts.map +1 -1
  74. package/dist/continuity-terminal.js +21 -0
  75. package/dist/continuity-terminal.js.map +1 -1
  76. package/dist/continuity.d.ts +1 -1
  77. package/dist/continuity.d.ts.map +1 -1
  78. package/dist/contract-gates.d.ts.map +1 -1
  79. package/dist/contract-gates.js +11 -6
  80. package/dist/contract-gates.js.map +1 -1
  81. package/dist/credential-cooldown.d.ts +2 -1
  82. package/dist/credential-cooldown.d.ts.map +1 -1
  83. package/dist/credential-cooldown.js +16 -7
  84. package/dist/credential-cooldown.js.map +1 -1
  85. package/dist/credential-preflight.d.ts.map +1 -1
  86. package/dist/credential-preflight.js +10 -7
  87. package/dist/credential-preflight.js.map +1 -1
  88. package/dist/credential-profile-rotation.d.ts +10 -3
  89. package/dist/credential-profile-rotation.d.ts.map +1 -1
  90. package/dist/credential-profile-rotation.js +28 -26
  91. package/dist/credential-profile-rotation.js.map +1 -1
  92. package/dist/deepScanReducer.d.ts +0 -3
  93. package/dist/deepScanReducer.d.ts.map +1 -1
  94. package/dist/deepScanReducer.js +22 -26
  95. package/dist/deepScanReducer.js.map +1 -1
  96. package/dist/delegationFailure.d.ts +105 -15
  97. package/dist/delegationFailure.d.ts.map +1 -1
  98. package/dist/delegationFailure.js +43 -12
  99. package/dist/delegationFailure.js.map +1 -1
  100. package/dist/delegationToolEvidence.d.ts +2 -0
  101. package/dist/delegationToolEvidence.d.ts.map +1 -1
  102. package/dist/delegationToolEvidence.js +21 -0
  103. package/dist/delegationToolEvidence.js.map +1 -1
  104. package/dist/diffReview.d.ts +1 -8
  105. package/dist/diffReview.d.ts.map +1 -1
  106. package/dist/diffReview.js +3 -18
  107. package/dist/diffReview.js.map +1 -1
  108. package/dist/directoryCandidate.d.ts +11 -1
  109. package/dist/directoryCandidate.d.ts.map +1 -1
  110. package/dist/directoryCandidate.js +34 -14
  111. package/dist/directoryCandidate.js.map +1 -1
  112. package/dist/inrun-continuity-carrier.d.ts +11 -1
  113. package/dist/inrun-continuity-carrier.d.ts.map +1 -1
  114. package/dist/inrun-continuity-carrier.js +32 -10
  115. package/dist/inrun-continuity-carrier.js.map +1 -1
  116. package/dist/inrun-continuity-types.d.ts +17 -4
  117. package/dist/inrun-continuity-types.d.ts.map +1 -1
  118. package/dist/inrun-continuity.d.ts +8 -3
  119. package/dist/inrun-continuity.d.ts.map +1 -1
  120. package/dist/inrun-continuity.js +41 -37
  121. package/dist/inrun-continuity.js.map +1 -1
  122. package/dist/inrun-continuity.test-support.d.ts +61 -4
  123. package/dist/inrun-continuity.test-support.d.ts.map +1 -1
  124. package/dist/inrun-continuity.test-support.js +12 -2
  125. package/dist/inrun-continuity.test-support.js.map +1 -1
  126. package/dist/modelGovernance.d.ts +87 -9
  127. package/dist/modelGovernance.d.ts.map +1 -1
  128. package/dist/modelGovernance.js +110 -15
  129. package/dist/modelGovernance.js.map +1 -1
  130. package/dist/orchestrator-credentials.d.ts +9 -4
  131. package/dist/orchestrator-credentials.d.ts.map +1 -1
  132. package/dist/orchestrator-credentials.js +14 -6
  133. package/dist/orchestrator-credentials.js.map +1 -1
  134. package/dist/orchestrator.d.ts +3 -2
  135. package/dist/orchestrator.d.ts.map +1 -1
  136. package/dist/orchestrator.js +298 -277
  137. package/dist/orchestrator.js.map +1 -1
  138. package/dist/planFinalize.d.ts.map +1 -1
  139. package/dist/planFinalize.js +3 -7
  140. package/dist/planFinalize.js.map +1 -1
  141. package/dist/planRun.js +2 -2
  142. package/dist/planRun.js.map +1 -1
  143. package/dist/plannerAttempt.d.ts +0 -2
  144. package/dist/plannerAttempt.d.ts.map +1 -1
  145. package/dist/plannerAttempt.js +64 -30
  146. package/dist/plannerAttempt.js.map +1 -1
  147. package/dist/policyFindings.d.ts +3 -0
  148. package/dist/policyFindings.d.ts.map +1 -1
  149. package/dist/policyFindings.js +11 -1
  150. package/dist/policyFindings.js.map +1 -1
  151. package/dist/pool-attempt-evidence.d.ts +1 -1
  152. package/dist/pool-attempt-evidence.d.ts.map +1 -1
  153. package/dist/pool-attempt-evidence.js +1 -1
  154. package/dist/pool-attempt-evidence.js.map +1 -1
  155. package/dist/primary-divergence.d.ts +7 -2
  156. package/dist/primary-divergence.d.ts.map +1 -1
  157. package/dist/primary-divergence.js +13 -5
  158. package/dist/primary-divergence.js.map +1 -1
  159. package/dist/quota-refusal-scope.d.ts +39 -1
  160. package/dist/quota-refusal-scope.d.ts.map +1 -1
  161. package/dist/quota-refusal-scope.js +95 -1
  162. package/dist/quota-refusal-scope.js.map +1 -1
  163. package/dist/readonlyTerminals.d.ts +0 -1
  164. package/dist/readonlyTerminals.d.ts.map +1 -1
  165. package/dist/readonlyTerminals.js +5 -3
  166. package/dist/readonlyTerminals.js.map +1 -1
  167. package/dist/requestRequirements.d.ts +23 -0
  168. package/dist/requestRequirements.d.ts.map +1 -1
  169. package/dist/requestRequirements.js +22 -0
  170. package/dist/requestRequirements.js.map +1 -1
  171. package/dist/resultNotice.d.ts +14 -0
  172. package/dist/resultNotice.d.ts.map +1 -0
  173. package/dist/resultNotice.js +21 -0
  174. package/dist/resultNotice.js.map +1 -0
  175. package/dist/reviewerInventory.d.ts +47 -0
  176. package/dist/reviewerInventory.d.ts.map +1 -0
  177. package/dist/reviewerInventory.js +74 -0
  178. package/dist/reviewerInventory.js.map +1 -0
  179. package/dist/reviewerPanel.d.ts.map +1 -1
  180. package/dist/reviewerPanel.js +37 -60
  181. package/dist/reviewerPanel.js.map +1 -1
  182. package/dist/routing-failure.d.ts +2 -1
  183. package/dist/routing-failure.d.ts.map +1 -1
  184. package/dist/routing-failure.js +2 -0
  185. package/dist/routing-failure.js.map +1 -1
  186. package/dist/runAdmission.d.ts.map +1 -1
  187. package/dist/runAdmission.js +1 -14
  188. package/dist/runAdmission.js.map +1 -1
  189. package/dist/runEventLog.d.ts +2 -1
  190. package/dist/runEventLog.d.ts.map +1 -1
  191. package/dist/runEventLog.js +5 -3
  192. package/dist/runEventLog.js.map +1 -1
  193. package/dist/runFactsBuilder.d.ts.map +1 -1
  194. package/dist/runFactsBuilder.js +18 -10
  195. package/dist/runFactsBuilder.js.map +1 -1
  196. package/dist/runFactsDeliverable.d.ts.map +1 -1
  197. package/dist/runFactsDeliverable.js +7 -1
  198. package/dist/runFactsDeliverable.js.map +1 -1
  199. package/dist/runSupport.d.ts +5 -10
  200. package/dist/runSupport.d.ts.map +1 -1
  201. package/dist/runSupport.js +38 -40
  202. package/dist/runSupport.js.map +1 -1
  203. package/dist/runTerminalResults.d.ts +9 -1
  204. package/dist/runTerminalResults.d.ts.map +1 -1
  205. package/dist/runTerminalResults.js +27 -5
  206. package/dist/runTerminalResults.js.map +1 -1
  207. package/dist/runTerminals.d.ts.map +1 -1
  208. package/dist/runTerminals.js +6 -3
  209. package/dist/runTerminals.js.map +1 -1
  210. package/dist/savedCandidate.d.ts +43 -0
  211. package/dist/savedCandidate.d.ts.map +1 -0
  212. package/dist/savedCandidate.js +88 -0
  213. package/dist/savedCandidate.js.map +1 -0
  214. package/dist/secretDiff.d.ts +85 -46
  215. package/dist/secretDiff.d.ts.map +1 -1
  216. package/dist/secretDiff.js +123 -126
  217. package/dist/secretDiff.js.map +1 -1
  218. package/dist/task-contract-builder.d.ts.map +1 -1
  219. package/dist/task-contract-builder.js +5 -7
  220. package/dist/task-contract-builder.js.map +1 -1
  221. package/dist/workReportEnvelope.d.ts.map +1 -1
  222. package/dist/workReportEnvelope.js +4 -16
  223. package/dist/workReportEnvelope.js.map +1 -1
  224. package/package.json +17 -17
  225. package/dist/persistedPatch.d.ts +0 -55
  226. package/dist/persistedPatch.d.ts.map +0 -1
  227. package/dist/persistedPatch.js +0 -132
  228. package/dist/persistedPatch.js.map +0 -1
@@ -6,23 +6,23 @@ import { requestRefusalFailure } from "./runTerminalResults.js";
6
6
  import { openRunScopeCustody, scopedRouteContext, scopedSpecEnv, } from "./runScope.js";
7
7
  import { delegationBeltFor } from "./delegationBelt.js";
8
8
  import { routePromptCacheTtl, withReviewerPromptCacheTtl } from "./prompt-cache-routing.js";
9
- import { bindProcessingAdmission, processingAttemptCostEvidence, processingAdmissionForLease, updateProcessingStreamHold, ProcessingBudgetAdmissionError, } from "./processing-dispatch.js";
9
+ import { bindProcessingAdmission, processingAttemptCostEvidence, processingAdmissionForLease, updateProcessingStreamHold, } from "./processing-dispatch.js";
10
10
  import { cancelledCandidatesResult, emptyCandidateResult, failedCandidatesResult, failAfterCandidates, } from "./candidateTerminals.js";
11
11
  import { deepScanFailureResult, readOnlyChainFailureResult, } from "./readonlyTerminals.js";
12
12
  import { effectiveAuthPreference, observeNativeSessionEvent, resumeSessionForProfile, } from "./credential-profiles.js";
13
13
  import { AdmissionProfileProbes, OrchestratorCredentials, reviewerProfileResolver, } from "./orchestrator-credentials.js";
14
- import { continuityWorkspace, resumableOf, resumableTerminal, } from "./continuity-terminal.js";
14
+ import { continuityWorkspace, carryingAttempts, resumableOf, resumableTerminal, } from "./continuity-terminal.js";
15
15
  import { openContinuity } from "./continue-from.js";
16
16
  import { accountPoolRows } from "./account-pool.js";
17
17
  import { PoolAttemptEvidence, terminalPoolAttempts, withPoolAttempts, } from "./pool-attempt-evidence.js";
18
18
  import { writeRunTelemetryArtifact } from "./runTelemetryWriter.js";
19
19
  import { buildFileBackedSynthesisInput, materializeWinnerOutputs, stageFileBackedContext, writeCandidateAttemptArtifacts, } from "./candidateOutputs.js";
20
20
  import { processAttemptUsage } from "./attemptUsage.js";
21
- import { captureDirectoryCandidate, directoryHasOutput, directoryCandidateStable, observeDirectoryPaths, publishDirectoryCandidate, } from "./directoryCandidate.js";
21
+ import { captureDirectoryCandidate, directoryPreparationNotice, directoryHasOutput, directoryCandidateStable, observeDirectoryPaths, publishDirectoryCandidate, } from "./directoryCandidate.js";
22
22
  import { appliedAttemptFacts, assertDelegatedEvidence, isMutatingAccess, outerBoundaryNotice, scopedHarnessHome, selectLaneHome, followSpecHome, } from "./delegatedHome.js";
23
23
  import * as AC from "./attemptUsageCost.js";
24
24
  import * as custody from "./continuation-custody.js";
25
- import { candidateRoster, candidateStatuses, convergenceOutcomeFacts, isWorkingCandidate, partitionCandidates, toCandidateEvidence, } from "./candidateEvidence.js";
25
+ import { candidateCaptureRefusals, candidateCompletion, candidateRoster, candidateStatuses, convergenceOutcomeFacts, isWorkingCandidate, partitionCandidates, toCandidateEvidence, } from "./candidateEvidence.js";
26
26
  import { capabilityIntents } from "@claudexor/gateway";
27
27
  import { reviewCandidateRuns, unreviewedCandidateEvidence, evaluateUnreviewedConvergence, } from "./candidateReview.js";
28
28
  import { join } from "node:path";
@@ -33,8 +33,8 @@ import { globalConfigDir } from "@claudexor/config";
33
33
  import { executionRunConfig } from "./run-defaults.js";
34
34
  import { preflightOneShot } from "./one-shot-preflight.js";
35
35
  import { prepareRoutedProcessing, processingCostEvidence, prepareReviewerProcessing, } from "./processing-routing.js";
36
- import { acceptedTryOutput, AccessProfileIncompatibleError, AuxiliaryWritableRootsUnsupportedError, CLAUDEXOR_BROWSER_ARTIFACT_SUBDIR, countsAsAgentProgress, HarnessUnavailableError, summarizeDiffPaths as diffStats, withInactivityWatchdog, } from "@claudexor/core";
37
- import { assertRouteModelsAllowed, runModelGovernedRoute } from "./modelGovernance.js";
36
+ import { acceptedTryOutput, AccessProfileIncompatibleError, AnswerAssembly, appendHarnessEvent, AuxiliaryWritableRootsUnsupportedError, CLAUDEXOR_BROWSER_ARTIFACT_SUBDIR, countsAsAgentProgress, HarnessUnavailableError, withInactivityWatchdog, } from "@claudexor/core";
37
+ import { assertRouteModelsAllowed, isDispatchRefusal, runModelGovernedRoute, } from "./modelGovernance.js";
38
38
  import { authModeForCredentialRoute, authModeForPreference, authRouteEvidenceFor, } from "./auth-route-classification.js";
39
39
  import { isFullAccess, RequestRequirementsResolver } from "./requestRequirements.js";
40
40
  import { activateDelegationParent } from "./delegation-parent-activation.js";
@@ -51,7 +51,7 @@ import { budgetFailureRecord, classifyBudgetFailure } from "./budgetFailure.js";
51
51
  import { finalizeStructuredOutput } from "./structuredOutput.js";
52
52
  import { prepareRunAdmission } from "./runAdmission.js";
53
53
  import { dropDeltaPastBudget, emitPlanProgress, emitTransientExhausted, observeReadonlySpend, recordAdapterThrow, } from "./laneStreamEvents.js";
54
- import { promptWithEngineConstraints, sleep, redactHarnessEvent, harnessEventPayload, safeErrorMessage, renderSummary, observeBudgetSignals, rotateOnStall, recordCleanAttemptMetrics, envInheritance, transientRetryPolicy, reviewerTimeoutMs, harnessInactivityTimeoutMs, observeAuthSwitch, emitPoolDegraded, deliveryRefusalFailure, winnerNeedsHuman, writeRaceDeliveryDecision, } from "./runSupport.js";
54
+ import { promptWithEngineConstraints, sleep, harnessEventPayload, safeErrorMessage, renderSummary, observeBudgetSignals, rotateOnStall, recordCleanAttemptMetrics, envInheritance, transientRetryPolicy, reviewerTimeoutMs, harnessInactivityTimeoutMs, observeAuthSwitch, emitPoolDegraded, deliveryRefusalFailure, winnerNeedsHuman, writeRaceDeliveryDecision, } from "./runSupport.js";
55
55
  import { candidateStatusInRouteContext, resolveReadOnlyRouteContext, } from "./routeContext.js";
56
56
  import { resolveAutoReviewerPanel, resolveExplicitReviewerPanel } from "./reviewerPanel.js";
57
57
  import { ensureClaudeBridgeForRun, ensureWriteModeGitBoundary } from "./git-precondition.js";
@@ -72,16 +72,17 @@ import { finalVerifyRun, gateSpecsFromContract, renderTestsEvidence } from "./co
72
72
  import { buildTaskContract } from "./task-contract-builder.js";
73
73
  import { recordProcessingIntent } from "./retry-processing-intent.js";
74
74
  import { prepareReviewEvidenceDir, recordReviewEvidenceCleanup } from "./reviewEvidence.js";
75
+ import { savedForSynthesis } from "./savedCandidate.js";
75
76
  import { ArtifactStore } from "@claudexor/artifact-store";
76
- import { buildContextPack, rawContextForEnvelope, writeEvidencePacket } from "@claudexor/context";
77
- import { WorkspaceManager, captureRawPatchEnvelope, createRevertAnchorFromPatchOrNull, createRevertAnchorOrNull, consumeRawPatchEnvelope, snapshotTree, } from "@claudexor/workspace";
77
+ import { buildContextPack, rawContextSizer, writeEvidencePacket } from "@claudexor/context";
78
+ import { WorkspaceManager, captureRawPatchEnvelope, consumeRawPatchEnvelope, snapshotTree, } from "@claudexor/workspace";
78
79
  import { blockedDecisionOverride, finalVerifyBlocks, verifyAndDeliverFiles, verifyAndDeliver, } from "@claudexor/delivery";
79
80
  import { HarnessGateway } from "@claudexor/gateway";
80
81
  import { ReadinessLedger, evaluateConvergence, failureSignature, gatesPassed, reviewCandidate, runGates, } from "@claudexor/review";
81
82
  import { arbitrate } from "@claudexor/arbitration";
82
83
  import { buildSynthesisPlan, decideSynthesis } from "@claudexor/synthesis";
83
- import { billingKnowledgeForAuthRoute, attemptUsageCostSettlement, BudgetLedger, isBudgetTerminal, RoutingPreflightError, explainRanking, loadHarnessMetrics, promptFingerprint, rankHarnesses, } from "@claudexor/budget";
84
- import { readTextSafe, appendLine, hashJson, newId, noProjectRepoRoot, redactSecrets, safeInvoke, sha256, userConfigDir, } from "@claudexor/util";
84
+ import { billingKnowledgeForAuthRoute, attemptUsageCostSettlement, BudgetLedger, isBudgetTerminal, explainRanking, loadHarnessMetrics, promptFingerprint, rankHarnesses, } from "@claudexor/budget";
85
+ import { readTextSafe, hashJson, newId, noProjectRepoRoot, redactSecrets, safeInvoke, userConfigDir, } from "@claudexor/util";
85
86
  const LABELS = "ABCDEFGHIJ".split("");
86
87
  const NO_PROJECT_ROOT = noProjectRepoRoot();
87
88
  export class Orchestrator {
@@ -188,20 +189,24 @@ export class Orchestrator {
188
189
  await custody.settleUnannounced();
189
190
  }
190
191
  }
191
- async resolveReviewers(cwd, runAuthPreference, onIgnoredSetting) {
192
+ async resolveReviewers(run, onIgnoredSetting) {
192
193
  if (this.deps.reviewers)
193
194
  return this.deps.reviewers;
194
- if (this.deps.reviewerPanel && this.deps.reviewerPanel.length > 0) {
195
- return this.resolveExplicitReviewerPanel(cwd, this.deps.reviewerPanel, runAuthPreference, onIgnoredSetting);
196
- }
197
- return resolveAutoReviewerPanel({
195
+ const { repoRoot: cwd, authPreference, signal } = run;
196
+ const panelDeps = {
198
197
  cwd,
199
198
  registry: this.deps.registry,
200
199
  harnessSettings: this.config(cwd)?.global.harnesses ?? {},
201
- authPreferenceFor: (id) => this.authPreferenceForHarness(cwd, id, runAuthPreference),
202
- resolveReviewerProfile: reviewerProfileResolver(this.credentials, cwd),
200
+ authPreferenceFor: (id) => this.authPreferenceForHarness(cwd, id, authPreference),
201
+ resolveReviewerProfile: reviewerProfileResolver(this.credentials, cwd, signal),
203
202
  onIgnoredSetting,
204
- }, { reviewerModels: this.deps.reviewerModels, reviewerEfforts: this.deps.reviewerEfforts });
203
+ };
204
+ if (this.deps.reviewerPanel && this.deps.reviewerPanel.length > 0)
205
+ return resolveExplicitReviewerPanel(panelDeps, this.deps.reviewerPanel);
206
+ return resolveAutoReviewerPanel(panelDeps, {
207
+ reviewerModels: this.deps.reviewerModels,
208
+ reviewerEfforts: this.deps.reviewerEfforts,
209
+ });
205
210
  }
206
211
  /**
207
212
  * Resolve reviewers INSIDE a strategy, after run-dir creation: an explicit
@@ -217,7 +222,7 @@ export class Orchestrator {
217
222
  // Reviewer knobs a panel omitted or dropped → ignored-settings channel (QA-070):
218
223
  const warn = (d) => void log.emit("review.preflight", { ignored_settings: [d] });
219
224
  const config = this.config(input.repoRoot).global;
220
- const reviewers = await this.resolveReviewers(input.repoRoot, input.authPreference, warn);
225
+ const reviewers = await this.resolveReviewers(input, warn);
221
226
  return {
222
227
  reviewers: await prepareReviewerProcessing(withReviewerPromptCacheTtl(reviewers, input.promptCacheTtl, warn), input, config, input.paidBudget ?? this.deps.paidBudget ?? config.budget.paid_budget_per_run),
223
228
  };
@@ -256,16 +261,6 @@ export class Orchestrator {
256
261
  };
257
262
  }
258
263
  }
259
- async resolveExplicitReviewerPanel(cwd, panel, runAuthPreference, onIgnoredSetting) {
260
- return resolveExplicitReviewerPanel({
261
- cwd,
262
- registry: this.deps.registry,
263
- harnessSettings: this.config(cwd)?.global.harnesses ?? {},
264
- authPreferenceFor: (id) => this.authPreferenceForHarness(cwd, id, runAuthPreference),
265
- resolveReviewerProfile: reviewerProfileResolver(this.credentials, cwd),
266
- onIgnoredSetting,
267
- }, panel);
268
- }
269
264
  authPreferenceForHarness(repoRoot, harnessId, runAuthPreference) {
270
265
  const cfg = this.config(repoRoot)?.global;
271
266
  return effectiveAuthPreference(runAuthPreference, cfg?.harnesses?.[harnessId]?.auth_preference, cfg?.routing?.auth_preference);
@@ -587,6 +582,11 @@ export class Orchestrator {
587
582
  dropLane(id, "access", `${id} (cannot apply execution.auxiliaryWritableRoots under ${requiredAccess})`);
588
583
  continue;
589
584
  }
585
+ const readRefusal = this.requestRequirements.projectReadRefusal(intent, input, status);
586
+ if (readRefusal) {
587
+ dropLane(id, "capability", readRefusal);
588
+ continue;
589
+ }
590
590
  const reason = status.reasons.length > 0 ? `: ${status.reasons.join("; ")}` : "";
591
591
  if (status.enabledIntents.includes(intent) && accessSupported) {
592
592
  pool.push({
@@ -720,7 +720,7 @@ export class Orchestrator {
720
720
  throw primaryQuotaRefusal.error;
721
721
  throw new HarnessUnavailableError(`no harness remains eligible for '${intent}' after budget and quota routing`);
722
722
  }
723
- emitPrimaryDivergence(log, input.primaryHarness, ordered, pool, dropped, browserOmissions);
723
+ emitPrimaryDivergence(log, input.primaryHarness, ordered, pool, dropped, browserOmissions, statusById);
724
724
  const n = input.n ?? ordered.length;
725
725
  const selectionOrder = ordered;
726
726
  const out = [];
@@ -1262,13 +1262,13 @@ export class Orchestrator {
1262
1262
  const inPlaceEnvelope = envelope.worktree_path === envelope.repo_root;
1263
1263
  const directory = envelope.workspace_kind === "directory";
1264
1264
  let directoryCapture = {};
1265
- const captureDirectory = async () => (directoryCapture = await captureDirectoryCandidate({
1265
+ const captureDirectory = async (final = false) => (directoryCapture = await captureDirectoryCandidate({
1266
1266
  manager: wsm,
1267
1267
  envelope,
1268
1268
  artifactRoot: join(paths.attemptsDir, attemptId),
1269
1269
  observedPaths: [...observedPaths],
1270
+ ...(final ? { holder: { runId: paths.runId, runDir: paths.root } } : {}),
1270
1271
  }));
1271
- const rawContextPacket = await rawContextForEnvelope(routed.implementationTransport, envelope);
1272
1272
  const sessionFields = runInput
1273
1273
  ? await this.sessionSpecFields(runInput, adapter.id, knobs.model, log, routed.authRouteEstimate, routed.quotaAdmission)
1274
1274
  : undefined;
@@ -1305,6 +1305,7 @@ export class Orchestrator {
1305
1305
  [
1306
1306
  prompt,
1307
1307
  outerBoundaryNotice(harnessHome, routed.auxiliaryWritableRoots),
1308
+ await directoryPreparationNotice(envelope, attemptId, log),
1308
1309
  laneContinuity?.pointerLine,
1309
1310
  continuationPointer,
1310
1311
  ]
@@ -1334,11 +1335,20 @@ export class Orchestrator {
1334
1335
  ? { resume_session_id: sessionFields.resume_session_id }
1335
1336
  : {}),
1336
1337
  ...(scopedEnv ? { env: scopedEnv } : {}),
1337
- raw_context_packet: rawContextPacket,
1338
1338
  stream_deltas: streamDeltas,
1339
1339
  });
1340
1340
  if (runInput)
1341
1341
  this.credentials.stampProfileSelection(spec, runInput, adapter.id);
1342
+ // #147: bound to the project's context config; each try's dispatch sizes its own
1343
+ // packet for THIS request from the catalog read the gate makes for that try.
1344
+ const { context } = this.projectConfig(contract.repo.root);
1345
+ const sizeRawContext = rawContextSizer(routed.implementationTransport, envelope, context);
1346
+ let rawContextPacket = null;
1347
+ const dispatch = sizeRawContext
1348
+ ? {
1349
+ rawContext: async (capacity) => (rawContextPacket = await sizeRawContext(capacity)),
1350
+ }
1351
+ : {};
1342
1352
  bindProcessingAdmission(spec, ledger, processingLease.lease, adapter.id, attemptId, processingLease.onDenied, processingAdmission);
1343
1353
  // Profile-less processing keeps its existing route estimate. Named rows
1344
1354
  // receive their own verification at the shared physical-dispatch gate.
@@ -1369,7 +1379,7 @@ export class Orchestrator {
1369
1379
  // QA-024: emit the belt-failure disclosure event at most once per attempt.
1370
1380
  let beltFailureDisclosed = false;
1371
1381
  const errors = [];
1372
- let answer = new secretDiff.CountedAnswerAssembly();
1382
+ let answer = new AnswerAssembly();
1373
1383
  let currentCapture;
1374
1384
  const retryPolicy = transientRetryPolicy(this.config(contract.repo.root));
1375
1385
  // QA-024: the delegation belt is the ONLY engine-owned extra MCP server
@@ -1398,13 +1408,15 @@ export class Orchestrator {
1398
1408
  workOrder: prompt,
1399
1409
  firstPrompt: spec.prompt,
1400
1410
  poolEvidence,
1411
+ later: continuationPointer ? "checkpoint" : undefined, // repair/synthesis never re-plan
1412
+ explicitModel: modelHint !== undefined,
1401
1413
  }), { spec, continuation: runInput?.continuation, store, telemetry }));
1402
1414
  try {
1403
1415
  for (let nativeTry = 0; !signal?.aborted; nativeTry += 1) {
1404
1416
  currentCapture = undefined;
1405
1417
  // A3 per-try isolation: no output, progress marker or model proof crosses tries.
1406
1418
  if (nativeTry > 0) {
1407
- answer = new secretDiff.CountedAnswerAssembly();
1419
+ answer = new AnswerAssembly();
1408
1420
  beginNativeRetry(telemetry);
1409
1421
  }
1410
1422
  const clearFileBackedContext = stageFileBackedContext(envelope.worktree_path, fileBackedContext);
@@ -1422,8 +1434,9 @@ export class Orchestrator {
1422
1434
  const transientStart = telemetry.transientFailures.length;
1423
1435
  const rateLimitStart = telemetry.rateLimits.length;
1424
1436
  let rawPatch = null;
1437
+ rawContextPacket = null; // a patch binds only the packet its own try sent
1425
1438
  try {
1426
- const watched = withInactivityWatchdog(runModelGovernedRoute(routed, runSpec), {
1439
+ const watched = withInactivityWatchdog(runModelGovernedRoute(routed, runSpec, dispatch), {
1427
1440
  timeoutMs: inactivityMs,
1428
1441
  countsAsProgress: countsAsAgentProgress,
1429
1442
  onTimeout: () => {
@@ -1435,31 +1448,34 @@ export class Orchestrator {
1435
1448
  // terminal/restart when the timeout is disabled.
1436
1449
  isSuspended: () => (interaction?.pendingCount?.() ?? 0) > 0,
1437
1450
  suspensionVersion: () => interaction?.suspensionVersion?.() ?? 0,
1451
+ stopSignal: signal, // after Stop: drained events are recorded, never used
1438
1452
  });
1439
1453
  for await (const ev of watched) {
1440
- rawPatch = captureRawPatchEnvelope(rawContextPacket !== null, rawPatch, ev);
1454
+ // After Stop: stored evidence only, but file paths are still collected for the capture.
1455
+ const stopped = signal?.aborted === true;
1456
+ if (!stopped)
1457
+ rawPatch = captureRawPatchEnvelope(sizeRawContext !== null, rawPatch, ev);
1441
1458
  if (ev.type === "patch_produced")
1442
1459
  continue;
1443
- const safeEv = redactHarnessEvent(ev);
1444
1460
  if (directory)
1445
- observeDirectoryPaths(observedPaths, safeEv, envelope.worktree_path);
1446
- const capped = dropDeltaPastBudget(safeEv, deltaFlood, Orchestrator.MAX_DELTAS_PER_ATTEMPT, (t, p) => log?.emit(t, p), adapter.id, attemptId);
1447
- const display = !capped && safeEv.payload?.["buffered"] !== true;
1448
- log?.emit("harness.event", harnessEventPayload(adapter.id, attemptId, safeEv), display);
1461
+ observeDirectoryPaths(observedPaths, ev, envelope.worktree_path);
1462
+ const capped = dropDeltaPastBudget(ev, deltaFlood, Orchestrator.MAX_DELTAS_PER_ATTEMPT, (t, p) => log?.emit(t, p), adapter.id, attemptId);
1463
+ const display = !stopped && !capped && ev.payload?.["buffered"] !== true;
1464
+ log?.emit("harness.event", harnessEventPayload(adapter.id, attemptId, ev), display);
1449
1465
  if (signal?.aborted)
1450
- break;
1466
+ continue; // a live observer may itself have pressed Stop
1451
1467
  if (display)
1452
- safeInvoke(onHarnessEvent, safeEv);
1453
- observeAuthSwitch(log, adapter.id, attemptId, safeEv);
1454
- observeAttemptTelemetry(telemetry, safeEv);
1455
- const mismatch = continuity.observe(safeEv, runSpec, telemetry.outputMarkers);
1468
+ safeInvoke(onHarnessEvent, ev);
1469
+ observeAuthSwitch(log, adapter.id, attemptId, ev);
1470
+ observeAttemptTelemetry(telemetry, ev);
1471
+ const mismatch = continuity.observe(ev, runSpec, telemetry.outputMarkers);
1456
1472
  if (mismatch) {
1457
1473
  harnessErrored = true;
1458
1474
  errors.push(mismatch);
1459
1475
  break;
1460
1476
  }
1461
1477
  if (inPlaceEnvelope && continuity.mayPublishSession)
1462
- observeNativeSessionEvent(runInput, adapter.id, safeEv);
1478
+ observeNativeSessionEvent(runInput, adapter.id, ev);
1463
1479
  // QA-024: the injected delegation belt's MCP server reported a
1464
1480
  // terminal startup failure. Disclose it ONCE while live; recoverable
1465
1481
  // exact tool-result failures are evaluated at attempt finalization.
@@ -1476,10 +1492,10 @@ export class Orchestrator {
1476
1492
  reason: "mcp_server_failed_to_start",
1477
1493
  });
1478
1494
  }
1479
- emitPlanProgress((t, p) => log?.emit(t, p), adapter.id, attemptId, safeEv);
1480
- if (safeEv.type === "usage") {
1495
+ emitPlanProgress((t, p) => log?.emit(t, p), adapter.id, attemptId, ev);
1496
+ if (ev.type === "usage") {
1481
1497
  const usage = processAttemptUsage({
1482
- event: safeEv,
1498
+ event: ev,
1483
1499
  telemetry,
1484
1500
  harnessId: adapter.id,
1485
1501
  attemptId,
@@ -1497,19 +1513,19 @@ export class Orchestrator {
1497
1513
  break;
1498
1514
  }
1499
1515
  }
1500
- if (safeEv.type === "error") {
1516
+ if (ev.type === "error") {
1501
1517
  harnessErrored = true;
1502
- errors.push(redactSecrets(safeEv.error ?? safeEv.text ?? "harness emitted error"));
1518
+ errors.push(redactSecrets(ev.error ?? ev.text ?? "harness emitted error"));
1503
1519
  }
1504
1520
  // Capture assistant prose so an answer-only turn (no file changes) still
1505
1521
  // has an honest output artifact; a TYPED final message wins verbatim.
1506
- answer.observeCounted(ev, safeEv);
1522
+ answer.observe(ev);
1507
1523
  // Observe ALL budget/quota signals (one codex usage event carries
1508
1524
  // BOTH spend and quota); pressure disclosed once per attempt.
1509
- observeBudgetSignals(ledger, log, adapter.id, attemptId, safeEv, budgetSignalState);
1510
- this.deps.quotaEventSink?.(adapter.id, safeEv);
1525
+ observeBudgetSignals(ledger, log, adapter.id, attemptId, ev, budgetSignalState);
1526
+ this.deps.quotaEventSink?.(adapter.id, ev);
1511
1527
  }
1512
- if (rawContextPacket && !harnessErrored)
1528
+ if (sizeRawContext && !harnessErrored)
1513
1529
  await consumeRawPatchEnvelope({
1514
1530
  repoRoot: envelope.repo_root,
1515
1531
  worktreePath: envelope.worktree_path,
@@ -1525,8 +1541,7 @@ export class Orchestrator {
1525
1541
  // gate and required-actions read a typed category, not a bare boolean.
1526
1542
  harnessErrored = true;
1527
1543
  errors.push(safeErrorMessage(err));
1528
- if (err instanceof ProcessingBudgetAdmissionError ||
1529
- err instanceof RoutingPreflightError) {
1544
+ if (isDispatchRefusal(err)) {
1530
1545
  processingRefusal = err;
1531
1546
  break;
1532
1547
  }
@@ -1557,11 +1572,11 @@ export class Orchestrator {
1557
1572
  await captureDirectory();
1558
1573
  currentCapture = directory
1559
1574
  ? undefined
1560
- : await secretDiff.captureCandidateDiff(wsm, envelope);
1575
+ : await secretDiff.captureCandidateDiff(wsm, envelope, paths.root);
1561
1576
  const currentDiff = secretDiff.capturedDiff(currentCapture);
1562
1577
  const workspaceUnchanged = directory
1563
1578
  ? !isMutatingAccess(access) || directoryCapture.files?.noChanges === true
1564
- : currentDiff?.trim().length === 0;
1579
+ : secretDiff.captureUnchanged(currentCapture);
1565
1580
  const deliverableEmpty = workspaceUnchanged && answer.text().length === 0;
1566
1581
  const delivered = !harnessErrored && !deliverableEmpty && !signal?.aborted;
1567
1582
  this.credentials.noteTryServed(refusal, telemetry.outputMarkers, delivered);
@@ -1617,21 +1632,20 @@ export class Orchestrator {
1617
1632
  // D-16: answer.md persists only the deliverable. A3: an errored attempt
1618
1633
  // with no typed final contributes no answer material (acceptedTryOutput).
1619
1634
  const unwrapped = unwrapWorkReportEnvelope(acceptedTryOutput(answer, harnessErrored), workReportMode, { sideToolReport: telemetry.sideToolWorkReport ?? undefined });
1620
- const redacted = redactSecrets(unwrapped.deliverable);
1621
- // INV-062: the (already redacted) answer is kept whatever the patch holds.
1622
- const answerText = redacted.trim().length > 0 ? redacted : undefined;
1635
+ const answerText = unwrapped.deliverable.trim().length > 0 ? unwrapped.deliverable : undefined;
1623
1636
  if (directory)
1624
- await captureDirectory();
1637
+ await captureDirectory(true);
1625
1638
  const captured = directory
1626
1639
  ? { diff: "", captureRefusal: directoryCapture.refusal }
1627
1640
  : await secretDiff.captureCandidateWorkspace({
1628
- ...{ wsm, envelope, inPlace: inPlaceEnvelope, projectRoot: store.repoRoot },
1629
- ...{ answerText, answerMatches: answer.secretLikeMatches() },
1641
+ ...{ wsm, envelope, inPlace: inPlaceEnvelope, contract },
1630
1642
  holder: { runId: paths.runId, runDir: paths.root },
1631
1643
  incompleteCapture: currentCapture?.captureIncomplete ? currentCapture : undefined,
1632
1644
  });
1633
- const { diff, captureRefusal } = captured;
1634
- const deliverableEvidence = diff.trim().length > 0 || Boolean(answerText) || directoryHasOutput(directoryCapture.files);
1645
+ const { captureRefusal } = captured;
1646
+ const deliverableEvidence = secretDiff.hasCandidateChanges(captured) ||
1647
+ Boolean(answerText) ||
1648
+ directoryHasOutput(directoryCapture.files);
1635
1649
  // Cancelled attempts skip gates: running a 600s-per-gate suite delays the ack
1636
1650
  // and burns compute on a result nobody will adopt. Diff/attempt.yaml
1637
1651
  // still land, so partial work stays inspectable.
@@ -1694,7 +1708,7 @@ export class Orchestrator {
1694
1708
  const errored = harnessErrored || webBlocked || captureRefusal !== undefined;
1695
1709
  const resumable = await continuity.finish({
1696
1710
  runSpec: spec,
1697
- errored,
1711
+ errored: harnessErrored || webBlocked, // a capture refusal is packaging, not work
1698
1712
  nonSuccess: !gatesPassed(gates),
1699
1713
  aborted: signal?.aborted === true,
1700
1714
  cancelReason: typeof signal?.reason === "string" ? signal.reason : null,
@@ -1716,14 +1730,14 @@ export class Orchestrator {
1716
1730
  aborted: signal?.aborted === true,
1717
1731
  authMode: telemetry.authMode,
1718
1732
  });
1719
- const producedFiles = AC.withAttemptFailureCost(() => writeCandidateAttemptArtifacts({
1733
+ const { produced: producedFiles, omitted: producedOmitted } = AC.withAttemptFailureCost(() => writeCandidateAttemptArtifacts({
1720
1734
  store,
1721
1735
  attemptDir,
1722
1736
  worktreePath: envelope.worktree_path,
1723
1737
  artifactRelativeDir,
1724
- ...{ diff, persistedDiff: captured.persistedDiff },
1738
+ ...secretDiff.attemptPatchInput(captured),
1725
1739
  persistPatch: !directory && captureRefusal === undefined && isMutatingAccess(access),
1726
- persistProducedMedia: !directory && captureRefusal === undefined,
1740
+ persistProducedMedia: !directory,
1727
1741
  answerText,
1728
1742
  record: {
1729
1743
  attempt_id: attemptId,
@@ -1773,6 +1787,7 @@ export class Orchestrator {
1773
1787
  reviewCwd: envelope.worktree_path,
1774
1788
  baseSha: envelope.base_sha ?? undefined,
1775
1789
  producedFiles,
1790
+ ...(producedOmitted.length ? { producedOmitted } : {}),
1776
1791
  gates,
1777
1792
  cost,
1778
1793
  errored,
@@ -1787,7 +1802,7 @@ export class Orchestrator {
1787
1802
  : {}),
1788
1803
  outcomeClass: finalized.outcomeClass,
1789
1804
  applied,
1790
- ...continuity.terminalFacts(resumable),
1805
+ ...continuity.terminalFacts(resumable, captureRefusal !== undefined),
1791
1806
  };
1792
1807
  }
1793
1808
  continuityDeps(adapter, routed, contract, attemptId, paths, runInput, log, lane) {
@@ -1803,9 +1818,11 @@ export class Orchestrator {
1803
1818
  workspace: continuityWorkspace(lane.envelope, cwd),
1804
1819
  workOrder: lane.workOrder,
1805
1820
  firstPrompt: lane.firstPrompt,
1821
+ later: lane.later,
1822
+ explicitModel: lane.explicitModel,
1806
1823
  registry: this.config(repoRoot)?.global.credential_profiles ?? [],
1807
1824
  policy: this.credentials.profilePolicy(repoRoot, adapter.id),
1808
- snapshots: this.deps.quotaSnapshots?.() ?? [],
1825
+ quotaSnapshots: () => this.deps.quotaSnapshots?.() ?? [],
1809
1826
  retryPolicy: transientRetryPolicy(this.config(repoRoot)),
1810
1827
  pinned: runInput?.credentialProfileId != null, // D-U6: a pin never rotates
1811
1828
  defaultRouteWasVendorNative: routed.authRouteEstimate === "local_session",
@@ -1860,7 +1877,9 @@ export class Orchestrator {
1860
1877
  // repoRoot. Both the WorkspaceManager and the git boundary resolve against
1861
1878
  // this SINGLE root.
1862
1879
  const execRoot = this.execRootOf(input);
1863
- const wsm = new WorkspaceManager(execRoot);
1880
+ const projectRoot = input.repoRoot;
1881
+ const wsm = new WorkspaceManager(execRoot, { projectRoot });
1882
+ const anchors = secretDiff.revertAnchors(execRoot, projectRoot);
1864
1883
  store.writeYaml(join(paths.contextDir, "task.yaml"), contract);
1865
1884
  log.emit("task.contract.created", { task_contract_hash: hashJson(contract) });
1866
1885
  // Write modes need a git boundary for worktree isolation and honest diffs.
@@ -1908,7 +1927,7 @@ export class Orchestrator {
1908
1927
  const reviewDir = join(paths.root, "review-evidence");
1909
1928
  if (contract.review_requested !== false)
1910
1929
  writeEvidencePacket(reviewDir, {
1911
- userIntent: redactSecrets(input.prompt),
1930
+ userIntent: input.prompt,
1912
1931
  diff: "(per-candidate diffs are supplied to reviewers individually)\n",
1913
1932
  tests: renderTestsEvidence(contract),
1914
1933
  });
@@ -2091,17 +2110,7 @@ export class Orchestrator {
2091
2110
  }, input, requestedSingleCandidate, // W-C4 deltas: single-candidate chat lane only (racing = noise x N)
2092
2111
  undefined, undefined, harnessHome, undefined, tried);
2093
2112
  ledger.settle(slot.lease.lease_id, attemptUsageCostSettlement(run.cost, run.costEstimated, run.attemptId, run.harnessId, run.telemetry.authMode, run.telemetry.usageCost));
2094
- log.emit("harness.completed", {
2095
- harness_id: adapter.id,
2096
- attempt_id: slot.attemptId,
2097
- // QA-027: never claim `success` over an attempt the operator/deadline
2098
- // cut short. An abort makes the run non-successful; the top-level
2099
- // status axis must say `cancelled` (the nested outcome axis already
2100
- // rides in telemetrySummary), not launder a torn-off stream as clean.
2101
- status: input.signal?.aborted ? "cancelled" : run.errored ? "failed" : "success",
2102
- cost_usd: run.cost,
2103
- ...telemetrySummary(run.telemetry),
2104
- });
2113
+ log.emit("harness.completed", candidateCompletion(run, input.signal));
2105
2114
  // D-16d one-shot continuation for an ENVELOPED candidate (parity with the
2106
2115
  // read-only loop, which had the ONLY continuation wiring). An eligible
2107
2116
  // terminal context exhaustion (repeated_refill, no completed report) gets
@@ -2125,7 +2134,7 @@ export class Orchestrator {
2125
2134
  harness: adapter.id,
2126
2135
  profileId: input.credentialProfileId ?? null,
2127
2136
  priorPrompt: input.prompt,
2128
- priorOutput: run.answerText ?? run.persistedDiff ?? run.diff ?? "",
2137
+ priorOutput: run.answerText ?? run.diff ?? "",
2129
2138
  }));
2130
2139
  // Reserve the continuation lease BEFORE any disclosure: a denied lease
2131
2140
  // must never emit run.continuation (which claims a continuation
@@ -2170,21 +2179,18 @@ export class Orchestrator {
2170
2179
  return true;
2171
2180
  }, input, requestedSingleCandidate, undefined, packet.pointerLine ?? undefined, harnessHome, undefined, contTried);
2172
2181
  ledger.settle(contLeaseId, attemptUsageCostSettlement(contRun.cost, contRun.costEstimated, contRun.attemptId, contRun.harnessId, contRun.telemetry.authMode, contRun.telemetry.usageCost));
2173
- log.emit("harness.completed", {
2174
- harness_id: adapter.id,
2175
- attempt_id: contAttemptId,
2176
- status: input.signal?.aborted
2177
- ? "cancelled"
2178
- : contRun.errored
2179
- ? "failed"
2180
- : "success",
2181
- cost_usd: contRun.cost,
2182
- ...telemetrySummary(contRun.telemetry),
2183
- });
2182
+ log.emit("harness.completed", candidateCompletion(contRun, input.signal));
2184
2183
  // Supersede the exhausted candidate ONLY after the continuation
2185
2184
  // actually completes cleanly (never over a torn-off/aborted stream).
2186
2185
  if (!contRun.errored && !input.signal?.aborted)
2187
2186
  effectiveRun = contRun;
2187
+ // A refused capture is errored: the original keeps leading, and
2188
+ // the copy they share stays kept under the continuation's receipt.
2189
+ if (contRun.captureRefusal)
2190
+ effectiveRun.continuationRefusal = {
2191
+ attemptId: contRun.attemptId,
2192
+ refusal: contRun.captureRefusal,
2193
+ };
2188
2194
  }
2189
2195
  catch (err) {
2190
2196
  ledger.settle(contLeaseId, AC.attemptFailureCost(err, "continuation-error", 0).settlement);
@@ -2287,6 +2293,7 @@ export class Orchestrator {
2287
2293
  requestedSingleCandidate &&
2288
2294
  runs[0]?.reviewCwd === execRoot,
2289
2295
  execRoot,
2296
+ projectRoot: input.repoRoot,
2290
2297
  preTurnSha,
2291
2298
  postTurnSha: earlyPostTurnSha,
2292
2299
  }
@@ -2316,11 +2323,12 @@ export class Orchestrator {
2316
2323
  await disposeReviewEnvelopes();
2317
2324
  return cancelledRaceResult();
2318
2325
  }
2319
- const failedDelegation = delegateFailure.dominantRaceCandidateFailure(runs);
2326
+ const failedDelegation = delegateFailure.dominantRaceCandidateFailure(runs, input);
2320
2327
  if (failedDelegation) {
2321
2328
  await disposeReviewEnvelopes();
2322
2329
  const failedOutput = {
2323
2330
  ...{ store, log, paths, execRoot, preTurnSha, taskId, mode, run: failedDelegation },
2331
+ projectRoot: input.repoRoot,
2324
2332
  live: input.inPlace === true &&
2325
2333
  input.workspaceKind !== "directory" &&
2326
2334
  failedDelegation.reviewCwd === execRoot,
@@ -2341,7 +2349,7 @@ export class Orchestrator {
2341
2349
  budgetDenial,
2342
2350
  ...(mutatingRun ? { liveCapture: failedOutput } : {}),
2343
2351
  });
2344
- const failure = delegateFailure.candidateFailureTerminal(failedDelegation, "race");
2352
+ const failure = delegateFailure.candidateFailureTerminal(failedDelegation, "race", runs);
2345
2353
  if (mutatingRun)
2346
2354
  await delegateFailure.persistFailedCandidateOutput(failedOutput);
2347
2355
  raceTerminal.writeTelemetry();
@@ -2376,7 +2384,7 @@ export class Orchestrator {
2376
2384
  // real verification). Compute the reviewable set first and emit a typed
2377
2385
  // `review.skipped` when nothing is reviewable, so every start has a matching
2378
2386
  // terminal and the no-diff path records `not_run` consistently.
2379
- const reviewableRuns = workingRuns.filter((r) => r.files ? r.files.noChanges !== true : r.diff.trim().length > 0);
2387
+ const reviewableRuns = workingRuns.filter((r) => secretDiff.hasCandidateChanges(r));
2380
2388
  const configuredFamilies = new Set(reviewers.map((r) => r.providerFamily)).size;
2381
2389
  if (reviewableRuns.length === 0 || reviewers.length === 0) {
2382
2390
  log.emit("review.skipped", {
@@ -2407,18 +2415,15 @@ export class Orchestrator {
2407
2415
  evidences = await this.reviewRuns(workingRuns, reviewers, reviewVerified, reviewDir, input.repoRoot, contract, store, paths, log, ledger, taskId, input.signal, this.reservationEstimateUsd(input), false, input.runScopeMarker);
2408
2416
  }
2409
2417
  catch (err) {
2410
- // Review preflight/evidence failures end TERMINALLY with artifacts —
2411
- // never as an escaped throw that orphans the run dir.
2412
- return failAfterCandidates(raceTerminal, "review", err);
2413
- }
2414
- finally {
2415
- // Review preflight failures must not leak candidate worktrees.
2418
+ // Review failures end TERMINALLY with artifacts and leak no candidate worktree.
2416
2419
  await disposeReviewEnvelopes();
2420
+ return failAfterCandidates(raceTerminal, "review", err);
2417
2421
  }
2418
2422
  if (input.signal?.aborted) {
2423
+ await disposeReviewEnvelopes();
2419
2424
  return cancelledRaceResult();
2420
2425
  }
2421
- // Synthesis: if worthwhile, run a synthesizer as a NEW, re-checked candidate.
2426
+ // Synthesis, if worthwhile: a NEW re-checked candidate; workspaces stay until it ends (#535).
2422
2427
  const synth = mutatingRun
2423
2428
  ? decideSynthesis(evidences, input.synthesis ?? "auto")
2424
2429
  : {
@@ -2426,86 +2431,95 @@ export class Orchestrator {
2426
2431
  reason: "readonly access has no write-backed synthesis lifecycle",
2427
2432
  sources: evidences.map((evidence) => evidence.attemptId),
2428
2433
  };
2429
- store.writeYaml(join(paths.arbitrationDir, "synthesis.yaml"), synth);
2430
- log.emit("synthesis.started", { synthesize: synth.synthesize, reason: synth.reason });
2431
- if (synth.synthesize && !budgetStopped) {
2432
- const synthRouted = adapters[0];
2433
- const lease = ledger.reserve({
2434
- taskId,
2435
- attemptId: "synth",
2436
- intent: "synthesize",
2437
- harnessId: synthRouted.adapter.id,
2438
- cost: processingAttemptCostEvidence(synthRouted.adapter.id, "synth", this.reservationEstimateUsd(input), this.routeBillingKnowledge(input, synthRouted.adapter.id, synthRouted), synthRouted.processing),
2439
- });
2440
- if (lease.granted) {
2441
- let envelope;
2442
- const synthTried = new PoolAttemptEvidence(synthRouted.adapter.id, "synth");
2443
- try {
2444
- const plan = buildSynthesisPlan(evidences);
2445
- const synthesisInput = buildFileBackedSynthesisInput({
2446
- instructions: plan.instructions,
2447
- findings: plan.fixFindings,
2448
- candidates: workingRuns,
2449
- });
2450
- const synthAdapter = synthRouted.adapter;
2451
- // Disclose against the PER-ROUTE policy (per-harness web defaults
2452
- // included), exactly like the candidate slots do.
2453
- const synthKnobs = this.routeSpecKnobs(synthRouted, contract, undefined, input.effort);
2454
- const effectiveWeb = this.discloseWebUpgrade(log, synthRouted, synthKnobs.webPolicy, "synth");
2455
- envelope = await wsm.create({
2456
- taskId,
2457
- attemptId: "synth",
2458
- baseRef: contract.repo.base_ref,
2459
- dirtyPolicy: "snapshot",
2460
- accessProfile: candidateAccess,
2461
- workspaceKind: input.workspaceKind,
2462
- scopePaths: input.scopePaths,
2463
- });
2464
- const synthHome = this.harnessHomeFor(wsm, envelope, synthRouted, input);
2465
- const run = await this.runCandidateInEnvelope(synthRouted, envelope, "synth", "Synthesis", contract, synthesisInput.prompt, store, paths, wsm, ledger, {
2466
- lease: lease.lease,
2467
- onDenied: (denial) => {
2468
- budgetStopped = true;
2469
- budgetDenial ??= denial;
2470
- },
2471
- }, candidateAccess, input.onHarnessEvent, input.signal, undefined, input.effort, "synthesize", log, effectiveWeb, interactionChannelFor(input, log, runId, taskId, "synth", synthAdapter.id, synthRouted.supportsInteractive), undefined, input, false, synthesisInput.content, undefined, synthHome, undefined, synthTried);
2472
- ledger.settle(lease.lease?.lease_id ?? "", attemptUsageCostSettlement(run.cost, run.costEstimated, run.attemptId, run.harnessId, run.telemetry.authMode, run.telemetry.usageCost));
2473
- reviewEnvelopes.push(envelope);
2474
- envelope = undefined;
2475
- // D-16 r8: only a WORKING synth is reviewed/adopted (same veto owner
2476
- // as the race lane); `runs` still records it for telemetry.
2477
- runs.push(run);
2434
+ try {
2435
+ store.writeYaml(join(paths.arbitrationDir, "synthesis.yaml"), synth);
2436
+ log.emit("synthesis.started", { synthesize: synth.synthesize, reason: synth.reason });
2437
+ if (synth.synthesize && !budgetStopped) {
2438
+ const synthRouted = adapters[0];
2439
+ const lease = ledger.reserve({
2440
+ taskId,
2441
+ attemptId: "synth",
2442
+ intent: "synthesize",
2443
+ harnessId: synthRouted.adapter.id,
2444
+ cost: processingAttemptCostEvidence(synthRouted.adapter.id, "synth", this.reservationEstimateUsd(input), this.routeBillingKnowledge(input, synthRouted.adapter.id, synthRouted), synthRouted.processing),
2445
+ });
2446
+ if (lease.granted) {
2447
+ let envelope;
2448
+ const synthTried = new PoolAttemptEvidence(synthRouted.adapter.id, "synth");
2449
+ let disposeSaved;
2478
2450
  try {
2479
- if (isWorkingCandidate(run)) {
2480
- const synthEvidence = await this.reviewRuns([run], reviewers, reviewVerified, reviewDir, input.repoRoot, contract, store, paths, log, ledger, taskId, input.signal, this.reservationEstimateUsd(input), false, input.runScopeMarker);
2481
- evidences.push(...synthEvidence);
2482
- workingRuns.push(run);
2451
+ const plan = buildSynthesisPlan(evidences);
2452
+ const saved = await savedForSynthesis(workingRuns, paths.root, contract.repo.root);
2453
+ disposeSaved = saved.dispose;
2454
+ const synthesisInput = buildFileBackedSynthesisInput({
2455
+ instructions: plan.instructions,
2456
+ findings: plan.fixFindings,
2457
+ candidates: saved.candidates,
2458
+ });
2459
+ const synthAdapter = synthRouted.adapter;
2460
+ // Disclose against the PER-ROUTE policy (per-harness web defaults
2461
+ // included), exactly like the candidate slots do.
2462
+ const synthKnobs = this.routeSpecKnobs(synthRouted, contract, undefined, input.effort);
2463
+ const effectiveWeb = this.discloseWebUpgrade(log, synthRouted, synthKnobs.webPolicy, "synth");
2464
+ envelope = await wsm.create({
2465
+ taskId,
2466
+ attemptId: "synth",
2467
+ baseRef: contract.repo.base_ref,
2468
+ dirtyPolicy: "snapshot",
2469
+ accessProfile: candidateAccess,
2470
+ workspaceKind: input.workspaceKind,
2471
+ scopePaths: input.scopePaths,
2472
+ });
2473
+ const synthHome = this.harnessHomeFor(wsm, envelope, synthRouted, input);
2474
+ const run = await this.runCandidateInEnvelope(synthRouted, envelope, "synth", "Synthesis", contract, synthesisInput.prompt, store, paths, wsm, ledger, {
2475
+ lease: lease.lease,
2476
+ onDenied: (denial) => {
2477
+ budgetStopped = true;
2478
+ budgetDenial ??= denial;
2479
+ },
2480
+ }, candidateAccess, input.onHarnessEvent, input.signal, undefined, input.effort, "synthesize", log, effectiveWeb, interactionChannelFor(input, log, runId, taskId, "synth", synthAdapter.id, synthRouted.supportsInteractive), undefined, input, false, synthesisInput.content, undefined, synthHome, undefined, synthTried);
2481
+ ledger.settle(lease.lease?.lease_id ?? "", attemptUsageCostSettlement(run.cost, run.costEstimated, run.attemptId, run.harnessId, run.telemetry.authMode, run.telemetry.usageCost));
2482
+ reviewEnvelopes.push(envelope);
2483
+ envelope = undefined;
2484
+ // D-16 r8: only a WORKING synth is reviewed/adopted (same veto owner
2485
+ // as the race lane); `runs` still records it for telemetry.
2486
+ runs.push(run);
2487
+ try {
2488
+ if (isWorkingCandidate(run)) {
2489
+ const synthEvidence = await this.reviewRuns([run], reviewers, reviewVerified, reviewDir, input.repoRoot, contract, store, paths, log, ledger, taskId, input.signal, this.reservationEstimateUsd(input), false, input.runScopeMarker);
2490
+ evidences.push(...synthEvidence);
2491
+ workingRuns.push(run);
2492
+ }
2493
+ if (input.signal?.aborted) {
2494
+ return cancelledResult(log, runId, taskId, mode, paths.root, candidateStatuses(runs), raceTerminal.writeTelemetry, ledger.spend(), input.signal, store, undefined, undefined, history());
2495
+ }
2483
2496
  }
2484
- if (input.signal?.aborted) {
2485
- return cancelledResult(log, runId, taskId, mode, paths.root, candidateStatuses(runs), raceTerminal.writeTelemetry, ledger.spend(), input.signal, store, undefined, undefined, history());
2497
+ finally {
2498
+ await disposeReviewEnvelopes();
2486
2499
  }
2487
2500
  }
2501
+ catch (err) {
2502
+ // Not yet in `runs`: the run goes on, so its tries' accounts stay in the history.
2503
+ if (!runs.some((run) => run.attemptId === "synth"))
2504
+ thrownSynthesis = { poolAttempts: synthTried.snapshot() };
2505
+ ledger.settle(lease.lease?.lease_id ?? "", AC.attemptFailureCost(err, "synthesis-error").settlement);
2506
+ log.emit("harness.completed", {
2507
+ attempt_id: "synth",
2508
+ status: "failed",
2509
+ error: safeErrorMessage(err),
2510
+ });
2511
+ }
2488
2512
  finally {
2489
- await disposeReviewEnvelopes();
2513
+ await disposeSaved?.();
2514
+ if (envelope)
2515
+ await wsm.dispose(envelope);
2490
2516
  }
2491
2517
  }
2492
- catch (err) {
2493
- // Not yet in `runs`: the run goes on, so its tries' accounts stay in the history.
2494
- if (!runs.some((run) => run.attemptId === "synth"))
2495
- thrownSynthesis = { poolAttempts: synthTried.snapshot() };
2496
- ledger.settle(lease.lease?.lease_id ?? "", AC.attemptFailureCost(err, "synthesis-error").settlement);
2497
- log.emit("harness.completed", {
2498
- attempt_id: "synth",
2499
- status: "failed",
2500
- error: safeErrorMessage(err),
2501
- });
2502
- }
2503
- finally {
2504
- if (envelope)
2505
- await wsm.dispose(envelope);
2506
- }
2507
2518
  }
2508
2519
  }
2520
+ finally {
2521
+ await disposeReviewEnvelopes();
2522
+ }
2509
2523
  if (input.signal?.aborted) {
2510
2524
  return cancelledRaceResult();
2511
2525
  }
@@ -2578,7 +2592,7 @@ export class Orchestrator {
2578
2592
  winnerRun &&
2579
2593
  !inPlaceWinner &&
2580
2594
  !deferredRaceVerify &&
2581
- (winnerRun.files ? winnerRun.files.noChanges !== true : winnerRun.diff.trim().length > 0) &&
2595
+ secretDiff.hasCandidateChanges(winnerRun) &&
2582
2596
  facts.lifecycle === "succeeded" &&
2583
2597
  facts.review !== "blocked" &&
2584
2598
  !input.signal?.aborted) {
@@ -2667,8 +2681,8 @@ export class Orchestrator {
2667
2681
  else if (mutatingRun) {
2668
2682
  const savedPatch = secretDiff.persistFinalPatch(store, paths.finalDir, winnerRun);
2669
2683
  const patchSha256 = savedPatch.patchSha256;
2670
- const wstats = diffStats(winnerRun.diff);
2671
- const hasDiff = winnerRun.diff.trim().length > 0;
2684
+ const wstats = secretDiff.resultDiffStats(winnerRun);
2685
+ const hasDiff = secretDiff.hasCandidateChanges(winnerRun);
2672
2686
  const blockers = winnerEvidence
2673
2687
  ? winnerEvidence.findings.filter((f) => isBlocking(f)).length
2674
2688
  : 0;
@@ -2693,7 +2707,7 @@ export class Orchestrator {
2693
2707
  }
2694
2708
  else if (adoptable) {
2695
2709
  // Protected apply preserves the live tree or reports tree_mutated.
2696
- const applied = await verifyAndDeliver(execRoot, winnerRun.diff, { mode: "apply", protectedApply: true }, gateSpecsFromContract(contract, input.runScopeMarker), (freshVerify) => {
2710
+ const applied = await verifyAndDeliver(execRoot, secretDiff.deliverableOf(winnerRun), { mode: "apply", protectedApply: true, projectRoot, owner: paths.root }, gateSpecsFromContract(contract, input.runScopeMarker), (freshVerify) => {
2697
2711
  finalVerify = freshVerify;
2698
2712
  return finalVerifyBlocks(freshVerify)
2699
2713
  ? (freshVerify.reason ?? "final verify failed before race adoption")
@@ -2710,17 +2724,15 @@ export class Orchestrator {
2710
2724
  patch_sha256: patchSha256,
2711
2725
  winner: winnerRun.attemptId,
2712
2726
  });
2713
- try {
2714
- postTurnSha = await snapshotTree(execRoot);
2715
- }
2716
- catch {
2717
- postTurnSha = null;
2718
- }
2719
- revertAnchorId = createRevertAnchorFromPatchOrNull(execRoot, winnerRun.diff);
2727
+ postTurnSha = await snapshotTree(execRoot).catch(() => null);
2728
+ revertAnchorId = await anchors.after(winnerRun, applied);
2720
2729
  }
2721
2730
  else {
2722
- adopted = false;
2723
- applyState = "not_applied";
2731
+ // A write that could not be taken back stays live and revertable (INV-114).
2732
+ adopted = applied.treeMutated === true;
2733
+ applyState = adopted ? "applied_review_blocked" : "not_applied";
2734
+ if (adopted)
2735
+ revertAnchorId = await anchors.after(winnerRun, applied);
2724
2736
  deliveryFailureReason = applied.detail ?? "race adoption delivery was refused";
2725
2737
  facts = { ...facts, checks: "failed", reason: "checks_failed" };
2726
2738
  if (finalVerifyBlocks(finalVerify))
@@ -2743,7 +2755,7 @@ export class Orchestrator {
2743
2755
  deliveryReceiptPath: raceDeliveryReceipt || directoryDeliveryReceipt ? "final/delivery_receipt.yaml" : null,
2744
2756
  });
2745
2757
  if (inPlaceWinner && requestedSingleCandidate && adopted === true) {
2746
- revertAnchorId = await createRevertAnchorOrNull(execRoot, preTurnSha, postTurnSha);
2758
+ revertAnchorId = await anchors.turn(preTurnSha, postTurnSha);
2747
2759
  }
2748
2760
  store.writeYaml(join(paths.finalDir, "work_product.yaml"), {
2749
2761
  id: newId("wp"),
@@ -2779,7 +2791,7 @@ export class Orchestrator {
2779
2791
  },
2780
2792
  });
2781
2793
  }
2782
- store.writeText(join(paths.finalDir, "summary.md"), withPoolAttempts(renderSummary(runId, mode, { ...result.decision, facts }, evidences, synth.reason, actualReviewVerified, secretDiff.secretLikeSummaryLine(winnerRun.secretLike)), racePool()));
2794
+ store.writeText(join(paths.finalDir, "summary.md"), withPoolAttempts(renderSummary(runId, mode, { ...result.decision, facts }, evidences, synth.reason, actualReviewVerified, delegateFailure.raceSummaryDisclosure(winnerRun, runs)), racePool()));
2783
2795
  // summary.md is a DIAGNOSTIC artifact only (V8/PLAN addendum 2): it no
2784
2796
  // longer carries primary-output authority. A clean applyable success or a
2785
2797
  // winner answer still marks it ready for legacy INV-116 ordering; any
@@ -2806,12 +2818,15 @@ export class Orchestrator {
2806
2818
  const needsDecisionTerminal = facts.review === "blocked" || facts.checks === "failed";
2807
2819
  const isFailureTerminal = facts.lifecycle !== "succeeded" || needsDecisionTerminal;
2808
2820
  const pool = racePool();
2821
+ // Beside whichever failure record leads, a source another attempt kept stays named.
2822
+ const keptSources = candidateCaptureRefusals(runs).flatMap(secretDiff.captureInspectionActions);
2809
2823
  if (deliveryFailureReason && !finalVerifyFailed) {
2810
2824
  const refused = deliveryRefusalFailure(deliveryFailureReason, paths.root);
2811
2825
  writeFailure(store, paths, {
2812
2826
  ...refused,
2813
2827
  safeMessage: withPoolAttempts(refused.safeMessage, pool),
2814
2828
  poolAttempts: pool,
2829
+ nextActions: [...refused.nextActions, ...keptSources],
2815
2830
  });
2816
2831
  }
2817
2832
  else if (finalVerifyFailed) {
@@ -2825,15 +2840,18 @@ export class Orchestrator {
2825
2840
  : `final verify failed: ${finalVerify?.reason ?? (finalVerify?.gates_passed === false ? "deterministic gates failed on the fresh verify tree" : "unknown")}`, pool),
2826
2841
  poolAttempts: pool,
2827
2842
  runDir: paths.root,
2828
- nextActions: finalVerify?.applied_cleanly === null
2829
- ? [
2830
- "Inspect arbitration/decision.yaml (final_verify) for the verifier error",
2831
- "Fix the verify infrastructure (git worktree/tmp) and re-run, or accept_risk to override",
2832
- ]
2833
- : [
2834
- "Inspect arbitration/decision.yaml (final_verify)",
2835
- "Re-run after fixing the base conflict or the failing gates",
2836
- ],
2843
+ nextActions: [
2844
+ ...(finalVerify?.applied_cleanly === null
2845
+ ? [
2846
+ "Inspect arbitration/decision.yaml (final_verify) for the verifier error",
2847
+ "Fix the verify infrastructure (git worktree/tmp) and re-run, or accept_risk to override",
2848
+ ]
2849
+ : [
2850
+ "Inspect arbitration/decision.yaml (final_verify)",
2851
+ "Re-run after fixing the base conflict or the failing gates",
2852
+ ]),
2853
+ ...keptSources,
2854
+ ],
2837
2855
  });
2838
2856
  }
2839
2857
  else if (isFailureTerminal) {
@@ -2865,19 +2883,22 @@ export class Orchestrator {
2865
2883
  ? `attempts/${winnerRun.attemptId}/attempt.yaml`
2866
2884
  : undefined,
2867
2885
  runDir: paths.root,
2868
- nextActions: decisionBlock
2869
- ? [
2870
- "Review the blocking findings on the run's turn",
2871
- "Accept the risk to apply this exact patch, or discard the change",
2872
- ...(facts.checks === "failed"
2873
- ? ["Configure/approve the deterministic test command, then re-run"]
2874
- : []),
2875
- ]
2876
- : [
2877
- "Open diagnostics",
2878
- "Inspect candidate artifacts",
2879
- "Retry with a narrower prompt or different harness pool",
2880
- ],
2886
+ nextActions: [
2887
+ ...(decisionBlock
2888
+ ? [
2889
+ "Review the blocking findings on the run's turn",
2890
+ "Accept the risk to apply this exact patch, or discard the change",
2891
+ ...(facts.checks === "failed"
2892
+ ? ["Configure/approve the deterministic test command, then re-run"]
2893
+ : []),
2894
+ ]
2895
+ : [
2896
+ "Open diagnostics",
2897
+ "Inspect candidate artifacts",
2898
+ "Retry with a narrower prompt or different harness pool",
2899
+ ]),
2900
+ ...keptSources,
2901
+ ],
2881
2902
  });
2882
2903
  if (!winnerRun) {
2883
2904
  store.writeText(join(paths.finalDir, "summary.md"), `# Run ${runId} (${mode})\n\n- Lifecycle: ${facts.lifecycle}${facts.reason ? ` (${facts.reason})` : ""}\n- Phase: arbitration\n\n${withPoolAttempts(result.decision.why_winner, pool)}\n`);
@@ -3033,7 +3054,8 @@ export class Orchestrator {
3033
3054
  // local `execRoot`; this path previously ensured the boundary on repoRoot,
3034
3055
  // which for an isolated thread is the project, not the mutated worktree.
3035
3056
  const execRoot = this.execRootOf(input);
3036
- const wsm = new WorkspaceManager(execRoot);
3057
+ const wsm = new WorkspaceManager(execRoot, { projectRoot: input.repoRoot });
3058
+ const anchors = secretDiff.revertAnchors(execRoot, input.repoRoot);
3037
3059
  const readiness = new ReadinessLedger();
3038
3060
  store.writeYaml(join(paths.contextDir, "task.yaml"), contract);
3039
3061
  // Legacy Git envelopes need their boundary; explicit directory execution
@@ -3063,7 +3085,7 @@ export class Orchestrator {
3063
3085
  const reviewDir = join(paths.root, "review-evidence");
3064
3086
  if (contract.review_requested !== false)
3065
3087
  writeEvidencePacket(reviewDir, {
3066
- userIntent: redactSecrets(input.prompt),
3088
+ userIntent: input.prompt,
3067
3089
  diff: "(per-attempt)\n",
3068
3090
  tests: renderTestsEvidence(contract),
3069
3091
  });
@@ -3257,7 +3279,7 @@ export class Orchestrator {
3257
3279
  exhausted = true;
3258
3280
  processingBudgetDenial ??= denial;
3259
3281
  },
3260
- }, convergenceAccess, input.onHarnessEvent, input.signal, undefined, input.effort, "repair", log, effectiveWeb, interactionChannelFor(input, log, runId, taskId, attemptId, adapter.id, routed.supportsInteractive), (streamedUsd) => {
3282
+ }, convergenceAccess, input.onHarnessEvent, input.signal, undefined, input.effort, this.requestRequirements.convergenceIntent(routed, this.candidateIntent(input)), log, effectiveWeb, interactionChannelFor(input, log, runId, taskId, attemptId, adapter.id, routed.supportsInteractive), (streamedUsd) => {
3261
3283
  ledger.updateHold(lease.lease?.lease_id ?? "", streamedUsd);
3262
3284
  return ledger.tier() === "hard";
3263
3285
  }, input, true, // convergence runs one candidate: live deltas on (W-C4)
@@ -3303,14 +3325,13 @@ export class Orchestrator {
3303
3325
  telemetry: createAttemptTelemetry(knobs.webPolicy, contract.external_context.web_required, effectiveWeb, [routed.browserRequirement, routed.denyRequirement, routed.delegationRequirement], knobs.model),
3304
3326
  };
3305
3327
  if (envelope.workspace_kind === "directory") {
3306
- const captured = await captureDirectoryCandidate({
3328
+ ({ files: run.files, refusal: run.captureRefusal } = await captureDirectoryCandidate({
3307
3329
  manager: wsm,
3308
3330
  envelope,
3309
3331
  artifactRoot: join(paths.attemptsDir, attemptId),
3310
3332
  observedPaths: [...observedPaths],
3311
- });
3312
- run.files = captured.files;
3313
- run.captureRefusal = captured.refusal;
3333
+ holder: { runId: paths.runId, runDir: paths.root },
3334
+ }));
3314
3335
  }
3315
3336
  }
3316
3337
  lastRun = run;
@@ -3350,6 +3371,7 @@ export class Orchestrator {
3350
3371
  const failure = delegateFailure.candidateFailureTerminal(run, "convergence");
3351
3372
  await delegateFailure.persistFailedCandidateOutput({
3352
3373
  ...{ store, log, paths, execRoot, preTurnSha, taskId, mode, run },
3374
+ projectRoot: input.repoRoot,
3353
3375
  live: input.inPlace === true && input.workspaceKind !== "directory",
3354
3376
  kind: input.create === true ? "new_repo" : "patch",
3355
3377
  attempts: attempt,
@@ -3398,7 +3420,8 @@ export class Orchestrator {
3398
3420
  actualReviewVerified = evidence.reviewVerified ?? false;
3399
3421
  lastDiffStable = run.files
3400
3422
  ? await directoryCandidateStable(wsm, envelope, run.files)
3401
- : sha256(await wsm.diff(envelope)) === sha256(run.diff);
3423
+ : secretDiff.captureIdentity(await wsm.captureDiff(envelope, paths.root)) ===
3424
+ secretDiff.captureIdentity(run);
3402
3425
  const evaluated = evaluateConvergence({
3403
3426
  predicate: contract.convergence,
3404
3427
  gates: evidence.gates,
@@ -3448,7 +3471,7 @@ export class Orchestrator {
3448
3471
  ? run.files.manifestSha256
3449
3472
  : input.workspaceKind === "directory"
3450
3473
  ? null
3451
- : sha256(run.diff);
3474
+ : secretDiff.captureIdentity(run);
3452
3475
  if (requiredGateFailing && diffHash !== null && diffHash === lastFailingGateDiffHash) {
3453
3476
  sameFailingGateDiffs += 1;
3454
3477
  }
@@ -3461,7 +3484,7 @@ export class Orchestrator {
3461
3484
  const failedGateIds = run.gates
3462
3485
  .filter((g) => g.required && g.status !== "passed")
3463
3486
  .map((g) => g.id);
3464
- stuckNoProgressReason = `same candidate diff (${diffHash}) produced ${sameFailingGateDiffs} consecutive failing required gate round(s): ${failedGateIds.join(", ") || "unknown gate"}`;
3487
+ stuckNoProgressReason = `same candidate result (${diffHash}) produced ${sameFailingGateDiffs} consecutive failing required gate round(s): ${failedGateIds.join(", ") || "unknown gate"}`;
3465
3488
  log.emit("finding.revalidated", {
3466
3489
  attempt_id: attemptId,
3467
3490
  stuck_no_progress: true,
@@ -3599,7 +3622,7 @@ export class Orchestrator {
3599
3622
  let convFinalVerify = null;
3600
3623
  if (input.inPlace !== true &&
3601
3624
  lastRun &&
3602
- (lastRun.files ? lastRun.files.noChanges !== true : lastRun.diff.trim().length > 0) &&
3625
+ secretDiff.hasCandidateChanges(lastRun) &&
3603
3626
  facts.lifecycle === "succeeded" &&
3604
3627
  facts.review !== "blocked" &&
3605
3628
  !input.signal?.aborted) {
@@ -3635,6 +3658,7 @@ export class Orchestrator {
3635
3658
  // An incomplete capture has no exact patch: never publish an empty one.
3636
3659
  await delegateFailure.persistFailedCandidateOutput({
3637
3660
  ...{ store, log, paths, execRoot, preTurnSha, taskId, mode, facts, run: lastRun },
3661
+ projectRoot: input.repoRoot,
3638
3662
  live: input.inPlace === true && input.workspaceKind !== "directory",
3639
3663
  kind: input.create === true ? "new_repo" : "patch",
3640
3664
  attempts: attempt,
@@ -3646,16 +3670,14 @@ export class Orchestrator {
3646
3670
  // Honest apply-state (parity with runRace single-candidate in-place): a
3647
3671
  // convergence run with inPlace mutated the live tree directly across its
3648
3672
  // attempts, so it is "applied" even when review blocked (Revert offered).
3649
- const convHasDiff = lastRun.diff.trim().length > 0;
3673
+ const convHasDiff = secretDiff.hasCandidateChanges(lastRun);
3650
3674
  const convAdopted = input.inPlace === true && convHasDiff ? true : null;
3651
3675
  const convApplyState = convAdopted === true
3652
3676
  ? convAdoptable
3653
3677
  ? "applied"
3654
3678
  : "applied_review_blocked"
3655
3679
  : "not_applied";
3656
- const revertAnchorId = convAdopted === true
3657
- ? await createRevertAnchorOrNull(execRoot, preTurnSha, lastPostTurnSha)
3658
- : null;
3680
+ const revertAnchorId = convAdopted === true ? await anchors.turn(preTurnSha, lastPostTurnSha) : null;
3659
3681
  store.writeYaml(join(paths.finalDir, "work_product.yaml"), {
3660
3682
  id: newId("wp"),
3661
3683
  kind: "patch",
@@ -3679,12 +3701,12 @@ export class Orchestrator {
3679
3701
  },
3680
3702
  });
3681
3703
  }
3682
- // INV-062: the answer is kept for every convergence result, patch or files.
3704
+ // The exact answer is kept for every convergence result, patch or files.
3683
3705
  if (lastRun.answerText) {
3684
3706
  store.writeText(join(paths.finalDir, "answer.md"), lastRun.answerText);
3685
3707
  log.emit("output.ready", { kind: "answer", path: "final/answer.md" });
3686
3708
  }
3687
- store.writeText(join(paths.finalDir, "summary.md"), `${withPoolAttempts(`# Run ${runId} (${mode})\n\n- Lifecycle: ${facts.lifecycle}${facts.reason ? ` (${facts.reason})` : ""}\n- Attempts: ${attempt}\n- Winner: ${lastRun.attemptId}\n- Review verified (cross-family): ${actualReviewVerified}\n- Apply recommendation: ${decision?.apply_recommendation ?? "inspect"}${stuckNoProgressReason ? `\n- No-progress reason: ${stuckNoProgressReason}` : ""}${secretDiff.summaryDisclosure(lastRun.secretLike)}`, convPool)}\n`);
3709
+ store.writeText(join(paths.finalDir, "summary.md"), `${withPoolAttempts(`# Run ${runId} (${mode})\n\n- Lifecycle: ${facts.lifecycle}${facts.reason ? ` (${facts.reason})` : ""}\n- Attempts: ${attempt}\n- Winner: ${lastRun.attemptId}\n- Review verified (cross-family): ${actualReviewVerified}\n- Apply recommendation: ${decision?.apply_recommendation ?? "inspect"}${stuckNoProgressReason ? `\n- No-progress reason: ${stuckNoProgressReason}` : ""}${secretDiff.resultSummaryDisclosure(lastRun)}`, convPool)}\n`);
3688
3710
  // Lifecycle invariant (all modes): output.ready precedes the terminal
3689
3711
  // event so a client that applied the terminal event has the output.
3690
3712
  log.emit("output.ready", {
@@ -3716,6 +3738,8 @@ export class Orchestrator {
3716
3738
  code: convBudgetMapping?.code ?? convDeclared?.code ?? null,
3717
3739
  resetsAt: convDeclared?.resetsAt ?? null,
3718
3740
  requestRefusal: convDeclared?.requestRefusal,
3741
+ quotaRefusal: convDeclared?.quotaRefusal,
3742
+ rawContextShortfall: convDeclared?.rawContextShortfall,
3719
3743
  harnessId: lastRun?.harnessId,
3720
3744
  attemptId: lastRun?.attemptId,
3721
3745
  runDir: paths.root,
@@ -4081,7 +4105,8 @@ export class Orchestrator {
4081
4105
  }
4082
4106
  const text = outcome.text ?? "(no output)";
4083
4107
  plans.push({ id: outcome.harnessId, text });
4084
- store.writeText(join(paths.root, "plans", `${outcome.harnessId}.md`), redactSecrets(text) + "\n");
4108
+ // The planner's own saved copy keeps its exact text (INV-146).
4109
+ store.writeText(join(paths.root, "plans", `${outcome.harnessId}.md`), text + "\n");
4085
4110
  // Solo planning (D31): the FIRST successful planner is the plan; later
4086
4111
  // pool members are a sequential fallback chain (ask parity), not
4087
4112
  // parallel co-authors. Council re-enables the multi-draft round.
@@ -4387,11 +4412,8 @@ export class Orchestrator {
4387
4412
  // carries the denial reason so a refusal discloses run.continuation.denied.
4388
4413
  onLaunch) => {
4389
4414
  const adapter = routed.adapter;
4390
- const attemptId = continuationPointer
4391
- ? `a${String(idx + 1).padStart(2, "0")}-cont`
4392
- : modelOverride
4393
- ? `a${String(idx + 1).padStart(2, "0")}-fb`
4394
- : `a${String(idx + 1).padStart(2, "0")}`;
4415
+ const suffix = continuationPointer ? "-cont" : modelOverride ? "-fb" : "";
4416
+ const attemptId = `a${String(idx + 1).padStart(2, "0")}${suffix}`;
4395
4417
  const budgetSignalState = { quotaPressureDisclosed: false };
4396
4418
  const lease = ledger.reserve({
4397
4419
  taskId,
@@ -4490,7 +4512,7 @@ export class Orchestrator {
4490
4512
  const readonlyWorkEnvelope = this.workReportEnvelopeFor(routed, contract, Boolean(reportInteraction));
4491
4513
  const readonlyWorkMode = applyWorkEnvelope(spec, readonlyWorkEnvelope);
4492
4514
  const attemptEventsPath = join(paths.attemptsDir, attemptId, "events.jsonl");
4493
- const answer = new secretDiff.CountedAnswerAssembly();
4515
+ const answer = new AnswerAssembly();
4494
4516
  const telemetry = createAttemptTelemetry(knobs.webPolicy, contract.external_context.web_required, effectiveWeb, [],
4495
4517
  // Requested-model capture so ask/audit route receipts detect a silent
4496
4518
  // model downgrade (typed model_mismatch), not just agent runs.
@@ -4555,6 +4577,8 @@ export class Orchestrator {
4555
4577
  workOrder: input.prompt,
4556
4578
  firstPrompt: spec.prompt,
4557
4579
  poolEvidence: tried,
4580
+ later: continuationPointer ? "checkpoint" : "fallback",
4581
+ explicitModel: modelOverride !== undefined,
4558
4582
  }), { spec, continuation: input.continuation, store, telemetry }));
4559
4583
  const onAbort = () => void adapter.cancel?.(activeSessionId)?.catch(() => { });
4560
4584
  if (input.signal) {
@@ -4574,7 +4598,7 @@ export class Orchestrator {
4574
4598
  // A3 per-try isolation (candidate-lane parity): a failed try's output,
4575
4599
  // progress markers and model proof never carry into the next try.
4576
4600
  if (nativeTry > 0) {
4577
- answer = new secretDiff.CountedAnswerAssembly();
4601
+ answer = new AnswerAssembly();
4578
4602
  beginNativeRetry(telemetry);
4579
4603
  }
4580
4604
  const runSpec = nativeTry === 0
@@ -4611,30 +4635,33 @@ export class Orchestrator {
4611
4635
  },
4612
4636
  isSuspended: () => (reportInteraction?.pendingCount?.() ?? 0) > 0,
4613
4637
  suspensionVersion: () => reportInteraction?.suspensionVersion?.() ?? 0,
4638
+ stopSignal: input.signal, // after Stop: drained events are recorded, never used
4614
4639
  });
4615
4640
  for await (const ev of watchedReport) {
4616
- const safeEv = redactHarnessEvent(ev);
4617
- if (safeEv.payload?.["buffered"] !== true)
4618
- safeInvoke(input.onHarnessEvent, safeEv);
4619
- observeAuthSwitch(log, adapter.id, attemptId, safeEv);
4620
- log.emit("harness.event", harnessEventPayload(adapter.id, attemptId, safeEv), safeEv.payload?.["buffered"] !== true);
4621
- appendLine(attemptEventsPath, JSON.stringify(safeEv));
4641
+ // A read after Stop is stored evidence only; a callback may itself press Stop.
4642
+ const shown = !input.signal?.aborted && ev.payload?.["buffered"] !== true;
4643
+ if (shown)
4644
+ safeInvoke(input.onHarnessEvent, ev);
4645
+ observeAuthSwitch(log, adapter.id, attemptId, ev);
4646
+ const live = shown && !input.signal?.aborted; // the callback may have pressed Stop
4647
+ log.emit("harness.event", harnessEventPayload(adapter.id, attemptId, ev), live);
4648
+ appendHarnessEvent(attemptEventsPath, ev);
4622
4649
  if (input.signal?.aborted)
4623
- break;
4624
- observeAttemptTelemetry(telemetry, safeEv);
4625
- const mismatch = continuity.observe(safeEv, runSpec, telemetry.outputMarkers);
4650
+ continue;
4651
+ observeAttemptTelemetry(telemetry, ev);
4652
+ const mismatch = continuity.observe(ev, runSpec, telemetry.outputMarkers);
4626
4653
  if (mismatch) {
4627
4654
  harnessError = mismatch;
4628
4655
  break;
4629
4656
  }
4630
4657
  if (laneRun && continuity.mayPublishSession)
4631
- observeNativeSessionEvent(input, adapter.id, safeEv);
4632
- emitPlanProgress((t, p) => log.emit(t, p), adapter.id, attemptId, safeEv);
4658
+ observeNativeSessionEvent(input, adapter.id, ev);
4659
+ emitPlanProgress((t, p) => log.emit(t, p), adapter.id, attemptId, ev);
4633
4660
  // read-only routes burn quota too (the orchestrate PLANNER is
4634
4661
  // the loudest) — same single owner as the agent loop.
4635
- observeBudgetSignals(ledger, log, adapter.id, attemptId, safeEv, budgetSignalState);
4636
- this.deps.quotaEventSink?.(adapter.id, safeEv);
4637
- const spend = observeReadonlySpend(safeEv, (t, p) => log.emit(t, p), adapter.id, attemptId);
4662
+ observeBudgetSignals(ledger, log, adapter.id, attemptId, ev, budgetSignalState);
4663
+ this.deps.quotaEventSink?.(adapter.id, ev);
4664
+ const spend = observeReadonlySpend(ev, (t, p) => log.emit(t, p), adapter.id, attemptId);
4638
4665
  cost += spend.costUsd;
4639
4666
  costEstimated ||= spend.estimated;
4640
4667
  const streamDenial = updateProcessingStreamHold(runSpec, telemetry.usageCost, ledger, lease.lease.lease_id, adapter.id, attemptId);
@@ -4647,17 +4674,14 @@ export class Orchestrator {
4647
4674
  break;
4648
4675
  }
4649
4676
  // A TYPED final message wins verbatim over joined narration.
4650
- answer.observeCounted(ev, safeEv);
4651
- if (safeEv.type === "error")
4652
- harnessError = safeEv.error
4653
- ? redactSecrets(safeEv.error)
4654
- : "harness emitted an error";
4677
+ answer.observe(ev);
4678
+ if (ev.type === "error")
4679
+ harnessError = ev.error ? redactSecrets(ev.error) : "harness emitted an error";
4655
4680
  }
4656
4681
  }
4657
4682
  catch (err) {
4658
4683
  harnessError = safeErrorMessage(err);
4659
- if (err instanceof ProcessingBudgetAdmissionError ||
4660
- err instanceof RoutingPreflightError) {
4684
+ if (isDispatchRefusal(err)) {
4661
4685
  processingRefusal = err;
4662
4686
  break;
4663
4687
  }
@@ -4732,7 +4756,7 @@ export class Orchestrator {
4732
4756
  // Trim symmetrically with the plan path: a whitespace-only answer is not
4733
4757
  // a delivered report (the final-artifact wrapper heading would otherwise
4734
4758
  // make it read as present content by construction).
4735
- const report = redactSecrets(roUnwrapped.deliverable).trim();
4759
+ const report = roUnwrapped.deliverable.trim();
4736
4760
  const unrecovered = unrecoveredToolErrors(telemetry);
4737
4761
  const webBlocked = webUnsatisfied(telemetry);
4738
4762
  const reportPresent = report.length > 0;
@@ -4818,7 +4842,6 @@ export class Orchestrator {
4818
4842
  harnessId: adapter.id,
4819
4843
  status: scoutInterrupted ? "failed" : "success",
4820
4844
  report: report || "(no output)",
4821
- answerMatches: answer.secretLikeMatches(),
4822
4845
  error: scoutInterrupted ? "context capacity exhausted before the scout completed" : null,
4823
4846
  telemetry,
4824
4847
  ...(scoutInterrupted ? { interrupted: true } : {}),
@@ -4985,7 +5008,8 @@ export class Orchestrator {
4985
5008
  harnessId: a.harnessId,
4986
5009
  status: a.status,
4987
5010
  }));
4988
- const cancelledTerminal = () => cancelledResult(log, runId, taskId, opts.mode, paths.root, candidateSummaries, () => this.writeRunTelemetry(store, paths, contract, runId, taskId, opts.mode, attemptTelemetries, null), ledger.spend(), input.signal, store, undefined, resumableOf(attempts, "cancelled"), attempts);
5011
+ const carried = () => (opts.deepScan ? attempts : carryingAttempts(attempts, paths.root));
5012
+ const cancelledTerminal = () => cancelledResult(log, runId, taskId, opts.mode, paths.root, candidateSummaries, () => this.writeRunTelemetry(store, paths, contract, runId, taskId, opts.mode, attemptTelemetries, null), ledger.spend(), input.signal, store, undefined, resumableOf(carried(), "cancelled"), attempts);
4989
5013
  if (input.signal?.aborted)
4990
5014
  return cancelledTerminal();
4991
5015
  const succeededReadonly = attempts.filter((a) => a.status === "success");
@@ -5007,9 +5031,8 @@ export class Orchestrator {
5007
5031
  // whole decision + reducer spawn lives in deepScanReducer.ts (its owner).
5008
5032
  let deepScanSynthesis = null;
5009
5033
  let reducedReport = null;
5010
- let answerMatches = succeeded.reduce((sum, a) => sum + (a.answerMatches ?? 0), 0);
5011
5034
  if (opts.deepScan) {
5012
- ({ deepScanSynthesis, reducedReport, answerMatches } = await resolveDeepScanSynthesis(this.deepScanReducerDeps(input, contract, log), {
5035
+ ({ deepScanSynthesis, reducedReport } = await resolveDeepScanSynthesis(this.deepScanReducerDeps(input, contract, log), {
5013
5036
  succeeded,
5014
5037
  adapters,
5015
5038
  budgetStopped,
@@ -5101,10 +5124,9 @@ export class Orchestrator {
5101
5124
  const harnessLabel = attempts
5102
5125
  .map((a) => `${a.attemptId}:${a.harnessId}:${a.status}`)
5103
5126
  .join(", ");
5104
- const secretLike = secretDiff.answerSecretLikeFinding(answerMatches);
5105
5127
  // A delivered report that still ends unsuccessfully or blocked keeps it and names every failed try.
5106
5128
  const reportPool = terminalPoolAttempts(terminalFacts, attempts);
5107
- store.writeText(join(paths.finalDir, "summary.md"), `# Run ${runId} (${opts.mode})\n\n- Harnesses: ${harnessLabel}\n- Lifecycle: ${terminalFacts.lifecycle}${terminalFacts.reason ? ` (${terminalFacts.reason})` : ""}${secretDiff.summaryDisclosure(secretLike)}\n\n${withPoolAttempts(report, reportPool)}\n`);
5129
+ store.writeText(join(paths.finalDir, "summary.md"), `# Run ${runId} (${opts.mode})\n\n- Harnesses: ${harnessLabel}\n- Lifecycle: ${terminalFacts.lifecycle}${terminalFacts.reason ? ` (${terminalFacts.reason})` : ""}\n\n${withPoolAttempts(report, reportPool)}\n`);
5108
5130
  const reportProducerAttemptId = opts.deepScan &&
5109
5131
  deepScanSynthesis?.status === "succeeded" &&
5110
5132
  deepScanSynthesis.reducer_attempt_id
@@ -5121,7 +5143,6 @@ export class Orchestrator {
5121
5143
  mode: opts.mode,
5122
5144
  intent: opts.intent,
5123
5145
  read_only: true,
5124
- ...(secretLike ? { secret_like: secretLike } : {}),
5125
5146
  },
5126
5147
  });
5127
5148
  log.emit("work_product.emitted", { kind: "report", winner: reportProducerAttemptId });
@@ -5145,7 +5166,7 @@ export class Orchestrator {
5145
5166
  phase: "executor",
5146
5167
  pool_attempts: reportPool,
5147
5168
  failure_ref: "final/failure.yaml",
5148
- ...resumableTerminal(store, paths, attempts, true),
5169
+ ...resumableTerminal(store, paths, carried(), true),
5149
5170
  });
5150
5171
  }
5151
5172
  else if (workVetoed) {
@@ -5154,7 +5175,7 @@ export class Orchestrator {
5154
5175
  facts: terminalFacts,
5155
5176
  reason: terminalFacts.reason,
5156
5177
  pool_attempts: reportPool,
5157
- ...resumableTerminal(store, paths, attempts, true),
5178
+ ...resumableTerminal(store, paths, carried(), true),
5158
5179
  });
5159
5180
  }
5160
5181
  else {
@@ -5162,7 +5183,7 @@ export class Orchestrator {
5162
5183
  lifecycle: terminalFacts.lifecycle,
5163
5184
  facts: terminalFacts,
5164
5185
  reason: terminalFacts.reason,
5165
- ...resumableTerminal(store, paths, attempts),
5186
+ ...resumableTerminal(store, paths, carried()),
5166
5187
  });
5167
5188
  }
5168
5189
  return {
@@ -5174,7 +5195,7 @@ export class Orchestrator {
5174
5195
  facts: terminalFacts,
5175
5196
  winner: null,
5176
5197
  runDir: paths.root,
5177
- summary: withPoolAttempts(redactSecrets(report).slice(0, 400), reportPool),
5198
+ summary: withPoolAttempts(report.slice(0, 400), reportPool),
5178
5199
  candidates: candidateSummaries,
5179
5200
  };
5180
5201
  }