peeksafe 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/CHANGELOG.md +146 -0
  2. package/LICENSE +190 -0
  3. package/NOTICE +78 -0
  4. package/README.md +492 -2
  5. package/RESEARCH-NOTES.md +274 -0
  6. package/dist/baseline.d.ts +45 -0
  7. package/dist/baseline.d.ts.map +1 -0
  8. package/dist/baseline.js +49 -0
  9. package/dist/baseline.js.map +1 -0
  10. package/dist/check.d.ts +64 -0
  11. package/dist/check.d.ts.map +1 -0
  12. package/dist/check.js +172 -0
  13. package/dist/check.js.map +1 -0
  14. package/dist/cluster.d.ts +328 -0
  15. package/dist/cluster.d.ts.map +1 -0
  16. package/dist/cluster.js +598 -0
  17. package/dist/cluster.js.map +1 -0
  18. package/dist/errors.d.ts +87 -0
  19. package/dist/errors.d.ts.map +1 -0
  20. package/dist/errors.js +143 -0
  21. package/dist/errors.js.map +1 -0
  22. package/dist/evidence.d.ts +15 -0
  23. package/dist/evidence.d.ts.map +1 -0
  24. package/dist/evidence.js +30 -0
  25. package/dist/evidence.js.map +1 -0
  26. package/dist/frontier.d.ts +269 -0
  27. package/dist/frontier.d.ts.map +1 -0
  28. package/dist/frontier.js +460 -0
  29. package/dist/frontier.js.map +1 -0
  30. package/dist/gate.d.ts +173 -0
  31. package/dist/gate.d.ts.map +1 -0
  32. package/dist/gate.js +196 -0
  33. package/dist/gate.js.map +1 -0
  34. package/dist/index.d.ts +60 -0
  35. package/dist/index.d.ts.map +1 -0
  36. package/dist/index.js +79 -0
  37. package/dist/index.js.map +1 -0
  38. package/dist/plan.d.ts +248 -0
  39. package/dist/plan.d.ts.map +1 -0
  40. package/dist/plan.js +482 -0
  41. package/dist/plan.js.map +1 -0
  42. package/dist/rand.d.ts +17 -0
  43. package/dist/rand.d.ts.map +1 -0
  44. package/dist/rand.js +92 -0
  45. package/dist/rand.js.map +1 -0
  46. package/dist/stats.d.ts +397 -0
  47. package/dist/stats.d.ts.map +1 -0
  48. package/dist/stats.js +1245 -0
  49. package/dist/stats.js.map +1 -0
  50. package/dist/stop.d.ts +163 -0
  51. package/dist/stop.d.ts.map +1 -0
  52. package/dist/stop.js +262 -0
  53. package/dist/stop.js.map +1 -0
  54. package/package.json +64 -4
  55. package/src/baseline.ts +72 -0
  56. package/src/check.ts +238 -0
  57. package/src/cluster.ts +830 -0
  58. package/src/errors.ts +208 -0
  59. package/src/evidence.ts +62 -0
  60. package/src/frontier.ts +782 -0
  61. package/src/gate.ts +358 -0
  62. package/src/index.ts +206 -0
  63. package/src/plan.ts +778 -0
  64. package/src/rand.ts +121 -0
  65. package/src/stats.ts +1579 -0
  66. package/src/stop.ts +452 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gate.d.ts","sourceRoot":"","sources":["../src/gate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAQlD,OAAO,EAEL,KAAK,QAAQ,EAId,MAAM,eAAe,CAAC;AACvB,OAAO,EAIL,KAAK,YAAY,EAElB,MAAM,YAAY,CAAC;AAEpB;;;GAGG;AACH,eAAO,MAAM,YAAY,aACb;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,OAC1C,MAAM,KACV,OAAsD,CAAC;AAE1D,4EAA4E;AAC5E,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,sDAAsD;IACtD,SAAS,EAAE,MAAM,CAAC;IAClB,sEAAsE;IACtE,MAAM,EAAE,MAAM,CAAC;IACf,gFAAgF;IAChF,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,MAAM,CAAC,EAAE,SAAS,CAAC;CACpB;AAED,8EAA8E;AAC9E,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,qDAAqD;IACrD,MAAM,EAAE,YAAY,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,iFAAiF;IACjF,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,oDAAoD;IACpD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;;OAIG;IACH,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB;AAED,eAAO,MAAM,oBAAoB;aAC/B,GAAG,EAAE,IAAI;aACT,GAAG,EAAE,IAAI;aACT,gBAAgB,EAAE,CAAC;aACnB,QAAQ,EAAE,OAAO;CACT,CAAC;AAEX,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,0EAA0E;IAC1E,SAAS,EAAE,OAAO,CAAC;IACnB,6DAA6D;IAC7D,MAAM,EAAE,MAAM,CAAC;IACf,oEAAoE;IACpE,IAAI,EAAE,MAAM,CAAC;IACb;;;;;OAKG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB,kEAAkE;IAClE,YAAY,EAAE,OAAO,CAAC;IACtB;;;;OAIG;IACH,UAAU,EAAE,OAAO,CAAC;IACpB,qEAAqE;IACrE,QAAQ,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAChD,QAAQ,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAChD,MAAM,EAAE,UAAU,GAAG,QAAQ,CAAC;IAC9B,yCAAyC;IACzC,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB;AAED,MAAM,WAAW,UAAU;IACzB,oDAAoD;IACpD,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,wDAAwD;IACxD,SAAS,EAAE,WAAW,EAAE,CAAC;IACzB;;;OAGG;IACH,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,4EAA4E;IAC5E,SAAS,EAAE,MAAM,CAAC;IAClB,4EAA4E;IAC5E,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC;IAC/B;;;;;;;OAOG;IACH,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;GAMG;AACH,wBAAgB,IAAI,CAClB,KAAK,EAAE,SAAS,CAAC,QAAQ,GAAG,cAAc,CAAC,EAAE,EAC7C,OAAO,GAAE,WAAgB,GACxB,UAAU,CAiKZ"}
package/dist/gate.js ADDED
@@ -0,0 +1,196 @@
1
+ /**
2
+ * gate.ts: the decision.
3
+ *
4
+ * You bring counts. This decides which cases regressed, at a false discovery
5
+ * rate you name, in a way that stays valid however many times you looked at the
6
+ * data on the way here.
7
+ *
8
+ * ## Why this is safe to peek at
9
+ *
10
+ * The usual construction is: run the suite, stop a case when it looks
11
+ * significant, compute a p-value from the counts, hand the p-values to
12
+ * Benjamini-Hochberg. That is invalid in two independent places.
13
+ *
14
+ * A p-value computed at a stopping boundary is not a p-value. `P(p_n <= a) <= a`
15
+ * holds for each fixed `n`; a procedure that adds runs and re-tests until the
16
+ * result looks significant reports `min` over the peeks, and that minimum is not
17
+ * bounded by `a`. Benjamini-Hochberg takes `P(p <= t) <= t` as its input
18
+ * assumption, so it inherits nothing and controls nothing.
19
+ *
20
+ * This module never computes a p-value. It computes an e-value, which is a
21
+ * non-negative statistic with mean at most 1 under the null. Ville's inequality
22
+ * bounds `P(sup_n E_n >= 1/a) <= a` over the whole trajectory, so an e-value is
23
+ * valid at any stopping time, including one chosen after looking. (The mean is
24
+ * exactly 1 averaged over the shared rate, not at every fixed rate; the README
25
+ * section "What that guarantee rests on" says where the bound is checked.) The
26
+ * multiplicity correction is e-BH (Wang and Ramdas), which takes e-values
27
+ * directly and controls FDR under arbitrary dependence between cases.
28
+ *
29
+ * The practical consequence: you may stop a case whenever you like, for any
30
+ * reason, including "it already looks bad". Nothing here cares when you stopped.
31
+ *
32
+ * ## What it will refuse to do
33
+ *
34
+ * Gate a case with no baseline. There is no null to test against, and the
35
+ * failure mode of inventing one is not a wrong number, it is a confident wrong
36
+ * number: a missing baseline read as `0/0` has a Beta(1,1) posterior median of
37
+ * 0.5, which gates the case against "it passes half the time" and reports a
38
+ * large improvement against nothing at all. Cases without a baseline come back
39
+ * in `newCases` and take no part in the verdict or the e-BH family.
40
+ *
41
+ * ## Paired cases
42
+ *
43
+ * A case may instead carry `paired` counts from re-running the baseline next to
44
+ * the candidate, one baseline run per candidate run. Its e-value is
45
+ * `pairedLogE` on the discordant pairs, which is valid at every rate by
46
+ * construction and has no ceiling, whichever `evidence` the unpaired cases use.
47
+ * The pairs need not share a seed: independent runs paired in order are still
48
+ * valid, and a shared seed only makes discordances more informative.
49
+ */
50
+ import { PeeksafeError, requireAltConcentration, requireCounts, requireOpenProbability, requirePairedCounts, } from "./errors.js";
51
+ import { ceilingLogEvidence, logEvidence, requireEvidence, toEvalue, } from "./evidence.js";
52
+ import { discordant, ebhCorrect, ebhSoloThreshold, pairedLogE, } from "./stats.js";
53
+ /**
54
+ * True when the baseline's observed rate leaves no room for an `mde`-sized drop.
55
+ * `makePlan` calls the same cases IMPOSSIBLE, by the same rule.
56
+ */
57
+ export const cannotDropBy = (baseline, mde) => baseline.successes / baseline.trials <= mde;
58
+ export const DEFAULT_GATE_OPTIONS = {
59
+ mde: 0.15,
60
+ fdr: 0.05,
61
+ altConcentration: 8,
62
+ evidence: "bayes",
63
+ };
64
+ /**
65
+ * Decide which cases regressed.
66
+ *
67
+ * Valid at any stopping time. Run every case to a fixed count, or stop each one
68
+ * the moment it looks decided, or anything in between; the guarantee does not
69
+ * depend on the rule you used.
70
+ */
71
+ export function gate(cases, options = {}) {
72
+ const opts = { ...DEFAULT_GATE_OPTIONS, ...options };
73
+ requireOpenProbability(opts.mde, "mde", "gate");
74
+ requireOpenProbability(opts.fdr, "fdr", "gate");
75
+ requireEvidence(opts.evidence, "gate");
76
+ requireAltConcentration(opts.altConcentration, opts.evidence, "gate");
77
+ const seen = new Set();
78
+ for (const c of cases) {
79
+ if (seen.has(c.id)) {
80
+ throw new PeeksafeError("PEEKSAFE_E_CASE_DUPLICATE", `gate: duplicate case id ${c.id}`, {
81
+ detail: { id: c.id },
82
+ hint: "two cases sharing an id would be merged into one baseline entry and counted once",
83
+ });
84
+ }
85
+ seen.add(c.id);
86
+ if (c.paired) {
87
+ requirePairedCounts(c.paired, `gate(${c.id}).paired`);
88
+ continue;
89
+ }
90
+ requireCounts(c.successes, c.trials, `gate(${c.id})`);
91
+ if (c.baseline)
92
+ requireCounts(c.baseline.successes, c.baseline.trials, `gate(${c.id}).baseline`);
93
+ }
94
+ const hasBaseline = (c) => c.paired !== undefined || (c.baseline !== undefined && c.baseline.trials > 0);
95
+ const newCases = cases.filter((c) => !hasBaseline(c)).map((c) => c.id);
96
+ const gated = cases.filter(hasBaseline);
97
+ if (gated.length === 0) {
98
+ throw new PeeksafeError("PEEKSAFE_E_BASELINE_MISSING", "gate: no case has a baseline, so there is nothing to test against", {
99
+ detail: { cases: cases.length, newCases: newCases.length },
100
+ hint: 'record a baseline on the reference revision first; gating without one compares against a Beta(1,1) prior, which reads as "this case passes half the time"',
101
+ });
102
+ }
103
+ const m = gated.length;
104
+ // Testing these anyway clamps the alternative onto a rate near zero, which is
105
+ // where the case already sits, and the false positive rate then exceeds `fdr`.
106
+ // A paired case has an exact null and never needs this.
107
+ const impossible = gated.map((c) => !c.paired && cannotDropBy(c.baseline, opts.mde));
108
+ const logEs = gated.map((c, i) => {
109
+ if (c.paired)
110
+ return pairedLogE(c.paired.worse, discordant(c.paired));
111
+ return impossible[i]
112
+ ? 0
113
+ : logEvidence(opts.evidence, c.successes, c.trials, c.baseline.successes, c.baseline.trials, opts.mde, opts.altConcentration);
114
+ });
115
+ const evalues = logEs.map(toEvalue);
116
+ const ebh = ebhCorrect(evalues, opts.fdr);
117
+ const solo = ebhSoloThreshold(m, opts.fdr);
118
+ const verdicts = gated.map((c, i) => {
119
+ const shared = { id: c.id, regressed: ebh.rejected[i], evalue: evalues[i], logE: logEs[i] };
120
+ if (c.paired) {
121
+ const p = c.paired;
122
+ const pairs = p.bothPass + p.worse + p.better + p.bothFail;
123
+ return {
124
+ ...shared,
125
+ ceiling: Infinity,
126
+ undetectable: false,
127
+ impossible: false,
128
+ observed: { successes: p.bothPass + p.better, trials: pairs },
129
+ baseline: { successes: p.bothPass + p.worse, trials: pairs },
130
+ design: "paired",
131
+ paired: { ...p },
132
+ };
133
+ }
134
+ // The ceiling is evaluated at the rate a regression would actually sit at,
135
+ // one MDE below the baseline's own rate. That is the alternative the gate is
136
+ // trying to detect, so it is the right place to ask "could this ever clear
137
+ // the bar". Matches how plan.ts prices the same case.
138
+ const bRate = c.baseline.successes / c.baseline.trials;
139
+ const pAlt = Math.max(1e-6, Math.min(1 - 1e-6, bRate - opts.mde));
140
+ const ceiling = impossible[i]
141
+ ? 1
142
+ : Math.exp(ceilingLogEvidence(opts.evidence, pAlt, c.baseline.successes, c.baseline.trials, opts.mde, opts.altConcentration));
143
+ return {
144
+ ...shared,
145
+ ceiling,
146
+ undetectable: !impossible[i] && ceiling < solo,
147
+ impossible: impossible[i],
148
+ observed: { successes: c.successes, trials: c.trials },
149
+ baseline: { successes: c.baseline.successes, trials: c.baseline.trials },
150
+ design: "unpaired",
151
+ };
152
+ });
153
+ const regressed = verdicts.filter((v) => v.regressed);
154
+ const blind = verdicts.filter((v) => v.undetectable && !v.regressed);
155
+ const untested = verdicts.filter((v) => v.impossible);
156
+ const caveats = [];
157
+ if (blind.length > 0) {
158
+ caveats.push(`${blind.length} of ${m} gated case(s) have a baseline too thin to certify a ` +
159
+ `${(opts.mde * 100).toFixed(0)}pt drop at any candidate budget (${blind
160
+ .slice(0, 3)
161
+ .map((v) => v.id)
162
+ .join(", ")}` +
163
+ `${blind.length > 3 ? ", …" : ""}), which needs more baseline runs, not more candidate runs`);
164
+ }
165
+ if (untested.length > 0) {
166
+ caveats.push(`${untested.length} case(s) pass at or below ${(opts.mde * 100).toFixed(0)}% and cannot drop by ` +
167
+ `${(opts.mde * 100).toFixed(0)}pts, so they were not tested (${untested
168
+ .slice(0, 3)
169
+ .map((v) => v.id)
170
+ .join(", ")}` +
171
+ `${untested.length > 3 ? ", …" : ""})`);
172
+ }
173
+ if (newCases.length > 0) {
174
+ caveats.push(`${newCases.length} case(s) have no baseline and were not gated ` +
175
+ `(${newCases.slice(0, 3).join(", ")}${newCases.length > 3 ? ", …" : ""})`);
176
+ }
177
+ const headline = (regressed.length === 0
178
+ ? `PASS: no case cleared the bar of ${solo.toFixed(0)} at ${(opts.fdr * 100).toFixed(0)}% FDR over ${m} gated case(s)`
179
+ : `FAIL: ${regressed.length} of ${m} gated case(s) certified as regressed at ${(opts.fdr * 100).toFixed(0)}% FDR ` +
180
+ `(${regressed
181
+ .slice(0, 3)
182
+ .map((v) => v.id)
183
+ .join(", ")}${regressed.length > 3 ? ", …" : ""})`) +
184
+ (caveats.length > 0 ? `. Read with care: ${caveats.join("; ")}.` : "");
185
+ return {
186
+ verdict: regressed.length === 0 ? "PASS" : "FAIL",
187
+ cases: verdicts,
188
+ regressed,
189
+ newCases,
190
+ threshold: ebh.threshold,
191
+ soloThreshold: solo,
192
+ options: opts,
193
+ headline,
194
+ };
195
+ }
196
+ //# sourceMappingURL=gate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gate.js","sourceRoot":"","sources":["../src/gate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * peeksafe: statistically valid gates for non-deterministic eval suites.
3
+ *
4
+ * The problem this exists for: you run an eval suite, watch results arrive, stop
5
+ * a case when it looks decided, then correct for multiplicity with
6
+ * Benjamini-Hochberg. That construction has no error control. A p-value computed
7
+ * at a stopping boundary is not a p-value, and BH assumes it is.
8
+ *
9
+ * The library is organised in four layers, and most callers only need the first.
10
+ *
11
+ * ## 1. The decision
12
+ *
13
+ * gate(cases, options) which cases regressed, valid at any stopping time
14
+ *
15
+ * You bring counts. It brings e-values and e-BH. Nothing here knows or cares how
16
+ * you ran the evals, and nothing here will gate a case that has no baseline.
17
+ *
18
+ * ## 2. The budget
19
+ *
20
+ * makePlan(...) how many runs each case needs, and which are impossible
21
+ * computeFrontier(...) what is certifiable inside a budget
22
+ * affordabilityGrid(...) the same question as a grid over two axes
23
+ *
24
+ * These answer "how many runs do I need" before you spend anything, including
25
+ * the case where the honest answer is that no candidate budget will do and only
26
+ * more baseline runs will.
27
+ *
28
+ * ## 3. The check
29
+ *
30
+ * typeOneError(...) the error rate the gate delivers at rates you name
31
+ * certifyProbability(...) the same computation with separate baseline and candidate rates
32
+ * pairedCertifyProbability(...) the power of a paired design
33
+ *
34
+ * These are exact, not simulated, so a caller can check the gate on their own
35
+ * rates before trusting a verdict.
36
+ *
37
+ * ## 4. The statistics
38
+ *
39
+ * Everything the first two layers are built from, exported so a caller can check
40
+ * the arithmetic, build a different gate, or use one piece on its own: special
41
+ * functions, intervals, the SPRT, e-values, e-BH, power, paired designs, and the
42
+ * cluster-robust suite summary.
43
+ *
44
+ * Cases in a suite are not independent draws. Several cases generated from one
45
+ * source file share a failure mode, so a change that breaks the file moves all
46
+ * of them together. `clusteredEffect` and the rest of `cluster` are what stop
47
+ * the suite-level interval from being too narrow for that reason.
48
+ */
49
+ export { type BaselineStat, baselineNullRate, type CaseRef, toBaselineMap, } from "./baseline.js";
50
+ export { type CertifyProbabilityOptions, certifyProbability, type PairedCertifyProbabilityOptions, pairedCertifyProbability, type TypeOneErrorOptions, typeOneError, } from "./check.js";
51
+ export { type ClusteredEffect, type ClusteredMean, type ClusterKeyDiagnostic, type ClusterObservation, caseFamily, clusteredEffect, clusterKey, clusterKeyDiagnostic, clusterRobustMean, compareEstimators, type FamilyEffect, type GroupingSummary, groupByCluster, iidMean, MIN_TRUSTWORTHY_CLUSTERS, type RandomEffectsMean, randomEffectsMean, } from "./cluster.js";
52
+ export { MAX_ALT_CONCENTRATION, PeeksafeError, type PeeksafeErrorCode, type PeeksafeErrorOptions, } from "./errors.js";
53
+ export type { Evidence } from "./evidence.js";
54
+ export { computeFrontier, costShares, DEFAULT_AXES, DEFAULT_FRONTIER, enumerateFrontier, evaluatePoint, type FrontierAxes, type FrontierBasis, type FrontierCell, type FrontierConfig, type FrontierCost, type FrontierDesign, type FrontierPoint, type FrontierResult, type FrontierScreen, fmtRate, typicalObservationsPerCase, } from "./frontier.js";
55
+ export { type CaseVerdict, DEFAULT_GATE_OPTIONS, type GateCase, type GateOptions, type GateResult, gate, type PairedGateCase, } from "./gate.js";
56
+ export { type AffordabilityCell, affordabilityGrid, DEFAULT_PLAN, type Detectability, expectedSequentialSamples, makePlan, type Plan, type PlanCase, type PlanConfig, type PlanTotals, planCase, } from "./plan.js";
57
+ export { hash32, makeRand, type Rand, streamFor } from "./rand.js";
58
+ export { type BetaPosterior, type BhResult, bernoulliEntropy, betaCredibleInterval, betaMassBetween, betaPosterior, betaQuantile, bhCorrect, cohensH, diffInterval, discordant, type EbhResult, ebhCorrect, ebhSoloThreshold, erf, evidenceCeilingAsymptotic, evidenceCeilingLogE, evidenceCeilingSlope, expectedLogE, expectedLogEExact, fisherExact2x2, gammaP, type Interval, ibeta, logBeta, logBetaPdf, logGamma, logMarginalBetaBinomial, mcnemarSamplesForEvidence, normalCdf, normalQuantile, type PairedCounts, pairedDiscordance, pairedLogE, pairPhi, probabilityMoved, type SprtDecision, type SprtOpts, type SprtResult, sampleSizeTwoProportion, samplesForEvidence, sprtDecision, sprtExpectedN, type TestResult, twoProportionZTest, twoSampleLogE, twoSamplePriors, universalCeilingLogE, universalTwoSampleLogE, wilsonInterval, } from "./stats.js";
59
+ export { DEFAULT_STOP_OPTIONS, type PairedStopDecision, type PairedStopOptions, type PairedStopReason, type StopDecision, type StopOptions, type StopReason, shouldStop, shouldStopPaired, } from "./stop.js";
60
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js ADDED
@@ -0,0 +1,79 @@
1
+ /**
2
+ * peeksafe: statistically valid gates for non-deterministic eval suites.
3
+ *
4
+ * The problem this exists for: you run an eval suite, watch results arrive, stop
5
+ * a case when it looks decided, then correct for multiplicity with
6
+ * Benjamini-Hochberg. That construction has no error control. A p-value computed
7
+ * at a stopping boundary is not a p-value, and BH assumes it is.
8
+ *
9
+ * The library is organised in four layers, and most callers only need the first.
10
+ *
11
+ * ## 1. The decision
12
+ *
13
+ * gate(cases, options) which cases regressed, valid at any stopping time
14
+ *
15
+ * You bring counts. It brings e-values and e-BH. Nothing here knows or cares how
16
+ * you ran the evals, and nothing here will gate a case that has no baseline.
17
+ *
18
+ * ## 2. The budget
19
+ *
20
+ * makePlan(...) how many runs each case needs, and which are impossible
21
+ * computeFrontier(...) what is certifiable inside a budget
22
+ * affordabilityGrid(...) the same question as a grid over two axes
23
+ *
24
+ * These answer "how many runs do I need" before you spend anything, including
25
+ * the case where the honest answer is that no candidate budget will do and only
26
+ * more baseline runs will.
27
+ *
28
+ * ## 3. The check
29
+ *
30
+ * typeOneError(...) the error rate the gate delivers at rates you name
31
+ * certifyProbability(...) the same computation with separate baseline and candidate rates
32
+ * pairedCertifyProbability(...) the power of a paired design
33
+ *
34
+ * These are exact, not simulated, so a caller can check the gate on their own
35
+ * rates before trusting a verdict.
36
+ *
37
+ * ## 4. The statistics
38
+ *
39
+ * Everything the first two layers are built from, exported so a caller can check
40
+ * the arithmetic, build a different gate, or use one piece on its own: special
41
+ * functions, intervals, the SPRT, e-values, e-BH, power, paired designs, and the
42
+ * cluster-robust suite summary.
43
+ *
44
+ * Cases in a suite are not independent draws. Several cases generated from one
45
+ * source file share a failure mode, so a change that breaks the file moves all
46
+ * of them together. `clusteredEffect` and the rest of `cluster` are what stop
47
+ * the suite-level interval from being too narrow for that reason.
48
+ */
49
+ export { baselineNullRate, toBaselineMap, } from "./baseline.js";
50
+ export { certifyProbability, pairedCertifyProbability, typeOneError, } from "./check.js";
51
+ export { caseFamily, clusteredEffect, clusterKey, clusterKeyDiagnostic, clusterRobustMean, compareEstimators, groupByCluster, iidMean, MIN_TRUSTWORTHY_CLUSTERS, randomEffectsMean, } from "./cluster.js";
52
+ /* ── errors and determinism ──────────────────────────────────────────────── */
53
+ export { MAX_ALT_CONCENTRATION, PeeksafeError, } from "./errors.js";
54
+ export { computeFrontier, costShares, DEFAULT_AXES, DEFAULT_FRONTIER, enumerateFrontier, evaluatePoint, fmtRate, typicalObservationsPerCase, } from "./frontier.js";
55
+ /* ── 1. the decision ─────────────────────────────────────────────────────── */
56
+ export { DEFAULT_GATE_OPTIONS, gate, } from "./gate.js";
57
+ /* ── 2. the budget ───────────────────────────────────────────────────────── */
58
+ export { affordabilityGrid, DEFAULT_PLAN, expectedSequentialSamples, makePlan, planCase, } from "./plan.js";
59
+ export { hash32, makeRand, streamFor } from "./rand.js";
60
+ /* ── 3. the statistics ───────────────────────────────────────────────────── */
61
+ export { bernoulliEntropy, betaCredibleInterval, betaMassBetween, betaPosterior, betaQuantile,
62
+ /* multiplicity */
63
+ bhCorrect, cohensH, diffInterval, discordant, ebhCorrect, ebhSoloThreshold, erf, evidenceCeilingAsymptotic, evidenceCeilingLogE, evidenceCeilingSlope, expectedLogE, expectedLogEExact, fisherExact2x2, gammaP, ibeta, logBeta, logBetaPdf,
64
+ /* special functions */
65
+ logGamma,
66
+ /* e-values */
67
+ logMarginalBetaBinomial, mcnemarSamplesForEvidence, normalCdf, normalQuantile, pairedDiscordance,
68
+ /* paired designs */
69
+ pairedLogE, pairPhi, probabilityMoved,
70
+ /* power */
71
+ sampleSizeTwoProportion, samplesForEvidence,
72
+ /* sequential */
73
+ sprtDecision, sprtExpectedN,
74
+ /* fixed-sample tests, for comparison rather than for gating */
75
+ twoProportionZTest, twoSampleLogE, twoSamplePriors, universalCeilingLogE, universalTwoSampleLogE,
76
+ /* intervals and posteriors */
77
+ wilsonInterval, } from "./stats.js";
78
+ export { DEFAULT_STOP_OPTIONS, shouldStop, shouldStopPaired, } from "./stop.js";
79
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AAEH,OAAO,EAEL,gBAAgB,EAEhB,aAAa,GACd,MAAM,eAAe,CAAC;AACvB,OAAO,EAEL,kBAAkB,EAElB,wBAAwB,EAExB,YAAY,GACb,MAAM,YAAY,CAAC;AACpB,OAAO,EAKL,UAAU,EACV,eAAe,EACf,UAAU,EACV,oBAAoB,EACpB,iBAAiB,EACjB,iBAAiB,EAGjB,cAAc,EACd,OAAO,EACP,wBAAwB,EAExB,iBAAiB,GAClB,MAAM,cAAc,CAAC;AACtB,gFAAgF;AAChF,OAAO,EACL,qBAAqB,EACrB,aAAa,GAGd,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,eAAe,EACf,UAAU,EACV,YAAY,EACZ,gBAAgB,EAChB,iBAAiB,EACjB,aAAa,EAUb,OAAO,EACP,0BAA0B,GAC3B,MAAM,eAAe,CAAC;AACvB,gFAAgF;AAChF,OAAO,EAEL,oBAAoB,EAIpB,IAAI,GAEL,MAAM,WAAW,CAAC;AACnB,gFAAgF;AAChF,OAAO,EAEL,iBAAiB,EACjB,YAAY,EAEZ,yBAAyB,EACzB,QAAQ,EAKR,QAAQ,GACT,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAa,SAAS,EAAE,MAAM,WAAW,CAAC;AACnE,gFAAgF;AAChF,OAAO,EAGL,gBAAgB,EAChB,oBAAoB,EACpB,eAAe,EACf,aAAa,EACb,YAAY;AACZ,kBAAkB;AAClB,SAAS,EACT,OAAO,EACP,YAAY,EACZ,UAAU,EAEV,UAAU,EACV,gBAAgB,EAChB,GAAG,EACH,yBAAyB,EACzB,mBAAmB,EACnB,oBAAoB,EACpB,YAAY,EACZ,iBAAiB,EACjB,cAAc,EACd,MAAM,EAEN,KAAK,EACL,OAAO,EACP,UAAU;AACV,uBAAuB;AACvB,QAAQ;AACR,cAAc;AACd,uBAAuB,EACvB,yBAAyB,EACzB,SAAS,EACT,cAAc,EAEd,iBAAiB;AACjB,oBAAoB;AACpB,UAAU,EACV,OAAO,EACP,gBAAgB;AAIhB,WAAW;AACX,uBAAuB,EACvB,kBAAkB;AAClB,gBAAgB;AAChB,YAAY,EACZ,aAAa;AAEb,+DAA+D;AAC/D,kBAAkB,EAClB,aAAa,EACb,eAAe,EACf,oBAAoB,EACpB,sBAAsB;AACtB,8BAA8B;AAC9B,cAAc,GACf,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,oBAAoB,EAOpB,UAAU,EACV,gBAAgB,GACjB,MAAM,WAAW,CAAC"}
package/dist/plan.d.ts ADDED
@@ -0,0 +1,248 @@
1
+ /**
2
+ * plan.ts: power economics. What will this cost, and can we even detect it?
3
+ *
4
+ * Without a plan, the first sign that a suite cannot be decided is a large bill
5
+ * and no certified case. This module tells you *before* you spend anything, and it will tell you that the honest answer is
6
+ * sometimes "you cannot detect this at any price".
7
+ *
8
+ * The three numbers that matter, per case:
9
+ *
10
+ * 1. **The bar.** e-BH at FDR q over m cases certifies a case on its own only
11
+ * once its e-value clears m/q. That is the target the evidence has to hit.
12
+ *
13
+ * 2. **The ceiling.** `evidenceCeilingLogE`, the limit of the unpaired
14
+ * two-sample e-value as candidate runs go to infinity. Both marginals are
15
+ * the same binomial likelihood under different priors, so everything that
16
+ * grows with n cancels and the Bayes factor converges to the prior density
17
+ * ratio at the observed rate. If the ceiling is under the bar, no number of
18
+ * candidate runs will certify the case. This is not a budget problem and no
19
+ * budget fixes it: **more baseline runs** fix it, by sharpening the null.
20
+ *
21
+ * 3. **The paired alternative.** Re-run the baseline alongside the candidate
22
+ * on the same seed and the null becomes an exact point mass at ½ (a
23
+ * discordant pair points either way with probability exactly one half under
24
+ * "nothing changed"). Nothing is estimated, so nothing caps the evidence:
25
+ * the paired e-value grows linearly in discordant pairs. It costs two runs
26
+ * per observation and it is still, routinely, the cheaper design, and it
27
+ * is the only one that works at all for a case whose ceiling is under the
28
+ * bar.
29
+ *
30
+ * Everything here is a *plan*: it evaluates the mean trajectory (the candidate
31
+ * scores exactly its expected successes). Realised sample counts vary around
32
+ * it.
33
+ */
34
+ import { type BaselineStat, type CaseRef } from "./baseline.js";
35
+ import { type PairedCounts } from "./stats.js";
36
+ export interface PlanConfig {
37
+ /** the drop we want to be able to detect, in probability units (0.15 = 15 points) */
38
+ mde: number;
39
+ /** suite-level false discovery rate */
40
+ fdr: number;
41
+ /** USD per candidate run */
42
+ costPerRunUsd: number;
43
+ /** milliseconds per run, wall clock, at concurrency 1 */
44
+ msPerRun: number;
45
+ /** how many runs the screening pass spends per case */
46
+ screenRuns: number;
47
+ /**
48
+ * Measured coupling between the paired arms, in [0,1]. 0 means the seeds
49
+ * bought nothing; 1 means perfect common-random-numbers coupling. Measure it
50
+ * with `pairPhi` on a pilot rather than assuming it, and plan at 0 as well
51
+ * so the sensitivity is visible.
52
+ */
53
+ pairCoupling: number;
54
+ /** how many runs to fan out in parallel, only affects wall time */
55
+ concurrency: number;
56
+ /** beyond this many runs for one case we stop calling it "affordable" */
57
+ runsPerCaseCeiling: number;
58
+ /**
59
+ * Which design the *expected* bill is priced for. A paired observation is two
60
+ * runs, so this doubles `typicalRuns`.
61
+ *
62
+ * `undefined` means "price the design this plan recommends", which is the
63
+ * only self-consistent answer: `makePlan` recommends pairing whenever more
64
+ * than a quarter of the suite has an unpaired evidence ceiling under the bar,
65
+ * and quoting the *unpaired* bill underneath that recommendation would price
66
+ * a design nobody runs.
67
+ */
68
+ design?: "unpaired" | "paired";
69
+ alpha: number;
70
+ beta: number;
71
+ minTrials: number;
72
+ maxTrials: number;
73
+ batchSize: number;
74
+ nullQuantile: number;
75
+ }
76
+ export declare const DEFAULT_PLAN: PlanConfig;
77
+ export type Detectability =
78
+ /** the unpaired sequential test can certify this case within the run ceiling */
79
+ "UNPAIRED"
80
+ /** only the paired design can certify it, the unpaired evidence ceiling is under the bar */
81
+ | "PAIRED_ONLY"
82
+ /** the run count is finite but past the ceiling: technically possible, practically not */
83
+ | "TOO_EXPENSIVE"
84
+ /** the case cannot lose `mde` points at all, its baseline rate is not that high */
85
+ | "IMPOSSIBLE";
86
+ export interface PlanCase {
87
+ caseId: string;
88
+ suite: string;
89
+ baseline: {
90
+ successes: number;
91
+ trials: number;
92
+ rate: number;
93
+ };
94
+ /** the rate the alternative sits at: baseline − mde, floored at 0 */
95
+ alternativeRate: number;
96
+ /** log of the e-value a case must reach to be certified on its own evidence */
97
+ barLogE: number;
98
+ /** the limit of the unpaired log e-value as runs → ∞ */
99
+ ceilingLogE: number;
100
+ unpaired: {
101
+ runs: number;
102
+ costUsd: number;
103
+ wallMs: number;
104
+ };
105
+ paired: {
106
+ pairs: number;
107
+ runs: number;
108
+ costUsd: number;
109
+ wallMs: number;
110
+ };
111
+ /**
112
+ * The coupling `paired` is priced at: `pairPhi` of this case's pilot when
113
+ * `makePlan` was given one, floored at 0, otherwise `config.pairCoupling`.
114
+ */
115
+ pairCoupling: number;
116
+ detectability: Detectability;
117
+ /**
118
+ * The design to run this case with: of the designs that decide it within
119
+ * `runsPerCaseCeiling`, the one that needs fewer runs, unpaired on a tie.
120
+ * Null when neither does.
121
+ */
122
+ design: "unpaired" | "paired" | null;
123
+ /**
124
+ * How many baseline runs this case would need for the *unpaired* design to
125
+ * work, or null if it already works. This is the actionable half of an
126
+ * "undetectable" verdict.
127
+ */
128
+ baselineRunsNeeded: number | null;
129
+ /** what a fixed-N two-proportion design would spend per arm, for comparison */
130
+ fixedNPerArm: number;
131
+ reason: string;
132
+ }
133
+ export interface PlanTotals {
134
+ cases: number;
135
+ /** how many cases each design can actually certify */
136
+ decidableUnpaired: number;
137
+ decidableBest: number;
138
+ /** every case run to certification, unpaired */
139
+ unpairedRuns: number;
140
+ unpairedCostUsd: number;
141
+ /** every case run to certification, paired */
142
+ pairedRuns: number;
143
+ pairedCostUsd: number;
144
+ /** per case, the cheaper of the two designs that can decide it */
145
+ bestRuns: number;
146
+ bestCostUsd: number;
147
+ /** screen everything cheaply, then pay only for what the screen keeps */
148
+ screenedRuns: number;
149
+ screenedCostUsd: number;
150
+ /** the fixed-N design with the same nominal guarantees */
151
+ fixedNRuns: number;
152
+ fixedNCostUsd: number;
153
+ wallMsUnpaired: number;
154
+ wallMsPaired: number;
155
+ wallMsBest: number;
156
+ wallMsScreened: number;
157
+ /** fraction of cases the screen is budgeted to carry through to the full test */
158
+ screenContinueFraction: number;
159
+ /** 1 unpaired, 2 paired, what one observation costs in runs */
160
+ runsPerObservation: number;
161
+ /** expected *runs* (not observations) for a pull request in which nothing moved */
162
+ typicalRuns: number;
163
+ typicalCostUsd: number;
164
+ wallMsTypical: number;
165
+ /** the same, with a screening pass in front */
166
+ typicalScreenedRuns: number;
167
+ typicalScreenedCostUsd: number;
168
+ }
169
+ export interface Plan {
170
+ config: PlanConfig;
171
+ cases: PlanCase[];
172
+ totals: PlanTotals;
173
+ /** cases no budget can decide with the current baseline */
174
+ undecidable: PlanCase[];
175
+ /** cases only the paired design can reach */
176
+ pairedOnly: PlanCase[];
177
+ /** cases whose baseline rate is too low to lose `mde` points at all */
178
+ impossible: PlanCase[];
179
+ /** the design the recommendation names, and the one `expectedCostUsd` prices */
180
+ recommendedDesign: "unpaired" | "paired";
181
+ /** the cheapest design that decides every decidable case */
182
+ recommendation: string;
183
+ /** honest one-liner about affordability at the configured cost per run */
184
+ verdict: string;
185
+ /**
186
+ * What a *typical* pull request costs, one in which nothing moved, so most
187
+ * cases stop at the H₀ wall. This is the headline number.
188
+ */
189
+ expectedCostUsd: number;
190
+ /**
191
+ * What a pull request in which *every* case regressed would cost.
192
+ *
193
+ * Not an upper bound on `expectedCostUsd`, despite running every case to
194
+ * certification: the sequential test stops a case as soon as it clears the
195
+ * bar, so an all-regressed suite can finish cheaper than one that did not
196
+ * move and ran its full schedule. `verdict` says which way round they came
197
+ * out rather than presenting this as the worst case.
198
+ */
199
+ ceilingCostUsd: number;
200
+ }
201
+ export declare function planCase(c: CaseRef, b: BaselineStat | undefined, cfg: PlanConfig, m: number): PlanCase;
202
+ /**
203
+ * Expected total samples for the sequential design, priced under Wald's
204
+ * expected sample number at a supplied "true" rate per case, and clamped into
205
+ * the gate's own [minTrials, maxTrials] batch grid.
206
+ *
207
+ * This is the number that predicts what the gate will actually spend.
208
+ * `samplesForEvidence`, the one behind `PlanCase.unpaired.runs`, answers a
209
+ * different question: how many runs it takes to *certify a regression*. A case
210
+ * that did not regress never gets there; it hits the H₀ wall in a few batches
211
+ * and stops. Pricing every case at the certification cost over-predicts the
212
+ * bill.
213
+ *
214
+ * `trueRate` defaults to the case's own baseline rate, i.e. "nothing moved", * which is what almost every pull request looks like.
215
+ */
216
+ export declare function expectedSequentialSamples(cases: Array<CaseRef>, baseline: Map<string, BaselineStat>, cfg: PlanConfig, trueRate?: (caseId: string, b: BaselineStat) => number): {
217
+ samples: number;
218
+ perCase: Map<string, number>;
219
+ };
220
+ /**
221
+ * Plan a suite. `pilots` holds a pair table per case from a pilot run of the
222
+ * paired design, ideally with both arms on the same revision; a case with one
223
+ * prices pairing at its measured `pairPhi` instead of `cfg.pairCoupling`, so
224
+ * its `design` is chosen from a coupling the runner actually delivers.
225
+ */
226
+ export declare function makePlan(cases: Array<CaseRef>, baseline: Map<string, BaselineStat>, cfg?: PlanConfig, pilots?: Map<string, PairedCounts>): Plan;
227
+ /**
228
+ * The suite size / MDE combinations that *are* affordable at a given per-run
229
+ * cost and budget. This is the honest answer to "is this usable for a
230
+ * coding-agent benchmark at $1 a run?", usually "not at 200 cases and 15
231
+ * points, but yes at 20 cases and 25 points".
232
+ */
233
+ export interface AffordabilityCell {
234
+ cases: number;
235
+ mde: number;
236
+ /** runs to certify every case, the ceiling */
237
+ runs: number;
238
+ costUsd: number;
239
+ /** runs a pull request that moved nothing actually spends, the expected bill */
240
+ typicalRuns: number;
241
+ typicalCostUsd: number;
242
+ /** does the *ceiling* fit the budget? */
243
+ affordable: boolean;
244
+ /** does the *expected* cost fit the budget? */
245
+ typicallyAffordable: boolean;
246
+ }
247
+ export declare function affordabilityGrid(baselineRate: number, baselineTrials: number, cfg: PlanConfig, budgetUsd: number, caseCounts?: number[], mdes?: number[]): AffordabilityCell[];
248
+ //# sourceMappingURL=plan.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan.d.ts","sourceRoot":"","sources":["../src/plan.ts"],"names":[],"mappings":"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"}