@claudexor/orchestrator 3.0.3 → 3.1.0

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 (65) hide show
  1. package/LICENSE +1 -1
  2. package/dist/attemptFinalize.d.ts +162 -0
  3. package/dist/attemptFinalize.d.ts.map +1 -0
  4. package/dist/attemptFinalize.js +368 -0
  5. package/dist/attemptFinalize.js.map +1 -0
  6. package/dist/attemptTelemetry.d.ts +88 -7
  7. package/dist/attemptTelemetry.d.ts.map +1 -1
  8. package/dist/attemptTelemetry.js +276 -14
  9. package/dist/attemptTelemetry.js.map +1 -1
  10. package/dist/budgetFailure.d.ts +70 -0
  11. package/dist/budgetFailure.d.ts.map +1 -0
  12. package/dist/budgetFailure.js +114 -0
  13. package/dist/budgetFailure.js.map +1 -0
  14. package/dist/candidateEvidence.d.ts +55 -1
  15. package/dist/candidateEvidence.d.ts.map +1 -1
  16. package/dist/candidateEvidence.js +72 -0
  17. package/dist/candidateEvidence.js.map +1 -1
  18. package/dist/continuation.d.ts +77 -0
  19. package/dist/continuation.d.ts.map +1 -0
  20. package/dist/continuation.js +92 -0
  21. package/dist/continuation.js.map +1 -0
  22. package/dist/deepScanReducer.d.ts +148 -0
  23. package/dist/deepScanReducer.d.ts.map +1 -0
  24. package/dist/deepScanReducer.js +352 -0
  25. package/dist/deepScanReducer.js.map +1 -0
  26. package/dist/harnessFailure.d.ts +27 -0
  27. package/dist/harnessFailure.d.ts.map +1 -0
  28. package/dist/harnessFailure.js +61 -0
  29. package/dist/harnessFailure.js.map +1 -0
  30. package/dist/orchestrator.d.ts +97 -10
  31. package/dist/orchestrator.d.ts.map +1 -1
  32. package/dist/orchestrator.js +1213 -295
  33. package/dist/orchestrator.js.map +1 -1
  34. package/dist/planQuestions.d.ts.map +1 -1
  35. package/dist/planQuestions.js +105 -50
  36. package/dist/planQuestions.js.map +1 -1
  37. package/dist/planRun.d.ts +15 -7
  38. package/dist/planRun.d.ts.map +1 -1
  39. package/dist/planRun.js +88 -42
  40. package/dist/planRun.js.map +1 -1
  41. package/dist/planTerminal.d.ts +36 -0
  42. package/dist/planTerminal.d.ts.map +1 -0
  43. package/dist/planTerminal.js +63 -0
  44. package/dist/planTerminal.js.map +1 -0
  45. package/dist/runSupport.d.ts +50 -2
  46. package/dist/runSupport.d.ts.map +1 -1
  47. package/dist/runSupport.js +60 -6
  48. package/dist/runSupport.js.map +1 -1
  49. package/dist/runTelemetryWriter.d.ts +6 -1
  50. package/dist/runTelemetryWriter.d.ts.map +1 -1
  51. package/dist/runTelemetryWriter.js +2 -0
  52. package/dist/runTelemetryWriter.js.map +1 -1
  53. package/dist/runTerminals.d.ts +15 -4
  54. package/dist/runTerminals.d.ts.map +1 -1
  55. package/dist/runTerminals.js +16 -1
  56. package/dist/runTerminals.js.map +1 -1
  57. package/dist/structuredOutput.d.ts +27 -0
  58. package/dist/structuredOutput.d.ts.map +1 -1
  59. package/dist/structuredOutput.js +65 -7
  60. package/dist/structuredOutput.js.map +1 -1
  61. package/dist/transientClassify.d.ts +59 -0
  62. package/dist/transientClassify.d.ts.map +1 -0
  63. package/dist/transientClassify.js +109 -0
  64. package/dist/transientClassify.js.map +1 -0
  65. package/package.json +17 -17
@@ -0,0 +1,148 @@
1
+ import type { CostEvidence, DeepScanSynthesis, ExternalContextPolicy, HarnessEvent, HarnessRunSpec } from "@claudexor/schema";
2
+ import { type BudgetLedger } from "@claudexor/budget";
3
+ import type { RunPaths } from "@claudexor/artifact-store";
4
+ import type { EventLog } from "@claudexor/event-log";
5
+ import { type BudgetDenial } from "./budgetFailure.js";
6
+ import type { RoutedAdapter } from "./orchestrator.js";
7
+ import { type WorkReportEnvelopeMode } from "./attemptFinalize.js";
8
+ import { type AttemptTelemetry } from "./attemptTelemetry.js";
9
+ /** The reducer runs under the fixed `synth` attempt id (roster/cost visible). */
10
+ export declare const DEEP_SCAN_REDUCER_ATTEMPT_ID = "synth";
11
+ /**
12
+ * #27 / D-6: the HONEST fallback artifact for a deep scan whose bounded
13
+ * synthesis reducer did not run or did not succeed. It is explicitly labeled a
14
+ * raw scout bundle (a marker heading), never presented as a merged synthesis:
15
+ * the per-scout reports are concatenated verbatim with attribution, the roster
16
+ * denominator stays honest, and omissions are preserved. `skipped` (a single
17
+ * width-1 report) and `failed` (reducer error/timeout/budget-denial or no
18
+ * synthesize-capable route) get distinct honest intros.
19
+ */
20
+ export declare function rawScoutBundle(args: {
21
+ succeeded: {
22
+ attemptId: string;
23
+ harnessId: string;
24
+ report: string;
25
+ telemetry: AttemptTelemetry;
26
+ }[];
27
+ unsuccessful: {
28
+ attemptId: string;
29
+ harnessId: string;
30
+ status: string;
31
+ error: string | null;
32
+ }[];
33
+ status: DeepScanSynthesis | null;
34
+ }): string;
35
+ /** A disposable read-only route context (env + reclaim). */
36
+ export interface ReducerHome {
37
+ env: Record<string, string>;
38
+ dispose: () => void;
39
+ }
40
+ /** The engine-owned bits the reducer needs. `buildSpec` keeps the orchestrator's
41
+ * private route/session/knob machinery on the caller side and hands back only a
42
+ * finished, public `HarnessRunSpec` plus the disclosed web policy/model, so this
43
+ * module stays free of those private types (mirrors the council extraction). */
44
+ export interface DeepScanReducerDeps {
45
+ /** Provision a fresh disposable read-only home (auth is home-independent). */
46
+ newReadOnlyHome: () => ReducerHome;
47
+ /** Per-attempt budget cost evidence (finite estimate floor + billing knowledge). */
48
+ costEvidence: (harnessId: string, attemptId: string) => CostEvidence;
49
+ /** Build the finished readonly/synthesize spec bound to the reducer home. */
50
+ buildSpec: (routed: RoutedAdapter, homeEnv: Record<string, string>, prompt: string, attemptId: string) => {
51
+ spec: HarnessRunSpec;
52
+ webPolicy: ExternalContextPolicy;
53
+ effectiveWeb: ExternalContextPolicy;
54
+ model: string | null;
55
+ /** D-16: the WorkReport transport mode compiled onto the reducer spec, so the
56
+ * reducer output is unwrapped + finalized through the SAME contract as every
57
+ * other attempt (never a fourth divergent deliverable predicate). Inactive on
58
+ * a route with no work_report transport (the report passes through untouched). */
59
+ workReportMode: WorkReportEnvelopeMode;
60
+ };
61
+ /** Hard (total) timeout for the single bounded pass. */
62
+ hardTimeoutMs: number;
63
+ /** Inactivity watchdog timeout (shared with the scout lane). */
64
+ inactivityTimeoutMs: number;
65
+ /** Whether the run's contract requires web evidence (telemetry seed). */
66
+ webRequired: boolean;
67
+ /** Optional quota event sink (same owner as the agent loop). */
68
+ quotaEventSink?: (harnessId: string, ev: HarnessEvent) => void;
69
+ }
70
+ export interface DeepScanReducerArgs {
71
+ taskId: string;
72
+ goal: string;
73
+ routed: RoutedAdapter;
74
+ scoutReports: {
75
+ attemptId: string;
76
+ harnessId: string;
77
+ absPath: string;
78
+ }[];
79
+ ledger: BudgetLedger;
80
+ log: EventLog;
81
+ paths: RunPaths;
82
+ signal?: AbortSignal;
83
+ onHarnessEvent?: (ev: HarnessEvent) => void;
84
+ attemptTelemetries: {
85
+ attemptId: string;
86
+ harnessId: string;
87
+ telemetry: AttemptTelemetry;
88
+ }[];
89
+ }
90
+ export type DeepScanReducerResult = {
91
+ status: "success";
92
+ report: string;
93
+ } | {
94
+ status: "failed";
95
+ error: string;
96
+ } | {
97
+ status: "budget_denied";
98
+ denial: BudgetDenial;
99
+ } | {
100
+ status: "cancelled";
101
+ };
102
+ /**
103
+ * #27 / D-6: the deep-scan bounded synthesis reducer. After the scouts finish,
104
+ * ONE synthesize-intent attempt merges the raw scout reports into a real
105
+ * synthesis. It is READ-ONLY and file-backed (the scout report files are pointed
106
+ * at by absolute path — the argv-size law: reports ride a file, never argv),
107
+ * reserves a budget lease like any attempt, and is bounded by a hard timeout. Its
108
+ * telemetry is pushed to the run roster (cost/route visible). On
109
+ * failure/timeout/budget-denial the caller degrades to an HONEST raw bundle; this
110
+ * function never fabricates a synthesis.
111
+ */
112
+ export declare function runDeepScanReducer(deps: DeepScanReducerDeps, args: DeepScanReducerArgs): Promise<DeepScanReducerResult>;
113
+ /**
114
+ * #27 / D-6: decide the deep-scan synthesis outcome and, when warranted, run the
115
+ * bounded reducer. Returns the typed `DeepScanSynthesis` telemetry status plus
116
+ * the merged report (non-null only on a clean reducer success; the caller writes
117
+ * an honest raw bundle otherwise). A width-1 (single-report) scan skips the
118
+ * reducer; a budget-stopped/cancelled scan degrades without spending on a merge;
119
+ * a scan with no synthesize-capable route degrades honestly.
120
+ */
121
+ export declare function resolveDeepScanSynthesis(deps: DeepScanReducerDeps, args: {
122
+ succeeded: {
123
+ attemptId: string;
124
+ harnessId: string;
125
+ report: string;
126
+ telemetry: AttemptTelemetry;
127
+ }[];
128
+ adapters: RoutedAdapter[];
129
+ budgetStopped: boolean;
130
+ aborted: boolean;
131
+ taskId: string;
132
+ goal: string;
133
+ findingsDir: string;
134
+ ledger: BudgetLedger;
135
+ log: EventLog;
136
+ paths: RunPaths;
137
+ signal?: AbortSignal;
138
+ onHarnessEvent?: (ev: HarnessEvent) => void;
139
+ attemptTelemetries: {
140
+ attemptId: string;
141
+ harnessId: string;
142
+ telemetry: AttemptTelemetry;
143
+ }[];
144
+ }): Promise<{
145
+ deepScanSynthesis: DeepScanSynthesis;
146
+ reducedReport: string | null;
147
+ }>;
148
+ //# sourceMappingURL=deepScanReducer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deepScanReducer.d.ts","sourceRoot":"","sources":["../src/deepScanReducer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,352 @@
1
+ import { join } from "node:path";
2
+ import { attemptUsageCostSettlement } from "@claudexor/budget";
3
+ import { AnswerAssembly, withInactivityWatchdog } from "@claudexor/core";
4
+ import { appendLine, redactSecrets, safeInvoke } from "@claudexor/util";
5
+ import { buildDeepScanReducerPrompt } from "@claudexor/synthesis";
6
+ import { classifyBudgetFailure } from "./budgetFailure.js";
7
+ import { finalizeAttempt, unwrapWorkReportEnvelope, } from "./attemptFinalize.js";
8
+ import { redactHarnessEvent, harnessEventPayload, observeBudgetSignals } from "./runSupport.js";
9
+ import { createAttemptTelemetry, observeAttemptTelemetry, setAttemptOutcome, telemetrySummary, toolWarnings, } from "./attemptTelemetry.js";
10
+ /** Redacted error message (mirrors the orchestrator's module-local helper). */
11
+ function safeErrorMessage(err) {
12
+ return redactSecrets(err instanceof Error ? err.message : String(err));
13
+ }
14
+ /** The reducer runs under the fixed `synth` attempt id (roster/cost visible). */
15
+ export const DEEP_SCAN_REDUCER_ATTEMPT_ID = "synth";
16
+ /**
17
+ * #27 / D-6: the HONEST fallback artifact for a deep scan whose bounded
18
+ * synthesis reducer did not run or did not succeed. It is explicitly labeled a
19
+ * raw scout bundle (a marker heading), never presented as a merged synthesis:
20
+ * the per-scout reports are concatenated verbatim with attribution, the roster
21
+ * denominator stays honest, and omissions are preserved. `skipped` (a single
22
+ * width-1 report) and `failed` (reducer error/timeout/budget-denial or no
23
+ * synthesize-capable route) get distinct honest intros.
24
+ */
25
+ export function rawScoutBundle(args) {
26
+ const total = args.succeeded.length + args.unsuccessful.length;
27
+ const intro = args.status?.status === "skipped"
28
+ ? [
29
+ "## Raw scout report (single scout — no merge needed)",
30
+ "",
31
+ "Only one scout produced a report, so no synthesis reducer was run.",
32
+ ]
33
+ : [
34
+ "## Raw scout bundle — NOT a merged synthesis",
35
+ "",
36
+ `The bounded synthesis reducer did not produce a merge (${args.status?.reason ?? "synthesis unavailable"}). The scout reports below are raw and unmerged; claims are not deduplicated and disagreements are not reconciled.`,
37
+ ];
38
+ return [
39
+ ...intro,
40
+ "",
41
+ `Explorers succeeded: ${args.succeeded.length}/${total}.`,
42
+ "",
43
+ "## Scout reports (raw, not merged)",
44
+ ...args.succeeded.map((a) => {
45
+ const warnings = toolWarnings(a.telemetry);
46
+ const warningText = warnings.length
47
+ ? `\n\n> Tool warnings: ${warnings.map((e) => `${e.tool}: ${e.summary}`).join("; ")}`
48
+ : "";
49
+ return `\n### ${a.attemptId} / ${a.harnessId}\n\n${a.report}${warningText}`;
50
+ }),
51
+ "",
52
+ "## Omissions / Uncertainty",
53
+ ...(args.unsuccessful.length
54
+ ? args.unsuccessful.map((a) => `- ${a.attemptId} / ${a.harnessId} ${a.status}: ${a.error}`)
55
+ : [
56
+ "- No explorer failures recorded. Claims still need evidence review before edit execution.",
57
+ ]),
58
+ ].join("\n");
59
+ }
60
+ /**
61
+ * #27 / D-6: the deep-scan bounded synthesis reducer. After the scouts finish,
62
+ * ONE synthesize-intent attempt merges the raw scout reports into a real
63
+ * synthesis. It is READ-ONLY and file-backed (the scout report files are pointed
64
+ * at by absolute path — the argv-size law: reports ride a file, never argv),
65
+ * reserves a budget lease like any attempt, and is bounded by a hard timeout. Its
66
+ * telemetry is pushed to the run roster (cost/route visible). On
67
+ * failure/timeout/budget-denial the caller degrades to an HONEST raw bundle; this
68
+ * function never fabricates a synthesis.
69
+ */
70
+ export async function runDeepScanReducer(deps, args) {
71
+ const { ledger, log, paths } = args;
72
+ const attemptId = DEEP_SCAN_REDUCER_ATTEMPT_ID;
73
+ const adapter = args.routed.adapter;
74
+ log.emit("synthesis.started", {
75
+ synthesize: true,
76
+ reason: `deep-scan reducer over ${args.scoutReports.length} scout reports`,
77
+ });
78
+ const lease = ledger.reserve({
79
+ taskId: args.taskId,
80
+ attemptId,
81
+ intent: "synthesize",
82
+ harnessId: adapter.id,
83
+ cost: deps.costEvidence(adapter.id, attemptId),
84
+ });
85
+ if (!lease.granted) {
86
+ log.emit("budget.lease.created", {
87
+ granted: false,
88
+ reason: lease.reason,
89
+ denied: lease.denied,
90
+ attempt_id: attemptId,
91
+ harness_id: adapter.id,
92
+ });
93
+ return {
94
+ status: "budget_denied",
95
+ denial: {
96
+ code: lease.denied ?? "hard_cap",
97
+ reason: lease.reason ?? "budget lease denied",
98
+ harnessId: adapter.id,
99
+ attemptId,
100
+ },
101
+ };
102
+ }
103
+ // A fresh disposable read-only home: the scouts' shared route context was
104
+ // already disposed, and auth truth is home-independent (credentials come from
105
+ // the profile/keychain/default store), so a fresh home shares the auth source.
106
+ const reducerHome = deps.newReadOnlyHome();
107
+ const prompt = buildDeepScanReducerPrompt(args.goal, args.scoutReports);
108
+ const built = deps.buildSpec(args.routed, reducerHome.env, prompt, attemptId);
109
+ const spec = built.spec;
110
+ // Hard (total) timeout — one attempt, no failover/transient retry loop.
111
+ const reducerAbort = new AbortController();
112
+ let timedOut = false;
113
+ const hardTimer = setTimeout(() => {
114
+ timedOut = true;
115
+ reducerAbort.abort();
116
+ void adapter.cancel?.(spec.session_id)?.catch(() => { });
117
+ }, deps.hardTimeoutMs);
118
+ spec.extra["abortSignal"] = args.signal
119
+ ? AbortSignal.any([args.signal, reducerAbort.signal])
120
+ : reducerAbort.signal;
121
+ const telemetry = createAttemptTelemetry(built.webPolicy, deps.webRequired || built.webPolicy === "cached" || built.webPolicy === "live", built.effectiveWeb, [], built.model);
122
+ const answer = new AnswerAssembly();
123
+ const attemptEventsPath = join(paths.attemptsDir, attemptId, "events.jsonl");
124
+ const budgetSignalState = { quotaPressureDisclosed: false };
125
+ let cost = 0;
126
+ let costEstimated = false;
127
+ let harnessError = null;
128
+ log.emit("harness.started", {
129
+ harness_id: adapter.id,
130
+ attempt_id: attemptId,
131
+ external_context_policy: built.webPolicy,
132
+ });
133
+ try {
134
+ const watched = withInactivityWatchdog(adapter.run(spec), {
135
+ timeoutMs: deps.inactivityTimeoutMs,
136
+ onTimeout: () => {
137
+ reducerAbort.abort();
138
+ void adapter.cancel?.(spec.session_id)?.catch(() => { });
139
+ },
140
+ isSuspended: () => false,
141
+ });
142
+ for await (const ev of watched) {
143
+ if (reducerAbort.signal.aborted)
144
+ break;
145
+ const safeEv = redactHarnessEvent(ev);
146
+ safeInvoke(args.onHarnessEvent, safeEv);
147
+ log.emit("harness.event", harnessEventPayload(adapter.id, attemptId, safeEv));
148
+ appendLine(attemptEventsPath, JSON.stringify(safeEv));
149
+ observeAttemptTelemetry(telemetry, safeEv);
150
+ observeBudgetSignals(ledger, log, adapter.id, attemptId, safeEv, budgetSignalState);
151
+ deps.quotaEventSink?.(adapter.id, safeEv);
152
+ if (safeEv.type === "usage" && safeEv.usage?.cost_usd) {
153
+ cost += safeEv.usage.cost_usd;
154
+ if (safeEv.usage.estimated)
155
+ costEstimated = true;
156
+ log.emit("budget.observation", {
157
+ harness_id: adapter.id,
158
+ attempt_id: attemptId,
159
+ kind: "spend",
160
+ usd: safeEv.usage.cost_usd,
161
+ estimated: safeEv.usage.estimated === true,
162
+ });
163
+ }
164
+ answer.observe(safeEv);
165
+ if (safeEv.type === "error")
166
+ harnessError = safeEv.error ? redactSecrets(safeEv.error) : "harness emitted an error";
167
+ }
168
+ }
169
+ catch (err) {
170
+ harnessError = safeErrorMessage(err);
171
+ }
172
+ finally {
173
+ clearTimeout(hardTimer);
174
+ reducerHome.dispose();
175
+ ledger.settle(lease.lease?.lease_id ?? "", attemptUsageCostSettlement(cost, costEstimated, attemptId, adapter.id, telemetry.authMode, telemetry.usageCost));
176
+ }
177
+ // D-16: unwrap the WorkReport envelope and finalize through the SAME contract as
178
+ // every other attempt — a capable reducer route that broke its WorkReport
179
+ // contract (or reported needs_input/incomplete/context-exhausted) must NEVER be
180
+ // accepted as a clean synthesis; the caller then degrades to an honest raw
181
+ // bundle. On an inactive-transport route the unwrap passes the report through
182
+ // untouched (unchanged behavior for schema-free reducer harnesses).
183
+ const unwrapped = unwrapWorkReportEnvelope(answer.machineText() ?? "", built.workReportMode, {
184
+ sideToolReport: telemetry.sideToolWorkReport ?? undefined,
185
+ });
186
+ const report = redactSecrets(unwrapped.deliverable);
187
+ const finalized = finalizeAttempt({
188
+ deliverableEvidence: report.trim().length > 0,
189
+ harnessErrored: harnessError !== null,
190
+ workReport: unwrapped.workReport,
191
+ workReportSource: unwrapped.source,
192
+ workReportViolation: unwrapped.contractViolation,
193
+ contextTerminalExhausted: telemetry.contextExhausted,
194
+ });
195
+ if (timedOut && !harnessError)
196
+ harnessError = `deep-scan reducer timed out after ${deps.hardTimeoutMs}ms`;
197
+ // A reducer must produce a CLEAN merged synthesis: a broken WorkReport contract,
198
+ // a needs_input/incomplete attestation, or a terminal context exhaustion is a
199
+ // typed reducer failure (degrade to the raw bundle), never a laundered success.
200
+ if (!harnessError && finalized.outcomeClass === "contract_failure") {
201
+ harnessError = `deep-scan reducer work_report contract: ${unwrapped.contractViolation}`;
202
+ }
203
+ else if (!harnessError && finalized.outcomeClass === "veto") {
204
+ harnessError = `deep-scan reducer reported ${finalized.workState.state} instead of a merged synthesis`;
205
+ }
206
+ else if (!harnessError && finalized.outcomeClass === "interrupted") {
207
+ harnessError = "deep-scan reducer ran out of context before completing the synthesis";
208
+ }
209
+ const reportPresent = finalized.deliverablePresent && report.trim().length > 0;
210
+ if (!harnessError && !reportPresent)
211
+ harnessError = "deep-scan reducer produced no synthesis";
212
+ // INV-116: a cancel on the OUTER run signal that landed WHILE this bounded
213
+ // reducer streamed is a cancellation — not a clean synthesis and not a typed
214
+ // failure. Any partial output is discarded (deliverablePresent forced false)
215
+ // so it can never be accepted as a merge, and the run terminalizes cancelled.
216
+ const runCancelled = args.signal?.aborted === true;
217
+ setAttemptOutcome(telemetry, {
218
+ deliverablePresent: reportPresent && !runCancelled,
219
+ gatesPassed: null,
220
+ harnessErrored: harnessError !== null || runCancelled,
221
+ webRequiredUnsatisfied: false,
222
+ workState: finalized.workState,
223
+ });
224
+ // Roster/cost visible: the reducer is a normal attempt in run telemetry.
225
+ args.attemptTelemetries.push({ attemptId, harnessId: adapter.id, telemetry });
226
+ if (runCancelled) {
227
+ log.emit("harness.completed", {
228
+ harness_id: adapter.id,
229
+ attempt_id: attemptId,
230
+ status: "cancelled",
231
+ ...telemetrySummary(telemetry),
232
+ });
233
+ return { status: "cancelled" };
234
+ }
235
+ if (harnessError) {
236
+ log.emit("harness.completed", {
237
+ harness_id: adapter.id,
238
+ attempt_id: attemptId,
239
+ status: "failed",
240
+ error: harnessError,
241
+ ...telemetrySummary(telemetry),
242
+ });
243
+ return { status: "failed", error: harnessError };
244
+ }
245
+ log.emit("harness.completed", {
246
+ harness_id: adapter.id,
247
+ attempt_id: attemptId,
248
+ status: "success",
249
+ ...telemetrySummary(telemetry),
250
+ });
251
+ return { status: "success", report };
252
+ }
253
+ /**
254
+ * #27 / D-6: decide the deep-scan synthesis outcome and, when warranted, run the
255
+ * bounded reducer. Returns the typed `DeepScanSynthesis` telemetry status plus
256
+ * the merged report (non-null only on a clean reducer success; the caller writes
257
+ * an honest raw bundle otherwise). A width-1 (single-report) scan skips the
258
+ * reducer; a budget-stopped/cancelled scan degrades without spending on a merge;
259
+ * a scan with no synthesize-capable route degrades honestly.
260
+ */
261
+ export async function resolveDeepScanSynthesis(deps, args) {
262
+ if (args.succeeded.length < 2) {
263
+ return {
264
+ deepScanSynthesis: {
265
+ status: "skipped",
266
+ reducer_attempt_id: null,
267
+ reason: "single scout report needs no merge",
268
+ },
269
+ reducedReport: null,
270
+ };
271
+ }
272
+ if (args.budgetStopped || args.aborted) {
273
+ return {
274
+ deepScanSynthesis: {
275
+ status: "failed",
276
+ reducer_attempt_id: null,
277
+ reason: args.aborted
278
+ ? "run cancelled before synthesis"
279
+ : "budget exhausted before synthesis",
280
+ },
281
+ reducedReport: null,
282
+ };
283
+ }
284
+ // Eligible route: a successful scout whose harness manifest supports the
285
+ // synthesize intent. Deep-scan repeats a surviving harness, so any routed slot
286
+ // for that harness id is a valid reducer route.
287
+ const eligible = args.succeeded
288
+ .map((s) => args.adapters.find((a) => a.adapter.id === s.harnessId && a.supportsSynthesize))
289
+ .find((a) => Boolean(a));
290
+ if (!eligible) {
291
+ return {
292
+ deepScanSynthesis: {
293
+ status: "failed",
294
+ reducer_attempt_id: null,
295
+ reason: "no synthesize-capable route among the scout harnesses",
296
+ },
297
+ reducedReport: null,
298
+ };
299
+ }
300
+ const reduced = await runDeepScanReducer(deps, {
301
+ taskId: args.taskId,
302
+ goal: args.goal,
303
+ routed: eligible,
304
+ scoutReports: args.succeeded.map((s) => ({
305
+ attemptId: s.attemptId,
306
+ harnessId: s.harnessId,
307
+ absPath: join(args.findingsDir, `${s.attemptId}.md`),
308
+ })),
309
+ ledger: args.ledger,
310
+ log: args.log,
311
+ paths: args.paths,
312
+ signal: args.signal,
313
+ onHarnessEvent: args.onHarnessEvent,
314
+ attemptTelemetries: args.attemptTelemetries,
315
+ });
316
+ if (reduced.status === "success") {
317
+ return {
318
+ deepScanSynthesis: {
319
+ status: "succeeded",
320
+ reducer_attempt_id: DEEP_SCAN_REDUCER_ATTEMPT_ID,
321
+ reason: null,
322
+ },
323
+ reducedReport: reduced.report,
324
+ };
325
+ }
326
+ // INV-116: a mid-reducer cancellation degrades with NO merged report (the
327
+ // partial output is discarded). The schema status has no `cancelled` member,
328
+ // so it is disclosed as a failed synthesis whose reason names the cancel; the
329
+ // run's own terminal is routed to `cancelled` by the caller's re-check.
330
+ if (reduced.status === "cancelled") {
331
+ return {
332
+ deepScanSynthesis: {
333
+ status: "failed",
334
+ reducer_attempt_id: DEEP_SCAN_REDUCER_ATTEMPT_ID,
335
+ reason: "run cancelled during synthesis",
336
+ },
337
+ reducedReport: null,
338
+ };
339
+ }
340
+ const reason = reduced.status === "budget_denied"
341
+ ? `reducer budget-denied: ${classifyBudgetFailure({ denial: reduced.denial, terminal: args.ledger.terminal() }).safeMessage}`
342
+ : reduced.error;
343
+ return {
344
+ deepScanSynthesis: {
345
+ status: "failed",
346
+ reducer_attempt_id: DEEP_SCAN_REDUCER_ATTEMPT_ID,
347
+ reason,
348
+ },
349
+ reducedReport: null,
350
+ };
351
+ }
352
+ //# sourceMappingURL=deepScanReducer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deepScanReducer.js","sourceRoot":"","sources":["../src/deepScanReducer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Harness-error remediation (GH #31), the transient-taxonomy sibling of the
3
+ * QA-050 budget classifier (budgetFailure.ts). A terminal harness error used to
4
+ * emit "Check harness authentication" unconditionally — doomed guidance when the
5
+ * cause was a timeout, a rate limit, or a process crash. This module maps the
6
+ * classified failure category onto the right required-actions: authentication
7
+ * guidance appears ONLY on `auth_failed`, exactly as budget guidance appears
8
+ * only on a real budget refusal.
9
+ */
10
+ import type { HarnessFailureCategory } from "@claudexor/schema";
11
+ import type { TransientFailureObservation } from "./transientClassify.js";
12
+ /**
13
+ * The category that best explains a terminal harness failure across a run's
14
+ * attempt telemetries. `auth_failed` and `capability_refused` are deterministic
15
+ * refusals that dominate (retrying never clears them, so they are the true
16
+ * cause even when a later transient also fired); otherwise the most recent
17
+ * classified failure wins. Null when no transient failure was classified.
18
+ */
19
+ export declare function dominantHarnessFailureCategory(transientFailures: TransientFailureObservation[]): HarnessFailureCategory | null;
20
+ /**
21
+ * Required-actions for a terminal harness failure, keyed off the classified
22
+ * category. Authentication guidance appears ONLY on `auth_failed`; every other
23
+ * category gets remediation that fits its actual cause. A null category (no
24
+ * classified transient) keeps the neutral diagnostics/retry guidance.
25
+ */
26
+ export declare function harnessFailureNextActions(category: HarnessFailureCategory | null): string[];
27
+ //# sourceMappingURL=harnessFailure.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"harnessFailure.d.ts","sourceRoot":"","sources":["../src/harnessFailure.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAChE,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,wBAAwB,CAAC;AAE1E;;;;;;GAMG;AACH,wBAAgB,8BAA8B,CAC5C,iBAAiB,EAAE,2BAA2B,EAAE,GAC/C,sBAAsB,GAAG,IAAI,CAO/B;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,sBAAsB,GAAG,IAAI,GAAG,MAAM,EAAE,CAsC3F"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * The category that best explains a terminal harness failure across a run's
3
+ * attempt telemetries. `auth_failed` and `capability_refused` are deterministic
4
+ * refusals that dominate (retrying never clears them, so they are the true
5
+ * cause even when a later transient also fired); otherwise the most recent
6
+ * classified failure wins. Null when no transient failure was classified.
7
+ */
8
+ export function dominantHarnessFailureCategory(transientFailures) {
9
+ if (transientFailures.length === 0)
10
+ return null;
11
+ const refusal = transientFailures.find((f) => f.category === "auth_failed" || f.category === "capability_refused");
12
+ if (refusal)
13
+ return refusal.category;
14
+ return transientFailures.at(-1)?.category ?? null;
15
+ }
16
+ /**
17
+ * Required-actions for a terminal harness failure, keyed off the classified
18
+ * category. Authentication guidance appears ONLY on `auth_failed`; every other
19
+ * category gets remediation that fits its actual cause. A null category (no
20
+ * classified transient) keeps the neutral diagnostics/retry guidance.
21
+ */
22
+ export function harnessFailureNextActions(category) {
23
+ switch (category) {
24
+ case "auth_failed":
25
+ return [
26
+ "Re-authenticate this harness (run `claudexor doctor`, then the vendor login it names)",
27
+ "Open diagnostics",
28
+ "Retry the run once the login is restored",
29
+ ];
30
+ case "capability_refused":
31
+ return [
32
+ "The route refused the requested capability (model/org/permission); choose a permitted model or route",
33
+ "Open diagnostics",
34
+ "Retry with a supported capability",
35
+ ];
36
+ case "config_error":
37
+ return [
38
+ "The harness could not start or accepted an invalid request; check its install and the run's settings",
39
+ "Open diagnostics",
40
+ "Retry after fixing the configuration",
41
+ ];
42
+ case "rate_limited":
43
+ return [
44
+ "The route was rate-limited; wait for the window to reset or route another account/profile",
45
+ "Open diagnostics",
46
+ "Retry the run",
47
+ ];
48
+ case "timeout":
49
+ return [
50
+ "The harness went silent past the inactivity window; raise runtime.harness_inactivity_timeout_ms if the workload is legitimately quiet",
51
+ "Open diagnostics",
52
+ "Retry the run",
53
+ ];
54
+ case "process_crash":
55
+ return ["The harness process crashed; open diagnostics for the exit detail", "Retry the run"];
56
+ case "unknown_harness_error":
57
+ case null:
58
+ return ["Open diagnostics", "Retry the run"];
59
+ }
60
+ }
61
+ //# sourceMappingURL=harnessFailure.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"harnessFailure.js","sourceRoot":"","sources":["../src/harnessFailure.ts"],"names":[],"mappings":"AAYA;;;;;;GAMG;AACH,MAAM,UAAU,8BAA8B,CAC5C,iBAAgD;IAEhD,IAAI,iBAAiB,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAChD,MAAM,OAAO,GAAG,iBAAiB,CAAC,IAAI,CACpC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,aAAa,IAAI,CAAC,CAAC,QAAQ,KAAK,oBAAoB,CAC3E,CAAC;IACF,IAAI,OAAO;QAAE,OAAO,OAAO,CAAC,QAAQ,CAAC;IACrC,OAAO,iBAAiB,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,IAAI,IAAI,CAAC;AACpD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,yBAAyB,CAAC,QAAuC;IAC/E,QAAQ,QAAQ,EAAE,CAAC;QACjB,KAAK,aAAa;YAChB,OAAO;gBACL,uFAAuF;gBACvF,kBAAkB;gBAClB,0CAA0C;aAC3C,CAAC;QACJ,KAAK,oBAAoB;YACvB,OAAO;gBACL,sGAAsG;gBACtG,kBAAkB;gBAClB,mCAAmC;aACpC,CAAC;QACJ,KAAK,cAAc;YACjB,OAAO;gBACL,sGAAsG;gBACtG,kBAAkB;gBAClB,sCAAsC;aACvC,CAAC;QACJ,KAAK,cAAc;YACjB,OAAO;gBACL,2FAA2F;gBAC3F,kBAAkB;gBAClB,eAAe;aAChB,CAAC;QACJ,KAAK,SAAS;YACZ,OAAO;gBACL,uIAAuI;gBACvI,kBAAkB;gBAClB,eAAe;aAChB,CAAC;QACJ,KAAK,eAAe;YAClB,OAAO,CAAC,mEAAmE,EAAE,eAAe,CAAC,CAAC;QAChG,KAAK,uBAAuB,CAAC;QAC7B,KAAK,IAAI;YACP,OAAO,CAAC,kBAAkB,EAAE,eAAe,CAAC,CAAC;IACjD,CAAC;AACH,CAAC"}