@claudexor/orchestrator 3.17.2 → 3.20.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/dist/account-evidence.d.ts +13 -0
  2. package/dist/account-evidence.d.ts.map +1 -0
  3. package/dist/account-evidence.js +55 -0
  4. package/dist/account-evidence.js.map +1 -0
  5. package/dist/account-resolution.d.ts.map +1 -1
  6. package/dist/account-resolution.js +22 -5
  7. package/dist/account-resolution.js.map +1 -1
  8. package/dist/auth-route-classification.d.ts +22 -1
  9. package/dist/auth-route-classification.d.ts.map +1 -1
  10. package/dist/auth-route-classification.js +38 -0
  11. package/dist/auth-route-classification.js.map +1 -1
  12. package/dist/candidateEvidence.js +1 -1
  13. package/dist/candidateEvidence.js.map +1 -1
  14. package/dist/candidateTerminals.d.ts +6 -0
  15. package/dist/candidateTerminals.d.ts.map +1 -1
  16. package/dist/candidateTerminals.js +28 -0
  17. package/dist/candidateTerminals.js.map +1 -1
  18. package/dist/candidateWorkProduct.d.ts +21 -0
  19. package/dist/candidateWorkProduct.d.ts.map +1 -0
  20. package/dist/candidateWorkProduct.js +43 -0
  21. package/dist/candidateWorkProduct.js.map +1 -0
  22. package/dist/continuity-facts.d.ts +3 -0
  23. package/dist/continuity-facts.d.ts.map +1 -1
  24. package/dist/continuity-facts.js +3 -0
  25. package/dist/continuity-facts.js.map +1 -1
  26. package/dist/continuity-summary.d.ts +5 -1
  27. package/dist/continuity-summary.d.ts.map +1 -1
  28. package/dist/continuity-summary.js +5 -4
  29. package/dist/continuity-summary.js.map +1 -1
  30. package/dist/credential-cooldown.d.ts +0 -10
  31. package/dist/credential-cooldown.d.ts.map +1 -1
  32. package/dist/credential-cooldown.js +0 -24
  33. package/dist/credential-cooldown.js.map +1 -1
  34. package/dist/credential-differential.d.ts +12 -1
  35. package/dist/credential-differential.d.ts.map +1 -1
  36. package/dist/credential-differential.js +42 -13
  37. package/dist/credential-differential.js.map +1 -1
  38. package/dist/credential-execution.d.ts +4 -0
  39. package/dist/credential-execution.d.ts.map +1 -0
  40. package/dist/credential-execution.js +101 -0
  41. package/dist/credential-execution.js.map +1 -0
  42. package/dist/credential-profile-rotation.d.ts.map +1 -1
  43. package/dist/credential-profile-rotation.js +8 -2
  44. package/dist/credential-profile-rotation.js.map +1 -1
  45. package/dist/credential-profiles.d.ts +3 -4
  46. package/dist/credential-profiles.d.ts.map +1 -1
  47. package/dist/credential-profiles.js +28 -6
  48. package/dist/credential-profiles.js.map +1 -1
  49. package/dist/deepScanReducer.d.ts.map +1 -1
  50. package/dist/deepScanReducer.js +5 -4
  51. package/dist/deepScanReducer.js.map +1 -1
  52. package/dist/delegationFailure.d.ts.map +1 -1
  53. package/dist/delegationFailure.js +7 -32
  54. package/dist/delegationFailure.js.map +1 -1
  55. package/dist/index.d.ts +4 -3
  56. package/dist/index.d.ts.map +1 -1
  57. package/dist/index.js +3 -2
  58. package/dist/index.js.map +1 -1
  59. package/dist/laneStreamEvents.d.ts +2 -4
  60. package/dist/laneStreamEvents.d.ts.map +1 -1
  61. package/dist/laneStreamEvents.js +3 -5
  62. package/dist/laneStreamEvents.js.map +1 -1
  63. package/dist/modelGovernance.d.ts +5 -31
  64. package/dist/modelGovernance.d.ts.map +1 -1
  65. package/dist/modelGovernance.js +51 -6
  66. package/dist/modelGovernance.js.map +1 -1
  67. package/dist/orchestrator-credentials.d.ts +23 -2
  68. package/dist/orchestrator-credentials.d.ts.map +1 -1
  69. package/dist/orchestrator-credentials.js +61 -6
  70. package/dist/orchestrator-credentials.js.map +1 -1
  71. package/dist/orchestrator.d.ts +10 -12
  72. package/dist/orchestrator.d.ts.map +1 -1
  73. package/dist/orchestrator.js +129 -144
  74. package/dist/orchestrator.js.map +1 -1
  75. package/dist/planRun.d.ts +3 -7
  76. package/dist/planRun.d.ts.map +1 -1
  77. package/dist/planRun.js +15 -13
  78. package/dist/planRun.js.map +1 -1
  79. package/dist/plannerAttempt.d.ts +15 -4
  80. package/dist/plannerAttempt.d.ts.map +1 -1
  81. package/dist/plannerAttempt.js +57 -30
  82. package/dist/plannerAttempt.js.map +1 -1
  83. package/dist/processing-dispatch.d.ts +7 -5
  84. package/dist/processing-dispatch.d.ts.map +1 -1
  85. package/dist/processing-dispatch.js +65 -31
  86. package/dist/processing-dispatch.js.map +1 -1
  87. package/dist/retainedOutput.d.ts +4 -0
  88. package/dist/retainedOutput.d.ts.map +1 -0
  89. package/dist/retainedOutput.js +31 -0
  90. package/dist/retainedOutput.js.map +1 -0
  91. package/dist/runFactsPresentation.d.ts.map +1 -1
  92. package/dist/runFactsPresentation.js +6 -1
  93. package/dist/runFactsPresentation.js.map +1 -1
  94. package/dist/runTerminalResults.d.ts.map +1 -1
  95. package/dist/runTerminalResults.js +20 -2
  96. package/dist/runTerminalResults.js.map +1 -1
  97. package/dist/runTerminals.d.ts.map +1 -1
  98. package/dist/runTerminals.js +9 -2
  99. package/dist/runTerminals.js.map +1 -1
  100. package/package.json +17 -17
@@ -1,11 +1,11 @@
1
1
  import { applyWorkEnvelope, promptWithPointers as renderPromptWithPointers, threadContextPointer, } from "./prompt-framing.js";
2
2
  import { requestRefusalFailure } from "./runTerminalResults.js";
3
3
  import { delegationBeltFor } from "./delegationBelt.js";
4
- import { bindProcessingAdmission, processingAdmissionForLease, updateProcessingStreamHold, ProcessingBudgetAdmissionError, } from "./processing-dispatch.js";
4
+ import { bindProcessingAdmission, processingAttemptCostEvidence, processingAdmissionForLease, updateProcessingStreamHold, ProcessingBudgetAdmissionError, } from "./processing-dispatch.js";
5
5
  import { cancelledCandidatesResult, emptyCandidateResult, failedCandidatesResult, } from "./candidateTerminals.js";
6
6
  import { existsSync } from "node:fs";
7
7
  import { effectiveAuthPreference, observeNativeSessionEvent, resumeSessionForProfile, rotateSpecOnTypedLimit, } from "./credential-profiles.js";
8
- import { OrchestratorCredentials, reviewerProfileResolver, rotatedSpecInLaneHome, } from "./orchestrator-credentials.js";
8
+ import { AdmissionProfileProbes, OrchestratorCredentials, reviewerProfileResolver, rotatedSpecInLaneHome, } from "./orchestrator-credentials.js";
9
9
  import { accountPoolRows } from "./account-pool.js";
10
10
  import { writeRunTelemetryArtifact } from "./runTelemetryWriter.js";
11
11
  import { buildFileBackedSynthesisInput, materializeWinnerOutputs, stageFileBackedContext, writeCandidateAttemptArtifacts, } from "./candidateOutputs.js";
@@ -18,13 +18,13 @@ import { capabilityIntents } from "@claudexor/gateway";
18
18
  import { reviewCandidateRuns, resolveEngineReview, unreviewedCandidateEvidence, evaluateUnreviewedConvergence, } from "./candidateReview.js";
19
19
  import { join } from "node:path";
20
20
  import { finalizePlanRun, runCouncilPlan, writePlanHarnessFailure, } from "./planRun.js";
21
- import { runPlannerAttempt as executePlannerAttempt, } from "./plannerAttempt.js";
21
+ import { runPlannerAttempt as executePlannerAttempt, plannerAttemptSummary, } from "./plannerAttempt.js";
22
22
  import { HarnessRunSpec, MAX_COUNCIL_MEMBERS_DEFAULT, ModeKind as ModeKindSchema, QuotaSnapshot as QuotaSnapshotSchema, isBlocking, makeOutcomeFacts, reviewAllowsApply, workStateVetoes, strictifyOutputSchema, estimateEffectiveAuthRoute, } from "@claudexor/schema";
23
23
  import { globalConfigDir, loadConfig } from "@claudexor/config";
24
24
  import { prepareRoutedProcessing, processingCostEvidence, prepareReviewerProcessing, } from "./processing-routing.js";
25
25
  import { acceptedTryOutput, AccessProfileIncompatibleError, AnswerAssembly, CLAUDEXOR_BROWSER_ARTIFACT_SUBDIR, countsAsAgentProgress, HarnessUnavailableError, summarizeDiffPaths as diffStats, withInactivityWatchdog, } from "@claudexor/core";
26
26
  import { assertRouteModelsAllowed, runModelGovernedRoute } from "./modelGovernance.js";
27
- import { authModeForCredentialRoute, authModeForPreference } from "./auth-route-classification.js";
27
+ import { authModeForCredentialRoute, authModeForPreference, authRouteEvidenceFor, } from "./auth-route-classification.js";
28
28
  import { governRouteEffort } from "./effortGovernance.js";
29
29
  import { isFullAccess, RequestRequirementsResolver } from "./requestRequirements.js";
30
30
  import { activateDelegationParent } from "./delegation-parent-activation.js";
@@ -69,7 +69,7 @@ import { HarnessGateway } from "@claudexor/gateway";
69
69
  import { ReadinessLedger, evaluateConvergence, failureSignature, gatesPassed, reviewCandidate, runGates, } from "@claudexor/review";
70
70
  import { arbitrate } from "@claudexor/arbitration";
71
71
  import { buildSynthesisPlan, decideSynthesis } from "@claudexor/synthesis";
72
- import { attemptCostEvidence, billingKnowledgeForAuthRoute, attemptUsageCostSettlement, BudgetLedger, isBudgetTerminal, explainRanking, loadHarnessMetrics, promptFingerprint, rankHarnesses, } from "@claudexor/budget";
72
+ import { billingKnowledgeForAuthRoute, attemptUsageCostSettlement, BudgetLedger, isBudgetTerminal, RoutingPreflightError, explainRanking, loadHarnessMetrics, promptFingerprint, rankHarnesses, } from "@claudexor/budget";
73
73
  import { readTextSafe, appendLine, assertNoInlineSecretValues, hashJson, newId, noProjectRepoRoot, redactSecrets, safeInvoke, sha256, userConfigDir, } from "@claudexor/util";
74
74
  const LABELS = "ABCDEFGHIJ".split("");
75
75
  const NO_PROJECT_ROOT = noProjectRepoRoot();
@@ -368,6 +368,8 @@ export class Orchestrator {
368
368
  quotaAbsences: () => this.deps.quotaAbsences?.() ?? [],
369
369
  credentialUnusable: () => this.deps.credentialUnusable?.() ?? [],
370
370
  recordCredentialUnusable: (obs) => this.deps.recordCredentialUnusable?.(obs),
371
+ credentialObserverFactory: () => this.deps.credentialObserverFactory,
372
+ credentialEvidence: () => this.deps.credentialEvidence,
371
373
  preProgressRefusals: () => this.deps.preProgressRefusals,
372
374
  authPreferenceForHarness: (repoRoot, harnessId, runPreference) => this.authPreferenceForHarness(repoRoot, harnessId, runPreference),
373
375
  });
@@ -489,9 +491,11 @@ export class Orchestrator {
489
491
  dropped.push(detail);
490
492
  droppedLanes.push({ harnessId, stage, detail });
491
493
  };
492
- // One observation set for the whole admission pass, so two lanes cannot be
493
- // judged against different vendor epochs.
494
+ // Initial lane readiness shares one quota observation. Selection and each
495
+ // physical dispatch still consume the latest exact-profile evidence.
494
496
  const vendorQuota = this.credentials.vendorQuotaObservations();
497
+ // Billing later reuses the probe that admitted each row (#260).
498
+ const admissionProbes = new AdmissionProfileProbes();
495
499
  const liveUnusable = this.deps.credentialUnusable?.() ?? [];
496
500
  for (const id of ids) {
497
501
  const adapter = this.deps.registry.get(id);
@@ -558,6 +562,7 @@ export class Orchestrator {
558
562
  // the profile's transport, so the default store's state is not the
559
563
  // routing truth). Capability/manifest gating above still applies.
560
564
  const profileAdapter = this.deps.registry.get(id);
565
+ const profileProbe = admissionProbes.record(profileAdapter?.probeCredentialProfile?.bind(profileAdapter));
561
566
  const explicitPin = this.credentials.effectiveProfileId(input, id);
562
567
  // Pins and bound/pool rows are checked against their own readiness.
563
568
  const rows = await this.credentials.admitRouteRows({
@@ -567,7 +572,7 @@ export class Orchestrator {
567
572
  model: input.models?.[id] ?? cfgEntry?.default_model ?? null,
568
573
  quota: vendorQuota,
569
574
  unusable: liveUnusable,
570
- probe: profileAdapter?.probeCredentialProfile?.bind(profileAdapter),
575
+ probe: profileProbe,
571
576
  });
572
577
  const profileAdmitted = rows.admitted;
573
578
  if (profileAdmitted) {
@@ -661,7 +666,7 @@ export class Orchestrator {
661
666
  // the default store's sources apply only to profile-less runs.
662
667
  authRouteEstimate: this.credentials.profileAuthRoute(input, id) ??
663
668
  estimateEffectiveAuthRoute(this.authPreferenceForHarness(input.repoRoot, id, input.authPreference), status.authSources),
664
- quotaAdmission: { model: null, profile: null, route: null },
669
+ quotaAdmission: { model: null, profile: null, route: null, profileVerification: null },
665
670
  supportsSynthesize: manifest.capabilities.synthesize,
666
671
  supportsInteractive: manifest.capabilities.interactive,
667
672
  liveInput: manifest.capability_profile.live_input,
@@ -706,7 +711,7 @@ export class Orchestrator {
706
711
  const model = input.models?.[routed.adapter.id] ?? routed.settings?.defaultModel ?? null;
707
712
  let profile;
708
713
  try {
709
- profile = await this.credentials.preflightProfile(input, routed.adapter.id, model, log, routed.authRouteEstimate);
714
+ profile = await this.credentials.preflightProfile(input, routed.adapter.id, model, log, routed.authRouteEstimate, admissionProbes);
710
715
  }
711
716
  catch (err) {
712
717
  // AUTO drops typed lane-local unavailability only when a sibling
@@ -730,8 +735,16 @@ export class Orchestrator {
730
735
  : routed.authRouteEstimate === "local_session"
731
736
  ? "vendor_native"
732
737
  : null;
738
+ const profileVerification = profile
739
+ ? await this.credentials.selectedProfileBillingVerification(profile, admissionProbes)
740
+ : null;
733
741
  return {
734
- prepared: { ...routed, quotaAdmission: { model, profile, route } },
742
+ prepared: {
743
+ ...routed,
744
+ quotaAdmission: { model, profile, route, profileVerification },
745
+ paidFallback: this.config(input.repoRoot).global.routing.paid_fallback,
746
+ billingVerificationForProfile: (actual) => this.credentials.selectedProfileBillingVerification(actual),
747
+ },
735
748
  refused: null,
736
749
  };
737
750
  }));
@@ -862,13 +875,14 @@ export class Orchestrator {
862
875
  // engine default. Profile A's cooldown never excludes profile B or the
863
876
  // default on the same harness and route.
864
877
  const credentialSubjectId = r.quotaAdmission.profile?.profile_id ?? null;
865
- // QA-034: the typed auth-route evidence (doctor source verification x the
866
- // resolved route) is AUTHORITATIVE for billing knowledge in the router —
867
- // a VERIFIED native route proves subscription_entitlement, so it survives
878
+ // QA-034: the typed auth-route evidence (the admitted profile's own
879
+ // verification, else doctor source verification, x the resolved route)
880
+ // is AUTHORITATIVE for billing knowledge in the router — a VERIFIED
881
+ // native route proves subscription_entitlement, so it survives
868
882
  // paid_fallback:never and ranks with a real economy tuple instead of
869
883
  // reading as unknown/paid. Absent (unknown route) falls back to the
870
884
  // metric-derived billingKnowledge below.
871
- const authRoute = this.authRouteEvidenceFor(authMode, status?.authSources ?? []);
885
+ const authRoute = authRouteEvidenceFor(authMode, status?.authSources ?? [], r.quotaAdmission.profileVerification);
872
886
  const processingCost = processingCostEvidence(r.processing, authRoute ? billingKnowledgeForAuthRoute(authRoute) : "unknown", [`harness:${r.adapter.id}`, `profile:${credentialSubjectId ?? "default"}`]);
873
887
  return {
874
888
  harnessId: r.adapter.id,
@@ -968,30 +982,6 @@ export class Orchestrator {
968
982
  },
969
983
  };
970
984
  }
971
- /**
972
- * Typed auth-route evidence for one candidate (QA-034): the concrete
973
- * credential route the resolved auth mode maps to, plus the doctor's
974
- * verification for the source that route runs under. `local_session` →
975
- * vendor_native + the native/OAuth source verification; `api_key` →
976
- * managed_api_key + the key source verification. Unknown route → no evidence
977
- * (the router keeps its conservative metric-derived billing). Verification is
978
- * the source's typed verdict — never inferred from mere availability.
979
- */
980
- authRouteEvidenceFor(authMode, sources) {
981
- const usable = (s) => s.availability === "available" && s.verification !== "failed";
982
- if (authMode === "local_session") {
983
- const native = sources.find((s) => usable(s) && (s.source === "native_session" || s.source === "oauth_token_env"));
984
- return { route: "vendor_native", verification: native?.verification ?? "not_run" };
985
- }
986
- if (authMode === "api_key") {
987
- const key = sources.find((s) => usable(s) &&
988
- (s.source === "api_key_env" ||
989
- s.source === "api_key_flag" ||
990
- s.source === "provider_auth_file"));
991
- return { route: "managed_api_key", verification: key?.verification ?? "not_run" };
992
- }
993
- return undefined;
994
- }
995
985
  /**
996
986
  * Lazy ContextPack: built ONLY for the read-only report modes
997
987
  * (explore/plan/readonly_audit) that consume it. Persisted to
@@ -1234,6 +1224,9 @@ export class Orchestrator {
1234
1224
  processing,
1235
1225
  processingAdmission,
1236
1226
  physicalDispatchStarted,
1227
+ credentialObserverFactory: this.deps.credentialObserverFactory,
1228
+ billingVerificationForProfile: (profile) => this.credentials.selectedProfileBillingVerification(profile),
1229
+ paidFallback: this.config(runInput.repoRoot).global.routing.paid_fallback,
1237
1230
  });
1238
1231
  const result = buildContinuation(req);
1239
1232
  // Disclose on every lane and stamp the turn (INV-137: never silent).
@@ -1319,7 +1312,7 @@ export class Orchestrator {
1319
1312
  const sessionFields = runInput
1320
1313
  ? await this.sessionSpecFields(runInput, adapter.id, knobs.model, log, routed.authRouteEstimate, routed.quotaAdmission)
1321
1314
  : undefined;
1322
- const processingAdmission = processingAdmissionForLease(ledger, processingLease.id, adapter.id, attemptId, processingLease.onDenied);
1315
+ const processingAdmission = processingAdmissionForLease(ledger, processingLease.lease, adapter.id, attemptId, processingLease.onDenied);
1323
1316
  const capturedProcessing = {
1324
1317
  processing_preference: contract.processing_preference,
1325
1318
  processing: knobs.processing?.receipt,
@@ -1327,7 +1320,7 @@ export class Orchestrator {
1327
1320
  processing_allow_paid: knobs.processingAllowPaid,
1328
1321
  };
1329
1322
  const laneContinuity = runInput
1330
- ? await this.resolveContinuity(runInput, adapter.id, sessionFields?.credential_profile?.profile_id ?? runInput.credentialProfileId ?? null, inPlaceEnvelope && !!sessionFields?.resume_session_id, sessionFields, store, paths, envelope.repo_root, log, capturedProcessing, processingAdmission, () => ledger.markPhysicalDispatchStarted(processingLease.id))
1323
+ ? await this.resolveContinuity(runInput, adapter.id, sessionFields?.credential_profile?.profile_id ?? runInput.credentialProfileId ?? null, inPlaceEnvelope && !!sessionFields?.resume_session_id, sessionFields, store, paths, envelope.repo_root, log, capturedProcessing, processingAdmission, () => ledger.markPhysicalDispatchStarted(processingLease.lease.lease_id))
1331
1324
  : null;
1332
1325
  const artifactRelativeDir = routed.browserRequirement.effective
1333
1326
  ? (wsm.ensureArtifactDirectory(envelope), wsm.ownedArtifactRelativeDirectory(envelope))
@@ -1372,16 +1365,12 @@ export class Orchestrator {
1372
1365
  });
1373
1366
  if (runInput)
1374
1367
  this.credentials.stampProfileSelection(spec, runInput, adapter.id);
1375
- bindProcessingAdmission(spec, ledger, processingLease.id, adapter.id, attemptId, processingLease.onDenied, processingAdmission);
1376
- const billingInput = runInput ?? { repoRoot: contract.repo.root };
1377
- // Keep billing route-bound until admission observes the actual prepared
1378
- // profile. The resolver is evaluated per physical dispatch; preparedCost
1379
- // gives an actual profile precedence over this pool fallback.
1380
- spec.extra["routeBillingKnowledge"] = (actual) => actual.credential_profile?.credential_kind === "api_key"
1381
- ? "metered"
1382
- : actual.credential_profile
1383
- ? "subscription_entitlement"
1384
- : this.routeBillingKnowledge(billingInput, adapter.id);
1368
+ bindProcessingAdmission(spec, ledger, processingLease.lease, adapter.id, attemptId, processingLease.onDenied, processingAdmission);
1369
+ // Profile-less processing keeps its existing route estimate. Named rows
1370
+ // receive their own verification at the shared physical-dispatch gate.
1371
+ spec.extra["routeBillingKnowledge"] = (actual) => actual.credential_profile
1372
+ ? "unknown"
1373
+ : this.routeBillingKnowledge(runInput ?? { repoRoot: contract.repo.root }, adapter.id);
1385
1374
  if (interaction)
1386
1375
  spec.extra["interactionChannel"] = interaction;
1387
1376
  const workEnvelope = this.workReportEnvelopeFor(routed, contract, Boolean(interaction));
@@ -1469,17 +1458,19 @@ export class Orchestrator {
1469
1458
  suspensionVersion: () => interaction?.suspensionVersion?.() ?? 0,
1470
1459
  });
1471
1460
  for await (const ev of watched) {
1472
- if (signal?.aborted)
1473
- break;
1474
1461
  rawPatch = captureRawPatchEnvelope(rawContextPacket !== null, rawPatch, ev);
1475
1462
  if (ev.type === "patch_produced")
1476
1463
  continue;
1477
1464
  const safeEv = redactHarnessEvent(ev);
1478
1465
  if (directory)
1479
1466
  observeDirectoryPaths(observedPaths, safeEv, envelope.worktree_path);
1480
- if (dropDeltaPastBudget(safeEv, deltaFlood, Orchestrator.MAX_DELTAS_PER_ATTEMPT, (t, p) => log?.emit(t, p), adapter.id, attemptId))
1481
- continue;
1482
- safeInvoke(onHarnessEvent, safeEv);
1467
+ const capped = dropDeltaPastBudget(safeEv, deltaFlood, Orchestrator.MAX_DELTAS_PER_ATTEMPT, (t, p) => log?.emit(t, p), adapter.id, attemptId);
1468
+ const display = !capped && safeEv.payload?.["buffered"] !== true;
1469
+ log?.emit("harness.event", harnessEventPayload(adapter.id, attemptId, safeEv), display);
1470
+ if (signal?.aborted)
1471
+ break;
1472
+ if (display)
1473
+ safeInvoke(onHarnessEvent, safeEv);
1483
1474
  // In-place turns run in the live tree under the native environment, so
1484
1475
  // the session they emit IS reachable for the next turn: record it. An
1485
1476
  // ISOLATED envelope-born session lives in the scoped home that dispose()
@@ -1554,7 +1545,8 @@ export class Orchestrator {
1554
1545
  // gate and required-actions read a typed category, not a bare boolean.
1555
1546
  harnessErrored = true;
1556
1547
  errors.push(safeErrorMessage(err));
1557
- if (err instanceof ProcessingBudgetAdmissionError) {
1548
+ if (err instanceof ProcessingBudgetAdmissionError ||
1549
+ err instanceof RoutingPreflightError) {
1558
1550
  processingRefusal = err;
1559
1551
  break;
1560
1552
  }
@@ -1778,6 +1770,12 @@ export class Orchestrator {
1778
1770
  estimated: costEstimated,
1779
1771
  settlement: attemptUsageCostSettlement(cost, costEstimated, attemptId, adapter.id, telemetry.authMode, telemetry.usageCost),
1780
1772
  });
1773
+ for (const path of producedFiles)
1774
+ log?.emit("output.ready", {
1775
+ kind: "artifact",
1776
+ path: `attempts/${attemptId}/produced/${path}`,
1777
+ state: "diagnostic",
1778
+ });
1781
1779
  return {
1782
1780
  attemptId,
1783
1781
  harnessId: adapter.id,
@@ -1948,7 +1946,7 @@ export class Orchestrator {
1948
1946
  attemptId,
1949
1947
  intent: this.candidateIntent(input),
1950
1948
  harnessId: routed.adapter.id,
1951
- cost: attemptCostEvidence(routed.adapter.id, attemptId, this.reservationEstimateUsd(input, i > 0), this.routeBillingKnowledge(input, routed.adapter.id), processingCostEvidence(routed.processing, this.routeBillingKnowledge(input, routed.adapter.id), [`harness:${routed.adapter.id}`])),
1949
+ cost: processingAttemptCostEvidence(routed.adapter.id, attemptId, this.reservationEstimateUsd(input, i > 0), this.routeBillingKnowledge(input, routed.adapter.id, routed), routed.processing),
1952
1950
  });
1953
1951
  log.emit("budget.lease.created", {
1954
1952
  granted: lease.granted,
@@ -1973,7 +1971,7 @@ export class Orchestrator {
1973
1971
  routed,
1974
1972
  attemptId,
1975
1973
  label: `Candidate ${LABELS[i] ?? i + 1}`,
1976
- leaseId: lease.lease?.lease_id ?? "",
1974
+ lease: lease.lease,
1977
1975
  });
1978
1976
  }
1979
1977
  const runsBySlot = new Array(slots.length);
@@ -1984,14 +1982,14 @@ export class Orchestrator {
1984
1982
  let candidateContinuationCount = 0;
1985
1983
  const runSlot = async (slot, slotIdx) => {
1986
1984
  if (input.signal?.aborted) {
1987
- ledger.cancel(slot.leaseId);
1985
+ ledger.cancel(slot.lease.lease_id);
1988
1986
  return;
1989
1987
  }
1990
1988
  // Leases are granted upfront (before spend exists); a worker still
1991
1989
  // re-checks the circuit breaker so queued slots beyond the parallel wave
1992
1990
  // do not start after earlier candidates already blew the hard cap.
1993
1991
  if (budgetStopped || ledger.tier() === "hard") {
1994
- ledger.cancel(slot.leaseId);
1992
+ ledger.cancel(slot.lease.lease_id);
1995
1993
  log.emit("budget.lease.created", {
1996
1994
  granted: false,
1997
1995
  reason: "budget exhausted (hard cap reached)",
@@ -2055,24 +2053,20 @@ export class Orchestrator {
2055
2053
  });
2056
2054
  harnessHome = this.harnessHomeFor(wsm, envelope, slot.routed, input);
2057
2055
  const run = await this.runCandidateInEnvelope(slot.routed, envelope, slot.attemptId, slot.label, contract, input.prompt, store, paths, wsm, ledger, {
2058
- id: slot.leaseId,
2056
+ lease: slot.lease,
2059
2057
  onDenied: (denial) => {
2060
2058
  budgetStopped = true;
2061
2059
  budgetDenial ??= denial;
2062
2060
  },
2063
- }, candidateAccess, (ev) => {
2064
- const safeEv = redactHarnessEvent(ev);
2065
- safeInvoke(input.onHarnessEvent, safeEv);
2066
- log.emit("harness.event", harnessEventPayload(adapter.id, slot.attemptId, safeEv));
2067
- }, input.signal, downgradeModel ?? undefined, input.effort, this.candidateIntent(input), log, effectiveWeb, this.interactionChannelFor(input, log, runId, taskId, slot.attemptId, adapter.id, slot.routed.supportsInteractive), (streamedUsd) => {
2068
- ledger.updateHold(slot.leaseId, streamedUsd);
2061
+ }, candidateAccess, input.onHarnessEvent, input.signal, downgradeModel ?? undefined, input.effort, this.candidateIntent(input), log, effectiveWeb, this.interactionChannelFor(input, log, runId, taskId, slot.attemptId, adapter.id, slot.routed.supportsInteractive), (streamedUsd) => {
2062
+ ledger.updateHold(slot.lease.lease_id, streamedUsd);
2069
2063
  if (ledger.tier() !== "hard")
2070
2064
  return false;
2071
2065
  budgetStopped = true;
2072
2066
  return true;
2073
2067
  }, input, requestedSingleCandidate, // W-C4 deltas: single-candidate chat lane only (racing = noise x N)
2074
2068
  undefined, undefined, harnessHome);
2075
- ledger.settle(slot.leaseId, attemptUsageCostSettlement(run.cost, run.costEstimated, run.attemptId, run.harnessId, run.telemetry.authMode, run.telemetry.usageCost));
2069
+ ledger.settle(slot.lease.lease_id, attemptUsageCostSettlement(run.cost, run.costEstimated, run.attemptId, run.harnessId, run.telemetry.authMode, run.telemetry.usageCost));
2076
2070
  log.emit("harness.completed", {
2077
2071
  harness_id: adapter.id,
2078
2072
  attempt_id: slot.attemptId,
@@ -2118,7 +2112,7 @@ export class Orchestrator {
2118
2112
  attemptId: contAttemptId,
2119
2113
  intent: this.candidateIntent(input),
2120
2114
  harnessId: adapter.id,
2121
- cost: attemptCostEvidence(adapter.id, contAttemptId, this.estimateUsdFloor(input.repoRoot), this.routeBillingKnowledge(input, adapter.id), processingCostEvidence(slot.routed.processing, this.routeBillingKnowledge(input, slot.routed.adapter.id), [`harness:${adapter.id}`])),
2115
+ cost: processingAttemptCostEvidence(adapter.id, contAttemptId, this.estimateUsdFloor(input.repoRoot), this.routeBillingKnowledge(input, adapter.id, slot.routed), slot.routed.processing),
2122
2116
  });
2123
2117
  if (contLease.granted) {
2124
2118
  candidateContinuationCount += 1; // claim the one-shot only once it launches
@@ -2138,16 +2132,12 @@ export class Orchestrator {
2138
2132
  const contLeaseId = contLease.lease?.lease_id ?? "";
2139
2133
  try {
2140
2134
  const contRun = await this.runCandidateInEnvelope(slot.routed, envelope, contAttemptId, slot.label, contract, input.prompt, store, paths, wsm, ledger, {
2141
- id: contLeaseId,
2135
+ lease: contLease.lease,
2142
2136
  onDenied: (denial) => {
2143
2137
  budgetStopped = true;
2144
2138
  budgetDenial ??= denial;
2145
2139
  },
2146
- }, candidateAccess, (ev) => {
2147
- const safeEv = redactHarnessEvent(ev);
2148
- safeInvoke(input.onHarnessEvent, safeEv);
2149
- log.emit("harness.event", harnessEventPayload(adapter.id, contAttemptId, safeEv));
2150
- }, input.signal, downgradeModel ?? undefined, input.effort, this.candidateIntent(input), log, effectiveWeb, this.interactionChannelFor(input, log, runId, taskId, contAttemptId, adapter.id, slot.routed.supportsInteractive), (streamedUsd) => {
2140
+ }, candidateAccess, input.onHarnessEvent, input.signal, downgradeModel ?? undefined, input.effort, this.candidateIntent(input), log, effectiveWeb, this.interactionChannelFor(input, log, runId, taskId, contAttemptId, adapter.id, slot.routed.supportsInteractive), (streamedUsd) => {
2151
2141
  ledger.updateHold(contLeaseId, streamedUsd);
2152
2142
  if (ledger.tier() !== "hard")
2153
2143
  return false;
@@ -2197,7 +2187,7 @@ export class Orchestrator {
2197
2187
  }
2198
2188
  catch (err) {
2199
2189
  const failureCost = AC.attemptFailureCost(err, "post-stream-error", 0);
2200
- ledger.settle(slot.leaseId, failureCost.settlement);
2190
+ ledger.settle(slot.lease.lease_id, failureCost.settlement);
2201
2191
  const message = safeErrorMessage(err);
2202
2192
  const declared = declaredFailure(err);
2203
2193
  const infraPhase = envelope === undefined ? "workspace" : "harness";
@@ -2251,6 +2241,16 @@ export class Orchestrator {
2251
2241
  mode,
2252
2242
  ledger,
2253
2243
  runs,
2244
+ git: input.workspaceKind !== "directory"
2245
+ ? {
2246
+ live: input.inPlace === true &&
2247
+ requestedSingleCandidate &&
2248
+ runs[0]?.reviewCwd === execRoot,
2249
+ execRoot,
2250
+ preTurnSha,
2251
+ postTurnSha: earlyPostTurnSha,
2252
+ }
2253
+ : undefined,
2254
2254
  signal: input.signal,
2255
2255
  writeTelemetry: () => this.writeRunTelemetry(store, paths, contract, runId, taskId, mode, candidateRoster(runs), null),
2256
2256
  });
@@ -2404,7 +2404,7 @@ export class Orchestrator {
2404
2404
  attemptId: "synth",
2405
2405
  intent: "synthesize",
2406
2406
  harnessId: synthRouted.adapter.id,
2407
- cost: attemptCostEvidence(synthRouted.adapter.id, "synth", this.reservationEstimateUsd(input), this.routeBillingKnowledge(input, synthRouted.adapter.id), processingCostEvidence(synthRouted.processing, this.routeBillingKnowledge(input, synthRouted.adapter.id), [`harness:${synthRouted.adapter.id}`])),
2407
+ cost: processingAttemptCostEvidence(synthRouted.adapter.id, "synth", this.reservationEstimateUsd(input), this.routeBillingKnowledge(input, synthRouted.adapter.id, synthRouted), synthRouted.processing),
2408
2408
  });
2409
2409
  if (lease.granted) {
2410
2410
  let envelope;
@@ -2431,16 +2431,12 @@ export class Orchestrator {
2431
2431
  });
2432
2432
  const synthHome = this.harnessHomeFor(wsm, envelope, synthRouted, input);
2433
2433
  const run = await this.runCandidateInEnvelope(synthRouted, envelope, "synth", "Synthesis", contract, synthesisInput.prompt, store, paths, wsm, ledger, {
2434
- id: lease.lease.lease_id,
2434
+ lease: lease.lease,
2435
2435
  onDenied: (denial) => {
2436
2436
  budgetStopped = true;
2437
2437
  budgetDenial ??= denial;
2438
2438
  },
2439
- }, candidateAccess, (ev) => {
2440
- const safeEv = redactHarnessEvent(ev);
2441
- safeInvoke(input.onHarnessEvent, safeEv);
2442
- log.emit("harness.event", harnessEventPayload(synthAdapter.id, "synth", safeEv));
2443
- }, input.signal, undefined, input.effort, "synthesize", log, effectiveWeb, this.interactionChannelFor(input, log, runId, taskId, "synth", synthAdapter.id, synthRouted.supportsInteractive), undefined, input, false, synthesisInput.content, undefined, synthHome);
2439
+ }, candidateAccess, input.onHarnessEvent, input.signal, undefined, input.effort, "synthesize", log, effectiveWeb, this.interactionChannelFor(input, log, runId, taskId, "synth", synthAdapter.id, synthRouted.supportsInteractive), undefined, input, false, synthesisInput.content, undefined, synthHome);
2444
2440
  ledger.settle(lease.lease?.lease_id ?? "", attemptUsageCostSettlement(run.cost, run.costEstimated, run.attemptId, run.harnessId, run.telemetry.authMode, run.telemetry.usageCost));
2445
2441
  reviewEnvelopes.push(envelope);
2446
2442
  envelope = undefined;
@@ -2744,6 +2740,7 @@ export class Orchestrator {
2744
2740
  pre_turn_sha: preTurnSha,
2745
2741
  post_turn_sha: postTurnSha,
2746
2742
  revert_anchor_id: revertAnchorId,
2743
+ execution_root: adopted === true ? execRoot : null,
2747
2744
  },
2748
2745
  });
2749
2746
  }
@@ -2923,6 +2920,7 @@ export class Orchestrator {
2923
2920
  reviewScoped(input) {
2924
2921
  return reviewCandidate({
2925
2922
  ...input,
2923
+ credentialObserverFactory: this.deps.credentialObserverFactory,
2926
2924
  reviewerTimeoutMs: input.reviewerTimeoutMs ?? reviewerTimeoutMs(this.config(input.cwd)),
2927
2925
  transientRetryPolicy: input.transientRetryPolicy ?? transientRetryPolicy(this.config(input.cwd)),
2928
2926
  });
@@ -3211,7 +3209,7 @@ export class Orchestrator {
3211
3209
  attemptId,
3212
3210
  intent: "repair",
3213
3211
  harnessId: adapter.id,
3214
- cost: attemptCostEvidence(adapter.id, attemptId, this.reservationEstimateUsd(input), this.routeBillingKnowledge(input, adapter.id), processingCostEvidence(routed.processing, this.routeBillingKnowledge(input, routed.adapter.id), [`harness:${adapter.id}`])),
3212
+ cost: processingAttemptCostEvidence(adapter.id, attemptId, this.reservationEstimateUsd(input), this.routeBillingKnowledge(input, adapter.id, routed), routed.processing),
3215
3213
  });
3216
3214
  if (!lease.granted) {
3217
3215
  exhausted = true;
@@ -3230,16 +3228,12 @@ export class Orchestrator {
3230
3228
  ...(knobs.ignored.length > 0 ? { ignored_settings: knobs.ignored } : {}),
3231
3229
  });
3232
3230
  run = await this.runCandidateInEnvelope(routed, envelope, attemptId, `Attempt ${attempt}`, contract, prompt, store, paths, wsm, ledger, {
3233
- id: lease.lease.lease_id,
3231
+ lease: lease.lease,
3234
3232
  onDenied: (denial) => {
3235
3233
  exhausted = true;
3236
3234
  processingBudgetDenial ??= denial;
3237
3235
  },
3238
- }, convergenceAccess, (ev) => {
3239
- const safeEv = redactHarnessEvent(ev);
3240
- safeInvoke(input.onHarnessEvent, safeEv);
3241
- log.emit("harness.event", harnessEventPayload(adapter.id, attemptId, safeEv));
3242
- }, input.signal, undefined, input.effort, "repair", log, effectiveWeb, this.interactionChannelFor(input, log, runId, taskId, attemptId, adapter.id, routed.supportsInteractive), (streamedUsd) => {
3236
+ }, convergenceAccess, input.onHarnessEvent, input.signal, undefined, input.effort, "repair", log, effectiveWeb, this.interactionChannelFor(input, log, runId, taskId, attemptId, adapter.id, routed.supportsInteractive), (streamedUsd) => {
3243
3237
  ledger.updateHold(lease.lease?.lease_id ?? "", streamedUsd);
3244
3238
  return ledger.tier() === "hard";
3245
3239
  }, input, true, // convergence runs one candidate: live deltas on (W-C4)
@@ -3300,6 +3294,20 @@ export class Orchestrator {
3300
3294
  // per attempt, so the proof is spent per attempt.
3301
3295
  assertDelegatedEvidence(input.delegated === true, convergenceAccess, [run]);
3302
3296
  attemptTelemetries.push({ attemptId, harnessId: adapter.id, telemetry: run.telemetry });
3297
+ lastPostTurnSha = null;
3298
+ // Post-mutation fence for in-place: snapshot the live tree NOW (after the
3299
+ // harness mutated it, before this attempt's review). The last attempt's
3300
+ // value is the revert target persisted into work_product.yaml.
3301
+ if (input.inPlace === true &&
3302
+ input.workspaceKind !== "directory" &&
3303
+ !run.secretDiffRefusal) {
3304
+ try {
3305
+ lastPostTurnSha = await snapshotTree(execRoot);
3306
+ }
3307
+ catch {
3308
+ lastPostTurnSha = null;
3309
+ }
3310
+ }
3303
3311
  // Cancellation/deadline keeps priority over a belt failure finalized concurrently.
3304
3312
  if (input.signal?.aborted || processingBudgetDenial)
3305
3313
  break;
@@ -3351,17 +3359,6 @@ export class Orchestrator {
3351
3359
  interrupted = true;
3352
3360
  break;
3353
3361
  }
3354
- // Post-mutation fence for in-place: snapshot the live tree NOW (after the
3355
- // harness mutated it, before this attempt's review). The last attempt's
3356
- // value is the revert target persisted into work_product.yaml.
3357
- if (input.inPlace === true && input.workspaceKind !== "directory") {
3358
- try {
3359
- lastPostTurnSha = await snapshotTree(execRoot);
3360
- }
3361
- catch {
3362
- lastPostTurnSha = null;
3363
- }
3364
- }
3365
3362
  // The review round is wrapped so a preflight/revalidation throw ends the
3366
3363
  // run TERMINALLY with artifacts instead of orphaning the run dir.
3367
3364
  let conv;
@@ -3644,6 +3641,7 @@ export class Orchestrator {
3644
3641
  pre_turn_sha: convAdopted === true ? preTurnSha : null,
3645
3642
  post_turn_sha: convAdopted === true ? lastPostTurnSha : null,
3646
3643
  revert_anchor_id: revertAnchorId,
3644
+ execution_root: convAdopted === true ? execRoot : null,
3647
3645
  },
3648
3646
  });
3649
3647
  }
@@ -3796,17 +3794,17 @@ export class Orchestrator {
3796
3794
  /** Bind private route/session preparation to the planner-attempt owner. */
3797
3795
  plannerAttemptDeps() {
3798
3796
  return {
3799
- billingKnowledge: (input, harnessId) => this.routeBillingKnowledge(input, harnessId),
3797
+ billingKnowledge: (input, harnessId, routed) => this.routeBillingKnowledge(input, harnessId, routed),
3800
3798
  inactivityTimeoutMs: (repoRoot) => harnessInactivityTimeoutMs(this.config(repoRoot)),
3801
3799
  quotaEventSink: this.deps.quotaEventSink,
3802
- prepare: async (args) => {
3800
+ prepare: async (args, processingAdmission, physicalDispatchStarted) => {
3803
3801
  const { input, contract, taskId, runId, log, store, paths, routed, attemptId } = args;
3804
3802
  const adapter = routed.adapter;
3805
3803
  const knobs = this.routeSpecKnobs(routed, contract, undefined, input.effort);
3806
3804
  const effectiveWeb = this.discloseWebUpgrade(log, routed, knobs.webPolicy, attemptId);
3807
3805
  const sessionFields = await this.sessionSpecFields(input, adapter.id, knobs.model, log, routed.authRouteEstimate, routed.quotaAdmission);
3808
3806
  const laneContinuity = args.laneRun
3809
- ? await this.resolveContinuity(input, adapter.id, sessionFields.credential_profile?.profile_id ?? input.credentialProfileId ?? null, sessionFields.resume_session_id !== null, sessionFields, store, paths, this.execRootOf(input), log)
3807
+ ? await this.resolveContinuity(input, adapter.id, sessionFields.credential_profile?.profile_id ?? input.credentialProfileId ?? null, sessionFields.resume_session_id !== null, sessionFields, store, paths, this.execRootOf(input), log, this.harnessSpecKnobs(contract, knobs, args.intent), processingAdmission, physicalDispatchStarted)
3810
3808
  : null;
3811
3809
  const spec = HarnessRunSpec.parse({
3812
3810
  session_id: newId("ses"),
@@ -3995,13 +3993,7 @@ export class Orchestrator {
3995
3993
  // terminal names the refused route and does not read "all planners
3996
3994
  // failed"; capture the typed denial for the budget classifier.
3997
3995
  planBudgetDenial ??= outcome.budgetDenial ?? null;
3998
- planAttempts.push({
3999
- attemptId,
4000
- harnessId: outcome.harnessId,
4001
- status: outcome.status,
4002
- outcomeClass: outcome.outcomeClass,
4003
- error: outcome.error,
4004
- });
3996
+ planAttempts.push(plannerAttemptSummary(outcome));
4005
3997
  break;
4006
3998
  }
4007
3999
  if (outcome.telemetry)
@@ -4010,13 +4002,7 @@ export class Orchestrator {
4010
4002
  harnessId: outcome.harnessId,
4011
4003
  telemetry: outcome.telemetry,
4012
4004
  });
4013
- planAttempts.push({
4014
- attemptId,
4015
- harnessId: outcome.harnessId,
4016
- status: outcome.status,
4017
- outcomeClass: outcome.outcomeClass,
4018
- error: outcome.error,
4019
- });
4005
+ planAttempts.push(plannerAttemptSummary(outcome));
4020
4006
  if (outcome.status !== "success") {
4021
4007
  if (outcome.telemetry?.effortResolution?.resolution === "rejected")
4022
4008
  break;
@@ -4141,7 +4127,13 @@ export class Orchestrator {
4141
4127
  quotaSnapshotPreflight() {
4142
4128
  return [...(this.deps.quotaSnapshots?.() ?? [])].map((snapshot) => QuotaSnapshotSchema.parse(snapshot));
4143
4129
  }
4144
- routeBillingKnowledge(input, harnessId) {
4130
+ routeBillingKnowledge(input, harnessId, routed) {
4131
+ if (routed?.quotaAdmission.profile) {
4132
+ return billingKnowledgeForAuthRoute({
4133
+ route: routed.quotaAdmission.route,
4134
+ verification: routed.quotaAdmission.profileVerification ?? "not_run",
4135
+ });
4136
+ }
4145
4137
  // A selected profile's credential_kind decides billing (round-18 #2).
4146
4138
  const profileRoute = this.credentials.profileAuthRoute(input, harnessId);
4147
4139
  if (profileRoute)
@@ -4173,9 +4165,7 @@ export class Orchestrator {
4173
4165
  // The reducer admits under a finite estimate floor (mirror of the n>1
4174
4166
  // scout reserve) so a subscription route is not refused for lacking a
4175
4167
  // cash quote.
4176
- attemptCostEvidence(harnessId, attemptId, this.estimateUsdFloor(input.repoRoot), this.routeBillingKnowledge(input, harnessId), processingCostEvidence(routed?.processing, this.routeBillingKnowledge(input, harnessId), [
4177
- `harness:${harnessId}`,
4178
- ])),
4168
+ processingAttemptCostEvidence(harnessId, attemptId, this.estimateUsdFloor(input.repoRoot), this.routeBillingKnowledge(input, harnessId, routed), routed?.processing),
4179
4169
  buildSpec: async (routed, homeEnv, prompt, attemptId) => {
4180
4170
  const knobs = this.routeSpecKnobs(routed, contract, undefined, input.effort);
4181
4171
  const effectiveWeb = this.discloseWebUpgrade(log, routed, knobs.webPolicy, attemptId);
@@ -4349,7 +4339,7 @@ export class Orchestrator {
4349
4339
  // (mirror of the candidate loop): the first top-level scout reserves
4350
4340
  // without a floor; later scouts and every real Delegate child pass the
4351
4341
  // repo floor because they overlap an existing family unit.
4352
- cost: attemptCostEvidence(adapter.id, attemptId, this.reservationEstimateUsd(input, opts.deepScan && idx > 0), this.routeBillingKnowledge(input, adapter.id), processingCostEvidence(routed.processing, this.routeBillingKnowledge(input, routed.adapter.id), [`harness:${adapter.id}`])),
4342
+ cost: processingAttemptCostEvidence(adapter.id, attemptId, this.reservationEstimateUsd(input, opts.deepScan && idx > 0), this.routeBillingKnowledge(input, adapter.id, routed), routed.processing),
4353
4343
  });
4354
4344
  if (!lease.granted) {
4355
4345
  log.emit("budget.lease.created", {
@@ -4378,6 +4368,10 @@ export class Orchestrator {
4378
4368
  }
4379
4369
  return { status: "budget_denied", reason: lease.reason ?? "budget lease denied" };
4380
4370
  }
4371
+ const processingAdmission = processingAdmissionForLease(ledger, lease.lease, adapter.id, attemptId, (denial) => {
4372
+ budgetStopped = true;
4373
+ budgetDenial ??= denial;
4374
+ });
4381
4375
  // As with planners, the granted lease owns profile/continuity/spec
4382
4376
  // preparation. Contain a pre-stream rejection as this attempt's failure;
4383
4377
  // parallel siblings can then finish before the shared HOME is disposed.
@@ -4398,7 +4392,7 @@ export class Orchestrator {
4398
4392
  // scouts are excluded from laneRun); native resume is available only when
4399
4393
  // this slot was granted the lane's recorded session.
4400
4394
  const laneContinuity = laneRun
4401
- ? await this.resolveContinuity(input, adapter.id, sessionFields.credential_profile?.profile_id ?? input.credentialProfileId ?? null, grantResume, sessionFields, store, paths, this.execRootOf(input), log)
4395
+ ? await this.resolveContinuity(input, adapter.id, sessionFields.credential_profile?.profile_id ?? input.credentialProfileId ?? null, grantResume, sessionFields, store, paths, this.execRootOf(input), log, this.harnessSpecKnobs(contract, knobs, opts.intent), processingAdmission, () => ledger.markPhysicalDispatchStarted(lease.lease.lease_id))
4402
4396
  : null;
4403
4397
  // D-16d: the continuation packet pointer rides after the lane pointer so
4404
4398
  // the fresh session is re-grounded in the exhausted attempt's work.
@@ -4457,7 +4451,7 @@ export class Orchestrator {
4457
4451
  const message = `read-only attempt setup failed: ${safeErrorMessage(preparation.error)}`;
4458
4452
  AC.settleGrantedAttemptLease({
4459
4453
  ledger,
4460
- leaseId: lease.lease?.lease_id ?? "",
4454
+ leaseId: lease.lease.lease_id,
4461
4455
  attemptId,
4462
4456
  harnessId: adapter.id,
4463
4457
  costUsd: 0,
@@ -4490,10 +4484,7 @@ export class Orchestrator {
4490
4484
  const { knobs, spec: preparedSpec, reportAbort, reportInteraction, readonlyWorkMode, attemptEventsPath, telemetry, } = preparation.value;
4491
4485
  let { answer } = preparation.value;
4492
4486
  let spec = preparedSpec;
4493
- bindProcessingAdmission(spec, ledger, lease.lease.lease_id, adapter.id, attemptId, (denial) => {
4494
- budgetStopped = true;
4495
- budgetDenial ??= denial;
4496
- });
4487
+ bindProcessingAdmission(spec, ledger, lease.lease, adapter.id, attemptId, undefined, processingAdmission);
4497
4488
  const retryPolicy = transientRetryPolicy(this.config(input.repoRoot));
4498
4489
  let activeSessionId = spec.session_id;
4499
4490
  const live = liveAttempt(input, routed, paths, contract, attemptId, () => activeSessionId);
@@ -4552,10 +4543,9 @@ export class Orchestrator {
4552
4543
  suspensionVersion: () => reportInteraction?.suspensionVersion?.() ?? 0,
4553
4544
  });
4554
4545
  for await (const ev of watchedReport) {
4555
- if (input.signal?.aborted)
4556
- break;
4557
4546
  const safeEv = redactHarnessEvent(ev);
4558
- safeInvoke(input.onHarnessEvent, safeEv);
4547
+ if (safeEv.payload?.["buffered"] !== true)
4548
+ safeInvoke(input.onHarnessEvent, safeEv);
4559
4549
  // A thread ASK turn IS a chat turn now (INV-034): its native
4560
4550
  // session lives in the DURABLE per-lane home, so record it for the
4561
4551
  // next lane turn's resume. The read-only fallback chain is
@@ -4565,8 +4555,10 @@ export class Orchestrator {
4565
4555
  if (laneRun)
4566
4556
  observeNativeSessionEvent(input, adapter.id, safeEv);
4567
4557
  observeAuthSwitch(log, adapter.id, attemptId, safeEv);
4568
- log.emit("harness.event", harnessEventPayload(adapter.id, attemptId, safeEv));
4558
+ log.emit("harness.event", harnessEventPayload(adapter.id, attemptId, safeEv), safeEv.payload?.["buffered"] !== true);
4569
4559
  appendLine(attemptEventsPath, JSON.stringify(safeEv));
4560
+ if (input.signal?.aborted)
4561
+ break;
4570
4562
  observeAttemptTelemetry(telemetry, safeEv);
4571
4563
  emitPlanProgress((t, p) => log.emit(t, p), adapter.id, attemptId, safeEv);
4572
4564
  // read-only routes burn quota too (the orchestrate PLANNER is
@@ -4595,7 +4587,8 @@ export class Orchestrator {
4595
4587
  }
4596
4588
  catch (err) {
4597
4589
  harnessError = safeErrorMessage(err);
4598
- if (err instanceof ProcessingBudgetAdmissionError) {
4590
+ if (err instanceof ProcessingBudgetAdmissionError ||
4591
+ err instanceof RoutingPreflightError) {
4599
4592
  processingRefusal = err;
4600
4593
  break;
4601
4594
  }
@@ -4676,7 +4669,7 @@ export class Orchestrator {
4676
4669
  input.signal?.removeEventListener("abort", onAbort);
4677
4670
  AC.settleGrantedAttemptLease({
4678
4671
  ledger,
4679
- leaseId: lease.lease?.lease_id ?? "",
4672
+ leaseId: lease.lease.lease_id,
4680
4673
  attemptId,
4681
4674
  harnessId: adapter.id,
4682
4675
  costUsd: cost,
@@ -4962,14 +4955,6 @@ export class Orchestrator {
4962
4955
  fallbackOpen = false;
4963
4956
  }
4964
4957
  const partialReport = [...attempts].reverse().find((a) => a.report)?.report ?? "";
4965
- if (partialReport) {
4966
- store.writeText(join(paths.finalDir, opts.artifactName), `# ${opts.title}\n\n> Unverified partial output. The run is ${webBlocked ? "blocked" : "failed"} because a required/attempted tool failed.\n\n${partialReport}\n`);
4967
- log.emit("output.ready", {
4968
- kind: opts.mode === "ask" ? "answer" : "report",
4969
- path: `final/${opts.artifactName}`,
4970
- state: "diagnostic",
4971
- });
4972
- }
4973
4958
  this.writeRunTelemetry(store, paths, contract, runId, taskId, opts.mode, attemptTelemetries, null);
4974
4959
  store.writeText(join(paths.contextDir, "context_error.md"), `# ${budgetMapping ? "Budget Denied" : "Harness Error"}\n\n${singleError}\n`);
4975
4960
  const roEventRefs = attempts.map((a) => `attempts/${a.attemptId}/events.jsonl`);