@claudexor/orchestrator 3.0.4 → 3.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/dist/attemptFinalize.d.ts +200 -0
  2. package/dist/attemptFinalize.d.ts.map +1 -0
  3. package/dist/attemptFinalize.js +412 -0
  4. package/dist/attemptFinalize.js.map +1 -0
  5. package/dist/attemptTelemetry.d.ts +88 -7
  6. package/dist/attemptTelemetry.d.ts.map +1 -1
  7. package/dist/attemptTelemetry.js +276 -14
  8. package/dist/attemptTelemetry.js.map +1 -1
  9. package/dist/budgetFailure.d.ts +70 -0
  10. package/dist/budgetFailure.d.ts.map +1 -0
  11. package/dist/budgetFailure.js +114 -0
  12. package/dist/budgetFailure.js.map +1 -0
  13. package/dist/candidateEvidence.d.ts +55 -1
  14. package/dist/candidateEvidence.d.ts.map +1 -1
  15. package/dist/candidateEvidence.js +72 -0
  16. package/dist/candidateEvidence.js.map +1 -1
  17. package/dist/continuation.d.ts +77 -0
  18. package/dist/continuation.d.ts.map +1 -0
  19. package/dist/continuation.js +92 -0
  20. package/dist/continuation.js.map +1 -0
  21. package/dist/deepScanReducer.d.ts +148 -0
  22. package/dist/deepScanReducer.d.ts.map +1 -0
  23. package/dist/deepScanReducer.js +348 -0
  24. package/dist/deepScanReducer.js.map +1 -0
  25. package/dist/effortGovernance.d.ts +49 -0
  26. package/dist/effortGovernance.d.ts.map +1 -0
  27. package/dist/effortGovernance.js +35 -0
  28. package/dist/effortGovernance.js.map +1 -0
  29. package/dist/harnessFailure.d.ts +27 -0
  30. package/dist/harnessFailure.d.ts.map +1 -0
  31. package/dist/harnessFailure.js +61 -0
  32. package/dist/harnessFailure.js.map +1 -0
  33. package/dist/index.d.ts +1 -1
  34. package/dist/index.d.ts.map +1 -1
  35. package/dist/index.js.map +1 -1
  36. package/dist/orchestrator.d.ts +103 -16
  37. package/dist/orchestrator.d.ts.map +1 -1
  38. package/dist/orchestrator.js +1245 -327
  39. package/dist/orchestrator.js.map +1 -1
  40. package/dist/planQuestions.d.ts.map +1 -1
  41. package/dist/planQuestions.js +105 -50
  42. package/dist/planQuestions.js.map +1 -1
  43. package/dist/planRun.d.ts +15 -7
  44. package/dist/planRun.d.ts.map +1 -1
  45. package/dist/planRun.js +88 -42
  46. package/dist/planRun.js.map +1 -1
  47. package/dist/planTerminal.d.ts +36 -0
  48. package/dist/planTerminal.d.ts.map +1 -0
  49. package/dist/planTerminal.js +63 -0
  50. package/dist/planTerminal.js.map +1 -0
  51. package/dist/reviewerPanel.d.ts +4 -0
  52. package/dist/reviewerPanel.d.ts.map +1 -1
  53. package/dist/reviewerPanel.js +54 -9
  54. package/dist/reviewerPanel.js.map +1 -1
  55. package/dist/revisePrompt.d.ts +17 -0
  56. package/dist/revisePrompt.d.ts.map +1 -0
  57. package/dist/revisePrompt.js +15 -0
  58. package/dist/revisePrompt.js.map +1 -0
  59. package/dist/runSupport.d.ts +67 -2
  60. package/dist/runSupport.d.ts.map +1 -1
  61. package/dist/runSupport.js +86 -6
  62. package/dist/runSupport.js.map +1 -1
  63. package/dist/runTelemetryWriter.d.ts +6 -1
  64. package/dist/runTelemetryWriter.d.ts.map +1 -1
  65. package/dist/runTelemetryWriter.js +2 -0
  66. package/dist/runTelemetryWriter.js.map +1 -1
  67. package/dist/runTerminals.d.ts +15 -4
  68. package/dist/runTerminals.d.ts.map +1 -1
  69. package/dist/runTerminals.js +16 -1
  70. package/dist/runTerminals.js.map +1 -1
  71. package/dist/structuredOutput.d.ts +27 -0
  72. package/dist/structuredOutput.d.ts.map +1 -1
  73. package/dist/structuredOutput.js +65 -7
  74. package/dist/structuredOutput.js.map +1 -1
  75. package/dist/transientClassify.d.ts +59 -0
  76. package/dist/transientClassify.d.ts.map +1 -0
  77. package/dist/transientClassify.js +109 -0
  78. package/dist/transientClassify.js.map +1 -0
  79. package/dist/write-isolation.d.ts +11 -0
  80. package/dist/write-isolation.d.ts.map +1 -0
  81. package/dist/write-isolation.js +13 -0
  82. package/dist/write-isolation.js.map +1 -0
  83. 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":"AACA,OAAO,KAAK,EACV,YAAY,EACZ,iBAAiB,EACjB,qBAAqB,EACrB,YAAY,EACZ,cAAc,EACf,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAA8B,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAGlF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAErD,OAAO,EAAE,KAAK,YAAY,EAAyB,MAAM,oBAAoB,CAAC;AAC9E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAGL,KAAK,sBAAsB,EAC5B,MAAM,sBAAsB,CAAC;AAO9B,OAAO,EACL,KAAK,gBAAgB,EAMtB,MAAM,uBAAuB,CAAC;AAE/B,iFAAiF;AACjF,eAAO,MAAM,4BAA4B,UAAU,CAAC;AAEpD;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE;IACnC,SAAS,EAAE;QACT,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;QAClB,MAAM,EAAE,MAAM,CAAC;QACf,SAAS,EAAE,gBAAgB,CAAC;KAC7B,EAAE,CAAC;IACJ,YAAY,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,EAAE,CAAC;IAC/F,MAAM,EAAE,iBAAiB,GAAG,IAAI,CAAC;CAClC,GAAG,MAAM,CAmCT;AAED,4DAA4D;AAC5D,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED;;;gFAGgF;AAChF,MAAM,WAAW,mBAAmB;IAClC,8EAA8E;IAC9E,eAAe,EAAE,MAAM,WAAW,CAAC;IACnC,oFAAoF;IACpF,YAAY,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,YAAY,CAAC;IACrE,6EAA6E;IAC7E,SAAS,EAAE,CACT,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC/B,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,KACd;QACH,IAAI,EAAE,cAAc,CAAC;QACrB,SAAS,EAAE,qBAAqB,CAAC;QACjC,YAAY,EAAE,qBAAqB,CAAC;QACpC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;QACrB;;;0FAGkF;QAClF,cAAc,EAAE,sBAAsB,CAAC;KACxC,CAAC;IACF,wDAAwD;IACxD,aAAa,EAAE,MAAM,CAAC;IACtB,gEAAgE;IAChE,mBAAmB,EAAE,MAAM,CAAC;IAC5B,yEAAyE;IACzE,WAAW,EAAE,OAAO,CAAC;IACrB,gEAAgE;IAChE,cAAc,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,YAAY,KAAK,IAAI,CAAC;CAChE;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,aAAa,CAAC;IACtB,YAAY,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC1E,MAAM,EAAE,YAAY,CAAC;IACrB,GAAG,EAAE,QAAQ,CAAC;IACd,KAAK,EAAE,QAAQ,CAAC;IAChB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,cAAc,CAAC,EAAE,CAAC,EAAE,EAAE,YAAY,KAAK,IAAI,CAAC;IAC5C,kBAAkB,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,gBAAgB,CAAA;KAAE,EAAE,CAAC;CAC7F;AAED,MAAM,MAAM,qBAAqB,GAC7B;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACrC;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACnC;IAAE,MAAM,EAAE,eAAe,CAAC;IAAC,MAAM,EAAE,YAAY,CAAA;CAAE,GAIjD;IAAE,MAAM,EAAE,WAAW,CAAA;CAAE,CAAC;AAE5B;;;;;;;;;GASG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,mBAAmB,EACzB,IAAI,EAAE,mBAAmB,GACxB,OAAO,CAAC,qBAAqB,CAAC,CA+LhC;AAED;;;;;;;GAOG;AACH,wBAAsB,wBAAwB,CAC5C,IAAI,EAAE,mBAAmB,EACzB,IAAI,EAAE;IACJ,SAAS,EAAE;QACT,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;QAClB,MAAM,EAAE,MAAM,CAAC;QACf,SAAS,EAAE,gBAAgB,CAAC;KAC7B,EAAE,CAAC;IACJ,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,aAAa,EAAE,OAAO,CAAC;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,YAAY,CAAC;IACrB,GAAG,EAAE,QAAQ,CAAC;IACd,KAAK,EAAE,QAAQ,CAAC;IAChB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,cAAc,CAAC,EAAE,CAAC,EAAE,EAAE,YAAY,KAAK,IAAI,CAAC;IAC5C,kBAAkB,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,gBAAgB,CAAA;KAAE,EAAE,CAAC;CAC7F,GACA,OAAO,CAAC;IAAE,iBAAiB,EAAE,iBAAiB,CAAC;IAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC,CA2FjF"}
@@ -0,0 +1,348 @@
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, safeErrorMessage, } from "./runSupport.js";
9
+ import { createAttemptTelemetry, observeAttemptTelemetry, setAttemptOutcome, telemetrySummary, toolWarnings, } from "./attemptTelemetry.js";
10
+ /** The reducer runs under the fixed `synth` attempt id (roster/cost visible). */
11
+ export const DEEP_SCAN_REDUCER_ATTEMPT_ID = "synth";
12
+ /**
13
+ * #27 / D-6: the HONEST fallback artifact for a deep scan whose bounded
14
+ * synthesis reducer did not run or did not succeed. It is explicitly labeled a
15
+ * raw scout bundle (a marker heading), never presented as a merged synthesis:
16
+ * the per-scout reports are concatenated verbatim with attribution, the roster
17
+ * denominator stays honest, and omissions are preserved. `skipped` (a single
18
+ * width-1 report) and `failed` (reducer error/timeout/budget-denial or no
19
+ * synthesize-capable route) get distinct honest intros.
20
+ */
21
+ export function rawScoutBundle(args) {
22
+ const total = args.succeeded.length + args.unsuccessful.length;
23
+ const intro = args.status?.status === "skipped"
24
+ ? [
25
+ "## Raw scout report (single scout — no merge needed)",
26
+ "",
27
+ "Only one scout produced a report, so no synthesis reducer was run.",
28
+ ]
29
+ : [
30
+ "## Raw scout bundle — NOT a merged synthesis",
31
+ "",
32
+ `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.`,
33
+ ];
34
+ return [
35
+ ...intro,
36
+ "",
37
+ `Explorers succeeded: ${args.succeeded.length}/${total}.`,
38
+ "",
39
+ "## Scout reports (raw, not merged)",
40
+ ...args.succeeded.map((a) => {
41
+ const warnings = toolWarnings(a.telemetry);
42
+ const warningText = warnings.length
43
+ ? `\n\n> Tool warnings: ${warnings.map((e) => `${e.tool}: ${e.summary}`).join("; ")}`
44
+ : "";
45
+ return `\n### ${a.attemptId} / ${a.harnessId}\n\n${a.report}${warningText}`;
46
+ }),
47
+ "",
48
+ "## Omissions / Uncertainty",
49
+ ...(args.unsuccessful.length
50
+ ? args.unsuccessful.map((a) => `- ${a.attemptId} / ${a.harnessId} ${a.status}: ${a.error}`)
51
+ : [
52
+ "- No explorer failures recorded. Claims still need evidence review before edit execution.",
53
+ ]),
54
+ ].join("\n");
55
+ }
56
+ /**
57
+ * #27 / D-6: the deep-scan bounded synthesis reducer. After the scouts finish,
58
+ * ONE synthesize-intent attempt merges the raw scout reports into a real
59
+ * synthesis. It is READ-ONLY and file-backed (the scout report files are pointed
60
+ * at by absolute path — the argv-size law: reports ride a file, never argv),
61
+ * reserves a budget lease like any attempt, and is bounded by a hard timeout. Its
62
+ * telemetry is pushed to the run roster (cost/route visible). On
63
+ * failure/timeout/budget-denial the caller degrades to an HONEST raw bundle; this
64
+ * function never fabricates a synthesis.
65
+ */
66
+ export async function runDeepScanReducer(deps, args) {
67
+ const { ledger, log, paths } = args;
68
+ const attemptId = DEEP_SCAN_REDUCER_ATTEMPT_ID;
69
+ const adapter = args.routed.adapter;
70
+ log.emit("synthesis.started", {
71
+ synthesize: true,
72
+ reason: `deep-scan reducer over ${args.scoutReports.length} scout reports`,
73
+ });
74
+ const lease = ledger.reserve({
75
+ taskId: args.taskId,
76
+ attemptId,
77
+ intent: "synthesize",
78
+ harnessId: adapter.id,
79
+ cost: deps.costEvidence(adapter.id, attemptId),
80
+ });
81
+ if (!lease.granted) {
82
+ log.emit("budget.lease.created", {
83
+ granted: false,
84
+ reason: lease.reason,
85
+ denied: lease.denied,
86
+ attempt_id: attemptId,
87
+ harness_id: adapter.id,
88
+ });
89
+ return {
90
+ status: "budget_denied",
91
+ denial: {
92
+ code: lease.denied ?? "hard_cap",
93
+ reason: lease.reason ?? "budget lease denied",
94
+ harnessId: adapter.id,
95
+ attemptId,
96
+ },
97
+ };
98
+ }
99
+ // A fresh disposable read-only home: the scouts' shared route context was
100
+ // already disposed, and auth truth is home-independent (credentials come from
101
+ // the profile/keychain/default store), so a fresh home shares the auth source.
102
+ const reducerHome = deps.newReadOnlyHome();
103
+ const prompt = buildDeepScanReducerPrompt(args.goal, args.scoutReports);
104
+ const built = deps.buildSpec(args.routed, reducerHome.env, prompt, attemptId);
105
+ const spec = built.spec;
106
+ // Hard (total) timeout — one attempt, no failover/transient retry loop.
107
+ const reducerAbort = new AbortController();
108
+ let timedOut = false;
109
+ const hardTimer = setTimeout(() => {
110
+ timedOut = true;
111
+ reducerAbort.abort();
112
+ void adapter.cancel?.(spec.session_id)?.catch(() => { });
113
+ }, deps.hardTimeoutMs);
114
+ spec.extra["abortSignal"] = args.signal
115
+ ? AbortSignal.any([args.signal, reducerAbort.signal])
116
+ : reducerAbort.signal;
117
+ const telemetry = createAttemptTelemetry(built.webPolicy, deps.webRequired || built.webPolicy === "cached" || built.webPolicy === "live", built.effectiveWeb, [], built.model);
118
+ const answer = new AnswerAssembly();
119
+ const attemptEventsPath = join(paths.attemptsDir, attemptId, "events.jsonl");
120
+ const budgetSignalState = { quotaPressureDisclosed: false };
121
+ let cost = 0;
122
+ let costEstimated = false;
123
+ let harnessError = null;
124
+ log.emit("harness.started", {
125
+ harness_id: adapter.id,
126
+ attempt_id: attemptId,
127
+ external_context_policy: built.webPolicy,
128
+ });
129
+ try {
130
+ const watched = withInactivityWatchdog(adapter.run(spec), {
131
+ timeoutMs: deps.inactivityTimeoutMs,
132
+ onTimeout: () => {
133
+ reducerAbort.abort();
134
+ void adapter.cancel?.(spec.session_id)?.catch(() => { });
135
+ },
136
+ isSuspended: () => false,
137
+ });
138
+ for await (const ev of watched) {
139
+ if (reducerAbort.signal.aborted)
140
+ break;
141
+ const safeEv = redactHarnessEvent(ev);
142
+ safeInvoke(args.onHarnessEvent, safeEv);
143
+ log.emit("harness.event", harnessEventPayload(adapter.id, attemptId, safeEv));
144
+ appendLine(attemptEventsPath, JSON.stringify(safeEv));
145
+ observeAttemptTelemetry(telemetry, safeEv);
146
+ observeBudgetSignals(ledger, log, adapter.id, attemptId, safeEv, budgetSignalState);
147
+ deps.quotaEventSink?.(adapter.id, safeEv);
148
+ if (safeEv.type === "usage" && safeEv.usage?.cost_usd) {
149
+ cost += safeEv.usage.cost_usd;
150
+ if (safeEv.usage.estimated)
151
+ costEstimated = true;
152
+ log.emit("budget.observation", {
153
+ harness_id: adapter.id,
154
+ attempt_id: attemptId,
155
+ kind: "spend",
156
+ usd: safeEv.usage.cost_usd,
157
+ estimated: safeEv.usage.estimated === true,
158
+ });
159
+ }
160
+ answer.observe(safeEv);
161
+ if (safeEv.type === "error")
162
+ harnessError = safeEv.error ? redactSecrets(safeEv.error) : "harness emitted an error";
163
+ }
164
+ }
165
+ catch (err) {
166
+ harnessError = safeErrorMessage(err);
167
+ }
168
+ finally {
169
+ clearTimeout(hardTimer);
170
+ reducerHome.dispose();
171
+ ledger.settle(lease.lease?.lease_id ?? "", attemptUsageCostSettlement(cost, costEstimated, attemptId, adapter.id, telemetry.authMode, telemetry.usageCost));
172
+ }
173
+ // D-16: unwrap the WorkReport envelope and finalize through the SAME contract as
174
+ // every other attempt — a capable reducer route that broke its WorkReport
175
+ // contract (or reported needs_input/incomplete/context-exhausted) must NEVER be
176
+ // accepted as a clean synthesis; the caller then degrades to an honest raw
177
+ // bundle. On an inactive-transport route the unwrap passes the report through
178
+ // untouched (unchanged behavior for schema-free reducer harnesses).
179
+ const unwrapped = unwrapWorkReportEnvelope(answer.machineText() ?? "", built.workReportMode, {
180
+ sideToolReport: telemetry.sideToolWorkReport ?? undefined,
181
+ });
182
+ const report = redactSecrets(unwrapped.deliverable);
183
+ const finalized = finalizeAttempt({
184
+ deliverableEvidence: report.trim().length > 0,
185
+ harnessErrored: harnessError !== null,
186
+ workReport: unwrapped.workReport,
187
+ workReportSource: unwrapped.source,
188
+ workReportViolation: unwrapped.contractViolation,
189
+ contextTerminalExhausted: telemetry.contextExhausted,
190
+ });
191
+ if (timedOut && !harnessError)
192
+ harnessError = `deep-scan reducer timed out after ${deps.hardTimeoutMs}ms`;
193
+ // A reducer must produce a CLEAN merged synthesis: a broken WorkReport contract,
194
+ // a needs_input/incomplete attestation, or a terminal context exhaustion is a
195
+ // typed reducer failure (degrade to the raw bundle), never a laundered success.
196
+ if (!harnessError && finalized.outcomeClass === "contract_failure") {
197
+ harnessError = `deep-scan reducer work_report contract: ${unwrapped.contractViolation}`;
198
+ }
199
+ else if (!harnessError && finalized.outcomeClass === "veto") {
200
+ harnessError = `deep-scan reducer reported ${finalized.workState.state} instead of a merged synthesis`;
201
+ }
202
+ else if (!harnessError && finalized.outcomeClass === "interrupted") {
203
+ harnessError = "deep-scan reducer ran out of context before completing the synthesis";
204
+ }
205
+ const reportPresent = finalized.deliverablePresent && report.trim().length > 0;
206
+ if (!harnessError && !reportPresent)
207
+ harnessError = "deep-scan reducer produced no synthesis";
208
+ // INV-116: a cancel on the OUTER run signal that landed WHILE this bounded
209
+ // reducer streamed is a cancellation — not a clean synthesis and not a typed
210
+ // failure. Any partial output is discarded (deliverablePresent forced false)
211
+ // so it can never be accepted as a merge, and the run terminalizes cancelled.
212
+ const runCancelled = args.signal?.aborted === true;
213
+ setAttemptOutcome(telemetry, {
214
+ deliverablePresent: reportPresent && !runCancelled,
215
+ gatesPassed: null,
216
+ harnessErrored: harnessError !== null || runCancelled,
217
+ webRequiredUnsatisfied: false,
218
+ workState: finalized.workState,
219
+ });
220
+ // Roster/cost visible: the reducer is a normal attempt in run telemetry.
221
+ args.attemptTelemetries.push({ attemptId, harnessId: adapter.id, telemetry });
222
+ if (runCancelled) {
223
+ log.emit("harness.completed", {
224
+ harness_id: adapter.id,
225
+ attempt_id: attemptId,
226
+ status: "cancelled",
227
+ ...telemetrySummary(telemetry),
228
+ });
229
+ return { status: "cancelled" };
230
+ }
231
+ if (harnessError) {
232
+ log.emit("harness.completed", {
233
+ harness_id: adapter.id,
234
+ attempt_id: attemptId,
235
+ status: "failed",
236
+ error: harnessError,
237
+ ...telemetrySummary(telemetry),
238
+ });
239
+ return { status: "failed", error: harnessError };
240
+ }
241
+ log.emit("harness.completed", {
242
+ harness_id: adapter.id,
243
+ attempt_id: attemptId,
244
+ status: "success",
245
+ ...telemetrySummary(telemetry),
246
+ });
247
+ return { status: "success", report };
248
+ }
249
+ /**
250
+ * #27 / D-6: decide the deep-scan synthesis outcome and, when warranted, run the
251
+ * bounded reducer. Returns the typed `DeepScanSynthesis` telemetry status plus
252
+ * the merged report (non-null only on a clean reducer success; the caller writes
253
+ * an honest raw bundle otherwise). A width-1 (single-report) scan skips the
254
+ * reducer; a budget-stopped/cancelled scan degrades without spending on a merge;
255
+ * a scan with no synthesize-capable route degrades honestly.
256
+ */
257
+ export async function resolveDeepScanSynthesis(deps, args) {
258
+ if (args.succeeded.length < 2) {
259
+ return {
260
+ deepScanSynthesis: {
261
+ status: "skipped",
262
+ reducer_attempt_id: null,
263
+ reason: "single scout report needs no merge",
264
+ },
265
+ reducedReport: null,
266
+ };
267
+ }
268
+ if (args.budgetStopped || args.aborted) {
269
+ return {
270
+ deepScanSynthesis: {
271
+ status: "failed",
272
+ reducer_attempt_id: null,
273
+ reason: args.aborted
274
+ ? "run cancelled before synthesis"
275
+ : "budget exhausted before synthesis",
276
+ },
277
+ reducedReport: null,
278
+ };
279
+ }
280
+ // Eligible route: a successful scout whose harness manifest supports the
281
+ // synthesize intent. Deep-scan repeats a surviving harness, so any routed slot
282
+ // for that harness id is a valid reducer route.
283
+ const eligible = args.succeeded
284
+ .map((s) => args.adapters.find((a) => a.adapter.id === s.harnessId && a.supportsSynthesize))
285
+ .find((a) => Boolean(a));
286
+ if (!eligible) {
287
+ return {
288
+ deepScanSynthesis: {
289
+ status: "failed",
290
+ reducer_attempt_id: null,
291
+ reason: "no synthesize-capable route among the scout harnesses",
292
+ },
293
+ reducedReport: null,
294
+ };
295
+ }
296
+ const reduced = await runDeepScanReducer(deps, {
297
+ taskId: args.taskId,
298
+ goal: args.goal,
299
+ routed: eligible,
300
+ scoutReports: args.succeeded.map((s) => ({
301
+ attemptId: s.attemptId,
302
+ harnessId: s.harnessId,
303
+ absPath: join(args.findingsDir, `${s.attemptId}.md`),
304
+ })),
305
+ ledger: args.ledger,
306
+ log: args.log,
307
+ paths: args.paths,
308
+ signal: args.signal,
309
+ onHarnessEvent: args.onHarnessEvent,
310
+ attemptTelemetries: args.attemptTelemetries,
311
+ });
312
+ if (reduced.status === "success") {
313
+ return {
314
+ deepScanSynthesis: {
315
+ status: "succeeded",
316
+ reducer_attempt_id: DEEP_SCAN_REDUCER_ATTEMPT_ID,
317
+ reason: null,
318
+ },
319
+ reducedReport: reduced.report,
320
+ };
321
+ }
322
+ // INV-116: a mid-reducer cancellation degrades with NO merged report (the
323
+ // partial output is discarded). The schema status has no `cancelled` member,
324
+ // so it is disclosed as a failed synthesis whose reason names the cancel; the
325
+ // run's own terminal is routed to `cancelled` by the caller's re-check.
326
+ if (reduced.status === "cancelled") {
327
+ return {
328
+ deepScanSynthesis: {
329
+ status: "failed",
330
+ reducer_attempt_id: DEEP_SCAN_REDUCER_ATTEMPT_ID,
331
+ reason: "run cancelled during synthesis",
332
+ },
333
+ reducedReport: null,
334
+ };
335
+ }
336
+ const reason = reduced.status === "budget_denied"
337
+ ? `reducer budget-denied: ${classifyBudgetFailure({ denial: reduced.denial, terminal: args.ledger.terminal() }).safeMessage}`
338
+ : reduced.error;
339
+ return {
340
+ deepScanSynthesis: {
341
+ status: "failed",
342
+ reducer_attempt_id: DEEP_SCAN_REDUCER_ATTEMPT_ID,
343
+ reason,
344
+ },
345
+ reducedReport: null,
346
+ };
347
+ }
348
+ //# 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,49 @@
1
+ /**
2
+ * Run-preflight effort gate (INV-105), the effort analog of `modelGovernance`.
3
+ *
4
+ * This gate DISCLOSES, it does not clamp. It answers exactly one question:
5
+ * does the harness's merged advertised ladder (`capabilities.effort_levels`,
6
+ * the positional merge of its models' vendor-ordered lists) know this level at
7
+ * all? A level the merged ladder has never seen is disclosed as ignored — the
8
+ * adapter would otherwise just omit the flag and the user would never learn
9
+ * their level went nowhere. A level the ladder DOES know rides through
10
+ * VERBATIM and is resolved by the adapter.
11
+ *
12
+ * Why the clamp lives downstream and not here: the manifest is discovered
13
+ * ONCE, against the DEFAULT native harness home (`discover()` takes no
14
+ * arguments), so its ladders describe the DEFAULT account's catalog. Codex
15
+ * advertises its ladders per ACCOUNT — every credential profile and API-key
16
+ * route gets its own `CODEX_HOME`, and `model/list` answers for whoever that
17
+ * home is logged into. Clamping here would therefore hold a profile-scoped run
18
+ * to another account's ceiling. The adapter re-resolves against the catalog
19
+ * for the env the child will ACTUALLY run in (`codexEffortsForEnv`), so it is
20
+ * the only layer entitled to clamp — and clamping is only ever a move INSIDE
21
+ * the vendor's own order, which only the adapter's resolved catalog carries.
22
+ *
23
+ * The membership test runs against the harness-wide merged ladder rather than
24
+ * the per-model narrowing, because the ladder is the broadest and least
25
+ * account-specific signal the manifest carries: a level any of the harness's
26
+ * models advertises is in it, so this gate cannot reject a level merely
27
+ * because the routed model's copy happens not to list it.
28
+ */
29
+ import type { EffortHint } from "@claudexor/schema";
30
+ export interface EffortGovernedRoute {
31
+ id: string;
32
+ /** Harness-wide merged advertised ladder; empty = effort is not a tunable surface. */
33
+ effortLevels: readonly EffortHint[];
34
+ }
35
+ /**
36
+ * The effort this route should FORWARD, plus any disclosure text.
37
+ * `effort: null` means "send no flag" — either nothing was asked for, or what
38
+ * was asked for could not be honored anywhere and is disclosed instead.
39
+ *
40
+ * A returned level is the RAW request, deliberately un-clamped: it is the
41
+ * adapter's `effort_hint`, and every adapter that consumes it resolves through
42
+ * the shared normalizer against its own profile-resolved advertised set
43
+ * (`normalizeEffort` in harness-claude, `codexEffortFor` in harness-codex).
44
+ */
45
+ export declare function governRouteEffort(requested: EffortHint | null, route: EffortGovernedRoute): {
46
+ effort: EffortHint | null;
47
+ ignored: string | null;
48
+ };
49
+ //# sourceMappingURL=effortGovernance.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"effortGovernance.d.ts","sourceRoot":"","sources":["../src/effortGovernance.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,sFAAsF;IACtF,YAAY,EAAE,SAAS,UAAU,EAAE,CAAC;CACrC;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,UAAU,GAAG,IAAI,EAC5B,KAAK,EAAE,mBAAmB,GACzB;IAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CAAC;IAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAuBvD"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * The effort this route should FORWARD, plus any disclosure text.
3
+ * `effort: null` means "send no flag" — either nothing was asked for, or what
4
+ * was asked for could not be honored anywhere and is disclosed instead.
5
+ *
6
+ * A returned level is the RAW request, deliberately un-clamped: it is the
7
+ * adapter's `effort_hint`, and every adapter that consumes it resolves through
8
+ * the shared normalizer against its own profile-resolved advertised set
9
+ * (`normalizeEffort` in harness-claude, `codexEffortFor` in harness-codex).
10
+ */
11
+ export function governRouteEffort(requested, route) {
12
+ if (!requested)
13
+ return { effort: null, ignored: null };
14
+ if (route.effortLevels.length === 0) {
15
+ return {
16
+ effort: null,
17
+ ignored: `effort=${requested} (manifest capabilities.effort_levels is empty for ${route.id})`,
18
+ };
19
+ }
20
+ // Pure membership against the merged vendor ladder: with no static rank
21
+ // table there is nothing else for this layer to rank against, which is the
22
+ // point — a level the harness's own advertised order has never seen is one
23
+ // no honest "nearest" could be invented for, so it is disclosed instead of
24
+ // vanishing. Anything the ladder knows is forwardable; WHERE it lands on the
25
+ // routed model is the adapter's call.
26
+ if (!route.effortLevels.includes(requested)) {
27
+ return {
28
+ effort: null,
29
+ ignored: `effort=${requested} (not on the advertised ladder of ${route.id}: ` +
30
+ `${route.effortLevels.join(", ")})`,
31
+ };
32
+ }
33
+ return { effort: requested, ignored: null };
34
+ }
35
+ //# sourceMappingURL=effortGovernance.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"effortGovernance.js","sourceRoot":"","sources":["../src/effortGovernance.ts"],"names":[],"mappings":"AAoCA;;;;;;;;;GASG;AACH,MAAM,UAAU,iBAAiB,CAC/B,SAA4B,EAC5B,KAA0B;IAE1B,IAAI,CAAC,SAAS;QAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IACvD,IAAI,KAAK,CAAC,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACpC,OAAO;YACL,MAAM,EAAE,IAAI;YACZ,OAAO,EAAE,UAAU,SAAS,sDAAsD,KAAK,CAAC,EAAE,GAAG;SAC9F,CAAC;IACJ,CAAC;IACD,wEAAwE;IACxE,2EAA2E;IAC3E,2EAA2E;IAC3E,2EAA2E;IAC3E,6EAA6E;IAC7E,sCAAsC;IACtC,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QAC5C,OAAO;YACL,MAAM,EAAE,IAAI;YACZ,OAAO,EACL,UAAU,SAAS,qCAAqC,KAAK,CAAC,EAAE,IAAI;gBACpE,GAAG,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;SACtC,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AAC9C,CAAC"}
@@ -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"}