/** * Sequential promotion evidence — family-wise error control for an ADAPTIVE * candidate stream (report item 2 / upstream @metaharness/flywheel 0.1.10 * `withSequentialEvidence` interop, implemented in-house so ruflo keeps the * property with every MetaHarness package removed). * * THE GAP THIS CLOSES: every promotion gate ruflo runs (accept/v1+sig, the * ruflo.flywheel-gate/v1 bootstrap) spends a FRESH alpha per candidate. A * flywheel proposes candidates adaptively — each new candidate is chosen after * looking at the last one's scores — so per-candidate alpha does not bound the * probability that ANY promotion in the stream is false. Published * measurements of greedy accept-if-improved loops put the false-commit rate at * 30-42% under exactly this regime. * * TWO COMPOSED MECHANISMS, both required by the promotion authority: * * 1. Anytime-valid e-process per candidate (testing-by-betting). Per paired * task, a discordant pair multiplies the e-value by (1+lambda) when the * candidate wins and (1-lambda) when the baseline wins; concordant pairs * carry no information (McNemar). Under the null the e-value is a * non-negative martingale with expectation 1, so by Ville's inequality * P(e ever reaches 1/alpha) <= alpha — no penalty for peeking mid-stream. * * 2. Alpha allocation ACROSS candidates. Candidate k in the lineage's test * stream must clear 1/alpha_k where alpha_k = alphaTotal * 6/(pi^2 * k^2), * so sum(alpha_k) = alphaTotal for arbitrarily many adaptively-chosen * candidates. The allocation index is persisted per receipt in the * transaction state — looking spends alpha whether or not the candidate * promotes, and retrying the same receipt reuses its index (no double * spend, no index shopping). * * Family-wise guarantee: P(any false promotion, ever, in the stream) * <= sum_k alpha_k = alphaTotal. The acceptance test for this module is the * 1,000-null-simulation in flywheel-sequential-evidence.test.ts. * * Pure, $0, deterministic. Never throws on well-typed input. */ export declare const SEQUENTIAL_EVIDENCE_VERSION = "ruflo.sequential-evidence/v1"; export declare const DEFAULT_ALPHA_TOTAL = 0.05; export declare const DEFAULT_LAMBDA = 0.5; /** Score tie-band: |candidate - baseline| <= epsilon is a concordant (uninformative) pair. */ export declare const DEFAULT_SCORE_EPSILON = 1e-9; /** Task-level paired outcome — the evidence unit receipts must now carry. */ export interface PairedTaskOutcome { taskId: string; baselineScore: number; candidateScore: number; } export interface SequentialEvidenceConfig { /** Total family-wise type-I budget across the WHOLE candidate stream. */ alphaTotal?: number; /** Betting fraction in (0,1); 0.5 needs no tuning. */ lambda?: number; /** Tie band on score comparisons. */ epsilon?: number; } export interface SequentialEvidenceVerdict { significant: boolean; eValue: number; threshold: number; alphaAllocated: number; testIndex: number; informativePairs: number; totalPairs: number; version: typeof SEQUENTIAL_EVIDENCE_VERSION; } /** * Alpha share for the k-th test in the stream: alphaTotal * 6/(pi^2 k^2). * Chosen over 2^-k because it decays polynomially — test 10 still gets a * workable ~0.6% of a 5% budget instead of ~0.005%. */ export declare function alphaForTest(testIndex: number, alphaTotal?: number): number; /** * Fold paired outcomes into an anytime-valid e-value and judge it against the * k-th test's allocated alpha. Deterministic; order of outcomes does not * change the final e-value (the product commutes). */ export declare function sequentialEvidenceVerdict(outcomes: PairedTaskOutcome[], testIndex: number, config?: SequentialEvidenceConfig): SequentialEvidenceVerdict; /** * Minimum number of INFORMATIVE (discordant) pairs a candidate must win — * with zero losses — to clear the k-th test's threshold: the smallest n with * (1+lambda)^n >= 1/alpha_k. The pre-flight power check (ADR-381 §4): an * evaluation whose promotion holdout is smaller than this cannot promote even * on a perfect sweep, so it should be refused BEFORE compute is spent and * before a doomed receipt can be presented to the gate (spending alpha). */ export declare function minInformativePairsToClear(testIndex: number, config?: SequentialEvidenceConfig): number; /** Family-wise budget left after `testsRun` allocated tests: alphaTotal - Σ alpha_k. */ export declare function remainingAlphaBudget(testsRun: number, alphaTotal?: number): number; export interface PairedEvidenceCheck { ok: boolean; reasons: string[]; } /** * Structural consistency between a receipt's paired outcomes and its * aggregate heldOutDeltas: same length and order, unique non-empty task IDs, * and each delta must equal candidateScore - baselineScore. This is what makes * paired outcomes EVIDENCE rather than decoration — an aggregate that cannot * be reproduced from its own per-task rows is refused. */ export declare function checkPairedOutcomesConsistency(pairedOutcomes: PairedTaskOutcome[], heldOutDeltas: number[], tolerance?: number): PairedEvidenceCheck; //# sourceMappingURL=flywheel-sequential-evidence.d.ts.map