@claudexor/orchestrator 4.1.0 → 4.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/candidateReview.d.ts +3 -1
- package/dist/candidateReview.d.ts.map +1 -1
- package/dist/candidateReview.js +6 -1
- package/dist/candidateReview.js.map +1 -1
- package/dist/contract-gates.d.ts +10 -2
- package/dist/contract-gates.d.ts.map +1 -1
- package/dist/contract-gates.js +14 -1
- package/dist/contract-gates.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/orchestrator.d.ts +11 -3
- package/dist/orchestrator.d.ts.map +1 -1
- package/dist/orchestrator.js +64 -79
- package/dist/orchestrator.js.map +1 -1
- package/dist/reviewEvidence.d.ts +4 -0
- package/dist/reviewEvidence.d.ts.map +1 -0
- package/dist/reviewEvidence.js +46 -0
- package/dist/reviewEvidence.js.map +1 -0
- package/dist/runScope.d.ts +86 -0
- package/dist/runScope.d.ts.map +1 -0
- package/dist/runScope.js +181 -0
- package/dist/runScope.js.map +1 -0
- package/dist/runTerminalHelpers.d.ts +26 -0
- package/dist/runTerminalHelpers.d.ts.map +1 -0
- package/dist/runTerminalHelpers.js +137 -0
- package/dist/runTerminalHelpers.js.map +1 -0
- package/dist/runTerminals.d.ts +1 -11
- package/dist/runTerminals.d.ts.map +1 -1
- package/dist/runTerminals.js +67 -130
- package/dist/runTerminals.js.map +1 -1
- package/package.json +17 -17
package/dist/orchestrator.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { applyWorkEnvelope, promptWithPointers as renderPromptWithPointers, threadContextPointer, } from "./prompt-framing.js";
|
|
2
2
|
import { requestRefusalFailure } from "./runTerminalResults.js";
|
|
3
|
+
import { openRunScopeCustody, scopedRouteContext, scopedSpecEnv, } from "./runScope.js";
|
|
3
4
|
import { delegationBeltFor } from "./delegationBelt.js";
|
|
4
5
|
import { bindProcessingAdmission, processingAttemptCostEvidence, processingAdmissionForLease, updateProcessingStreamHold, ProcessingBudgetAdmissionError, } from "./processing-dispatch.js";
|
|
5
6
|
import { cancelledCandidatesResult, emptyCandidateResult, failedCandidatesResult, failAfterCandidates, } from "./candidateTerminals.js";
|
|
6
|
-
import { existsSync } from "node:fs";
|
|
7
7
|
import { effectiveAuthPreference, observeNativeSessionEvent, resumeSessionForProfile, } from "./credential-profiles.js";
|
|
8
8
|
import { AdmissionProfileProbes, OrchestratorCredentials, reviewerProfileResolver, } from "./orchestrator-credentials.js";
|
|
9
9
|
import { continuityWorkspace, resumableOf, resumableTerminal, } from "./continuity-terminal.js";
|
|
@@ -62,12 +62,13 @@ import { resolveWorkReportEnvelope, unwrapWorkReportEnvelope, } from "./workRepo
|
|
|
62
62
|
import { buildContinuationPacket, decideContinuation, synthesizeContinuationRequest, } from "./continuation.js";
|
|
63
63
|
import { interactionChannelFor } from "./interaction.js";
|
|
64
64
|
import { liveAttempt } from "./live-input.js";
|
|
65
|
-
import { gateSpecsFromContract, renderTestsEvidence } from "./contract-gates.js";
|
|
65
|
+
import { finalVerifyRun, gateSpecsFromContract, renderTestsEvidence } from "./contract-gates.js";
|
|
66
66
|
import { buildTaskContract } from "./task-contract-builder.js";
|
|
67
|
+
import { prepareReviewEvidenceDir, recordReviewEvidenceCleanup } from "./reviewEvidence.js";
|
|
67
68
|
import { ArtifactStore } from "@claudexor/artifact-store";
|
|
68
|
-
import { buildContextPack, rawContextForEnvelope,
|
|
69
|
+
import { buildContextPack, rawContextForEnvelope, writeEvidencePacket } from "@claudexor/context";
|
|
69
70
|
import { WorkspaceManager, captureRawPatchEnvelope, createRevertAnchorFromPatchOrNull, createRevertAnchorOrNull, consumeRawPatchEnvelope, snapshotTree, } from "@claudexor/workspace";
|
|
70
|
-
import { blockedDecisionOverride, finalVerifyBlocks,
|
|
71
|
+
import { blockedDecisionOverride, finalVerifyBlocks, verifyAndDeliverFiles, verifyAndDeliver, } from "@claudexor/delivery";
|
|
71
72
|
import { HarnessGateway } from "@claudexor/gateway";
|
|
72
73
|
import { ReadinessLedger, evaluateConvergence, failureSignature, gatesPassed, reviewCandidate, runGates, } from "@claudexor/review";
|
|
73
74
|
import { arbitrate } from "@claudexor/arbitration";
|
|
@@ -162,39 +163,54 @@ export class Orchestrator {
|
|
|
162
163
|
this.routingRationaleByRun.delete(settledRunId);
|
|
163
164
|
this.deps.delegationBudgetAuthority?.releaseRun(settledRunId);
|
|
164
165
|
};
|
|
166
|
+
// Process custody (owner 1A, #449; `runScope.ts`): the marker is minted and
|
|
167
|
+
// recorded BEFORE the first launch, rides every spec env (`scopedSpecEnv`),
|
|
168
|
+
// and every announced run HOLDS its terminal until the barrier has ended
|
|
169
|
+
// what still carries it. The reap never changes the verdict.
|
|
170
|
+
const custody = await openRunScopeCustody(this.deps.runScopes, runId);
|
|
171
|
+
resolved = { ...resolved, runScopeMarker: custody.marker };
|
|
165
172
|
try {
|
|
166
173
|
return await guardAnnouncedRun(resolved.signal, (announce) => {
|
|
174
|
+
const announced = custody.announced(announce);
|
|
167
175
|
switch (mode) {
|
|
168
176
|
case "ask":
|
|
169
177
|
// `--deep-scan` widens the answer into the bounded multi-scout
|
|
170
178
|
// research sweep with synthesis (the old `audit --swarm`/`explore`).
|
|
171
179
|
return resolved.deepScan
|
|
172
|
-
? this.runDeepScan(resolved,
|
|
173
|
-
: this.runAsk(resolved,
|
|
180
|
+
? this.runDeepScan(resolved, announced)
|
|
181
|
+
: this.runAsk(resolved, announced);
|
|
174
182
|
case "agent":
|
|
175
183
|
// Engine strategies are FLAGS on agent (v0.9 collapse): `--until-clean`
|
|
176
184
|
// and `--attempts` select the convergence loop; `--n` selects the race
|
|
177
185
|
// width; `--create` switches the candidate intent to create_from_scratch.
|
|
178
186
|
if (resolved.untilClean)
|
|
179
|
-
return this.runConvergence(resolved, mode, null,
|
|
187
|
+
return this.runConvergence(resolved, mode, null, announced);
|
|
180
188
|
if (resolved.attempts !== undefined && resolved.attempts !== null) {
|
|
181
|
-
return this.runConvergence(resolved, mode, resolved.attempts,
|
|
189
|
+
return this.runConvergence(resolved, mode, resolved.attempts, announced);
|
|
182
190
|
}
|
|
183
|
-
return this.runRace({ ...resolved, n: resolved.n ?? 1 }, mode,
|
|
191
|
+
return this.runRace({ ...resolved, n: resolved.n ?? 1 }, mode, announced);
|
|
184
192
|
case "plan":
|
|
185
|
-
return this.runPlan(resolved,
|
|
193
|
+
return this.runPlan(resolved, announced);
|
|
186
194
|
}
|
|
187
|
-
},
|
|
195
|
+
},
|
|
196
|
+
// The whole-run barrier: drain delegated children, then end the run's
|
|
197
|
+
// process scope and record its outcome before ANY terminal is flushed
|
|
198
|
+
// (a child-drain rejection keeps its error). Bounded by the reap deadline.
|
|
199
|
+
({ runId }) => custody.barrier(async () => {
|
|
188
200
|
const authority = this.deps.delegationBudgetAuthority;
|
|
189
201
|
if (!authority?.hasParent(runId))
|
|
190
202
|
return;
|
|
191
203
|
authority.beginParentClose(runId);
|
|
192
204
|
await authority.waitForChildren(runId);
|
|
193
|
-
},
|
|
194
|
-
// Single per-run terminalization hook:
|
|
195
|
-
//
|
|
196
|
-
//
|
|
197
|
-
|
|
205
|
+
}),
|
|
206
|
+
// Single per-run terminalization hook: the custody fallback for a path
|
|
207
|
+
// that never reached the barrier, then release per-run engine state
|
|
208
|
+
// (the delegated-child drain authority is released only AFTER
|
|
209
|
+
// settlement) on EVERY terminal.
|
|
210
|
+
async (settledRunId) => {
|
|
211
|
+
await custody.record();
|
|
212
|
+
releaseRunState(settledRunId);
|
|
213
|
+
});
|
|
198
214
|
}
|
|
199
215
|
catch (error) {
|
|
200
216
|
// A durable startup sink may refuse `run.created` before the strategy can
|
|
@@ -206,6 +222,9 @@ export class Orchestrator {
|
|
|
206
222
|
}
|
|
207
223
|
throw error;
|
|
208
224
|
}
|
|
225
|
+
finally {
|
|
226
|
+
await custody.settleUnannounced();
|
|
227
|
+
}
|
|
209
228
|
}
|
|
210
229
|
async resolveReviewers(cwd, runAuthPreference, onIgnoredSetting) {
|
|
211
230
|
if (this.deps.reviewers)
|
|
@@ -1217,7 +1236,7 @@ export class Orchestrator {
|
|
|
1217
1236
|
adapter: this.deps.registry.get(harnessId),
|
|
1218
1237
|
credentialProfile: sessionFields.credential_profile,
|
|
1219
1238
|
authPreference: sessionFields.auth_preference ?? "auto",
|
|
1220
|
-
laneEnv: this.laneHomeEnvFor(runInput, harnessId, profileId) ?? {},
|
|
1239
|
+
laneEnv: scopedSpecEnv(runInput.runScopeMarker, this.laneHomeEnvFor(runInput, harnessId, profileId) ?? {}) ?? {},
|
|
1221
1240
|
envInheritance: envInheritance(this.config(runInput.repoRoot)),
|
|
1222
1241
|
signal: runInput.signal,
|
|
1223
1242
|
processing,
|
|
@@ -1328,6 +1347,9 @@ export class Orchestrator {
|
|
|
1328
1347
|
if (routed.browserRequirement.effective && artifactRelativeDir === null) {
|
|
1329
1348
|
throw new Error("browser artifact ownership marker was not persisted");
|
|
1330
1349
|
}
|
|
1350
|
+
// The run's scope marker rides every spec env (plus the host facts when the
|
|
1351
|
+
// HOME is scoped), added AFTER the lane/profile home so that patch is kept.
|
|
1352
|
+
const scopedEnv = scopedSpecEnv(runInput?.runScopeMarker, harnessHome.env);
|
|
1331
1353
|
let spec = HarnessRunSpec.parse({
|
|
1332
1354
|
session_id: newId("ses"),
|
|
1333
1355
|
intent,
|
|
@@ -1359,7 +1381,7 @@ export class Orchestrator {
|
|
|
1359
1381
|
...(inPlaceEnvelope && sessionFields?.resume_session_id
|
|
1360
1382
|
? { resume_session_id: sessionFields.resume_session_id }
|
|
1361
1383
|
: {}),
|
|
1362
|
-
...(
|
|
1384
|
+
...(scopedEnv ? { env: scopedEnv } : {}),
|
|
1363
1385
|
raw_context_packet: rawContextPacket,
|
|
1364
1386
|
stream_deltas: streamDeltas,
|
|
1365
1387
|
});
|
|
@@ -1650,7 +1672,7 @@ export class Orchestrator {
|
|
|
1650
1672
|
}
|
|
1651
1673
|
const gates = gateSignalAborted
|
|
1652
1674
|
? []
|
|
1653
|
-
: await runGates(gateSpecsFromContract(contract), {
|
|
1675
|
+
: await runGates(gateSpecsFromContract(contract, runInput?.runScopeMarker), {
|
|
1654
1676
|
cwd: envelope.worktree_path,
|
|
1655
1677
|
env: wsm.envFor(envelope),
|
|
1656
1678
|
signal,
|
|
@@ -2396,7 +2418,7 @@ export class Orchestrator {
|
|
|
2396
2418
|
// candidates (a trivial greeting in agent mode no longer burns two reviewers on
|
|
2397
2419
|
// "(empty diff)"). Candidates still flow through arbitration/gates so the
|
|
2398
2420
|
// no_op/answer outcome and gate failures are unchanged.
|
|
2399
|
-
evidences = await this.reviewRuns(workingRuns, reviewers, reviewVerified, reviewDir, input.repoRoot, contract, store, paths, log, ledger, taskId, input.signal, this.reservationEstimateUsd(input));
|
|
2421
|
+
evidences = await this.reviewRuns(workingRuns, reviewers, reviewVerified, reviewDir, input.repoRoot, contract, store, paths, log, ledger, taskId, input.signal, this.reservationEstimateUsd(input), false, input.runScopeMarker);
|
|
2400
2422
|
}
|
|
2401
2423
|
catch (err) {
|
|
2402
2424
|
// Review preflight/evidence failures end TERMINALLY with artifacts —
|
|
@@ -2468,7 +2490,7 @@ export class Orchestrator {
|
|
|
2468
2490
|
runs.push(run);
|
|
2469
2491
|
try {
|
|
2470
2492
|
if (isWorkingCandidate(run)) {
|
|
2471
|
-
const synthEvidence = await this.reviewRuns([run], reviewers, reviewVerified, reviewDir, input.repoRoot, contract, store, paths, log, ledger, taskId, input.signal, this.reservationEstimateUsd(input));
|
|
2493
|
+
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);
|
|
2472
2494
|
evidences.push(...synthEvidence);
|
|
2473
2495
|
workingRuns.push(run);
|
|
2474
2496
|
}
|
|
@@ -2570,9 +2592,7 @@ export class Orchestrator {
|
|
|
2570
2592
|
facts.lifecycle === "succeeded" &&
|
|
2571
2593
|
facts.review !== "blocked" &&
|
|
2572
2594
|
!input.signal?.aborted) {
|
|
2573
|
-
finalVerify = winnerRun
|
|
2574
|
-
? await finalVerifyFiles(winnerRun.files, undefined, gateSpecsFromContract(contract), log)
|
|
2575
|
-
: await finalVerifyPatch(execRoot, winnerRun, gateSpecsFromContract(contract), log);
|
|
2595
|
+
finalVerify = await finalVerifyRun(execRoot, winnerRun, contract, log, input);
|
|
2576
2596
|
finalVerifyFailed = finalVerifyBlocks(finalVerify);
|
|
2577
2597
|
if (finalVerifyFailed)
|
|
2578
2598
|
facts = { ...facts, checks: "failed", reason: "checks_failed" };
|
|
@@ -2617,7 +2637,7 @@ export class Orchestrator {
|
|
|
2617
2637
|
facts.checks !== "failed" &&
|
|
2618
2638
|
!workStateVetoes(facts);
|
|
2619
2639
|
if (input.inPlace === true && !inPlaceWinner && directoryAdoptable) {
|
|
2620
|
-
const delivered = await verifyAndDeliverFiles(execRoot, winnerRun.files, {}, gateSpecsFromContract(contract), (freshVerify) => finalVerifyBlocks(freshVerify)
|
|
2640
|
+
const delivered = await verifyAndDeliverFiles(execRoot, winnerRun.files, {}, gateSpecsFromContract(contract, input.runScopeMarker), (freshVerify) => finalVerifyBlocks(freshVerify)
|
|
2621
2641
|
? (freshVerify.reason ?? "final verify failed before directory race adoption")
|
|
2622
2642
|
: null, log);
|
|
2623
2643
|
store.writeYaml(join(paths.finalDir, "delivery_receipt.yaml"), delivered);
|
|
@@ -2680,7 +2700,7 @@ export class Orchestrator {
|
|
|
2680
2700
|
}
|
|
2681
2701
|
else if (adoptable) {
|
|
2682
2702
|
// Protected apply preserves the live tree or reports tree_mutated.
|
|
2683
|
-
const applied = await verifyAndDeliver(execRoot, winnerRun.diff, { mode: "apply", protectedApply: true }, gateSpecsFromContract(contract), (freshVerify) => {
|
|
2703
|
+
const applied = await verifyAndDeliver(execRoot, winnerRun.diff, { mode: "apply", protectedApply: true }, gateSpecsFromContract(contract, input.runScopeMarker), (freshVerify) => {
|
|
2684
2704
|
finalVerify = freshVerify;
|
|
2685
2705
|
return finalVerifyBlocks(freshVerify)
|
|
2686
2706
|
? (freshVerify.reason ?? "final verify failed before race adoption")
|
|
@@ -2954,7 +2974,7 @@ export class Orchestrator {
|
|
|
2954
2974
|
transientRetryPolicy: input.transientRetryPolicy ?? transientRetryPolicy(this.config(input.cwd)),
|
|
2955
2975
|
});
|
|
2956
2976
|
}
|
|
2957
|
-
async reviewRuns(runs, reviewers, reviewVerified, reviewDir, cwd, contract, store, paths, log, ledger, taskId, signal, reservationEstimateUsd, reviewUnchanged = false) {
|
|
2977
|
+
async reviewRuns(runs, reviewers, reviewVerified, reviewDir, cwd, contract, store, paths, log, ledger, taskId, signal, reservationEstimateUsd, reviewUnchanged = false, runScopeMarker) {
|
|
2958
2978
|
return reviewCandidateRuns({
|
|
2959
2979
|
runs,
|
|
2960
2980
|
reviewers,
|
|
@@ -2970,50 +2990,17 @@ export class Orchestrator {
|
|
|
2970
2990
|
signal,
|
|
2971
2991
|
reservationEstimateUsd,
|
|
2972
2992
|
reviewUnchanged,
|
|
2993
|
+
runScopeMarker,
|
|
2973
2994
|
}, {
|
|
2974
2995
|
prepareReviewEvidenceDir: this.prepareReviewEvidenceDir.bind(this),
|
|
2975
|
-
recordReviewEvidenceCleanup
|
|
2996
|
+
recordReviewEvidenceCleanup,
|
|
2976
2997
|
reviewScoped: this.reviewScoped.bind(this),
|
|
2977
2998
|
config: this.config.bind(this),
|
|
2978
2999
|
});
|
|
2979
3000
|
}
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
// the candidate tree would contaminate the Git diff and, worse, overwrite a
|
|
2984
|
-
// user-owned path with the same name.
|
|
2985
|
-
if (!existsSync(sourceDir)) {
|
|
2986
|
-
throw new Error(`review evidence preflight failed for ${sourceDir}: source packet missing`);
|
|
2987
|
-
}
|
|
2988
|
-
return this.requireReviewEvidence(sourceDir);
|
|
2989
|
-
}
|
|
2990
|
-
requireReviewEvidence(dir) {
|
|
2991
|
-
const result = preflightEvidence(dir);
|
|
2992
|
-
if (result.ok)
|
|
2993
|
-
return dir;
|
|
2994
|
-
const missing = result.missing.length ? `missing=${result.missing.join(",")}` : "";
|
|
2995
|
-
const empty = result.empty.length ? `empty=${result.empty.join(",")}` : "";
|
|
2996
|
-
throw new Error(`review evidence preflight failed for ${dir}: ${[missing, empty].filter(Boolean).join(" ")}`);
|
|
2997
|
-
}
|
|
2998
|
-
cleanupReviewEvidenceDir(_candidateEvidenceDir, _candidateCwd) {
|
|
2999
|
-
// No candidate-tree packet exists in v2; external runtime retention is
|
|
3000
|
-
// governed by the artifact/journal lifecycle rather than best-effort rm.
|
|
3001
|
-
return null;
|
|
3002
|
-
}
|
|
3003
|
-
recordReviewEvidenceCleanup(store, metadataPath, attemptId, candidateEvidenceDir, candidateCwd) {
|
|
3004
|
-
const cleanupMetadata = this.cleanupReviewEvidenceDir(candidateEvidenceDir, candidateCwd);
|
|
3005
|
-
if (!cleanupMetadata)
|
|
3006
|
-
return;
|
|
3007
|
-
try {
|
|
3008
|
-
store.writeYaml(metadataPath, {
|
|
3009
|
-
...cleanupMetadata,
|
|
3010
|
-
attempt_id: attemptId,
|
|
3011
|
-
});
|
|
3012
|
-
}
|
|
3013
|
-
catch {
|
|
3014
|
-
// Cleanup telemetry must not mask the review/revalidation failure that
|
|
3015
|
-
// triggered best-effort cleanup.
|
|
3016
|
-
}
|
|
3001
|
+
/** The instance method is the seam tests stub to make evidence setup fail. */
|
|
3002
|
+
prepareReviewEvidenceDir(sourceDir, candidateCwd) {
|
|
3003
|
+
return prepareReviewEvidenceDir(sourceDir, candidateCwd);
|
|
3017
3004
|
}
|
|
3018
3005
|
async runConvergence(input, mode, maxAttempts, announce) {
|
|
3019
3006
|
const taskId = input.taskId ?? newId("task");
|
|
@@ -3398,7 +3385,7 @@ export class Orchestrator {
|
|
|
3398
3385
|
log.emit("review.skipped", { reason: "not_requested", attempt_id: attemptId });
|
|
3399
3386
|
return evaluateUnreviewedConvergence(evidence, contract);
|
|
3400
3387
|
}
|
|
3401
|
-
const [evidence] = await this.reviewRuns([run], reviewers, reviewVerified, reviewDir, input.repoRoot, contract, store, paths, log, ledger, taskId, input.signal, this.reservationEstimateUsd(input), true);
|
|
3388
|
+
const [evidence] = await this.reviewRuns([run], reviewers, reviewVerified, reviewDir, input.repoRoot, contract, store, paths, log, ledger, taskId, input.signal, this.reservationEstimateUsd(input), true, input.runScopeMarker);
|
|
3402
3389
|
if (!evidence)
|
|
3403
3390
|
throw new Error("Convergence review produced no evidence");
|
|
3404
3391
|
lastFindings = evidence.findings;
|
|
@@ -3587,9 +3574,7 @@ export class Orchestrator {
|
|
|
3587
3574
|
facts.lifecycle === "succeeded" &&
|
|
3588
3575
|
facts.review !== "blocked" &&
|
|
3589
3576
|
!input.signal?.aborted) {
|
|
3590
|
-
convFinalVerify = lastRun
|
|
3591
|
-
? await finalVerifyFiles(lastRun.files, undefined, gateSpecsFromContract(contract), log)
|
|
3592
|
-
: await finalVerifyPatch(execRoot, lastRun, gateSpecsFromContract(contract), log);
|
|
3577
|
+
convFinalVerify = await finalVerifyRun(execRoot, lastRun, contract, log, input);
|
|
3593
3578
|
if (finalVerifyBlocks(convFinalVerify))
|
|
3594
3579
|
facts = { ...facts, checks: "failed", reason: "checks_failed" };
|
|
3595
3580
|
}
|
|
@@ -3848,9 +3833,9 @@ export class Orchestrator {
|
|
|
3848
3833
|
...sessionFields,
|
|
3849
3834
|
...this.harnessSpecKnobs(contract, knobs, args.intent),
|
|
3850
3835
|
env_inheritance: envInheritance(this.config(input.repoRoot)),
|
|
3851
|
-
env: (args.laneRun
|
|
3836
|
+
env: scopedSpecEnv(input.runScopeMarker, (args.laneRun
|
|
3852
3837
|
? this.laneHomeEnvFor(input, adapter.id, sessionFields.credential_profile?.profile_id ?? input.credentialProfileId ?? null)
|
|
3853
|
-
: null) ?? args.fallbackHome,
|
|
3838
|
+
: null) ?? args.fallbackHome),
|
|
3854
3839
|
});
|
|
3855
3840
|
this.credentials.stampProfileSelection(spec, input, adapter.id);
|
|
3856
3841
|
const plannerAbort = new AbortController();
|
|
@@ -3903,9 +3888,9 @@ export class Orchestrator {
|
|
|
3903
3888
|
// harnesses run sequentially. Doctor, model inventory, and spawn share each
|
|
3904
3889
|
// lane's durable HOME; the disposable context remains the non-thread fallback.
|
|
3905
3890
|
const laneRun = Boolean(input.threadId);
|
|
3906
|
-
const roHome = resolveReadOnlyRouteContext(this.execRootOf(input), laneRun
|
|
3891
|
+
const roHome = scopedRouteContext(resolveReadOnlyRouteContext(this.execRootOf(input), laneRun
|
|
3907
3892
|
? (id) => this.laneHomeEnvFor(input, id, input.credentialProfileId ?? null)
|
|
3908
|
-
: undefined);
|
|
3893
|
+
: undefined), input.runScopeMarker);
|
|
3909
3894
|
let adapters;
|
|
3910
3895
|
try {
|
|
3911
3896
|
adapters = await this.resolveCandidateAdapters({ ...input, n: undefined }, "plan", ledger, log, roHome, runId);
|
|
@@ -4190,7 +4175,7 @@ export class Orchestrator {
|
|
|
4190
4175
|
*/
|
|
4191
4176
|
deepScanReducerDeps(input, contract, log) {
|
|
4192
4177
|
return {
|
|
4193
|
-
newReadOnlyHome: () => resolveReadOnlyRouteContext(this.execRootOf(input)),
|
|
4178
|
+
newReadOnlyHome: () => scopedRouteContext(resolveReadOnlyRouteContext(this.execRootOf(input)), input.runScopeMarker),
|
|
4194
4179
|
costEvidence: (harnessId, attemptId, routed) =>
|
|
4195
4180
|
// The reducer admits under a finite estimate floor (mirror of the n>1
|
|
4196
4181
|
// scout reserve) so a subscription route is not refused for lacking a
|
|
@@ -4213,7 +4198,7 @@ export class Orchestrator {
|
|
|
4213
4198
|
resume_session_id: null,
|
|
4214
4199
|
...this.harnessSpecKnobs(contract, knobs, "synthesize"),
|
|
4215
4200
|
env_inheritance: envInheritance(this.config(input.repoRoot)),
|
|
4216
|
-
env: homeEnv,
|
|
4201
|
+
env: scopedSpecEnv(input.runScopeMarker, homeEnv),
|
|
4217
4202
|
});
|
|
4218
4203
|
this.credentials.stampProfileSelection(spec, input, routed.adapter.id);
|
|
4219
4204
|
// D-16: compile the WorkReport transport onto the reducer spec (the
|
|
@@ -4265,9 +4250,9 @@ export class Orchestrator {
|
|
|
4265
4250
|
// and the next lane turn resumes it (INV-034). Its doctor/model/spawn path
|
|
4266
4251
|
// shares that lane HOME; deep-scan and one-shot asks keep the disposable one.
|
|
4267
4252
|
const laneRun = Boolean(input.threadId) && opts.mode === "ask" && !opts.deepScan;
|
|
4268
|
-
const roHome = resolveReadOnlyRouteContext(this.execRootOf(input), laneRun
|
|
4253
|
+
const roHome = scopedRouteContext(resolveReadOnlyRouteContext(this.execRootOf(input), laneRun
|
|
4269
4254
|
? (id) => this.laneHomeEnvFor(input, id, input.credentialProfileId ?? null)
|
|
4270
|
-
: undefined);
|
|
4255
|
+
: undefined), input.runScopeMarker);
|
|
4271
4256
|
let adapters, width;
|
|
4272
4257
|
try {
|
|
4273
4258
|
({ adapters, width } = await resolveReadOnlyCandidates({
|
|
@@ -4445,9 +4430,9 @@ export class Orchestrator {
|
|
|
4445
4430
|
// A thread lane turn spawns in its DURABLE per-lane home so the native
|
|
4446
4431
|
// session it records is reachable for resume next turn; everything else
|
|
4447
4432
|
// uses the disposable route-context home.
|
|
4448
|
-
env: (laneRun
|
|
4433
|
+
env: scopedSpecEnv(input.runScopeMarker, (laneRun
|
|
4449
4434
|
? this.laneHomeEnvFor(input, adapter.id, sessionFields.credential_profile?.profile_id ?? input.credentialProfileId ?? null)
|
|
4450
|
-
: null) ?? roHome.env,
|
|
4435
|
+
: null) ?? roHome.env),
|
|
4451
4436
|
});
|
|
4452
4437
|
this.credentials.stampProfileSelection(spec, input, adapter.id);
|
|
4453
4438
|
const reportInteraction = interactionChannelFor(input, log, runId, taskId, attemptId, adapter.id, routed.supportsInteractive);
|