@claudexor/orchestrator 3.0.4 → 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.
- package/dist/attemptFinalize.d.ts +162 -0
- package/dist/attemptFinalize.d.ts.map +1 -0
- package/dist/attemptFinalize.js +368 -0
- package/dist/attemptFinalize.js.map +1 -0
- package/dist/attemptTelemetry.d.ts +88 -7
- package/dist/attemptTelemetry.d.ts.map +1 -1
- package/dist/attemptTelemetry.js +276 -14
- package/dist/attemptTelemetry.js.map +1 -1
- package/dist/budgetFailure.d.ts +70 -0
- package/dist/budgetFailure.d.ts.map +1 -0
- package/dist/budgetFailure.js +114 -0
- package/dist/budgetFailure.js.map +1 -0
- package/dist/candidateEvidence.d.ts +55 -1
- package/dist/candidateEvidence.d.ts.map +1 -1
- package/dist/candidateEvidence.js +72 -0
- package/dist/candidateEvidence.js.map +1 -1
- package/dist/continuation.d.ts +77 -0
- package/dist/continuation.d.ts.map +1 -0
- package/dist/continuation.js +92 -0
- package/dist/continuation.js.map +1 -0
- package/dist/deepScanReducer.d.ts +148 -0
- package/dist/deepScanReducer.d.ts.map +1 -0
- package/dist/deepScanReducer.js +352 -0
- package/dist/deepScanReducer.js.map +1 -0
- package/dist/harnessFailure.d.ts +27 -0
- package/dist/harnessFailure.d.ts.map +1 -0
- package/dist/harnessFailure.js +61 -0
- package/dist/harnessFailure.js.map +1 -0
- package/dist/orchestrator.d.ts +97 -10
- package/dist/orchestrator.d.ts.map +1 -1
- package/dist/orchestrator.js +1213 -295
- package/dist/orchestrator.js.map +1 -1
- package/dist/planQuestions.d.ts.map +1 -1
- package/dist/planQuestions.js +105 -50
- package/dist/planQuestions.js.map +1 -1
- package/dist/planRun.d.ts +15 -7
- package/dist/planRun.d.ts.map +1 -1
- package/dist/planRun.js +88 -42
- package/dist/planRun.js.map +1 -1
- package/dist/planTerminal.d.ts +36 -0
- package/dist/planTerminal.d.ts.map +1 -0
- package/dist/planTerminal.js +63 -0
- package/dist/planTerminal.js.map +1 -0
- package/dist/runSupport.d.ts +50 -2
- package/dist/runSupport.d.ts.map +1 -1
- package/dist/runSupport.js +60 -6
- package/dist/runSupport.js.map +1 -1
- package/dist/runTelemetryWriter.d.ts +6 -1
- package/dist/runTelemetryWriter.d.ts.map +1 -1
- package/dist/runTelemetryWriter.js +2 -0
- package/dist/runTelemetryWriter.js.map +1 -1
- package/dist/runTerminals.d.ts +15 -4
- package/dist/runTerminals.d.ts.map +1 -1
- package/dist/runTerminals.js +16 -1
- package/dist/runTerminals.js.map +1 -1
- package/dist/structuredOutput.d.ts +27 -0
- package/dist/structuredOutput.d.ts.map +1 -1
- package/dist/structuredOutput.js +65 -7
- package/dist/structuredOutput.js.map +1 -1
- package/dist/transientClassify.d.ts +59 -0
- package/dist/transientClassify.d.ts.map +1 -0
- package/dist/transientClassify.js +109 -0
- package/dist/transientClassify.js.map +1 -0
- package/package.json +17 -17
|
@@ -5,7 +5,9 @@
|
|
|
5
5
|
* no regex over prose, and a tool error is "recovered" only when the SAME
|
|
6
6
|
* tool later succeeds against the SAME target.
|
|
7
7
|
*/
|
|
8
|
-
import type { AttemptTelemetryRecord, AuthSourceKind, ExternalContextPolicy, HarnessEvent, RequestRequirementResolution, TaskContract, ToolKind } from "@claudexor/schema";
|
|
8
|
+
import type { AttemptTelemetryRecord, AuthSourceKind, ExternalContextPolicy, HarnessEvent, RequestRequirementResolution, TaskContract, ToolKind, WorkState } from "@claudexor/schema";
|
|
9
|
+
import { type TransientFailureObservation } from "./transientClassify.js";
|
|
10
|
+
export { type TransientFailureObservation, classifyAdapterThrow } from "./transientClassify.js";
|
|
9
11
|
export interface ToolErrorRecord {
|
|
10
12
|
tool: string;
|
|
11
13
|
kind: ToolKind;
|
|
@@ -23,6 +25,9 @@ export interface AttemptOutcomeState {
|
|
|
23
25
|
webRequiredUnsatisfied: boolean;
|
|
24
26
|
toolWarningsCount: number;
|
|
25
27
|
status: AttemptOutcomeStatus;
|
|
28
|
+
/** D-16 model-attested work outcome (from the finalizer); absent on routes
|
|
29
|
+
* with no work_report transport. */
|
|
30
|
+
workState?: WorkState;
|
|
26
31
|
}
|
|
27
32
|
export interface WebEvidenceState {
|
|
28
33
|
required: boolean;
|
|
@@ -31,10 +36,44 @@ export interface WebEvidenceState {
|
|
|
31
36
|
attempted: boolean;
|
|
32
37
|
satisfied: boolean;
|
|
33
38
|
failed: boolean;
|
|
39
|
+
/** QA-042: retrieval strength — "verified" once any web result carried a
|
|
40
|
+
* typed successful retrieval, else "dispatched" once web activity completed
|
|
41
|
+
* with no typed outcome (codex), else "none". Never downgrades verified. */
|
|
42
|
+
verification: "verified" | "dispatched" | "none";
|
|
34
43
|
tool: string | null;
|
|
35
44
|
target: string | null;
|
|
36
45
|
errorSummary: string | null;
|
|
37
46
|
}
|
|
47
|
+
/**
|
|
48
|
+
* QA-040: runtime browser-MCP evidence for one attempt. `requested` is set when
|
|
49
|
+
* the engine armed the browser injection (a fixed `browser` server namespace).
|
|
50
|
+
* A browser tool call/result matched to that injected server flips attempted/
|
|
51
|
+
* satisfied/failed — so a successful browser navigation is recognized as
|
|
52
|
+
* trusted live-web activity even though adapters normalize browser calls as
|
|
53
|
+
* `kind:"mcp"`. Spoof-resistant: only the engine-injected server name matches.
|
|
54
|
+
*/
|
|
55
|
+
export interface BrowserEvidenceState {
|
|
56
|
+
requested: boolean;
|
|
57
|
+
serverName: string | null;
|
|
58
|
+
attempted: boolean;
|
|
59
|
+
satisfied: boolean;
|
|
60
|
+
failed: boolean;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Delegation-belt runtime readiness for one attempt (QA-024). `requested` is
|
|
64
|
+
* set at attempt creation when a belt MCP server was injected into the spec;
|
|
65
|
+
* `ready`/`failed` are filled from the harness's `started` event (its
|
|
66
|
+
* `mcp_servers[<belt>].status`); `toolEvidence` flips when any `mcp__<belt>__*`
|
|
67
|
+
* tool actually runs. A requested belt that reports `failed` with no tool
|
|
68
|
+
* evidence is the false-success trap the outcome axis must catch.
|
|
69
|
+
*/
|
|
70
|
+
export interface DelegationBeltState {
|
|
71
|
+
requested: boolean;
|
|
72
|
+
serverName: string | null;
|
|
73
|
+
ready: boolean;
|
|
74
|
+
failed: boolean;
|
|
75
|
+
toolEvidence: boolean;
|
|
76
|
+
}
|
|
38
77
|
export interface AttemptTelemetry {
|
|
39
78
|
requestRequirements: RequestRequirementResolution[];
|
|
40
79
|
toolErrors: ToolErrorRecord[];
|
|
@@ -58,17 +97,32 @@ export interface AttemptTelemetry {
|
|
|
58
97
|
/** Model hint the engine SENT this attempt (requested side; observedModel is
|
|
59
98
|
* the disclosed side of the model x route truth). */
|
|
60
99
|
requestedModel: string | null;
|
|
61
|
-
/** Adapter-declared transient failures seen during this attempt
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
retryDelayMs: number | null;
|
|
65
|
-
}[];
|
|
100
|
+
/** Adapter-declared transient failures seen during this attempt, each
|
|
101
|
+
* classified into the GH #31 typed taxonomy the retry policy gates on. */
|
|
102
|
+
transientFailures: TransientFailureObservation[];
|
|
66
103
|
/** TYPED vendor rate-limit signals seen during this attempt (W5.4): the
|
|
67
104
|
* rotation predicate reads these, never prose or plain transients. */
|
|
68
105
|
rateLimits: {
|
|
69
106
|
retryDelayMs: number | null;
|
|
70
107
|
resetsAt: string | null;
|
|
71
108
|
}[];
|
|
109
|
+
/** Delegation-belt runtime readiness (QA-024); requested=false on non-delegate attempts. */
|
|
110
|
+
delegationBelt: DelegationBeltState;
|
|
111
|
+
/** Browser-MCP runtime evidence (QA-040); requested=false unless the browser
|
|
112
|
+
* injection was armed for this attempt. */
|
|
113
|
+
browser: BrowserEvidenceState;
|
|
114
|
+
/** D-16: a terminal `capacity_exhausted` context signal was observed this
|
|
115
|
+
* attempt (never a transient; consumed by the finalizer, not the retry loop). */
|
|
116
|
+
contextExhausted: boolean;
|
|
117
|
+
/** D-16d: the typed cause of the terminal capacity exhaustion (last-wins),
|
|
118
|
+
* or null when none observed. The continuation controller keys eligibility on
|
|
119
|
+
* `repeated_refill` (claude's rapid-refill breaker), never on `prompt_too_long`
|
|
120
|
+
* (an irreducible packet). */
|
|
121
|
+
contextExhaustedCause: NonNullable<HarnessEvent["context"]>["cause"] | null;
|
|
122
|
+
/** D-16c: the raw `{work_report}` payload a `side_tool` route surfaced on its
|
|
123
|
+
* final message (claude StructuredOutput tool), or null. The unwrap validates
|
|
124
|
+
* it while the markdown answer stays the deliverable. */
|
|
125
|
+
sideToolWorkReport: unknown;
|
|
72
126
|
/** Contract/outcome truth for this attempt, produced by the orchestrator. */
|
|
73
127
|
outcome: AttemptOutcomeState | null;
|
|
74
128
|
/** Token usage summed across this attempt's usage events (money stays in the
|
|
@@ -89,7 +143,30 @@ export interface AttemptTelemetry {
|
|
|
89
143
|
unknownUsd: number;
|
|
90
144
|
};
|
|
91
145
|
}
|
|
92
|
-
export declare function createAttemptTelemetry(policy: ExternalContextPolicy, webRequired: boolean, effectiveMode?: ExternalContextPolicy, requestRequirements?: RequestRequirementResolution[], requestedModel?: string | null
|
|
146
|
+
export declare function createAttemptTelemetry(policy: ExternalContextPolicy, webRequired: boolean, effectiveMode?: ExternalContextPolicy, requestRequirements?: RequestRequirementResolution[], requestedModel?: string | null,
|
|
147
|
+
/** The delegation-belt MCP server name injected into THIS attempt's spec, or
|
|
148
|
+
* null when no belt was injected (QA-024). Non-null marks the belt requested. */
|
|
149
|
+
beltServerName?: string | null,
|
|
150
|
+
/** The browser MCP server name armed for THIS attempt (fixed `browser`
|
|
151
|
+
* namespace), or null when the browser was not injected (QA-040). Non-null
|
|
152
|
+
* marks the browser requested/armed. */
|
|
153
|
+
browserServerName?: string | null): AttemptTelemetry;
|
|
154
|
+
/**
|
|
155
|
+
* The delegation belt was requested (--delegate injected it) but never became
|
|
156
|
+
* operational: the harness reported the server `failed` and no belt tool ever
|
|
157
|
+
* ran (QA-024). This is the false-success trap — the harness may have answered
|
|
158
|
+
* from its own native subagent with no Claudexor sub-run provenance. A belt
|
|
159
|
+
* that was ready-but-unused is NOT unavailable (docs leave the spawn decision to
|
|
160
|
+
* the harness); only a startup failure counts.
|
|
161
|
+
*/
|
|
162
|
+
export declare function delegationBeltUnavailable(t: AttemptTelemetry): boolean;
|
|
163
|
+
/**
|
|
164
|
+
* QA-040: the browser was armed but never called while generic web evidence
|
|
165
|
+
* satisfied the run — a legitimately policy-satisfied run (e.g. web_search
|
|
166
|
+
* answered) that nonetheless did not exercise the requested browser. Disclosure
|
|
167
|
+
* only: it must NOT fail the run.
|
|
168
|
+
*/
|
|
169
|
+
export declare function browserUnused(t: AttemptTelemetry): boolean;
|
|
93
170
|
/**
|
|
94
171
|
* Observe a normalized harness event into the attempt telemetry. Governance is
|
|
95
172
|
* fully typed: only the `tool` ToolRef on tool_call/tool_result/file_change
|
|
@@ -104,6 +181,10 @@ export declare function setAttemptOutcome(t: AttemptTelemetry, opts: {
|
|
|
104
181
|
gatesPassed: boolean | null;
|
|
105
182
|
harnessErrored: boolean;
|
|
106
183
|
webRequiredUnsatisfied: boolean;
|
|
184
|
+
/** D-16 work_state from the unified finalizer (INV-116): a needs_input/
|
|
185
|
+
* incomplete veto rides HERE without flipping `status` — the lifecycle
|
|
186
|
+
* stays succeeded-class; applyability and the CLI exit read the axis. */
|
|
187
|
+
workState?: WorkState;
|
|
107
188
|
}): void;
|
|
108
189
|
/** Bounded telemetry summary for events/artifacts (full detail lives in telemetry.yaml). */
|
|
109
190
|
export declare function telemetrySummary(t: AttemptTelemetry): Record<string, unknown>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"attemptTelemetry.d.ts","sourceRoot":"","sources":["../src/attemptTelemetry.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EACV,sBAAsB,EACtB,cAAc,EACd,qBAAqB,EACrB,YAAY,EACZ,4BAA4B,EAC5B,YAAY,EACZ,QAAQ,
|
|
1
|
+
{"version":3,"file":"attemptTelemetry.d.ts","sourceRoot":"","sources":["../src/attemptTelemetry.ts"],"names":[],"mappings":"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"}
|
package/dist/attemptTelemetry.js
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
import { redactSecrets } from "@claudexor/util";
|
|
2
|
-
|
|
2
|
+
import { classifyCompletedCrash, classifyRateLimit, classifyStatusError, classifyTransientSignal, } from "./transientClassify.js";
|
|
3
|
+
export { classifyAdapterThrow } from "./transientClassify.js";
|
|
4
|
+
export function createAttemptTelemetry(policy, webRequired, effectiveMode = policy, requestRequirements = [], requestedModel = null,
|
|
5
|
+
/** The delegation-belt MCP server name injected into THIS attempt's spec, or
|
|
6
|
+
* null when no belt was injected (QA-024). Non-null marks the belt requested. */
|
|
7
|
+
beltServerName = null,
|
|
8
|
+
/** The browser MCP server name armed for THIS attempt (fixed `browser`
|
|
9
|
+
* namespace), or null when the browser was not injected (QA-040). Non-null
|
|
10
|
+
* marks the browser requested/armed. */
|
|
11
|
+
browserServerName = null) {
|
|
3
12
|
return {
|
|
4
13
|
requestRequirements,
|
|
5
14
|
toolErrors: [],
|
|
@@ -12,6 +21,7 @@ export function createAttemptTelemetry(policy, webRequired, effectiveMode = poli
|
|
|
12
21
|
attempted: false,
|
|
13
22
|
satisfied: false,
|
|
14
23
|
failed: false,
|
|
24
|
+
verification: "none",
|
|
15
25
|
tool: null,
|
|
16
26
|
target: null,
|
|
17
27
|
errorSummary: null,
|
|
@@ -24,6 +34,23 @@ export function createAttemptTelemetry(policy, webRequired, effectiveMode = poli
|
|
|
24
34
|
requestedModel,
|
|
25
35
|
transientFailures: [],
|
|
26
36
|
rateLimits: [],
|
|
37
|
+
delegationBelt: {
|
|
38
|
+
requested: beltServerName !== null,
|
|
39
|
+
serverName: beltServerName,
|
|
40
|
+
ready: false,
|
|
41
|
+
failed: false,
|
|
42
|
+
toolEvidence: false,
|
|
43
|
+
},
|
|
44
|
+
browser: {
|
|
45
|
+
requested: browserServerName !== null,
|
|
46
|
+
serverName: browserServerName,
|
|
47
|
+
attempted: false,
|
|
48
|
+
satisfied: false,
|
|
49
|
+
failed: false,
|
|
50
|
+
},
|
|
51
|
+
contextExhausted: false,
|
|
52
|
+
contextExhaustedCause: null,
|
|
53
|
+
sideToolWorkReport: null,
|
|
27
54
|
outcome: null,
|
|
28
55
|
usage: { inputTokens: null, outputTokens: null, cachedInputTokens: null },
|
|
29
56
|
usageCost: { cashUsd: 0, valuationUsd: 0, unknownUsd: 0 },
|
|
@@ -34,6 +61,76 @@ export function createAttemptTelemetry(policy, webRequired, effectiveMode = poli
|
|
|
34
61
|
function addToken(acc, value) {
|
|
35
62
|
return value === undefined ? acc : (acc ?? 0) + value;
|
|
36
63
|
}
|
|
64
|
+
/**
|
|
65
|
+
* Read the injected belt server's status out of the harness `started` frame's
|
|
66
|
+
* `mcp_servers` list (QA-024). The shape is the vendor's — claude emits
|
|
67
|
+
* `{ name, status }` entries — so we defensively narrow each entry and match by
|
|
68
|
+
* the injected belt server name. `status:"failed"` (or "error") is the startup
|
|
69
|
+
* failure the outcome axis must not let terminalize a silent success.
|
|
70
|
+
*/
|
|
71
|
+
function observeBeltStartup(t, ev) {
|
|
72
|
+
const payload = ev.payload;
|
|
73
|
+
const servers = payload?.["mcp_servers"];
|
|
74
|
+
if (!Array.isArray(servers))
|
|
75
|
+
return;
|
|
76
|
+
for (const raw of servers) {
|
|
77
|
+
if (!raw || typeof raw !== "object")
|
|
78
|
+
continue;
|
|
79
|
+
const entry = raw;
|
|
80
|
+
if (entry.name !== t.delegationBelt.serverName)
|
|
81
|
+
continue;
|
|
82
|
+
const status = typeof entry.status === "string" ? entry.status.toLowerCase() : "";
|
|
83
|
+
if (status === "failed" || status === "error")
|
|
84
|
+
t.delegationBelt.failed = true;
|
|
85
|
+
else if (status === "connected" || status === "ready" || status === "ok") {
|
|
86
|
+
t.delegationBelt.ready = true;
|
|
87
|
+
}
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* The delegation belt was requested (--delegate injected it) but never became
|
|
93
|
+
* operational: the harness reported the server `failed` and no belt tool ever
|
|
94
|
+
* ran (QA-024). This is the false-success trap — the harness may have answered
|
|
95
|
+
* from its own native subagent with no Claudexor sub-run provenance. A belt
|
|
96
|
+
* that was ready-but-unused is NOT unavailable (docs leave the spawn decision to
|
|
97
|
+
* the harness); only a startup failure counts.
|
|
98
|
+
*/
|
|
99
|
+
export function delegationBeltUnavailable(t) {
|
|
100
|
+
return t.delegationBelt.requested && t.delegationBelt.failed && !t.delegationBelt.toolEvidence;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* QA-040: does this tool ref belong to the engine-armed browser MCP? Adapters
|
|
104
|
+
* normalize browser calls as `kind:"mcp"` (codex `browser:browser_navigate`,
|
|
105
|
+
* claude `mcp__browser__browser_navigate`), so the ToolKind cannot express
|
|
106
|
+
* "browser". Match on the ENGINE-INJECTED server namespace only — a user MCP
|
|
107
|
+
* server cannot spoof trusted browser evidence because the browser is matched
|
|
108
|
+
* solely when the engine armed it under its fixed injected name.
|
|
109
|
+
*/
|
|
110
|
+
function matchesBrowser(t, tool) {
|
|
111
|
+
const server = t.browser.serverName;
|
|
112
|
+
if (!t.browser.requested || !server)
|
|
113
|
+
return false;
|
|
114
|
+
return tool.name.startsWith(`mcp__${server}__`) || (tool.target ?? "").startsWith(`${server}:`);
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* QA-040: the browser was armed but never called while generic web evidence
|
|
118
|
+
* satisfied the run — a legitimately policy-satisfied run (e.g. web_search
|
|
119
|
+
* answered) that nonetheless did not exercise the requested browser. Disclosure
|
|
120
|
+
* only: it must NOT fail the run.
|
|
121
|
+
*/
|
|
122
|
+
export function browserUnused(t) {
|
|
123
|
+
return t.browser.requested && !t.browser.attempted && t.web.satisfied;
|
|
124
|
+
}
|
|
125
|
+
/** QA-042: raise the web retrieval strength, never downgrading a proven
|
|
126
|
+
* `verified`. A typed success promotes to verified; any other satisfied web
|
|
127
|
+
* activity is dispatch-strength (completed, content not typed-proven). */
|
|
128
|
+
function bumpWebVerification(t, retrieval) {
|
|
129
|
+
if (retrieval === "verified")
|
|
130
|
+
t.web.verification = "verified";
|
|
131
|
+
else if (t.web.verification !== "verified")
|
|
132
|
+
t.web.verification = "dispatched";
|
|
133
|
+
}
|
|
37
134
|
/**
|
|
38
135
|
* Observe a normalized harness event into the attempt telemetry. Governance is
|
|
39
136
|
* fully typed: only the `tool` ToolRef on tool_call/tool_result/file_change
|
|
@@ -41,6 +138,21 @@ function addToken(acc, value) {
|
|
|
41
138
|
* matching or tool-name heuristics.
|
|
42
139
|
*/
|
|
43
140
|
export function observeAttemptTelemetry(t, ev) {
|
|
141
|
+
// Delegation belt readiness (QA-024): the harness's `started` frame lists its
|
|
142
|
+
// MCP servers and each one's status. When the engine injected a belt, read
|
|
143
|
+
// THAT server's status as first-class readiness truth — never prose. A
|
|
144
|
+
// `failed` belt with no later tool evidence is the false-success trap.
|
|
145
|
+
if (ev.type === "started" && t.delegationBelt.requested) {
|
|
146
|
+
observeBeltStartup(t, ev);
|
|
147
|
+
}
|
|
148
|
+
// Belt tool evidence: any `mcp__<belt>__*` tool call/result proves the belt
|
|
149
|
+
// was actually reachable and used (a real Claudexor sub-run path), which
|
|
150
|
+
// distinguishes a used belt from one the harness silently substituted.
|
|
151
|
+
if (t.delegationBelt.requested && t.delegationBelt.serverName && ev.tool?.name) {
|
|
152
|
+
if (ev.tool.name.startsWith(`mcp__${t.delegationBelt.serverName}`)) {
|
|
153
|
+
t.delegationBelt.toolEvidence = true;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
44
156
|
// Route evidence: remember the model identity the stream itself disclosed.
|
|
45
157
|
if (ev.observed_model && !t.observedModel)
|
|
46
158
|
t.observedModel = ev.observed_model;
|
|
@@ -83,18 +195,38 @@ export function observeAttemptTelemetry(t, ev) {
|
|
|
83
195
|
// produced the deliverable.
|
|
84
196
|
if (ev.credential_profile_id)
|
|
85
197
|
t.profileId = ev.credential_profile_id;
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
198
|
+
// #31: classify every disclosed transient into the typed taxonomy (see
|
|
199
|
+
// transientClassify.ts). An adapter `transient` and a `rate_limit` are
|
|
200
|
+
// retryable failures; the vendor's typed `status.error_category` surfaces only
|
|
201
|
+
// the deterministic FAILURE classes (auth/capability/config) so required-
|
|
202
|
+
// actions attach the right remediation. Rate limits ALSO stay in rateLimits
|
|
203
|
+
// for the W5.4 rotation predicate.
|
|
204
|
+
if (ev.transient)
|
|
205
|
+
t.transientFailures.push(classifyTransientSignal(ev.transient));
|
|
92
206
|
if (ev.rate_limit) {
|
|
93
207
|
t.rateLimits.push({
|
|
94
208
|
retryDelayMs: ev.rate_limit.retry_delay_ms ?? null,
|
|
95
209
|
resetsAt: ev.rate_limit.resets_at ?? null,
|
|
96
210
|
});
|
|
211
|
+
t.transientFailures.push(classifyRateLimit(ev.rate_limit.retry_delay_ms ?? null));
|
|
97
212
|
}
|
|
213
|
+
if (ev.status?.error_category) {
|
|
214
|
+
const obs = classifyStatusError(ev.status.error_category, ev.status.retry_delay_ms ?? null);
|
|
215
|
+
if (obs)
|
|
216
|
+
t.transientFailures.push(obs);
|
|
217
|
+
}
|
|
218
|
+
// D-16 context signal: a terminal capacity_exhausted marks the attempt for the
|
|
219
|
+
// finalizer's interrupted/context_capacity_exhausted mapping. Context signals
|
|
220
|
+
// NEVER enter the transient-retry loop (they are not transient failures).
|
|
221
|
+
if (ev.context?.kind === "capacity_exhausted") {
|
|
222
|
+
t.contextExhausted = true;
|
|
223
|
+
t.contextExhaustedCause = ev.context.cause ?? null;
|
|
224
|
+
}
|
|
225
|
+
// D-16c side_tool: capture the raw work_report the StructuredOutput tool
|
|
226
|
+
// surfaced on the final message (last-wins). The unwrap validates it.
|
|
227
|
+
const sideTool = ev.payload?.["work_report_side_tool"];
|
|
228
|
+
if (sideTool !== undefined)
|
|
229
|
+
t.sideToolWorkReport = sideTool;
|
|
98
230
|
// Token usage: SUM across the attempt's usage events (single-event adapters
|
|
99
231
|
// sum == last-wins; codex per-turn needs the sum). Money is the ledger's job.
|
|
100
232
|
if (ev.type === "usage" && ev.usage) {
|
|
@@ -107,6 +239,11 @@ export function observeAttemptTelemetry(t, ev) {
|
|
|
107
239
|
Number(ev.payload?.["dropped_unrecognized_events"] ?? 0);
|
|
108
240
|
if (Number.isFinite(dropped) && dropped > 0)
|
|
109
241
|
t.droppedEvents += dropped;
|
|
242
|
+
// #31 process crash: the run loop discloses a non-aborted signal kill, a
|
|
243
|
+
// non-zero exit, or a spawn failure as TYPED payload fields (never prose).
|
|
244
|
+
const crash = classifyCompletedCrash(ev.payload);
|
|
245
|
+
if (crash)
|
|
246
|
+
t.transientFailures.push(crash);
|
|
110
247
|
return;
|
|
111
248
|
}
|
|
112
249
|
const tool = ev.tool;
|
|
@@ -118,6 +255,15 @@ export function observeAttemptTelemetry(t, ev) {
|
|
|
118
255
|
t.web.tool = tool.name;
|
|
119
256
|
t.web.target = tool.target ?? t.web.target;
|
|
120
257
|
}
|
|
258
|
+
// QA-040: an armed browser MCP call is trusted live-web ACTIVITY even though
|
|
259
|
+
// its kind is "mcp" — mark the browser attempted and count it as web
|
|
260
|
+
// attempted (a successful result below satisfies the generic web gate).
|
|
261
|
+
if (matchesBrowser(t, tool)) {
|
|
262
|
+
t.browser.attempted = true;
|
|
263
|
+
t.web.attempted = true;
|
|
264
|
+
t.web.tool = t.web.tool ?? tool.name;
|
|
265
|
+
t.web.target = tool.target ?? t.web.target;
|
|
266
|
+
}
|
|
121
267
|
return;
|
|
122
268
|
}
|
|
123
269
|
if (ev.type !== "tool_result")
|
|
@@ -133,6 +279,10 @@ export function observeAttemptTelemetry(t, ev) {
|
|
|
133
279
|
t.web.tool = tool.name;
|
|
134
280
|
t.web.target = tool.target ?? t.web.target;
|
|
135
281
|
}
|
|
282
|
+
if (matchesBrowser(t, tool)) {
|
|
283
|
+
t.browser.attempted = true;
|
|
284
|
+
t.web.attempted = true;
|
|
285
|
+
}
|
|
136
286
|
return;
|
|
137
287
|
}
|
|
138
288
|
if (tool.status === "error") {
|
|
@@ -151,6 +301,19 @@ export function observeAttemptTelemetry(t, ev) {
|
|
|
151
301
|
t.web.target = tool.target ?? t.web.target;
|
|
152
302
|
t.web.errorSummary = redactSecrets(tool.error_summary ?? "web tool result marked error").slice(0, 1000);
|
|
153
303
|
}
|
|
304
|
+
// QA-040: a failed armed-browser call is browser activity that did not
|
|
305
|
+
// satisfy. It contributes web `attempted` (a call was made) and, since the
|
|
306
|
+
// browser is a live-egress channel, a web failure — but a later successful
|
|
307
|
+
// web/browser call still recovers the generic gate (the ok branch below).
|
|
308
|
+
if (matchesBrowser(t, tool)) {
|
|
309
|
+
t.browser.attempted = true;
|
|
310
|
+
t.browser.failed = true;
|
|
311
|
+
t.web.attempted = true;
|
|
312
|
+
t.web.failed = true;
|
|
313
|
+
t.web.errorSummary =
|
|
314
|
+
t.web.errorSummary ??
|
|
315
|
+
redactSecrets(tool.error_summary ?? "browser tool result marked error").slice(0, 1000);
|
|
316
|
+
}
|
|
154
317
|
return;
|
|
155
318
|
}
|
|
156
319
|
// status === "ok": a later success of the SAME tool against the SAME target
|
|
@@ -191,6 +354,34 @@ export function observeAttemptTelemetry(t, ev) {
|
|
|
191
354
|
: null;
|
|
192
355
|
t.web.tool = tool.name;
|
|
193
356
|
t.web.target = tool.target ?? t.web.target;
|
|
357
|
+
// QA-042: the retrieval STRENGTH. A typed `verified` retrieval (claude
|
|
358
|
+
// WebFetch content) proves content; codex `web_search`/`open_page` stamp
|
|
359
|
+
// `dispatched` (completed, no typed fetch outcome — a hidden 502 is
|
|
360
|
+
// indistinguishable), so the gate is satisfied at DISPATCH strength only.
|
|
361
|
+
// Absent stamp is treated as dispatch (never claim verified without proof).
|
|
362
|
+
bumpWebVerification(t, tool.web_retrieval);
|
|
363
|
+
}
|
|
364
|
+
// QA-040: a successful armed-browser call is trusted live-web evidence. It
|
|
365
|
+
// satisfies the generic web gate AND records browser runtime evidence — a
|
|
366
|
+
// real navigation/screenshot is a typed success, so it is `verified` strength
|
|
367
|
+
// (unlike a dispatch-only codex web_search). A user MCP server cannot reach
|
|
368
|
+
// here: matchesBrowser only accepts the engine-injected server namespace.
|
|
369
|
+
if (matchesBrowser(t, tool)) {
|
|
370
|
+
t.browser.attempted = true;
|
|
371
|
+
t.browser.satisfied = true;
|
|
372
|
+
t.web.attempted = true;
|
|
373
|
+
t.web.satisfied = true;
|
|
374
|
+
t.web.verification = "verified";
|
|
375
|
+
// The recovery loop above already marked a matching earlier browser error
|
|
376
|
+
// recovered; recompute the disclosed failure rollup from what remains.
|
|
377
|
+
t.browser.failed = t.toolErrors.some((e) => e.kind === "mcp" &&
|
|
378
|
+
matchesBrowser(t, { name: e.tool, target: e.target ?? undefined }) &&
|
|
379
|
+
!e.recovered);
|
|
380
|
+
t.web.failed = t.toolErrors.some((e) => e.kind === "web" && !e.recovered) || t.browser.failed;
|
|
381
|
+
if (!t.web.failed)
|
|
382
|
+
t.web.errorSummary = null;
|
|
383
|
+
t.web.tool = t.web.tool ?? tool.name;
|
|
384
|
+
t.web.target = tool.target ?? t.web.target;
|
|
194
385
|
}
|
|
195
386
|
}
|
|
196
387
|
const TELEMETRY_TOOL_ERRORS_MAX = 20;
|
|
@@ -209,9 +400,18 @@ export function toolWarnings(t) {
|
|
|
209
400
|
export function setAttemptOutcome(t, opts) {
|
|
210
401
|
const warnings = toolWarnings(t).length;
|
|
211
402
|
const contractFailed = !opts.deliverablePresent || opts.gatesPassed === false;
|
|
403
|
+
// QA-024: a requested belt that failed to start with no tool evidence is an
|
|
404
|
+
// explicitly-requested capability that never became operational — treated
|
|
405
|
+
// like an unsatisfied hard requirement (never a silent clean success). It
|
|
406
|
+
// rides the same axis order as web: it can only ELEVATE severity, never mask
|
|
407
|
+
// a harder failure. NOTE (D-16 seam): this producer maps belt-unavailable to
|
|
408
|
+
// `failed`; a future finalizer that prefers a softer disclosure would flip
|
|
409
|
+
// this to `success_with_warnings` — the typed telemetry fact
|
|
410
|
+
// (delegation_belt.*) is what a consumer reads either way.
|
|
411
|
+
const beltUnavailable = delegationBeltUnavailable(t);
|
|
212
412
|
const status = opts.webRequiredUnsatisfied
|
|
213
413
|
? "blocked"
|
|
214
|
-
: opts.harnessErrored || contractFailed
|
|
414
|
+
: opts.harnessErrored || contractFailed || beltUnavailable
|
|
215
415
|
? "failed"
|
|
216
416
|
: warnings > 0
|
|
217
417
|
? "success_with_warnings"
|
|
@@ -223,6 +423,7 @@ export function setAttemptOutcome(t, opts) {
|
|
|
223
423
|
webRequiredUnsatisfied: opts.webRequiredUnsatisfied,
|
|
224
424
|
toolWarningsCount: warnings,
|
|
225
425
|
status,
|
|
426
|
+
...(opts.workState ? { workState: opts.workState } : {}),
|
|
226
427
|
};
|
|
227
428
|
}
|
|
228
429
|
function webStatus(t) {
|
|
@@ -246,10 +447,22 @@ export function telemetrySummary(t) {
|
|
|
246
447
|
attempted: t.web.attempted,
|
|
247
448
|
satisfied: t.web.satisfied,
|
|
248
449
|
status: webStatus(t),
|
|
450
|
+
verification: t.web.verification,
|
|
249
451
|
tool: t.web.tool,
|
|
250
452
|
target: t.web.target,
|
|
251
453
|
error_summary: t.web.errorSummary,
|
|
252
454
|
},
|
|
455
|
+
...(t.browser.requested
|
|
456
|
+
? {
|
|
457
|
+
browser_evidence: {
|
|
458
|
+
server_name: t.browser.serverName,
|
|
459
|
+
attempted: t.browser.attempted,
|
|
460
|
+
satisfied: t.browser.satisfied,
|
|
461
|
+
failed: t.browser.failed,
|
|
462
|
+
unused: browserUnused(t),
|
|
463
|
+
},
|
|
464
|
+
}
|
|
465
|
+
: {}),
|
|
253
466
|
tool_errors_total: t.toolErrors.length,
|
|
254
467
|
unrecovered_tool_errors: unrecovered.length,
|
|
255
468
|
tool_errors: unrecovered
|
|
@@ -264,11 +477,25 @@ export function telemetrySummary(t) {
|
|
|
264
477
|
}
|
|
265
478
|
: {}),
|
|
266
479
|
...(t.outcome ? { outcome: t.outcome } : {}),
|
|
480
|
+
...(t.delegationBelt.requested
|
|
481
|
+
? {
|
|
482
|
+
delegation_belt: {
|
|
483
|
+
server_name: t.delegationBelt.serverName,
|
|
484
|
+
ready: t.delegationBelt.ready,
|
|
485
|
+
failed: t.delegationBelt.failed,
|
|
486
|
+
tool_evidence: t.delegationBelt.toolEvidence,
|
|
487
|
+
unavailable: delegationBeltUnavailable(t),
|
|
488
|
+
},
|
|
489
|
+
}
|
|
490
|
+
: {}),
|
|
267
491
|
...(t.transientFailures.length > 0
|
|
268
492
|
? {
|
|
269
|
-
transient_failures: t.transientFailures
|
|
270
|
-
.
|
|
271
|
-
|
|
493
|
+
transient_failures: t.transientFailures.slice(-5).map((e) => ({
|
|
494
|
+
kind: e.kind,
|
|
495
|
+
category: e.category,
|
|
496
|
+
retryable: e.retryable,
|
|
497
|
+
retry_delay_ms: e.retryDelayMs,
|
|
498
|
+
})),
|
|
272
499
|
}
|
|
273
500
|
: {}),
|
|
274
501
|
...(t.droppedEvents > 0 ? { dropped_events: t.droppedEvents } : {}),
|
|
@@ -294,6 +521,7 @@ export function attemptTelemetryRecord(attemptId, harnessId, t) {
|
|
|
294
521
|
attempted: t.web.attempted,
|
|
295
522
|
satisfied: t.web.satisfied,
|
|
296
523
|
status: webStatus(t),
|
|
524
|
+
verification: t.web.verification,
|
|
297
525
|
tool: t.web.tool,
|
|
298
526
|
target: t.web.target,
|
|
299
527
|
error_summary: t.web.errorSummary,
|
|
@@ -310,17 +538,50 @@ export function attemptTelemetryRecord(attemptId, harnessId, t) {
|
|
|
310
538
|
unrecovered_tool_errors: unrecoveredToolErrors(t).length,
|
|
311
539
|
statusless_tool_results: t.statuslessResults,
|
|
312
540
|
dropped_events: t.droppedEvents,
|
|
313
|
-
transient_failures: t.transientFailures
|
|
314
|
-
.
|
|
315
|
-
|
|
541
|
+
transient_failures: t.transientFailures.slice(-TELEMETRY_TOOL_ERRORS_MAX).map((e) => ({
|
|
542
|
+
kind: e.kind,
|
|
543
|
+
category: e.category,
|
|
544
|
+
retryable: e.retryable,
|
|
545
|
+
retry_delay_ms: e.retryDelayMs,
|
|
546
|
+
http_status: e.httpStatus,
|
|
547
|
+
signal: e.signal,
|
|
548
|
+
adapter_code: e.adapterCode,
|
|
549
|
+
})),
|
|
316
550
|
outcome: {
|
|
317
551
|
deliverable_present: t.outcome?.deliverablePresent ?? false,
|
|
318
552
|
gates_passed: t.outcome?.gatesPassed ?? null,
|
|
319
553
|
harness_errored: t.outcome?.harnessErrored ?? false,
|
|
320
554
|
web_required_unsatisfied: t.outcome?.webRequiredUnsatisfied ?? false,
|
|
555
|
+
delegation_belt_unavailable: delegationBeltUnavailable(t),
|
|
321
556
|
tool_warnings_count: t.outcome?.toolWarningsCount ?? warnings.length,
|
|
322
557
|
status: t.outcome?.status ?? (warnings.length > 0 ? "success_with_warnings" : "success"),
|
|
558
|
+
...(t.outcome?.workState ? { work_state: t.outcome.workState } : {}),
|
|
323
559
|
},
|
|
560
|
+
// Only present when a belt was actually injected into this attempt (QA-024).
|
|
561
|
+
...(t.delegationBelt.requested
|
|
562
|
+
? {
|
|
563
|
+
delegation_belt: {
|
|
564
|
+
requested: t.delegationBelt.requested,
|
|
565
|
+
server_name: t.delegationBelt.serverName,
|
|
566
|
+
ready: t.delegationBelt.ready,
|
|
567
|
+
failed: t.delegationBelt.failed,
|
|
568
|
+
tool_evidence: t.delegationBelt.toolEvidence,
|
|
569
|
+
},
|
|
570
|
+
}
|
|
571
|
+
: {}),
|
|
572
|
+
// Only present when the browser was armed for this attempt (QA-040).
|
|
573
|
+
...(t.browser.requested
|
|
574
|
+
? {
|
|
575
|
+
browser: {
|
|
576
|
+
requested: t.browser.requested,
|
|
577
|
+
server_name: t.browser.serverName,
|
|
578
|
+
attempted: t.browser.attempted,
|
|
579
|
+
satisfied: t.browser.satisfied,
|
|
580
|
+
failed: t.browser.failed,
|
|
581
|
+
unused: browserUnused(t),
|
|
582
|
+
},
|
|
583
|
+
}
|
|
584
|
+
: {}),
|
|
324
585
|
usage: {
|
|
325
586
|
input_tokens: t.usage.inputTokens,
|
|
326
587
|
output_tokens: t.usage.outputTokens,
|
|
@@ -360,6 +621,7 @@ export function aggregateRunWebEvidence(records, contract) {
|
|
|
360
621
|
attempted: false,
|
|
361
622
|
satisfied: false,
|
|
362
623
|
status: contract.external_context.web_required ? "unverified" : "none",
|
|
624
|
+
verification: "none",
|
|
363
625
|
tool: null,
|
|
364
626
|
target: null,
|
|
365
627
|
error_summary: null,
|