peeksafe 0.1.0 → 0.3.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.
- package/CHANGELOG.md +220 -1
- package/README.md +3 -5
- package/dist/cluster.d.ts.map +1 -1
- package/dist/cluster.js +8 -0
- package/dist/cluster.js.map +1 -1
- package/dist/errors.d.ts +24 -3
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +52 -3
- package/dist/errors.js.map +1 -1
- package/dist/frontier.d.ts +9 -6
- package/dist/frontier.d.ts.map +1 -1
- package/dist/frontier.js +99 -55
- package/dist/frontier.js.map +1 -1
- package/dist/gate.d.ts +2 -0
- package/dist/gate.d.ts.map +1 -1
- package/dist/gate.js +5 -1
- package/dist/gate.js.map +1 -1
- package/dist/plan.d.ts +65 -17
- package/dist/plan.d.ts.map +1 -1
- package/dist/plan.js +289 -51
- package/dist/plan.js.map +1 -1
- package/dist/rand.d.ts.map +1 -1
- package/dist/rand.js +16 -4
- package/dist/rand.js.map +1 -1
- package/dist/stats.d.ts +7 -3
- package/dist/stats.d.ts.map +1 -1
- package/dist/stats.js +103 -45
- package/dist/stats.js.map +1 -1
- package/dist/stop.d.ts.map +1 -1
- package/dist/stop.js +12 -4
- package/dist/stop.js.map +1 -1
- package/package.json +10 -11
- package/src/cluster.ts +12 -0
- package/src/errors.ts +70 -3
- package/src/frontier.ts +131 -71
- package/src/gate.ts +6 -1
- package/src/plan.ts +355 -66
- package/src/rand.ts +20 -4
- package/src/stats.ts +134 -51
- package/src/stop.ts +16 -4
package/dist/stop.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stop.js","sourceRoot":"","sources":["../src/stop.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AAGH,OAAO,EACL,aAAa,EACb,uBAAuB,EACvB,aAAa,EACb,sBAAsB,EACtB,mBAAmB,GACpB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,kBAAkB,EAElB,WAAW,EACX,eAAe,EACf,QAAQ,GACT,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAC/
|
|
1
|
+
{"version":3,"file":"stop.js","sourceRoot":"","sources":["../src/stop.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "peeksafe",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Statistically valid gates for non-deterministic eval suites. Stop early without losing error control.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"evals",
|
|
@@ -43,6 +43,14 @@
|
|
|
43
43
|
"engines": {
|
|
44
44
|
"node": ">=22"
|
|
45
45
|
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@biomejs/biome": "2.5.15",
|
|
48
|
+
"@types/node": "22.20.5",
|
|
49
|
+
"knip": "6.39.0",
|
|
50
|
+
"lefthook": "2.1.16",
|
|
51
|
+
"typescript": "7.0.2",
|
|
52
|
+
"vitest": "5.0.3"
|
|
53
|
+
},
|
|
46
54
|
"scripts": {
|
|
47
55
|
"build": "tsc -p tsconfig.build.json",
|
|
48
56
|
"clean": "rm -rf dist",
|
|
@@ -52,15 +60,6 @@
|
|
|
52
60
|
"knip": "knip --treat-config-hints-as-errors",
|
|
53
61
|
"test": "vitest run",
|
|
54
62
|
"test:watch": "vitest",
|
|
55
|
-
"prepack": "pnpm run clean && pnpm run build",
|
|
56
63
|
"version": "node scripts/release-changelog.mjs && git add CHANGELOG.md"
|
|
57
|
-
},
|
|
58
|
-
"devDependencies": {
|
|
59
|
-
"@biomejs/biome": "catalog:",
|
|
60
|
-
"@types/node": "catalog:",
|
|
61
|
-
"knip": "catalog:",
|
|
62
|
-
"lefthook": "catalog:",
|
|
63
|
-
"typescript": "catalog:",
|
|
64
|
-
"vitest": "catalog:"
|
|
65
64
|
}
|
|
66
|
-
}
|
|
65
|
+
}
|
package/src/cluster.ts
CHANGED
|
@@ -188,6 +188,18 @@ export interface ClusteredMean extends Interval {
|
|
|
188
188
|
/** The naive iid interval, kept so the two can be printed side by side. */
|
|
189
189
|
export function iidMean(values: number[], level = 0.95): Interval {
|
|
190
190
|
requireLevel(level, "iidMean");
|
|
191
|
+
// groupByCluster refused these for the other estimators, so the same data was an error there and a NaN interval here.
|
|
192
|
+
for (let i = 0; i < values.length; i++) {
|
|
193
|
+
if (!Number.isFinite(values[i])) {
|
|
194
|
+
throw new PeeksafeError(
|
|
195
|
+
"PEEKSAFE_E_STAT_DOMAIN",
|
|
196
|
+
`iidMean: value at index ${i} is not finite`,
|
|
197
|
+
{
|
|
198
|
+
detail: { index: i, value: values[i] },
|
|
199
|
+
},
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
191
203
|
const n = values.length;
|
|
192
204
|
if (n === 0) return { low: -1, high: 1, point: 0, observations: 0 };
|
|
193
205
|
const mean = values.reduce((a, b) => a + b, 0) / n;
|
package/src/errors.ts
CHANGED
|
@@ -153,11 +153,11 @@ export function requireAltConcentration(v: number, evidence: string, where: stri
|
|
|
153
153
|
}
|
|
154
154
|
|
|
155
155
|
/**
|
|
156
|
-
* The error rates of
|
|
157
|
-
* between 0 and 1, and summing to less than 1.
|
|
156
|
+
* The error rates of a Wald SPRT, run by `sprtDecision` or priced by a
|
|
157
|
+
* planner: each strictly between 0 and 1, and summing to less than 1.
|
|
158
158
|
*
|
|
159
159
|
* At `alpha + beta >= 1` Wald's walls meet or cross, so the test decides
|
|
160
|
-
* before it has seen a run. `sprtExpectedN`
|
|
160
|
+
* before it has seen a run. `sprtExpectedN` answered a small positive number
|
|
161
161
|
* there, and a plan at `alpha: 0.6, beta: 0.5` priced every case at
|
|
162
162
|
* `minTrials` with nothing to say the design had no error control left.
|
|
163
163
|
*/
|
|
@@ -176,6 +176,59 @@ export function requireErrorRates(alpha: number, beta: number, where: string): v
|
|
|
176
176
|
}
|
|
177
177
|
}
|
|
178
178
|
|
|
179
|
+
/**
|
|
180
|
+
* `runsPerCaseCeiling`: finite and at least one run. The planners search up to
|
|
181
|
+
* eight times it, and at NaN or 0 that search never ran, so every case came
|
|
182
|
+
* back undecidable with a reason that blamed the evidence bar.
|
|
183
|
+
*/
|
|
184
|
+
export function requireRunCeiling(v: number, where: string): void {
|
|
185
|
+
if (!(v >= 1) || !Number.isFinite(v)) {
|
|
186
|
+
throw new PeeksafeError(
|
|
187
|
+
"PEEKSAFE_E_CONFIG",
|
|
188
|
+
`${where}: runsPerCaseCeiling must be finite and at least 1, got ${v}`,
|
|
189
|
+
{
|
|
190
|
+
detail: { runsPerCaseCeiling: v, where },
|
|
191
|
+
},
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* The batch grid a plan prices the gate on: `minTrials` and `batchSize`
|
|
198
|
+
* positive integers, `maxTrials` an integer at least `minTrials`. A NaN bound
|
|
199
|
+
* or a zero batch made the typical bill NaN, and a cap under the minimum
|
|
200
|
+
* priced every case at the cap.
|
|
201
|
+
*/
|
|
202
|
+
export function requireTrialGrid(
|
|
203
|
+
cfg: { minTrials: number; maxTrials: number; batchSize: number },
|
|
204
|
+
where: string,
|
|
205
|
+
): void {
|
|
206
|
+
const { minTrials, maxTrials, batchSize } = cfg;
|
|
207
|
+
const detail = { minTrials, maxTrials, batchSize, where };
|
|
208
|
+
for (const [name, v] of [
|
|
209
|
+
["minTrials", minTrials],
|
|
210
|
+
["batchSize", batchSize],
|
|
211
|
+
] as const) {
|
|
212
|
+
if (!Number.isInteger(v) || v < 1) {
|
|
213
|
+
throw new PeeksafeError(
|
|
214
|
+
"PEEKSAFE_E_CONFIG",
|
|
215
|
+
`${where}: ${name} must be a positive integer, got ${v}`,
|
|
216
|
+
{ detail },
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
if (!Number.isInteger(maxTrials) || maxTrials < minTrials) {
|
|
221
|
+
throw new PeeksafeError(
|
|
222
|
+
"PEEKSAFE_E_CONFIG",
|
|
223
|
+
`${where}: maxTrials must be an integer ≥ minTrials, got ${maxTrials} vs ${minTrials}`,
|
|
224
|
+
{
|
|
225
|
+
detail,
|
|
226
|
+
hint: "the typical bill is clamped to [minTrials, maxTrials]; a cap under the minimum prices a gate that stops before it starts",
|
|
227
|
+
},
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
179
232
|
/** The four cells of a pair table, each a non-negative integer. */
|
|
180
233
|
export function requirePairedCounts(
|
|
181
234
|
p: { bothPass: number; worse: number; better: number; bothFail: number },
|
|
@@ -206,3 +259,17 @@ export function requireProbability(p: number, name: string, where: string): void
|
|
|
206
259
|
);
|
|
207
260
|
}
|
|
208
261
|
}
|
|
262
|
+
|
|
263
|
+
/** Case ids, each at most once: a repeated id is planned twice and inflates the suite size the bar is set from. */
|
|
264
|
+
export function requireUniqueCaseIds(cases: readonly { id: string }[], where: string): void {
|
|
265
|
+
const seen = new Set<string>();
|
|
266
|
+
for (const c of cases) {
|
|
267
|
+
if (seen.has(c.id)) {
|
|
268
|
+
throw new PeeksafeError("PEEKSAFE_E_CASE_DUPLICATE", `${where}: duplicate case id ${c.id}`, {
|
|
269
|
+
detail: { id: c.id, where },
|
|
270
|
+
hint: "a case listed twice is priced twice and counted twice in the suite size; dedupe the case list before calling",
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
seen.add(c.id);
|
|
274
|
+
}
|
|
275
|
+
}
|
package/src/frontier.ts
CHANGED
|
@@ -62,15 +62,20 @@ import {
|
|
|
62
62
|
requireErrorRates,
|
|
63
63
|
requireOpenProbability,
|
|
64
64
|
requireProbability,
|
|
65
|
+
requireRunCeiling,
|
|
66
|
+
requireTrialGrid,
|
|
65
67
|
} from "./errors.js";
|
|
66
|
-
import { DEFAULT_PLAN } from "./plan.js";
|
|
67
68
|
import {
|
|
68
|
-
|
|
69
|
+
DEFAULT_PLAN,
|
|
70
|
+
expectedSettlePairs,
|
|
71
|
+
expectedStopRuns,
|
|
72
|
+
requireSettleConfidence,
|
|
73
|
+
} from "./plan.js";
|
|
74
|
+
import {
|
|
69
75
|
ebhSoloThreshold,
|
|
70
76
|
evidenceCeilingLogE,
|
|
71
77
|
mcnemarSamplesForEvidence,
|
|
72
78
|
samplesForEvidence,
|
|
73
|
-
sprtExpectedN,
|
|
74
79
|
} from "./stats.js";
|
|
75
80
|
|
|
76
81
|
export type FrontierDesign = "unpaired" | "paired";
|
|
@@ -161,9 +166,9 @@ export interface FrontierConfig {
|
|
|
161
166
|
/**
|
|
162
167
|
* Baseline runs per case the *paired* design needs. The paired e-value's null
|
|
163
168
|
* is a point mass, so the stored baseline is not part of its validity and
|
|
164
|
-
* does not set a ceiling
|
|
165
|
-
*
|
|
166
|
-
* design wins at these prices.
|
|
169
|
+
* does not set a ceiling; here it is only the baseline bill, since a paired
|
|
170
|
+
* typical bill is priced in pairs to settle. A short one is enough, and that
|
|
171
|
+
* asymmetry is most of why the paired design wins at these prices.
|
|
167
172
|
*/
|
|
168
173
|
pairedBaselineRuns: number;
|
|
169
174
|
/** fraction of cases a screen carries through to the expensive test */
|
|
@@ -185,6 +190,8 @@ export interface FrontierConfig {
|
|
|
185
190
|
maxTrials: number;
|
|
186
191
|
batchSize: number;
|
|
187
192
|
nullQuantile: number;
|
|
193
|
+
/** the `futilityConfidence` `shouldStop` and `shouldStopPaired` run at; unset takes their default */
|
|
194
|
+
futilityConfidence?: number;
|
|
188
195
|
}
|
|
189
196
|
|
|
190
197
|
export const DEFAULT_FRONTIER: FrontierConfig = {
|
|
@@ -268,6 +275,7 @@ export interface FrontierPoint {
|
|
|
268
275
|
}
|
|
269
276
|
|
|
270
277
|
const RUNS_PER_OBS: Record<FrontierDesign, number> = { unpaired: 1, paired: 2 };
|
|
278
|
+
const SCREENS: readonly FrontierScreen[] = ["none", "expensive", "proxy"];
|
|
271
279
|
|
|
272
280
|
/** $1.00, but $0.0021 rather than $0.00, a per-run price rounds to nothing. */
|
|
273
281
|
export const fmtRate = (x: number): string =>
|
|
@@ -283,32 +291,98 @@ export const fmtRate = (x: number): string =>
|
|
|
283
291
|
const graded = (runs: number, cfg: FrontierConfig): number =>
|
|
284
292
|
runs * (cfg.costPerRunUsd + cfg.costPerGradeUsd);
|
|
285
293
|
|
|
294
|
+
function requireBaselineRuns(v: number, name: string, where: string): void {
|
|
295
|
+
if (!Number.isInteger(v) || v < 1) {
|
|
296
|
+
throw new PeeksafeError(
|
|
297
|
+
"PEEKSAFE_E_CONFIG",
|
|
298
|
+
`${where}: ${name} must be a positive integer, got ${v}`,
|
|
299
|
+
{
|
|
300
|
+
detail: { [name]: v, where },
|
|
301
|
+
},
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* The budget, the prices, the screen's keep fraction and `amortisePrs`.
|
|
308
|
+
* `enumerateFrontier` checked these and `evaluatePoint` did not, so a direct
|
|
309
|
+
* call recommended a point at a negative bill and priced a screen that kept
|
|
310
|
+
* twice the suite.
|
|
311
|
+
*/
|
|
312
|
+
function requirePricing(cfg: FrontierConfig, where: string): void {
|
|
313
|
+
const finiteCost = (v: number) => Number.isFinite(v) && v >= 0;
|
|
314
|
+
if (!(cfg.budgetUsd >= 0) || !finiteCost(cfg.costPerRunUsd) || !finiteCost(cfg.costPerGradeUsd)) {
|
|
315
|
+
throw new PeeksafeError(
|
|
316
|
+
"PEEKSAFE_E_CONFIG",
|
|
317
|
+
`${where}: budget must be ≥ 0 and costs finite and ≥ 0`,
|
|
318
|
+
{
|
|
319
|
+
detail: {
|
|
320
|
+
budgetUsd: cfg.budgetUsd,
|
|
321
|
+
costPerRunUsd: cfg.costPerRunUsd,
|
|
322
|
+
costPerGradeUsd: cfg.costPerGradeUsd,
|
|
323
|
+
where,
|
|
324
|
+
},
|
|
325
|
+
hint: "an infinite cost fits an infinite budget, so the frontier recommended a point on an infinite bill",
|
|
326
|
+
},
|
|
327
|
+
);
|
|
328
|
+
}
|
|
329
|
+
if (!(cfg.screenKeepFraction > 0) || !(cfg.screenKeepFraction <= 1)) {
|
|
330
|
+
throw new PeeksafeError(
|
|
331
|
+
"PEEKSAFE_E_CONFIG",
|
|
332
|
+
`${where}: screenKeepFraction must be in (0,1], got ${cfg.screenKeepFraction}`,
|
|
333
|
+
{
|
|
334
|
+
detail: { screenKeepFraction: cfg.screenKeepFraction, where },
|
|
335
|
+
},
|
|
336
|
+
);
|
|
337
|
+
}
|
|
338
|
+
if (!Number.isInteger(cfg.amortisePrs) || cfg.amortisePrs < 1) {
|
|
339
|
+
throw new PeeksafeError(
|
|
340
|
+
"PEEKSAFE_E_CONFIG",
|
|
341
|
+
`${where}: amortisePrs must be a positive integer, got ${cfg.amortisePrs}`,
|
|
342
|
+
{
|
|
343
|
+
detail: { amortisePrs: cfg.amortisePrs, where },
|
|
344
|
+
hint: 'a baseline spread over "infinity" pull requests is how the baseline cost disappears from a plan',
|
|
345
|
+
},
|
|
346
|
+
);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
286
350
|
/**
|
|
287
|
-
*
|
|
288
|
-
*
|
|
351
|
+
* Expected runs `shouldStop` takes to stop an unpaired case where nothing
|
|
352
|
+
* moved, in a suite of `cases`, at `mde`, `fdr` and `futilityConfidence`: the
|
|
353
|
+
* per-case share `evaluatePoint` bills an unpaired point at.
|
|
289
354
|
*/
|
|
290
355
|
export function typicalObservationsPerCase(
|
|
291
356
|
rate: number,
|
|
292
357
|
mde: number,
|
|
293
358
|
cfg: FrontierConfig,
|
|
294
359
|
baselineRuns: number,
|
|
360
|
+
cases: number,
|
|
295
361
|
): number {
|
|
296
|
-
|
|
297
|
-
// one outside (0,1)
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
362
|
+
const where = "typicalObservationsPerCase";
|
|
363
|
+
// `makePlan` reaches this quantile through `baselineNullRate`, which refuses one outside (0,1), so the frontier refuses it too.
|
|
364
|
+
requireOpenProbability(cfg.nullQuantile, "nullQuantile", where);
|
|
365
|
+
requireTrialGrid(cfg, where);
|
|
366
|
+
// Unchecked, an mde of 0 or below priced a bill for an effect nobody can detect, and a bad rate or run count was refused under another function's name.
|
|
367
|
+
requireOpenProbability(rate, "rate", where);
|
|
368
|
+
requireOpenProbability(mde, "mde", where);
|
|
369
|
+
requireBaselineRuns(baselineRuns, "baselineRuns", where);
|
|
370
|
+
if (!Number.isInteger(cases) || cases < 1) {
|
|
371
|
+
throw new PeeksafeError(
|
|
372
|
+
"PEEKSAFE_E_CONFIG",
|
|
373
|
+
`${where}: cases must be a positive integer, got ${cases}`,
|
|
374
|
+
{
|
|
375
|
+
detail: { cases, where },
|
|
376
|
+
},
|
|
377
|
+
);
|
|
378
|
+
}
|
|
379
|
+
requireOpenProbability(cfg.fdr, "fdr", where);
|
|
380
|
+
requireSettleConfidence(cfg, where);
|
|
381
|
+
const successes = Math.round(rate * baselineRuns);
|
|
382
|
+
return expectedStopRuns({ caseId: "typical", successes, trials: baselineRuns }, rate, cases, {
|
|
383
|
+
...cfg,
|
|
384
|
+
mde,
|
|
385
|
+
});
|
|
312
386
|
}
|
|
313
387
|
|
|
314
388
|
export function evaluatePoint(
|
|
@@ -327,13 +401,15 @@ export function evaluatePoint(
|
|
|
327
401
|
requireOpenProbability(mde, "mde", "evaluatePoint");
|
|
328
402
|
requireOpenProbability(cfg.baselineRate, "baselineRate", "evaluatePoint");
|
|
329
403
|
// `makePlan` refuses these two and this did not, so one options object was a
|
|
330
|
-
// refusal through the planner and a priced frontier through here.
|
|
331
|
-
// in `sprtExpectedN`, which answers NaN or Infinity outside (0,1), and
|
|
332
|
-
// `typicalObservationsPerCase` reads either as "cannot price this" and falls
|
|
333
|
-
// back to the run ceiling.
|
|
404
|
+
// refusal through the planner and a priced frontier through here.
|
|
334
405
|
requireErrorRates(cfg.alpha, cfg.beta, "evaluatePoint");
|
|
335
406
|
requireProbability(cfg.pairCoupling, "pairCoupling", "evaluatePoint");
|
|
336
407
|
requireOpenProbability(cfg.nullQuantile, "nullQuantile", "evaluatePoint");
|
|
408
|
+
requireSettleConfidence(cfg, "evaluatePoint");
|
|
409
|
+
// makePlan refuses it; unchecked, an fdr of 2 cut the bar and 0 was blamed on the ceiling.
|
|
410
|
+
requireOpenProbability(cfg.fdr, "fdr", "evaluatePoint");
|
|
411
|
+
requireRunCeiling(cfg.runsPerCaseCeiling, "evaluatePoint");
|
|
412
|
+
requirePricing(cfg, "evaluatePoint");
|
|
337
413
|
if (!Number.isInteger(cases) || cases < 1) {
|
|
338
414
|
throw new PeeksafeError(
|
|
339
415
|
"PEEKSAFE_E_CONFIG",
|
|
@@ -343,25 +419,35 @@ export function evaluatePoint(
|
|
|
343
419
|
},
|
|
344
420
|
);
|
|
345
421
|
}
|
|
346
|
-
|
|
422
|
+
// The paired design prices its baseline from this one, and 0 or 2.5 runs priced a cheaper frontier than any real baseline.
|
|
423
|
+
requireBaselineRuns(cfg.pairedBaselineRuns, "pairedBaselineRuns", "evaluatePoint");
|
|
424
|
+
requireBaselineRuns(baselineRuns, "baselineRuns", "evaluatePoint");
|
|
425
|
+
requireTrialGrid(cfg, "evaluatePoint");
|
|
426
|
+
// An unknown design fell through to the paired branch with no runs per observation and came back feasible on an infinite bill.
|
|
427
|
+
if (!Object.hasOwn(RUNS_PER_OBS, design)) {
|
|
347
428
|
throw new PeeksafeError(
|
|
348
429
|
"PEEKSAFE_E_CONFIG",
|
|
349
|
-
`frontier:
|
|
430
|
+
`frontier: design must be one of ${Object.keys(RUNS_PER_OBS).join(", ")}, got "${String(design)}"`,
|
|
350
431
|
{
|
|
351
|
-
detail: {
|
|
432
|
+
detail: { design },
|
|
352
433
|
},
|
|
353
434
|
);
|
|
354
435
|
}
|
|
355
|
-
|
|
436
|
+
// An unknown screen was priced and recommended as the expensive one.
|
|
437
|
+
if (!SCREENS.includes(screen)) {
|
|
356
438
|
throw new PeeksafeError(
|
|
357
439
|
"PEEKSAFE_E_CONFIG",
|
|
358
|
-
`frontier:
|
|
440
|
+
`frontier: screen must be one of ${SCREENS.join(", ")}, got "${String(screen)}"`,
|
|
359
441
|
{
|
|
360
|
-
detail: {
|
|
361
|
-
hint: "the ceiling bill is priced at this cap; a cap of zero prices a gate that never runs",
|
|
442
|
+
detail: { screen },
|
|
362
443
|
},
|
|
363
444
|
);
|
|
364
445
|
}
|
|
446
|
+
// Only null withholds a recommendation, so a NaN recall (0 of 0 regressions caught) recommended the screen.
|
|
447
|
+
for (const kind of ["expensive", "proxy"] as const) {
|
|
448
|
+
const recall = cfg.screenRecall[kind];
|
|
449
|
+
if (recall !== null) requireProbability(recall, `screenRecall.${kind}`, "evaluatePoint");
|
|
450
|
+
}
|
|
365
451
|
if (screen !== "none" && (!Number.isInteger(screenRunsPerCase) || screenRunsPerCase < 1)) {
|
|
366
452
|
throw new PeeksafeError(
|
|
367
453
|
"PEEKSAFE_E_CONFIG",
|
|
@@ -428,7 +514,11 @@ export function evaluatePoint(
|
|
|
428
514
|
}
|
|
429
515
|
const feasible = infeasibleBecause === null;
|
|
430
516
|
|
|
431
|
-
|
|
517
|
+
// Each design is counted under the rule that stops it, as `makePlan` does; Wald's SPRT figure ignores the coupling and the suite size.
|
|
518
|
+
const typicalObservations =
|
|
519
|
+
design === "paired"
|
|
520
|
+
? expectedSettlePairs(rate, cfg.pairCoupling, mde, cases, cfg)
|
|
521
|
+
: typicalObservationsPerCase(rate, mde, cfg, effectiveBaselineRuns, cases);
|
|
432
522
|
const keep = screen === "none" ? cases : Math.max(1, Math.ceil(cases * cfg.screenKeepFraction));
|
|
433
523
|
|
|
434
524
|
// Screening runs are graded by whichever grader the screen uses. A proxy
|
|
@@ -449,7 +539,7 @@ export function evaluatePoint(
|
|
|
449
539
|
|
|
450
540
|
// The baseline. Unpaired buys its ceiling here; paired does not.
|
|
451
541
|
const baselineRunsTotal = cases * effectiveBaselineRuns;
|
|
452
|
-
const baselineRunsAmortised = baselineRunsTotal /
|
|
542
|
+
const baselineRunsAmortised = baselineRunsTotal / cfg.amortisePrs;
|
|
453
543
|
const baselineUsd = graded(baselineRunsAmortised, cfg);
|
|
454
544
|
|
|
455
545
|
const costFor = (obsPerCase: number): FrontierCost => {
|
|
@@ -495,8 +585,8 @@ export function evaluatePoint(
|
|
|
495
585
|
"certify-all": certifyAll,
|
|
496
586
|
ceiling,
|
|
497
587
|
};
|
|
498
|
-
|
|
499
|
-
if (
|
|
588
|
+
// `hasOwn`, as in `costShares`: `BILLS.toString` is inherited, so "toString" passed an `undefined` check.
|
|
589
|
+
if (!Object.hasOwn(BILLS, cfg.basis)) {
|
|
500
590
|
throw new PeeksafeError(
|
|
501
591
|
"PEEKSAFE_E_CONFIG",
|
|
502
592
|
`frontier: basis must be one of ${Object.keys(BILLS).join(", ")}, got "${String(cfg.basis)}"`,
|
|
@@ -506,6 +596,7 @@ export function evaluatePoint(
|
|
|
506
596
|
},
|
|
507
597
|
);
|
|
508
598
|
}
|
|
599
|
+
const basisCost = BILLS[cfg.basis];
|
|
509
600
|
const withinBudget = feasible && basisCost.totalUsd <= cfg.budgetUsd;
|
|
510
601
|
|
|
511
602
|
// Reportable and recommendable are different. A screen whose recall nobody
|
|
@@ -551,38 +642,7 @@ export function enumerateFrontier(
|
|
|
551
642
|
cfg: FrontierConfig,
|
|
552
643
|
axes: FrontierAxes = DEFAULT_AXES,
|
|
553
644
|
): FrontierPoint[] {
|
|
554
|
-
|
|
555
|
-
throw new PeeksafeError(
|
|
556
|
-
"PEEKSAFE_E_CONFIG",
|
|
557
|
-
"frontier: budget and costs must be ≥ 0 and not NaN",
|
|
558
|
-
{
|
|
559
|
-
detail: {
|
|
560
|
-
budgetUsd: cfg.budgetUsd,
|
|
561
|
-
costPerRunUsd: cfg.costPerRunUsd,
|
|
562
|
-
costPerGradeUsd: cfg.costPerGradeUsd,
|
|
563
|
-
},
|
|
564
|
-
},
|
|
565
|
-
);
|
|
566
|
-
}
|
|
567
|
-
if (!(cfg.screenKeepFraction > 0) || !(cfg.screenKeepFraction <= 1)) {
|
|
568
|
-
throw new PeeksafeError(
|
|
569
|
-
"PEEKSAFE_E_CONFIG",
|
|
570
|
-
`frontier: screenKeepFraction must be in (0,1], got ${cfg.screenKeepFraction}`,
|
|
571
|
-
{
|
|
572
|
-
detail: { screenKeepFraction: cfg.screenKeepFraction },
|
|
573
|
-
},
|
|
574
|
-
);
|
|
575
|
-
}
|
|
576
|
-
if (!Number.isInteger(cfg.amortisePrs) || cfg.amortisePrs < 1) {
|
|
577
|
-
throw new PeeksafeError(
|
|
578
|
-
"PEEKSAFE_E_CONFIG",
|
|
579
|
-
`frontier: amortisePrs must be a positive integer, got ${cfg.amortisePrs}`,
|
|
580
|
-
{
|
|
581
|
-
detail: { amortisePrs: cfg.amortisePrs },
|
|
582
|
-
hint: 'a baseline spread over "infinity" pull requests is how the baseline cost disappears from a plan',
|
|
583
|
-
},
|
|
584
|
-
);
|
|
585
|
-
}
|
|
645
|
+
requirePricing(cfg, "frontier");
|
|
586
646
|
for (const [name, xs] of Object.entries(axes) as Array<[string, unknown[]]>) {
|
|
587
647
|
if (!Array.isArray(xs) || xs.length === 0) {
|
|
588
648
|
throw new PeeksafeError(
|
package/src/gate.ts
CHANGED
|
@@ -80,6 +80,11 @@ export const cannotDropBy = (
|
|
|
80
80
|
mde: number,
|
|
81
81
|
): boolean => baseline.successes / baseline.trials <= mde;
|
|
82
82
|
|
|
83
|
+
/** `options` without its `undefined` entries, so a spread over the defaults leaves those defaults in place. */
|
|
84
|
+
export function definedOptions<T extends object>(options: T): T {
|
|
85
|
+
return Object.fromEntries(Object.entries(options ?? {}).filter(([, v]) => v !== undefined)) as T;
|
|
86
|
+
}
|
|
87
|
+
|
|
83
88
|
/** One case's candidate result, and the baseline it is measured against. */
|
|
84
89
|
export interface GateCase {
|
|
85
90
|
id: string;
|
|
@@ -195,7 +200,7 @@ export function gate(
|
|
|
195
200
|
cases: readonly (GateCase | PairedGateCase)[],
|
|
196
201
|
options: GateOptions = {},
|
|
197
202
|
): GateResult {
|
|
198
|
-
const opts: Required<GateOptions> = { ...DEFAULT_GATE_OPTIONS, ...options };
|
|
203
|
+
const opts: Required<GateOptions> = { ...DEFAULT_GATE_OPTIONS, ...definedOptions(options) };
|
|
199
204
|
requireOpenProbability(opts.mde, "mde", "gate");
|
|
200
205
|
requireOpenProbability(opts.fdr, "fdr", "gate");
|
|
201
206
|
requireEvidence(opts.evidence, "gate");
|