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/dist/stop.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"stop.js","sourceRoot":"","sources":["../src/stop.ts"],"names":[],"mappings":"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"}
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.1.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 the sequential test a planner prices: each strictly
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` answers a small positive number
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
- betaQuantile,
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, it only feeds the SPRT stopping rule and the
165
- * screen. A short one is enough, and that asymmetry is most of why the paired
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
- * Observations per case on a pull request where nothing moved, clamped onto the
288
- * gate's own batch grid.
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
- // `makePlan` reaches this quantile through `baselineNullRate`, which refuses
297
- // one outside (0,1). This handed it to `betaQuantile` directly, which answers
298
- // 0 for a quantile at or below 0, 1 at or above 1, and about 0 for NaN, so the
299
- // frontier priced the typical bill against a null rate nobody chose.
300
- requireOpenProbability(cfg.nullQuantile, "nullQuantile", "typicalObservationsPerCase");
301
- const s = Math.round(rate * baselineRuns);
302
- const p0 = betaQuantile(1 + s, 1 + baselineRuns - s, cfg.nullQuantile);
303
- const p1 = Math.max(0.005, p0 - mde);
304
- const raw = sprtExpectedN(rate, p0, p1, cfg.alpha, cfg.beta);
305
- const n =
306
- Number.isFinite(raw) && raw > 0
307
- ? Math.min(cfg.maxTrials, Math.max(cfg.minTrials, Math.ceil(raw)))
308
- : cfg.maxTrials;
309
- const batched =
310
- cfg.minTrials + Math.ceil(Math.max(0, n - cfg.minTrials) / cfg.batchSize) * cfg.batchSize;
311
- return Math.min(cfg.maxTrials, batched);
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. Both end up
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
- if (!Number.isInteger(baselineRuns) || baselineRuns < 1) {
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: baselineRuns must be a positive integer, got ${baselineRuns}`,
430
+ `frontier: design must be one of ${Object.keys(RUNS_PER_OBS).join(", ")}, got "${String(design)}"`,
350
431
  {
351
- detail: { baselineRuns },
432
+ detail: { design },
352
433
  },
353
434
  );
354
435
  }
355
- if (!Number.isInteger(cfg.maxTrials) || cfg.maxTrials < 1 || cfg.maxTrials < cfg.minTrials) {
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: maxTrials must be a positive integer ≥ minTrials, got ${cfg.maxTrials} vs ${cfg.minTrials}`,
440
+ `frontier: screen must be one of ${SCREENS.join(", ")}, got "${String(screen)}"`,
359
441
  {
360
- detail: { maxTrials: cfg.maxTrials, minTrials: cfg.minTrials },
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
- const typicalObservations = typicalObservationsPerCase(rate, mde, cfg, effectiveBaselineRuns);
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 / Math.max(1, cfg.amortisePrs);
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
- const basisCost = BILLS[cfg.basis];
499
- if (basisCost === undefined) {
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
- if (!(cfg.budgetUsd >= 0) || !(cfg.costPerRunUsd >= 0) || !(cfg.costPerGradeUsd >= 0)) {
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");