engineering-behavior-observatory 0.2.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 (178) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +151 -0
  3. package/contracts/codex-app-server-0.150.1/manifest.json +25 -0
  4. package/contracts/codex-app-server-0.150.1/schema/InitializeParams.json +84 -0
  5. package/contracts/codex-app-server-0.150.1/schema/JSONRPCMessage.json +137 -0
  6. package/contracts/codex-app-server-0.150.1/schema/v2/ThreadReadParams.json +17 -0
  7. package/contracts/codex-app-server-0.150.1/schema/v2/ThreadTokenUsageUpdatedNotification.json +82 -0
  8. package/contracts/codex-app-server-0.150.1/schema/v2/TurnInterruptParams.json +17 -0
  9. package/contracts/codex-app-server-0.150.1/types/AskForApproval.ts +5 -0
  10. package/contracts/codex-app-server-0.150.1/types/ClientNotification.ts +5 -0
  11. package/contracts/codex-app-server-0.150.1/types/SandboxMode.ts +5 -0
  12. package/contracts/codex-app-server-0.150.1/types/ThreadReadParams.ts +9 -0
  13. package/contracts/codex-app-server-0.150.1/types/TokenUsageBreakdown.ts +5 -0
  14. package/contracts/codex-app-server-0.150.1/types/TurnInterruptParams.ts +5 -0
  15. package/contracts/codex-app-server-0.153.4/manifest.json +27 -0
  16. package/contracts/codex-app-server-0.153.4/schema/JSONRPCMessage.json +137 -0
  17. package/contracts/codex-app-server-0.153.4/schema/v1/InitializeParams.json +84 -0
  18. package/contracts/codex-app-server-0.153.4/schema/v2/ThreadReadParams.json +17 -0
  19. package/contracts/codex-app-server-0.153.4/schema/v2/ThreadStartParams.json +515 -0
  20. package/contracts/codex-app-server-0.153.4/schema/v2/ThreadTokenUsageUpdatedNotification.json +82 -0
  21. package/contracts/codex-app-server-0.153.4/schema/v2/TurnInterruptParams.json +17 -0
  22. package/contracts/codex-app-server-0.153.4/schema/v2/TurnStartParams.json +921 -0
  23. package/contracts/codex-app-server-0.153.4/types/AskForApproval.ts +5 -0
  24. package/contracts/codex-app-server-0.153.4/types/ClientNotification.ts +5 -0
  25. package/contracts/codex-app-server-0.153.4/types/SandboxMode.ts +5 -0
  26. package/contracts/codex-app-server-0.153.4/types/ThreadReadParams.ts +12 -0
  27. package/contracts/codex-app-server-0.153.4/types/TokenUsageBreakdown.ts +5 -0
  28. package/contracts/codex-app-server-0.153.4/types/TurnInterruptParams.ts +5 -0
  29. package/contracts/openhands-agent-server-v1.44.1.json +65 -0
  30. package/contracts/openhands-agent-server-v1.46.0.json +46 -0
  31. package/dist/contracts/codex-app-server-0.153.4/types/AskForApproval.d.ts +9 -0
  32. package/dist/contracts/codex-app-server-0.153.4/types/AskForApproval.js +2 -0
  33. package/dist/contracts/codex-app-server-0.153.4/types/ClientNotification.d.ts +3 -0
  34. package/dist/contracts/codex-app-server-0.153.4/types/ClientNotification.js +2 -0
  35. package/dist/contracts/codex-app-server-0.153.4/types/SandboxMode.d.ts +1 -0
  36. package/dist/contracts/codex-app-server-0.153.4/types/SandboxMode.js +2 -0
  37. package/dist/contracts/codex-app-server-0.153.4/types/ThreadReadParams.d.ts +10 -0
  38. package/dist/contracts/codex-app-server-0.153.4/types/ThreadReadParams.js +2 -0
  39. package/dist/contracts/codex-app-server-0.153.4/types/TokenUsageBreakdown.d.ts +8 -0
  40. package/dist/contracts/codex-app-server-0.153.4/types/TokenUsageBreakdown.js +2 -0
  41. package/dist/contracts/codex-app-server-0.153.4/types/TurnInterruptParams.d.ts +4 -0
  42. package/dist/contracts/codex-app-server-0.153.4/types/TurnInterruptParams.js +2 -0
  43. package/dist/src/agent-sdk-normalizer.d.ts +22 -0
  44. package/dist/src/agent-sdk-normalizer.js +995 -0
  45. package/dist/src/agent-sdk-run.d.ts +31 -0
  46. package/dist/src/agent-sdk-run.js +242 -0
  47. package/dist/src/agent-sdk-runner.d.ts +96 -0
  48. package/dist/src/agent-sdk-runner.js +407 -0
  49. package/dist/src/agent-sdk.d.ts +294 -0
  50. package/dist/src/agent-sdk.js +644 -0
  51. package/dist/src/aggregation.d.ts +183 -0
  52. package/dist/src/aggregation.js +513 -0
  53. package/dist/src/artifacts.d.ts +36 -0
  54. package/dist/src/artifacts.js +1372 -0
  55. package/dist/src/atlas-grafana.d.ts +377 -0
  56. package/dist/src/atlas-grafana.js +47 -0
  57. package/dist/src/atlas-html.d.ts +2 -0
  58. package/dist/src/atlas-html.js +34 -0
  59. package/dist/src/atlas.d.ts +130 -0
  60. package/dist/src/atlas.js +235 -0
  61. package/dist/src/behavior-assertions.d.ts +95 -0
  62. package/dist/src/behavior-assertions.js +154 -0
  63. package/dist/src/cli.d.ts +5 -0
  64. package/dist/src/cli.js +957 -0
  65. package/dist/src/codex-judge.d.ts +44 -0
  66. package/dist/src/codex-judge.js +214 -0
  67. package/dist/src/codex-run.d.ts +114 -0
  68. package/dist/src/codex-run.js +519 -0
  69. package/dist/src/codex.d.ts +187 -0
  70. package/dist/src/codex.js +1028 -0
  71. package/dist/src/contracts.d.ts +155 -0
  72. package/dist/src/contracts.js +866 -0
  73. package/dist/src/corpus.d.ts +67 -0
  74. package/dist/src/corpus.js +540 -0
  75. package/dist/src/cursor-sdk-runner.d.ts +81 -0
  76. package/dist/src/cursor-sdk-runner.js +362 -0
  77. package/dist/src/cursor-sdk.d.ts +81 -0
  78. package/dist/src/cursor-sdk.js +1078 -0
  79. package/dist/src/deepseek-adapter.d.ts +152 -0
  80. package/dist/src/deepseek-adapter.js +777 -0
  81. package/dist/src/exports.d.ts +69 -0
  82. package/dist/src/exports.js +966 -0
  83. package/dist/src/human-calibration.d.ts +167 -0
  84. package/dist/src/human-calibration.js +618 -0
  85. package/dist/src/index.d.ts +71 -0
  86. package/dist/src/index.js +38 -0
  87. package/dist/src/lifecycle.d.ts +196 -0
  88. package/dist/src/lifecycle.js +1889 -0
  89. package/dist/src/normalization-integrity.d.ts +128 -0
  90. package/dist/src/normalization-integrity.js +429 -0
  91. package/dist/src/openhands-run.d.ts +36 -0
  92. package/dist/src/openhands-run.js +415 -0
  93. package/dist/src/openhands.d.ts +130 -0
  94. package/dist/src/openhands.js +859 -0
  95. package/dist/src/pi.d.ts +203 -0
  96. package/dist/src/pi.js +1345 -0
  97. package/dist/src/process-protocol.d.ts +245 -0
  98. package/dist/src/process-protocol.js +1261 -0
  99. package/dist/src/retained-evidence.d.ts +12 -0
  100. package/dist/src/retained-evidence.js +201 -0
  101. package/dist/src/run-bundles.d.ts +193 -0
  102. package/dist/src/run-bundles.js +993 -0
  103. package/dist/src/scheduler.d.ts +109 -0
  104. package/dist/src/scheduler.js +1080 -0
  105. package/dist/src/semantic-judge.d.ts +194 -0
  106. package/dist/src/semantic-judge.js +875 -0
  107. package/dist/src/structural-observations.d.ts +124 -0
  108. package/dist/src/structural-observations.js +671 -0
  109. package/dist/src/task-packets.d.ts +115 -0
  110. package/dist/src/task-packets.js +683 -0
  111. package/dist/src/uniform-events.d.ts +120 -0
  112. package/dist/src/uniform-events.js +158 -0
  113. package/dist/src/verifiers.d.ts +116 -0
  114. package/dist/src/verifiers.js +819 -0
  115. package/dist/src/workspaces.d.ts +56 -0
  116. package/dist/src/workspaces.js +1314 -0
  117. package/docs/README.md +60 -0
  118. package/docs/development/README.md +71 -0
  119. package/docs/development/documentation-sync.md +58 -0
  120. package/docs/development/extension-contracts.md +307 -0
  121. package/docs/evaluation/README.md +48 -0
  122. package/docs/evaluation/aggregation.md +112 -0
  123. package/docs/evaluation/behavior-assertions.md +45 -0
  124. package/docs/evaluation/human-calibration.md +170 -0
  125. package/docs/evaluation/normalization-integrity.md +80 -0
  126. package/docs/evaluation/semantic-judge.md +188 -0
  127. package/docs/evaluation/structural-observations.md +84 -0
  128. package/docs/evaluation/uniform-events.md +131 -0
  129. package/docs/guides/atlas.md +144 -0
  130. package/docs/guides/evidence-and-sharing.md +100 -0
  131. package/docs/guides/operator-guide.md +424 -0
  132. package/docs/guides/quickstart.md +152 -0
  133. package/docs/guides/telemetry.md +66 -0
  134. package/docs/harnesses/README.md +31 -0
  135. package/docs/harnesses/claude-agent-sdk.md +61 -0
  136. package/docs/harnesses/codex-harness.md +174 -0
  137. package/docs/harnesses/cursor-sdk.md +149 -0
  138. package/docs/harnesses/deepseek-harness.md +134 -0
  139. package/docs/harnesses/openhands-agent-server.md +153 -0
  140. package/docs/harnesses/pi-sdk.md +66 -0
  141. package/docs/reference/README.md +19 -0
  142. package/docs/reference/agent-sdk-operational-runner.md +118 -0
  143. package/docs/reference/cli.md +114 -0
  144. package/docs/reference/contracts.md +222 -0
  145. package/docs/reference/run-bundle-contract.md +354 -0
  146. package/docs/reference/run-lifecycle.md +54 -0
  147. package/examples/cursor-sdk/README.md +11 -0
  148. package/examples/cursor-sdk/capture-profile.json +1 -0
  149. package/examples/cursor-sdk/harness.json +1 -0
  150. package/examples/cursor-sdk/model.json +1 -0
  151. package/examples/cursor-sdk/native-limits.json +1 -0
  152. package/examples/cursor-sdk/native-tool-policy.json +1 -0
  153. package/ontology/behavior-categories.v1.json +46 -0
  154. package/package.json +66 -0
  155. package/release/0.1.0/KNOWN_LIMITATIONS.md +35 -0
  156. package/release/0.1.0/README.md +46 -0
  157. package/release/0.1.0/reproducibility.json +61 -0
  158. package/release/0.2.0/KNOWN_LIMITATIONS.md +40 -0
  159. package/release/0.2.0/README.md +42 -0
  160. package/release/0.2.0/reproducibility.json +73 -0
  161. package/release/0.2.1/KNOWN_LIMITATIONS.md +18 -0
  162. package/release/0.2.1/README.md +63 -0
  163. package/release/0.2.1/reproducibility.json +73 -0
  164. package/release/README.md +13 -0
  165. package/schemas/aggregation.v1.json +293 -0
  166. package/schemas/behavior-assertions.v1.json +220 -0
  167. package/schemas/deepseek-runtime-composition.v1.schema.json +122 -0
  168. package/schemas/experiment.v1.schema.json +188 -0
  169. package/schemas/human-calibration.v1.json +336 -0
  170. package/schemas/normalization-integrity.v1.json +302 -0
  171. package/schemas/run-bundles/v1.json +1040 -0
  172. package/schemas/run-queue.v1.schema.json +206 -0
  173. package/schemas/semantic-judge.v1.json +380 -0
  174. package/schemas/structural-observations.v1.json +131 -0
  175. package/schemas/task-packet-freeze.v1.schema.json +106 -0
  176. package/schemas/task-packet.v1.schema.json +234 -0
  177. package/schemas/uniform-events/v1.json +289 -0
  178. package/scripts/atlas-grafana.sh +18 -0
@@ -0,0 +1,12 @@
1
+ import { type AgentSdkNativeRecord } from "./agent-sdk-normalizer.js";
2
+ import { type AdapterCoverageReport, type NormalizedDataset } from "./normalization-integrity.js";
3
+ import type { NormalizationInput, NativeEvidenceResolver } from "./uniform-events.js";
4
+ export type RetainedBehaviorEvidence = {
5
+ capture: NormalizationInput<unknown>;
6
+ /** Verified bundle metadata for outcome import; never replaces native session records. */
7
+ outcomeCapture: NormalizationInput<AgentSdkNativeRecord>;
8
+ dataset: NormalizedDataset;
9
+ resolver: NativeEvidenceResolver;
10
+ coverage: AdapterCoverageReport;
11
+ };
12
+ export declare function createRetainedBehaviorEvidence(bundleRoot: string): Promise<RetainedBehaviorEvidence>;
@@ -0,0 +1,201 @@
1
+ import { join } from "node:path";
2
+ import { CLAUDE_AGENT_SDK_HARNESS, readQualifiedRunCapture, createAgentSdkNativeEvidenceResolver } from "./agent-sdk-normalizer.js";
3
+ import { createAgentSdkBehaviorEvidence } from "./behavior-assertions.js";
4
+ import { describeAndValidateCodexDataset, CODEX_HARNESS } from "./codex.js";
5
+ import { normalizeOpenHandsCapture, openHandsCapabilityProfile } from "./openhands.js";
6
+ import { createDeepSeekHarnessAdapter, DEEPSEEK_HARNESS_ID, DEEPSEEK_SDK_VERSION, normalizeDeepSeekCapture, qualifyRetainedDeepSeekCapture } from "./deepseek-adapter.js";
7
+ import { createCursorSdkBehaviorEvidence, CURSOR_SDK_HARNESS } from "./cursor-sdk.js";
8
+ import { createCapturedNativeEvidenceResolver, describeNormalizedDataset, validateNormalizedDataset } from "./normalization-integrity.js";
9
+ import { readBoundedFile } from "./scheduler.js";
10
+ import { assertProtocolObservation } from "./process-protocol.js";
11
+ import { assertPiNativeRecord, normalizePiCapture, piCapabilityProfile, piNativeType, qualifyRetainedPiCapture, PI_ADAPTER_VERSION, PI_HARNESS, PINNED_PI_SDK_VERSION, } from "./pi.js";
12
+ export async function createRetainedBehaviorEvidence(bundleRoot) {
13
+ const manifest = JSON.parse(readBoundedFile(join(bundleRoot, "manifest.json"), "Run manifest").toString("utf8"));
14
+ const harness = manifest.run.harness.id;
15
+ if (harness === CURSOR_SDK_HARNESS)
16
+ return createCursorSdkBehaviorEvidence(bundleRoot);
17
+ const isAgentSdk = [CLAUDE_AGENT_SDK_HARNESS, "agent-sdk"].includes(harness)
18
+ || manifest.run.runtime.some(({ source, name }) => source === "anthropic" && [CLAUDE_AGENT_SDK_HARNESS, "agent-sdk"].includes(name));
19
+ if (isAgentSdk) {
20
+ const evidence = await createAgentSdkBehaviorEvidence(bundleRoot);
21
+ return { ...evidence, outcomeCapture: evidence.capture };
22
+ }
23
+ if (![CODEX_HARNESS, "openhands-agent-server", DEEPSEEK_HARNESS_ID, PI_HARNESS].includes(harness)) {
24
+ throw new Error(`Unsupported retained harness ${harness}; refusing Agent SDK fallback normalization.`);
25
+ }
26
+ if (harness === "openhands-agent-server")
27
+ openHandsCapabilityProfile(manifest.run.harness.version);
28
+ if (harness === DEEPSEEK_HARNESS_ID && manifest.run.harness.version !== DEEPSEEK_SDK_VERSION) {
29
+ throw new Error(`Unsupported retained DeepSeek runtime ${manifest.run.harness.version}.`);
30
+ }
31
+ if (harness === PI_HARNESS && manifest.run.harness.version !== PINNED_PI_SDK_VERSION) {
32
+ throw new Error(`Unsupported retained Pi runtime ${manifest.run.harness.version}.`);
33
+ }
34
+ if (harness === PI_HARNESS) {
35
+ const expected = new Map([
36
+ ["pi-coding-agent", { source: "earendil-works", version: PINNED_PI_SDK_VERSION }],
37
+ [PI_HARNESS, { source: "EBO", version: PINNED_PI_SDK_VERSION }],
38
+ ["pi-sdk-adapter", { source: "EBO", version: PI_ADAPTER_VERSION }],
39
+ ]);
40
+ for (const [name, identity] of expected) {
41
+ const matches = manifest.run.runtime.filter((runtime) => runtime.name === name);
42
+ if (matches.length !== 1 || matches[0].source !== identity.source || matches[0].version !== identity.version) {
43
+ throw new Error(`Retained Pi runtime identity ${name} differs from the pinned adapter manifest.`);
44
+ }
45
+ }
46
+ }
47
+ const outcomeCapture = await readQualifiedRunCapture(bundleRoot);
48
+ // A verifier task failure also presupposes a normally completed native run.
49
+ const expectsCompletion = manifest.terminal.state === "completed" || manifest.terminal.failureClass === "task";
50
+ const capture = {
51
+ ...outcomeCapture,
52
+ records: outcomeCapture.records.filter(({ record }) => record.kind === "session")
53
+ .map(({ reference, record }) => {
54
+ const line = Number(reference.recordLocator.match(/^line:(\d+)$/u)?.[1]);
55
+ if (harness === PI_HARNESS)
56
+ assertPiNativeRecord(record.document, line);
57
+ else
58
+ assertNativeEnvelope(harness, record.document, line);
59
+ return { reference, record: record.document };
60
+ }),
61
+ };
62
+ const resolver = createCapturedNativeEvidenceResolver(capture, createAgentSdkNativeEvidenceResolver({ ...outcomeCapture,
63
+ records: outcomeCapture.records.filter(({ record }) => record.kind !== "session" && record.kind !== "hook"),
64
+ }));
65
+ let dataset;
66
+ if (harness === PI_HARNESS) {
67
+ const native = qualifyRetainedPiCapture(capture, manifest.run.native?.sessionId, expectsCompletion);
68
+ capture.qualification = native.qualification;
69
+ outcomeCapture.qualification = native.qualification;
70
+ dataset = describeNormalizedDataset({
71
+ capture: native,
72
+ normalization: await normalizePiCapture(native),
73
+ capabilityProfile: piCapabilityProfile,
74
+ adapterVersion: PI_ADAPTER_VERSION,
75
+ nativeType: piNativeType,
76
+ });
77
+ }
78
+ else if (harness === CODEX_HARNESS) {
79
+ const native = capture;
80
+ const handshakeVersions = native.records.filter(({ record }) => record.kind === "response" && record.source === CODEX_HARNESS && record.method === "initialize")
81
+ .map(({ record }) => String(record.payload?.userAgent ?? "").match(/^[^\s/]+\/([^\s]+)/u)?.[1]);
82
+ const telemetryVersions = outcomeCapture.records.flatMap(({ record }) => {
83
+ const document = record.document;
84
+ return document?.schemaVersion === "ebo.codex-telemetry/v1" ? [document.runtime?.version] : [];
85
+ });
86
+ if (handshakeVersions.length === 0 || [...handshakeVersions, ...telemetryVersions,
87
+ ...manifest.run.runtime.filter(({ name }) => name === CODEX_HARNESS).map(({ version }) => version),
88
+ ].some((version) => version !== manifest.run.harness.version)) {
89
+ throw new Error("Retained Codex native runtime version differs from the run manifest.");
90
+ }
91
+ let acceptedStartSequence = 0;
92
+ const identities = (method, key) => {
93
+ const accepted = native.records.filter(({ record }) => {
94
+ const payload = record.payload;
95
+ return record.kind === "response" && record.source === CODEX_HARNESS && record.method === method
96
+ && typeof payload?.[key]?.id === "string" && payload[key].id.trim() !== "";
97
+ });
98
+ const optionalPartialTurn = key === "turn" && !expectsCompletion;
99
+ if (accepted.length === 0 && optionalPartialTurn)
100
+ return undefined;
101
+ if (accepted.length !== 1)
102
+ throw new Error(`Retained Codex ${method} requires one owned identity.`);
103
+ const response = accepted[0].record;
104
+ const requests = native.records.filter(({ record }) => record.kind === "request" && record.source === "ebo-codex-client" && record.id === response.id);
105
+ const responses = native.records.filter(({ record }) => record.kind === "response" && record.source === CODEX_HARNESS && record.id === response.id);
106
+ const request = requests[0]?.record;
107
+ const payload = response.payload;
108
+ if (response.id === undefined || response.id === null || requests.length !== 1 || responses.length !== 1
109
+ || request?.method !== method || request.sequence <= acceptedStartSequence || request.sequence >= response.sequence
110
+ || key === "turn" && (request.payload?.threadId !== native.threadId
111
+ || payload.turn.threadId !== undefined && payload.turn.threadId !== native.threadId)) {
112
+ throw new Error(`Retained Codex ${method} requires a unique ordered owned request/response pair.`);
113
+ }
114
+ acceptedStartSequence = response.sequence;
115
+ return payload[key].id;
116
+ };
117
+ native.threadId = identities("thread/start", "thread");
118
+ native.turnId = identities("turn/start", "turn");
119
+ if (native.threadId !== manifest.run.native?.sessionId)
120
+ throw new Error("Retained Codex thread identity differs from the run manifest.");
121
+ const terminals = native.records.filter(({ record }) => {
122
+ const payload = record.payload;
123
+ return record.kind === "notification" && record.source === CODEX_HARNESS && record.method === "turn/completed"
124
+ && payload?.threadId === native.threadId && payload?.turn?.id === native.turnId;
125
+ });
126
+ if (terminals.length > 1 || terminals.some(({ record }) => record.sequence <= acceptedStartSequence)
127
+ || expectsCompletion && terminals[0]?.record.payload?.turn?.status !== "completed") {
128
+ throw new Error("Retained Codex capture requires unambiguous matching owned terminal evidence.");
129
+ }
130
+ dataset = (await describeAndValidateCodexDataset(native, manifest.run.harness.version)).dataset;
131
+ }
132
+ else if (harness === "openhands-agent-server") {
133
+ const native = capture;
134
+ const sessionId = manifest.run.native?.sessionId;
135
+ const serverInfo = native.records.filter(({ record }) => record.channel === "server-info");
136
+ if (serverInfo.length !== 1)
137
+ throw new Error("Retained OpenHands capture requires exactly one native server-info record.");
138
+ for (const { record } of native.records) {
139
+ if (record.channel === "server-info" && record.payload.version !== manifest.run.harness.version) {
140
+ throw new Error("Retained OpenHands native server version differs from the run manifest.");
141
+ }
142
+ if (record.session_id !== undefined && record.session_id !== sessionId
143
+ || ["conversation-created", "websocket-status", "websocket-event", "rest-event", "conversation-final"].includes(record.channel)
144
+ && (sessionId === undefined || record.session_id !== sessionId)
145
+ || ["conversation-created", "conversation-final"].includes(record.channel) && record.payload.id !== sessionId) {
146
+ throw new Error("Retained OpenHands conversation identity differs from the run manifest.");
147
+ }
148
+ }
149
+ const finals = native.records.filter(({ record }) => record.channel === "conversation-final");
150
+ if (expectsCompletion && (finals.length !== 1 || finals[0].record.payload.execution_status !== "finished")) {
151
+ throw new Error("Completed retained OpenHands capture lacks owned finished conversation evidence.");
152
+ }
153
+ dataset = describeNormalizedDataset({ capture: native, normalization: await normalizeOpenHandsCapture(native),
154
+ capabilityProfile: openHandsCapabilityProfile(manifest.run.harness.version), adapterVersion: manifest.run.harness.version,
155
+ nativeType: (record) => typeof record.payload.kind === "string" ? record.payload.kind : record.channel });
156
+ }
157
+ else {
158
+ const native = qualifyRetainedDeepSeekCapture(capture, manifest.run.native?.sessionId, expectsCompletion);
159
+ capture.qualification = native.qualification;
160
+ outcomeCapture.qualification = native.qualification;
161
+ dataset = describeNormalizedDataset({ capture: native, normalization: normalizeDeepSeekCapture(native),
162
+ capabilityProfile: createDeepSeekHarnessAdapter().normalization.capabilityProfile, adapterVersion: DEEPSEEK_SDK_VERSION,
163
+ nativeType: (record) => record.method ?? record.kind });
164
+ }
165
+ const coverage = await validateNormalizedDataset(dataset, resolver);
166
+ return { capture, outcomeCapture, dataset, resolver, coverage };
167
+ }
168
+ function assertNativeEnvelope(harness, value, line) {
169
+ const fail = () => { throw new Error(`Invalid retained ${harness} native envelope at line ${line}.`); };
170
+ if (value === null || typeof value !== "object" || Array.isArray(value))
171
+ fail();
172
+ const record = value;
173
+ if (!Number.isSafeInteger(line) || line < 1 || record.sequence !== line)
174
+ fail();
175
+ if (harness === CODEX_HARNESS) {
176
+ assertProtocolObservation(value, line);
177
+ if (value.source !== CODEX_HARNESS && value.source !== "ebo-codex-client")
178
+ fail();
179
+ if (value.source === "ebo-codex-client" && (!["request", "response", "notification"].includes(value.kind)
180
+ || value.kind === "notification" && value.method !== "initialized"))
181
+ fail();
182
+ return;
183
+ }
184
+ const optionalText = (fields) => fields.every((field) => record[field] === undefined
185
+ || typeof record[field] === "string" && record[field].trim() !== "");
186
+ if (harness === "openhands-agent-server") {
187
+ if (record.schemaVersion !== "ebo.openhands-native-record/v1"
188
+ || !["server-info", "conversation-create-response", "conversation-created", "websocket-status", "websocket-event", "conversation-final", "rest-event", "capture-error", "cleanup"].includes(String(record.channel))
189
+ || record.payload === null || typeof record.payload !== "object" || Array.isArray(record.payload)
190
+ || !optionalText(["session_id"]) || record.channelSequence !== undefined
191
+ && (typeof record.channelSequence !== "number" || !Number.isSafeInteger(record.channelSequence) || record.channelSequence < 0))
192
+ fail();
193
+ return;
194
+ }
195
+ if (record.schemaVersion !== "ebo.deepseek-native-observation/v1"
196
+ || !["composition", "capability", "request", "response", "notification", "diagnostic", "error"].includes(String(record.kind))
197
+ || typeof record.observedAt !== "string" || record.observedAt.trim() === ""
198
+ || !optionalText(["method", "sessionId", "sourceIdentity"]) || record.stream !== undefined && record.stream !== "stderr"
199
+ || ["request", "response", "notification"].includes(String(record.kind)) && typeof record.method !== "string")
200
+ fail();
201
+ }
@@ -0,0 +1,193 @@
1
+ import { type AssessmentMode } from "./contracts.js";
2
+ import type { ClaudeAgentSdkAttemptEvidence, ClaudeAgentSdkCapabilities } from "./agent-sdk.js";
3
+ import type { AttemptIdentity, TerminalRecord } from "./lifecycle.js";
4
+ type DigestString = `sha256:${string}`;
5
+ type SharingClass = "unknown" | "restricted" | "internal" | "partner" | "public";
6
+ type EvidenceKind = "session" | "hook" | "telemetry" | "workspace" | "verifier";
7
+ type EvidenceAuthority = "semantic" | "timing-resource" | "outcome";
8
+ export type RunBundleRuntimeComponent = {
9
+ source: string;
10
+ name: string;
11
+ version: string;
12
+ };
13
+ export type RunBundleRun = {
14
+ id: string;
15
+ trial?: {
16
+ index: number;
17
+ };
18
+ assessmentMode: AssessmentMode;
19
+ task: {
20
+ id: string;
21
+ digest?: DigestString;
22
+ };
23
+ fixture: {
24
+ id: string;
25
+ digest: DigestString;
26
+ };
27
+ model: {
28
+ provider: string;
29
+ id: string;
30
+ configurationDigest?: DigestString;
31
+ };
32
+ harness: {
33
+ id: string;
34
+ version: string;
35
+ configurationDigest?: DigestString;
36
+ };
37
+ runtime: RunBundleRuntimeComponent[];
38
+ verifier?: {
39
+ locator: string;
40
+ digest: DigestString;
41
+ format?: "commonjs" | "module";
42
+ };
43
+ native?: {
44
+ sessionId?: string;
45
+ traceId?: string;
46
+ };
47
+ };
48
+ export type RunBundleConfiguration = {
49
+ digest: DigestString;
50
+ captureProfileDigest?: DigestString;
51
+ budgetDigest: DigestString;
52
+ toolPolicyDigest: DigestString;
53
+ };
54
+ export type RunBundleEvidenceDescriptor = {
55
+ id: string;
56
+ source: string;
57
+ kind: EvidenceKind | "diagnostic" | "capture-report" | "export-manifest";
58
+ authority: EvidenceAuthority | "capture" | "export";
59
+ mediaType: string;
60
+ digest: DigestString;
61
+ sizeBytes: number;
62
+ sharingClass: SharingClass;
63
+ relativePath: string;
64
+ fingerprint?: DigestString;
65
+ nativeReference?: {
66
+ type: string;
67
+ id: string;
68
+ };
69
+ sanitizedFrom?: {
70
+ artifactId: string;
71
+ digest: DigestString;
72
+ };
73
+ };
74
+ export type RunManifest = {
75
+ schemaVersion: "run-manifest/v1";
76
+ bundleId: string;
77
+ run: RunBundleRun;
78
+ attempt: AttemptIdentity;
79
+ configuration: RunBundleConfiguration;
80
+ terminal: TerminalRecord;
81
+ evidence: RunBundleEvidenceDescriptor[];
82
+ };
83
+ export type CaptureMissingEvidence = {
84
+ kind: string;
85
+ reason: "not-emitted" | "not-collected" | "optional-beta-unavailable" | "process-interrupted" | "policy-restricted" | "unsupported" | "not-checked";
86
+ affects: Array<"semantic" | "timing-resource" | "outcome">;
87
+ detail?: string;
88
+ };
89
+ export type RunBundleDefinition = {
90
+ bundleRoot: string;
91
+ bundleId: string;
92
+ run: RunBundleRun;
93
+ attempt: AttemptIdentity;
94
+ configuration: RunBundleConfiguration;
95
+ };
96
+ export type RegisterRunBundleArtifact = {
97
+ id: string;
98
+ source: string;
99
+ kind: EvidenceKind;
100
+ mediaType: string;
101
+ sharingClass: Exclude<SharingClass, "partner" | "public">;
102
+ relativePath: string;
103
+ fingerprint?: DigestString;
104
+ nativeReference?: {
105
+ type: string;
106
+ id: string;
107
+ };
108
+ };
109
+ export type CaptureWorkspaceOutcomeOptions = {
110
+ startPath: string;
111
+ finalPath: string;
112
+ excludeDirectoryNames?: readonly string[];
113
+ respectGitignore?: boolean;
114
+ omitEmptyDirectories?: boolean;
115
+ id?: string;
116
+ source?: string;
117
+ relativePath?: string;
118
+ snapshotRelativePath?: string;
119
+ };
120
+ export type CapturedWorkspaceOutcome = {
121
+ descriptor: RunBundleEvidenceDescriptor;
122
+ fingerprint: DigestString;
123
+ treeDigest: DigestString;
124
+ format: "patch" | "snapshot";
125
+ };
126
+ export type CaptureQualificationStatus = "qualified" | "qualified-with-gaps" | "unqualified";
127
+ export type CaptureQualificationDimension = "attemptIdentity" | "semanticEvidence" | "hooks" | "telemetry" | "workspace" | "verifier" | "terminal" | "sharing";
128
+ export type CaptureQualificationReasonCode = "MANIFEST_INVALID" | "ATTEMPT_IDENTITY_INVALID" | "ARTIFACT_INTEGRITY_INVALID" | "ARTIFACT_TOO_LARGE" | "NATIVE_JSON_EMPTY" | "NATIVE_JSON_MALFORMED" | "NATIVE_JSONL_EMPTY" | "NATIVE_JSONL_MALFORMED" | "SESSION_EVIDENCE_MISSING" | "SESSION_IDENTITY_MISSING" | "SESSION_RECORD_IDENTITY_MISMATCH" | "HOOK_EVIDENCE_MISSING" | "HOOK_RECORDS_MISSING" | "HOOK_CAPABILITY_NOT_CHECKED" | "HOOK_CAPABILITY_VERSION_MISMATCH" | "HOOK_SUPPORTED_BUT_MISSING" | "HOOK_UNSUPPORTED_BY_PINNED_SDK" | "HOOK_CAPABILITY_CONTRADICTION" | "HOOK_CAPTURE_WARNING" | "TELEMETRY_EVIDENCE_MISSING" | "TELEMETRY_RECEIPT_MISSING" | "TELEMETRY_UNSUPPORTED_BY_PINNED_RUNTIME" | "OPTIONAL_BETA_TIMING_UNAVAILABLE" | "WORKSPACE_EVIDENCE_MISSING" | "WORKSPACE_PATCH_NOT_CHECKED" | "WORKSPACE_PATCH_UNUSABLE" | "VERIFIER_EVIDENCE_MISSING" | "VERIFIER_RESULT_ERROR" | "VERIFIER_RESULT_NOT_RUN" | "TERMINAL_CLASSIFICATION_INVALID" | "INFRASTRUCTURE_FAILURE_MISCLASSIFIED_AS_TASK" | "SHARING_CLASSIFICATION_UNKNOWN" | "CAPTURE_REPORT_MISSING" | "CAPTURE_REPORT_INVALID" | "CAPTURE_REPORT_CONTRADICTS_SOURCE" | "EVENT_LOG_COMPLETENESS_UNPROVEN" | "EXPORT_MANIFEST_INVALID";
129
+ export type CaptureQualificationReason = {
130
+ code: CaptureQualificationReasonCode;
131
+ dimension: CaptureQualificationDimension;
132
+ evidenceId?: string;
133
+ detail: string;
134
+ };
135
+ export type CaptureQualificationReport = {
136
+ status: CaptureQualificationStatus;
137
+ semanticAnalysisUsable: boolean;
138
+ assessmentMode?: AssessmentMode;
139
+ attempt?: AttemptIdentity;
140
+ terminal?: TerminalRecord;
141
+ dimensions: Record<CaptureQualificationDimension, {
142
+ status: "qualified" | "unsupported" | "gap" | "unqualified";
143
+ reasonCodes: CaptureQualificationReasonCode[];
144
+ }>;
145
+ reasons: CaptureQualificationReason[];
146
+ };
147
+ export type AgentSdkQualificationEvidence = Pick<ClaudeAgentSdkAttemptEvidence, "capabilities" | "effectiveConfiguration" | "captureWarnings">;
148
+ export type CaptureQualificationOptions = {
149
+ startingWorkspacePath?: string;
150
+ workspaceOutcomeExcludedDirectoryNames?: readonly string[];
151
+ workspaceOutcomeRespectsGitignore?: boolean;
152
+ workspaceOutcomeOmitsEmptyDirectories?: boolean;
153
+ hookCapabilities?: Pick<ClaudeAgentSdkCapabilities, "sdkVersion" | "hooks" | "unsupportedHooks">;
154
+ agentSdkEvidence?: AgentSdkQualificationEvidence;
155
+ expectedHooks?: readonly string[];
156
+ semanticEvidenceKinds?: readonly ("session" | "hook")[];
157
+ relatedSessionIds?: readonly string[];
158
+ };
159
+ export declare function createRunBundleAssembler(definition: RunBundleDefinition): Promise<RunBundleAssembler>;
160
+ export declare class RunBundleAssembler {
161
+ readonly bundleRoot: string;
162
+ readonly bundleId: string;
163
+ readonly attempt: AttemptIdentity;
164
+ private run;
165
+ private readonly configuration;
166
+ private evidence;
167
+ private manifest?;
168
+ private revision;
169
+ private finalized;
170
+ private captureMissing;
171
+ constructor(definition: RunBundleDefinition);
172
+ initialize(): Promise<void>;
173
+ currentManifest(): RunManifest;
174
+ registerArtifact(input: RegisterRunBundleArtifact): Promise<RunBundleEvidenceDescriptor>;
175
+ writeJsonArtifact(input: RegisterRunBundleArtifact, document: unknown): Promise<RunBundleEvidenceDescriptor>;
176
+ writeAgentSdkTelemetry(input: {
177
+ evidence: Pick<ClaudeAgentSdkAttemptEvidence, "telemetry" | "usage">;
178
+ traceId?: string;
179
+ id?: string;
180
+ relativePath?: string;
181
+ }): Promise<RunBundleEvidenceDescriptor>;
182
+ captureWorkspaceOutcome(options: CaptureWorkspaceOutcomeOptions, whileProjected?: (projectedPath: string, outcome: CapturedWorkspaceOutcome) => Promise<void>): Promise<CapturedWorkspaceOutcome>;
183
+ finalize(input: {
184
+ terminal: TerminalRecord;
185
+ missingEvidence?: CaptureMissingEvidence[];
186
+ qualification?: CaptureQualificationOptions;
187
+ }): Promise<RunManifest>;
188
+ private assertOpen;
189
+ private checkpoint;
190
+ }
191
+ /** Structurally qualify one retained run bundle without normalizing native evidence. */
192
+ export declare function qualifyRunBundle(bundleRoot: string, options?: CaptureQualificationOptions): Promise<CaptureQualificationReport>;
193
+ export {};