@tangle-network/agent-eval 0.171.0 → 0.172.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.
- package/CHANGELOG.md +85 -0
- package/README.md +3 -0
- package/dist/adapters/http.d.ts +2 -2
- package/dist/analyst/index.d.ts +5 -5
- package/dist/analyst/index.js +2 -2
- package/dist/{experiment-tracker-Dm8yQMqb.d.ts → attestation-CJBGmMVh.d.ts} +78 -2
- package/dist/attestation-CJBGmMVh.d.ts.map +1 -0
- package/dist/{experiment-tracker-BKEumQug.js → attestation-XSUpbc4o.js} +96 -2
- package/dist/attestation-XSUpbc4o.js.map +1 -0
- package/dist/{benchmark-command-D8k3Gf0J.js → benchmark-command--qeZUHbu.js} +2 -2
- package/dist/{benchmark-command-D8k3Gf0J.js.map → benchmark-command--qeZUHbu.js.map} +1 -1
- package/dist/benchmarks/index.d.ts +4 -4
- package/dist/benchmarks/index.js +2 -2
- package/dist/bounded-process-VIi0KSL2.js +212 -0
- package/dist/bounded-process-VIi0KSL2.js.map +1 -0
- package/dist/builder-eval/index.js +39 -98
- package/dist/builder-eval/index.js.map +1 -1
- package/dist/campaign/index.d.ts +8 -7
- package/dist/campaign/index.js +4 -4
- package/dist/{campaign-B72njjHj.js → campaign-Dp35pBbS.js} +4 -4
- package/dist/{campaign-B72njjHj.js.map → campaign-Dp35pBbS.js.map} +1 -1
- package/dist/canonical-CFpojCN5.d.ts +31 -0
- package/dist/canonical-CFpojCN5.d.ts.map +1 -0
- package/dist/{chat-client-DEtybj5i.js → chat-client-DI79OPye.js} +2 -2
- package/dist/{chat-client-DEtybj5i.js.map → chat-client-DI79OPye.js.map} +1 -1
- package/dist/cli.js +1 -1
- package/dist/{client-CDtcZ3p9.d.ts → client-Df7wdslk.d.ts} +2 -2
- package/dist/{client-CDtcZ3p9.d.ts.map → client-Df7wdslk.d.ts.map} +1 -1
- package/dist/contract/index.d.ts +9 -9
- package/dist/contract/index.js +4 -4
- package/dist/{default-registry-B0s2zU-s.d.ts → default-registry-XxedTLwu.d.ts} +3 -3
- package/dist/{default-registry-B0s2zU-s.d.ts.map → default-registry-XxedTLwu.d.ts.map} +1 -1
- package/dist/{define-agent-eval-Cjy2yhqP.d.ts → define-agent-eval-0wW7gFhr.d.ts} +4 -4
- package/dist/{define-agent-eval-Cjy2yhqP.d.ts.map → define-agent-eval-0wW7gFhr.d.ts.map} +1 -1
- package/dist/{define-agent-eval-Dy8QgxAI.js → define-agent-eval-jS8xj_Q_.js} +2 -2
- package/dist/{define-agent-eval-Dy8QgxAI.js.map → define-agent-eval-jS8xj_Q_.js.map} +1 -1
- package/dist/descriptive-B2iPaT9J.d.ts +89 -0
- package/dist/descriptive-B2iPaT9J.d.ts.map +1 -0
- package/dist/{engine-CAmTUk52.d.ts → engine-BfRay1qD.d.ts} +2 -2
- package/dist/{engine-CAmTUk52.d.ts.map → engine-BfRay1qD.d.ts.map} +1 -1
- package/dist/experiment/index.d.ts +3 -54
- package/dist/experiment/index.d.ts.map +1 -1
- package/dist/experiment/index.js +1 -95
- package/dist/experiment/index.js.map +1 -1
- package/dist/{heldout-gate-Dh2b62w8.d.ts → heldout-gate-JgNRDZwZ.d.ts} +3 -3
- package/dist/{heldout-gate-Dh2b62w8.d.ts.map → heldout-gate-JgNRDZwZ.d.ts.map} +1 -1
- package/dist/hosted/index.d.ts +1 -1
- package/dist/{index-lfaSeKSD.d.ts → index-D-UdhAmg.d.ts} +3 -31
- package/dist/index-D-UdhAmg.d.ts.map +1 -0
- package/dist/{index-DT73JraI.d.ts → index-DDAPhUJJ.d.ts} +4 -4
- package/dist/{index-DT73JraI.d.ts.map → index-DDAPhUJJ.d.ts.map} +1 -1
- package/dist/{index-fNXZMCzX.d.ts → index-DnglhM0A.d.ts} +9 -9
- package/dist/{index-fNXZMCzX.d.ts.map → index-DnglhM0A.d.ts.map} +1 -1
- package/dist/{index-8VIogTyS.d.ts → index-_vPrVMRX.d.ts} +6 -6
- package/dist/{index-8VIogTyS.d.ts.map → index-_vPrVMRX.d.ts.map} +1 -1
- package/dist/index.d.ts +154 -15
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -6
- package/dist/index.js.map +1 -1
- package/dist/{integrity-CyWSSoQS.js → integrity-BWywb34E.js} +34 -11
- package/dist/{integrity-CyWSSoQS.js.map → integrity-BWywb34E.js.map} +1 -1
- package/dist/ledger-core/index.d.ts +2 -1
- package/dist/{llm-judge-BtJ2Sfk_.js → llm-judge-aQHIk5_-.js} +16 -10
- package/dist/llm-judge-aQHIk5_-.js.map +1 -0
- package/dist/{matrix-DiHmUobV.d.ts → matrix-Ch8JO1pG.d.ts} +2 -2
- package/dist/{matrix-DiHmUobV.d.ts.map → matrix-Ch8JO1pG.d.ts.map} +1 -1
- package/dist/meta-eval/index.d.ts +162 -2
- package/dist/meta-eval/index.d.ts.map +1 -1
- package/dist/meta-eval/index.js +287 -2
- package/dist/meta-eval/index.js.map +1 -1
- package/dist/multishot/golden/index.d.ts +1 -1
- package/dist/multishot/index.d.ts +2 -2
- package/dist/openapi.json +1 -1
- package/dist/{produced-state-Cm6DU_Ao.js → produced-state-CxmbFxFd.js} +2 -2
- package/dist/{produced-state-Cm6DU_Ao.js.map → produced-state-CxmbFxFd.js.map} +1 -1
- package/dist/{promotion-policy-WSXtBgBb.d.ts → promotion-policy-BBBcz5_3.d.ts} +2 -2
- package/dist/{promotion-policy-WSXtBgBb.d.ts.map → promotion-policy-BBBcz5_3.d.ts.map} +1 -1
- package/dist/{provenance-CafMdZKM.d.ts → provenance-Dp-vvyrU.d.ts} +13 -5
- package/dist/provenance-Dp-vvyrU.d.ts.map +1 -0
- package/dist/rl.d.ts +1 -1
- package/dist/sandbox-harness-BlSOu4LX.d.ts.map +1 -1
- package/dist/{skillopt-optimization-method-DzlF2RM7.js → skillopt-optimization-method-LHi02MzH.js} +2 -2
- package/dist/{skillopt-optimization-method-DzlF2RM7.js.map → skillopt-optimization-method-LHi02MzH.js.map} +1 -1
- package/dist/{statistical-heldout-UhiexnjU.d.ts → statistical-heldout-Yldkntvy.d.ts} +2 -2
- package/dist/{statistical-heldout-UhiexnjU.d.ts.map → statistical-heldout-Yldkntvy.d.ts.map} +1 -1
- package/dist/{store-tool-spans-D_qMl2__.d.ts → store-tool-spans-BvdUbeOB.d.ts} +3 -3
- package/dist/{store-tool-spans-D_qMl2__.d.ts.map → store-tool-spans-BvdUbeOB.d.ts.map} +1 -1
- package/dist/supervisor-run/index.d.ts +35 -2
- package/dist/supervisor-run/index.d.ts.map +1 -1
- package/dist/supervisor-run/index.js +83 -38
- package/dist/supervisor-run/index.js.map +1 -1
- package/dist/{tool-groups-RGYfVWpc.d.ts → tool-groups-DjwlMBvW.d.ts} +2 -2
- package/dist/tool-groups-DjwlMBvW.d.ts.map +1 -0
- package/dist/trace-repair/index.d.ts +1 -1
- package/dist/traces.d.ts +2 -2
- package/dist/{types-CMyW4GnH.d.ts → types-CCZ34qmV.d.ts} +2 -2
- package/dist/{types-CMyW4GnH.d.ts.map → types-CCZ34qmV.d.ts.map} +1 -1
- package/dist/{types-DeIUdzNd.d.ts → types-CoPUTiXb.d.ts} +23 -92
- package/dist/types-CoPUTiXb.d.ts.map +1 -0
- package/dist/{types-JHMOqZI4.d.ts → types-nokrtr7M.d.ts} +11 -1
- package/dist/types-nokrtr7M.d.ts.map +1 -0
- package/docs/eval-surface-map.md +36 -0
- package/docs/insight-report.md +19 -0
- package/docs/plants.md +123 -0
- package/docs/public-api.md +45 -20
- package/package.json +1 -1
- package/dist/experiment-tracker-BKEumQug.js.map +0 -1
- package/dist/experiment-tracker-Dm8yQMqb.d.ts.map +0 -1
- package/dist/index-lfaSeKSD.d.ts.map +0 -1
- package/dist/llm-judge-BtJ2Sfk_.js.map +0 -1
- package/dist/provenance-CafMdZKM.d.ts.map +0 -1
- package/dist/tool-groups-RGYfVWpc.d.ts.map +0 -1
- package/dist/types-DeIUdzNd.d.ts.map +0 -1
- package/dist/types-JHMOqZI4.d.ts.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["populations"],"sources":["../../src/experiment/ast.ts","../../src/experiment/budget.ts","../../src/experiment/funnel.ts","../../src/experiment/define.ts","../../src/attestation.ts","../../src/experiment/evidence-receipt.ts","../../src/experiment/evidence-record.ts","../../src/experiment/power.ts"],"sourcesContent":["/**\n * The registered-rule AST: every rule an experiment registers is DATA.\n *\n * A closure cannot be canonicalized or hashed; a node tree can. `sealExperiment`\n * hashes the whole tree, and every interpreter in this file takes only a node\n * plus evidence records — no parameter for alpha, threshold, metric, or\n * stopping rule exists on any executable surface. The registered object and\n * the executed object are therefore the same object, and registered-vs-ran\n * drift is unrepresentable rather than checked.\n *\n * Node families:\n * Predicate closed-key comparisons — the only leaf\n * AdmissionRule monotone funnel stages with registered waivers\n * SelectionRule deterministic subsets over a closed field set\n * Estimand what the experiment measures\n * IntervalSpec how uncertainty is computed, seed included\n * Condition decision guards over named derived quantities\n * DecisionRule ordered verdict table, or a registered absence of one\n * Obligation a control that must exist before a verdict class is read\n * ValidityGate pre-spend design checks\n * HaltRule gates as prerequisites — failure refuses the spend\n * BudgetRule spend schedules with a named ledger\n * MatchedBudgetRule arm budget matching as a refusal\n * ReissuePolicy carrier faults are reissued; model outcomes stand\n */\n\nimport { ValidationError } from '../errors'\nimport { mulberry32 } from '../statistics'\n\n/** JSON-serializable value — everything a sealed node may carry. */\nexport type JsonValue = string | number | boolean | null | JsonValue[] | { [k: string]: JsonValue }\n\n/** Evidence row shape. Fields are addressed by dot-separated paths. */\nexport type EvidenceRecord = Record<string, unknown>\n\n/** A decision rule's branches did not cover the evidence. */\nclass DecisionTableNotTotalError extends ValidationError {}\n\n// ── Predicate ────────────────────────────────────────────────────────\n\n/**\n * Closed-key comparison over a declared record schema. The only leaf node.\n * `field` is a dot-separated path into an evidence record.\n */\nexport type Predicate =\n | {\n kind: 'compare'\n field: string\n op: 'eq' | 'ne' | 'lt' | 'lte' | 'gt' | 'gte'\n value: JsonValue\n }\n | { kind: 'in'; field: string; values: JsonValue[] }\n | { kind: 'all'; of: Predicate[] }\n | { kind: 'any'; of: Predicate[] }\n | { kind: 'not'; of: Predicate }\n\n/** Read a dot-separated field path. Missing segments yield `undefined`. */\nexport function readField(record: EvidenceRecord, path: string): unknown {\n let current: unknown = record\n for (const key of path.split('.')) {\n if (current === null || typeof current !== 'object') return undefined\n current = (current as Record<string, unknown>)[key]\n }\n return current\n}\n\n/** Evaluate a predicate against one evidence record. */\nexport function evaluatePredicate(predicate: Predicate, record: EvidenceRecord): boolean {\n switch (predicate.kind) {\n case 'compare':\n return compareValues(readField(record, predicate.field), predicate.op, predicate.value)\n case 'in':\n return predicate.values.includes(readField(record, predicate.field) as JsonValue)\n case 'all':\n return predicate.of.every((p) => evaluatePredicate(p, record))\n case 'any':\n return predicate.of.some((p) => evaluatePredicate(p, record))\n case 'not':\n return !evaluatePredicate(predicate.of, record)\n }\n}\n\n/** Numbers compare numerically; everything else compares as strings. */\nfunction compareValues(\n value: unknown,\n op: 'eq' | 'ne' | 'lt' | 'lte' | 'gt' | 'gte',\n target: JsonValue,\n): boolean {\n if (op === 'eq') return value === target\n if (op === 'ne') return value !== target\n const numeric = typeof value === 'number' && typeof target === 'number'\n const left = numeric ? (value as number) : String(value)\n const right = numeric ? (target as number) : String(target)\n switch (op) {\n case 'lt':\n return left < right\n case 'lte':\n return left <= right\n case 'gt':\n return left > right\n case 'gte':\n return left >= right\n }\n}\n\n// ── Admission ────────────────────────────────────────────────────────\n\n/**\n * One monotone funnel stage. `waives` names substrate admission conditions\n * deliberately NOT applied, so a waiver is registered, never implicit.\n */\nexport interface AdmissionStage {\n id: string\n keep: Predicate\n waives?: string[]\n}\n\n/** A partition is a set reported separately and never pooled. */\nexport interface AdmissionPartition {\n id: string\n /** Stage whose dropped rows this partition draws from. */\n from: string\n keep: Predicate\n pooling: 'never'\n}\n\n/** Declarative row-admission funnel. Stages only remove rows. */\nexport interface AdmissionRule {\n population: string\n stages: AdmissionStage[]\n partitions?: AdmissionPartition[]\n}\n\n// ── Selection ────────────────────────────────────────────────────────\n\n/**\n * Deterministic subset selection. `reads` is the closed field set the rule\n * may touch — outcome-contaminated selection is unrepresentable because an\n * outcome field is simply not in the list.\n */\nexport type SelectionRule =\n | {\n kind: 'round-robin'\n groupBy: string\n groupOrder: 'lex-asc'\n withinOrder: { field: string; dir: 'asc' | 'desc' }\n take: number\n reads: string[]\n }\n | {\n kind: 'filter-of'\n /** Name of the sealed subset or selection this rule filters. */\n base: string\n keep: Predicate\n order: { field: string; dir: 'asc' | 'desc' }\n }\n\n/**\n * Execute a selection rule.\n *\n * Round-robin walks groups in lexicographic order and takes ids in\n * within-group order until `take` ids are chosen. Filter-of keeps the ids of\n * `bases[rule.base]` whose record satisfies the predicate, in the registered\n * order. Ids absent from `records` are evaluated on their id alone (fields\n * derived from the id via `idFields`), so a sealed base outlives its source\n * records.\n */\nexport function runSelectionRule(\n rule: SelectionRule,\n records: readonly EvidenceRecord[],\n options: {\n /** Field carrying a row's identity. */\n idField: string\n /** Sealed or previously-computed subsets, by name. */\n bases?: Record<string, readonly string[]>\n /** Derive predicate-readable fields from a bare id when its record is absent. */\n idFields?: (id: string) => EvidenceRecord\n },\n): string[] {\n if (rule.kind === 'round-robin') {\n const allowed = new Set(rule.reads)\n for (const field of [rule.groupBy, rule.withinOrder.field]) {\n if (!allowed.has(field)) {\n throw new ValidationError(\n `runSelectionRule: round-robin reads '${field}' but its closed read set is [${rule.reads.join(', ')}]`,\n )\n }\n }\n const byGroup = new Map<string, string[]>()\n for (const record of records) {\n const group = String(readField(record, rule.groupBy))\n const id = String(readField(record, rule.withinOrder.field))\n const bucket = byGroup.get(group)\n if (bucket) bucket.push(id)\n else byGroup.set(group, [id])\n }\n for (const ids of byGroup.values()) {\n ids.sort()\n if (rule.withinOrder.dir === 'desc') ids.reverse()\n }\n const groups = [...byGroup.keys()].sort()\n const chosen: string[] = []\n let cursor = 0\n while (chosen.length < rule.take && groups.some((g) => byGroup.get(g)!.length > 0)) {\n const group = groups[cursor % groups.length]!\n const ids = byGroup.get(group)!\n if (ids.length > 0) chosen.push(ids.shift()!)\n cursor += 1\n }\n return chosen\n }\n\n const base = options.bases?.[rule.base]\n if (!base) {\n throw new ValidationError(`runSelectionRule: filter-of base '${rule.base}' was not provided`)\n }\n const index = new Map(records.map((r) => [String(readField(r, options.idField)), r]))\n const kept = base.filter((id) => {\n const record = index.get(id) ?? options.idFields?.(id)\n if (!record) {\n throw new ValidationError(\n `runSelectionRule: base id '${id}' has no record and no idFields derivation`,\n )\n }\n return evaluatePredicate(rule.keep, record)\n })\n const sorted = [...kept].sort()\n if (rule.order.dir === 'desc') sorted.reverse()\n return sorted\n}\n\n// ── Estimands ────────────────────────────────────────────────────────\n\n/** A named set of row identities, built from arm rows and an event predicate. */\nexport type SetExpr =\n | { kind: 'rows-where'; arm: string; event: Predicate }\n | { kind: 'intersect'; of: SetExpr[] }\n\n/**\n * What the experiment measures. Every estimand names the fields it reads, so\n * the sealed tree records the full data dependency of the number.\n */\nexport type Estimand =\n | { kind: 'rate'; event: Predicate; over: 'rollouts' }\n | { kind: 'rate-at-least-once'; event: Predicate; groupBy: string }\n | {\n kind: 'paired-mean-diff'\n armField: string\n treatment: string\n control: string\n pairBy: string\n /**\n * Field path to the per-row outcome. A boolean reads as 1 or 0, so a\n * binary pass/fail outcome gives the risk difference directly.\n */\n value: string\n /** A pair one arm did not answer contributes a difference of exactly zero. */\n missing: 'zero-diff'\n }\n | {\n kind: 'set-ratio'\n armField: string\n idField: string\n numerator: SetExpr\n denominator: SetExpr\n }\n\nexport interface EstimandResult {\n value: number\n numerator: number\n denominator: number\n}\n\nfunction evaluateSetExpr(\n expr: SetExpr,\n rows: readonly EvidenceRecord[],\n armField: string,\n idField: string,\n): Set<string> {\n if (expr.kind === 'rows-where') {\n const ids = new Set<string>()\n for (const row of rows) {\n if (String(readField(row, armField)) !== expr.arm) continue\n if (evaluatePredicate(expr.event, row)) ids.add(String(readField(row, idField)))\n }\n return ids\n }\n if (expr.of.length === 0) throw new ValidationError('computeEstimand: empty intersect')\n const sets = expr.of.map((e) => evaluateSetExpr(e, rows, armField, idField))\n const [first, ...rest] = sets\n const out = new Set<string>()\n for (const id of first!) {\n if (rest.every((s) => s.has(id))) out.add(id)\n }\n return out\n}\n\n/**\n * Read one registered outcome field as a number.\n *\n * A binary outcome reaches evidence as `true` or `false`. Its mean is the pass\n * rate and the mean of its paired differences is the risk difference, so\n * `true` reads as 1 and `false` as 0 — the same quantity a caller would\n * otherwise encode by hand, and the same reading in every interpreter here.\n * Every other type, and a non-finite number, is a measurement defect: it\n * rejects instead of poisoning the mean with `NaN` or a coerced zero.\n */\nfunction readNumericOutcome(raw: unknown, context: string, field: string, where: string): number {\n if (typeof raw === 'boolean') return raw ? 1 : 0\n if (typeof raw === 'number' && Number.isFinite(raw)) return raw\n throw new ValidationError(\n `${context}: value field '${field}' is not a finite number or a boolean on ${where}`,\n )\n}\n\n/** Compute an estimand over evidence rows. Pure; reads only registered fields. */\nexport function computeEstimand(\n estimand: Estimand,\n rows: readonly EvidenceRecord[],\n): EstimandResult {\n switch (estimand.kind) {\n case 'rate': {\n const numerator = rows.filter((r) => evaluatePredicate(estimand.event, r)).length\n if (rows.length === 0) throw new ValidationError('computeEstimand: rate over zero rows')\n return { value: numerator / rows.length, numerator, denominator: rows.length }\n }\n case 'rate-at-least-once': {\n const byGroup = new Map<string, boolean>()\n for (const row of rows) {\n const group = String(readField(row, estimand.groupBy))\n const hit = evaluatePredicate(estimand.event, row)\n byGroup.set(group, (byGroup.get(group) ?? false) || hit)\n }\n if (byGroup.size === 0) {\n throw new ValidationError('computeEstimand: rate-at-least-once over zero groups')\n }\n const numerator = [...byGroup.values()].filter(Boolean).length\n return { value: numerator / byGroup.size, numerator, denominator: byGroup.size }\n }\n case 'paired-mean-diff': {\n const byPair = new Map<string, { treatment?: number; control?: number }>()\n for (const row of rows) {\n const arm = String(readField(row, estimand.armField))\n if (arm !== estimand.treatment && arm !== estimand.control) continue\n const pair = String(readField(row, estimand.pairBy))\n const value = readNumericOutcome(\n readField(row, estimand.value),\n 'computeEstimand paired-mean-diff',\n estimand.value,\n `pair '${pair}'`,\n )\n const slot = byPair.get(pair) ?? {}\n if (arm === estimand.treatment) slot.treatment = value\n else slot.control = value\n byPair.set(pair, slot)\n }\n if (byPair.size === 0) {\n throw new ValidationError('computeEstimand: paired-mean-diff over zero pairs')\n }\n let sum = 0\n for (const slot of byPair.values()) {\n // missing: 'zero-diff' — an unanswered side contributes zero, never a drop\n sum += (slot.treatment ?? 0) - (slot.control ?? 0)\n }\n return { value: sum / byPair.size, numerator: sum, denominator: byPair.size }\n }\n case 'set-ratio': {\n const numeratorSet = evaluateSetExpr(\n estimand.numerator,\n rows,\n estimand.armField,\n estimand.idField,\n )\n const denominatorSet = evaluateSetExpr(\n estimand.denominator,\n rows,\n estimand.armField,\n estimand.idField,\n )\n if (denominatorSet.size === 0) {\n throw new ValidationError('computeEstimand: set-ratio denominator set is empty')\n }\n return {\n value: numeratorSet.size / denominatorSet.size,\n numerator: numeratorSet.size,\n denominator: denominatorSet.size,\n }\n }\n }\n}\n\n// ── Intervals ────────────────────────────────────────────────────────\n\n/** How uncertainty is computed. The seed is part of the registration. */\nexport type IntervalSpec =\n | {\n kind: 'cluster-bootstrap'\n clusterBy: string\n resamples: number\n seed: number\n level: number\n method: 'percentile'\n }\n | { kind: 'clopper-pearson'; level: number }\n\nexport interface ComputedInterval {\n lower: number\n upper: number\n level: number\n}\n\n/**\n * Execute an interval spec.\n *\n * Cluster-bootstrap resamples whole clusters of the per-row `value` field and\n * takes percentile bounds of the pooled mean. Clopper-Pearson computes the\n * exact binomial interval and requires `successes`/`trials` evidence instead\n * of rows.\n */\nexport function computeInterval(\n spec: IntervalSpec,\n evidence:\n | { kind: 'rows'; rows: readonly EvidenceRecord[]; value: string }\n | { kind: 'binomial'; successes: number; trials: number },\n): ComputedInterval {\n if (spec.kind === 'cluster-bootstrap') {\n if (evidence.kind !== 'rows') {\n throw new ValidationError('computeInterval: cluster-bootstrap requires row evidence')\n }\n const clusters = new Map<string, number[]>()\n for (const row of evidence.rows) {\n const cluster = String(readField(row, spec.clusterBy))\n const value = readNumericOutcome(\n readField(row, evidence.value),\n 'computeInterval cluster-bootstrap',\n evidence.value,\n `cluster '${cluster}'`,\n )\n const bucket = clusters.get(cluster)\n if (bucket) bucket.push(value)\n else clusters.set(cluster, [value])\n }\n const clusterValues = [...clusters.entries()]\n .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))\n .map(([, values]) => values)\n if (clusterValues.length < 2) {\n throw new ValidationError(\n `computeInterval: cluster-bootstrap needs >= 2 clusters, got ${clusterValues.length}`,\n )\n }\n const rng = mulberry32(spec.seed)\n const means = new Array<number>(spec.resamples)\n for (let draw = 0; draw < spec.resamples; draw++) {\n let sum = 0\n let count = 0\n for (let pick = 0; pick < clusterValues.length; pick++) {\n const cluster = clusterValues[Math.floor(rng() * clusterValues.length)]!\n for (const value of cluster) sum += value\n count += cluster.length\n }\n means[draw] = sum / count\n }\n means.sort((a, b) => a - b)\n const alpha = 1 - spec.level\n const lowerIndex = Math.floor((alpha / 2) * spec.resamples)\n const upperIndex = Math.min(spec.resamples - 1, Math.ceil((1 - alpha / 2) * spec.resamples) - 1)\n return {\n lower: means[lowerIndex]!,\n upper: means[Math.max(lowerIndex, upperIndex)]!,\n level: spec.level,\n }\n }\n\n if (evidence.kind !== 'binomial') {\n throw new ValidationError('computeInterval: clopper-pearson requires binomial evidence')\n }\n const { successes, trials } = evidence\n if (!Number.isInteger(successes) || !Number.isInteger(trials) || trials <= 0 || successes < 0) {\n throw new ValidationError(\n `computeInterval: clopper-pearson needs 0 <= successes <= trials, got ${successes}/${trials}`,\n )\n }\n if (successes > trials) {\n throw new ValidationError(\n `computeInterval: clopper-pearson successes ${successes} exceed trials ${trials}`,\n )\n }\n const alpha = 1 - spec.level\n const lower = successes === 0 ? 0 : binomialQuantile(successes, trials, alpha / 2, 'lower')\n const upper = successes === trials ? 1 : binomialQuantile(successes, trials, alpha / 2, 'upper')\n return { lower, upper, level: spec.level }\n}\n\n/**\n * Clopper-Pearson bound by bisection on the binomial tail. The lower bound is\n * the p with P(X >= successes | p) = alpha; the upper is the p with\n * P(X <= successes | p) = alpha. Deterministic, no special functions.\n */\nfunction binomialQuantile(\n successes: number,\n trials: number,\n alpha: number,\n side: 'lower' | 'upper',\n): number {\n const tail = (p: number): number => {\n // log-space binomial pmf accumulation for numeric stability\n let sum = 0\n for (let k = 0; k <= trials; k++) {\n const inTail = side === 'lower' ? k >= successes : k <= successes\n if (!inTail) continue\n sum += Math.exp(logBinomialPmf(k, trials, p))\n }\n return sum\n }\n let lo = 0\n let hi = 1\n for (let iter = 0; iter < 100; iter++) {\n const mid = (lo + hi) / 2\n if (tail(mid) < alpha) {\n if (side === 'lower') lo = mid\n else hi = mid\n } else {\n if (side === 'lower') hi = mid\n else lo = mid\n }\n }\n return (lo + hi) / 2\n}\n\nfunction logBinomialPmf(k: number, n: number, p: number): number {\n if (p <= 0) return k === 0 ? 0 : Number.NEGATIVE_INFINITY\n if (p >= 1) return k === n ? 0 : Number.NEGATIVE_INFINITY\n return logChoose(n, k) + k * Math.log(p) + (n - k) * Math.log(1 - p)\n}\n\nfunction logChoose(n: number, k: number): number {\n return logFactorial(n) - logFactorial(k) - logFactorial(n - k)\n}\n\nconst LOG_FACTORIAL_CACHE: number[] = [0]\nfunction logFactorial(n: number): number {\n for (let i = LOG_FACTORIAL_CACHE.length; i <= n; i++) {\n LOG_FACTORIAL_CACHE[i] = LOG_FACTORIAL_CACHE[i - 1]! + Math.log(i)\n }\n return LOG_FACTORIAL_CACHE[n]!\n}\n\n// ── Conditions and decisions ─────────────────────────────────────────\n\n/** Decision guards read only named derived quantities — never raw rows. */\nexport type Condition =\n | { kind: 'interval-excludes-zero'; interval: string; sign: 'positive' | 'negative' }\n | { kind: 'interval-includes-zero'; interval: string }\n | { kind: 'quantity-threshold'; quantity: string; op: 'gte' | 'lte' | 'gt' | 'lt'; value: number }\n | { kind: 'obligation-met'; obligation: string }\n | { kind: 'all'; of: Condition[] }\n | { kind: 'any'; of: Condition[] }\n | { kind: 'not'; of: Condition }\n\n/** The named quantities a decision rule may read. Nothing else reaches it. */\nexport interface DerivedQuantities {\n intervals: Record<string, { lower: number; upper: number }>\n quantities: Record<string, number>\n obligationsMet: Record<string, boolean>\n}\n\nexport function evaluateCondition(condition: Condition, evidence: DerivedQuantities): boolean {\n switch (condition.kind) {\n case 'interval-excludes-zero': {\n const interval = evidence.intervals[condition.interval]\n if (!interval) {\n throw new ValidationError(\n `evaluateCondition: interval '${condition.interval}' is not in the evidence`,\n )\n }\n const excludes = interval.lower > 0 || interval.upper < 0\n return excludes && (condition.sign === 'positive' ? interval.lower > 0 : interval.upper < 0)\n }\n case 'interval-includes-zero': {\n const interval = evidence.intervals[condition.interval]\n if (!interval) {\n throw new ValidationError(\n `evaluateCondition: interval '${condition.interval}' is not in the evidence`,\n )\n }\n return interval.lower <= 0 && interval.upper >= 0\n }\n case 'quantity-threshold': {\n const value = evidence.quantities[condition.quantity]\n if (value === undefined) {\n throw new ValidationError(\n `evaluateCondition: quantity '${condition.quantity}' is not in the evidence`,\n )\n }\n return compareValues(value, condition.op, condition.value)\n }\n case 'obligation-met':\n return evidence.obligationsMet[condition.obligation] === true\n case 'all':\n return condition.of.every((c) => evaluateCondition(c, evidence))\n case 'any':\n return condition.of.some((c) => evaluateCondition(c, evidence))\n case 'not':\n return !evaluateCondition(condition.of, evidence)\n }\n}\n\nexport interface DecisionBranch {\n when: Condition\n verdict: string\n report: string[]\n}\n\n/**\n * Ordered decision table: the first branch whose condition holds fires, and a\n * table no branch matches throws — a non-total registration is a defect, not\n * an implicit verdict. `report-only` registers the ABSENCE of a verdict\n * branch: the estimate and the per-row table are the finding, and the\n * registered meaning prose rides as non-executable interpretation data.\n */\nexport type DecisionRule =\n | { kind: 'table'; branches: DecisionBranch[] }\n | {\n kind: 'report-only'\n estimands: string[]\n intervals: string[]\n perRow: string[]\n interpretation?: { onQualitative: string; consequence: string }[]\n }\n\nexport interface DecisionOutcome {\n verdict: string\n report: string[]\n}\n\nexport function executeDecisionRule(\n rule: DecisionRule,\n evidence: DerivedQuantities,\n): DecisionOutcome {\n if (rule.kind === 'report-only') {\n return { verdict: 'report-only', report: [...rule.estimands, ...rule.intervals] }\n }\n for (const branch of rule.branches) {\n if (evaluateCondition(branch.when, evidence)) {\n return { verdict: branch.verdict, report: branch.report }\n }\n }\n throw new DecisionTableNotTotalError(\n 'executeDecisionRule: decision table is not total — no branch matched the evidence',\n )\n}\n\n/** A registered control that must exist before a class of verdicts is read. */\nexport interface Obligation {\n id: string\n appliesToVerdicts: string[]\n control: string\n}\n\n// ── Validity gates and halt ──────────────────────────────────────────\n\n/** Pre-spend design checks. Each returns pass/fail plus its evidence. */\nexport type ValidityGate =\n | {\n kind: 'oracle-determinism'\n unit: 'suite' | 'assertion'\n replicates: number\n maxFlipRate: number\n }\n | {\n kind: 'population-reproducibility'\n joinOn: string\n compare: string[]\n maxChangedRows: number\n }\n | { kind: 'provenance-assertion'; claim: Predicate }\n | {\n kind: 'power-floor'\n target: number\n effectGrid: number[]\n sim: { trials: number; resamples: number; seed: number }\n }\n | { kind: 'identity'; field: 'served-model'; op: 'basename-eq'; onFail: 'abort' }\n\nexport interface GateResult {\n id: string\n passed: boolean\n evidence: JsonValue\n}\n\n/**\n * Replicate-flip counting over graded states. A state whose replicates split\n * between pass and fail is flipping; its flip rate is the minority share.\n */\nexport function evaluateOracleDeterminismGate(\n id: string,\n gate: Extract<ValidityGate, { kind: 'oracle-determinism' }>,\n repsByState: Record<string, readonly boolean[]>,\n): GateResult {\n const evidence: Record<string, JsonValue> = {}\n let passed = true\n for (const [state, reps] of Object.entries(repsByState)) {\n const passes = reps.filter(Boolean).length\n const flipRate = reps.length === 0 ? 0 : Math.min(passes, reps.length - passes) / reps.length\n evidence[state] = { passes, replicates: reps.length, flipRate }\n if (flipRate > gate.maxFlipRate) passed = false\n }\n return { id, passed, evidence }\n}\n\n/**\n * Join two population snapshots on `joinOn` and compare the registered fields.\n * Only rows present in both snapshots are compared; a presence change is a\n * different failure and needs its own gate.\n */\nexport function evaluatePopulationReproducibilityGate(\n id: string,\n gate: Extract<ValidityGate, { kind: 'population-reproducibility' }>,\n populations: { left: readonly EvidenceRecord[]; right: readonly EvidenceRecord[] },\n): GateResult {\n const rightByKey = new Map(populations.right.map((r) => [String(readField(r, gate.joinOn)), r]))\n const changed: string[] = []\n for (const left of populations.left) {\n const key = String(readField(left, gate.joinOn))\n const right = rightByKey.get(key)\n if (!right) continue\n const moved = gate.compare.filter((f) => readField(left, f) !== readField(right, f))\n if (moved.length > 0) {\n changed.push(\n `${key} ${moved.map((f) => `${f}:${String(readField(left, f))}->${String(readField(right, f))}`).join(' ')}`,\n )\n }\n }\n return { id, passed: changed.length <= gate.maxChangedRows, evidence: changed }\n}\n\n/** The registered claim about provenance must hold on the provenance record. */\nexport function evaluateProvenanceGate(\n id: string,\n gate: Extract<ValidityGate, { kind: 'provenance-assertion' }>,\n provenance: EvidenceRecord,\n): GateResult {\n const passed = evaluatePredicate(gate.claim, provenance)\n return { id, passed, evidence: { claimHolds: passed } }\n}\n\n/** Final path segment equality between the pinned and the served identity. */\nexport function evaluateIdentityGate(\n id: string,\n _gate: Extract<ValidityGate, { kind: 'identity' }>,\n identities: { pinned: string; served: string },\n): GateResult {\n const basename = (s: string): string => s.split('/').pop() ?? s\n const passed = basename(identities.pinned) === basename(identities.served)\n return {\n id,\n passed,\n evidence: { pinned: identities.pinned, served: identities.served, matched: passed },\n }\n}\n\n/**\n * The design's power curve must reach the registered target at some grid\n * effect. The curve must cover the registered effect grid exactly — a curve\n * computed on a different grid is different evidence and is refused.\n */\nexport function evaluatePowerFloorGate(\n id: string,\n gate: Extract<ValidityGate, { kind: 'power-floor' }>,\n curve: readonly { effect: number; power: number }[],\n): GateResult {\n const byEffect = new Map(curve.map((point) => [point.effect, point.power]))\n const missing = gate.effectGrid.filter((effect) => !byEffect.has(effect))\n if (missing.length > 0) {\n throw new ValidationError(\n `evaluatePowerFloorGate: curve does not cover registered effects [${missing.join(', ')}]`,\n )\n }\n const powers = gate.effectGrid.map((effect) => byEffect.get(effect)!)\n const maxPower = Math.max(...powers)\n return {\n id,\n passed: maxPower >= gate.target,\n evidence: {\n target: gate.target,\n maxPower,\n curve: gate.effectGrid.map((effect) => ({ effect, power: byEffect.get(effect)! })),\n },\n }\n}\n\n/** Checks as prerequisites: any named gate failing refuses the spend. */\nexport interface HaltRule {\n when: { kind: 'any-gate-failed'; gates: string[] }\n action: 'refuse-spend'\n report: 'settling-n'\n}\n\nexport interface HaltOutcome {\n fired: boolean\n action: 'refuse-spend' | null\n failedGates: string[]\n}\n\nexport function evaluateHaltRule(halt: HaltRule, gates: readonly GateResult[]): HaltOutcome {\n const seen = new Map(gates.map((g) => [g.id, g]))\n const missing = halt.when.gates.filter((id) => !seen.has(id))\n if (missing.length > 0) {\n throw new ValidationError(\n `evaluateHaltRule: halt references gates that were not evaluated: [${missing.join(', ')}]`,\n )\n }\n const failed = halt.when.gates.filter((id) => !seen.get(id)!.passed)\n return failed.length > 0\n ? { fired: true, action: halt.action, failedGates: failed }\n : { fired: false, action: null, failedGates: [] }\n}\n\n// ── Budget rules ─────────────────────────────────────────────────────\n\n/**\n * Spend schedules as data. `ledger` names every entry the ceiling counts, so\n * what the gate reads is registered, not improvised at gate time.\n */\nexport type BudgetRule =\n | {\n kind: 'uniform-pass'\n ceilingUsd: number\n maxPasses: number\n projection: 'last-pass-cost'\n costSource: 'priced-per-call'\n ledger: { id: string; usd: number }[]\n partialPass: 'report-never-lift'\n }\n | {\n kind: 'n-ladder'\n steps: number[]\n ceilingUsd: number\n projection: 'unit-cost-times-rows-times-n'\n onExhaust: 'refuse-report-projection'\n }\n\nexport interface UniformPassDecision {\n pass: number\n cumulativeBefore: number\n projected: number\n go: boolean\n}\n\nexport interface UniformPassSchedule {\n decisions: UniformPassDecision[]\n uniformN: number\n}\n\n/**\n * Execute the uniform-pass schedule against measured pass costs. Pass 1 always\n * runs; each later pass runs only when the cumulative spend plus the last\n * measured pass cost stays at or under the registered ceiling. The registered\n * ledger is the pre-spend the ceiling counts.\n */\nexport function runUniformPassBudget(\n rule: Extract<BudgetRule, { kind: 'uniform-pass' }>,\n measuredPassCosts: readonly number[],\n): UniformPassSchedule {\n const preSpend = rule.ledger.reduce((sum, entry) => sum + entry.usd, 0)\n let cumulative = preSpend\n const decisions: UniformPassDecision[] = []\n let uniformN = 0\n for (let pass = 1; pass <= rule.maxPasses; pass++) {\n if (pass === 1) {\n if (measuredPassCosts[0] === undefined) break\n cumulative += measuredPassCosts[0]\n uniformN = 1\n continue\n }\n const projected = measuredPassCosts[pass - 2]\n if (projected === undefined) break\n const go = cumulative + projected <= rule.ceilingUsd\n decisions.push({ pass, cumulativeBefore: cumulative, projected, go })\n if (!go || measuredPassCosts[pass - 1] === undefined) break\n cumulative += measuredPassCosts[pass - 1]!\n uniformN = pass\n }\n return { decisions, uniformN }\n}\n\nexport interface NLadderProjection {\n chosenN: number | null\n projections: { n: number; projectedUsd: number; affordable: boolean }[]\n refusal: null | { onExhaust: 'refuse-report-projection'; reason: string }\n}\n\n/**\n * Walk the registered n-ladder and pick the first affordable step. When no\n * step fits the ceiling, the rule refuses and reports the projection instead\n * of shrinking the row set — \"never subset rows\" is the registered invariant.\n */\nexport function projectNLadderBudget(\n rule: Extract<BudgetRule, { kind: 'n-ladder' }>,\n measured: { unitCostUsd: number; rows: number },\n): NLadderProjection {\n const projections = rule.steps.map((n) => {\n const projectedUsd = measured.unitCostUsd * measured.rows * n\n return { n, projectedUsd, affordable: projectedUsd <= rule.ceilingUsd }\n })\n const first = projections.find((p) => p.affordable)\n if (first) return { chosenN: first.n, projections, refusal: null }\n return {\n chosenN: null,\n projections,\n refusal: {\n onExhaust: rule.onExhaust,\n reason: `no ladder step fits the ${rule.ceilingUsd} USD ceiling at ${measured.rows} rows x ${measured.unitCostUsd} USD per unit`,\n },\n }\n}\n\n// ── Matched budget and reissue ───────────────────────────────────────\n\n/** Arm budget matching as a refusal, not prose. Verified by `verifyMatchedBudgets`. */\nexport interface MatchedBudgetRule {\n measure: 'realized-tokens'\n tolerance: number\n onFail: 'refuse-contrast'\n}\n\n/** Carrier faults are reissued; model outcomes stand. Closed enumeration. */\nexport interface ReissuePolicy {\n carrierEvents: ('http-status' | 'transport-error' | 'deadline' | 'empty-content')[]\n modelOutcomesStand: true\n maxIssues: number\n}\n\nexport type ReissueVerdict = 'reissue' | 'stands' | 'exhausted'\n\n/**\n * Classify one rollout event under the registered reissue policy. A carrier\n * event within the issue budget is reissued; a model outcome always stands;\n * a carrier event past `maxIssues` is exhausted and reported, never retried.\n */\nexport function classifyReissue(\n policy: ReissuePolicy,\n event: string,\n issuesSoFar: number,\n): ReissueVerdict {\n if (!(policy.carrierEvents as string[]).includes(event)) return 'stands'\n return issuesSoFar < policy.maxIssues ? 'reissue' : 'exhausted'\n}\n","/**\n * Matched-budget verification between arms, as a refusal object.\n *\n * A paired contrast is only meaningful when both arms spent comparable\n * resources; \"realized prompt and completion tokens must agree within 5%\" is\n * a registered rule, so its verification returns a verdict artifact — the\n * refusal lives inside the result, never in prose beside it.\n */\n\nimport { CaptureIntegrityError } from '../errors'\nimport type { MatchedBudgetRule } from './ast'\n\n/** Arms whose realized budgets diverge past the registered tolerance. */\nexport class MatchedBudgetError extends CaptureIntegrityError {}\n\nexport interface ArmRealizedBudget {\n armId: string\n /** Realized prompt + completion tokens the arm actually consumed. */\n realizedTokens: number\n}\n\nexport interface MatchedBudgetVerdict {\n rule: MatchedBudgetRule\n arms: ArmRealizedBudget[]\n /** (max - min) / max over all arms; 0 when every arm spent nothing. */\n maxRelativeGap: number\n /** The two arms with the widest gap; null when fewer than two arms. */\n widestPair: [string, string] | null\n matched: boolean\n /** Populated exactly when `matched` is false. */\n refusal: null | { onFail: 'refuse-contrast'; reason: string }\n}\n\n/**\n * Compare realized per-arm spend under the registered tolerance. Requires at\n * least two arms — a single arm has nothing to match against. Negative or\n * non-finite token counts are refused as evidence corruption, not compared.\n */\nexport function verifyMatchedBudgets(\n rule: MatchedBudgetRule,\n arms: readonly ArmRealizedBudget[],\n): MatchedBudgetVerdict {\n if (arms.length < 2) {\n throw new MatchedBudgetError(\n `verifyMatchedBudgets: need >= 2 arms to match budgets, got ${arms.length}`,\n )\n }\n for (const arm of arms) {\n if (!Number.isFinite(arm.realizedTokens) || arm.realizedTokens < 0) {\n throw new MatchedBudgetError(\n `verifyMatchedBudgets: arm '${arm.armId}' has invalid realized tokens ${arm.realizedTokens}`,\n )\n }\n }\n const sorted = [...arms].sort((a, b) => a.realizedTokens - b.realizedTokens)\n const min = sorted[0]!\n const max = sorted[sorted.length - 1]!\n const maxRelativeGap =\n max.realizedTokens === 0 ? 0 : (max.realizedTokens - min.realizedTokens) / max.realizedTokens\n const matched = maxRelativeGap <= rule.tolerance\n return {\n rule,\n arms: [...arms],\n maxRelativeGap,\n widestPair: [min.armId, max.armId],\n matched,\n refusal: matched\n ? null\n : {\n onFail: rule.onFail,\n reason:\n `realized ${rule.measure} diverge ${(maxRelativeGap * 100).toFixed(1)}% between ` +\n `'${min.armId}' (${min.realizedTokens}) and '${max.armId}' (${max.realizedTokens}) — ` +\n `registered tolerance is ${(rule.tolerance * 100).toFixed(1)}%; the contrast is refused`,\n },\n }\n}\n\n/** Throw the refusal for callers that gate the contrast on it. */\nexport function assertMatchedBudgets(\n rule: MatchedBudgetRule,\n arms: readonly ArmRealizedBudget[],\n): MatchedBudgetVerdict {\n const verdict = verifyMatchedBudgets(rule, arms)\n if (verdict.refusal) throw new MatchedBudgetError(verdict.refusal.reason)\n return verdict\n}\n","/**\n * The denominator chain as a first-class object.\n *\n * A benchmark whose denominator is not auditable is not a benchmark. Every\n * stage names what entered, what it removed, and what survived, so\n * `input = surviving + sum(excluded)` reads off the table instead of being\n * trusted. A stage that gains rows is refused at construction — a funnel is\n * monotone by definition, and a non-monotone one is a broken denominator,\n * not a formatting choice.\n *\n * The object is its own JSON render; `renderFunnelTable` is the text render.\n * `executeAdmissionRule` produces one by running a sealed {@link AdmissionRule}\n * over evidence records.\n */\n\nimport { CaptureIntegrityError } from '../errors'\nimport { type AdmissionRule, type EvidenceRecord, evaluatePredicate } from './ast'\n\n/** A funnel stage gained rows, double-counted them, or failed to reconcile. */\nexport class FunnelIntegrityError extends CaptureIntegrityError {}\n\nexport interface FunnelStageCount {\n id: string\n entering: number\n excluded: number\n remaining: number\n /** Named exclusion reasons summing to `excluded`, when the stage has them. */\n exclusions?: Record<string, number>\n /** Substrate checks this stage deliberately does not apply. Registered, never implicit. */\n waives?: string[]\n}\n\nexport interface FunnelPartitionCount {\n id: string\n /** Stage whose excluded rows the partition draws from. */\n from: string\n count: number\n /** A partition is reported separately and never pooled into the survivors. */\n pooling: 'never'\n}\n\nexport interface ExperimentFunnel {\n population: string\n input: number\n stages: FunnelStageCount[]\n surviving: number\n partitions: FunnelPartitionCount[]\n}\n\nexport interface FunnelStageInput {\n id: string\n /** Rows this stage removed. */\n excluded: number\n exclusions?: Record<string, number>\n waives?: string[]\n}\n\n/**\n * Build a funnel from counts and refuse anything non-monotone.\n *\n * Refusals: a negative count, a stage that gains rows (excluded < 0 is the\n * only way to gain — `remaining = entering - excluded` by construction, so a\n * gain cannot be smuggled in through `remaining`), named exclusions that do\n * not sum to the stage total, and a partition drawing from an unknown stage\n * or exceeding what that stage excluded.\n */\nexport function buildFunnel(input: {\n population: string\n input: number\n stages: FunnelStageInput[]\n partitions?: { id: string; from: string; count: number }[]\n}): ExperimentFunnel {\n if (!Number.isInteger(input.input) || input.input < 0) {\n throw new FunnelIntegrityError(\n `funnel input must be a non-negative integer, got ${input.input}`,\n )\n }\n let entering = input.input\n const stages: FunnelStageCount[] = []\n for (const stage of input.stages) {\n if (!Number.isInteger(stage.excluded)) {\n throw new FunnelIntegrityError(\n `funnel stage '${stage.id}' excluded count must be an integer, got ${stage.excluded}`,\n )\n }\n if (stage.excluded < 0) {\n throw new FunnelIntegrityError(\n `funnel stage '${stage.id}' gains ${-stage.excluded} rows — a funnel stage can only remove rows`,\n )\n }\n if (stage.excluded > entering) {\n throw new FunnelIntegrityError(\n `funnel stage '${stage.id}' excludes ${stage.excluded} rows but only ${entering} entered`,\n )\n }\n if (stage.exclusions) {\n const sum = Object.values(stage.exclusions).reduce((a, b) => a + b, 0)\n if (sum !== stage.excluded) {\n throw new FunnelIntegrityError(\n `funnel stage '${stage.id}' names exclusions summing to ${sum} but excludes ${stage.excluded}`,\n )\n }\n }\n const remaining = entering - stage.excluded\n stages.push({\n id: stage.id,\n entering,\n excluded: stage.excluded,\n remaining,\n ...(stage.exclusions ? { exclusions: { ...stage.exclusions } } : {}),\n ...(stage.waives ? { waives: [...stage.waives] } : {}),\n })\n entering = remaining\n }\n const byStage = new Map(stages.map((s) => [s.id, s]))\n const partitions: FunnelPartitionCount[] = (input.partitions ?? []).map((partition) => {\n const source = byStage.get(partition.from)\n if (!source) {\n throw new FunnelIntegrityError(\n `funnel partition '${partition.id}' draws from unknown stage '${partition.from}'`,\n )\n }\n if (partition.count < 0 || partition.count > source.excluded) {\n throw new FunnelIntegrityError(\n `funnel partition '${partition.id}' counts ${partition.count} rows but stage '${partition.from}' excluded ${source.excluded}`,\n )\n }\n return { id: partition.id, from: partition.from, count: partition.count, pooling: 'never' }\n })\n const funnel: ExperimentFunnel = {\n population: input.population,\n input: input.input,\n stages,\n surviving: entering,\n partitions,\n }\n assertFunnelReconciles(funnel)\n return funnel\n}\n\n/** A chain that does not add up is a broken denominator, so this throws. */\nexport function assertFunnelReconciles(funnel: ExperimentFunnel): void {\n const excluded = funnel.stages.reduce((sum, stage) => sum + stage.excluded, 0)\n if (funnel.input !== funnel.surviving + excluded) {\n throw new FunnelIntegrityError(\n `funnel '${funnel.population}' does not reconcile: input ${funnel.input} != surviving ${funnel.surviving} + excluded ${excluded}`,\n )\n }\n let entering = funnel.input\n for (const stage of funnel.stages) {\n if (stage.entering !== entering || stage.remaining !== stage.entering - stage.excluded) {\n throw new FunnelIntegrityError(\n `funnel '${funnel.population}' stage '${stage.id}' does not chain: ` +\n `entering ${stage.entering} (expected ${entering}), remaining ${stage.remaining}`,\n )\n }\n if (stage.remaining > stage.entering) {\n throw new FunnelIntegrityError(\n `funnel '${funnel.population}' stage '${stage.id}' gains rows: ${stage.entering} -> ${stage.remaining}`,\n )\n }\n entering = stage.remaining\n }\n}\n\nexport interface AdmissionExecution {\n funnel: ExperimentFunnel\n survivors: EvidenceRecord[]\n /** Partition rows by partition id, reported separately and never pooled. */\n partitionRows: Record<string, EvidenceRecord[]>\n}\n\n/**\n * Run a sealed admission rule over evidence records. Each stage keeps the rows\n * its predicate accepts; partitions draw from the rows their source stage\n * dropped. The result embeds the funnel, so the denominator chain and the\n * surviving rows can never disagree.\n */\nexport function executeAdmissionRule(\n rule: AdmissionRule,\n records: readonly EvidenceRecord[],\n): AdmissionExecution {\n let current = [...records]\n const droppedAt = new Map<string, EvidenceRecord[]>()\n const stageInputs: FunnelStageInput[] = []\n for (const stage of rule.stages) {\n const kept: EvidenceRecord[] = []\n const dropped: EvidenceRecord[] = []\n for (const record of current) {\n if (evaluatePredicate(stage.keep, record)) kept.push(record)\n else dropped.push(record)\n }\n droppedAt.set(stage.id, dropped)\n stageInputs.push({\n id: stage.id,\n excluded: dropped.length,\n ...(stage.waives ? { waives: stage.waives } : {}),\n })\n current = kept\n }\n const partitionRows: Record<string, EvidenceRecord[]> = {}\n const partitionCounts: { id: string; from: string; count: number }[] = []\n for (const partition of rule.partitions ?? []) {\n const source = droppedAt.get(partition.from)\n if (!source) {\n throw new FunnelIntegrityError(\n `admission partition '${partition.id}' draws from unknown stage '${partition.from}'`,\n )\n }\n const rows = source.filter((record) => evaluatePredicate(partition.keep, record))\n partitionRows[partition.id] = rows\n partitionCounts.push({ id: partition.id, from: partition.from, count: rows.length })\n }\n const funnel = buildFunnel({\n population: rule.population,\n input: records.length,\n stages: stageInputs,\n partitions: partitionCounts,\n })\n return { funnel, survivors: current, partitionRows }\n}\n\n/**\n * Chain two funnels whose boundary agrees: the second funnel's input must be\n * exactly the first funnel's survivors. Anything else is a gap or an\n * injection, and both are refused.\n */\nexport function composeFunnels(\n first: ExperimentFunnel,\n second: ExperimentFunnel,\n): ExperimentFunnel {\n if (second.input !== first.surviving) {\n throw new FunnelIntegrityError(\n `cannot compose funnels: '${first.population}' survives ${first.surviving} rows but '${second.population}' starts from ${second.input}`,\n )\n }\n return buildFunnel({\n population: first.population,\n input: first.input,\n stages: [...first.stages, ...second.stages].map((stage) => ({\n id: stage.id,\n excluded: stage.excluded,\n ...(stage.exclusions ? { exclusions: stage.exclusions } : {}),\n ...(stage.waives ? { waives: stage.waives } : {}),\n })),\n partitions: [...first.partitions, ...second.partitions].map((partition) => ({\n id: partition.id,\n from: partition.from,\n count: partition.count,\n })),\n })\n}\n\n/**\n * Text render of the chain. One row per stage; the reconciliation line at the\n * bottom restates `input = surviving + excluded` so a reader can check the\n * arithmetic without a tool.\n */\nexport function renderFunnelTable(funnel: ExperimentFunnel): string {\n const rows = funnel.stages.map((stage) => [\n stage.id + (stage.waives?.length ? ` (waives: ${stage.waives.join(', ')})` : ''),\n String(stage.entering),\n String(stage.excluded),\n String(stage.remaining),\n ])\n const header = ['stage', 'entering', 'excluded', 'remaining']\n const widths = header.map((h, col) => Math.max(h.length, ...rows.map((r) => r[col]!.length)))\n const line = (cells: string[]): string =>\n cells.map((cell, col) => cell.padEnd(widths[col]!)).join(' ')\n const out: string[] = [\n `population: ${funnel.population}`,\n `input: ${funnel.input}`,\n line(header),\n line(widths.map((w) => '-'.repeat(w))),\n ...rows.map((r) => line(r)),\n ]\n const excluded = funnel.stages.reduce((sum, stage) => sum + stage.excluded, 0)\n out.push(\n `surviving: ${funnel.surviving} (input ${funnel.input} = surviving ${funnel.surviving} + excluded ${excluded})`,\n )\n for (const partition of funnel.partitions) {\n out.push(\n `partition ${partition.id}: ${partition.count} rows from '${partition.from}' — reported separately, never pooled`,\n )\n }\n return out.join('\\n')\n}\n","/**\n * Define, seal, and execute experiments whose every rule is registered data.\n *\n * `defineExperiment` validates the cross-references inside a spec and freezes\n * it. `sealExperiment` canonicalizes and hashes the whole tree — arms, row\n * admission, selection, estimands, intervals, decision rule, gates, halt,\n * budget — into one digest that lands on every downstream artifact. Changing\n * what is decided requires a new digest: an amendment is a re-seal with a\n * reason and blindness attestations, and the digest history is the audit\n * trail.\n *\n * `openSealedExperiment` is the only execution surface. It verifies the seal\n * and returns executors bound to the sealed spec; none of them takes a\n * parameter for alpha, threshold, metric, or stopping rule, so\n * registered-vs-ran drift is unrepresentable rather than checked.\n */\n\nimport { createHash } from 'node:crypto'\nimport { ValidationError } from '../errors'\nimport { canonicalString } from '../ledger-core/canonical'\nimport {\n type AdmissionRule,\n type BudgetRule,\n type ComputedInterval,\n type Condition,\n computeEstimand,\n computeInterval,\n type DecisionOutcome,\n type DecisionRule,\n type DerivedQuantities,\n type Estimand,\n type EstimandResult,\n type EvidenceRecord,\n evaluateHaltRule,\n evaluateIdentityGate,\n evaluateOracleDeterminismGate,\n evaluatePopulationReproducibilityGate,\n evaluatePowerFloorGate,\n evaluateProvenanceGate,\n executeDecisionRule,\n type GateResult,\n type HaltOutcome,\n type HaltRule,\n type IntervalSpec,\n type JsonValue,\n type MatchedBudgetRule,\n type NLadderProjection,\n type Obligation,\n projectNLadderBudget,\n type ReissuePolicy,\n runSelectionRule,\n runUniformPassBudget,\n type SelectionRule,\n type UniformPassSchedule,\n type ValidityGate,\n} from './ast'\nimport { type ArmRealizedBudget, type MatchedBudgetVerdict, verifyMatchedBudgets } from './budget'\nimport { type AdmissionExecution, executeAdmissionRule } from './funnel'\n\n/** A sealed experiment whose digest no longer matches its spec. */\nexport class SealIntegrityError extends ValidationError {}\n\n// ── Spec ─────────────────────────────────────────────────────────────\n\nexport interface ArmSpec {\n id: string\n role: 'treatment' | 'control'\n /** Digest of the AgentProfile the arm runs under. */\n profileDigest?: string\n /** Digest of the pinned execution policy the arm runs under. */\n policyDigest?: string\n /** Registered arm pins (model, seed, step budget, ...) as data. */\n pins?: Record<string, JsonValue>\n}\n\nexport type OutcomeSpec =\n | {\n kind: 'binary'\n /** Where the pass verdict comes from, e.g. 'injected-suite'. */\n source?: string\n digestVerified?: boolean\n /** What counts as a pass, e.g. 'exit-0' or 'reward-file-contains-1'. */\n pass?: string\n /** Errored rollouts stay in the denominator; dropping them is unregistered. */\n droppedRollouts?: 'forbidden'\n }\n | {\n kind: 'bounded-score'\n min: number\n max: number\n orientation: 'higher-is-better' | 'lower-is-better'\n }\n\n/**\n * Per-rollout seed derivation as a closed source list. `arm` is not in the\n * union, so arm-dependent seeding is unrepresentable.\n */\nexport interface SeedDerivation {\n from: ('seed' | 'rowId' | 'rolloutIndex')[]\n}\n\nexport interface ExperimentSpec {\n id: string\n /** Human prose for the audit trail — never executable. */\n hypothesis?: string\n arms: ArmSpec[]\n outcome: OutcomeSpec\n admission?: AdmissionRule\n /** Named deterministic subset rules. */\n selections?: Record<string, SelectionRule>\n /**\n * Selection OUTPUTS pinned into the seal. A filter-of base resolves here, so\n * reusing an earlier draw is registered and a re-draw is a new digest.\n */\n sealedSubsets?: Record<string, string[]>\n estimands?: Record<string, Estimand>\n intervals?: Record<string, IntervalSpec>\n decision: DecisionRule\n obligations?: Obligation[]\n /** Named pre-spend validity gates; the halt rule references these names. */\n gates?: Record<string, ValidityGate>\n halt?: HaltRule\n budget?: BudgetRule\n matchedBudget?: MatchedBudgetRule\n reissue?: ReissuePolicy\n seedDerivation?: SeedDerivation\n seed?: number\n}\n\n// ── Validation ───────────────────────────────────────────────────────\n\nfunction conditionRefs(condition: Condition): {\n intervals: string[]\n quantities: string[]\n obligations: string[]\n} {\n switch (condition.kind) {\n case 'interval-excludes-zero':\n case 'interval-includes-zero':\n return { intervals: [condition.interval], quantities: [], obligations: [] }\n case 'quantity-threshold':\n return { intervals: [], quantities: [condition.quantity], obligations: [] }\n case 'obligation-met':\n return { intervals: [], quantities: [], obligations: [condition.obligation] }\n case 'all':\n case 'any': {\n const nested = condition.of.map(conditionRefs)\n return {\n intervals: nested.flatMap((r) => r.intervals),\n quantities: nested.flatMap((r) => r.quantities),\n obligations: nested.flatMap((r) => r.obligations),\n }\n }\n case 'not':\n return conditionRefs(condition.of)\n }\n}\n\n/**\n * Validate every cross-reference inside a spec and freeze it.\n *\n * A decision condition may only read a registered interval, a registered\n * estimand, or a registered obligation; a halt rule may only reference\n * registered gates; a filter-of base must resolve to a registered selection\n * or sealed subset. Anything else is refused here, before sealing.\n */\nexport function defineExperiment(spec: ExperimentSpec): ExperimentSpec {\n const problems: string[] = []\n if (!spec.id || spec.id.trim().length === 0) problems.push('id is empty')\n if (spec.arms.length === 0) problems.push('at least one arm is required')\n const armIds = new Set<string>()\n for (const arm of spec.arms) {\n if (armIds.has(arm.id)) problems.push(`duplicate arm id '${arm.id}'`)\n armIds.add(arm.id)\n }\n if (!spec.arms.some((arm) => arm.role === 'treatment')) {\n problems.push('at least one arm must have role treatment')\n }\n\n const intervalNames = new Set(Object.keys(spec.intervals ?? {}))\n const estimandNames = new Set(Object.keys(spec.estimands ?? {}))\n const obligationIds = new Set((spec.obligations ?? []).map((o) => o.id))\n const gateNames = new Set(Object.keys(spec.gates ?? {}))\n const selectionNames = new Set(Object.keys(spec.selections ?? {}))\n const sealedSubsetNames = new Set(Object.keys(spec.sealedSubsets ?? {}))\n\n const checkCondition = (condition: Condition, where: string): void => {\n const refs = conditionRefs(condition)\n for (const name of refs.intervals) {\n if (!intervalNames.has(name)) problems.push(`${where} reads unregistered interval '${name}'`)\n }\n for (const name of refs.quantities) {\n if (!estimandNames.has(name)) problems.push(`${where} reads unregistered quantity '${name}'`)\n }\n for (const name of refs.obligations) {\n if (!obligationIds.has(name))\n problems.push(`${where} reads unregistered obligation '${name}'`)\n }\n }\n\n if (spec.decision.kind === 'table') {\n if (spec.decision.branches.length === 0) problems.push('decision table has no branches')\n spec.decision.branches.forEach((branch, index) => {\n checkCondition(branch.when, `decision branch ${index} ('${branch.verdict}')`)\n })\n } else {\n for (const name of spec.decision.estimands) {\n if (!estimandNames.has(name)) {\n problems.push(`report-only decision names unregistered estimand '${name}'`)\n }\n }\n for (const name of spec.decision.intervals) {\n if (!intervalNames.has(name)) {\n problems.push(`report-only decision names unregistered interval '${name}'`)\n }\n }\n }\n\n if (spec.decision.kind === 'table' && spec.obligations) {\n const verdicts = new Set(spec.decision.branches.map((b) => b.verdict))\n for (const obligation of spec.obligations) {\n for (const verdict of obligation.appliesToVerdicts) {\n if (!verdicts.has(verdict)) {\n problems.push(\n `obligation '${obligation.id}' applies to verdict '${verdict}' which no branch produces`,\n )\n }\n }\n }\n }\n\n if (spec.halt) {\n for (const gate of spec.halt.when.gates) {\n if (!gateNames.has(gate)) problems.push(`halt rule references unregistered gate '${gate}'`)\n }\n }\n\n for (const [name, selection] of Object.entries(spec.selections ?? {})) {\n if (selection.kind === 'filter-of') {\n if (!selectionNames.has(selection.base) && !sealedSubsetNames.has(selection.base)) {\n problems.push(\n `selection '${name}' filters unregistered base '${selection.base}' (not a selection or sealed subset)`,\n )\n }\n }\n }\n\n if (spec.admission) {\n const stageIds = new Set<string>()\n for (const stage of spec.admission.stages) {\n if (stageIds.has(stage.id)) problems.push(`duplicate admission stage id '${stage.id}'`)\n stageIds.add(stage.id)\n }\n for (const partition of spec.admission.partitions ?? []) {\n if (!stageIds.has(partition.from)) {\n problems.push(\n `admission partition '${partition.id}' draws from unknown stage '${partition.from}'`,\n )\n }\n }\n }\n\n if (problems.length > 0) {\n throw new ValidationError(`defineExperiment('${spec.id}'): ${problems.join('; ')}`)\n }\n return deepFreeze(structuredClone(spec))\n}\n\nfunction deepFreeze<T>(value: T): T {\n if (value !== null && typeof value === 'object') {\n for (const key of Object.keys(value as object)) {\n deepFreeze((value as Record<string, unknown>)[key])\n }\n Object.freeze(value)\n }\n return value\n}\n\n// ── Seal ─────────────────────────────────────────────────────────────\n\nexport interface SealAmendment {\n /** ISO8601 timestamp of the re-seal. */\n at: string\n reason: string\n /** Blindness attestations: what was verifiably unseen when the amendment was made. */\n blind: string[]\n /** Digest of the spec after this amendment. */\n digest: string\n}\n\n/**\n * Digest scheme of a sealed experiment. Both are sha256 hex over the\n * serialized spec and differ only in the serialization: `'sha256-rfc8785'` is\n * RFC 8785 canonical JSON, `'sha256-content'` is key-sorted `JSON.stringify`.\n */\nexport type SealAlgo = 'sha256-content' | 'sha256-rfc8785'\n\nexport interface SealedExperiment {\n spec: ExperimentSpec\n /** sha256 over the serialized spec, under the scheme `algo` names. */\n digest: string\n /**\n * Digest scheme of `digest`. `'sha256-rfc8785'` is what {@link sealExperiment}\n * emits; `'sha256-content'` is read-only, carried by seals from an earlier\n * release, and still verifies.\n */\n algo: SealAlgo\n sealedAt: string\n /** Digest of the original registration, before any amendment. */\n initialDigest: string\n amendments: SealAmendment[]\n}\n\n/** Validate, canonicalize, and hash a spec into its registration. */\nexport async function sealExperiment(\n spec: ExperimentSpec,\n options: { sealedAt?: string } = {},\n): Promise<SealedExperiment> {\n const validated = defineExperiment(spec)\n const digest = specDigest(validated, 'sha256-rfc8785')\n return {\n spec: validated,\n digest,\n algo: 'sha256-rfc8785',\n sealedAt: options.sealedAt ?? new Date().toISOString(),\n initialDigest: digest,\n amendments: [],\n }\n}\n\n/**\n * Amend a sealed experiment. The current seal is verified first, the new spec\n * is validated and re-hashed, and the amendment appends to the digest chain.\n * There is no way to change what is decided without producing a new digest.\n */\nexport async function amendExperiment(\n sealed: SealedExperiment,\n amendment: { spec: ExperimentSpec; reason: string; blind: string[]; at?: string },\n): Promise<SealedExperiment> {\n await assertSealIntact(sealed)\n const validated = defineExperiment(amendment.spec)\n const digest = specDigest(validated, 'sha256-rfc8785')\n return {\n spec: validated,\n digest,\n algo: 'sha256-rfc8785',\n sealedAt: sealed.sealedAt,\n initialDigest: sealed.initialDigest,\n amendments: [\n ...sealed.amendments,\n {\n at: amendment.at ?? new Date().toISOString(),\n reason: amendment.reason,\n blind: [...amendment.blind],\n digest,\n },\n ],\n }\n}\n\n/** True when the sealed digest still matches the spec it carries, under the\n * scheme the seal declares. */\nexport async function verifySealedExperiment(sealed: SealedExperiment): Promise<boolean> {\n return specDigest(sealed.spec, sealed.algo) === sealed.digest\n}\n\n/**\n * Serialize a spec under `algo` and digest it. `'sha256-content'` is read-only\n * — it exists so a seal written by an earlier release still verifies, and no\n * path that WRITES a digest may pass it.\n */\nfunction specDigest(spec: ExperimentSpec, algo: SealAlgo): string {\n const serialized =\n algo === 'sha256-rfc8785' ? canonicalString(spec) : JSON.stringify(sortKeysDeep(spec))\n return createHash('sha256').update(serialized, 'utf8').digest('hex')\n}\n\nfunction sortKeysDeep(value: unknown): unknown {\n if (value === null || typeof value !== 'object') return value\n if (Array.isArray(value)) return value.map(sortKeysDeep)\n const out: Record<string, unknown> = {}\n for (const key of Object.keys(value as Record<string, unknown>).sort()) {\n out[key] = sortKeysDeep((value as Record<string, unknown>)[key])\n }\n return out\n}\n\nasync function assertSealIntact(sealed: SealedExperiment): Promise<void> {\n if (!(await verifySealedExperiment(sealed))) {\n throw new SealIntegrityError(\n `sealed experiment '${sealed.spec.id}' digest ${sealed.digest} does not match its spec — the registration was tampered with`,\n )\n }\n}\n\n// ── Sealed execution ─────────────────────────────────────────────────\n\n/** Evidence a gate executor consumes, discriminated to match the gate kind. */\nexport type GateEvidence =\n | { kind: 'oracle-determinism'; repsByState: Record<string, readonly boolean[]> }\n | {\n kind: 'population-reproducibility'\n left: readonly EvidenceRecord[]\n right: readonly EvidenceRecord[]\n }\n | { kind: 'provenance-assertion'; provenance: EvidenceRecord }\n | { kind: 'identity'; pinned: string; served: string }\n | { kind: 'power-floor'; curve: readonly { effect: number; power: number }[] }\n\n/**\n * Executors bound to one verified seal. Every method reads its rule from the\n * sealed spec; evidence is the only argument anywhere.\n */\nexport interface RegisteredExperiment {\n readonly sealed: SealedExperiment\n /** Execute the registered decision rule on derived quantities. */\n decide(evidence: DerivedQuantities): DecisionOutcome\n /** Run the registered admission funnel over evidence rows. */\n admit(records: readonly EvidenceRecord[]): AdmissionExecution\n /** Run a registered selection rule. Filter-of bases resolve to sealed subsets. */\n select(name: string, records: readonly EvidenceRecord[], options: { idField: string }): string[]\n /** Evaluate a registered validity gate on evidence of the matching kind. */\n gate(name: string, evidence: GateEvidence): GateResult\n /** Evaluate the registered halt rule over gate results. */\n halt(gates: readonly GateResult[]): HaltOutcome\n /** Execute the registered uniform-pass budget schedule. */\n runUniformPassBudget(measuredPassCosts: readonly number[]): UniformPassSchedule\n /** Project the registered n-ladder budget. */\n projectNLadderBudget(measured: { unitCostUsd: number; rows: number }): NLadderProjection\n /** Verify realized arm budgets under the registered matched-budget rule. */\n matchedBudgets(arms: readonly ArmRealizedBudget[]): MatchedBudgetVerdict\n /** Compute a registered estimand over evidence rows. */\n estimate(name: string, rows: readonly EvidenceRecord[]): EstimandResult\n /** Compute a registered interval spec. */\n interval(\n name: string,\n evidence:\n | { kind: 'rows'; rows: readonly EvidenceRecord[]; value: string }\n | { kind: 'binomial'; successes: number; trials: number },\n ): ComputedInterval\n}\n\n/**\n * Verify the seal and return executors bound to it. This is the module's only\n * execution surface: a rule that is not in the sealed spec cannot run, and a\n * rule that is cannot run differently.\n */\nexport async function openSealedExperiment(\n sealed: SealedExperiment,\n): Promise<RegisteredExperiment> {\n await assertSealIntact(sealed)\n const spec = sealed.spec\n const need = <T>(value: T | undefined, what: string): T => {\n if (value === undefined) {\n throw new ValidationError(`experiment '${spec.id}' registered no ${what}`)\n }\n return value\n }\n return {\n sealed,\n decide: (evidence) => executeDecisionRule(spec.decision, evidence),\n admit: (records) => executeAdmissionRule(need(spec.admission, 'admission rule'), records),\n select: (name, records, options) => {\n const rule = need(spec.selections?.[name], `selection '${name}'`)\n return runSelectionRule(rule, records, {\n idField: options.idField,\n bases: spec.sealedSubsets,\n })\n },\n gate: (name, evidence) => {\n const gate = need(spec.gates?.[name], `gate '${name}'`)\n if (gate.kind !== evidence.kind) {\n throw new ValidationError(\n `gate '${name}' is registered as ${gate.kind} but received ${evidence.kind} evidence`,\n )\n }\n switch (gate.kind) {\n case 'oracle-determinism':\n return evaluateOracleDeterminismGate(\n name,\n gate,\n (evidence as Extract<GateEvidence, { kind: 'oracle-determinism' }>).repsByState,\n )\n case 'population-reproducibility': {\n const populations = evidence as Extract<\n GateEvidence,\n { kind: 'population-reproducibility' }\n >\n return evaluatePopulationReproducibilityGate(name, gate, populations)\n }\n case 'provenance-assertion':\n return evaluateProvenanceGate(\n name,\n gate,\n (evidence as Extract<GateEvidence, { kind: 'provenance-assertion' }>).provenance,\n )\n case 'identity':\n return evaluateIdentityGate(\n name,\n gate,\n evidence as Extract<GateEvidence, { kind: 'identity' }>,\n )\n case 'power-floor':\n return evaluatePowerFloorGate(\n name,\n gate,\n (evidence as Extract<GateEvidence, { kind: 'power-floor' }>).curve,\n )\n }\n },\n halt: (gates) => evaluateHaltRule(need(spec.halt, 'halt rule'), gates),\n runUniformPassBudget: (measuredPassCosts) => {\n const budget = need(spec.budget, 'budget rule')\n if (budget.kind !== 'uniform-pass') {\n throw new ValidationError(\n `experiment '${spec.id}' registered a ${budget.kind} budget, not uniform-pass`,\n )\n }\n return runUniformPassBudget(budget, measuredPassCosts)\n },\n projectNLadderBudget: (measured) => {\n const budget = need(spec.budget, 'budget rule')\n if (budget.kind !== 'n-ladder') {\n throw new ValidationError(\n `experiment '${spec.id}' registered a ${budget.kind} budget, not n-ladder`,\n )\n }\n return projectNLadderBudget(budget, measured)\n },\n matchedBudgets: (arms) =>\n verifyMatchedBudgets(need(spec.matchedBudget, 'matched-budget rule'), arms),\n estimate: (name, rows) =>\n computeEstimand(need(spec.estimands?.[name], `estimand '${name}'`), rows),\n interval: (name, evidence) =>\n computeInterval(need(spec.intervals?.[name], `interval '${name}'`), evidence),\n }\n}\n","/**\n * Reproducibility attestation for any serializable report object.\n *\n * `attest()` binds a report to its content address (sha-256 over canonical\n * JSON) AND binds that address to the provenance needed to reproduce it:\n * model versions, seeds, price-table hash, code SHA, inputs hash. The outer\n * `envelopeHash` prevents provenance from being rewritten while leaving the\n * report hash valid.\n *\n * Layering: content-addressing is the substrate's job; cryptographic SIGNING\n * (who vouches for the attestation, key management, transparency logs) is the\n * consumer's layer on top. An `AttestedReport` is a stable byte-identical\n * payload a consumer can sign — the substrate never holds keys.\n *\n * Generic by design: the report parameter is ANY value `canonicalJson`\n * accepts (campaign results, fuzz capsules, scorecards, cost ledgers). Do not\n * couple this module to a specific report schema.\n */\n\nimport { contentHash } from './verdict-cache'\n\n/** Hash scheme identifier carried by every attestation. A verifier rejects\n * unknown algorithms instead of guessing. */\nexport const ATTESTATION_ALGORITHM = 'sha256/canonical-json' as const\n\nexport interface AttestationProvenance {\n /** Every model involved in producing the report, name → version/id. */\n modelVersions: Record<string, string>\n /** RNG seeds the run was driven by, when seeded. */\n seeds?: number[]\n /** Content hash of the price table used for cost figures — cost numbers\n * are only reproducible against the same prices. */\n priceTableHash?: string\n /** Git SHA of the code that produced the report. */\n codeSha: string\n /** Content hash of the input set (scenarios, dataset manifest, ...). */\n inputsHash?: string\n /** ISO-8601 timestamp, caller-supplied — the substrate stays clock-free\n * so attestation is deterministic and testable. */\n createdAt: string\n}\n\nexport interface AttestedReport {\n /** Hex sha-256 over the canonical JSON of the report. */\n reportHash: string\n provenance: AttestationProvenance\n algorithm: typeof ATTESTATION_ALGORITHM\n /**\n * Hex sha-256 over `{ reportHash, provenance, algorithm }`. New attestations\n * always carry it. Optional only so persisted pre-envelope attestations can\n * still be read and explicitly recognized as legacy by callers.\n */\n envelopeHash?: string\n}\n\nexport interface AttestationVerification {\n valid: boolean\n /** Populated iff `valid` is false — names the exact mismatch. */\n reason?: string\n /** True only for a valid pre-envelope attestation whose provenance is not cryptographically bound. */\n legacyUnboundProvenance?: true\n}\n\nfunction envelopeMaterial(\n reportHash: string,\n provenance: AttestationProvenance,\n algorithm: typeof ATTESTATION_ALGORITHM,\n): object {\n return { reportHash, provenance, algorithm }\n}\n\n/**\n * Content-address a report and bind it to its provenance. Throws (via\n * `canonicalJson`) if the report or provenance contains undefined / function /\n * symbol / non-finite numbers — an attestation that cannot be unambiguously\n * serialized cannot be trusted.\n */\nexport function attest(report: unknown, provenance: AttestationProvenance): AttestedReport {\n const reportHash = contentHash(report)\n const algorithm = ATTESTATION_ALGORITHM\n return {\n reportHash,\n provenance,\n algorithm,\n envelopeHash: contentHash(envelopeMaterial(reportHash, provenance, algorithm)),\n }\n}\n\n/**\n * Verify a report against its attestation. Returns a typed outcome rather\n * than throwing: an unverifiable report (e.g. one that no longer\n * canonicalizes) is a verification failure with the cause in `reason`, not a\n * crash — verifiers run in pipelines that must record WHY, not die.\n *\n * Legacy attestations without `envelopeHash` remain readable, but verification\n * explicitly marks their provenance as unbound so a promotion path can refuse\n * them instead of accidentally treating old metadata as cryptographic proof.\n */\nexport function verifyAttestation(\n report: unknown,\n attested: AttestedReport,\n): AttestationVerification {\n if (attested.algorithm !== ATTESTATION_ALGORITHM) {\n return {\n valid: false,\n reason: `unknown algorithm '${attested.algorithm}' — this verifier only checks '${ATTESTATION_ALGORITHM}'`,\n }\n }\n let recomputed: string\n try {\n recomputed = contentHash(report)\n } catch (err) {\n return {\n valid: false,\n reason: `report is not canonicalizable: ${err instanceof Error ? err.message : String(err)}`,\n }\n }\n if (recomputed !== attested.reportHash) {\n return {\n valid: false,\n reason: `report hash mismatch: attested ${attested.reportHash}, recomputed ${recomputed}`,\n }\n }\n\n if (attested.envelopeHash === undefined) {\n return { valid: true, legacyUnboundProvenance: true }\n }\n\n let envelopeHash: string\n try {\n envelopeHash = contentHash(\n envelopeMaterial(attested.reportHash, attested.provenance, attested.algorithm),\n )\n } catch (err) {\n return {\n valid: false,\n reason: `attestation provenance is not canonicalizable: ${err instanceof Error ? err.message : String(err)}`,\n }\n }\n if (envelopeHash !== attested.envelopeHash) {\n return {\n valid: false,\n reason: `attestation envelope hash mismatch: attested ${attested.envelopeHash}, recomputed ${envelopeHash}`,\n }\n }\n\n return { valid: true }\n}\n","/**\n * Evidence receipts are the join between Runtime execution and Eval promotion.\n *\n * Runtime says what actually ran. Eval says what independently measured it.\n * This receipt binds those worlds without making either package import the other:\n * stable pursuit/run identity, exact candidate/evaluator/environment/input/output\n * content identities, and the authority class that produced the observation.\n *\n * The payload is attested with agent-eval's existing canonical report attestation.\n * Signing/key management deliberately remains outside this substrate; consumers may\n * sign the byte-stable receipt or anchor its attestation in a transparency log.\n */\n\nimport {\n type AttestationProvenance,\n type AttestedReport,\n attest,\n verifyAttestation,\n} from '../attestation'\n\nexport const EVIDENCE_RECEIPT_VERSION = '1.0.0' as const\n\n/** Closed promotion vocabulary. A typo or unknown future kind is never independent by default. */\nexport const EVIDENCE_AUTHORITY_KINDS = [\n 'candidate-self-report',\n 'independent-evaluator',\n 'independent-replication',\n 'human-review',\n 'production-canary',\n] as const\n\nexport type EvidenceAuthorityKind = (typeof EVIDENCE_AUTHORITY_KINDS)[number]\n\nexport const INDEPENDENT_EVIDENCE_AUTHORITY_KINDS = [\n 'independent-evaluator',\n 'independent-replication',\n 'human-review',\n 'production-canary',\n] as const satisfies readonly EvidenceAuthorityKind[]\n\nexport interface EvidenceAuthority {\n readonly kind: EvidenceAuthorityKind\n /** Stable authority/service/person identifier; never inferred from model prose. */\n readonly id: string\n}\n\nexport interface EvidenceBinding {\n readonly schemaVersion: typeof EVIDENCE_RECEIPT_VERSION\n /** Stable objective identity spanning retries, forks, resumes, and multiple runs. */\n readonly pursuitId: string\n /** Concrete execution/evaluation run this evidence was produced from. */\n readonly runId: string\n /** Exact candidate/program/profile bundle under evaluation. */\n readonly candidateDigest: string\n /** Exact evaluator/checker program or registered experiment definition. */\n readonly evaluatorDigest: string\n /** Exact sandbox/container/dependency/environment identity. */\n readonly environmentDigest: string\n /** Commitment to the input set. The hidden inputs themselves need not be exposed. */\n readonly inputSetCommitment: string\n /** Content identity of the raw evaluated output/artifact set. */\n readonly outputDigest: string\n /** Content identity of the evaluation result/report/verdict body. */\n readonly resultDigest: string\n readonly authority: EvidenceAuthority\n /** Optional experiment seal that governed the evaluation. */\n readonly experimentDigest?: string\n /** Optional observer-journal chain tip covering the execution being evaluated. */\n readonly observerDigest?: string\n}\n\nexport interface EvidenceReceipt {\n readonly binding: EvidenceBinding\n readonly attestation: AttestedReport\n}\n\nexport interface EvidenceReceiptVerification {\n readonly valid: boolean\n readonly reason?: string\n}\n\nexport interface CreateEvidenceReceiptInput extends Omit<EvidenceBinding, 'schemaVersion'> {}\n\n/**\n * Mint a content-attested evidence receipt. Required identity fields are deliberately\n * non-optional: unknown evidence stays unknown and cannot accidentally look certified.\n * The attestation's input provenance must equal the receipt commitment so two competing\n * descriptions of the evaluated population cannot coexist inside one valid receipt.\n */\nexport function createEvidenceReceipt(\n input: CreateEvidenceReceiptInput,\n provenance: AttestationProvenance,\n): EvidenceReceipt {\n const inputSetCommitment = requiredIdentity(input.inputSetCommitment, 'inputSetCommitment')\n assertInputCommitment(provenance, inputSetCommitment)\n const binding: EvidenceBinding = Object.freeze({\n schemaVersion: EVIDENCE_RECEIPT_VERSION,\n pursuitId: requiredIdentity(input.pursuitId, 'pursuitId'),\n runId: requiredIdentity(input.runId, 'runId'),\n candidateDigest: requiredIdentity(input.candidateDigest, 'candidateDigest'),\n evaluatorDigest: requiredIdentity(input.evaluatorDigest, 'evaluatorDigest'),\n environmentDigest: requiredIdentity(input.environmentDigest, 'environmentDigest'),\n inputSetCommitment,\n outputDigest: requiredIdentity(input.outputDigest, 'outputDigest'),\n resultDigest: requiredIdentity(input.resultDigest, 'resultDigest'),\n authority: requiredAuthority(input.authority),\n ...(input.experimentDigest === undefined\n ? {}\n : { experimentDigest: requiredIdentity(input.experimentDigest, 'experimentDigest') }),\n ...(input.observerDigest === undefined\n ? {}\n : { observerDigest: requiredIdentity(input.observerDigest, 'observerDigest') }),\n })\n return Object.freeze({ binding, attestation: attest(binding, provenance) })\n}\n\n/**\n * Verify promotion-grade evidence. Generic report attestation keeps a legacy read path,\n * but an EvidenceReceipt never accepts unbound provenance: changing the evaluator code,\n * model versions, input commitment provenance, or creation record must invalidate the\n * evidence rather than merely annotating it as legacy.\n */\nexport function verifyEvidenceReceipt(receipt: EvidenceReceipt): EvidenceReceiptVerification {\n if (receipt.binding.schemaVersion !== EVIDENCE_RECEIPT_VERSION) {\n return {\n valid: false,\n reason: `unsupported evidence receipt version '${receipt.binding.schemaVersion}'`,\n }\n }\n try {\n for (const [field, value] of Object.entries({\n pursuitId: receipt.binding.pursuitId,\n runId: receipt.binding.runId,\n candidateDigest: receipt.binding.candidateDigest,\n evaluatorDigest: receipt.binding.evaluatorDigest,\n environmentDigest: receipt.binding.environmentDigest,\n inputSetCommitment: receipt.binding.inputSetCommitment,\n outputDigest: receipt.binding.outputDigest,\n resultDigest: receipt.binding.resultDigest,\n })) {\n requiredIdentity(value, field)\n }\n requiredAuthority(receipt.binding.authority)\n assertInputCommitment(receipt.attestation.provenance, receipt.binding.inputSetCommitment)\n } catch (error) {\n return { valid: false, reason: error instanceof Error ? error.message : String(error) }\n }\n\n const verification = verifyAttestation(receipt.binding, receipt.attestation)\n if (!verification.valid) return verification\n if (\n verification.legacyUnboundProvenance === true ||\n receipt.attestation.envelopeHash === undefined\n ) {\n return {\n valid: false,\n reason: 'evidence receipt provenance is not bound by an attestation envelope',\n }\n }\n return { valid: true }\n}\n\n/**\n * Promotion may choose a stricter policy, but this primitive makes the basic separation\n * explicit: only a recognized independent authority is independent. Unknown/forged kinds\n * and candidate self-reports both return false.\n */\nexport function isIndependentEvidence(receipt: EvidenceReceipt): boolean {\n return (INDEPENDENT_EVIDENCE_AUTHORITY_KINDS as readonly string[]).includes(\n receipt.binding.authority?.kind,\n )\n}\n\nfunction requiredAuthority(value: unknown): EvidenceAuthority {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n throw new TypeError('evidence receipt: authority must be an object')\n }\n const authority = value as { kind?: unknown; id?: unknown }\n if (\n typeof authority.kind !== 'string' ||\n !(EVIDENCE_AUTHORITY_KINDS as readonly string[]).includes(authority.kind)\n ) {\n throw new TypeError(`evidence receipt: unknown authority kind '${String(authority.kind)}'`)\n }\n if (typeof authority.id !== 'string') {\n throw new TypeError('evidence receipt: authority.id must be a string')\n }\n return Object.freeze({\n kind: authority.kind as EvidenceAuthorityKind,\n id: requiredIdentity(authority.id, 'authority.id'),\n })\n}\n\nfunction assertInputCommitment(\n provenance: AttestationProvenance,\n inputSetCommitment: string,\n): void {\n if (typeof provenance?.inputsHash !== 'string' || provenance.inputsHash.trim().length === 0) {\n throw new TypeError('evidence receipt: provenance.inputsHash is required')\n }\n if (provenance.inputsHash.trim() !== inputSetCommitment) {\n throw new TypeError(\n 'evidence receipt: provenance.inputsHash must equal binding.inputSetCommitment',\n )\n }\n}\n\nfunction requiredIdentity(value: string, field: string): string {\n const normalized = value.trim()\n if (normalized.length === 0) throw new TypeError(`evidence receipt: ${field} must be non-empty`)\n return normalized\n}\n","/**\n * The evidence registry record — the canonical, machine-readable unit for a\n * measured claim about an agent, a prompt, a policy, or an instrument.\n *\n * One record answers, in typed fields, the questions a scattered results doc\n * leaves to prose: what was claimed, what instrument measured it, the exact\n * command that reproduces it, which arms ran, the denominator, what it cost,\n * what confounds the comparison, and how much trust the evidence has earned.\n *\n * Records live as JSON files in `evidence/records/` at the repo root — one\n * file per claim, filename `<id>.json`. The registry lives in agent-eval\n * because the measurement substrate owns evidence legitimacy; every other\n * repo keeps at most a pointer file. `scripts/render-evidence-index.ts`\n * generates the human index from these records, so prose can never drift\n * from data, and `pnpm run evidence:check` (part of `verify:package`) fails\n * on an invalid record or a stale index.\n *\n * The shape extends the `.evolve/experiments.jsonl` session-log vocabulary\n * (ts/hypothesis/change/result/evidence) into a curated registry record.\n * Session logs stay append-only diaries; a registry record is the durable,\n * addressable claim distilled from them.\n */\n\nimport { z } from 'zod'\n\n/**\n * Trust ladder for a recorded claim, strongest first.\n *\n * - `CERTIFIED` — pre-registered rule, sealed or held-out data, and either a\n * defended challenge or a check that re-runs in the suite.\n * - `MEASURED-ONCE` — one honest measurement on the real path, not replicated.\n * - `RESOLVED-NULL` — measured with an adequate instrument; the effect did not\n * appear under the registered rule. A null is a result, not a failure.\n * - `UNVERIFIED` — stated somewhere load-bearing, but no independent check has\n * run. Admitting this state is what keeps folklore out of the other four.\n * - `KILLED` — refuted, invalidated, or superseded by a stronger record.\n */\nexport const EVIDENCE_STATES = [\n 'CERTIFIED',\n 'MEASURED-ONCE',\n 'RESOLVED-NULL',\n 'UNVERIFIED',\n 'KILLED',\n] as const\n\nexport type EvidenceState = (typeof EVIDENCE_STATES)[number]\n\nconst idPattern = /^[a-z0-9]+(?:-[a-z0-9]+)*$/\nconst datePattern = /^\\d{4}-\\d{2}-\\d{2}$/\nconst sha256Pattern = /^[0-9a-f]{64}$/\n\n/** Denominator of the measurement. A claim without an `n` is prose, not evidence. */\nconst evidenceDenominatorSchema = z.strictObject({\n value: z.number().positive().finite(),\n /** What one unit is: rows, cases, rollouts, records, leaves… */\n unit: z.string().min(1),\n /** Clustering, reps, split names — whatever the bare number hides. */\n detail: z.string().min(1).optional(),\n})\n\nexport type EvidenceDenominator = z.infer<typeof evidenceDenominatorSchema>\n\nexport const evidenceRegistryRecordSchema = z.strictObject({\n /** Stable kebab-case identity; the registry filename is `<id>.json`. */\n id: z.string().regex(idPattern),\n /** Date the decisive measurement completed, `YYYY-MM-DD`. */\n date: z.string().regex(datePattern),\n /** The one-sentence load-bearing claim, stated so it can fail. */\n claim: z.string().min(1),\n /** Domain the claim lives in: trace-repair, multishot, analyst, vertical-bench… */\n domain: z.string().min(1),\n /** The instrument that produced the number — script, harness, oracle, judge. */\n instrument: z.string().min(1),\n /**\n * The exact invocation that reproduces the measurement.\n * `null` means the invocation was not preserved — a named gap, never a guess.\n */\n command: z.string().min(1).nullable(),\n /** Compared arms. Empty for a single-arm measurement. */\n arms: z.array(z.string().min(1)),\n n: evidenceDenominatorSchema,\n /** The measured numbers, with uncertainty when it exists. Numbers, not adjectives. */\n result: z.string().min(1),\n evidenceState: z.enum(EVIDENCE_STATES),\n /** Where the raw data lives: repo paths, PR/gist URLs, run directories. Never empty. */\n artifacts: z.array(z.string().min(1)).min(1),\n /**\n * Measured spend in USD. `0` is a true zero (deterministic, no paid calls);\n * `null` means spend was not captured — a named gap, never a silent zero.\n */\n costUsd: z.number().nonnegative().nullable(),\n /** Every known asymmetry or threat to validity. Empty only when none is known. */\n confounds: z.array(z.string().min(1)),\n /** Repo whose work produced the evidence (the registry itself lives here). */\n sourceRepo: z.string().min(1),\n /** Seal digest of the registered experiment (`./experiment`), when one governed the run. */\n experimentDigest: z.string().regex(sha256Pattern).optional(),\n /** Ids of records this one supersedes. */\n supersedes: z.array(z.string().regex(idPattern)).optional(),\n notes: z.string().min(1).optional(),\n})\n\nexport type EvidenceRegistryRecord = z.infer<typeof evidenceRegistryRecordSchema>\n\n/** Parse one record; throws with the zod issue list on any violation. */\nexport function parseEvidenceRegistryRecord(raw: unknown): EvidenceRegistryRecord {\n return evidenceRegistryRecordSchema.parse(raw)\n}\n\nclass EvidenceRegistryError extends Error {}\n\n/**\n * Validate a set of records as one registry: every record parses, ids are\n * unique, and every `supersedes` target exists. Returns records sorted in\n * the registry's canonical order (trust ladder, then date desc, then id).\n */\nexport function validateEvidenceRegistry(raws: readonly unknown[]): EvidenceRegistryRecord[] {\n const records = raws.map((raw) => parseEvidenceRegistryRecord(raw))\n const seen = new Set<string>()\n for (const record of records) {\n if (seen.has(record.id)) {\n throw new EvidenceRegistryError(`duplicate evidence record id: ${record.id}`)\n }\n seen.add(record.id)\n }\n for (const record of records) {\n for (const target of record.supersedes ?? []) {\n if (!seen.has(target)) {\n throw new EvidenceRegistryError(`record ${record.id} supersedes unknown record: ${target}`)\n }\n }\n }\n const stateRank = new Map(EVIDENCE_STATES.map((state, index) => [state, index]))\n return [...records].sort((a, b) => {\n const byState = (stateRank.get(a.evidenceState) ?? 0) - (stateRank.get(b.evidenceState) ?? 0)\n if (byState !== 0) return byState\n if (a.date !== b.date) return a.date < b.date ? 1 : -1\n return a.id < b.id ? -1 : 1\n })\n}\n\nfunction mdEscape(text: string): string {\n return text.replace(/\\|/g, '\\\\|').replace(/\\n/g, ' ')\n}\n\nfunction formatCost(costUsd: number | null): string {\n if (costUsd === null) return 'not captured'\n return `$${costUsd.toFixed(2)}`\n}\n\nfunction formatN(n: EvidenceDenominator): string {\n const base = `${n.value} ${n.unit}`\n return n.detail ? `${base} (${n.detail})` : base\n}\n\n/**\n * Render the registry's human index from records. Deterministic: identical\n * records always produce identical output, so a byte diff against the\n * committed index is the freshness check. No clocks, no environment.\n */\nexport function renderEvidenceIndex(raws: readonly unknown[]): string {\n const records = validateEvidenceRegistry(raws)\n const lines: string[] = [\n '# Evidence index',\n '',\n '<!-- GENERATED by scripts/render-evidence-index.ts from evidence/records/*.json.',\n ' Edit the records, run `pnpm run evidence:render`, and commit both.',\n ' `pnpm run evidence:check` (inside verify:package) fails when this file drifts. -->',\n '',\n `${records.length} records. States: ${EVIDENCE_STATES.join(' > ')}.`,\n '',\n '| state | date | id | claim | result |',\n '| --- | --- | --- | --- | --- |',\n ]\n for (const r of records) {\n lines.push(\n `| ${r.evidenceState} | ${r.date} | [\\`${r.id}\\`](#${r.id}) | ${mdEscape(r.claim)} | ${mdEscape(r.result)} |`,\n )\n }\n for (const r of records) {\n lines.push('', `## ${r.id}`, '')\n lines.push(`**${r.evidenceState}** · ${r.date} · ${r.domain} · source repo \\`${r.sourceRepo}\\``)\n lines.push('', `**Claim.** ${r.claim}`, '', `**Result.** ${r.result}`, '')\n lines.push(`- **Instrument**: ${r.instrument}`)\n lines.push(`- **Command**: ${r.command === null ? 'not preserved' : `\\`${r.command}\\``}`)\n lines.push(`- **Arms**: ${r.arms.length === 0 ? 'single-arm' : r.arms.join(' vs ')}`)\n lines.push(`- **n**: ${formatN(r.n)}`)\n lines.push(`- **Cost**: ${formatCost(r.costUsd)}`)\n if (r.experimentDigest) lines.push(`- **Experiment seal**: \\`${r.experimentDigest}\\``)\n lines.push(`- **Artifacts**:`)\n for (const artifact of r.artifacts) lines.push(` - ${artifact}`)\n if (r.confounds.length === 0) {\n lines.push('- **Confounds**: none recorded')\n } else {\n lines.push('- **Confounds**:')\n for (const confound of r.confounds) lines.push(` - ${confound}`)\n }\n if (r.supersedes && r.supersedes.length > 0) {\n lines.push(`- **Supersedes**: ${r.supersedes.map((s) => `\\`${s}\\``).join(', ')}`)\n }\n if (r.notes) lines.push(`- **Notes**: ${r.notes}`)\n }\n lines.push('')\n return lines.join('\\n')\n}\n","/**\n * Design-time power for task-clustered paired designs, with a refusal verdict.\n *\n * The failure this prevents (measured): a pre-registered kill test fixed a\n * task-clustered bootstrap over 14 rows in 4 task clusters. Simulated at the\n * registered seed, the design's power topped out at 0.69 — at a per-row\n * effect of 1.0. \"Four clusters cannot certify any effect size, including\n * 1.0\" was learned by running the experiment; this module computes it before\n * a dollar is spent.\n *\n * Two floors, one simulation:\n * - Closed form, zero spend: with C independent clusters the exact\n * whole-cluster sign-flip test can never produce a two-sided p below\n * 2^(1-C). C=4 gives 0.125; C=3 gives 0.25 — both above a 0.05 alpha, so\n * those designs are refused at ANY effect size, before simulation.\n * - Seeded simulation: per-row paired contrasts drawn under a registered\n * effect model, a whole-cluster percentile bootstrap on each trial, power =\n * the fraction of trials whose interval excludes zero.\n *\n * The refusal is a verdict INSIDE the returned artifact (the powerPreflight\n * shape, made cluster-aware); `assertDesignAdequate` turns it into a throw for\n * callers that want configuration-time failure.\n */\n\nimport { ValidationError } from '../errors'\nimport { mulberry32 } from '../statistics'\n\n/** A design refused at configuration time, before any spend. */\nexport class DesignRefusalError extends ValidationError {}\n\nexport interface ClusteredPowerOptions {\n /** Rows per independent cluster, e.g. [6, 3, 3, 2]. */\n clusterSizes: number[]\n /** Per-row effect grid: each effect is P(win) - P(loss) added to the base rates. */\n effects: number[]\n /** Deterministic seed for outcome draws and bootstrap resampling. */\n seed: number\n /** Simulated experiments per effect. Default 2000. */\n trials?: number\n /** Whole-cluster bootstrap draws per trial. Default 4000. */\n resamples?: number\n /** Percentile interval level. Default 0.95. */\n confidence?: number\n /** Sign-flip alpha the closed-form floor is checked against. Default 0.05. */\n alpha?: number\n /** Power the design must reach at some grid effect. Default 0.8. */\n targetPower?: number\n /** Base P(row favors treatment) with no effect. Default 0.10 (tie-heavy rows). */\n baseWinRate?: number\n /** Base P(row favors control). Default 0.10. */\n baseLossRate?: number\n /**\n * Clusters whose rows carry outcome noise instead of signal: each row wins\n * with `flipRate` and loses with `flipRate`, independent of the effect.\n * Index into `clusterSizes`.\n */\n noisyClusters?: { index: number; flipRate: number }[]\n}\n\nexport interface ClusteredPowerPoint {\n effect: number\n power: number\n medianCiWidth: number\n}\n\nexport interface SignFlipFloor {\n /** Smallest achievable two-sided p: 2^(1-C) for C clusters. */\n twoSidedP: number\n /** Smallest achievable one-sided p: 2^-C. */\n oneSidedP: number\n alpha: number\n /** False when the cluster count can never certify at `alpha`, at any effect. */\n certifiableAtAlpha: boolean\n /** Smallest cluster count whose two-sided floor is at or under `alpha`. */\n minClustersForAlpha: number\n}\n\nexport interface ClusteredPowerRefusal {\n verdict: 'underpowered'\n reasons: string[]\n recommendation: string\n}\n\nexport interface ClusteredPowerResult {\n clusterCount: number\n totalRows: number\n trials: number\n resamples: number\n seed: number\n confidence: number\n targetPower: number\n curve: ClusteredPowerPoint[]\n /** Maximum simulated power across the effect grid. */\n maxPower: number\n signFlipFloor: SignFlipFloor\n /** True only when the sign-flip floor certifies AND simulation reaches target. */\n adequate: boolean\n /** Populated exactly when `adequate` is false. The refusal lives in the artifact. */\n refusal: ClusteredPowerRefusal | null\n}\n\n/**\n * Simulate the power of a whole-cluster percentile-bootstrap design and refuse\n * a structure that cannot reach the target at any registered effect.\n */\nexport function clusteredPower(options: ClusteredPowerOptions): ClusteredPowerResult {\n const clusterSizes = options.clusterSizes\n if (clusterSizes.length === 0 || clusterSizes.some((n) => !Number.isInteger(n) || n <= 0)) {\n throw new ValidationError(\n `clusteredPower: clusterSizes must be positive integers, got [${clusterSizes.join(', ')}]`,\n )\n }\n if (options.effects.length === 0) {\n throw new ValidationError('clusteredPower: effects grid is empty')\n }\n if (!Number.isInteger(options.seed)) {\n throw new ValidationError(`clusteredPower: seed must be an integer, got ${options.seed}`)\n }\n const trials = options.trials ?? 2000\n const resamples = options.resamples ?? 4000\n if (!Number.isInteger(trials) || trials <= 0 || !Number.isInteger(resamples) || resamples <= 0) {\n throw new ValidationError(\n `clusteredPower: trials and resamples must be positive integers, got ${trials}/${resamples}`,\n )\n }\n const confidence = options.confidence ?? 0.95\n if (confidence <= 0 || confidence >= 1) {\n throw new ValidationError(`clusteredPower: confidence must be in (0,1), got ${confidence}`)\n }\n const alpha = options.alpha ?? 0.05\n const targetPower = options.targetPower ?? 0.8\n const baseWinRate = options.baseWinRate ?? 0.1\n const baseLossRate = options.baseLossRate ?? 0.1\n const noisy = new Map<number, number>()\n for (const cluster of options.noisyClusters ?? []) {\n if (cluster.index < 0 || cluster.index >= clusterSizes.length) {\n throw new ValidationError(\n `clusteredPower: noisy cluster index ${cluster.index} outside [0,${clusterSizes.length - 1}]`,\n )\n }\n noisy.set(cluster.index, cluster.flipRate)\n }\n\n const clusterCount = clusterSizes.length\n const totalRows = clusterSizes.reduce((a, b) => a + b, 0)\n const signFlipFloor = computeSignFlipFloor(clusterCount, alpha)\n\n const curve: ClusteredPowerPoint[] = []\n for (const effect of options.effects) {\n curve.push(\n simulateEffect(effect, {\n clusterSizes,\n seed: options.seed,\n trials,\n resamples,\n confidence,\n baseWinRate,\n baseLossRate,\n noisy,\n }),\n )\n }\n const maxPower = Math.max(...curve.map((point) => point.power))\n\n const reasons: string[] = []\n if (!signFlipFloor.certifiableAtAlpha) {\n reasons.push(\n `${clusterCount} clusters cannot certify any effect size, including 1.0: the exact ` +\n `whole-cluster sign-flip test's smallest two-sided p is 2^(1-${clusterCount}) = ` +\n `${signFlipFloor.twoSidedP} > alpha ${alpha}; at least ` +\n `${signFlipFloor.minClustersForAlpha} clusters are needed`,\n )\n }\n if (maxPower < targetPower) {\n const best = curve.reduce((a, b) => (b.power > a.power ? b : a))\n reasons.push(\n `simulated power tops out at ${maxPower.toFixed(3)} (effect ${best.effect}) across the ` +\n `registered grid — below the ${targetPower} target at every effect`,\n )\n }\n const adequate = reasons.length === 0\n return {\n clusterCount,\n totalRows,\n trials,\n resamples,\n seed: options.seed,\n confidence,\n targetPower,\n curve,\n maxPower,\n signFlipFloor,\n adequate,\n refusal: adequate\n ? null\n : {\n verdict: 'underpowered',\n reasons,\n recommendation:\n `Do not spend on this structure. Add independent clusters (>= ` +\n `${Math.max(signFlipFloor.minClustersForAlpha, clusterCount)}) or register a design ` +\n `whose simulated power reaches ${targetPower}, then re-run clusteredPower.`,\n },\n }\n}\n\n/** Throw the refusal for callers that want configuration-time failure. */\nexport function assertDesignAdequate(result: ClusteredPowerResult): void {\n if (result.refusal) {\n throw new DesignRefusalError(\n `design refused (underpowered): ${result.refusal.reasons.join('; ')}`,\n )\n }\n}\n\nfunction computeSignFlipFloor(clusterCount: number, alpha: number): SignFlipFloor {\n const twoSidedP = 2 ** (1 - clusterCount)\n const oneSidedP = 2 ** -clusterCount\n let minClusters = 1\n while (2 ** (1 - minClusters) > alpha) minClusters += 1\n return {\n twoSidedP,\n oneSidedP,\n alpha,\n certifiableAtAlpha: twoSidedP <= alpha,\n minClustersForAlpha: minClusters,\n }\n}\n\ninterface SimulationConfig {\n clusterSizes: number[]\n seed: number\n trials: number\n resamples: number\n confidence: number\n baseWinRate: number\n baseLossRate: number\n noisy: Map<number, number>\n}\n\n/**\n * One effect point. Per row the paired contrast is +1 with probability\n * min(baseWin + effect, 1), -1 with the base loss rate (capped by what\n * remains), else 0. Noisy clusters draw win and loss independently at their\n * flip rate. Each trial computes a whole-cluster percentile bootstrap of the\n * pooled row mean; the trial counts toward power when the interval excludes\n * zero.\n */\nfunction simulateEffect(effect: number, config: SimulationConfig): ClusteredPowerPoint {\n const rng = mulberry32(mixSeed(config.seed, effect))\n const clusterCount = config.clusterSizes.length\n let excludes = 0\n const widths = new Array<number>(config.trials)\n const sums = new Array<number>(clusterCount)\n const means = new Array<number>(config.resamples)\n for (let trial = 0; trial < config.trials; trial++) {\n for (let cluster = 0; cluster < clusterCount; cluster++) {\n const size = config.clusterSizes[cluster]!\n const flipRate = config.noisy.get(cluster)\n let sum = 0\n for (let row = 0; row < size; row++) {\n if (flipRate !== undefined) {\n const win = rng() < flipRate ? 1 : 0\n const loss = rng() < flipRate ? 1 : 0\n sum += win - loss\n } else {\n const winRate = Math.min(1, config.baseWinRate + effect)\n const lossRate = Math.min(1 - winRate, config.baseLossRate)\n const u = rng()\n sum += u < winRate ? 1 : u < winRate + lossRate ? -1 : 0\n }\n }\n sums[cluster] = sum\n }\n for (let draw = 0; draw < config.resamples; draw++) {\n let pooledSum = 0\n let pooledRows = 0\n for (let pick = 0; pick < clusterCount; pick++) {\n const index = Math.floor(rng() * clusterCount)\n pooledSum += sums[index]!\n pooledRows += config.clusterSizes[index]!\n }\n means[draw] = pooledSum / pooledRows\n }\n means.sort((a, b) => a - b)\n const tail = 1 - config.confidence\n const lower = means[Math.floor((tail / 2) * config.resamples)]!\n const upper =\n means[\n Math.max(\n Math.floor((tail / 2) * config.resamples),\n Math.min(config.resamples - 1, Math.ceil((1 - tail / 2) * config.resamples) - 1),\n )\n ]!\n widths[trial] = upper - lower\n if (lower > 0 || upper < 0) excludes += 1\n }\n widths.sort((a, b) => a - b)\n return {\n effect,\n power: excludes / config.trials,\n medianCiWidth: widths[Math.floor(config.trials / 2)]!,\n }\n}\n\n/** Fold the effect into the seed so every grid point draws an independent stream. */\nfunction mixSeed(seed: number, effect: number): number {\n const scaled = Math.round(effect * 1_000_003)\n return ((seed ^ (scaled * 0x9e3779b9)) >>> 0) | 0\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["populations"],"sources":["../../src/experiment/ast.ts","../../src/experiment/budget.ts","../../src/experiment/funnel.ts","../../src/experiment/define.ts","../../src/experiment/evidence-receipt.ts","../../src/experiment/evidence-record.ts","../../src/experiment/power.ts"],"sourcesContent":["/**\n * The registered-rule AST: every rule an experiment registers is DATA.\n *\n * A closure cannot be canonicalized or hashed; a node tree can. `sealExperiment`\n * hashes the whole tree, and every interpreter in this file takes only a node\n * plus evidence records — no parameter for alpha, threshold, metric, or\n * stopping rule exists on any executable surface. The registered object and\n * the executed object are therefore the same object, and registered-vs-ran\n * drift is unrepresentable rather than checked.\n *\n * Node families:\n * Predicate closed-key comparisons — the only leaf\n * AdmissionRule monotone funnel stages with registered waivers\n * SelectionRule deterministic subsets over a closed field set\n * Estimand what the experiment measures\n * IntervalSpec how uncertainty is computed, seed included\n * Condition decision guards over named derived quantities\n * DecisionRule ordered verdict table, or a registered absence of one\n * Obligation a control that must exist before a verdict class is read\n * ValidityGate pre-spend design checks\n * HaltRule gates as prerequisites — failure refuses the spend\n * BudgetRule spend schedules with a named ledger\n * MatchedBudgetRule arm budget matching as a refusal\n * ReissuePolicy carrier faults are reissued; model outcomes stand\n */\n\nimport { ValidationError } from '../errors'\nimport { mulberry32 } from '../statistics'\n\n/** JSON-serializable value — everything a sealed node may carry. */\nexport type JsonValue = string | number | boolean | null | JsonValue[] | { [k: string]: JsonValue }\n\n/** Evidence row shape. Fields are addressed by dot-separated paths. */\nexport type EvidenceRecord = Record<string, unknown>\n\n/** A decision rule's branches did not cover the evidence. */\nclass DecisionTableNotTotalError extends ValidationError {}\n\n// ── Predicate ────────────────────────────────────────────────────────\n\n/**\n * Closed-key comparison over a declared record schema. The only leaf node.\n * `field` is a dot-separated path into an evidence record.\n */\nexport type Predicate =\n | {\n kind: 'compare'\n field: string\n op: 'eq' | 'ne' | 'lt' | 'lte' | 'gt' | 'gte'\n value: JsonValue\n }\n | { kind: 'in'; field: string; values: JsonValue[] }\n | { kind: 'all'; of: Predicate[] }\n | { kind: 'any'; of: Predicate[] }\n | { kind: 'not'; of: Predicate }\n\n/** Read a dot-separated field path. Missing segments yield `undefined`. */\nexport function readField(record: EvidenceRecord, path: string): unknown {\n let current: unknown = record\n for (const key of path.split('.')) {\n if (current === null || typeof current !== 'object') return undefined\n current = (current as Record<string, unknown>)[key]\n }\n return current\n}\n\n/** Evaluate a predicate against one evidence record. */\nexport function evaluatePredicate(predicate: Predicate, record: EvidenceRecord): boolean {\n switch (predicate.kind) {\n case 'compare':\n return compareValues(readField(record, predicate.field), predicate.op, predicate.value)\n case 'in':\n return predicate.values.includes(readField(record, predicate.field) as JsonValue)\n case 'all':\n return predicate.of.every((p) => evaluatePredicate(p, record))\n case 'any':\n return predicate.of.some((p) => evaluatePredicate(p, record))\n case 'not':\n return !evaluatePredicate(predicate.of, record)\n }\n}\n\n/** Numbers compare numerically; everything else compares as strings. */\nfunction compareValues(\n value: unknown,\n op: 'eq' | 'ne' | 'lt' | 'lte' | 'gt' | 'gte',\n target: JsonValue,\n): boolean {\n if (op === 'eq') return value === target\n if (op === 'ne') return value !== target\n const numeric = typeof value === 'number' && typeof target === 'number'\n const left = numeric ? (value as number) : String(value)\n const right = numeric ? (target as number) : String(target)\n switch (op) {\n case 'lt':\n return left < right\n case 'lte':\n return left <= right\n case 'gt':\n return left > right\n case 'gte':\n return left >= right\n }\n}\n\n// ── Admission ────────────────────────────────────────────────────────\n\n/**\n * One monotone funnel stage. `waives` names substrate admission conditions\n * deliberately NOT applied, so a waiver is registered, never implicit.\n */\nexport interface AdmissionStage {\n id: string\n keep: Predicate\n waives?: string[]\n}\n\n/** A partition is a set reported separately and never pooled. */\nexport interface AdmissionPartition {\n id: string\n /** Stage whose dropped rows this partition draws from. */\n from: string\n keep: Predicate\n pooling: 'never'\n}\n\n/** Declarative row-admission funnel. Stages only remove rows. */\nexport interface AdmissionRule {\n population: string\n stages: AdmissionStage[]\n partitions?: AdmissionPartition[]\n}\n\n// ── Selection ────────────────────────────────────────────────────────\n\n/**\n * Deterministic subset selection. `reads` is the closed field set the rule\n * may touch — outcome-contaminated selection is unrepresentable because an\n * outcome field is simply not in the list.\n */\nexport type SelectionRule =\n | {\n kind: 'round-robin'\n groupBy: string\n groupOrder: 'lex-asc'\n withinOrder: { field: string; dir: 'asc' | 'desc' }\n take: number\n reads: string[]\n }\n | {\n kind: 'filter-of'\n /** Name of the sealed subset or selection this rule filters. */\n base: string\n keep: Predicate\n order: { field: string; dir: 'asc' | 'desc' }\n }\n\n/**\n * Execute a selection rule.\n *\n * Round-robin walks groups in lexicographic order and takes ids in\n * within-group order until `take` ids are chosen. Filter-of keeps the ids of\n * `bases[rule.base]` whose record satisfies the predicate, in the registered\n * order. Ids absent from `records` are evaluated on their id alone (fields\n * derived from the id via `idFields`), so a sealed base outlives its source\n * records.\n */\nexport function runSelectionRule(\n rule: SelectionRule,\n records: readonly EvidenceRecord[],\n options: {\n /** Field carrying a row's identity. */\n idField: string\n /** Sealed or previously-computed subsets, by name. */\n bases?: Record<string, readonly string[]>\n /** Derive predicate-readable fields from a bare id when its record is absent. */\n idFields?: (id: string) => EvidenceRecord\n },\n): string[] {\n if (rule.kind === 'round-robin') {\n const allowed = new Set(rule.reads)\n for (const field of [rule.groupBy, rule.withinOrder.field]) {\n if (!allowed.has(field)) {\n throw new ValidationError(\n `runSelectionRule: round-robin reads '${field}' but its closed read set is [${rule.reads.join(', ')}]`,\n )\n }\n }\n const byGroup = new Map<string, string[]>()\n for (const record of records) {\n const group = String(readField(record, rule.groupBy))\n const id = String(readField(record, rule.withinOrder.field))\n const bucket = byGroup.get(group)\n if (bucket) bucket.push(id)\n else byGroup.set(group, [id])\n }\n for (const ids of byGroup.values()) {\n ids.sort()\n if (rule.withinOrder.dir === 'desc') ids.reverse()\n }\n const groups = [...byGroup.keys()].sort()\n const chosen: string[] = []\n let cursor = 0\n while (chosen.length < rule.take && groups.some((g) => byGroup.get(g)!.length > 0)) {\n const group = groups[cursor % groups.length]!\n const ids = byGroup.get(group)!\n if (ids.length > 0) chosen.push(ids.shift()!)\n cursor += 1\n }\n return chosen\n }\n\n const base = options.bases?.[rule.base]\n if (!base) {\n throw new ValidationError(`runSelectionRule: filter-of base '${rule.base}' was not provided`)\n }\n const index = new Map(records.map((r) => [String(readField(r, options.idField)), r]))\n const kept = base.filter((id) => {\n const record = index.get(id) ?? options.idFields?.(id)\n if (!record) {\n throw new ValidationError(\n `runSelectionRule: base id '${id}' has no record and no idFields derivation`,\n )\n }\n return evaluatePredicate(rule.keep, record)\n })\n const sorted = [...kept].sort()\n if (rule.order.dir === 'desc') sorted.reverse()\n return sorted\n}\n\n// ── Estimands ────────────────────────────────────────────────────────\n\n/** A named set of row identities, built from arm rows and an event predicate. */\nexport type SetExpr =\n | { kind: 'rows-where'; arm: string; event: Predicate }\n | { kind: 'intersect'; of: SetExpr[] }\n\n/**\n * What the experiment measures. Every estimand names the fields it reads, so\n * the sealed tree records the full data dependency of the number.\n */\nexport type Estimand =\n | { kind: 'rate'; event: Predicate; over: 'rollouts' }\n | { kind: 'rate-at-least-once'; event: Predicate; groupBy: string }\n | {\n kind: 'paired-mean-diff'\n armField: string\n treatment: string\n control: string\n pairBy: string\n /**\n * Field path to the per-row outcome. A boolean reads as 1 or 0, so a\n * binary pass/fail outcome gives the risk difference directly.\n */\n value: string\n /** A pair one arm did not answer contributes a difference of exactly zero. */\n missing: 'zero-diff'\n }\n | {\n kind: 'set-ratio'\n armField: string\n idField: string\n numerator: SetExpr\n denominator: SetExpr\n }\n\nexport interface EstimandResult {\n value: number\n numerator: number\n denominator: number\n}\n\nfunction evaluateSetExpr(\n expr: SetExpr,\n rows: readonly EvidenceRecord[],\n armField: string,\n idField: string,\n): Set<string> {\n if (expr.kind === 'rows-where') {\n const ids = new Set<string>()\n for (const row of rows) {\n if (String(readField(row, armField)) !== expr.arm) continue\n if (evaluatePredicate(expr.event, row)) ids.add(String(readField(row, idField)))\n }\n return ids\n }\n if (expr.of.length === 0) throw new ValidationError('computeEstimand: empty intersect')\n const sets = expr.of.map((e) => evaluateSetExpr(e, rows, armField, idField))\n const [first, ...rest] = sets\n const out = new Set<string>()\n for (const id of first!) {\n if (rest.every((s) => s.has(id))) out.add(id)\n }\n return out\n}\n\n/**\n * Read one registered outcome field as a number.\n *\n * A binary outcome reaches evidence as `true` or `false`. Its mean is the pass\n * rate and the mean of its paired differences is the risk difference, so\n * `true` reads as 1 and `false` as 0 — the same quantity a caller would\n * otherwise encode by hand, and the same reading in every interpreter here.\n * Every other type, and a non-finite number, is a measurement defect: it\n * rejects instead of poisoning the mean with `NaN` or a coerced zero.\n */\nfunction readNumericOutcome(raw: unknown, context: string, field: string, where: string): number {\n if (typeof raw === 'boolean') return raw ? 1 : 0\n if (typeof raw === 'number' && Number.isFinite(raw)) return raw\n throw new ValidationError(\n `${context}: value field '${field}' is not a finite number or a boolean on ${where}`,\n )\n}\n\n/** Compute an estimand over evidence rows. Pure; reads only registered fields. */\nexport function computeEstimand(\n estimand: Estimand,\n rows: readonly EvidenceRecord[],\n): EstimandResult {\n switch (estimand.kind) {\n case 'rate': {\n const numerator = rows.filter((r) => evaluatePredicate(estimand.event, r)).length\n if (rows.length === 0) throw new ValidationError('computeEstimand: rate over zero rows')\n return { value: numerator / rows.length, numerator, denominator: rows.length }\n }\n case 'rate-at-least-once': {\n const byGroup = new Map<string, boolean>()\n for (const row of rows) {\n const group = String(readField(row, estimand.groupBy))\n const hit = evaluatePredicate(estimand.event, row)\n byGroup.set(group, (byGroup.get(group) ?? false) || hit)\n }\n if (byGroup.size === 0) {\n throw new ValidationError('computeEstimand: rate-at-least-once over zero groups')\n }\n const numerator = [...byGroup.values()].filter(Boolean).length\n return { value: numerator / byGroup.size, numerator, denominator: byGroup.size }\n }\n case 'paired-mean-diff': {\n const byPair = new Map<string, { treatment?: number; control?: number }>()\n for (const row of rows) {\n const arm = String(readField(row, estimand.armField))\n if (arm !== estimand.treatment && arm !== estimand.control) continue\n const pair = String(readField(row, estimand.pairBy))\n const value = readNumericOutcome(\n readField(row, estimand.value),\n 'computeEstimand paired-mean-diff',\n estimand.value,\n `pair '${pair}'`,\n )\n const slot = byPair.get(pair) ?? {}\n if (arm === estimand.treatment) slot.treatment = value\n else slot.control = value\n byPair.set(pair, slot)\n }\n if (byPair.size === 0) {\n throw new ValidationError('computeEstimand: paired-mean-diff over zero pairs')\n }\n let sum = 0\n for (const slot of byPair.values()) {\n // missing: 'zero-diff' — an unanswered side contributes zero, never a drop\n sum += (slot.treatment ?? 0) - (slot.control ?? 0)\n }\n return { value: sum / byPair.size, numerator: sum, denominator: byPair.size }\n }\n case 'set-ratio': {\n const numeratorSet = evaluateSetExpr(\n estimand.numerator,\n rows,\n estimand.armField,\n estimand.idField,\n )\n const denominatorSet = evaluateSetExpr(\n estimand.denominator,\n rows,\n estimand.armField,\n estimand.idField,\n )\n if (denominatorSet.size === 0) {\n throw new ValidationError('computeEstimand: set-ratio denominator set is empty')\n }\n return {\n value: numeratorSet.size / denominatorSet.size,\n numerator: numeratorSet.size,\n denominator: denominatorSet.size,\n }\n }\n }\n}\n\n// ── Intervals ────────────────────────────────────────────────────────\n\n/** How uncertainty is computed. The seed is part of the registration. */\nexport type IntervalSpec =\n | {\n kind: 'cluster-bootstrap'\n clusterBy: string\n resamples: number\n seed: number\n level: number\n method: 'percentile'\n }\n | { kind: 'clopper-pearson'; level: number }\n\nexport interface ComputedInterval {\n lower: number\n upper: number\n level: number\n}\n\n/**\n * Execute an interval spec.\n *\n * Cluster-bootstrap resamples whole clusters of the per-row `value` field and\n * takes percentile bounds of the pooled mean. Clopper-Pearson computes the\n * exact binomial interval and requires `successes`/`trials` evidence instead\n * of rows.\n */\nexport function computeInterval(\n spec: IntervalSpec,\n evidence:\n | { kind: 'rows'; rows: readonly EvidenceRecord[]; value: string }\n | { kind: 'binomial'; successes: number; trials: number },\n): ComputedInterval {\n if (spec.kind === 'cluster-bootstrap') {\n if (evidence.kind !== 'rows') {\n throw new ValidationError('computeInterval: cluster-bootstrap requires row evidence')\n }\n const clusters = new Map<string, number[]>()\n for (const row of evidence.rows) {\n const cluster = String(readField(row, spec.clusterBy))\n const value = readNumericOutcome(\n readField(row, evidence.value),\n 'computeInterval cluster-bootstrap',\n evidence.value,\n `cluster '${cluster}'`,\n )\n const bucket = clusters.get(cluster)\n if (bucket) bucket.push(value)\n else clusters.set(cluster, [value])\n }\n const clusterValues = [...clusters.entries()]\n .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))\n .map(([, values]) => values)\n if (clusterValues.length < 2) {\n throw new ValidationError(\n `computeInterval: cluster-bootstrap needs >= 2 clusters, got ${clusterValues.length}`,\n )\n }\n const rng = mulberry32(spec.seed)\n const means = new Array<number>(spec.resamples)\n for (let draw = 0; draw < spec.resamples; draw++) {\n let sum = 0\n let count = 0\n for (let pick = 0; pick < clusterValues.length; pick++) {\n const cluster = clusterValues[Math.floor(rng() * clusterValues.length)]!\n for (const value of cluster) sum += value\n count += cluster.length\n }\n means[draw] = sum / count\n }\n means.sort((a, b) => a - b)\n const alpha = 1 - spec.level\n const lowerIndex = Math.floor((alpha / 2) * spec.resamples)\n const upperIndex = Math.min(spec.resamples - 1, Math.ceil((1 - alpha / 2) * spec.resamples) - 1)\n return {\n lower: means[lowerIndex]!,\n upper: means[Math.max(lowerIndex, upperIndex)]!,\n level: spec.level,\n }\n }\n\n if (evidence.kind !== 'binomial') {\n throw new ValidationError('computeInterval: clopper-pearson requires binomial evidence')\n }\n const { successes, trials } = evidence\n if (!Number.isInteger(successes) || !Number.isInteger(trials) || trials <= 0 || successes < 0) {\n throw new ValidationError(\n `computeInterval: clopper-pearson needs 0 <= successes <= trials, got ${successes}/${trials}`,\n )\n }\n if (successes > trials) {\n throw new ValidationError(\n `computeInterval: clopper-pearson successes ${successes} exceed trials ${trials}`,\n )\n }\n const alpha = 1 - spec.level\n const lower = successes === 0 ? 0 : binomialQuantile(successes, trials, alpha / 2, 'lower')\n const upper = successes === trials ? 1 : binomialQuantile(successes, trials, alpha / 2, 'upper')\n return { lower, upper, level: spec.level }\n}\n\n/**\n * Clopper-Pearson bound by bisection on the binomial tail. The lower bound is\n * the p with P(X >= successes | p) = alpha; the upper is the p with\n * P(X <= successes | p) = alpha. Deterministic, no special functions.\n */\nfunction binomialQuantile(\n successes: number,\n trials: number,\n alpha: number,\n side: 'lower' | 'upper',\n): number {\n const tail = (p: number): number => {\n // log-space binomial pmf accumulation for numeric stability\n let sum = 0\n for (let k = 0; k <= trials; k++) {\n const inTail = side === 'lower' ? k >= successes : k <= successes\n if (!inTail) continue\n sum += Math.exp(logBinomialPmf(k, trials, p))\n }\n return sum\n }\n let lo = 0\n let hi = 1\n for (let iter = 0; iter < 100; iter++) {\n const mid = (lo + hi) / 2\n if (tail(mid) < alpha) {\n if (side === 'lower') lo = mid\n else hi = mid\n } else {\n if (side === 'lower') hi = mid\n else lo = mid\n }\n }\n return (lo + hi) / 2\n}\n\nfunction logBinomialPmf(k: number, n: number, p: number): number {\n if (p <= 0) return k === 0 ? 0 : Number.NEGATIVE_INFINITY\n if (p >= 1) return k === n ? 0 : Number.NEGATIVE_INFINITY\n return logChoose(n, k) + k * Math.log(p) + (n - k) * Math.log(1 - p)\n}\n\nfunction logChoose(n: number, k: number): number {\n return logFactorial(n) - logFactorial(k) - logFactorial(n - k)\n}\n\nconst LOG_FACTORIAL_CACHE: number[] = [0]\nfunction logFactorial(n: number): number {\n for (let i = LOG_FACTORIAL_CACHE.length; i <= n; i++) {\n LOG_FACTORIAL_CACHE[i] = LOG_FACTORIAL_CACHE[i - 1]! + Math.log(i)\n }\n return LOG_FACTORIAL_CACHE[n]!\n}\n\n// ── Conditions and decisions ─────────────────────────────────────────\n\n/** Decision guards read only named derived quantities — never raw rows. */\nexport type Condition =\n | { kind: 'interval-excludes-zero'; interval: string; sign: 'positive' | 'negative' }\n | { kind: 'interval-includes-zero'; interval: string }\n | { kind: 'quantity-threshold'; quantity: string; op: 'gte' | 'lte' | 'gt' | 'lt'; value: number }\n | { kind: 'obligation-met'; obligation: string }\n | { kind: 'all'; of: Condition[] }\n | { kind: 'any'; of: Condition[] }\n | { kind: 'not'; of: Condition }\n\n/** The named quantities a decision rule may read. Nothing else reaches it. */\nexport interface DerivedQuantities {\n intervals: Record<string, { lower: number; upper: number }>\n quantities: Record<string, number>\n obligationsMet: Record<string, boolean>\n}\n\nexport function evaluateCondition(condition: Condition, evidence: DerivedQuantities): boolean {\n switch (condition.kind) {\n case 'interval-excludes-zero': {\n const interval = evidence.intervals[condition.interval]\n if (!interval) {\n throw new ValidationError(\n `evaluateCondition: interval '${condition.interval}' is not in the evidence`,\n )\n }\n const excludes = interval.lower > 0 || interval.upper < 0\n return excludes && (condition.sign === 'positive' ? interval.lower > 0 : interval.upper < 0)\n }\n case 'interval-includes-zero': {\n const interval = evidence.intervals[condition.interval]\n if (!interval) {\n throw new ValidationError(\n `evaluateCondition: interval '${condition.interval}' is not in the evidence`,\n )\n }\n return interval.lower <= 0 && interval.upper >= 0\n }\n case 'quantity-threshold': {\n const value = evidence.quantities[condition.quantity]\n if (value === undefined) {\n throw new ValidationError(\n `evaluateCondition: quantity '${condition.quantity}' is not in the evidence`,\n )\n }\n return compareValues(value, condition.op, condition.value)\n }\n case 'obligation-met':\n return evidence.obligationsMet[condition.obligation] === true\n case 'all':\n return condition.of.every((c) => evaluateCondition(c, evidence))\n case 'any':\n return condition.of.some((c) => evaluateCondition(c, evidence))\n case 'not':\n return !evaluateCondition(condition.of, evidence)\n }\n}\n\nexport interface DecisionBranch {\n when: Condition\n verdict: string\n report: string[]\n}\n\n/**\n * Ordered decision table: the first branch whose condition holds fires, and a\n * table no branch matches throws — a non-total registration is a defect, not\n * an implicit verdict. `report-only` registers the ABSENCE of a verdict\n * branch: the estimate and the per-row table are the finding, and the\n * registered meaning prose rides as non-executable interpretation data.\n */\nexport type DecisionRule =\n | { kind: 'table'; branches: DecisionBranch[] }\n | {\n kind: 'report-only'\n estimands: string[]\n intervals: string[]\n perRow: string[]\n interpretation?: { onQualitative: string; consequence: string }[]\n }\n\nexport interface DecisionOutcome {\n verdict: string\n report: string[]\n}\n\nexport function executeDecisionRule(\n rule: DecisionRule,\n evidence: DerivedQuantities,\n): DecisionOutcome {\n if (rule.kind === 'report-only') {\n return { verdict: 'report-only', report: [...rule.estimands, ...rule.intervals] }\n }\n for (const branch of rule.branches) {\n if (evaluateCondition(branch.when, evidence)) {\n return { verdict: branch.verdict, report: branch.report }\n }\n }\n throw new DecisionTableNotTotalError(\n 'executeDecisionRule: decision table is not total — no branch matched the evidence',\n )\n}\n\n/** A registered control that must exist before a class of verdicts is read. */\nexport interface Obligation {\n id: string\n appliesToVerdicts: string[]\n control: string\n}\n\n// ── Validity gates and halt ──────────────────────────────────────────\n\n/** Pre-spend design checks. Each returns pass/fail plus its evidence. */\nexport type ValidityGate =\n | {\n kind: 'oracle-determinism'\n unit: 'suite' | 'assertion'\n replicates: number\n maxFlipRate: number\n }\n | {\n kind: 'population-reproducibility'\n joinOn: string\n compare: string[]\n maxChangedRows: number\n }\n | { kind: 'provenance-assertion'; claim: Predicate }\n | {\n kind: 'power-floor'\n target: number\n effectGrid: number[]\n sim: { trials: number; resamples: number; seed: number }\n }\n | { kind: 'identity'; field: 'served-model'; op: 'basename-eq'; onFail: 'abort' }\n\nexport interface GateResult {\n id: string\n passed: boolean\n evidence: JsonValue\n}\n\n/**\n * Replicate-flip counting over graded states. A state whose replicates split\n * between pass and fail is flipping; its flip rate is the minority share.\n */\nexport function evaluateOracleDeterminismGate(\n id: string,\n gate: Extract<ValidityGate, { kind: 'oracle-determinism' }>,\n repsByState: Record<string, readonly boolean[]>,\n): GateResult {\n const evidence: Record<string, JsonValue> = {}\n let passed = true\n for (const [state, reps] of Object.entries(repsByState)) {\n const passes = reps.filter(Boolean).length\n const flipRate = reps.length === 0 ? 0 : Math.min(passes, reps.length - passes) / reps.length\n evidence[state] = { passes, replicates: reps.length, flipRate }\n if (flipRate > gate.maxFlipRate) passed = false\n }\n return { id, passed, evidence }\n}\n\n/**\n * Join two population snapshots on `joinOn` and compare the registered fields.\n * Only rows present in both snapshots are compared; a presence change is a\n * different failure and needs its own gate.\n */\nexport function evaluatePopulationReproducibilityGate(\n id: string,\n gate: Extract<ValidityGate, { kind: 'population-reproducibility' }>,\n populations: { left: readonly EvidenceRecord[]; right: readonly EvidenceRecord[] },\n): GateResult {\n const rightByKey = new Map(populations.right.map((r) => [String(readField(r, gate.joinOn)), r]))\n const changed: string[] = []\n for (const left of populations.left) {\n const key = String(readField(left, gate.joinOn))\n const right = rightByKey.get(key)\n if (!right) continue\n const moved = gate.compare.filter((f) => readField(left, f) !== readField(right, f))\n if (moved.length > 0) {\n changed.push(\n `${key} ${moved.map((f) => `${f}:${String(readField(left, f))}->${String(readField(right, f))}`).join(' ')}`,\n )\n }\n }\n return { id, passed: changed.length <= gate.maxChangedRows, evidence: changed }\n}\n\n/** The registered claim about provenance must hold on the provenance record. */\nexport function evaluateProvenanceGate(\n id: string,\n gate: Extract<ValidityGate, { kind: 'provenance-assertion' }>,\n provenance: EvidenceRecord,\n): GateResult {\n const passed = evaluatePredicate(gate.claim, provenance)\n return { id, passed, evidence: { claimHolds: passed } }\n}\n\n/** Final path segment equality between the pinned and the served identity. */\nexport function evaluateIdentityGate(\n id: string,\n _gate: Extract<ValidityGate, { kind: 'identity' }>,\n identities: { pinned: string; served: string },\n): GateResult {\n const basename = (s: string): string => s.split('/').pop() ?? s\n const passed = basename(identities.pinned) === basename(identities.served)\n return {\n id,\n passed,\n evidence: { pinned: identities.pinned, served: identities.served, matched: passed },\n }\n}\n\n/**\n * The design's power curve must reach the registered target at some grid\n * effect. The curve must cover the registered effect grid exactly — a curve\n * computed on a different grid is different evidence and is refused.\n */\nexport function evaluatePowerFloorGate(\n id: string,\n gate: Extract<ValidityGate, { kind: 'power-floor' }>,\n curve: readonly { effect: number; power: number }[],\n): GateResult {\n const byEffect = new Map(curve.map((point) => [point.effect, point.power]))\n const missing = gate.effectGrid.filter((effect) => !byEffect.has(effect))\n if (missing.length > 0) {\n throw new ValidationError(\n `evaluatePowerFloorGate: curve does not cover registered effects [${missing.join(', ')}]`,\n )\n }\n const powers = gate.effectGrid.map((effect) => byEffect.get(effect)!)\n const maxPower = Math.max(...powers)\n return {\n id,\n passed: maxPower >= gate.target,\n evidence: {\n target: gate.target,\n maxPower,\n curve: gate.effectGrid.map((effect) => ({ effect, power: byEffect.get(effect)! })),\n },\n }\n}\n\n/** Checks as prerequisites: any named gate failing refuses the spend. */\nexport interface HaltRule {\n when: { kind: 'any-gate-failed'; gates: string[] }\n action: 'refuse-spend'\n report: 'settling-n'\n}\n\nexport interface HaltOutcome {\n fired: boolean\n action: 'refuse-spend' | null\n failedGates: string[]\n}\n\nexport function evaluateHaltRule(halt: HaltRule, gates: readonly GateResult[]): HaltOutcome {\n const seen = new Map(gates.map((g) => [g.id, g]))\n const missing = halt.when.gates.filter((id) => !seen.has(id))\n if (missing.length > 0) {\n throw new ValidationError(\n `evaluateHaltRule: halt references gates that were not evaluated: [${missing.join(', ')}]`,\n )\n }\n const failed = halt.when.gates.filter((id) => !seen.get(id)!.passed)\n return failed.length > 0\n ? { fired: true, action: halt.action, failedGates: failed }\n : { fired: false, action: null, failedGates: [] }\n}\n\n// ── Budget rules ─────────────────────────────────────────────────────\n\n/**\n * Spend schedules as data. `ledger` names every entry the ceiling counts, so\n * what the gate reads is registered, not improvised at gate time.\n */\nexport type BudgetRule =\n | {\n kind: 'uniform-pass'\n ceilingUsd: number\n maxPasses: number\n projection: 'last-pass-cost'\n costSource: 'priced-per-call'\n ledger: { id: string; usd: number }[]\n partialPass: 'report-never-lift'\n }\n | {\n kind: 'n-ladder'\n steps: number[]\n ceilingUsd: number\n projection: 'unit-cost-times-rows-times-n'\n onExhaust: 'refuse-report-projection'\n }\n\nexport interface UniformPassDecision {\n pass: number\n cumulativeBefore: number\n projected: number\n go: boolean\n}\n\nexport interface UniformPassSchedule {\n decisions: UniformPassDecision[]\n uniformN: number\n}\n\n/**\n * Execute the uniform-pass schedule against measured pass costs. Pass 1 always\n * runs; each later pass runs only when the cumulative spend plus the last\n * measured pass cost stays at or under the registered ceiling. The registered\n * ledger is the pre-spend the ceiling counts.\n */\nexport function runUniformPassBudget(\n rule: Extract<BudgetRule, { kind: 'uniform-pass' }>,\n measuredPassCosts: readonly number[],\n): UniformPassSchedule {\n const preSpend = rule.ledger.reduce((sum, entry) => sum + entry.usd, 0)\n let cumulative = preSpend\n const decisions: UniformPassDecision[] = []\n let uniformN = 0\n for (let pass = 1; pass <= rule.maxPasses; pass++) {\n if (pass === 1) {\n if (measuredPassCosts[0] === undefined) break\n cumulative += measuredPassCosts[0]\n uniformN = 1\n continue\n }\n const projected = measuredPassCosts[pass - 2]\n if (projected === undefined) break\n const go = cumulative + projected <= rule.ceilingUsd\n decisions.push({ pass, cumulativeBefore: cumulative, projected, go })\n if (!go || measuredPassCosts[pass - 1] === undefined) break\n cumulative += measuredPassCosts[pass - 1]!\n uniformN = pass\n }\n return { decisions, uniformN }\n}\n\nexport interface NLadderProjection {\n chosenN: number | null\n projections: { n: number; projectedUsd: number; affordable: boolean }[]\n refusal: null | { onExhaust: 'refuse-report-projection'; reason: string }\n}\n\n/**\n * Walk the registered n-ladder and pick the first affordable step. When no\n * step fits the ceiling, the rule refuses and reports the projection instead\n * of shrinking the row set — \"never subset rows\" is the registered invariant.\n */\nexport function projectNLadderBudget(\n rule: Extract<BudgetRule, { kind: 'n-ladder' }>,\n measured: { unitCostUsd: number; rows: number },\n): NLadderProjection {\n const projections = rule.steps.map((n) => {\n const projectedUsd = measured.unitCostUsd * measured.rows * n\n return { n, projectedUsd, affordable: projectedUsd <= rule.ceilingUsd }\n })\n const first = projections.find((p) => p.affordable)\n if (first) return { chosenN: first.n, projections, refusal: null }\n return {\n chosenN: null,\n projections,\n refusal: {\n onExhaust: rule.onExhaust,\n reason: `no ladder step fits the ${rule.ceilingUsd} USD ceiling at ${measured.rows} rows x ${measured.unitCostUsd} USD per unit`,\n },\n }\n}\n\n// ── Matched budget and reissue ───────────────────────────────────────\n\n/** Arm budget matching as a refusal, not prose. Verified by `verifyMatchedBudgets`. */\nexport interface MatchedBudgetRule {\n measure: 'realized-tokens'\n tolerance: number\n onFail: 'refuse-contrast'\n}\n\n/** Carrier faults are reissued; model outcomes stand. Closed enumeration. */\nexport interface ReissuePolicy {\n carrierEvents: ('http-status' | 'transport-error' | 'deadline' | 'empty-content')[]\n modelOutcomesStand: true\n maxIssues: number\n}\n\nexport type ReissueVerdict = 'reissue' | 'stands' | 'exhausted'\n\n/**\n * Classify one rollout event under the registered reissue policy. A carrier\n * event within the issue budget is reissued; a model outcome always stands;\n * a carrier event past `maxIssues` is exhausted and reported, never retried.\n */\nexport function classifyReissue(\n policy: ReissuePolicy,\n event: string,\n issuesSoFar: number,\n): ReissueVerdict {\n if (!(policy.carrierEvents as string[]).includes(event)) return 'stands'\n return issuesSoFar < policy.maxIssues ? 'reissue' : 'exhausted'\n}\n","/**\n * Matched-budget verification between arms, as a refusal object.\n *\n * A paired contrast is only meaningful when both arms spent comparable\n * resources; \"realized prompt and completion tokens must agree within 5%\" is\n * a registered rule, so its verification returns a verdict artifact — the\n * refusal lives inside the result, never in prose beside it.\n */\n\nimport { CaptureIntegrityError } from '../errors'\nimport type { MatchedBudgetRule } from './ast'\n\n/** Arms whose realized budgets diverge past the registered tolerance. */\nexport class MatchedBudgetError extends CaptureIntegrityError {}\n\nexport interface ArmRealizedBudget {\n armId: string\n /** Realized prompt + completion tokens the arm actually consumed. */\n realizedTokens: number\n}\n\nexport interface MatchedBudgetVerdict {\n rule: MatchedBudgetRule\n arms: ArmRealizedBudget[]\n /** (max - min) / max over all arms; 0 when every arm spent nothing. */\n maxRelativeGap: number\n /** The two arms with the widest gap; null when fewer than two arms. */\n widestPair: [string, string] | null\n matched: boolean\n /** Populated exactly when `matched` is false. */\n refusal: null | { onFail: 'refuse-contrast'; reason: string }\n}\n\n/**\n * Compare realized per-arm spend under the registered tolerance. Requires at\n * least two arms — a single arm has nothing to match against. Negative or\n * non-finite token counts are refused as evidence corruption, not compared.\n */\nexport function verifyMatchedBudgets(\n rule: MatchedBudgetRule,\n arms: readonly ArmRealizedBudget[],\n): MatchedBudgetVerdict {\n if (arms.length < 2) {\n throw new MatchedBudgetError(\n `verifyMatchedBudgets: need >= 2 arms to match budgets, got ${arms.length}`,\n )\n }\n for (const arm of arms) {\n if (!Number.isFinite(arm.realizedTokens) || arm.realizedTokens < 0) {\n throw new MatchedBudgetError(\n `verifyMatchedBudgets: arm '${arm.armId}' has invalid realized tokens ${arm.realizedTokens}`,\n )\n }\n }\n const sorted = [...arms].sort((a, b) => a.realizedTokens - b.realizedTokens)\n const min = sorted[0]!\n const max = sorted[sorted.length - 1]!\n const maxRelativeGap =\n max.realizedTokens === 0 ? 0 : (max.realizedTokens - min.realizedTokens) / max.realizedTokens\n const matched = maxRelativeGap <= rule.tolerance\n return {\n rule,\n arms: [...arms],\n maxRelativeGap,\n widestPair: [min.armId, max.armId],\n matched,\n refusal: matched\n ? null\n : {\n onFail: rule.onFail,\n reason:\n `realized ${rule.measure} diverge ${(maxRelativeGap * 100).toFixed(1)}% between ` +\n `'${min.armId}' (${min.realizedTokens}) and '${max.armId}' (${max.realizedTokens}) — ` +\n `registered tolerance is ${(rule.tolerance * 100).toFixed(1)}%; the contrast is refused`,\n },\n }\n}\n\n/** Throw the refusal for callers that gate the contrast on it. */\nexport function assertMatchedBudgets(\n rule: MatchedBudgetRule,\n arms: readonly ArmRealizedBudget[],\n): MatchedBudgetVerdict {\n const verdict = verifyMatchedBudgets(rule, arms)\n if (verdict.refusal) throw new MatchedBudgetError(verdict.refusal.reason)\n return verdict\n}\n","/**\n * The denominator chain as a first-class object.\n *\n * A benchmark whose denominator is not auditable is not a benchmark. Every\n * stage names what entered, what it removed, and what survived, so\n * `input = surviving + sum(excluded)` reads off the table instead of being\n * trusted. A stage that gains rows is refused at construction — a funnel is\n * monotone by definition, and a non-monotone one is a broken denominator,\n * not a formatting choice.\n *\n * The object is its own JSON render; `renderFunnelTable` is the text render.\n * `executeAdmissionRule` produces one by running a sealed {@link AdmissionRule}\n * over evidence records.\n */\n\nimport { CaptureIntegrityError } from '../errors'\nimport { type AdmissionRule, type EvidenceRecord, evaluatePredicate } from './ast'\n\n/** A funnel stage gained rows, double-counted them, or failed to reconcile. */\nexport class FunnelIntegrityError extends CaptureIntegrityError {}\n\nexport interface FunnelStageCount {\n id: string\n entering: number\n excluded: number\n remaining: number\n /** Named exclusion reasons summing to `excluded`, when the stage has them. */\n exclusions?: Record<string, number>\n /** Substrate checks this stage deliberately does not apply. Registered, never implicit. */\n waives?: string[]\n}\n\nexport interface FunnelPartitionCount {\n id: string\n /** Stage whose excluded rows the partition draws from. */\n from: string\n count: number\n /** A partition is reported separately and never pooled into the survivors. */\n pooling: 'never'\n}\n\nexport interface ExperimentFunnel {\n population: string\n input: number\n stages: FunnelStageCount[]\n surviving: number\n partitions: FunnelPartitionCount[]\n}\n\nexport interface FunnelStageInput {\n id: string\n /** Rows this stage removed. */\n excluded: number\n exclusions?: Record<string, number>\n waives?: string[]\n}\n\n/**\n * Build a funnel from counts and refuse anything non-monotone.\n *\n * Refusals: a negative count, a stage that gains rows (excluded < 0 is the\n * only way to gain — `remaining = entering - excluded` by construction, so a\n * gain cannot be smuggled in through `remaining`), named exclusions that do\n * not sum to the stage total, and a partition drawing from an unknown stage\n * or exceeding what that stage excluded.\n */\nexport function buildFunnel(input: {\n population: string\n input: number\n stages: FunnelStageInput[]\n partitions?: { id: string; from: string; count: number }[]\n}): ExperimentFunnel {\n if (!Number.isInteger(input.input) || input.input < 0) {\n throw new FunnelIntegrityError(\n `funnel input must be a non-negative integer, got ${input.input}`,\n )\n }\n let entering = input.input\n const stages: FunnelStageCount[] = []\n for (const stage of input.stages) {\n if (!Number.isInteger(stage.excluded)) {\n throw new FunnelIntegrityError(\n `funnel stage '${stage.id}' excluded count must be an integer, got ${stage.excluded}`,\n )\n }\n if (stage.excluded < 0) {\n throw new FunnelIntegrityError(\n `funnel stage '${stage.id}' gains ${-stage.excluded} rows — a funnel stage can only remove rows`,\n )\n }\n if (stage.excluded > entering) {\n throw new FunnelIntegrityError(\n `funnel stage '${stage.id}' excludes ${stage.excluded} rows but only ${entering} entered`,\n )\n }\n if (stage.exclusions) {\n const sum = Object.values(stage.exclusions).reduce((a, b) => a + b, 0)\n if (sum !== stage.excluded) {\n throw new FunnelIntegrityError(\n `funnel stage '${stage.id}' names exclusions summing to ${sum} but excludes ${stage.excluded}`,\n )\n }\n }\n const remaining = entering - stage.excluded\n stages.push({\n id: stage.id,\n entering,\n excluded: stage.excluded,\n remaining,\n ...(stage.exclusions ? { exclusions: { ...stage.exclusions } } : {}),\n ...(stage.waives ? { waives: [...stage.waives] } : {}),\n })\n entering = remaining\n }\n const byStage = new Map(stages.map((s) => [s.id, s]))\n const partitions: FunnelPartitionCount[] = (input.partitions ?? []).map((partition) => {\n const source = byStage.get(partition.from)\n if (!source) {\n throw new FunnelIntegrityError(\n `funnel partition '${partition.id}' draws from unknown stage '${partition.from}'`,\n )\n }\n if (partition.count < 0 || partition.count > source.excluded) {\n throw new FunnelIntegrityError(\n `funnel partition '${partition.id}' counts ${partition.count} rows but stage '${partition.from}' excluded ${source.excluded}`,\n )\n }\n return { id: partition.id, from: partition.from, count: partition.count, pooling: 'never' }\n })\n const funnel: ExperimentFunnel = {\n population: input.population,\n input: input.input,\n stages,\n surviving: entering,\n partitions,\n }\n assertFunnelReconciles(funnel)\n return funnel\n}\n\n/** A chain that does not add up is a broken denominator, so this throws. */\nexport function assertFunnelReconciles(funnel: ExperimentFunnel): void {\n const excluded = funnel.stages.reduce((sum, stage) => sum + stage.excluded, 0)\n if (funnel.input !== funnel.surviving + excluded) {\n throw new FunnelIntegrityError(\n `funnel '${funnel.population}' does not reconcile: input ${funnel.input} != surviving ${funnel.surviving} + excluded ${excluded}`,\n )\n }\n let entering = funnel.input\n for (const stage of funnel.stages) {\n if (stage.entering !== entering || stage.remaining !== stage.entering - stage.excluded) {\n throw new FunnelIntegrityError(\n `funnel '${funnel.population}' stage '${stage.id}' does not chain: ` +\n `entering ${stage.entering} (expected ${entering}), remaining ${stage.remaining}`,\n )\n }\n if (stage.remaining > stage.entering) {\n throw new FunnelIntegrityError(\n `funnel '${funnel.population}' stage '${stage.id}' gains rows: ${stage.entering} -> ${stage.remaining}`,\n )\n }\n entering = stage.remaining\n }\n}\n\nexport interface AdmissionExecution {\n funnel: ExperimentFunnel\n survivors: EvidenceRecord[]\n /** Partition rows by partition id, reported separately and never pooled. */\n partitionRows: Record<string, EvidenceRecord[]>\n}\n\n/**\n * Run a sealed admission rule over evidence records. Each stage keeps the rows\n * its predicate accepts; partitions draw from the rows their source stage\n * dropped. The result embeds the funnel, so the denominator chain and the\n * surviving rows can never disagree.\n */\nexport function executeAdmissionRule(\n rule: AdmissionRule,\n records: readonly EvidenceRecord[],\n): AdmissionExecution {\n let current = [...records]\n const droppedAt = new Map<string, EvidenceRecord[]>()\n const stageInputs: FunnelStageInput[] = []\n for (const stage of rule.stages) {\n const kept: EvidenceRecord[] = []\n const dropped: EvidenceRecord[] = []\n for (const record of current) {\n if (evaluatePredicate(stage.keep, record)) kept.push(record)\n else dropped.push(record)\n }\n droppedAt.set(stage.id, dropped)\n stageInputs.push({\n id: stage.id,\n excluded: dropped.length,\n ...(stage.waives ? { waives: stage.waives } : {}),\n })\n current = kept\n }\n const partitionRows: Record<string, EvidenceRecord[]> = {}\n const partitionCounts: { id: string; from: string; count: number }[] = []\n for (const partition of rule.partitions ?? []) {\n const source = droppedAt.get(partition.from)\n if (!source) {\n throw new FunnelIntegrityError(\n `admission partition '${partition.id}' draws from unknown stage '${partition.from}'`,\n )\n }\n const rows = source.filter((record) => evaluatePredicate(partition.keep, record))\n partitionRows[partition.id] = rows\n partitionCounts.push({ id: partition.id, from: partition.from, count: rows.length })\n }\n const funnel = buildFunnel({\n population: rule.population,\n input: records.length,\n stages: stageInputs,\n partitions: partitionCounts,\n })\n return { funnel, survivors: current, partitionRows }\n}\n\n/**\n * Chain two funnels whose boundary agrees: the second funnel's input must be\n * exactly the first funnel's survivors. Anything else is a gap or an\n * injection, and both are refused.\n */\nexport function composeFunnels(\n first: ExperimentFunnel,\n second: ExperimentFunnel,\n): ExperimentFunnel {\n if (second.input !== first.surviving) {\n throw new FunnelIntegrityError(\n `cannot compose funnels: '${first.population}' survives ${first.surviving} rows but '${second.population}' starts from ${second.input}`,\n )\n }\n return buildFunnel({\n population: first.population,\n input: first.input,\n stages: [...first.stages, ...second.stages].map((stage) => ({\n id: stage.id,\n excluded: stage.excluded,\n ...(stage.exclusions ? { exclusions: stage.exclusions } : {}),\n ...(stage.waives ? { waives: stage.waives } : {}),\n })),\n partitions: [...first.partitions, ...second.partitions].map((partition) => ({\n id: partition.id,\n from: partition.from,\n count: partition.count,\n })),\n })\n}\n\n/**\n * Text render of the chain. One row per stage; the reconciliation line at the\n * bottom restates `input = surviving + excluded` so a reader can check the\n * arithmetic without a tool.\n */\nexport function renderFunnelTable(funnel: ExperimentFunnel): string {\n const rows = funnel.stages.map((stage) => [\n stage.id + (stage.waives?.length ? ` (waives: ${stage.waives.join(', ')})` : ''),\n String(stage.entering),\n String(stage.excluded),\n String(stage.remaining),\n ])\n const header = ['stage', 'entering', 'excluded', 'remaining']\n const widths = header.map((h, col) => Math.max(h.length, ...rows.map((r) => r[col]!.length)))\n const line = (cells: string[]): string =>\n cells.map((cell, col) => cell.padEnd(widths[col]!)).join(' ')\n const out: string[] = [\n `population: ${funnel.population}`,\n `input: ${funnel.input}`,\n line(header),\n line(widths.map((w) => '-'.repeat(w))),\n ...rows.map((r) => line(r)),\n ]\n const excluded = funnel.stages.reduce((sum, stage) => sum + stage.excluded, 0)\n out.push(\n `surviving: ${funnel.surviving} (input ${funnel.input} = surviving ${funnel.surviving} + excluded ${excluded})`,\n )\n for (const partition of funnel.partitions) {\n out.push(\n `partition ${partition.id}: ${partition.count} rows from '${partition.from}' — reported separately, never pooled`,\n )\n }\n return out.join('\\n')\n}\n","/**\n * Define, seal, and execute experiments whose every rule is registered data.\n *\n * `defineExperiment` validates the cross-references inside a spec and freezes\n * it. `sealExperiment` canonicalizes and hashes the whole tree — arms, row\n * admission, selection, estimands, intervals, decision rule, gates, halt,\n * budget — into one digest that lands on every downstream artifact. Changing\n * what is decided requires a new digest: an amendment is a re-seal with a\n * reason and blindness attestations, and the digest history is the audit\n * trail.\n *\n * `openSealedExperiment` is the only execution surface. It verifies the seal\n * and returns executors bound to the sealed spec; none of them takes a\n * parameter for alpha, threshold, metric, or stopping rule, so\n * registered-vs-ran drift is unrepresentable rather than checked.\n */\n\nimport { createHash } from 'node:crypto'\nimport { ValidationError } from '../errors'\nimport { canonicalString } from '../ledger-core/canonical'\nimport {\n type AdmissionRule,\n type BudgetRule,\n type ComputedInterval,\n type Condition,\n computeEstimand,\n computeInterval,\n type DecisionOutcome,\n type DecisionRule,\n type DerivedQuantities,\n type Estimand,\n type EstimandResult,\n type EvidenceRecord,\n evaluateHaltRule,\n evaluateIdentityGate,\n evaluateOracleDeterminismGate,\n evaluatePopulationReproducibilityGate,\n evaluatePowerFloorGate,\n evaluateProvenanceGate,\n executeDecisionRule,\n type GateResult,\n type HaltOutcome,\n type HaltRule,\n type IntervalSpec,\n type JsonValue,\n type MatchedBudgetRule,\n type NLadderProjection,\n type Obligation,\n projectNLadderBudget,\n type ReissuePolicy,\n runSelectionRule,\n runUniformPassBudget,\n type SelectionRule,\n type UniformPassSchedule,\n type ValidityGate,\n} from './ast'\nimport { type ArmRealizedBudget, type MatchedBudgetVerdict, verifyMatchedBudgets } from './budget'\nimport { type AdmissionExecution, executeAdmissionRule } from './funnel'\n\n/** A sealed experiment whose digest no longer matches its spec. */\nexport class SealIntegrityError extends ValidationError {}\n\n// ── Spec ─────────────────────────────────────────────────────────────\n\nexport interface ArmSpec {\n id: string\n role: 'treatment' | 'control'\n /** Digest of the AgentProfile the arm runs under. */\n profileDigest?: string\n /** Digest of the pinned execution policy the arm runs under. */\n policyDigest?: string\n /** Registered arm pins (model, seed, step budget, ...) as data. */\n pins?: Record<string, JsonValue>\n}\n\nexport type OutcomeSpec =\n | {\n kind: 'binary'\n /** Where the pass verdict comes from, e.g. 'injected-suite'. */\n source?: string\n digestVerified?: boolean\n /** What counts as a pass, e.g. 'exit-0' or 'reward-file-contains-1'. */\n pass?: string\n /** Errored rollouts stay in the denominator; dropping them is unregistered. */\n droppedRollouts?: 'forbidden'\n }\n | {\n kind: 'bounded-score'\n min: number\n max: number\n orientation: 'higher-is-better' | 'lower-is-better'\n }\n\n/**\n * Per-rollout seed derivation as a closed source list. `arm` is not in the\n * union, so arm-dependent seeding is unrepresentable.\n */\nexport interface SeedDerivation {\n from: ('seed' | 'rowId' | 'rolloutIndex')[]\n}\n\nexport interface ExperimentSpec {\n id: string\n /** Human prose for the audit trail — never executable. */\n hypothesis?: string\n arms: ArmSpec[]\n outcome: OutcomeSpec\n admission?: AdmissionRule\n /** Named deterministic subset rules. */\n selections?: Record<string, SelectionRule>\n /**\n * Selection OUTPUTS pinned into the seal. A filter-of base resolves here, so\n * reusing an earlier draw is registered and a re-draw is a new digest.\n */\n sealedSubsets?: Record<string, string[]>\n estimands?: Record<string, Estimand>\n intervals?: Record<string, IntervalSpec>\n decision: DecisionRule\n obligations?: Obligation[]\n /** Named pre-spend validity gates; the halt rule references these names. */\n gates?: Record<string, ValidityGate>\n halt?: HaltRule\n budget?: BudgetRule\n matchedBudget?: MatchedBudgetRule\n reissue?: ReissuePolicy\n seedDerivation?: SeedDerivation\n seed?: number\n}\n\n// ── Validation ───────────────────────────────────────────────────────\n\nfunction conditionRefs(condition: Condition): {\n intervals: string[]\n quantities: string[]\n obligations: string[]\n} {\n switch (condition.kind) {\n case 'interval-excludes-zero':\n case 'interval-includes-zero':\n return { intervals: [condition.interval], quantities: [], obligations: [] }\n case 'quantity-threshold':\n return { intervals: [], quantities: [condition.quantity], obligations: [] }\n case 'obligation-met':\n return { intervals: [], quantities: [], obligations: [condition.obligation] }\n case 'all':\n case 'any': {\n const nested = condition.of.map(conditionRefs)\n return {\n intervals: nested.flatMap((r) => r.intervals),\n quantities: nested.flatMap((r) => r.quantities),\n obligations: nested.flatMap((r) => r.obligations),\n }\n }\n case 'not':\n return conditionRefs(condition.of)\n }\n}\n\n/**\n * Validate every cross-reference inside a spec and freeze it.\n *\n * A decision condition may only read a registered interval, a registered\n * estimand, or a registered obligation; a halt rule may only reference\n * registered gates; a filter-of base must resolve to a registered selection\n * or sealed subset. Anything else is refused here, before sealing.\n */\nexport function defineExperiment(spec: ExperimentSpec): ExperimentSpec {\n const problems: string[] = []\n if (!spec.id || spec.id.trim().length === 0) problems.push('id is empty')\n if (spec.arms.length === 0) problems.push('at least one arm is required')\n const armIds = new Set<string>()\n for (const arm of spec.arms) {\n if (armIds.has(arm.id)) problems.push(`duplicate arm id '${arm.id}'`)\n armIds.add(arm.id)\n }\n if (!spec.arms.some((arm) => arm.role === 'treatment')) {\n problems.push('at least one arm must have role treatment')\n }\n\n const intervalNames = new Set(Object.keys(spec.intervals ?? {}))\n const estimandNames = new Set(Object.keys(spec.estimands ?? {}))\n const obligationIds = new Set((spec.obligations ?? []).map((o) => o.id))\n const gateNames = new Set(Object.keys(spec.gates ?? {}))\n const selectionNames = new Set(Object.keys(spec.selections ?? {}))\n const sealedSubsetNames = new Set(Object.keys(spec.sealedSubsets ?? {}))\n\n const checkCondition = (condition: Condition, where: string): void => {\n const refs = conditionRefs(condition)\n for (const name of refs.intervals) {\n if (!intervalNames.has(name)) problems.push(`${where} reads unregistered interval '${name}'`)\n }\n for (const name of refs.quantities) {\n if (!estimandNames.has(name)) problems.push(`${where} reads unregistered quantity '${name}'`)\n }\n for (const name of refs.obligations) {\n if (!obligationIds.has(name))\n problems.push(`${where} reads unregistered obligation '${name}'`)\n }\n }\n\n if (spec.decision.kind === 'table') {\n if (spec.decision.branches.length === 0) problems.push('decision table has no branches')\n spec.decision.branches.forEach((branch, index) => {\n checkCondition(branch.when, `decision branch ${index} ('${branch.verdict}')`)\n })\n } else {\n for (const name of spec.decision.estimands) {\n if (!estimandNames.has(name)) {\n problems.push(`report-only decision names unregistered estimand '${name}'`)\n }\n }\n for (const name of spec.decision.intervals) {\n if (!intervalNames.has(name)) {\n problems.push(`report-only decision names unregistered interval '${name}'`)\n }\n }\n }\n\n if (spec.decision.kind === 'table' && spec.obligations) {\n const verdicts = new Set(spec.decision.branches.map((b) => b.verdict))\n for (const obligation of spec.obligations) {\n for (const verdict of obligation.appliesToVerdicts) {\n if (!verdicts.has(verdict)) {\n problems.push(\n `obligation '${obligation.id}' applies to verdict '${verdict}' which no branch produces`,\n )\n }\n }\n }\n }\n\n if (spec.halt) {\n for (const gate of spec.halt.when.gates) {\n if (!gateNames.has(gate)) problems.push(`halt rule references unregistered gate '${gate}'`)\n }\n }\n\n for (const [name, selection] of Object.entries(spec.selections ?? {})) {\n if (selection.kind === 'filter-of') {\n if (!selectionNames.has(selection.base) && !sealedSubsetNames.has(selection.base)) {\n problems.push(\n `selection '${name}' filters unregistered base '${selection.base}' (not a selection or sealed subset)`,\n )\n }\n }\n }\n\n if (spec.admission) {\n const stageIds = new Set<string>()\n for (const stage of spec.admission.stages) {\n if (stageIds.has(stage.id)) problems.push(`duplicate admission stage id '${stage.id}'`)\n stageIds.add(stage.id)\n }\n for (const partition of spec.admission.partitions ?? []) {\n if (!stageIds.has(partition.from)) {\n problems.push(\n `admission partition '${partition.id}' draws from unknown stage '${partition.from}'`,\n )\n }\n }\n }\n\n if (problems.length > 0) {\n throw new ValidationError(`defineExperiment('${spec.id}'): ${problems.join('; ')}`)\n }\n return deepFreeze(structuredClone(spec))\n}\n\nfunction deepFreeze<T>(value: T): T {\n if (value !== null && typeof value === 'object') {\n for (const key of Object.keys(value as object)) {\n deepFreeze((value as Record<string, unknown>)[key])\n }\n Object.freeze(value)\n }\n return value\n}\n\n// ── Seal ─────────────────────────────────────────────────────────────\n\nexport interface SealAmendment {\n /** ISO8601 timestamp of the re-seal. */\n at: string\n reason: string\n /** Blindness attestations: what was verifiably unseen when the amendment was made. */\n blind: string[]\n /** Digest of the spec after this amendment. */\n digest: string\n}\n\n/**\n * Digest scheme of a sealed experiment. Both are sha256 hex over the\n * serialized spec and differ only in the serialization: `'sha256-rfc8785'` is\n * RFC 8785 canonical JSON, `'sha256-content'` is key-sorted `JSON.stringify`.\n */\nexport type SealAlgo = 'sha256-content' | 'sha256-rfc8785'\n\nexport interface SealedExperiment {\n spec: ExperimentSpec\n /** sha256 over the serialized spec, under the scheme `algo` names. */\n digest: string\n /**\n * Digest scheme of `digest`. `'sha256-rfc8785'` is what {@link sealExperiment}\n * emits; `'sha256-content'` is read-only, carried by seals from an earlier\n * release, and still verifies.\n */\n algo: SealAlgo\n sealedAt: string\n /** Digest of the original registration, before any amendment. */\n initialDigest: string\n amendments: SealAmendment[]\n}\n\n/** Validate, canonicalize, and hash a spec into its registration. */\nexport async function sealExperiment(\n spec: ExperimentSpec,\n options: { sealedAt?: string } = {},\n): Promise<SealedExperiment> {\n const validated = defineExperiment(spec)\n const digest = specDigest(validated, 'sha256-rfc8785')\n return {\n spec: validated,\n digest,\n algo: 'sha256-rfc8785',\n sealedAt: options.sealedAt ?? new Date().toISOString(),\n initialDigest: digest,\n amendments: [],\n }\n}\n\n/**\n * Amend a sealed experiment. The current seal is verified first, the new spec\n * is validated and re-hashed, and the amendment appends to the digest chain.\n * There is no way to change what is decided without producing a new digest.\n */\nexport async function amendExperiment(\n sealed: SealedExperiment,\n amendment: { spec: ExperimentSpec; reason: string; blind: string[]; at?: string },\n): Promise<SealedExperiment> {\n await assertSealIntact(sealed)\n const validated = defineExperiment(amendment.spec)\n const digest = specDigest(validated, 'sha256-rfc8785')\n return {\n spec: validated,\n digest,\n algo: 'sha256-rfc8785',\n sealedAt: sealed.sealedAt,\n initialDigest: sealed.initialDigest,\n amendments: [\n ...sealed.amendments,\n {\n at: amendment.at ?? new Date().toISOString(),\n reason: amendment.reason,\n blind: [...amendment.blind],\n digest,\n },\n ],\n }\n}\n\n/** True when the sealed digest still matches the spec it carries, under the\n * scheme the seal declares. */\nexport async function verifySealedExperiment(sealed: SealedExperiment): Promise<boolean> {\n return specDigest(sealed.spec, sealed.algo) === sealed.digest\n}\n\n/**\n * Serialize a spec under `algo` and digest it. `'sha256-content'` is read-only\n * — it exists so a seal written by an earlier release still verifies, and no\n * path that WRITES a digest may pass it.\n */\nfunction specDigest(spec: ExperimentSpec, algo: SealAlgo): string {\n const serialized =\n algo === 'sha256-rfc8785' ? canonicalString(spec) : JSON.stringify(sortKeysDeep(spec))\n return createHash('sha256').update(serialized, 'utf8').digest('hex')\n}\n\nfunction sortKeysDeep(value: unknown): unknown {\n if (value === null || typeof value !== 'object') return value\n if (Array.isArray(value)) return value.map(sortKeysDeep)\n const out: Record<string, unknown> = {}\n for (const key of Object.keys(value as Record<string, unknown>).sort()) {\n out[key] = sortKeysDeep((value as Record<string, unknown>)[key])\n }\n return out\n}\n\nasync function assertSealIntact(sealed: SealedExperiment): Promise<void> {\n if (!(await verifySealedExperiment(sealed))) {\n throw new SealIntegrityError(\n `sealed experiment '${sealed.spec.id}' digest ${sealed.digest} does not match its spec — the registration was tampered with`,\n )\n }\n}\n\n// ── Sealed execution ─────────────────────────────────────────────────\n\n/** Evidence a gate executor consumes, discriminated to match the gate kind. */\nexport type GateEvidence =\n | { kind: 'oracle-determinism'; repsByState: Record<string, readonly boolean[]> }\n | {\n kind: 'population-reproducibility'\n left: readonly EvidenceRecord[]\n right: readonly EvidenceRecord[]\n }\n | { kind: 'provenance-assertion'; provenance: EvidenceRecord }\n | { kind: 'identity'; pinned: string; served: string }\n | { kind: 'power-floor'; curve: readonly { effect: number; power: number }[] }\n\n/**\n * Executors bound to one verified seal. Every method reads its rule from the\n * sealed spec; evidence is the only argument anywhere.\n */\nexport interface RegisteredExperiment {\n readonly sealed: SealedExperiment\n /** Execute the registered decision rule on derived quantities. */\n decide(evidence: DerivedQuantities): DecisionOutcome\n /** Run the registered admission funnel over evidence rows. */\n admit(records: readonly EvidenceRecord[]): AdmissionExecution\n /** Run a registered selection rule. Filter-of bases resolve to sealed subsets. */\n select(name: string, records: readonly EvidenceRecord[], options: { idField: string }): string[]\n /** Evaluate a registered validity gate on evidence of the matching kind. */\n gate(name: string, evidence: GateEvidence): GateResult\n /** Evaluate the registered halt rule over gate results. */\n halt(gates: readonly GateResult[]): HaltOutcome\n /** Execute the registered uniform-pass budget schedule. */\n runUniformPassBudget(measuredPassCosts: readonly number[]): UniformPassSchedule\n /** Project the registered n-ladder budget. */\n projectNLadderBudget(measured: { unitCostUsd: number; rows: number }): NLadderProjection\n /** Verify realized arm budgets under the registered matched-budget rule. */\n matchedBudgets(arms: readonly ArmRealizedBudget[]): MatchedBudgetVerdict\n /** Compute a registered estimand over evidence rows. */\n estimate(name: string, rows: readonly EvidenceRecord[]): EstimandResult\n /** Compute a registered interval spec. */\n interval(\n name: string,\n evidence:\n | { kind: 'rows'; rows: readonly EvidenceRecord[]; value: string }\n | { kind: 'binomial'; successes: number; trials: number },\n ): ComputedInterval\n}\n\n/**\n * Verify the seal and return executors bound to it. This is the module's only\n * execution surface: a rule that is not in the sealed spec cannot run, and a\n * rule that is cannot run differently.\n */\nexport async function openSealedExperiment(\n sealed: SealedExperiment,\n): Promise<RegisteredExperiment> {\n await assertSealIntact(sealed)\n const spec = sealed.spec\n const need = <T>(value: T | undefined, what: string): T => {\n if (value === undefined) {\n throw new ValidationError(`experiment '${spec.id}' registered no ${what}`)\n }\n return value\n }\n return {\n sealed,\n decide: (evidence) => executeDecisionRule(spec.decision, evidence),\n admit: (records) => executeAdmissionRule(need(spec.admission, 'admission rule'), records),\n select: (name, records, options) => {\n const rule = need(spec.selections?.[name], `selection '${name}'`)\n return runSelectionRule(rule, records, {\n idField: options.idField,\n bases: spec.sealedSubsets,\n })\n },\n gate: (name, evidence) => {\n const gate = need(spec.gates?.[name], `gate '${name}'`)\n if (gate.kind !== evidence.kind) {\n throw new ValidationError(\n `gate '${name}' is registered as ${gate.kind} but received ${evidence.kind} evidence`,\n )\n }\n switch (gate.kind) {\n case 'oracle-determinism':\n return evaluateOracleDeterminismGate(\n name,\n gate,\n (evidence as Extract<GateEvidence, { kind: 'oracle-determinism' }>).repsByState,\n )\n case 'population-reproducibility': {\n const populations = evidence as Extract<\n GateEvidence,\n { kind: 'population-reproducibility' }\n >\n return evaluatePopulationReproducibilityGate(name, gate, populations)\n }\n case 'provenance-assertion':\n return evaluateProvenanceGate(\n name,\n gate,\n (evidence as Extract<GateEvidence, { kind: 'provenance-assertion' }>).provenance,\n )\n case 'identity':\n return evaluateIdentityGate(\n name,\n gate,\n evidence as Extract<GateEvidence, { kind: 'identity' }>,\n )\n case 'power-floor':\n return evaluatePowerFloorGate(\n name,\n gate,\n (evidence as Extract<GateEvidence, { kind: 'power-floor' }>).curve,\n )\n }\n },\n halt: (gates) => evaluateHaltRule(need(spec.halt, 'halt rule'), gates),\n runUniformPassBudget: (measuredPassCosts) => {\n const budget = need(spec.budget, 'budget rule')\n if (budget.kind !== 'uniform-pass') {\n throw new ValidationError(\n `experiment '${spec.id}' registered a ${budget.kind} budget, not uniform-pass`,\n )\n }\n return runUniformPassBudget(budget, measuredPassCosts)\n },\n projectNLadderBudget: (measured) => {\n const budget = need(spec.budget, 'budget rule')\n if (budget.kind !== 'n-ladder') {\n throw new ValidationError(\n `experiment '${spec.id}' registered a ${budget.kind} budget, not n-ladder`,\n )\n }\n return projectNLadderBudget(budget, measured)\n },\n matchedBudgets: (arms) =>\n verifyMatchedBudgets(need(spec.matchedBudget, 'matched-budget rule'), arms),\n estimate: (name, rows) =>\n computeEstimand(need(spec.estimands?.[name], `estimand '${name}'`), rows),\n interval: (name, evidence) =>\n computeInterval(need(spec.intervals?.[name], `interval '${name}'`), evidence),\n }\n}\n","/**\n * Evidence receipts are the join between Runtime execution and Eval promotion.\n *\n * Runtime says what actually ran. Eval says what independently measured it.\n * This receipt binds those worlds without making either package import the other:\n * stable pursuit/run identity, exact candidate/evaluator/environment/input/output\n * content identities, and the authority class that produced the observation.\n *\n * The payload is attested with agent-eval's existing canonical report attestation.\n * Signing/key management deliberately remains outside this substrate; consumers may\n * sign the byte-stable receipt or anchor its attestation in a transparency log.\n */\n\nimport {\n type AttestationProvenance,\n type AttestedReport,\n attest,\n verifyAttestation,\n} from '../attestation'\n\nexport const EVIDENCE_RECEIPT_VERSION = '1.0.0' as const\n\n/** Closed promotion vocabulary. A typo or unknown future kind is never independent by default. */\nexport const EVIDENCE_AUTHORITY_KINDS = [\n 'candidate-self-report',\n 'independent-evaluator',\n 'independent-replication',\n 'human-review',\n 'production-canary',\n] as const\n\nexport type EvidenceAuthorityKind = (typeof EVIDENCE_AUTHORITY_KINDS)[number]\n\nexport const INDEPENDENT_EVIDENCE_AUTHORITY_KINDS = [\n 'independent-evaluator',\n 'independent-replication',\n 'human-review',\n 'production-canary',\n] as const satisfies readonly EvidenceAuthorityKind[]\n\nexport interface EvidenceAuthority {\n readonly kind: EvidenceAuthorityKind\n /** Stable authority/service/person identifier; never inferred from model prose. */\n readonly id: string\n}\n\nexport interface EvidenceBinding {\n readonly schemaVersion: typeof EVIDENCE_RECEIPT_VERSION\n /** Stable objective identity spanning retries, forks, resumes, and multiple runs. */\n readonly pursuitId: string\n /** Concrete execution/evaluation run this evidence was produced from. */\n readonly runId: string\n /** Exact candidate/program/profile bundle under evaluation. */\n readonly candidateDigest: string\n /** Exact evaluator/checker program or registered experiment definition. */\n readonly evaluatorDigest: string\n /** Exact sandbox/container/dependency/environment identity. */\n readonly environmentDigest: string\n /** Commitment to the input set. The hidden inputs themselves need not be exposed. */\n readonly inputSetCommitment: string\n /** Content identity of the raw evaluated output/artifact set. */\n readonly outputDigest: string\n /** Content identity of the evaluation result/report/verdict body. */\n readonly resultDigest: string\n readonly authority: EvidenceAuthority\n /** Optional experiment seal that governed the evaluation. */\n readonly experimentDigest?: string\n /** Optional observer-journal chain tip covering the execution being evaluated. */\n readonly observerDigest?: string\n}\n\nexport interface EvidenceReceipt {\n readonly binding: EvidenceBinding\n readonly attestation: AttestedReport\n}\n\nexport interface EvidenceReceiptVerification {\n readonly valid: boolean\n readonly reason?: string\n}\n\nexport interface CreateEvidenceReceiptInput extends Omit<EvidenceBinding, 'schemaVersion'> {}\n\n/**\n * Mint a content-attested evidence receipt. Required identity fields are deliberately\n * non-optional: unknown evidence stays unknown and cannot accidentally look certified.\n * The attestation's input provenance must equal the receipt commitment so two competing\n * descriptions of the evaluated population cannot coexist inside one valid receipt.\n */\nexport function createEvidenceReceipt(\n input: CreateEvidenceReceiptInput,\n provenance: AttestationProvenance,\n): EvidenceReceipt {\n const inputSetCommitment = requiredIdentity(input.inputSetCommitment, 'inputSetCommitment')\n assertInputCommitment(provenance, inputSetCommitment)\n const binding: EvidenceBinding = Object.freeze({\n schemaVersion: EVIDENCE_RECEIPT_VERSION,\n pursuitId: requiredIdentity(input.pursuitId, 'pursuitId'),\n runId: requiredIdentity(input.runId, 'runId'),\n candidateDigest: requiredIdentity(input.candidateDigest, 'candidateDigest'),\n evaluatorDigest: requiredIdentity(input.evaluatorDigest, 'evaluatorDigest'),\n environmentDigest: requiredIdentity(input.environmentDigest, 'environmentDigest'),\n inputSetCommitment,\n outputDigest: requiredIdentity(input.outputDigest, 'outputDigest'),\n resultDigest: requiredIdentity(input.resultDigest, 'resultDigest'),\n authority: requiredAuthority(input.authority),\n ...(input.experimentDigest === undefined\n ? {}\n : { experimentDigest: requiredIdentity(input.experimentDigest, 'experimentDigest') }),\n ...(input.observerDigest === undefined\n ? {}\n : { observerDigest: requiredIdentity(input.observerDigest, 'observerDigest') }),\n })\n return Object.freeze({ binding, attestation: attest(binding, provenance) })\n}\n\n/**\n * Verify promotion-grade evidence. Generic report attestation keeps a legacy read path,\n * but an EvidenceReceipt never accepts unbound provenance: changing the evaluator code,\n * model versions, input commitment provenance, or creation record must invalidate the\n * evidence rather than merely annotating it as legacy.\n */\nexport function verifyEvidenceReceipt(receipt: EvidenceReceipt): EvidenceReceiptVerification {\n if (receipt.binding.schemaVersion !== EVIDENCE_RECEIPT_VERSION) {\n return {\n valid: false,\n reason: `unsupported evidence receipt version '${receipt.binding.schemaVersion}'`,\n }\n }\n try {\n for (const [field, value] of Object.entries({\n pursuitId: receipt.binding.pursuitId,\n runId: receipt.binding.runId,\n candidateDigest: receipt.binding.candidateDigest,\n evaluatorDigest: receipt.binding.evaluatorDigest,\n environmentDigest: receipt.binding.environmentDigest,\n inputSetCommitment: receipt.binding.inputSetCommitment,\n outputDigest: receipt.binding.outputDigest,\n resultDigest: receipt.binding.resultDigest,\n })) {\n requiredIdentity(value, field)\n }\n requiredAuthority(receipt.binding.authority)\n assertInputCommitment(receipt.attestation.provenance, receipt.binding.inputSetCommitment)\n } catch (error) {\n return { valid: false, reason: error instanceof Error ? error.message : String(error) }\n }\n\n const verification = verifyAttestation(receipt.binding, receipt.attestation)\n if (!verification.valid) return verification\n if (\n verification.legacyUnboundProvenance === true ||\n receipt.attestation.envelopeHash === undefined\n ) {\n return {\n valid: false,\n reason: 'evidence receipt provenance is not bound by an attestation envelope',\n }\n }\n return { valid: true }\n}\n\n/**\n * Promotion may choose a stricter policy, but this primitive makes the basic separation\n * explicit: only a recognized independent authority is independent. Unknown/forged kinds\n * and candidate self-reports both return false.\n */\nexport function isIndependentEvidence(receipt: EvidenceReceipt): boolean {\n return (INDEPENDENT_EVIDENCE_AUTHORITY_KINDS as readonly string[]).includes(\n receipt.binding.authority?.kind,\n )\n}\n\nfunction requiredAuthority(value: unknown): EvidenceAuthority {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n throw new TypeError('evidence receipt: authority must be an object')\n }\n const authority = value as { kind?: unknown; id?: unknown }\n if (\n typeof authority.kind !== 'string' ||\n !(EVIDENCE_AUTHORITY_KINDS as readonly string[]).includes(authority.kind)\n ) {\n throw new TypeError(`evidence receipt: unknown authority kind '${String(authority.kind)}'`)\n }\n if (typeof authority.id !== 'string') {\n throw new TypeError('evidence receipt: authority.id must be a string')\n }\n return Object.freeze({\n kind: authority.kind as EvidenceAuthorityKind,\n id: requiredIdentity(authority.id, 'authority.id'),\n })\n}\n\nfunction assertInputCommitment(\n provenance: AttestationProvenance,\n inputSetCommitment: string,\n): void {\n if (typeof provenance?.inputsHash !== 'string' || provenance.inputsHash.trim().length === 0) {\n throw new TypeError('evidence receipt: provenance.inputsHash is required')\n }\n if (provenance.inputsHash.trim() !== inputSetCommitment) {\n throw new TypeError(\n 'evidence receipt: provenance.inputsHash must equal binding.inputSetCommitment',\n )\n }\n}\n\nfunction requiredIdentity(value: string, field: string): string {\n const normalized = value.trim()\n if (normalized.length === 0) throw new TypeError(`evidence receipt: ${field} must be non-empty`)\n return normalized\n}\n","/**\n * The evidence registry record — the canonical, machine-readable unit for a\n * measured claim about an agent, a prompt, a policy, or an instrument.\n *\n * One record answers, in typed fields, the questions a scattered results doc\n * leaves to prose: what was claimed, what instrument measured it, the exact\n * command that reproduces it, which arms ran, the denominator, what it cost,\n * what confounds the comparison, and how much trust the evidence has earned.\n *\n * Records live as JSON files in `evidence/records/` at the repo root — one\n * file per claim, filename `<id>.json`. The registry lives in agent-eval\n * because the measurement substrate owns evidence legitimacy; every other\n * repo keeps at most a pointer file. `scripts/render-evidence-index.ts`\n * generates the human index from these records, so prose can never drift\n * from data, and `pnpm run evidence:check` (part of `verify:package`) fails\n * on an invalid record or a stale index.\n *\n * The shape extends the `.evolve/experiments.jsonl` session-log vocabulary\n * (ts/hypothesis/change/result/evidence) into a curated registry record.\n * Session logs stay append-only diaries; a registry record is the durable,\n * addressable claim distilled from them.\n */\n\nimport { z } from 'zod'\n\n/**\n * Trust ladder for a recorded claim, strongest first.\n *\n * - `CERTIFIED` — pre-registered rule, sealed or held-out data, and either a\n * defended challenge or a check that re-runs in the suite.\n * - `MEASURED-ONCE` — one honest measurement on the real path, not replicated.\n * - `RESOLVED-NULL` — measured with an adequate instrument; the effect did not\n * appear under the registered rule. A null is a result, not a failure.\n * - `UNVERIFIED` — stated somewhere load-bearing, but no independent check has\n * run. Admitting this state is what keeps folklore out of the other four.\n * - `KILLED` — refuted, invalidated, or superseded by a stronger record.\n */\nexport const EVIDENCE_STATES = [\n 'CERTIFIED',\n 'MEASURED-ONCE',\n 'RESOLVED-NULL',\n 'UNVERIFIED',\n 'KILLED',\n] as const\n\nexport type EvidenceState = (typeof EVIDENCE_STATES)[number]\n\nconst idPattern = /^[a-z0-9]+(?:-[a-z0-9]+)*$/\nconst datePattern = /^\\d{4}-\\d{2}-\\d{2}$/\nconst sha256Pattern = /^[0-9a-f]{64}$/\n\n/** Denominator of the measurement. A claim without an `n` is prose, not evidence. */\nconst evidenceDenominatorSchema = z.strictObject({\n value: z.number().positive().finite(),\n /** What one unit is: rows, cases, rollouts, records, leaves… */\n unit: z.string().min(1),\n /** Clustering, reps, split names — whatever the bare number hides. */\n detail: z.string().min(1).optional(),\n})\n\nexport type EvidenceDenominator = z.infer<typeof evidenceDenominatorSchema>\n\nexport const evidenceRegistryRecordSchema = z.strictObject({\n /** Stable kebab-case identity; the registry filename is `<id>.json`. */\n id: z.string().regex(idPattern),\n /** Date the decisive measurement completed, `YYYY-MM-DD`. */\n date: z.string().regex(datePattern),\n /** The one-sentence load-bearing claim, stated so it can fail. */\n claim: z.string().min(1),\n /** Domain the claim lives in: trace-repair, multishot, analyst, vertical-bench… */\n domain: z.string().min(1),\n /** The instrument that produced the number — script, harness, oracle, judge. */\n instrument: z.string().min(1),\n /**\n * The exact invocation that reproduces the measurement.\n * `null` means the invocation was not preserved — a named gap, never a guess.\n */\n command: z.string().min(1).nullable(),\n /** Compared arms. Empty for a single-arm measurement. */\n arms: z.array(z.string().min(1)),\n n: evidenceDenominatorSchema,\n /** The measured numbers, with uncertainty when it exists. Numbers, not adjectives. */\n result: z.string().min(1),\n evidenceState: z.enum(EVIDENCE_STATES),\n /** Where the raw data lives: repo paths, PR/gist URLs, run directories. Never empty. */\n artifacts: z.array(z.string().min(1)).min(1),\n /**\n * Measured spend in USD. `0` is a true zero (deterministic, no paid calls);\n * `null` means spend was not captured — a named gap, never a silent zero.\n */\n costUsd: z.number().nonnegative().nullable(),\n /** Every known asymmetry or threat to validity. Empty only when none is known. */\n confounds: z.array(z.string().min(1)),\n /** Repo whose work produced the evidence (the registry itself lives here). */\n sourceRepo: z.string().min(1),\n /** Seal digest of the registered experiment (`./experiment`), when one governed the run. */\n experimentDigest: z.string().regex(sha256Pattern).optional(),\n /** Ids of records this one supersedes. */\n supersedes: z.array(z.string().regex(idPattern)).optional(),\n notes: z.string().min(1).optional(),\n})\n\nexport type EvidenceRegistryRecord = z.infer<typeof evidenceRegistryRecordSchema>\n\n/** Parse one record; throws with the zod issue list on any violation. */\nexport function parseEvidenceRegistryRecord(raw: unknown): EvidenceRegistryRecord {\n return evidenceRegistryRecordSchema.parse(raw)\n}\n\nclass EvidenceRegistryError extends Error {}\n\n/**\n * Validate a set of records as one registry: every record parses, ids are\n * unique, and every `supersedes` target exists. Returns records sorted in\n * the registry's canonical order (trust ladder, then date desc, then id).\n */\nexport function validateEvidenceRegistry(raws: readonly unknown[]): EvidenceRegistryRecord[] {\n const records = raws.map((raw) => parseEvidenceRegistryRecord(raw))\n const seen = new Set<string>()\n for (const record of records) {\n if (seen.has(record.id)) {\n throw new EvidenceRegistryError(`duplicate evidence record id: ${record.id}`)\n }\n seen.add(record.id)\n }\n for (const record of records) {\n for (const target of record.supersedes ?? []) {\n if (!seen.has(target)) {\n throw new EvidenceRegistryError(`record ${record.id} supersedes unknown record: ${target}`)\n }\n }\n }\n const stateRank = new Map(EVIDENCE_STATES.map((state, index) => [state, index]))\n return [...records].sort((a, b) => {\n const byState = (stateRank.get(a.evidenceState) ?? 0) - (stateRank.get(b.evidenceState) ?? 0)\n if (byState !== 0) return byState\n if (a.date !== b.date) return a.date < b.date ? 1 : -1\n return a.id < b.id ? -1 : 1\n })\n}\n\nfunction mdEscape(text: string): string {\n return text.replace(/\\|/g, '\\\\|').replace(/\\n/g, ' ')\n}\n\nfunction formatCost(costUsd: number | null): string {\n if (costUsd === null) return 'not captured'\n return `$${costUsd.toFixed(2)}`\n}\n\nfunction formatN(n: EvidenceDenominator): string {\n const base = `${n.value} ${n.unit}`\n return n.detail ? `${base} (${n.detail})` : base\n}\n\n/**\n * Render the registry's human index from records. Deterministic: identical\n * records always produce identical output, so a byte diff against the\n * committed index is the freshness check. No clocks, no environment.\n */\nexport function renderEvidenceIndex(raws: readonly unknown[]): string {\n const records = validateEvidenceRegistry(raws)\n const lines: string[] = [\n '# Evidence index',\n '',\n '<!-- GENERATED by scripts/render-evidence-index.ts from evidence/records/*.json.',\n ' Edit the records, run `pnpm run evidence:render`, and commit both.',\n ' `pnpm run evidence:check` (inside verify:package) fails when this file drifts. -->',\n '',\n `${records.length} records. States: ${EVIDENCE_STATES.join(' > ')}.`,\n '',\n '| state | date | id | claim | result |',\n '| --- | --- | --- | --- | --- |',\n ]\n for (const r of records) {\n lines.push(\n `| ${r.evidenceState} | ${r.date} | [\\`${r.id}\\`](#${r.id}) | ${mdEscape(r.claim)} | ${mdEscape(r.result)} |`,\n )\n }\n for (const r of records) {\n lines.push('', `## ${r.id}`, '')\n lines.push(`**${r.evidenceState}** · ${r.date} · ${r.domain} · source repo \\`${r.sourceRepo}\\``)\n lines.push('', `**Claim.** ${r.claim}`, '', `**Result.** ${r.result}`, '')\n lines.push(`- **Instrument**: ${r.instrument}`)\n lines.push(`- **Command**: ${r.command === null ? 'not preserved' : `\\`${r.command}\\``}`)\n lines.push(`- **Arms**: ${r.arms.length === 0 ? 'single-arm' : r.arms.join(' vs ')}`)\n lines.push(`- **n**: ${formatN(r.n)}`)\n lines.push(`- **Cost**: ${formatCost(r.costUsd)}`)\n if (r.experimentDigest) lines.push(`- **Experiment seal**: \\`${r.experimentDigest}\\``)\n lines.push(`- **Artifacts**:`)\n for (const artifact of r.artifacts) lines.push(` - ${artifact}`)\n if (r.confounds.length === 0) {\n lines.push('- **Confounds**: none recorded')\n } else {\n lines.push('- **Confounds**:')\n for (const confound of r.confounds) lines.push(` - ${confound}`)\n }\n if (r.supersedes && r.supersedes.length > 0) {\n lines.push(`- **Supersedes**: ${r.supersedes.map((s) => `\\`${s}\\``).join(', ')}`)\n }\n if (r.notes) lines.push(`- **Notes**: ${r.notes}`)\n }\n lines.push('')\n return lines.join('\\n')\n}\n","/**\n * Design-time power for task-clustered paired designs, with a refusal verdict.\n *\n * The failure this prevents (measured): a pre-registered kill test fixed a\n * task-clustered bootstrap over 14 rows in 4 task clusters. Simulated at the\n * registered seed, the design's power topped out at 0.69 — at a per-row\n * effect of 1.0. \"Four clusters cannot certify any effect size, including\n * 1.0\" was learned by running the experiment; this module computes it before\n * a dollar is spent.\n *\n * Two floors, one simulation:\n * - Closed form, zero spend: with C independent clusters the exact\n * whole-cluster sign-flip test can never produce a two-sided p below\n * 2^(1-C). C=4 gives 0.125; C=3 gives 0.25 — both above a 0.05 alpha, so\n * those designs are refused at ANY effect size, before simulation.\n * - Seeded simulation: per-row paired contrasts drawn under a registered\n * effect model, a whole-cluster percentile bootstrap on each trial, power =\n * the fraction of trials whose interval excludes zero.\n *\n * The refusal is a verdict INSIDE the returned artifact (the powerPreflight\n * shape, made cluster-aware); `assertDesignAdequate` turns it into a throw for\n * callers that want configuration-time failure.\n */\n\nimport { ValidationError } from '../errors'\nimport { mulberry32 } from '../statistics'\n\n/** A design refused at configuration time, before any spend. */\nexport class DesignRefusalError extends ValidationError {}\n\nexport interface ClusteredPowerOptions {\n /** Rows per independent cluster, e.g. [6, 3, 3, 2]. */\n clusterSizes: number[]\n /** Per-row effect grid: each effect is P(win) - P(loss) added to the base rates. */\n effects: number[]\n /** Deterministic seed for outcome draws and bootstrap resampling. */\n seed: number\n /** Simulated experiments per effect. Default 2000. */\n trials?: number\n /** Whole-cluster bootstrap draws per trial. Default 4000. */\n resamples?: number\n /** Percentile interval level. Default 0.95. */\n confidence?: number\n /** Sign-flip alpha the closed-form floor is checked against. Default 0.05. */\n alpha?: number\n /** Power the design must reach at some grid effect. Default 0.8. */\n targetPower?: number\n /** Base P(row favors treatment) with no effect. Default 0.10 (tie-heavy rows). */\n baseWinRate?: number\n /** Base P(row favors control). Default 0.10. */\n baseLossRate?: number\n /**\n * Clusters whose rows carry outcome noise instead of signal: each row wins\n * with `flipRate` and loses with `flipRate`, independent of the effect.\n * Index into `clusterSizes`.\n */\n noisyClusters?: { index: number; flipRate: number }[]\n}\n\nexport interface ClusteredPowerPoint {\n effect: number\n power: number\n medianCiWidth: number\n}\n\nexport interface SignFlipFloor {\n /** Smallest achievable two-sided p: 2^(1-C) for C clusters. */\n twoSidedP: number\n /** Smallest achievable one-sided p: 2^-C. */\n oneSidedP: number\n alpha: number\n /** False when the cluster count can never certify at `alpha`, at any effect. */\n certifiableAtAlpha: boolean\n /** Smallest cluster count whose two-sided floor is at or under `alpha`. */\n minClustersForAlpha: number\n}\n\nexport interface ClusteredPowerRefusal {\n verdict: 'underpowered'\n reasons: string[]\n recommendation: string\n}\n\nexport interface ClusteredPowerResult {\n clusterCount: number\n totalRows: number\n trials: number\n resamples: number\n seed: number\n confidence: number\n targetPower: number\n curve: ClusteredPowerPoint[]\n /** Maximum simulated power across the effect grid. */\n maxPower: number\n signFlipFloor: SignFlipFloor\n /** True only when the sign-flip floor certifies AND simulation reaches target. */\n adequate: boolean\n /** Populated exactly when `adequate` is false. The refusal lives in the artifact. */\n refusal: ClusteredPowerRefusal | null\n}\n\n/**\n * Simulate the power of a whole-cluster percentile-bootstrap design and refuse\n * a structure that cannot reach the target at any registered effect.\n */\nexport function clusteredPower(options: ClusteredPowerOptions): ClusteredPowerResult {\n const clusterSizes = options.clusterSizes\n if (clusterSizes.length === 0 || clusterSizes.some((n) => !Number.isInteger(n) || n <= 0)) {\n throw new ValidationError(\n `clusteredPower: clusterSizes must be positive integers, got [${clusterSizes.join(', ')}]`,\n )\n }\n if (options.effects.length === 0) {\n throw new ValidationError('clusteredPower: effects grid is empty')\n }\n if (!Number.isInteger(options.seed)) {\n throw new ValidationError(`clusteredPower: seed must be an integer, got ${options.seed}`)\n }\n const trials = options.trials ?? 2000\n const resamples = options.resamples ?? 4000\n if (!Number.isInteger(trials) || trials <= 0 || !Number.isInteger(resamples) || resamples <= 0) {\n throw new ValidationError(\n `clusteredPower: trials and resamples must be positive integers, got ${trials}/${resamples}`,\n )\n }\n const confidence = options.confidence ?? 0.95\n if (confidence <= 0 || confidence >= 1) {\n throw new ValidationError(`clusteredPower: confidence must be in (0,1), got ${confidence}`)\n }\n const alpha = options.alpha ?? 0.05\n const targetPower = options.targetPower ?? 0.8\n const baseWinRate = options.baseWinRate ?? 0.1\n const baseLossRate = options.baseLossRate ?? 0.1\n const noisy = new Map<number, number>()\n for (const cluster of options.noisyClusters ?? []) {\n if (cluster.index < 0 || cluster.index >= clusterSizes.length) {\n throw new ValidationError(\n `clusteredPower: noisy cluster index ${cluster.index} outside [0,${clusterSizes.length - 1}]`,\n )\n }\n noisy.set(cluster.index, cluster.flipRate)\n }\n\n const clusterCount = clusterSizes.length\n const totalRows = clusterSizes.reduce((a, b) => a + b, 0)\n const signFlipFloor = computeSignFlipFloor(clusterCount, alpha)\n\n const curve: ClusteredPowerPoint[] = []\n for (const effect of options.effects) {\n curve.push(\n simulateEffect(effect, {\n clusterSizes,\n seed: options.seed,\n trials,\n resamples,\n confidence,\n baseWinRate,\n baseLossRate,\n noisy,\n }),\n )\n }\n const maxPower = Math.max(...curve.map((point) => point.power))\n\n const reasons: string[] = []\n if (!signFlipFloor.certifiableAtAlpha) {\n reasons.push(\n `${clusterCount} clusters cannot certify any effect size, including 1.0: the exact ` +\n `whole-cluster sign-flip test's smallest two-sided p is 2^(1-${clusterCount}) = ` +\n `${signFlipFloor.twoSidedP} > alpha ${alpha}; at least ` +\n `${signFlipFloor.minClustersForAlpha} clusters are needed`,\n )\n }\n if (maxPower < targetPower) {\n const best = curve.reduce((a, b) => (b.power > a.power ? b : a))\n reasons.push(\n `simulated power tops out at ${maxPower.toFixed(3)} (effect ${best.effect}) across the ` +\n `registered grid — below the ${targetPower} target at every effect`,\n )\n }\n const adequate = reasons.length === 0\n return {\n clusterCount,\n totalRows,\n trials,\n resamples,\n seed: options.seed,\n confidence,\n targetPower,\n curve,\n maxPower,\n signFlipFloor,\n adequate,\n refusal: adequate\n ? null\n : {\n verdict: 'underpowered',\n reasons,\n recommendation:\n `Do not spend on this structure. Add independent clusters (>= ` +\n `${Math.max(signFlipFloor.minClustersForAlpha, clusterCount)}) or register a design ` +\n `whose simulated power reaches ${targetPower}, then re-run clusteredPower.`,\n },\n }\n}\n\n/** Throw the refusal for callers that want configuration-time failure. */\nexport function assertDesignAdequate(result: ClusteredPowerResult): void {\n if (result.refusal) {\n throw new DesignRefusalError(\n `design refused (underpowered): ${result.refusal.reasons.join('; ')}`,\n )\n }\n}\n\nfunction computeSignFlipFloor(clusterCount: number, alpha: number): SignFlipFloor {\n const twoSidedP = 2 ** (1 - clusterCount)\n const oneSidedP = 2 ** -clusterCount\n let minClusters = 1\n while (2 ** (1 - minClusters) > alpha) minClusters += 1\n return {\n twoSidedP,\n oneSidedP,\n alpha,\n certifiableAtAlpha: twoSidedP <= alpha,\n minClustersForAlpha: minClusters,\n }\n}\n\ninterface SimulationConfig {\n clusterSizes: number[]\n seed: number\n trials: number\n resamples: number\n confidence: number\n baseWinRate: number\n baseLossRate: number\n noisy: Map<number, number>\n}\n\n/**\n * One effect point. Per row the paired contrast is +1 with probability\n * min(baseWin + effect, 1), -1 with the base loss rate (capped by what\n * remains), else 0. Noisy clusters draw win and loss independently at their\n * flip rate. Each trial computes a whole-cluster percentile bootstrap of the\n * pooled row mean; the trial counts toward power when the interval excludes\n * zero.\n */\nfunction simulateEffect(effect: number, config: SimulationConfig): ClusteredPowerPoint {\n const rng = mulberry32(mixSeed(config.seed, effect))\n const clusterCount = config.clusterSizes.length\n let excludes = 0\n const widths = new Array<number>(config.trials)\n const sums = new Array<number>(clusterCount)\n const means = new Array<number>(config.resamples)\n for (let trial = 0; trial < config.trials; trial++) {\n for (let cluster = 0; cluster < clusterCount; cluster++) {\n const size = config.clusterSizes[cluster]!\n const flipRate = config.noisy.get(cluster)\n let sum = 0\n for (let row = 0; row < size; row++) {\n if (flipRate !== undefined) {\n const win = rng() < flipRate ? 1 : 0\n const loss = rng() < flipRate ? 1 : 0\n sum += win - loss\n } else {\n const winRate = Math.min(1, config.baseWinRate + effect)\n const lossRate = Math.min(1 - winRate, config.baseLossRate)\n const u = rng()\n sum += u < winRate ? 1 : u < winRate + lossRate ? -1 : 0\n }\n }\n sums[cluster] = sum\n }\n for (let draw = 0; draw < config.resamples; draw++) {\n let pooledSum = 0\n let pooledRows = 0\n for (let pick = 0; pick < clusterCount; pick++) {\n const index = Math.floor(rng() * clusterCount)\n pooledSum += sums[index]!\n pooledRows += config.clusterSizes[index]!\n }\n means[draw] = pooledSum / pooledRows\n }\n means.sort((a, b) => a - b)\n const tail = 1 - config.confidence\n const lower = means[Math.floor((tail / 2) * config.resamples)]!\n const upper =\n means[\n Math.max(\n Math.floor((tail / 2) * config.resamples),\n Math.min(config.resamples - 1, Math.ceil((1 - tail / 2) * config.resamples) - 1),\n )\n ]!\n widths[trial] = upper - lower\n if (lower > 0 || upper < 0) excludes += 1\n }\n widths.sort((a, b) => a - b)\n return {\n effect,\n power: excludes / config.trials,\n medianCiWidth: widths[Math.floor(config.trials / 2)]!,\n }\n}\n\n/** Fold the effect into the seed so every grid point draws an independent stream. */\nfunction mixSeed(seed: number, effect: number): number {\n const scaled = Math.round(effect * 1_000_003)\n return ((seed ^ (scaled * 0x9e3779b9)) >>> 0) | 0\n}\n"],"mappings":"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"}
|