@claudexor/orchestrator 5.0.1 → 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.
@@ -18,11 +18,11 @@ import { PoolAttemptEvidence, terminalPoolAttempts, withPoolAttempts, } from "./
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";
@@ -1262,11 +1262,12 @@ 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
1272
  const sessionFields = runInput
1272
1273
  ? await this.sessionSpecFields(runInput, adapter.id, knobs.model, log, routed.authRouteEstimate, routed.quotaAdmission)
@@ -1304,6 +1305,7 @@ export class Orchestrator {
1304
1305
  [
1305
1306
  prompt,
1306
1307
  outerBoundaryNotice(harnessHome, routed.auxiliaryWritableRoots),
1308
+ await directoryPreparationNotice(envelope, attemptId, log),
1307
1309
  laneContinuity?.pointerLine,
1308
1310
  continuationPointer,
1309
1311
  ]
@@ -1632,7 +1634,7 @@ export class Orchestrator {
1632
1634
  const unwrapped = unwrapWorkReportEnvelope(acceptedTryOutput(answer, harnessErrored), workReportMode, { sideToolReport: telemetry.sideToolWorkReport ?? undefined });
1633
1635
  const answerText = unwrapped.deliverable.trim().length > 0 ? unwrapped.deliverable : undefined;
1634
1636
  if (directory)
1635
- await captureDirectory();
1637
+ await captureDirectory(true);
1636
1638
  const captured = directory
1637
1639
  ? { diff: "", captureRefusal: directoryCapture.refusal }
1638
1640
  : await secretDiff.captureCandidateWorkspace({
@@ -2108,17 +2110,7 @@ export class Orchestrator {
2108
2110
  }, input, requestedSingleCandidate, // W-C4 deltas: single-candidate chat lane only (racing = noise x N)
2109
2111
  undefined, undefined, harnessHome, undefined, tried);
2110
2112
  ledger.settle(slot.lease.lease_id, attemptUsageCostSettlement(run.cost, run.costEstimated, run.attemptId, run.harnessId, run.telemetry.authMode, run.telemetry.usageCost));
2111
- log.emit("harness.completed", {
2112
- harness_id: adapter.id,
2113
- attempt_id: slot.attemptId,
2114
- // QA-027: never claim `success` over an attempt the operator/deadline
2115
- // cut short. An abort makes the run non-successful; the top-level
2116
- // status axis must say `cancelled` (the nested outcome axis already
2117
- // rides in telemetrySummary), not launder a torn-off stream as clean.
2118
- status: input.signal?.aborted ? "cancelled" : run.errored ? "failed" : "success",
2119
- cost_usd: run.cost,
2120
- ...telemetrySummary(run.telemetry),
2121
- });
2113
+ log.emit("harness.completed", candidateCompletion(run, input.signal));
2122
2114
  // D-16d one-shot continuation for an ENVELOPED candidate (parity with the
2123
2115
  // read-only loop, which had the ONLY continuation wiring). An eligible
2124
2116
  // terminal context exhaustion (repeated_refill, no completed report) gets
@@ -2187,21 +2179,18 @@ export class Orchestrator {
2187
2179
  return true;
2188
2180
  }, input, requestedSingleCandidate, undefined, packet.pointerLine ?? undefined, harnessHome, undefined, contTried);
2189
2181
  ledger.settle(contLeaseId, attemptUsageCostSettlement(contRun.cost, contRun.costEstimated, contRun.attemptId, contRun.harnessId, contRun.telemetry.authMode, contRun.telemetry.usageCost));
2190
- log.emit("harness.completed", {
2191
- harness_id: adapter.id,
2192
- attempt_id: contAttemptId,
2193
- status: input.signal?.aborted
2194
- ? "cancelled"
2195
- : contRun.errored
2196
- ? "failed"
2197
- : "success",
2198
- cost_usd: contRun.cost,
2199
- ...telemetrySummary(contRun.telemetry),
2200
- });
2182
+ log.emit("harness.completed", candidateCompletion(contRun, input.signal));
2201
2183
  // Supersede the exhausted candidate ONLY after the continuation
2202
2184
  // actually completes cleanly (never over a torn-off/aborted stream).
2203
2185
  if (!contRun.errored && !input.signal?.aborted)
2204
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
+ };
2205
2194
  }
2206
2195
  catch (err) {
2207
2196
  ledger.settle(contLeaseId, AC.attemptFailureCost(err, "continuation-error", 0).settlement);
@@ -2334,7 +2323,7 @@ export class Orchestrator {
2334
2323
  await disposeReviewEnvelopes();
2335
2324
  return cancelledRaceResult();
2336
2325
  }
2337
- const failedDelegation = delegateFailure.dominantRaceCandidateFailure(runs);
2326
+ const failedDelegation = delegateFailure.dominantRaceCandidateFailure(runs, input);
2338
2327
  if (failedDelegation) {
2339
2328
  await disposeReviewEnvelopes();
2340
2329
  const failedOutput = {
@@ -2360,7 +2349,7 @@ export class Orchestrator {
2360
2349
  budgetDenial,
2361
2350
  ...(mutatingRun ? { liveCapture: failedOutput } : {}),
2362
2351
  });
2363
- const failure = delegateFailure.candidateFailureTerminal(failedDelegation, "race");
2352
+ const failure = delegateFailure.candidateFailureTerminal(failedDelegation, "race", runs);
2364
2353
  if (mutatingRun)
2365
2354
  await delegateFailure.persistFailedCandidateOutput(failedOutput);
2366
2355
  raceTerminal.writeTelemetry();
@@ -2802,7 +2791,7 @@ export class Orchestrator {
2802
2791
  },
2803
2792
  });
2804
2793
  }
2805
- store.writeText(join(paths.finalDir, "summary.md"), withPoolAttempts(renderSummary(runId, mode, { ...result.decision, facts }, evidences, synth.reason, actualReviewVerified, secretDiff.resultSummaryLines(winnerRun)), racePool()));
2794
+ store.writeText(join(paths.finalDir, "summary.md"), withPoolAttempts(renderSummary(runId, mode, { ...result.decision, facts }, evidences, synth.reason, actualReviewVerified, delegateFailure.raceSummaryDisclosure(winnerRun, runs)), racePool()));
2806
2795
  // summary.md is a DIAGNOSTIC artifact only (V8/PLAN addendum 2): it no
2807
2796
  // longer carries primary-output authority. A clean applyable success or a
2808
2797
  // winner answer still marks it ready for legacy INV-116 ordering; any
@@ -2829,12 +2818,15 @@ export class Orchestrator {
2829
2818
  const needsDecisionTerminal = facts.review === "blocked" || facts.checks === "failed";
2830
2819
  const isFailureTerminal = facts.lifecycle !== "succeeded" || needsDecisionTerminal;
2831
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);
2832
2823
  if (deliveryFailureReason && !finalVerifyFailed) {
2833
2824
  const refused = deliveryRefusalFailure(deliveryFailureReason, paths.root);
2834
2825
  writeFailure(store, paths, {
2835
2826
  ...refused,
2836
2827
  safeMessage: withPoolAttempts(refused.safeMessage, pool),
2837
2828
  poolAttempts: pool,
2829
+ nextActions: [...refused.nextActions, ...keptSources],
2838
2830
  });
2839
2831
  }
2840
2832
  else if (finalVerifyFailed) {
@@ -2848,15 +2840,18 @@ export class Orchestrator {
2848
2840
  : `final verify failed: ${finalVerify?.reason ?? (finalVerify?.gates_passed === false ? "deterministic gates failed on the fresh verify tree" : "unknown")}`, pool),
2849
2841
  poolAttempts: pool,
2850
2842
  runDir: paths.root,
2851
- nextActions: finalVerify?.applied_cleanly === null
2852
- ? [
2853
- "Inspect arbitration/decision.yaml (final_verify) for the verifier error",
2854
- "Fix the verify infrastructure (git worktree/tmp) and re-run, or accept_risk to override",
2855
- ]
2856
- : [
2857
- "Inspect arbitration/decision.yaml (final_verify)",
2858
- "Re-run after fixing the base conflict or the failing gates",
2859
- ],
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
+ ],
2860
2855
  });
2861
2856
  }
2862
2857
  else if (isFailureTerminal) {
@@ -2888,19 +2883,22 @@ export class Orchestrator {
2888
2883
  ? `attempts/${winnerRun.attemptId}/attempt.yaml`
2889
2884
  : undefined,
2890
2885
  runDir: paths.root,
2891
- nextActions: decisionBlock
2892
- ? [
2893
- "Review the blocking findings on the run's turn",
2894
- "Accept the risk to apply this exact patch, or discard the change",
2895
- ...(facts.checks === "failed"
2896
- ? ["Configure/approve the deterministic test command, then re-run"]
2897
- : []),
2898
- ]
2899
- : [
2900
- "Open diagnostics",
2901
- "Inspect candidate artifacts",
2902
- "Retry with a narrower prompt or different harness pool",
2903
- ],
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
+ ],
2904
2902
  });
2905
2903
  if (!winnerRun) {
2906
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`);
@@ -3327,14 +3325,13 @@ export class Orchestrator {
3327
3325
  telemetry: createAttemptTelemetry(knobs.webPolicy, contract.external_context.web_required, effectiveWeb, [routed.browserRequirement, routed.denyRequirement, routed.delegationRequirement], knobs.model),
3328
3326
  };
3329
3327
  if (envelope.workspace_kind === "directory") {
3330
- const captured = await captureDirectoryCandidate({
3328
+ ({ files: run.files, refusal: run.captureRefusal } = await captureDirectoryCandidate({
3331
3329
  manager: wsm,
3332
3330
  envelope,
3333
3331
  artifactRoot: join(paths.attemptsDir, attemptId),
3334
3332
  observedPaths: [...observedPaths],
3335
- });
3336
- run.files = captured.files;
3337
- run.captureRefusal = captured.refusal;
3333
+ holder: { runId: paths.runId, runDir: paths.root },
3334
+ }));
3338
3335
  }
3339
3336
  }
3340
3337
  lastRun = run;