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,377 @@
1
+ import { type AtlasView } from "./atlas.js";
2
+ /** Native Grafana panels backed by the maintained Infinity JSON data source. */
3
+ export declare function atlasDashboards(view: AtlasView, atlasUrl?: string): {
4
+ uid: string;
5
+ title: string;
6
+ schemaVersion: number;
7
+ version: number;
8
+ editable: boolean;
9
+ tags: string[];
10
+ timezone: string;
11
+ refresh: string;
12
+ time: {
13
+ from: string;
14
+ to: string;
15
+ };
16
+ description: string;
17
+ templating: {
18
+ list: ({
19
+ name: "q";
20
+ label: string;
21
+ type: string;
22
+ query: string;
23
+ current: {
24
+ text: string;
25
+ value: string;
26
+ };
27
+ multi?: undefined;
28
+ includeAll?: undefined;
29
+ allValue?: undefined;
30
+ options?: undefined;
31
+ } | {
32
+ name: "task" | "model" | "harness" | "outcome" | "capture" | "trial" | "review" | "category" | "assessment";
33
+ label: "task" | "model" | "harness" | "outcome" | "capture" | "trial" | "review" | "category" | "assessment";
34
+ type: string;
35
+ query: string;
36
+ multi: boolean;
37
+ includeAll: boolean;
38
+ allValue: string;
39
+ current: {
40
+ text: string;
41
+ value: string;
42
+ };
43
+ options: {
44
+ text: string;
45
+ value: string;
46
+ selected: boolean;
47
+ }[];
48
+ })[];
49
+ };
50
+ links: ({
51
+ type: string;
52
+ title: string;
53
+ url: string;
54
+ targetBlank: boolean;
55
+ includeVars?: undefined;
56
+ } | {
57
+ type: string;
58
+ title: string;
59
+ url: string;
60
+ includeVars: boolean;
61
+ targetBlank?: undefined;
62
+ })[];
63
+ panels: ({
64
+ id: number;
65
+ type: string;
66
+ title: string;
67
+ gridPos: {
68
+ x: number;
69
+ y: number;
70
+ w: number;
71
+ h: number;
72
+ };
73
+ options: {
74
+ mode: string;
75
+ content: string;
76
+ showHeader?: undefined;
77
+ cellHeight?: undefined;
78
+ orientation?: undefined;
79
+ showValue?: undefined;
80
+ stacking?: undefined;
81
+ legend?: undefined;
82
+ };
83
+ datasource?: undefined;
84
+ transformations?: undefined;
85
+ targets?: undefined;
86
+ fieldConfig?: undefined;
87
+ description?: undefined;
88
+ } | {
89
+ id: number;
90
+ type: string;
91
+ title: string;
92
+ gridPos: {
93
+ x: number;
94
+ y: number;
95
+ w: number;
96
+ h: number;
97
+ };
98
+ datasource: {
99
+ type: string;
100
+ uid: string;
101
+ };
102
+ transformations: {
103
+ id: string;
104
+ options: {
105
+ indexByName: {
106
+ [k: string]: number;
107
+ };
108
+ };
109
+ }[];
110
+ targets: {
111
+ refId: string;
112
+ datasource: {
113
+ type: string;
114
+ uid: string;
115
+ };
116
+ type: string;
117
+ source: string;
118
+ url: string;
119
+ url_options: {
120
+ method: string;
121
+ data: string;
122
+ headers: never[];
123
+ params: never[];
124
+ };
125
+ parser: string;
126
+ format: string;
127
+ root_selector: string;
128
+ columns: {
129
+ selector: string;
130
+ text: string;
131
+ type: string;
132
+ }[];
133
+ }[];
134
+ fieldConfig: {
135
+ defaults: {
136
+ custom: {
137
+ inspect: boolean;
138
+ filterable: boolean;
139
+ width: number;
140
+ axisWidth?: undefined;
141
+ };
142
+ links: {
143
+ title: string;
144
+ url: string;
145
+ targetBlank: boolean;
146
+ }[];
147
+ unit?: undefined;
148
+ min?: undefined;
149
+ };
150
+ overrides: never[];
151
+ };
152
+ options: {
153
+ showHeader: boolean;
154
+ cellHeight: string;
155
+ mode?: undefined;
156
+ content?: undefined;
157
+ orientation?: undefined;
158
+ showValue?: undefined;
159
+ stacking?: undefined;
160
+ legend?: undefined;
161
+ };
162
+ description?: undefined;
163
+ } | {
164
+ id: number;
165
+ type: string;
166
+ title: string;
167
+ description: string;
168
+ gridPos: {
169
+ x: number;
170
+ y: number;
171
+ w: number;
172
+ h: number;
173
+ };
174
+ datasource: {
175
+ type: string;
176
+ uid: string;
177
+ };
178
+ targets: {
179
+ refId: string;
180
+ datasource: {
181
+ type: string;
182
+ uid: string;
183
+ };
184
+ type: string;
185
+ source: string;
186
+ url: string;
187
+ url_options: {
188
+ method: string;
189
+ data: string;
190
+ headers: never[];
191
+ params: never[];
192
+ };
193
+ parser: string;
194
+ format: string;
195
+ root_selector: string;
196
+ columns: {
197
+ selector: string;
198
+ text: string;
199
+ type: string;
200
+ }[];
201
+ }[];
202
+ options: {
203
+ orientation: string;
204
+ showValue: string;
205
+ stacking: string;
206
+ legend: {
207
+ showLegend: boolean;
208
+ };
209
+ mode?: undefined;
210
+ content?: undefined;
211
+ showHeader?: undefined;
212
+ cellHeight?: undefined;
213
+ };
214
+ fieldConfig: {
215
+ defaults: {
216
+ unit: string;
217
+ min: number;
218
+ custom: {
219
+ axisWidth: number;
220
+ inspect?: undefined;
221
+ filterable?: undefined;
222
+ width?: undefined;
223
+ };
224
+ links?: undefined;
225
+ };
226
+ overrides: never[];
227
+ };
228
+ transformations?: undefined;
229
+ } | {
230
+ id: number;
231
+ type: string;
232
+ title: string;
233
+ gridPos: {
234
+ x: number;
235
+ y: number;
236
+ w: number;
237
+ h: number;
238
+ };
239
+ datasource: {
240
+ type: string;
241
+ uid: string;
242
+ };
243
+ targets: {
244
+ refId: string;
245
+ datasource: {
246
+ type: string;
247
+ uid: string;
248
+ };
249
+ type: string;
250
+ source: string;
251
+ url: string;
252
+ url_options: {
253
+ method: string;
254
+ data: string;
255
+ headers: never[];
256
+ params: never[];
257
+ };
258
+ parser: string;
259
+ format: string;
260
+ root_selector: string;
261
+ columns: {
262
+ selector: string;
263
+ text: string;
264
+ type: string;
265
+ }[];
266
+ }[];
267
+ transformations: {
268
+ id: string;
269
+ options: {
270
+ indexByName: {
271
+ [k: string]: number;
272
+ };
273
+ };
274
+ }[];
275
+ fieldConfig: {
276
+ defaults: {
277
+ custom: {
278
+ filterable: boolean;
279
+ width: number;
280
+ inspect?: undefined;
281
+ axisWidth?: undefined;
282
+ };
283
+ links?: undefined;
284
+ unit?: undefined;
285
+ min?: undefined;
286
+ };
287
+ overrides: never[];
288
+ };
289
+ options: {
290
+ showHeader: boolean;
291
+ cellHeight: string;
292
+ mode?: undefined;
293
+ content?: undefined;
294
+ orientation?: undefined;
295
+ showValue?: undefined;
296
+ stacking?: undefined;
297
+ legend?: undefined;
298
+ };
299
+ description?: undefined;
300
+ } | {
301
+ id: number;
302
+ type: string;
303
+ title: string;
304
+ gridPos: {
305
+ x: number;
306
+ y: number;
307
+ w: number;
308
+ h: number;
309
+ };
310
+ datasource: {
311
+ type: string;
312
+ uid: string;
313
+ };
314
+ transformations: {
315
+ id: string;
316
+ options: {
317
+ indexByName: {
318
+ [k: string]: number;
319
+ };
320
+ };
321
+ }[];
322
+ targets: {
323
+ refId: string;
324
+ datasource: {
325
+ type: string;
326
+ uid: string;
327
+ };
328
+ type: string;
329
+ source: string;
330
+ url: string;
331
+ url_options: {
332
+ method: string;
333
+ data: string;
334
+ headers: never[];
335
+ params: never[];
336
+ };
337
+ parser: string;
338
+ format: string;
339
+ root_selector: string;
340
+ columns: {
341
+ selector: string;
342
+ text: string;
343
+ type: string;
344
+ }[];
345
+ }[];
346
+ fieldConfig: {
347
+ defaults: {
348
+ custom: {
349
+ filterable: boolean;
350
+ width: number;
351
+ inspect?: undefined;
352
+ axisWidth?: undefined;
353
+ };
354
+ links: {
355
+ title: string;
356
+ url: string;
357
+ targetBlank: boolean;
358
+ }[];
359
+ unit?: undefined;
360
+ min?: undefined;
361
+ };
362
+ overrides: never[];
363
+ };
364
+ options: {
365
+ showHeader: boolean;
366
+ cellHeight: string;
367
+ mode?: undefined;
368
+ content?: undefined;
369
+ orientation?: undefined;
370
+ showValue?: undefined;
371
+ stacking?: undefined;
372
+ legend?: undefined;
373
+ };
374
+ description?: undefined;
375
+ })[];
376
+ }[];
377
+ export declare function writeAtlasGrafana(outputRoot: string, view: AtlasView): Promise<void>;
@@ -0,0 +1,47 @@
1
+ import { mkdir, writeFile } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { ATLAS_FILTERS } from "./atlas.js";
4
+ /** Native Grafana panels backed by the maintained Infinity JSON data source. */
5
+ export function atlasDashboards(view, atlasUrl = view.atlasUrl ?? "http://127.0.0.1:13011") {
6
+ const query = ATLAS_FILTERS.map((key) => `${key}=\${${key}:percentencode}`).join("&");
7
+ const datasource = { type: "yesoreyeram-infinity-datasource", uid: "ebo-atlas-derived" };
8
+ const organize = (names) => [{ id: "organize", options: { indexByName: Object.fromEntries(names.map((name, index) => [name, index])) } }];
9
+ const variables = ATLAS_FILTERS.map((name) => name === "q" ? { name, label: "Search case evidence", type: "textbox", query: "", current: { text: "", value: "" } } : {
10
+ name, label: name, type: "custom", query: (view.filterOptions[name] ?? []).map((value) => value.replaceAll(",", "\\,")).join(","),
11
+ multi: false, includeAll: true, allValue: "$__all", current: { text: "All", value: "$__all" },
12
+ options: [{ text: "All", value: "$__all", selected: true }, ...(view.filterOptions[name] ?? []).map((value) => ({ text: value, value, selected: false }))],
13
+ });
14
+ const target = (path, columns) => ({ refId: "A", datasource, type: "json", source: "url", url: `${atlasUrl}${path}?${query}`, url_options: { method: "GET", data: "", headers: [], params: [] }, parser: "backend", format: "table", root_selector: "", columns: columns.map((selector) => ({ selector, text: selector, type: ["numerator", "denominator", "count"].includes(selector) ? "number" : "string" })) });
15
+ return ["overview", "behavior"].map((kind) => ({
16
+ uid: `ebo-atlas-${kind}`, title: `EBO | ${kind === "overview" ? "Cohort overview" : "Behavior Atlas"}`, schemaVersion: 39, version: 1, editable: false,
17
+ tags: ["ebo", "derived", "restricted-local"], timezone: "utc", refresh: "", time: { from: "now-1h", to: "now" },
18
+ description: "Rebuildable EBO-derived cohort queries. Not a live capture monitor. No composite score or causal inference.",
19
+ templating: { list: variables },
20
+ links: [{ type: "link", title: "Evidence workbench / export cohort report", url: `${atlasUrl}/?${query}`, targetBlank: true }, { type: "link", title: kind === "overview" ? "Behavior Atlas" : "Cohort overview", url: `/d/ebo-atlas-${kind === "overview" ? "behavior" : "overview"}`, includeVars: true }],
21
+ panels: [
22
+ { id: 1, type: "text", title: "Evidence and population boundaries", gridPos: { x: 0, y: 0, w: 24, h: 4 }, options: { mode: "markdown", content: "### EBO · Research workbench\nNative evidence remains authoritative. Filters select attempts through matching cases; all judgments on selected attempts remain in metrics. **Proposed is not human-confirmed.** Numerators, denominators and exclusions are shown together. The Grafana time picker affects Tempo only, not the frozen EBO cohort. Use the evidence workbench for review lineage, cited records and standalone report/PDF export." } },
23
+ { id: 2, type: "table", title: kind === "overview" ? "Selected cohort metrics · exact counts and exclusions" : "Confirmed behavior distributions · opposite assessments remain separate", gridPos: { x: 0, y: 4, w: 24, h: 13 }, datasource,
24
+ transformations: organize(kind === "overview" ? ["group", "metric", "status", "numerator", "denominator", "unit", "exclusions", "cohortDigest"] : ["group", "category", "assessment", "numerator", "denominator", "status", "exclusions", "dimension", "unit", "rubric", "evaluator", "vocabulary", "cohortDigest"]),
25
+ targets: [target(kind === "overview" ? "/api/metrics" : "/api/behaviors", kind === "overview" ? ["group", "metric", "status", "numerator", "denominator", "unit", "exclusions", "cohortDigest"] : ["group", "category", "dimension", "rubric", "evaluator", "assessment", "status", "numerator", "denominator", "unit", "exclusions", "cohortDigest"])],
26
+ fieldConfig: { defaults: { custom: { inspect: true, filterable: true, width: 150 }, links: [{ title: "Inspect selected cohort evidence", url: `${atlasUrl}/?${query}`, targetBlank: true }] }, overrides: [] }, options: { showHeader: true, cellHeight: "sm" } },
27
+ ...(kind === "behavior" ? [{ id: 4, type: "barchart", title: "Confirmed assessment counts · denominators and exclusions in table above", description: "Counts, not model quality scores. Unavailable values remain null. Exact populations and exclusions are in the behavior table.", gridPos: { x: 0, y: 17, w: 24, h: 10 }, datasource, targets: [target("/api/behavior-chart", ["label", "count"])], options: { orientation: "horizontal", showValue: "always", stacking: "none", legend: { showLegend: false } }, fieldConfig: { defaults: { unit: "short", min: 0, custom: { axisWidth: 180 } }, overrides: [] } }] : []),
28
+ { id: 5, type: "table", title: "Comparison eligibility · unsupported pairs are unavailable", gridPos: { x: 0, y: kind === "behavior" ? 27 : 17, w: 24, h: 8 }, datasource,
29
+ targets: [target("/api/comparisons", ["comparison", "measure", "status", "numerator", "denominator", "unit", "exclusions", "limitations"])], transformations: organize(["comparison", "measure", "status", "numerator", "denominator", "unit", "exclusions", "limitations"]),
30
+ fieldConfig: { defaults: { custom: { filterable: true, width: 150 } }, overrides: [] }, options: { showHeader: true, cellHeight: "sm" } },
31
+ { id: 3, type: "table", title: "Searchable cases · inspect in Atlas", gridPos: { x: 0, y: kind === "behavior" ? 35 : 25, w: 24, h: 10 }, datasource,
32
+ transformations: organize(["runId", "attemptId", "model", "harness", "assessment", "review", "task", "trial", "category", "href"]),
33
+ targets: [target("/api/cases", ["runId", "attemptId", "model", "harness", "task", "trial", "category", "assessment", "review", "href"])],
34
+ fieldConfig: { defaults: { custom: { filterable: true, width: 150 }, links: [{ title: "Open case and cited evidence", url: "${__data.fields.href}", targetBlank: true }] }, overrides: [] }, options: { showHeader: true, cellHeight: "sm" } },
35
+ ],
36
+ }));
37
+ }
38
+ export async function writeAtlasGrafana(outputRoot, view) {
39
+ const root = join(outputRoot, "grafana");
40
+ for (const directory of ["dashboards", "provisioning/dashboards", "provisioning/datasources"])
41
+ await mkdir(join(root, directory), { recursive: true, mode: 0o700 });
42
+ for (const dashboard of atlasDashboards(view))
43
+ await writeFile(join(root, "dashboards", `${dashboard.uid}.json`), JSON.stringify(dashboard, null, 2), { mode: 0o600 });
44
+ await writeFile(join(root, "provisioning/dashboards/atlas.yaml"), "apiVersion: 1\nproviders:\n - name: ebo-atlas\n folder: EBO Atlas\n type: file\n disableDeletion: true\n options:\n path: ${EBO_ATLAS_DASHBOARDS}\n", { mode: 0o600 });
45
+ await writeFile(join(root, "provisioning/datasources/atlas.yaml"), `apiVersion: 1\ndatasources:\n - name: EBO Atlas derived data\n uid: ebo-atlas-derived\n type: yesoreyeram-infinity-datasource\n access: proxy\n editable: false\n jsonData:\n allowedHosts:\n - ${view.atlasUrl ?? "http://127.0.0.1:13011"}\n`, { mode: 0o600 });
46
+ await writeFile(join(root, "grafana.ini"), `[server]\nhttp_addr = 127.0.0.1\nhttp_port = ${new URL(view.grafanaUrl ?? "http://127.0.0.1:13010").port || "80"}\n[auth.anonymous]\nenabled = true\norg_role = Viewer\n[auth]\ndisable_login_form = true\n[analytics]\nreporting_enabled = false\ncheck_for_updates = false\ncheck_for_plugin_updates = false\n[plugins]\npreinstall_disabled = true\npreinstall_auto_update = false\n`, { mode: 0o600 });
47
+ }
@@ -0,0 +1,2 @@
1
+ import { type AtlasView } from "./atlas.js";
2
+ export declare function renderAtlas(view: AtlasView, interactive: boolean): string;
@@ -0,0 +1,34 @@
1
+ import { ATLAS_FILTERS, atlasBehaviorPartitions } from "./atlas.js";
2
+ import { escapeHtml } from "./human-calibration.js";
3
+ const h = (value) => escapeHtml(value ?? "");
4
+ const title = (value) => value.replaceAll("-", " ");
5
+ const pretty = (value) => h(JSON.stringify(value, null, 2));
6
+ const badge = (value) => `<span class="badge ${["constructive", "adverse", "mixed", "context-dependent", "confirmed", "disputed", "rejected", "abstained", "proposed", "unavailable", "insufficient-evidence"].includes(value) ? value : ""}">${h(title(value))}</span>`;
7
+ export function renderAtlas(view, interactive) {
8
+ const query = new URLSearchParams(view.filters).toString();
9
+ const control = interactive ? `<form action="/" method="get" aria-label="Select cohort"><div class="filters">${ATLAS_FILTERS.filter((key) => key !== "q").map((key) => `<label>${h(title(key))}<select name="${key}"><option value="">All ${h(key)}</option>${(view.filterOptions[key] ?? []).map((value) => `<option value="${h(value)}"${view.filters[key] === value ? " selected" : ""}>${h(value)}</option>`).join("")}</select></label>`).join("")}<label class="search">Search case evidence<input name="q" type="search" value="${h(view.filters.q ?? "")}" placeholder="Run, task, category or rationale"></label></div><div class="actions"><button type="submit">Apply cohort</button><a href="/">Clear filters</a><span>Filters select attempts through matching cases. Metrics retain every judgment on selected attempts.</span></div></form>` : `<p class="frozen">Frozen cohort · ${Object.entries(view.filters).map(([key, value]) => `${h(key)}: ${h(value)}`).join(" · ") || "All source attempts"}. Rebuild or use the local workbench to change populations.</p>`;
10
+ const metricRows = view.report.groups.flatMap((group) => group.metrics.filter(({ id }) => !id.startsWith("structural:")).map((metric) => `<tr><th scope="row">${h(title(metric.id))}<small>${h(metric.population)} population · ${h(Object.values(group.dimensions).join(" / ") || "Selected cohort")}</small></th>${measurement(metric.measurement, metric.id.endsWith("-rate"))}</tr>`)).join("");
11
+ const structuralRows = view.report.groups.flatMap((group) => group.metrics.filter(({ id }) => id.startsWith("structural:")).map((metric) => `<tr><th scope="row">${h(title(metric.id))}<small>${h(Object.values(group.dimensions).join(" / "))}</small></th>${measurement(metric.measurement)}</tr>`)).join("");
12
+ const comparisons = view.report.comparisons.map((comparison) => `<tr><th scope="row">${h(comparison.id)}<small>${h(comparison.measure)}</small></th>${measurement(comparison.matchedDifference)}<td>${badge(comparison.claimStatus)}<small>${h(comparison.limitations.join(" "))}</small></td></tr>`).join("");
13
+ const behaviorGroups = atlasBehaviorPartitions(view).map(({ group, partition }) => `<figure><figcaption><strong>${h(group)} · ${h(partition.behavior.categoryId)}</strong><small>${h(partition.behavior.dimensionId)} · vocabulary ${h(partition.behavior.vocabularyVersion)} · rubric ${h(partition.rubric.id)} ${h(partition.rubric.version)} · evaluator ${h(partition.evaluator.id)} ${h(partition.evaluator.version)}</small></figcaption>${partition.assessments.map(({ assessment, measurement: measure }) => `<div class="distribution">${badge(assessment)} ${measure.status === "available" ? `<meter min="0" max="${measure.denominator.value}" value="${measure.numerator.value}" aria-label="${h(assessment)}: ${measure.numerator.value} of ${measure.denominator.value} ${h(measure.denominator.unit)}"></meter><span>${measure.numerator.value} / ${measure.denominator.value}</span>` : badge("unavailable")}</div>`).join("")}<div class="tablewrap"><table><caption>${h(partition.population)} population · exact counts and exclusions</caption><thead><tr><th>Assessment</th><th>Numerator</th><th>Denominator</th><th>Rate / status</th><th>Exclusions</th></tr></thead><tbody>${partition.assessments.map(({ assessment, measurement: measure }) => `<tr><th>${h(assessment)}</th>${measurement(measure, true)}</tr>`).join("")}</tbody></table></div><details><summary>Source assertions and evaluator bindings</summary><pre>${pretty({ evaluator: partition.evaluator, rubric: partition.rubric, assertions: partition.assertions })}</pre></details></figure>`).join("");
14
+ const exports = interactive ? `<a class="button secondary" href="/report.html?${h(query)}" target="_blank" rel="noopener">Open cohort report</a><a href="/report.json?${h(query)}" download="atlas-report.json">JSON</a><a href="/report.html?${h(query)}&amp;share=true" target="_blank" rel="noopener">Approved shareable report</a>` : `<button type="button" id="print">Print / save PDF</button>`;
15
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="referrer" content="no-referrer"><title>${h(view.title)} · Behavior Atlas</title><style>${CSS}</style></head><body>
16
+ <a class="skip" href="#main">Skip to research results</a><header><a class="brand" href="#main">EBO <span>Engineering Behavior Observatory</span></a><div>${badge(view.mode)}<span class="edition">ATLAS / 01</span></div></header>
17
+ <main id="main"><section class="intro"><div><p class="eyebrow">Evidence before interpretation</p><h1>${h(view.title)}</h1><p class="dek">A research workbench for outcomes, behavioral judgments, and the evidence that supports them.</p></div><nav class="exports" aria-label="Report exports">${exports}${view.grafanaUrl ? `<a href="${h(view.grafanaUrl)}/d/ebo-atlas-overview">Grafana overview ↗</a>` : ""}</nav></section>
18
+ <p class="boundary">${view.mode === "restricted-local-only" ? "Restricted local inspection. Semantic judgments are proposals until an explicit human decision confirms them. This report is not approved for sharing." : "Sanitized approved summary. Semantic findings, human prose, native records, operator narrative and local links are excluded."}</p>
19
+ ${control}<section class="population" aria-label="Selected population"><div><strong>${view.report.sourcePopulation.uniqueRuns}</strong><span>distinct runs</span></div><div><strong>${view.report.sourcePopulation.selectedAttempts}<em> / ${view.report.sourcePopulation.uniqueAttempts}</em></strong><span>selected / cohort attempts</span></div><div><strong>${view.matchingCases ?? "Unavailable"}</strong><span>matching evidence cases</span></div><div><strong>${view.filteredOutAttempts}<em> / ${view.sourceAttempts}</em></strong><span>attempts excluded by filters / source</span></div></section><p class="empty">Attempt policy excludes ${view.policyExcludedAttempts} / ${view.sourceAttempts} source attempts before case filters. No earlier attempt substitutes for a filtered-out latest retry.</p>
20
+ <section><div class="sectionhead"><h2>01 <span>Observed outcomes</span></h2><p>Counts, units, and eligible populations stay visible.</p></div><div class="tablewrap"><table><caption>Selected cohort metrics from EBO aggregation</caption><thead><tr><th scope="col">Measure / group</th><th scope="col">Numerator</th><th scope="col">Denominator</th><th scope="col">Rate or status</th><th scope="col">Exclusions</th></tr></thead><tbody>${metricRows || '<tr><td colspan="5">No attempts match this cohort. Metrics are unavailable; an empty denominator is not zero performance.</td></tr>'}</tbody></table></div></section>
21
+ ${structuralRows ? `<details><summary>Inspect structural measurements and missing capabilities</summary><div class="tablewrap"><table><caption>Structural counts and per-attempt means; ratios with different units are not percentages</caption><thead><tr><th>Measure / group</th><th>Numerator</th><th>Denominator</th><th>Mean or status</th><th>Exclusions</th></tr></thead><tbody>${structuralRows}</tbody></table></div></details>` : ""}
22
+ <section><div class="sectionhead"><h2>02 <span>Behavior &amp; human review</span></h2><p>Opposite assessments remain separate; confidence is evaluator reported.</p></div><div class="legend">${["constructive", "adverse", "mixed", "context-dependent", "proposed", "confirmed", "disputed", "rejected", "abstained", "unavailable"].map(badge).join(" ")}</div>${behaviorGroups || '<p class="empty">Confirmed behavior distributions are unavailable for this cohort or input version.</p>'}<p>Case filters select attempts, not a favorable subset of judgments. Proposed, rejected, disputed and abstained cases are inspectable; they do not become confirmed findings.</p><div class="tablewrap"><table><caption>Matching cases · expand a row for evidence and review lineage</caption><thead><tr><th scope="col">Attempt / condition</th><th scope="col">Assessment</th><th scope="col">Review</th><th scope="col">Evidence</th></tr></thead><tbody>${view.cases.map((item) => caseRow(item, !interactive)).join("") || '<tr><td colspan="4">No matching cases. Native evidence may be absent, or excluded from this sharing mode.</td></tr>'}</tbody></table></div></section>
23
+ <section><div class="sectionhead"><h2>03 <span>Comparison boundaries</span></h2><p>Eligibility gates govern every matched difference.</p></div><div class="tablewrap"><table><caption>Matched comparisons; no causal or significance claims</caption><thead><tr><th>Comparison</th><th>Numerator</th><th>Denominator</th><th>Rate or status</th><th>Exclusions</th><th>Claim / limits</th></tr></thead><tbody>${comparisons || '<tr><td colspan="6">Comparison unavailable: no matched, measure-bound comparison request is configured.</td></tr>'}</tbody></table></div></section>
24
+ ${view.operatorNarrative ? `<section class="narrative"><p class="eyebrow">Operator-authored narrative · not inferred by EBO</p><h2>Research notes</h2><p>${h(view.operatorNarrative).replaceAll("\n", "<br>")}</p></section>` : ""}
25
+ <section class="method"><div><h2>Method &amp; limitations</h2><ul>${view.report.limitations.map((item) => `<li>${h(item)}</li>`).join("")}<li>Attempt policy: ${h(view.report.policy.selectedAttemptPolicy)}. Recurrence threshold: ${view.report.policy.recurrence.minimumOccurrences}. Duplicate inputs ignored: ${view.report.sourcePopulation.duplicateInputsIgnored}.</li><li>Displayed cited records are sanitized for secrets and hidden fields. Native evidence remains authoritative.</li><li>Trace views use a separate Tempo backend. Original and replay timestamps are identified per linked case; absence of a link means trace viewing is unavailable.</li></ul>${view.reviewPackets.length ? `<h3>Existing human review packets</h3><p>These local-file links open from the standalone report; browsers may block them from HTTP.</p><ul>${view.reviewPackets.map((href, index) => `<li><a href="${h(href)}">Open configured review packet ${index + 1}</a></li>`).join("")}</ul>` : '<p>No human review packet links configured.</p>'}</div><div><h2>Reproducibility record</h2><dl><dt>Generated</dt><dd>${h(view.generatedAt)}</dd><dt>Read model / aggregate version</dt><dd>${h(view.schemaVersion)}<br>${h(view.report.schemaVersion)}</dd><dt>Source digest</dt><dd><code>${h(view.sourceDigest)}</code></dd><dt>Selected cohort digest</dt><dd><code>${h(view.cohortDigest)}</code></dd></dl><details><summary>Exact source digests and version bindings</summary><pre>${pretty(view.report.sourceLineage)}</pre></details></div></section>
26
+ </main><footer>EBO · Native evidence remains authoritative <span>Descriptive research / no composite ranking</span></footer><script>document.getElementById('print')?.addEventListener('click',()=>window.print());</script></body></html>`;
27
+ }
28
+ function measurement(value, percent = false) {
29
+ return `<td class="number">${value.numerator.value}<small>${h(value.numerator.unit)}</small></td><td class="number">${value.denominator.value}<small>${h(value.denominator.unit)}</small></td><td>${value.status === "unavailable" ? badge("unavailable") : value.rate === undefined ? "Count" : percent ? `${(value.rate * 100).toFixed(1)}%` : `${Number(value.rate.toPrecision(5))}<small>${h(value.numerator.unit)} / ${h(value.denominator.unit)}</small>`}<small>${h(value.reason ?? "")}</small></td><td>${value.exclusions.map(({ reason, count, unit }) => `${count} ${h(unit)}: ${h(reason)}`).join("<br>") || "None"}</td>`;
30
+ }
31
+ function caseRow(item, expanded) {
32
+ return `<tr id="case-${h(item.key)}"><th scope="row">${h(item.runId)}<small>${h(item.attemptId)}${item.retryOf ? ` · retry of ${h(item.retryOf)}` : ""}<br>${h(item.model)} · ${h(item.harness)} ${h(item.harnessVersion ?? "version unavailable")}<br>${h(item.task)} · trial ${h(item.trial)}<br>${h(item.capture)} · ${h(item.outcome)}</small></th><td>${badge(item.assessment)}<small>${h(item.category)}<br>${h(item.assertion?.behavior.dimensionId)}</small></td><td>${badge(item.review)}</td><td><details${expanded ? " open" : ""}><summary>Inspect ${item.citations.length} citation${item.citations.length === 1 ? "" : "s"}</summary>${item.assertion ? `<h3>Judgment rationale</h3><p>${h(item.assertion.judgment.rationale)}</p><h3>Alternative explanation</h3><p>${h(item.assertion.judgment.alternativeExplanation)}</p><p>${item.assertion.judgment.disposition === "assessed" ? `Evaluator-reported confidence: ${item.assertion.judgment.confidence.value} / 1 (not calibrated probability)` : `Abstention reason: ${h(item.assertion.judgment.reason)}`}</p><p>Vocabulary ${h(item.assertion.behavior.vocabularyVersion)} · rubric ${h(item.assertion.rubric.id)} ${h(item.assertion.rubric.version)} · evaluator ${h(item.assertion.evaluator.id)} ${h(item.assertion.evaluator.version)}</p><code>${h(item.assertionDigest)}</code>` : "<p>Assertion unavailable: no semantic assessment source was supplied.</p>"}${item.citations.map((citation, index) => `<details id="evidence-${h(item.key)}-${index}"><summary>${h(citation.eventId)} · normalized → native</summary><h3>Native reference</h3><pre>${pretty(citation.nativeReference)}</pre><h3>Normalized event</h3><pre>${pretty(citation.normalizedEvent)}</pre><h3>Cited native record · sanitized display</h3><pre>${pretty(citation.nativeRecord)}</pre></details>`).join("")}<h3>Human decision lineage</h3>${item.decisions.length ? `<ul>${item.decisions.map((decision) => `<li>${h(decision.state)} · ${h(decision.reviewer.id)} · ${h(decision.decidedAt)}<br>${h(decision.rationale)}</li>`).join("")}</ul><details><summary>Exact decision lineage (${item.decisions.length} records)</summary><pre>${pretty(item.decisions)}</pre></details>` : "<p>No human decision supplied. This is not human confirmation.</p>"}${item.trace ? `<p><a href="${h(item.trace.href)}" target="_blank" rel="noopener">Open trace in Tempo ↗</a><br>Original: ${h(item.trace.originalStart)}<br>${item.trace.replayStart ? `Replay-shifted: ${h(item.trace.replayStart)}` : "No replay shift declared"}</p>` : '<p>Trace backend/link unavailable.</p>'}</details></td></tr>`;
33
+ }
34
+ const CSS = `:root{color-scheme:light;--paper:#f7f5ef;--ink:#202b2c;--muted:#526568;--line:#d3d8d0;--accent:#116a68}*{box-sizing:border-box}body{margin:0;background:var(--paper);color:var(--ink);font:15px/1.55 'Avenir Next',Avenir,'Segoe UI',sans-serif}a{color:#095e63;text-underline-offset:3px}button,.button{font:inherit;cursor:pointer;background:var(--accent);color:white;border:1px solid var(--accent);border-radius:3px;padding:9px 14px;text-decoration:none}button:hover,.button:hover{background:#084c4b}a:focus-visible,button:focus-visible,input:focus-visible,select:focus-visible,summary:focus-visible{outline:3px solid #b44b13;outline-offset:3px}header,footer{padding:20px 4vw;display:flex;justify-content:space-between;border-bottom:1px solid var(--line);gap:20px}.brand{font-weight:800;letter-spacing:.13em;text-decoration:none;color:var(--ink)}.brand span{font-size:12px;letter-spacing:.02em;font-weight:400;margin-left:15px}.edition{font:11px monospace;margin-left:18px}main{max-width:1500px;margin:auto;padding:24px 4vw 60px}.intro{display:flex;align-items:center;justify-content:space-between;gap:45px;margin:22px 0}.eyebrow{text-transform:uppercase;letter-spacing:.14em;font-size:11px;color:var(--accent);font-weight:700}h1{font:400 clamp(36px,4vw,60px)/1.08 Georgia,'Times New Roman',serif;max-width:850px;letter-spacing:-.035em;margin:14px 0 20px}.dek{max-width:680px;color:var(--muted);font-size:17px}.exports{display:flex;align-items:center;gap:13px;flex-wrap:wrap;max-width:260px;font-size:13px}.boundary{border-left:3px solid #9a6c27;background:#efeadd;padding:12px 16px;font-size:13px}.filters{display:grid;grid-template-columns:repeat(5,minmax(120px,1fr));gap:12px;margin-top:25px}label{display:grid;gap:5px;font-size:12px;text-transform:capitalize;color:var(--muted)}input,select{font:14px inherit;width:100%;min-height:40px;background:#fffef9;color:var(--ink);border:1px solid #9caeaa;border-radius:3px;padding:8px}.search{grid-column:span 2}.actions{display:flex;align-items:center;gap:18px;margin:16px 0;font-size:13px}.actions span{max-width:650px;color:var(--muted)}.population{display:grid;grid-template-columns:repeat(4,1fr);border-top:2px solid var(--ink);border-bottom:1px solid var(--line);margin:28px 0 38px;padding:20px 0}.population>div{padding:0 20px;border-right:1px solid var(--line)}.population>div:first-child{padding-left:0}.population>div:last-child{border:0}.population strong{display:block;font:38px Georgia,serif;font-variant-numeric:tabular-nums}.population em{font:20px Georgia,serif;color:var(--muted)}.population span{font-size:12px;color:var(--muted)}section{margin-bottom:30px}.sectionhead{display:flex;justify-content:space-between;align-items:baseline;gap:20px}.sectionhead h2{font:13px monospace;color:var(--accent);white-space:nowrap}.sectionhead h2 span{font:26px Georgia,serif;color:var(--ink);margin-left:15px}.sectionhead p{font-size:12px;color:var(--muted)}.tablewrap{overflow-x:auto;border-top:1px solid var(--ink)}table{width:100%;border-collapse:collapse;text-align:left;font-size:13px}caption{text-align:left;padding:12px 0;color:var(--muted);font-size:12px}th,td{vertical-align:top;padding:13px 12px;border-bottom:1px solid var(--line);overflow-wrap:anywhere}thead th{font-size:10px;letter-spacing:.08em;text-transform:uppercase;color:var(--muted);background:#eeeFE8}tbody th{font-weight:500;min-width:175px}small{display:block;font-size:11px;line-height:1.55;color:var(--muted);font-weight:400;margin-top:4px}.number{font-variant-numeric:tabular-nums;font-size:17px;min-width:110px}td:last-child{min-width:170px}details{margin:5px 0;max-width:720px}summary{cursor:pointer;color:var(--accent);font-size:13px;padding:5px 0}details p{max-width:620px}h3{font-size:13px;margin-bottom:4px}pre{white-space:pre-wrap;overflow-wrap:anywhere;max-height:420px;overflow:auto;background:#eceee8;padding:12px;font:11px/1.6 'SFMono-Regular',Consolas,monospace}code{font:11px/1.5 monospace;overflow-wrap:anywhere}.badge{display:inline-block;white-space:nowrap;background:#e5e9e6;color:#344b4c;border:1px solid #bbc8c2;font-size:10px;line-height:1.5;padding:3px 6px;border-radius:3px;text-transform:uppercase;letter-spacing:.025em}.constructive,.confirmed{color:#195b37;background:#e4f0e3;border-color:#8eb796}.adverse,.rejected{color:#8d261f;background:#fae8df;border-color:#d99d88}.mixed,.disputed{color:#764607;background:#f8efcc;border-color:#c8aa62}.context-dependent,.proposed{color:#245b85;background:#e4edf5;border-color:#91adc4}.abstained,.insufficient-evidence{color:#634579;background:#eee6f0;border-color:#bba3c4}.unavailable{color:#5a5d5b;background:#e8e7e3;border-style:dashed}.distribution{display:grid;grid-template-columns:160px 1fr 70px;gap:12px;align-items:center;max-width:720px;margin:10px 0;font-size:12px}meter::-webkit-meter-optimum-value{background:#42676a}meter{width:100%;height:18px;accent-color:var(--accent)}figure{margin:24px 0;padding:20px;border:1px solid var(--line);background:#fffef9}.legend{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:16px}.empty,.frozen{color:var(--muted);font-size:13px}.narrative{max-width:850px;border-left:3px solid var(--accent);padding:15px 25px}.narrative h2,.method h2{font:26px Georgia,serif}.method{display:grid;grid-template-columns:1.2fr 1fr;gap:60px;margin-top:40px;padding-top:20px;border-top:2px solid var(--ink)}.method li,.method p,dl{font-size:12px;color:var(--muted)}dt{font-weight:700;margin-top:12px}dd{margin:4px 0}.skip{position:absolute;left:-999px}.skip:focus{left:15px;top:15px;background:white;padding:12px}footer{font-size:11px;color:var(--muted);border-top:1px solid var(--line);border-bottom:0}@media screen and (max-width:800px){.intro,.sectionhead{display:block}.exports{max-width:none}.filters{grid-template-columns:repeat(2,minmax(100px,1fr))}.population{grid-template-columns:repeat(2,1fr);gap:20px}.population>div:nth-child(3){padding-left:0}.population>div:nth-child(2){border:0}.method{grid-template-columns:1fr;gap:20px}.brand span,.edition{display:none}.actions{flex-wrap:wrap}.sectionhead p{margin-top:0}header,footer{padding:15px 4vw}.tablewrap table{min-width:650px}}@media print{.narrative{break-inside:avoid}th:nth-child(5),td:nth-child(5){min-width:80pt}h2,h3,caption{break-after:avoid}section{margin-bottom:14px}figure{padding:10px;margin:12px 0;break-inside:avoid}.number{font-size:10pt}small{font-size:7pt}td p,td li{font-size:8pt;line-height:1.3;margin:5px 0}.dek{font-size:11pt}.population strong{font-size:20pt}h3{font-size:8pt;margin:6px 0}body{background:white;font-size:10pt}header{padding:0 0 12px}main{padding:12px 0}form,.exports,.skip{display:none}.intro{margin:10px 0}h1{font-size:32pt}.population{margin:12px 0;padding:12px 0}.tablewrap{overflow:visible}table{font-size:8pt}th,td{padding:7px}thead{display:table-header-group}tr,.population{break-inside:avoid}details{break-inside:auto}.method{gap:20px}.sectionhead h2 span{font-size:20pt}pre{max-height:none;overflow:visible}footer{padding:12px 0}@page{size:A4 landscape;margin:14mm}}`;
@@ -0,0 +1,130 @@
1
+ import { type Server } from "node:http";
2
+ import { type BehaviorAggregate, type AggregationInput, type AggregationReport, type AggregationRequest } from "./aggregation.js";
3
+ import type { BehaviorAssertion } from "./behavior-assertions.js";
4
+ import { type PortableExportPolicy } from "./exports.js";
5
+ import { type ReviewDecision } from "./human-calibration.js";
6
+ type Digest = `sha256:${string}`;
7
+ export declare const ATLAS_FILTERS: readonly ["model", "harness", "task", "trial", "capture", "outcome", "review", "category", "assessment", "q"];
8
+ export type AtlasFilters = Partial<Record<typeof ATLAS_FILTERS[number], string>>;
9
+ export type AtlasRequest = {
10
+ schemaVersion: "ebo.atlas-request/v1";
11
+ aggregationRequest: string;
12
+ title: string;
13
+ operatorNarrative?: string;
14
+ reviewPackets?: readonly string[];
15
+ traces?: ReadonlyArray<{
16
+ runId: string;
17
+ attemptId: string;
18
+ traceId: string;
19
+ originalStart: string;
20
+ replayStart?: string;
21
+ }>;
22
+ grafanaUrl?: string;
23
+ atlasUrl?: string;
24
+ tempoDatasourceUid?: string;
25
+ sharing?: {
26
+ policy: PortableExportPolicy;
27
+ approvedExports: readonly string[];
28
+ fields: readonly string[];
29
+ };
30
+ };
31
+ export type AtlasCase = {
32
+ key: string;
33
+ runId: string;
34
+ attemptId: string;
35
+ model: string;
36
+ harness: string;
37
+ task: string;
38
+ trial: string;
39
+ capture: string;
40
+ outcome: string;
41
+ review: string;
42
+ category: string;
43
+ assessment: string;
44
+ harnessVersion?: string;
45
+ assertion?: BehaviorAssertion;
46
+ assertionDigest?: Digest;
47
+ decisions: readonly ReviewDecision[];
48
+ citations: ReadonlyArray<{
49
+ eventId: string;
50
+ nativeReference: unknown;
51
+ normalizedEvent: unknown;
52
+ nativeRecord: unknown;
53
+ }>;
54
+ trace?: {
55
+ href: string;
56
+ originalStart: string;
57
+ replayStart?: string;
58
+ };
59
+ retryOf?: string;
60
+ };
61
+ export type AtlasView = {
62
+ schemaVersion: "ebo.atlas-view/v1";
63
+ title: string;
64
+ mode: "restricted-local-only" | "partner" | "public";
65
+ generatedAt: string;
66
+ sourceDigest: Digest;
67
+ cohortDigest: Digest;
68
+ filters: AtlasFilters;
69
+ filterOptions: Record<string, string[]>;
70
+ report: AggregationReport;
71
+ cases: readonly AtlasCase[];
72
+ sourceAttempts: number;
73
+ policyExcludedAttempts: number;
74
+ filteredOutAttempts: number;
75
+ matchingCases: number | null;
76
+ operatorNarrative?: string;
77
+ reviewPackets: readonly string[];
78
+ grafanaUrl?: string;
79
+ atlasUrl?: string;
80
+ };
81
+ export type AtlasSource = {
82
+ request: AtlasRequest;
83
+ aggregation: AggregationRequest;
84
+ input: AggregationInput;
85
+ corpusRoot: string;
86
+ requestPath: string;
87
+ cases: AtlasCase[];
88
+ sourceDigest: Digest;
89
+ };
90
+ export declare function atlasBehaviorPartitions(view: AtlasView): Array<{
91
+ group: string;
92
+ partition: BehaviorAggregate;
93
+ }>;
94
+ export declare function atlasBehaviorRows(view: AtlasView): {
95
+ group: string;
96
+ category: string;
97
+ dimension: string;
98
+ vocabulary: string;
99
+ rubric: string;
100
+ evaluator: string;
101
+ assessment: "constructive" | "adverse" | "mixed" | "context-dependent";
102
+ label: string;
103
+ status: "available" | "unavailable";
104
+ numerator: number | null;
105
+ denominator: number;
106
+ unit: string;
107
+ exclusions: string;
108
+ cohortDigest: `sha256:${string}`;
109
+ }[] | {
110
+ group: string;
111
+ category: string;
112
+ dimension: string;
113
+ vocabulary: string;
114
+ rubric: string;
115
+ evaluator: string;
116
+ assessment: string;
117
+ label: string;
118
+ status: string;
119
+ numerator: null;
120
+ denominator: number;
121
+ unit: string;
122
+ exclusions: string;
123
+ cohortDigest: `sha256:${string}`;
124
+ }[];
125
+ export declare function loadAtlas(requestPath: string): Promise<AtlasSource>;
126
+ export declare function queryAtlas(source: AtlasSource, filters?: AtlasFilters): Promise<AtlasView>;
127
+ export declare function shareAtlas(source: AtlasSource, view: AtlasView): Promise<AtlasView>;
128
+ export declare function writeAtlas(requestPath: string, outputRoot: string, filters?: AtlasFilters, share?: boolean): Promise<AtlasView>;
129
+ export declare function serveAtlas(requestPath: string, port?: number): Promise<Server>;
130
+ export {};