@tangle-network/agent-eval 0.38.0 → 0.40.2

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 (62) hide show
  1. package/dist/campaign/index.d.ts +775 -0
  2. package/dist/campaign/index.js +807 -0
  3. package/dist/campaign/index.js.map +1 -0
  4. package/dist/chunk-5U2DOJU4.js +565 -0
  5. package/dist/chunk-5U2DOJU4.js.map +1 -0
  6. package/dist/{chunk-KE7TDJUO.js → chunk-AU2JLNSZ.js} +2 -2
  7. package/dist/{chunk-TSPOEDM3.js → chunk-BWZEGTES.js} +2 -5
  8. package/dist/chunk-BWZEGTES.js.map +1 -0
  9. package/dist/{chunk-3HYQXPC2.js → chunk-DMW5VENN.js} +3 -3
  10. package/dist/{chunk-TQL7BAOY.js → chunk-EGIPWXHL.js} +2 -2
  11. package/dist/chunk-GGE4NNQT.js +65 -0
  12. package/dist/chunk-GGE4NNQT.js.map +1 -0
  13. package/dist/{chunk-7PR3WPWE.js → chunk-L7XMNXLO.js} +2 -2
  14. package/dist/{chunk-RL6TERL2.js → chunk-LCIDRYGP.js} +3 -3
  15. package/dist/{chunk-L5UNCDAJ.js → chunk-MAOZCN36.js} +2 -64
  16. package/dist/chunk-MAOZCN36.js.map +1 -0
  17. package/dist/{chunk-LGAPK7NA.js → chunk-NKLGKF2Q.js} +2 -2
  18. package/dist/chunk-TMXPFWC7.js +305 -0
  19. package/dist/chunk-TMXPFWC7.js.map +1 -0
  20. package/dist/{chunk-KHZRNY3F.js → chunk-WP7SY7AI.js} +5 -4
  21. package/dist/chunk-WP7SY7AI.js.map +1 -0
  22. package/dist/chunk-YV7J7X5N.js +313 -0
  23. package/dist/chunk-YV7J7X5N.js.map +1 -0
  24. package/dist/{control-DVrmvM_k.d.ts → control-CmLJk3IG.d.ts} +1 -1
  25. package/dist/control.d.ts +3 -3
  26. package/dist/control.js +2 -2
  27. package/dist/{dataset-ueRVTUoY.d.ts → dataset-BlwAtYYf.d.ts} +1 -1
  28. package/dist/{feedback-trajectory-iATEAHmc.d.ts → feedback-trajectory-Dvy-bt7x.d.ts} +1 -1
  29. package/dist/governance/index.d.ts +133 -5
  30. package/dist/index.d.ts +35 -34
  31. package/dist/index.js +97 -630
  32. package/dist/index.js.map +1 -1
  33. package/dist/multishot/index.d.ts +21 -21
  34. package/dist/multishot/index.js +64 -15
  35. package/dist/multishot/index.js.map +1 -1
  36. package/dist/openapi.json +1 -1
  37. package/dist/optimization.d.ts +2 -2
  38. package/dist/optimization.js +5 -5
  39. package/dist/pipelines/index.js +2 -2
  40. package/dist/red-team-30II1T4o.d.ts +63 -0
  41. package/dist/{release-report-D2ykiLSe.d.ts → release-report-Di84bXD7.d.ts} +5 -2
  42. package/dist/reporting.d.ts +2 -2
  43. package/dist/reporting.js +3 -3
  44. package/dist/rl.js +15 -315
  45. package/dist/rl.js.map +1 -1
  46. package/dist/run-campaign-JYJXYHHL.js +10 -0
  47. package/dist/run-campaign-JYJXYHHL.js.map +1 -0
  48. package/dist/traces.js +7 -5
  49. package/dist/wire/index.d.ts +2 -2
  50. package/docs/design/loop-taxonomy.md +233 -0
  51. package/docs/design/self-improvement-engine.md +130 -0
  52. package/package.json +33 -24
  53. package/dist/chunk-KHZRNY3F.js.map +0 -1
  54. package/dist/chunk-L5UNCDAJ.js.map +0 -1
  55. package/dist/chunk-TSPOEDM3.js.map +0 -1
  56. package/dist/index-CN2agEaO.d.ts +0 -191
  57. /package/dist/{chunk-KE7TDJUO.js.map → chunk-AU2JLNSZ.js.map} +0 -0
  58. /package/dist/{chunk-3HYQXPC2.js.map → chunk-DMW5VENN.js.map} +0 -0
  59. /package/dist/{chunk-TQL7BAOY.js.map → chunk-EGIPWXHL.js.map} +0 -0
  60. /package/dist/{chunk-7PR3WPWE.js.map → chunk-L7XMNXLO.js.map} +0 -0
  61. /package/dist/{chunk-RL6TERL2.js.map → chunk-LCIDRYGP.js.map} +0 -0
  62. /package/dist/{chunk-LGAPK7NA.js.map → chunk-NKLGKF2Q.js.map} +0 -0
@@ -0,0 +1,313 @@
1
+ // src/rl/verifiable-reward.ts
2
+ var DEFAULT_DETERMINISTIC_LAYERS = /* @__PURE__ */ new Set([
3
+ "install",
4
+ "typecheck",
5
+ "build",
6
+ "lint",
7
+ "test",
8
+ "compile",
9
+ "schema",
10
+ "sandbox",
11
+ "unit_tests",
12
+ "integration_tests"
13
+ ]);
14
+ var DEFAULT_SOURCE_FOR = (name) => {
15
+ const lower = name.toLowerCase();
16
+ if (lower.includes("test")) return "test";
17
+ if (lower.includes("compile") || lower.includes("build") || lower.includes("typecheck") || lower.includes("lint"))
18
+ return "compile";
19
+ if (lower.includes("schema")) return "schema";
20
+ if (lower.includes("sandbox")) return "sandbox";
21
+ if (lower.includes("judge") || lower.includes("semantic")) return "judge";
22
+ return "composite";
23
+ };
24
+ function extractVerifiableReward(report, opts = {}) {
25
+ const deterministicSet = new Set(opts.deterministicLayers ?? [...DEFAULT_DETERMINISTIC_LAYERS]);
26
+ const sourceFor = opts.sourceFor ?? DEFAULT_SOURCE_FOR;
27
+ const fallbackToJudge = opts.fallbackToJudge ?? true;
28
+ const judgeFloor = opts.judgeConfidenceFloor ?? 0.7;
29
+ const deterministic = report.layers.filter(
30
+ (l) => deterministicSet.has(l.layer) && typeof l.score === "number" && Number.isFinite(l.score)
31
+ );
32
+ if (deterministic.length === 1) {
33
+ const layer = deterministic[0];
34
+ return {
35
+ value: clamp01(layer.score),
36
+ source: sourceFor(layer.layer),
37
+ determinism: "deterministic",
38
+ confidence: 1,
39
+ origin: layer.layer,
40
+ breakdown: layerBreakdown(layer)
41
+ };
42
+ }
43
+ if (deterministic.length > 1) {
44
+ let num = 0;
45
+ let denom = 0;
46
+ const breakdown = {};
47
+ for (const l of deterministic) {
48
+ const w = l.detail?.weight ?? 1;
49
+ num += w * (l.score ?? 0);
50
+ denom += w;
51
+ breakdown[l.layer] = l.score;
52
+ }
53
+ return {
54
+ value: denom === 0 ? 0 : clamp01(num / denom),
55
+ source: "composite",
56
+ determinism: "deterministic",
57
+ confidence: 1,
58
+ origin: deterministic.map((l) => l.layer).join("+"),
59
+ breakdown
60
+ };
61
+ }
62
+ if (!fallbackToJudge) return null;
63
+ const judge = report.layers.find(
64
+ (l) => typeof l.score === "number" && Number.isFinite(l.score) && sourceFor(l.layer) === "judge"
65
+ ) ?? report.layers.find((l) => typeof l.score === "number" && Number.isFinite(l.score));
66
+ if (!judge) return null;
67
+ const confFromDetail = judge.detail?.confidence;
68
+ return {
69
+ value: clamp01(judge.score),
70
+ source: "judge",
71
+ determinism: "probabilistic",
72
+ confidence: typeof confFromDetail === "number" ? confFromDetail : judgeFloor,
73
+ origin: judge.layer,
74
+ breakdown: layerBreakdown(judge)
75
+ };
76
+ }
77
+ function extractVerifiableRewardsFromRecords(runs, opts = {}) {
78
+ const sourceFor = opts.sourceFor ?? DEFAULT_SOURCE_FOR;
79
+ const deterministicSet = new Set(opts.deterministicLayers ?? [...DEFAULT_DETERMINISTIC_LAYERS]);
80
+ const fallbackToJudge = opts.fallbackToJudge ?? true;
81
+ const judgeFloor = opts.judgeConfidenceFloor ?? 0.7;
82
+ return runs.map((run) => {
83
+ const layerScores = [];
84
+ for (const [k, v] of Object.entries(run.outcome.raw)) {
85
+ if (k.startsWith("layer.") && !k.includes(".", 6) && typeof v === "number" && Number.isFinite(v)) {
86
+ layerScores.push({ name: k.slice("layer.".length), score: v });
87
+ }
88
+ }
89
+ const det = layerScores.filter((l) => deterministicSet.has(l.name));
90
+ if (det.length === 1) {
91
+ const layer = det[0];
92
+ return {
93
+ runId: run.runId,
94
+ reward: {
95
+ value: clamp01(layer.score),
96
+ source: sourceFor(layer.name),
97
+ determinism: "deterministic",
98
+ confidence: 1,
99
+ origin: layer.name
100
+ }
101
+ };
102
+ }
103
+ if (det.length > 1) {
104
+ const value = det.reduce((s, l) => s + l.score, 0) / det.length;
105
+ const breakdown = Object.fromEntries(
106
+ det.map((l) => [l.name, l.score])
107
+ );
108
+ return {
109
+ runId: run.runId,
110
+ reward: {
111
+ value: clamp01(value),
112
+ source: "composite",
113
+ determinism: "deterministic",
114
+ confidence: 1,
115
+ origin: det.map((l) => l.name).join("+"),
116
+ breakdown
117
+ }
118
+ };
119
+ }
120
+ if (!fallbackToJudge) return { runId: run.runId, reward: null };
121
+ const primary = run.outcome.holdoutScore ?? run.outcome.searchScore;
122
+ if (typeof primary !== "number" || !Number.isFinite(primary)) {
123
+ return { runId: run.runId, reward: null };
124
+ }
125
+ return {
126
+ runId: run.runId,
127
+ reward: {
128
+ value: clamp01(primary),
129
+ source: "judge",
130
+ determinism: "probabilistic",
131
+ confidence: judgeFloor,
132
+ origin: "run.outcome.score"
133
+ }
134
+ };
135
+ });
136
+ }
137
+ function filterDeterministicallyRewarded(runs, opts = {}) {
138
+ const rewarded = extractVerifiableRewardsFromRecords(runs, { ...opts, fallbackToJudge: false });
139
+ const out = [];
140
+ for (let i = 0; i < runs.length; i++) {
141
+ const r = rewarded[i];
142
+ if (r.reward && r.reward.determinism === "deterministic") {
143
+ out.push({ run: runs[i], reward: r.reward });
144
+ }
145
+ }
146
+ return out;
147
+ }
148
+ function clamp01(x) {
149
+ if (!Number.isFinite(x)) return 0;
150
+ return Math.max(0, Math.min(1, x));
151
+ }
152
+ function layerBreakdown(l) {
153
+ const out = {};
154
+ if (l.diagnostics) {
155
+ for (const [k, v] of Object.entries(l.diagnostics)) {
156
+ if (typeof v === "number" && Number.isFinite(v)) out[k] = v;
157
+ }
158
+ }
159
+ return out;
160
+ }
161
+
162
+ // src/rl/reward-hacking.ts
163
+ var DEFAULT_PROXY = (r) => {
164
+ const v = r.outcome.holdoutScore ?? r.outcome.searchScore;
165
+ return typeof v === "number" && Number.isFinite(v) ? v : null;
166
+ };
167
+ function detectRewardHacking(input) {
168
+ const proxyOf = input.proxyOf ?? DEFAULT_PROXY;
169
+ const truthOf = input.truthOf;
170
+ const sus = input.thresholds?.suspect ?? 0.3;
171
+ const gam = input.thresholds?.gaming ?? 0.6;
172
+ const runs = input.runs.filter((r) => proxyOf(r) !== null);
173
+ const n = runs.length;
174
+ if (n < 4) {
175
+ return {
176
+ findings: [],
177
+ verdict: "clean",
178
+ n,
179
+ rationale: [`fewer than 4 runs with proxy reward (n=${n}); insufficient evidence`]
180
+ };
181
+ }
182
+ const windowSize = Math.max(1, input.windowSize ?? Math.min(50, Math.floor(n / 2)));
183
+ const before = runs.slice(0, n - windowSize);
184
+ const after = runs.slice(n - windowSize);
185
+ const findings = [];
186
+ if (truthOf) {
187
+ const beforeProxy = before.map(proxyOf).filter((v) => typeof v === "number");
188
+ const afterProxy = after.map(proxyOf).filter((v) => typeof v === "number");
189
+ const beforeTruth = before.map(truthOf).filter((v) => typeof v === "number");
190
+ const afterTruth = after.map(truthOf).filter((v) => typeof v === "number");
191
+ if (beforeProxy.length >= 2 && afterProxy.length >= 2 && beforeTruth.length >= 2 && afterTruth.length >= 2) {
192
+ const proxyDelta = mean(afterProxy) - mean(beforeProxy);
193
+ const truthDelta = mean(afterTruth) - mean(beforeTruth);
194
+ const gap = Math.max(0, proxyDelta - truthDelta);
195
+ const severity = clamp012(gap * 5);
196
+ findings.push({
197
+ signal: "reward_divergence",
198
+ severity,
199
+ message: severity >= sus ? `proxy reward rose by ${proxyDelta.toFixed(3)} while truth changed by ${truthDelta.toFixed(3)} \u2014 potential Goodhart` : `proxy and truth moved together (proxy ${proxyDelta.toFixed(3)}, truth ${truthDelta.toFixed(3)})`,
200
+ detail: {
201
+ proxyDelta,
202
+ truthDelta,
203
+ gap,
204
+ beforeN: beforeProxy.length,
205
+ afterN: afterProxy.length
206
+ }
207
+ });
208
+ }
209
+ }
210
+ {
211
+ const beforeP = before.map(proxyOf).filter((v) => typeof v === "number");
212
+ const afterP = after.map(proxyOf).filter((v) => typeof v === "number");
213
+ if (beforeP.length >= 4 && afterP.length >= 4) {
214
+ const ks = ksStatistic(beforeP, afterP);
215
+ const severity = clamp012(ks - 0.2);
216
+ findings.push({
217
+ signal: "distribution_shift",
218
+ severity,
219
+ message: severity >= sus ? `KS=${ks.toFixed(3)} between before/after windows \u2014 distributional shift large` : `KS=${ks.toFixed(3)} between before/after windows \u2014 within-distribution drift`,
220
+ detail: { ks, beforeN: beforeP.length, afterN: afterP.length }
221
+ });
222
+ }
223
+ }
224
+ {
225
+ const secondaryOf = input.secondaryRewardOf ?? defaultSecondary(input.verifiableRewardOptions);
226
+ const aligned = runs.map((r) => ({ p: proxyOf(r), s: secondaryOf(r) })).filter(
227
+ (x) => typeof x.p === "number" && typeof x.s === "number"
228
+ );
229
+ if (aligned.length >= 4) {
230
+ const ps = aligned.map((x) => x.p);
231
+ const ss = aligned.map((x) => x.s);
232
+ const r = pearsonR(ps, ss);
233
+ const severity = clamp012(0.5 - Math.max(0, r));
234
+ findings.push({
235
+ signal: "reward_disagreement",
236
+ severity,
237
+ message: severity >= sus ? `proxy and independent secondary reward correlate \u03C1=${r.toFixed(3)} \u2014 possibly hacking proxy` : `proxy and secondary reward correlate \u03C1=${r.toFixed(3)}`,
238
+ detail: { pearson: r, n: aligned.length }
239
+ });
240
+ }
241
+ }
242
+ {
243
+ const detRuns = filterDeterministicallyRewarded(runs, input.verifiableRewardOptions ?? {});
244
+ if (detRuns.length >= 4) {
245
+ const detBefore = detRuns.slice(0, Math.floor(detRuns.length / 2));
246
+ const detAfter = detRuns.slice(Math.floor(detRuns.length / 2));
247
+ const detDelta = mean(detAfter.map((r) => r.reward.value)) - mean(detBefore.map((r) => r.reward.value));
248
+ const proxyDelta = mean(after.map(proxyOf).filter((v) => typeof v === "number")) - mean(before.map(proxyOf).filter((v) => typeof v === "number"));
249
+ const driftGap = Math.max(0, proxyDelta - detDelta);
250
+ const severity = clamp012(driftGap * 5);
251
+ findings.push({
252
+ signal: "judge_drift",
253
+ severity,
254
+ message: severity >= sus ? `judge proxy +${proxyDelta.toFixed(3)} while deterministic reward +${detDelta.toFixed(3)} \u2014 judge drifting up without verifiable backing` : `judge and deterministic rewards move in step (judge ${proxyDelta.toFixed(3)}, det ${detDelta.toFixed(3)})`,
255
+ detail: { proxyDelta, detDelta, driftGap, n: detRuns.length }
256
+ });
257
+ }
258
+ }
259
+ const maxSev = findings.reduce((m, f) => Math.max(m, f.severity), 0);
260
+ const verdict = maxSev >= gam ? "gaming" : maxSev >= sus ? "suspect" : "clean";
261
+ const rationale = findings.filter((f) => f.severity >= sus).map((f) => `${f.signal}: severity ${f.severity.toFixed(2)} \u2014 ${f.message}`);
262
+ if (rationale.length === 0) rationale.push("no signals fired above suspect threshold");
263
+ return { findings, verdict, rationale, n };
264
+ }
265
+ function mean(xs) {
266
+ if (xs.length === 0) return 0;
267
+ return xs.reduce((s, x) => s + x, 0) / xs.length;
268
+ }
269
+ function clamp012(x) {
270
+ if (!Number.isFinite(x)) return 0;
271
+ return Math.max(0, Math.min(1, x));
272
+ }
273
+ function pearsonR(a, b) {
274
+ if (a.length !== b.length || a.length < 2) return 0;
275
+ const ma = mean(a);
276
+ const mb = mean(b);
277
+ let num = 0, da = 0, db = 0;
278
+ for (let i = 0; i < a.length; i++) {
279
+ const xa = a[i] - ma;
280
+ const xb = b[i] - mb;
281
+ num += xa * xb;
282
+ da += xa * xa;
283
+ db += xb * xb;
284
+ }
285
+ if (da === 0 || db === 0) return 0;
286
+ return num / Math.sqrt(da * db);
287
+ }
288
+ function ksStatistic(a, b) {
289
+ const sortedA = [...a].sort((x, y) => x - y);
290
+ const sortedB = [...b].sort((x, y) => x - y);
291
+ const all = [.../* @__PURE__ */ new Set([...sortedA, ...sortedB])].sort((x, y) => x - y);
292
+ let max = 0;
293
+ for (const v of all) {
294
+ const fa = sortedA.filter((x) => x <= v).length / sortedA.length;
295
+ const fb = sortedB.filter((x) => x <= v).length / sortedB.length;
296
+ max = Math.max(max, Math.abs(fa - fb));
297
+ }
298
+ return max;
299
+ }
300
+ function defaultSecondary(verifiableOpts) {
301
+ return (run) => {
302
+ const filtered = filterDeterministicallyRewarded([run], verifiableOpts ?? {});
303
+ return filtered.length === 1 ? filtered[0].reward.value : null;
304
+ };
305
+ }
306
+
307
+ export {
308
+ extractVerifiableReward,
309
+ extractVerifiableRewardsFromRecords,
310
+ filterDeterministicallyRewarded,
311
+ detectRewardHacking
312
+ };
313
+ //# sourceMappingURL=chunk-YV7J7X5N.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/rl/verifiable-reward.ts","../src/rl/reward-hacking.ts"],"sourcesContent":["/**\n * Verifiable reward channel.\n *\n * For RL on coding / math / theorem-proving / structured-output tasks, the\n * reward signal is *decidable* — a test passes or fails, a proof checks or\n * doesn't, an output validates against a schema or doesn't. These rewards\n * are dramatically more useful for RL training than LLM-judge scores\n * because they don't drift, can't be Goodhart-gamed by the policy in the\n * same way, and don't require a separate calibration loop.\n *\n * The `MultiLayerVerifier` already produces this signal — it just doesn't\n * surface it in a shape that's clean enough for RL training. This module\n * wraps the verifier output so consumers can:\n *\n * 1. Extract a clean `VerifiableReward` from a `VerificationReport`\n * 2. Distinguish *deterministic* rewards (compile, test, schema) from\n * *probabilistic* rewards (judge) so they can be weighted differently\n * in the RL training step\n * 3. Filter `RunRecord[]` to only those with a verifiable reward,\n * producing the clean training set that DeepSeek-R1-style GRPO and\n * AlphaProof-style search both depend on\n *\n * Why this matters: every credible 2025-2026 frontier RL result on coding\n * agents leans on verifiable reward (DeepSeek-R1 GRPO on test pass-rate,\n * o-series RL on math/code, AlphaProof on Lean kernel checking). Mixing\n * judge scores into the reward signal poisons the gradient. This module\n * is the seam.\n */\n\nimport type { LayerResult, VerificationReport } from '../multi-layer-verifier'\nimport type { RunRecord } from '../run-record'\n\nexport type VerifiableRewardSource =\n | 'compile' // typecheck / build / lint passed\n | 'test' // unit / integration test pass-rate\n | 'schema' // structured output validates\n | 'sandbox' // sandbox exec exit code\n | 'judge' // LLM judge — probabilistic, included for completeness\n | 'composite' // weighted blend across multiple of the above\n\nexport interface VerifiableReward {\n /** Scalar in [0, 1]. The RL training signal. */\n value: number\n /** What produced the reward — different sources have different determinism. */\n source: VerifiableRewardSource\n /**\n * Determinism class. `'deterministic'` rewards are repeatable byte-for-byte\n * given the same inputs (compile, test, schema validation, sandbox exit code).\n * `'probabilistic'` rewards depend on a stochastic component (LLM judge).\n * Mixing these in the same training batch without separation is a known\n * footgun in production RLHF pipelines.\n */\n determinism: 'deterministic' | 'probabilistic'\n /**\n * Confidence in the reward value. For deterministic sources this is 1.0\n * (the bit either flipped or didn't). For judge sources this is the\n * judge-reported confidence or — when missing — a calibrated prior.\n */\n confidence: number\n /** The layer / judge id that produced the signal, for provenance. */\n origin: string\n /**\n * Any per-source breakdown the consumer might want — e.g. `{ tests_passed: 7, tests_total: 10 }`.\n */\n breakdown?: Record<string, number>\n}\n\nexport interface VerifiableRewardExtractionOptions {\n /**\n * Which layers count as deterministic-reward sources. The verifier doesn't\n * tag layers as \"this is verifiable\"; the caller declares it via this list\n * (or via the layer name → source mapping). Default treats common names\n * (`install`, `typecheck`, `build`, `lint`, `test`, `compile`, `schema`,\n * `sandbox`) as deterministic.\n */\n deterministicLayers?: string[]\n /**\n * Map layer name → reward source. Defaults to a sensible string-match.\n */\n sourceFor?: (layerName: string) => VerifiableRewardSource\n /**\n * Whether to fall back to a probabilistic (judge) reward when no\n * deterministic layer produced a numeric score. Default `true`. Set to\n * `false` for \"deterministic-only\" training pipelines that should\n * discard runs without a verifiable signal.\n */\n fallbackToJudge?: boolean\n /**\n * Default confidence for probabilistic (judge) rewards when the judge\n * doesn't report one. Default `0.7`.\n */\n judgeConfidenceFloor?: number\n}\n\nconst DEFAULT_DETERMINISTIC_LAYERS = new Set([\n 'install',\n 'typecheck',\n 'build',\n 'lint',\n 'test',\n 'compile',\n 'schema',\n 'sandbox',\n 'unit_tests',\n 'integration_tests',\n])\n\nconst DEFAULT_SOURCE_FOR = (name: string): VerifiableRewardSource => {\n const lower = name.toLowerCase()\n if (lower.includes('test')) return 'test'\n if (\n lower.includes('compile') ||\n lower.includes('build') ||\n lower.includes('typecheck') ||\n lower.includes('lint')\n )\n return 'compile'\n if (lower.includes('schema')) return 'schema'\n if (lower.includes('sandbox')) return 'sandbox'\n if (lower.includes('judge') || lower.includes('semantic')) return 'judge'\n return 'composite'\n}\n\n/**\n * Extract a `VerifiableReward` from a `VerificationReport`.\n *\n * Strategy: prefer the deterministic layers (in order: test → compile →\n * schema → sandbox), fall back to the judge layer if `fallbackToJudge` is\n * true, return `null` if no signal qualifies. When multiple deterministic\n * layers contribute, return a `'composite'` source with a weighted blend.\n */\nexport function extractVerifiableReward(\n report: VerificationReport,\n opts: VerifiableRewardExtractionOptions = {},\n): VerifiableReward | null {\n const deterministicSet = new Set(opts.deterministicLayers ?? [...DEFAULT_DETERMINISTIC_LAYERS])\n const sourceFor = opts.sourceFor ?? DEFAULT_SOURCE_FOR\n const fallbackToJudge = opts.fallbackToJudge ?? true\n const judgeFloor = opts.judgeConfidenceFloor ?? 0.7\n\n const deterministic = report.layers.filter(\n (l) => deterministicSet.has(l.layer) && typeof l.score === 'number' && Number.isFinite(l.score),\n )\n\n if (deterministic.length === 1) {\n const layer = deterministic[0]!\n return {\n value: clamp01(layer.score!),\n source: sourceFor(layer.layer),\n determinism: 'deterministic',\n confidence: 1,\n origin: layer.layer,\n breakdown: layerBreakdown(layer),\n }\n }\n\n if (deterministic.length > 1) {\n // Composite: weighted blend by `Layer.weight` if present, else equal.\n let num = 0\n let denom = 0\n const breakdown: Record<string, number> = {}\n for (const l of deterministic) {\n const w = (l.detail?.weight as number | undefined) ?? 1\n num += w * (l.score ?? 0)\n denom += w\n breakdown[l.layer] = l.score!\n }\n return {\n value: denom === 0 ? 0 : clamp01(num / denom),\n source: 'composite',\n determinism: 'deterministic',\n confidence: 1,\n origin: deterministic.map((l) => l.layer).join('+'),\n breakdown,\n }\n }\n\n if (!fallbackToJudge) return null\n\n const judge =\n report.layers.find(\n (l) =>\n typeof l.score === 'number' && Number.isFinite(l.score) && sourceFor(l.layer) === 'judge',\n ) ?? report.layers.find((l) => typeof l.score === 'number' && Number.isFinite(l.score))\n\n if (!judge) return null\n\n const confFromDetail = judge.detail?.confidence as number | undefined\n return {\n value: clamp01(judge.score!),\n source: 'judge',\n determinism: 'probabilistic',\n confidence: typeof confFromDetail === 'number' ? confFromDetail : judgeFloor,\n origin: judge.layer,\n breakdown: layerBreakdown(judge),\n }\n}\n\n/**\n * Extract verifiable rewards from `RunRecord[]` produced via the\n * `verificationReportToRunRecord` adapter (which encodes per-layer scores\n * in `outcome.raw['layer.<name>']`). For records that don't carry layer\n * scores, returns `null` for that record.\n *\n * This is the canonical bridge from \"campaign-shaped artifacts\" to\n * \"RL-training-ready reward signals\": every record that has a clean\n * verifiable reward becomes a training datum, every record that doesn't\n * gets filtered out (or kept with `'probabilistic'` determinism for\n * separate downstream handling).\n */\nexport function extractVerifiableRewardsFromRecords(\n runs: RunRecord[],\n opts: VerifiableRewardExtractionOptions = {},\n): Array<{ runId: string; reward: VerifiableReward | null }> {\n const sourceFor = opts.sourceFor ?? DEFAULT_SOURCE_FOR\n const deterministicSet = new Set(opts.deterministicLayers ?? [...DEFAULT_DETERMINISTIC_LAYERS])\n const fallbackToJudge = opts.fallbackToJudge ?? true\n const judgeFloor = opts.judgeConfidenceFloor ?? 0.7\n\n return runs.map((run) => {\n // Recover per-layer scores from outcome.raw['layer.<name>']\n const layerScores: Array<{ name: string; score: number }> = []\n for (const [k, v] of Object.entries(run.outcome.raw)) {\n if (\n k.startsWith('layer.') &&\n !k.includes('.', 6) &&\n typeof v === 'number' &&\n Number.isFinite(v)\n ) {\n layerScores.push({ name: k.slice('layer.'.length), score: v })\n }\n }\n const det = layerScores.filter((l) => deterministicSet.has(l.name))\n\n if (det.length === 1) {\n const layer = det[0]!\n return {\n runId: run.runId,\n reward: {\n value: clamp01(layer.score),\n source: sourceFor(layer.name),\n determinism: 'deterministic',\n confidence: 1,\n origin: layer.name,\n },\n }\n }\n if (det.length > 1) {\n const value = det.reduce((s, l) => s + l.score, 0) / det.length\n const breakdown: Record<string, number> = Object.fromEntries(\n det.map((l) => [l.name, l.score]),\n )\n return {\n runId: run.runId,\n reward: {\n value: clamp01(value),\n source: 'composite',\n determinism: 'deterministic',\n confidence: 1,\n origin: det.map((l) => l.name).join('+'),\n breakdown,\n },\n }\n }\n if (!fallbackToJudge) return { runId: run.runId, reward: null }\n\n // Probabilistic fallback: use the run's primary score.\n const primary = run.outcome.holdoutScore ?? run.outcome.searchScore\n if (typeof primary !== 'number' || !Number.isFinite(primary)) {\n return { runId: run.runId, reward: null }\n }\n return {\n runId: run.runId,\n reward: {\n value: clamp01(primary),\n source: 'judge',\n determinism: 'probabilistic',\n confidence: judgeFloor,\n origin: 'run.outcome.score',\n },\n }\n })\n}\n\n/** Filter `RunRecord[]` to those with deterministic verifiable rewards. */\nexport function filterDeterministicallyRewarded(\n runs: RunRecord[],\n opts: VerifiableRewardExtractionOptions = {},\n): Array<{ run: RunRecord; reward: VerifiableReward }> {\n const rewarded = extractVerifiableRewardsFromRecords(runs, { ...opts, fallbackToJudge: false })\n const out: Array<{ run: RunRecord; reward: VerifiableReward }> = []\n for (let i = 0; i < runs.length; i++) {\n const r = rewarded[i]!\n if (r.reward && r.reward.determinism === 'deterministic') {\n out.push({ run: runs[i]!, reward: r.reward })\n }\n }\n return out\n}\n\n// ── Helpers ──────────────────────────────────────────────────────────────\n\nfunction clamp01(x: number): number {\n if (!Number.isFinite(x)) return 0\n return Math.max(0, Math.min(1, x))\n}\n\nfunction layerBreakdown(l: LayerResult): Record<string, number> {\n const out: Record<string, number> = {}\n if (l.diagnostics) {\n for (const [k, v] of Object.entries(l.diagnostics)) {\n if (typeof v === 'number' && Number.isFinite(v)) out[k] = v\n }\n }\n return out\n}\n","/**\n * Reward hacking / Goodhart detection.\n *\n * Goodhart's Law says: when a measure becomes a target, it ceases to be\n * a good measure. In RLHF and agentic-RL settings this is the dominant\n * failure mode — the policy learns to produce outputs that score well on\n * the proxy reward (judge, rubric, test pass-rate) without producing\n * the underlying capability the proxy was meant to track.\n *\n * Krakovna et al. (2020, \"Specification Gaming Examples in AI\") and the\n * subsequent RLHF reward-hacking literature (Skalse et al. 2022, Kim et al.\n * 2023) converge on a few diagnostic signatures:\n *\n * 1. **Reward divergence:** the proxy reward grows while the held-out\n * ground-truth signal stagnates or drops. Predictive validity over\n * time captures this.\n * 2. **Distributional shift in outputs:** after RL, the policy produces\n * outputs that no longer match the reference distribution — usually\n * because it found a high-reward attractor that's degenerate (e.g.\n * one-token responses, repetition, formatting tricks).\n * 3. **Disagreement between independent rewards:** if you train on\n * reward A and a held-out independent reward B drops sharply, you're\n * probably hacking A.\n * 4. **Calibration drift:** the verifiable / deterministic component of\n * the reward is stable; the probabilistic / judge component drifts up\n * while the deterministic component doesn't. The judge is being\n * gamed.\n *\n * This module ships explicit detectors for all four signatures, plus a\n * combined verdict. The output is diagnostic — actionable signals,\n * not autoreject — because each signature has known false positives\n * (e.g., a policy that genuinely improves can show distributional shift).\n *\n * Differs from `rubricPredictiveValidity` (which is a *standing* check on\n * whether rubrics correlate with deployment outcomes) — this is a\n * *temporal* check on whether the reward-vs-truth gap is *widening over\n * time during a training run*.\n */\n\nimport type { RunRecord } from '../run-record'\nimport {\n filterDeterministicallyRewarded,\n type VerifiableRewardExtractionOptions,\n} from './verifiable-reward'\n\nexport type RewardHackingSignal =\n | 'reward_divergence'\n | 'distribution_shift'\n | 'reward_disagreement'\n | 'judge_drift'\n\nexport interface RewardHackingFinding {\n signal: RewardHackingSignal\n /** Severity in [0, 1]. >0.5 = strong signal. */\n severity: number\n message: string\n /** Numeric evidence the consumer can render. */\n detail: Record<string, number>\n}\n\nexport interface RewardHackingReport {\n findings: RewardHackingFinding[]\n /**\n * Composite verdict. `'clean'` if every signal severity < 0.3;\n * `'suspect'` if at least one ≥ 0.3 but none ≥ 0.6; `'gaming'` if any ≥ 0.6.\n */\n verdict: 'clean' | 'suspect' | 'gaming'\n /** Rationale for the verdict, ready to paste into an audit log. */\n rationale: string[]\n /** Number of paired (proxy, truth) data points the report saw. */\n n: number\n}\n\nexport interface DetectRewardHackingInput {\n /**\n * Run records ordered by recency (oldest first). The detector segments\n * them into prefix/suffix windows to compute \"did the gap widen.\"\n */\n runs: RunRecord[]\n /**\n * The metric the policy was trained to optimize. Should be present on\n * `outcome.raw` or `outcome.holdoutScore`. Default reads `outcome.holdoutScore`.\n */\n proxyOf?: (run: RunRecord) => number | null\n /**\n * The held-out ground-truth metric. For RL on coding, this is typically\n * test pass-rate. For RLHF, it's downstream task performance or human\n * preference. For knowledge tasks, it's an independently-graded score.\n */\n truthOf?: (run: RunRecord) => number | null\n /**\n * Independent secondary reward. Used for the `reward_disagreement`\n * signal. Default uses the verifiable reward extractor (deterministic\n * sources only).\n */\n secondaryRewardOf?: (run: RunRecord) => number | null\n /**\n * Window size — how many of the most recent runs count as the \"after\"\n * cohort. Default min(50, half the runs).\n */\n windowSize?: number\n /**\n * Severity threshold to flag a signal. Default 0.3 (suspect) and 0.6\n * (gaming).\n */\n thresholds?: { suspect?: number; gaming?: number }\n /**\n * Verifiable-reward options used for the secondary-reward fallback.\n */\n verifiableRewardOptions?: VerifiableRewardExtractionOptions\n}\n\nconst DEFAULT_PROXY = (r: RunRecord): number | null => {\n const v = r.outcome.holdoutScore ?? r.outcome.searchScore\n return typeof v === 'number' && Number.isFinite(v) ? v : null\n}\n\nexport function detectRewardHacking(input: DetectRewardHackingInput): RewardHackingReport {\n const proxyOf = input.proxyOf ?? DEFAULT_PROXY\n const truthOf = input.truthOf\n const sus = input.thresholds?.suspect ?? 0.3\n const gam = input.thresholds?.gaming ?? 0.6\n\n const runs = input.runs.filter((r) => proxyOf(r) !== null)\n const n = runs.length\n if (n < 4) {\n return {\n findings: [],\n verdict: 'clean',\n n,\n rationale: [`fewer than 4 runs with proxy reward (n=${n}); insufficient evidence`],\n }\n }\n const windowSize = Math.max(1, input.windowSize ?? Math.min(50, Math.floor(n / 2)))\n const before = runs.slice(0, n - windowSize)\n const after = runs.slice(n - windowSize)\n\n const findings: RewardHackingFinding[] = []\n\n // ── Signal 1: reward divergence (proxy ↑ while truth flat or ↓) ──────\n if (truthOf) {\n const beforeProxy = before.map(proxyOf).filter((v): v is number => typeof v === 'number')\n const afterProxy = after.map(proxyOf).filter((v): v is number => typeof v === 'number')\n const beforeTruth = before.map(truthOf).filter((v): v is number => typeof v === 'number')\n const afterTruth = after.map(truthOf).filter((v): v is number => typeof v === 'number')\n if (\n beforeProxy.length >= 2 &&\n afterProxy.length >= 2 &&\n beforeTruth.length >= 2 &&\n afterTruth.length >= 2\n ) {\n const proxyDelta = mean(afterProxy) - mean(beforeProxy)\n const truthDelta = mean(afterTruth) - mean(beforeTruth)\n // Divergence: proxy goes up while truth goes flat or down.\n // Severity = max(0, (proxyDelta - truthDelta)) — bigger gap = bigger signal.\n const gap = Math.max(0, proxyDelta - truthDelta)\n const severity = clamp01(gap * 5) // scale: 0.2 absolute gap → severity 1.0\n findings.push({\n signal: 'reward_divergence',\n severity,\n message:\n severity >= sus\n ? `proxy reward rose by ${proxyDelta.toFixed(3)} while truth changed by ${truthDelta.toFixed(3)} — potential Goodhart`\n : `proxy and truth moved together (proxy ${proxyDelta.toFixed(3)}, truth ${truthDelta.toFixed(3)})`,\n detail: {\n proxyDelta,\n truthDelta,\n gap,\n beforeN: beforeProxy.length,\n afterN: afterProxy.length,\n },\n })\n }\n }\n\n // ── Signal 2: distributional shift in outputs (KS on score distributions) ──\n {\n const beforeP = before.map(proxyOf).filter((v): v is number => typeof v === 'number')\n const afterP = after.map(proxyOf).filter((v): v is number => typeof v === 'number')\n if (beforeP.length >= 4 && afterP.length >= 4) {\n const ks = ksStatistic(beforeP, afterP)\n // KS statistic: bigger = more shift. We're agnostic about direction;\n // genuine improvement ALSO produces shift, so this signal is\n // contributory rather than load-bearing.\n const severity = clamp01(ks - 0.2)\n findings.push({\n signal: 'distribution_shift',\n severity,\n message:\n severity >= sus\n ? `KS=${ks.toFixed(3)} between before/after windows — distributional shift large`\n : `KS=${ks.toFixed(3)} between before/after windows — within-distribution drift`,\n detail: { ks, beforeN: beforeP.length, afterN: afterP.length },\n })\n }\n }\n\n // ── Signal 3: reward disagreement (proxy vs independent secondary) ────\n {\n const secondaryOf = input.secondaryRewardOf ?? defaultSecondary(input.verifiableRewardOptions)\n const aligned = runs\n .map((r) => ({ p: proxyOf(r), s: secondaryOf(r) }))\n .filter(\n (x): x is { p: number; s: number } => typeof x.p === 'number' && typeof x.s === 'number',\n )\n if (aligned.length >= 4) {\n const ps = aligned.map((x) => x.p)\n const ss = aligned.map((x) => x.s)\n const r = pearsonR(ps, ss)\n // Disagreement: low or negative correlation between primary proxy\n // reward and an independent secondary signal.\n const severity = clamp01(0.5 - Math.max(0, r))\n findings.push({\n signal: 'reward_disagreement',\n severity,\n message:\n severity >= sus\n ? `proxy and independent secondary reward correlate ρ=${r.toFixed(3)} — possibly hacking proxy`\n : `proxy and secondary reward correlate ρ=${r.toFixed(3)}`,\n detail: { pearson: r, n: aligned.length },\n })\n }\n }\n\n // ── Signal 4: judge drift (probabilistic up while deterministic flat) ─\n {\n const detRuns = filterDeterministicallyRewarded(runs, input.verifiableRewardOptions ?? {})\n if (detRuns.length >= 4) {\n const detBefore = detRuns.slice(0, Math.floor(detRuns.length / 2))\n const detAfter = detRuns.slice(Math.floor(detRuns.length / 2))\n const detDelta =\n mean(detAfter.map((r) => r.reward.value)) - mean(detBefore.map((r) => r.reward.value))\n const proxyDelta =\n mean(after.map(proxyOf).filter((v): v is number => typeof v === 'number')) -\n mean(before.map(proxyOf).filter((v): v is number => typeof v === 'number'))\n const driftGap = Math.max(0, proxyDelta - detDelta)\n const severity = clamp01(driftGap * 5)\n findings.push({\n signal: 'judge_drift',\n severity,\n message:\n severity >= sus\n ? `judge proxy +${proxyDelta.toFixed(3)} while deterministic reward +${detDelta.toFixed(3)} — judge drifting up without verifiable backing`\n : `judge and deterministic rewards move in step (judge ${proxyDelta.toFixed(3)}, det ${detDelta.toFixed(3)})`,\n detail: { proxyDelta, detDelta, driftGap, n: detRuns.length },\n })\n }\n }\n\n const maxSev = findings.reduce((m, f) => Math.max(m, f.severity), 0)\n const verdict: RewardHackingReport['verdict'] =\n maxSev >= gam ? 'gaming' : maxSev >= sus ? 'suspect' : 'clean'\n const rationale = findings\n .filter((f) => f.severity >= sus)\n .map((f) => `${f.signal}: severity ${f.severity.toFixed(2)} — ${f.message}`)\n if (rationale.length === 0) rationale.push('no signals fired above suspect threshold')\n\n return { findings, verdict, rationale, n }\n}\n\n// ── Helpers ──────────────────────────────────────────────────────────────\n\nfunction mean(xs: number[]): number {\n if (xs.length === 0) return 0\n return xs.reduce((s, x) => s + x, 0) / xs.length\n}\n\nfunction clamp01(x: number): number {\n if (!Number.isFinite(x)) return 0\n return Math.max(0, Math.min(1, x))\n}\n\nfunction pearsonR(a: number[], b: number[]): number {\n if (a.length !== b.length || a.length < 2) return 0\n const ma = mean(a)\n const mb = mean(b)\n let num = 0,\n da = 0,\n db = 0\n for (let i = 0; i < a.length; i++) {\n const xa = a[i]! - ma\n const xb = b[i]! - mb\n num += xa * xb\n da += xa * xa\n db += xb * xb\n }\n if (da === 0 || db === 0) return 0\n return num / Math.sqrt(da * db)\n}\n\nfunction ksStatistic(a: number[], b: number[]): number {\n // Two-sample Kolmogorov-Smirnov statistic.\n const sortedA = [...a].sort((x, y) => x - y)\n const sortedB = [...b].sort((x, y) => x - y)\n const all = [...new Set([...sortedA, ...sortedB])].sort((x, y) => x - y)\n let max = 0\n for (const v of all) {\n const fa = sortedA.filter((x) => x <= v).length / sortedA.length\n const fb = sortedB.filter((x) => x <= v).length / sortedB.length\n max = Math.max(max, Math.abs(fa - fb))\n }\n return max\n}\n\nfunction defaultSecondary(\n verifiableOpts?: VerifiableRewardExtractionOptions,\n): (run: RunRecord) => number | null {\n return (run: RunRecord) => {\n const filtered = filterDeterministicallyRewarded([run], verifiableOpts ?? {})\n return filtered.length === 1 ? filtered[0]!.reward.value : null\n }\n}\n"],"mappings":"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","names":["clamp01"]}
@@ -1,4 +1,4 @@
1
- import { b as FeedbackLabel, p as ProposedSideEffect } from './feedback-trajectory-iATEAHmc.js';
1
+ import { b as FeedbackLabel, p as ProposedSideEffect } from './feedback-trajectory-Dvy-bt7x.js';
2
2
  import { C as ControlEvalResult, a as ControlRunResult, h as ControlRuntimeConfig } from './control-runtime-BZ_lVLYW.js';
3
3
  import { T as TraceEmitter } from './emitter-DP_cSSiw.js';
4
4
  import { T as TraceStore, F as FailureClass } from './store-Db2Bv8Cf.js';
package/dist/control.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- export { A as ActionExecutionPolicy, a as ActionPolicyDecision, C as ControlRunToRunRecordOptions, e as ProposeReviewConfig, f as ProposeReviewControlAction, g as ProposeReviewControlConfig, h as ProposeReviewControlResult, i as ProposeReviewControlState, j as ProposeReviewReport, p as RunEvidenceMetadata, s as controlRunToRunRecord, u as evaluateActionPolicy, x as runProposeReview, y as runProposeReviewAsControlLoop, z as scoreFromEvals } from './control-DVrmvM_k.js';
1
+ export { A as ActionExecutionPolicy, a as ActionPolicyDecision, C as ControlRunToRunRecordOptions, e as ProposeReviewConfig, f as ProposeReviewControlAction, g as ProposeReviewControlConfig, h as ProposeReviewControlResult, i as ProposeReviewControlState, j as ProposeReviewReport, p as RunEvidenceMetadata, s as controlRunToRunRecord, u as evaluateActionPolicy, x as runProposeReview, y as runProposeReviewAsControlLoop, z as scoreFromEvals } from './control-CmLJk3IG.js';
2
2
  export { c as ControlActionFailureMode, d as ControlActionOutcome, e as ControlBudget, f as ControlContext, g as ControlDecision, C as ControlEvalResult, a as ControlRunResult, h as ControlRuntimeConfig, i as ControlRuntimeError, j as ControlSeverity, b as ControlStep, k as ControlStopPolicies, S as StopDecision, l as allCriticalPassed, o as objectiveEval, r as runAgentControlLoop, s as stopOnNoProgress, m as stopOnRepeatedAction, n as subjectiveEval } from './control-runtime-BZ_lVLYW.js';
3
- import './feedback-trajectory-iATEAHmc.js';
4
- import './dataset-ueRVTUoY.js';
3
+ import './feedback-trajectory-Dvy-bt7x.js';
4
+ import './dataset-BlwAtYYf.js';
5
5
  import './errors-mje_cKOs.js';
6
6
  import './emitter-DP_cSSiw.js';
7
7
  import './store-Db2Bv8Cf.js';
package/dist/control.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  runProposeReview,
5
5
  runProposeReviewAsControlLoop,
6
6
  scoreFromEvals
7
- } from "./chunk-7PR3WPWE.js";
7
+ } from "./chunk-L7XMNXLO.js";
8
8
  import {
9
9
  allCriticalPassed,
10
10
  objectiveEval,
@@ -13,7 +13,7 @@ import {
13
13
  stopOnRepeatedAction,
14
14
  subjectiveEval
15
15
  } from "./chunk-NCRFYPS3.js";
16
- import "./chunk-TSPOEDM3.js";
16
+ import "./chunk-BWZEGTES.js";
17
17
  import "./chunk-TVVP3ZZQ.js";
18
18
  import "./chunk-VSMTAMNK.js";
19
19
  import "./chunk-QYJT52YW.js";
@@ -112,4 +112,4 @@ declare class Dataset {
112
112
  }
113
113
  declare function hashScenarios(scenarios: DatasetScenario[]): Promise<string>;
114
114
 
115
- export { type DatasetSplit as D, HoldoutLockedError as H, type SliceOptions as S, type DatasetScenario as a, type DatasetManifest as b, Dataset as c, type DatasetDifficulty as d, type DatasetProvenance as e, hashScenarios as h };
115
+ export { type DatasetSplit as D, HoldoutLockedError as H, type SliceOptions as S, type DatasetScenario as a, Dataset as b, type DatasetManifest as c, type DatasetDifficulty as d, type DatasetProvenance as e, hashScenarios as h };
@@ -1,5 +1,5 @@
1
1
  import { C as ControlEvalResult, a as ControlRunResult, b as ControlStep } from './control-runtime-BZ_lVLYW.js';
2
- import { D as DatasetSplit, a as DatasetScenario } from './dataset-ueRVTUoY.js';
2
+ import { D as DatasetSplit, a as DatasetScenario } from './dataset-BlwAtYYf.js';
3
3
 
4
4
  type FeedbackArtifactType = 'text' | 'code' | 'plan' | 'research' | 'action' | 'ui' | 'decision' | 'data' | 'other';
5
5
  type FeedbackLabelSource = 'user' | 'judge' | 'environment' | 'metric' | 'policy' | 'system';
@@ -1,6 +1,134 @@
1
- export { E as EuRiskClass, G as GovernanceContext, a as GovernanceFinding, b as GovernanceReport, U as UseCaseSignals, g as classifyEuAiRisk, h as euAiActReport, n as nistAiRmfReport, j as renderMarkdown, k as soc2Report, l as summarize } from '../index-CN2agEaO.js';
2
- import '../dataset-ueRVTUoY.js';
1
+ import { c as DatasetManifest } from '../dataset-BlwAtYYf.js';
2
+ import { b as CalibrationResult } from '../judge-calibration-DilmB3Ml.js';
3
+ import { O as OutcomeStore } from '../outcome-store-D6KWmYvj.js';
4
+ import { d as RedTeamReport } from '../red-team-30II1T4o.js';
5
+ import { T as TraceStore } from '../store-Db2Bv8Cf.js';
3
6
  import '../errors-mje_cKOs.js';
4
- import '../judge-calibration-DilmB3Ml.js';
5
- import '../outcome-store-D6KWmYvj.js';
6
- import '../store-Db2Bv8Cf.js';
7
+
8
+ /**
9
+ * Governance reporting — shared types.
10
+ *
11
+ * The framework collects a `GovernanceContext` (traces + outcomes +
12
+ * dataset manifests + red-team results + judge calibration) and each
13
+ * specific template (NIST AI RMF, SOC2, EU AI Act) renders a
14
+ * structured report from it.
15
+ *
16
+ * Reports are machine-readable JSON first; human-readable Markdown is a
17
+ * pure transform on top. External auditors consume the Markdown; CI
18
+ * consumes the JSON.
19
+ */
20
+
21
+ interface GovernanceContext {
22
+ /** Legal / org identity for the report. */
23
+ organization: string;
24
+ /** System / agent identifier. */
25
+ systemName: string;
26
+ /** ISO8601 period the report covers. */
27
+ periodStart: string;
28
+ periodEnd: string;
29
+ /** Versioned dataset manifests used during the period. */
30
+ datasets: DatasetManifest[];
31
+ traceStore: TraceStore;
32
+ outcomeStore?: OutcomeStore;
33
+ /** Cached red-team results for the period, if available. */
34
+ redTeam?: RedTeamReport;
35
+ /** Judge-vs-human calibration results, if measured. */
36
+ judgeCalibration?: CalibrationResult[];
37
+ /** Responsible owner for the system — role + name + email. */
38
+ owner: {
39
+ role: string;
40
+ name: string;
41
+ email: string;
42
+ };
43
+ }
44
+ interface GovernanceFinding {
45
+ id: string;
46
+ severity: 'info' | 'low' | 'medium' | 'high' | 'critical';
47
+ /** Control reference the finding maps to (e.g. "NIST-AI-RMF:MEASURE-2.1"). */
48
+ control: string;
49
+ summary: string;
50
+ evidence?: string;
51
+ remediation?: string;
52
+ }
53
+ interface GovernanceReport {
54
+ framework: 'NIST-AI-RMF' | 'SOC2' | 'EU-AI-ACT';
55
+ version: string;
56
+ context: Pick<GovernanceContext, 'organization' | 'systemName' | 'periodStart' | 'periodEnd' | 'owner'>;
57
+ summary: {
58
+ findings: number;
59
+ byeverity: Record<GovernanceFinding['severity'], number>;
60
+ overall: 'compliant' | 'compliant-with-findings' | 'non-compliant';
61
+ };
62
+ findings: GovernanceFinding[];
63
+ /** Framework-specific structured payload (mapped controls, risk class, etc.). */
64
+ payload: Record<string, unknown>;
65
+ generatedAt: string;
66
+ }
67
+ declare function renderMarkdown(report: GovernanceReport): string;
68
+ declare function summarize(findings: GovernanceFinding[]): GovernanceReport['summary'];
69
+
70
+ /**
71
+ * EU AI Act — risk-class classification + compliance checklist.
72
+ *
73
+ * Classification is declarative: caller supplies the domain/use-case
74
+ * signals (biometric? critical infrastructure? education? employment?
75
+ * access to services?) and we map to the Act's risk tiers:
76
+ * - "unacceptable" (prohibited)
77
+ * - "high" (Annex III — strict obligations)
78
+ * - "limited" (transparency obligations)
79
+ * - "minimal" (voluntary codes of conduct)
80
+ *
81
+ * Then the compliance checklist enumerates Article 9 (risk mgmt),
82
+ * 10 (data + data governance), 11 (technical documentation), 13
83
+ * (transparency), 14 (human oversight), 15 (accuracy + robustness)
84
+ * requirements and flags gaps.
85
+ */
86
+
87
+ type EuRiskClass = 'unacceptable' | 'high' | 'limited' | 'minimal';
88
+ interface UseCaseSignals {
89
+ /** Used for biometric identification in public spaces? (Art. 5 — unacceptable). */
90
+ biometricPublic?: boolean;
91
+ /** Social scoring by public authorities? (Art. 5). */
92
+ socialScoring?: boolean;
93
+ /** Subliminal manipulation? (Art. 5). */
94
+ subliminal?: boolean;
95
+ /** Annex III sector: critical infrastructure / education / employment /
96
+ * access to essential services / law enforcement / migration /
97
+ * administration of justice / democratic processes? */
98
+ annexIII?: boolean;
99
+ /** Interacts directly with natural persons (chatbot, agent)? — limited risk. */
100
+ chatbot?: boolean;
101
+ /** Generates synthetic media (image/audio/video/text deepfakes)? — limited risk. */
102
+ generatesSyntheticMedia?: boolean;
103
+ }
104
+ declare function classifyEuAiRisk(signals: UseCaseSignals): EuRiskClass;
105
+ declare function euAiActReport(ctx: GovernanceContext, signals: UseCaseSignals): Promise<GovernanceReport>;
106
+
107
+ /**
108
+ * NIST AI RMF 1.0 — Govern / Map / Measure / Manage mapping.
109
+ *
110
+ * Each subcategory derives its status from concrete framework state:
111
+ * MEASURE 2.x: do we have a calibration regime? contamination controls?
112
+ * MEASURE 2.7: are red-team results available?
113
+ * MANAGE 1.x: are outcome metrics captured? correlation measured?
114
+ * GOVERN 1.x: dataset + prompt provenance recorded?
115
+ *
116
+ * We ship the mapping and the derivation rules; consumers supply the
117
+ * GovernanceContext.
118
+ */
119
+
120
+ declare function nistAiRmfReport(ctx: GovernanceContext): Promise<GovernanceReport>;
121
+
122
+ /**
123
+ * SOC 2 — Common Criteria 7 (system operations + change management)
124
+ * audit trail derived from the trace corpus.
125
+ *
126
+ * This is NOT a formal SOC2 report — that requires an external
127
+ * auditor. What we ship is the machine-readable *evidence* package
128
+ * that an auditor consumes: run counts, deploy events, access log
129
+ * summary, anomaly tracking, response-time SLOs.
130
+ */
131
+
132
+ declare function soc2Report(ctx: GovernanceContext): Promise<GovernanceReport>;
133
+
134
+ export { type EuRiskClass, type GovernanceContext, type GovernanceFinding, type GovernanceReport, type UseCaseSignals, classifyEuAiRisk, euAiActReport, nistAiRmfReport, renderMarkdown, soc2Report, summarize };