@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.
- package/dist/account-pool.d.ts +4 -1
- package/dist/account-pool.d.ts.map +1 -1
- package/dist/account-pool.js +25 -19
- package/dist/account-pool.js.map +1 -1
- package/dist/account-resolution.d.ts +1 -4
- package/dist/account-resolution.d.ts.map +1 -1
- package/dist/account-resolution.js +19 -42
- package/dist/account-resolution.js.map +1 -1
- package/dist/attemptOutputMarkers.d.ts +7 -0
- package/dist/attemptOutputMarkers.d.ts.map +1 -1
- package/dist/attemptOutputMarkers.js +1 -1
- package/dist/attemptOutputMarkers.js.map +1 -1
- package/dist/attemptTelemetry.d.ts +4 -1
- package/dist/attemptTelemetry.d.ts.map +1 -1
- package/dist/attemptTelemetry.js +9 -26
- package/dist/attemptTelemetry.js.map +1 -1
- package/dist/candidateEvidence.d.ts +29 -9
- package/dist/candidateEvidence.d.ts.map +1 -1
- package/dist/candidateEvidence.js +68 -16
- package/dist/candidateEvidence.js.map +1 -1
- package/dist/candidateOutputs.d.ts +44 -22
- package/dist/candidateOutputs.d.ts.map +1 -1
- package/dist/candidateOutputs.js +116 -72
- package/dist/candidateOutputs.js.map +1 -1
- package/dist/candidateReview.d.ts.map +1 -1
- package/dist/candidateReview.js +44 -8
- package/dist/candidateReview.js.map +1 -1
- package/dist/candidateTerminals.d.ts +1 -0
- package/dist/candidateTerminals.d.ts.map +1 -1
- package/dist/candidateTerminals.js +38 -15
- package/dist/candidateTerminals.js.map +1 -1
- package/dist/candidateWorkProduct.d.ts +2 -1
- package/dist/candidateWorkProduct.d.ts.map +1 -1
- package/dist/candidateWorkProduct.js +6 -3
- package/dist/candidateWorkProduct.js.map +1 -1
- package/dist/captureRefusal.d.ts +41 -3
- package/dist/captureRefusal.d.ts.map +1 -1
- package/dist/captureRefusal.js +168 -25
- package/dist/captureRefusal.js.map +1 -1
- package/dist/continuation-chain.test-support.d.ts +473 -0
- package/dist/continuation-chain.test-support.d.ts.map +1 -0
- package/dist/continuation-chain.test-support.js +206 -0
- package/dist/continuation-chain.test-support.js.map +1 -0
- package/dist/continuation-custody.d.ts +4 -1
- package/dist/continuation-custody.d.ts.map +1 -1
- package/dist/continuation-custody.js +71 -29
- package/dist/continuation-custody.js.map +1 -1
- package/dist/continuation-evidence-io.d.ts +30 -4
- package/dist/continuation-evidence-io.d.ts.map +1 -1
- package/dist/continuation-evidence-io.js +162 -46
- package/dist/continuation-evidence-io.js.map +1 -1
- package/dist/continuation-evidence.d.ts +40 -3
- package/dist/continuation-evidence.d.ts.map +1 -1
- package/dist/continuation-evidence.js +85 -11
- package/dist/continuation-evidence.js.map +1 -1
- package/dist/continuation-input.d.ts +10 -1
- package/dist/continuation-input.d.ts.map +1 -1
- package/dist/continuation-input.js +21 -20
- package/dist/continuation-input.js.map +1 -1
- package/dist/continuation-later.d.ts +30 -0
- package/dist/continuation-later.d.ts.map +1 -0
- package/dist/continuation-later.js +108 -0
- package/dist/continuation-later.js.map +1 -0
- package/dist/continue-from.d.ts +4 -3
- package/dist/continue-from.d.ts.map +1 -1
- package/dist/continue-from.js +62 -26
- package/dist/continue-from.js.map +1 -1
- package/dist/continuity-notice.d.ts +3 -1
- package/dist/continuity-notice.d.ts.map +1 -1
- package/dist/continuity-notice.js +3 -1
- package/dist/continuity-notice.js.map +1 -1
- package/dist/continuity-terminal.d.ts +16 -0
- package/dist/continuity-terminal.d.ts.map +1 -1
- package/dist/continuity-terminal.js +21 -0
- package/dist/continuity-terminal.js.map +1 -1
- package/dist/continuity.d.ts +1 -1
- package/dist/continuity.d.ts.map +1 -1
- package/dist/contract-gates.d.ts.map +1 -1
- package/dist/contract-gates.js +11 -6
- package/dist/contract-gates.js.map +1 -1
- package/dist/credential-cooldown.d.ts +2 -1
- package/dist/credential-cooldown.d.ts.map +1 -1
- package/dist/credential-cooldown.js +16 -7
- package/dist/credential-cooldown.js.map +1 -1
- package/dist/credential-preflight.d.ts.map +1 -1
- package/dist/credential-preflight.js +10 -7
- package/dist/credential-preflight.js.map +1 -1
- package/dist/credential-profile-rotation.d.ts +10 -3
- package/dist/credential-profile-rotation.d.ts.map +1 -1
- package/dist/credential-profile-rotation.js +28 -26
- package/dist/credential-profile-rotation.js.map +1 -1
- package/dist/deepScanReducer.d.ts +0 -3
- package/dist/deepScanReducer.d.ts.map +1 -1
- package/dist/deepScanReducer.js +22 -26
- package/dist/deepScanReducer.js.map +1 -1
- package/dist/delegationFailure.d.ts +105 -15
- package/dist/delegationFailure.d.ts.map +1 -1
- package/dist/delegationFailure.js +43 -12
- package/dist/delegationFailure.js.map +1 -1
- package/dist/delegationToolEvidence.d.ts +2 -0
- package/dist/delegationToolEvidence.d.ts.map +1 -1
- package/dist/delegationToolEvidence.js +21 -0
- package/dist/delegationToolEvidence.js.map +1 -1
- package/dist/diffReview.d.ts +1 -8
- package/dist/diffReview.d.ts.map +1 -1
- package/dist/diffReview.js +3 -18
- package/dist/diffReview.js.map +1 -1
- package/dist/directoryCandidate.d.ts +11 -1
- package/dist/directoryCandidate.d.ts.map +1 -1
- package/dist/directoryCandidate.js +34 -14
- package/dist/directoryCandidate.js.map +1 -1
- package/dist/inrun-continuity-carrier.d.ts +11 -1
- package/dist/inrun-continuity-carrier.d.ts.map +1 -1
- package/dist/inrun-continuity-carrier.js +32 -10
- package/dist/inrun-continuity-carrier.js.map +1 -1
- package/dist/inrun-continuity-types.d.ts +17 -4
- package/dist/inrun-continuity-types.d.ts.map +1 -1
- package/dist/inrun-continuity.d.ts +8 -3
- package/dist/inrun-continuity.d.ts.map +1 -1
- package/dist/inrun-continuity.js +41 -37
- package/dist/inrun-continuity.js.map +1 -1
- package/dist/inrun-continuity.test-support.d.ts +61 -4
- package/dist/inrun-continuity.test-support.d.ts.map +1 -1
- package/dist/inrun-continuity.test-support.js +12 -2
- package/dist/inrun-continuity.test-support.js.map +1 -1
- package/dist/modelGovernance.d.ts +87 -9
- package/dist/modelGovernance.d.ts.map +1 -1
- package/dist/modelGovernance.js +110 -15
- package/dist/modelGovernance.js.map +1 -1
- package/dist/orchestrator-credentials.d.ts +9 -4
- package/dist/orchestrator-credentials.d.ts.map +1 -1
- package/dist/orchestrator-credentials.js +14 -6
- package/dist/orchestrator-credentials.js.map +1 -1
- package/dist/orchestrator.d.ts +3 -2
- package/dist/orchestrator.d.ts.map +1 -1
- package/dist/orchestrator.js +298 -277
- package/dist/orchestrator.js.map +1 -1
- package/dist/planFinalize.d.ts.map +1 -1
- package/dist/planFinalize.js +3 -7
- package/dist/planFinalize.js.map +1 -1
- package/dist/planRun.js +2 -2
- package/dist/planRun.js.map +1 -1
- package/dist/plannerAttempt.d.ts +0 -2
- package/dist/plannerAttempt.d.ts.map +1 -1
- package/dist/plannerAttempt.js +64 -30
- package/dist/plannerAttempt.js.map +1 -1
- package/dist/policyFindings.d.ts +3 -0
- package/dist/policyFindings.d.ts.map +1 -1
- package/dist/policyFindings.js +11 -1
- package/dist/policyFindings.js.map +1 -1
- package/dist/pool-attempt-evidence.d.ts +1 -1
- package/dist/pool-attempt-evidence.d.ts.map +1 -1
- package/dist/pool-attempt-evidence.js +1 -1
- package/dist/pool-attempt-evidence.js.map +1 -1
- package/dist/primary-divergence.d.ts +7 -2
- package/dist/primary-divergence.d.ts.map +1 -1
- package/dist/primary-divergence.js +13 -5
- package/dist/primary-divergence.js.map +1 -1
- package/dist/quota-refusal-scope.d.ts +39 -1
- package/dist/quota-refusal-scope.d.ts.map +1 -1
- package/dist/quota-refusal-scope.js +95 -1
- package/dist/quota-refusal-scope.js.map +1 -1
- package/dist/readonlyTerminals.d.ts +0 -1
- package/dist/readonlyTerminals.d.ts.map +1 -1
- package/dist/readonlyTerminals.js +5 -3
- package/dist/readonlyTerminals.js.map +1 -1
- package/dist/requestRequirements.d.ts +23 -0
- package/dist/requestRequirements.d.ts.map +1 -1
- package/dist/requestRequirements.js +22 -0
- package/dist/requestRequirements.js.map +1 -1
- package/dist/resultNotice.d.ts +14 -0
- package/dist/resultNotice.d.ts.map +1 -0
- package/dist/resultNotice.js +21 -0
- package/dist/resultNotice.js.map +1 -0
- package/dist/reviewerInventory.d.ts +47 -0
- package/dist/reviewerInventory.d.ts.map +1 -0
- package/dist/reviewerInventory.js +74 -0
- package/dist/reviewerInventory.js.map +1 -0
- package/dist/reviewerPanel.d.ts.map +1 -1
- package/dist/reviewerPanel.js +37 -60
- package/dist/reviewerPanel.js.map +1 -1
- package/dist/routing-failure.d.ts +2 -1
- package/dist/routing-failure.d.ts.map +1 -1
- package/dist/routing-failure.js +2 -0
- package/dist/routing-failure.js.map +1 -1
- package/dist/runAdmission.d.ts.map +1 -1
- package/dist/runAdmission.js +1 -14
- package/dist/runAdmission.js.map +1 -1
- package/dist/runEventLog.d.ts +2 -1
- package/dist/runEventLog.d.ts.map +1 -1
- package/dist/runEventLog.js +5 -3
- package/dist/runEventLog.js.map +1 -1
- package/dist/runFactsBuilder.d.ts.map +1 -1
- package/dist/runFactsBuilder.js +18 -10
- package/dist/runFactsBuilder.js.map +1 -1
- package/dist/runFactsDeliverable.d.ts.map +1 -1
- package/dist/runFactsDeliverable.js +7 -1
- package/dist/runFactsDeliverable.js.map +1 -1
- package/dist/runSupport.d.ts +5 -10
- package/dist/runSupport.d.ts.map +1 -1
- package/dist/runSupport.js +38 -40
- package/dist/runSupport.js.map +1 -1
- package/dist/runTerminalResults.d.ts +9 -1
- package/dist/runTerminalResults.d.ts.map +1 -1
- package/dist/runTerminalResults.js +27 -5
- package/dist/runTerminalResults.js.map +1 -1
- package/dist/runTerminals.d.ts.map +1 -1
- package/dist/runTerminals.js +6 -3
- package/dist/runTerminals.js.map +1 -1
- package/dist/savedCandidate.d.ts +43 -0
- package/dist/savedCandidate.d.ts.map +1 -0
- package/dist/savedCandidate.js +88 -0
- package/dist/savedCandidate.js.map +1 -0
- package/dist/secretDiff.d.ts +85 -46
- package/dist/secretDiff.d.ts.map +1 -1
- package/dist/secretDiff.js +123 -126
- package/dist/secretDiff.js.map +1 -1
- package/dist/task-contract-builder.d.ts.map +1 -1
- package/dist/task-contract-builder.js +5 -7
- package/dist/task-contract-builder.js.map +1 -1
- package/dist/workReportEnvelope.d.ts.map +1 -1
- package/dist/workReportEnvelope.js +4 -16
- package/dist/workReportEnvelope.js.map +1 -1
- package/package.json +17 -17
- package/dist/persistedPatch.d.ts +0 -55
- package/dist/persistedPatch.d.ts.map +0 -1
- package/dist/persistedPatch.js +0 -132
- package/dist/persistedPatch.js.map +0 -1
package/dist/orchestrator.js
CHANGED
|
@@ -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,
|
|
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,
|
|
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,
|
|
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,
|
|
77
|
-
import { WorkspaceManager, captureRawPatchEnvelope,
|
|
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,
|
|
84
|
-
import { readTextSafe,
|
|
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(
|
|
192
|
+
async resolveReviewers(run, onIgnoredSetting) {
|
|
192
193
|
if (this.deps.reviewers)
|
|
193
194
|
return this.deps.reviewers;
|
|
194
|
-
|
|
195
|
-
|
|
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,
|
|
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
|
-
}
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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,
|
|
1446
|
-
const capped = dropDeltaPastBudget(
|
|
1447
|
-
const display = !capped &&
|
|
1448
|
-
log?.emit("harness.event", harnessEventPayload(adapter.id, attemptId,
|
|
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
|
-
|
|
1466
|
+
continue; // a live observer may itself have pressed Stop
|
|
1451
1467
|
if (display)
|
|
1452
|
-
safeInvoke(onHarnessEvent,
|
|
1453
|
-
observeAuthSwitch(log, adapter.id, attemptId,
|
|
1454
|
-
observeAttemptTelemetry(telemetry,
|
|
1455
|
-
const mismatch = continuity.observe(
|
|
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,
|
|
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,
|
|
1480
|
-
if (
|
|
1495
|
+
emitPlanProgress((t, p) => log?.emit(t, p), adapter.id, attemptId, ev);
|
|
1496
|
+
if (ev.type === "usage") {
|
|
1481
1497
|
const usage = processAttemptUsage({
|
|
1482
|
-
event:
|
|
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 (
|
|
1516
|
+
if (ev.type === "error") {
|
|
1501
1517
|
harnessErrored = true;
|
|
1502
|
-
errors.push(redactSecrets(
|
|
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.
|
|
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,
|
|
1510
|
-
this.deps.quotaEventSink?.(adapter.id,
|
|
1525
|
+
observeBudgetSignals(ledger, log, adapter.id, attemptId, ev, budgetSignalState);
|
|
1526
|
+
this.deps.quotaEventSink?.(adapter.id, ev);
|
|
1511
1527
|
}
|
|
1512
|
-
if (
|
|
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
|
|
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
|
-
:
|
|
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
|
|
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,
|
|
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 {
|
|
1634
|
-
const deliverableEvidence =
|
|
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
|
-
...
|
|
1738
|
+
...secretDiff.attemptPatchInput(captured),
|
|
1725
1739
|
persistPatch: !directory && captureRefusal === undefined && isMutatingAccess(access),
|
|
1726
|
-
persistProducedMedia: !directory
|
|
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
|
-
|
|
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
|
|
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:
|
|
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.
|
|
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) =>
|
|
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
|
|
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
|
|
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
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
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
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
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
|
-
|
|
2485
|
-
|
|
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
|
|
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
|
|
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 =
|
|
2671
|
-
const hasDiff =
|
|
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
|
|
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
|
-
|
|
2714
|
-
|
|
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
|
-
|
|
2723
|
-
|
|
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
|
|
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,
|
|
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:
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
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:
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
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:
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
:
|
|
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
|
-
:
|
|
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
|
|
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
|
|
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 =
|
|
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
|
-
//
|
|
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.
|
|
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
|
-
|
|
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
|
|
4391
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
4617
|
-
|
|
4618
|
-
|
|
4619
|
-
|
|
4620
|
-
log
|
|
4621
|
-
|
|
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
|
-
|
|
4624
|
-
observeAttemptTelemetry(telemetry,
|
|
4625
|
-
const mismatch = continuity.observe(
|
|
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,
|
|
4632
|
-
emitPlanProgress((t, p) => log.emit(t, p), adapter.id, attemptId,
|
|
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,
|
|
4636
|
-
this.deps.quotaEventSink?.(adapter.id,
|
|
4637
|
-
const spend = observeReadonlySpend(
|
|
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.
|
|
4651
|
-
if (
|
|
4652
|
-
harnessError =
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
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})` : ""}
|
|
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,
|
|
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,
|
|
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,
|
|
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(
|
|
5198
|
+
summary: withPoolAttempts(report.slice(0, 400), reportPool),
|
|
5178
5199
|
candidates: candidateSummaries,
|
|
5179
5200
|
};
|
|
5180
5201
|
}
|