kestrel.markets
Version:
A typed, token-efficient language + runtime for agentic trading: agents author bounded plans, the runtime fires them at the tick. CLI + typed library + MCP server.
396 lines • 26.9 kB
TypeScript
/**
* # session/grid — the Simulate config-comparison harness: buildGrid + CellAggregate + leaderboard (kestrel-5zl.8)
*
* THE POINT of Simulate: the SAME recorded tape graded under N configs → a GRID of graded
* {@link import("../blotter").Blotter}s → a pure comparison LEADERBOARD. This module is the two PURE
* derivations that turn a set of FINALIZED Blotters into that grid + table — no wall clock, no RNG
* (RUNTIME §0) — and it is a MEASUREMENT / reporting layer: it only READS the finalized record, and never
* writes a byte back onto the graded bus or the Blotter (zero golden / e2e churn), and stamps NO new schema
* field. It builds strictly on the run-identity layer (5zl.7 {@link cellOf}) + the config layer (5zl.6):
*
* 1. {@link buildGrid} — `(runs: readonly Blotter[]) → Grid`. Group the finalized Blotters by their 5zl.7
* {@link cellOf} CellKey (tape × fill_model × config-ConfigId). Runs sharing a CellKey are REPLICATES in
* one comparison cell; each replicate keeps a DISTINCT SimRunId, read straight off the finalized record
* as `blotter.session.bus.sha256` (which equals `SimRunId(gradedBus)` — the 5zl.7 pure-read
* reconciliation, so no raw bus is needed). Each cell is a {@link CellAggregate} over its replicate runs.
*
* 2. {@link CellAggregate} — the honest measurements across a cell's replicate runs, using the Session/day
* (one finalized Blotter = one run) as the INDEPENDENT EVIDENCE UNIT, and REPORTING UNCERTAINTY: every
* numeric axis is a {@link Dist} — `{ n, mean, min, max, stdev }` — a distribution/spread over the
* replicates, NEVER a single cherry-picked point (a single-run cell reports `n = 1`, spread `0` — still a
* distribution, never a bare scalar). The axes come straight off the Blotter: financial (EV / P&L), risk,
* process, fidelity, provider, cost — plus a {@link CertificationBreakdown}.
*
* 3. {@link leaderboard} — `(grid: Grid) → readonly LeaderboardRow[]`. A pure comparison table: ONE ROW PER
* CELL, the honest multi-axis measurements reported SIDE BY SIDE with per-axis uncertainty, and NO opaque
* omnibus score (the m9i principle: "report the financial, risk, process, attention, provider, and
* interface measurements WITHOUT an opaque omnibus score"). The axes are laid out; they are never blended
* into one number, and never sorted into a rank — the caller reads the axes it cares about.
*
* ## Determinism (RUNTIME §0 — a CI invariant)
* Both derivations are PURE and INPUT-ORDER-INSENSITIVE: the same runs in ANY order ⇒ a byte-identical grid
* and table. buildGrid sorts the cells by CellKey and each cell's replicates by SimRunId BEFORE any
* aggregation, so every reduction (mean, stdev, …) folds over a FIXED order — no order-dependent float drift.
*
* ## Honesty (the 5zl.8 mandate)
* The config axis of a cell is the FULL ConfigId (`session.config_id`, m9i.2 owner tweak) — a PROVISIONAL
* run keys by its own stamped ConfigId (or, absent any config identity, the NO_ENVELOPE sentinel), so it
* lands in its OWN cell, distinct from every differently-configured cell, and can NEVER be silently absorbed
* into a certified cell's numbers (a provisional and a certified run can only share a cell by sharing the
* ENTIRE config — and an identical config yields an identical completeness verdict). The cell's
* {@link CertificationBreakdown} carries the certified/provisional COUNTS and a WORST-CASE verdict
* (provisional if ANY replicate is provisional) — the projector's grade is surfaced, never laundered.
* Provider / cost read the run's `session.envelope`, absent (`null`) for a no-envelope / provisional cell —
* an honest gap, never a fabricated identity.
*/
import type { Blotter, ExperimentalEnvelope, FidelitySelfLimitation, Verdict } from "../blotter/index.ts";
/**
* The distribution of one numeric measurement over a cell's replicate runs — the honest unit of the
* leaderboard. `n` is the number of independent evidence units (Session/day runs) the measurement rests on;
* `mean` is their arithmetic mean; `min`/`max`/`stdev` are the SPREAD — the uncertainty around the mean.
* A single-run cell still reports a Dist (`n = 1`, `min = max = mean`, `stdev = 0`) — never a bare scalar, so
* a consumer can never mistake one run for a converged estimate. `stdev` is the POPULATION standard deviation
* (divide by `n`, not `n − 1`): a descriptive spread of the runs in hand, not an inferential estimator.
*/
export interface Dist {
/** The number of replicate runs (Session/day evidence units) this distribution rests on. */
readonly n: number;
/** The arithmetic mean of the per-run measurements. */
readonly mean: number;
/** The smallest per-run measurement (the low end of the spread). */
readonly min: number;
/** The largest per-run measurement (the high end of the spread). */
readonly max: number;
/** The population standard deviation of the per-run measurements (0 for a single-run cell). */
readonly stdev: number;
}
/** Summarize a fixed-order list of per-run measurements as a {@link Dist}. PURE — folds in the caller's
* (deterministic) order, so the same values always yield byte-identical floats. `values` is never empty (a
* cell always holds ≥ 1 run). Exported so other measurement layers (e.g. the percept-lab score log,
* kestrel-m9i.12) fold their replicate probes with the SAME semantics and their rows port into this grid. */
export declare function distOf(values: readonly number[]): Dist;
/**
* The cell underlier's price series over the horizon plus the units held — the source of the buy-and-hold
* BASELINE (kestrel-m9i.19). The driver extracts the open → close SPOT series of the cell underlier from the
* cell tape and hands it in (grid never reaches into the bus): `prices[0]` is the OPEN, `prices[last]` the
* CLOSE, and `qty` the units held across the horizon. `symbol` is the underlier (SPY for an equity basket, BTC
* for crypto — §4.1 public benchmark vocabulary), surfaced onto the {@link Benchmark} for provenance.
*/
export interface UnderlierHold {
/** The underlier symbol held over the horizon (SPY for an equity basket, BTC for crypto — §4.1). */
readonly symbol: string;
/** The underlier price series over the cell horizon: `[0]` = open, `[last]` = close (read off the cell tape). */
readonly prices: readonly number[];
/** The units of the underlier held across the horizon. */
readonly qty: number;
}
/**
* The buy-and-hold P&L of an underlier over the horizon (kestrel-m9i.19): `qty × (close − open)`, where
* `open = prices[0]` and `close = prices[last]`. PURE + byte-stable (no wall clock, no RNG — RUNTIME §0): the
* interior prints don't matter, the hold is open → close and `qty` scales it linearly. FAIL-CLOSED — an
* underlier price the baseline needs but cannot resolve (an empty series, or a non-finite open / close / qty)
* is a typed refusal, NEVER a silent 0 (a silent 0-alpha would launder market direction as judgment).
*/
export declare function buyAndHoldBaseline(hold: UnderlierHold): number;
/** The benchmark sub-axis of the financial axis (kestrel-m9i.19): the per-cell buy-and-hold BASELINE plus the
* benchmark-relative ALPHA, reported ALONGSIDE the absolute `expected` EV (never replacing it). Position /
* swing / crypto cells are BETA-dominated — absolute P&L there measures market DIRECTION, not judgment — so
* this rides the cell EV against a buy-and-hold of the cell underlier (SPY for an equity basket, BTC for
* crypto — §4.1) over the cell horizon. Present ONLY when a per-cell hold is supplied to {@link buildGrid};
* ABSENT (the field is not stamped) otherwise, so an un-baselined cell is byte-identical to today's grid. */
export interface Benchmark {
/** The underlier held over the horizon for the baseline (SPY for equity, BTC for crypto — §4.1). */
readonly symbol: string;
/** The buy-and-hold P&L of that underlier over the horizon ({@link buyAndHoldBaseline}) — a scalar $ amount,
* the provenance `alpha` is measured against (mirrors 5zl.16.8 `InstanceFinancial.baseline`). */
readonly baseline: number;
/** The benchmark-relative alpha as a {@link Dist} over the replicates: `alpha_i = expected_i − baseline`, so
* `alpha.mean = cell EV − baseline` (the 5zl.16.8 identity), reported WITH grid-consistent uncertainty. */
readonly alpha: Dist;
}
/** The financial (EV / P&L) axis — the conservative definite-fill floor and the expected total, plus the
* expected-$ partitioned by fill support (the `calibrated` slice a grader banks vs the `extrapolated` slice it
* refuses to bank, 9gu.3). Each a distribution over the cell's replicate runs. */
export interface FinancialAxis {
/** `totals.floor` — realized / definite-fill $ — across the replicates. */
readonly floor: Dist;
/** `totals.expected` — E[$] — across the replicates. */
readonly expected: Dist;
/** The `calibrated`-support slice of `totals.expected` (a grader banks this). */
readonly calibrated: Dist;
/** The `extrapolated`-support slice of `totals.expected` (a grader refuses to bank this). */
readonly extrapolated: Dist;
/** The per-cell benchmark baseline + benchmark-relative alpha (kestrel-m9i.19), reported ALONGSIDE the
* absolute `expected` EV. Present ONLY when a per-cell hold is supplied to {@link buildGrid}; the field is
* OMITTED otherwise (no grid churn — an un-baselined cell is byte-identical to today's). */
readonly benchmark?: Benchmark;
}
/** The risk axis — the headline taint and the far-OTM directional-cap disposition (9gu.6). Reported as honest
* counts / a union of reasons across the cell's replicate runs (categorical, not a numeric distribution). */
export interface RiskAxis {
/** How many replicate runs carried a TAINTED headline (`totals.headline.tainted`). */
readonly tainted_runs: number;
/** The union of `totals.headline.reasons` across the replicates, de-duplicated and sorted (deterministic). */
readonly headline_reasons: readonly string[];
/** The far-OTM directional-cap disposition tallied over every order in every replicate run (9gu.6). */
readonly directional_cap: {
readonly applied: number;
readonly exempt: number;
readonly na: number;
};
}
/** The process axis — the shape of the run's activity (orders, fills, reprices, plans), each a distribution
* over the cell's replicate runs. */
export interface ProcessAxis {
/** The placed-order count per run. */
readonly orders: Dist;
/** The definite-fill count per run (`orders[].filled`). */
readonly fills: Dist;
/** Σ `orders[].reprice_count` per run — the cancel/replace churn. */
readonly reprices: Dist;
/** The plan-record count per run. */
readonly plans: Dist;
}
/** The fidelity axis — the realism `level` breakdown plus the judge's self-limitation (what the fill model
* structurally could NOT observe). The self-limitation is invariant across a cell (the fill model is a CellKey
* axis), so it is reported once. */
export interface FidelityAxis {
/** The count of replicate runs at each fidelity level (e.g. `{ modeled: 3 }`) — the level breakdown. */
readonly levels: Readonly<Record<string, number>>;
/** The judge's self-limitation (fill model + what it could not observe) — invariant across the cell. */
readonly self_limitation: FidelitySelfLimitation;
}
/** The cost axis — the INJECTED token accounting (`session.envelope.token_accounting`), each a distribution
* over the cell's replicate runs. Config-level in the current schema (constant across a cell's replicates), so
* the spread is `0` — reported honestly as a Dist all the same. */
export interface CostAxis {
readonly input: Dist;
readonly output: Dist;
readonly thinking: Dist;
}
/** The certification breakdown of a cell — the projector's grade, surfaced, never laundered: the
* certified/provisional replicate COUNTS plus a WORST-CASE verdict (provisional if ANY replicate is
* provisional). A provisional run is thus never rendered as if certified. */
export interface CertificationBreakdown {
/** How many replicate runs the projector graded `certified`. */
readonly certified: number;
/** How many replicate runs the projector graded `provisional`. */
readonly provisional: number;
/** The cell's worst-case verdict: `provisional` if any replicate is provisional, else `certified`. */
readonly verdict: Verdict;
}
/** The rankable breakdown of a cell (kestrel-m9i.25) — the DERIVED leaderboard-ELIGIBILITY axis, surfaced
* DISTINCTLY from {@link CertificationBreakdown}. The two are ORTHOGONAL: a cell can be
* `certification.verdict === "certified"` yet `rankable.verdict === false` (a certified PRE-cutoff cell).
* The rankable/not-rankable replicate COUNTS plus a WORST-CASE verdict — the cell is rankable ONLY if EVERY
* replicate is rankable (one not-rankable replicate makes the cell not rankable), mirroring the
* worst-case discipline of the certification breakdown. */
export interface RankableBreakdown {
/** How many replicate runs the projector derived `rankable`. */
readonly rankable: number;
/** How many replicate runs the projector derived NOT rankable. */
readonly not_rankable: number;
/** The cell's worst-case verdict: `true` only if every replicate is rankable, else `false`. */
readonly verdict: boolean;
}
/**
* The aggregate of ONE comparison cell — the honest, multi-axis measurements over the cell's replicate runs,
* each reported WITH uncertainty (a {@link Dist} for every numeric axis) and keyed to the cell's 5zl.7
* CellKey. Deliberately carries NO blended / omnibus score: the axes stand side by side (the m9i principle).
*/
export interface CellAggregate {
/** The 5zl.7 CellKey (tape × fill_model × config-ConfigId) this cell aggregates — its stable identity. */
readonly cell: string;
/** The number of replicate runs (Session/day evidence units) in this cell. */
readonly runs: number;
/** The DISTINCT SimRunIds of the replicates (= `session.bus.sha256`), sorted for a byte-stable order. */
readonly runIds: readonly string[];
/** The financial (EV / P&L) axis. */
readonly financial: FinancialAxis;
/** The risk axis (headline taint + directional-cap disposition). */
readonly risk: RiskAxis;
/** The process axis (orders / fills / reprices / plans). */
readonly process: ProcessAxis;
/** The fidelity axis (level breakdown + judge self-limitation). */
readonly fidelity: FidelityAxis;
/** The provider axis — the a57.14 experimental envelope (the author's identity), invariant across the cell,
* or `null` for a no-envelope cell (an honest gap, never a fabricated identity). */
readonly provider: ExperimentalEnvelope | null;
/** The cost axis (injected token accounting), or `null` when the cell declares no envelope. */
readonly cost: CostAxis | null;
/** The certification breakdown — the projector's grade, surfaced. */
readonly certification: CertificationBreakdown;
/** The rankable breakdown (kestrel-m9i.25) — the DERIVED leaderboard-eligibility axis, surfaced DISTINCTLY
* from {@link certification} (a certified cell can be not rankable). */
readonly rankable: RankableBreakdown;
}
/** The config-comparison GRID: the deterministically ordered set of {@link CellAggregate}s, one per distinct
* CellKey. Cells are sorted by CellKey so the grid is byte-stable regardless of input order. */
export interface Grid {
readonly cells: readonly CellAggregate[];
}
/**
* The ADDITIVE options of {@link buildGrid} (kestrel-m9i.19): a per-cell buy-and-hold BASELINE source, keyed by
* the 5zl.7 {@link cellOf} CellKey (the tape axis already identifies the cell underlier). A cell WITH a supplied
* hold gets a `financial.benchmark` (baseline + alpha); a cell WITHOUT one is byte-identical to today's grid.
* The whole options object is OPTIONAL — `buildGrid(runs)` and `buildGrid(runs, {})` are byte-identical to each
* other and to today's grid (no churn).
*/
export interface BuildGridOptions {
/** Per-cell (CellKey → {@link UnderlierHold}) — the buy-and-hold source for that cell's benchmark baseline. */
readonly baselines?: ReadonlyMap<string, UnderlierHold>;
}
/**
* Group a set of FINALIZED Blotters into the config-comparison {@link Grid} (kestrel-5zl.8). Each run is keyed
* by its 5zl.7 {@link cellOf} CellKey (tape × fill_model × config-ConfigId); runs sharing a key are REPLICATES
* aggregated into one {@link CellAggregate} (each keeping a distinct SimRunId). PURE and
* INPUT-ORDER-INSENSITIVE: cells are sorted by CellKey and each cell's replicates by SimRunId before any
* aggregation, so the same runs in ANY order yield a byte-identical grid (RUNTIME §0). Reads finalized
* Blotters only — writes no bus/Blotter byte, stamps no schema field.
*
* ADDITIVE (kestrel-m9i.19): the optional 2nd arg supplies a per-cell buy-and-hold BASELINE. A cell whose
* CellKey appears in `opts.baselines` gets a `financial.benchmark` (the baseline + benchmark-relative alpha,
* ALONGSIDE absolute EV); every other cell — and the whole grid when no options are supplied — is BYTE-IDENTICAL
* to today's. The baseline touches neither CellKey nor SimRunId nor the leaderboard row shape. FAIL-CLOSED: an
* unresolvable supplied underlier price propagates {@link buyAndHoldBaseline}'s typed refusal (never a silent 0).
*/
export declare function buildGrid(runs: readonly Blotter[], opts?: BuildGridOptions): Grid;
/** One row of the {@link leaderboard} — one comparison cell's honest measurements laid out SIDE BY SIDE with
* per-axis uncertainty. Deliberately carries NO omnibus / composite / rank field (the m9i principle). */
export interface LeaderboardRow {
/** The 5zl.7 CellKey this row reports on. */
readonly cell: string;
/** The replicate (Session/day evidence-unit) count behind this row's measurements. */
readonly runs: number;
/** The distinct SimRunIds of the replicates (provenance for the row's numbers). */
readonly runIds: readonly string[];
/** The financial axis, WITH uncertainty. */
readonly financial: FinancialAxis;
/** The risk axis. */
readonly risk: RiskAxis;
/** The process axis, WITH uncertainty. */
readonly process: ProcessAxis;
/** The fidelity axis. */
readonly fidelity: FidelityAxis;
/** The provider (envelope identity) axis, or `null`. */
readonly provider: ExperimentalEnvelope | null;
/** The cost axis, WITH uncertainty, or `null`. */
readonly cost: CostAxis | null;
/** The certification breakdown — a provisional cell is surfaced as provisional, never as certified. */
readonly certification: CertificationBreakdown;
/** The rankable breakdown (kestrel-m9i.25) — leaderboard ELIGIBILITY, a DISTINCT axis from
* {@link certification}: a row can be `certification.verdict === "certified"` yet `rankable.verdict === false`. */
readonly rankable: RankableBreakdown;
}
/**
* Project a {@link Grid} into the comparison LEADERBOARD (kestrel-5zl.8): ONE ROW PER CELL, the honest
* multi-axis measurements reported SIDE BY SIDE with per-axis uncertainty, and NO opaque omnibus score — the
* axes are laid out, never blended into one number and never sorted into a rank (the m9i principle). PURE and
* deterministic: the row order mirrors the grid's (CellKey-sorted), so the same grid always yields a
* byte-identical table.
*/
export declare function leaderboard(grid: Grid): readonly LeaderboardRow[];
/**
* One link of the Instance's chained-cash ledger — session `ordinal`'s place in the running P&L chain, a PURE
* read of the finalized per-session Blotter. `openingCash` is the cash session N+1 OPENS from (= session N's
* `closingCash`), `realized` is the session's definite-fill floor (`totals.floor`), and `closingCash =
* openingCash + realized`. This re-derives, purely from the ordered Blotters, the exact chain `carry.ts`
* threads (`carry.cash = prior.cash + settle.floorTotal`, and `settle.floorTotal === totals.floor`).
*/
export interface SessionLink {
/** The session ordinal `k` (its position in the ordered sequence). */
readonly ordinal: number;
/** The session's {@link SimRunId} (`session.bus.sha256`) — provenance for this link of the chain. */
readonly runId: string;
/** The cash this session OPENS from — session `k-1`'s `closingCash` (`0` at the sequence origin). */
readonly openingCash: number;
/** The session's realized / definite-fill P&L (`totals.floor`) — the chain increment. */
readonly realized: number;
/** The cash this session CLOSES at — `openingCash + realized`, carried into session `k+1`'s open. */
readonly closingCash: number;
}
/**
* The Instance's financial axis — the chained cash of the whole horizon plus the benchmark-relative ALPHA
* hook. `cash` is the final running cash of the chain (`Σ per-session realized floor`); `instanceEV` is the
* chained expected value (`Σ totals.expected`); `alpha = instanceEV − baseline` is the honest judgment axis
* (ONE measure alongside `cash`/`instanceEV`, never a top-level collapse), and `baseline` is surfaced as the
* provenance of that alpha. A missing / non-finite baseline is a typed refusal, never a silent 0-alpha default.
*/
export interface InstanceFinancial {
/** The chained cash of the whole horizon (`Σ per-session realized floor` = the final `closingCash`). */
readonly cash: number;
/** The chained expected value of the whole horizon (`Σ totals.expected`). */
readonly instanceEV: number;
/** The benchmark-relative alpha: `instanceEV − baseline` (one honest axis, never raw EV, never raw beta). */
readonly alpha: number;
/** The supplied benchmark expected value (in $) alpha is measured against — the provenance of `alpha`. */
readonly baseline: number;
}
/**
* The sequence-level GRADE of an Instance — the honest multi-axis measurements over the ordered sequence,
* each an axis reported SIDE BY SIDE, with NO opaque omnibus score (the m9i principle). The `financial` axis
* is the CHAINED, benchmark-relative {@link InstanceFinancial}; the non-financial axes
* (risk/process/fidelity/provider/cost/certification) reuse the EXISTING grid axes ({@link aggregateCell})
* over the sessions-as-replicate-runs, so a length-1 Instance's non-financial axes are BYTE-IDENTICAL to
* today's single-Session grid cell.
*/
export interface InstanceGrade {
/** The chained + benchmark-relative financial axis. */
readonly financial: InstanceFinancial;
/** The risk axis (headline taint + directional-cap disposition) over the sessions. */
readonly risk: RiskAxis;
/** The process axis (orders / fills / reprices / plans) over the sessions. */
readonly process: ProcessAxis;
/** The fidelity axis (level breakdown + judge self-limitation) over the sessions. */
readonly fidelity: FidelityAxis;
/** The provider axis — the a57.14 experimental envelope, or `null` for a no-envelope Instance. */
readonly provider: ExperimentalEnvelope | null;
/** The cost axis (injected token accounting), or `null` when no envelope is declared. */
readonly cost: CostAxis | null;
/** The certification breakdown — the projector's grade over the sessions, surfaced. */
readonly certification: CertificationBreakdown;
}
/**
* The aggregate of ONE multi-session **Instance** (kestrel-5zl.16.8): the ORDERED sequence of per-session
* {@link SessionLink}s (the chained-cash ledger) plus the sequence-level {@link InstanceGrade}, keyed by the
* Instance's 5zl.16.5 identity. Deliberately carries NO blended / omnibus score — the axes stand side by side
* (the m9i principle); alpha is ONE honest axis inside `financial`, never a collapse.
*/
export interface InstanceBlotter {
/** The whole Instance's identity — `sha256` of the ORDERED per-session SimRunIds (kestrel-5zl.16.5). */
readonly instanceRunId: string;
/** The Instance's sequence CELL key — the ordered per-session {@link cellOf} keys (length-1 unchanged). */
readonly sequenceCellKey: string;
/** The ordered chained-cash ledger — one {@link SessionLink} per session, in SEQUENCE order. */
readonly sessions: readonly SessionLink[];
/** The sequence-level grade — honest multi-axis, chained financial + benchmark-relative alpha, NO omnibus. */
readonly grade: InstanceGrade;
}
/** Build options for {@link buildInstanceBlotter} — the supplied benchmark against which alpha is measured. */
export interface BuildInstanceBlotterOptions {
/** The benchmark expected value (in $) alpha subtracts from `instanceEV`. Required + finite (fail-closed). */
readonly baseline: number;
}
/**
* Fold the ORDERED per-session Blotters of a multi-session Instance into ONE {@link InstanceBlotter}
* (kestrel-5zl.16.8) — a PURE read of the finalized sequence (no wall clock, no RNG — RUNTIME §0; no bus /
* Blotter byte written, no schema field stamped). Where {@link buildGrid} folds order-INSENSITIVE REPLICATES
* into a distribution, this folds an order-SENSITIVE SEQUENCE into one CHAINED record — the ordering IS the
* semantics. Three things:
*
* 1. CHAINS per-session cash across the sequence: session N+1 OPENS from session N's carried cash
* (`openingCash[k] = closingCash[k-1] = Σ_{j<k} realized_j`, `realized_k = totals.floor`), exactly
* re-deriving the chain `carry.ts` threads (`carry.cash = prior.cash + settle.floorTotal`). Deterministic
* + byte-stable: the ledger folds in SEQUENCE order (no clock, no RNG). `grade.financial.cash` is the
* final running cash.
* 2. a sequence-level GRADE — the financial axis chained; the non-financial axes reuse the EXISTING grid
* axes ({@link aggregateCell}) over the sessions-as-replicate-runs, so a LENGTH-1 Instance's non-financial
* axes are BYTE-IDENTICAL to `buildGrid([bl]).cells[0]` (NO existing-grid churn). NO opaque omnibus score.
* 3. a benchmark-relative ALPHA hook — `alpha = instanceEV − baseline`, `instanceEV = Σ totals.expected`.
* alpha lives INSIDE the financial axis, one honest measure — never a collapsed single score.
*
* FAIL-CLOSED: an empty (unstitchable) sequence, or a missing / non-finite baseline, is a typed refusal —
* never a silent default (no silent 0-alpha).
*/
export declare function buildInstanceBlotter(orderedBlotters: readonly Blotter[], opts: BuildInstanceBlotterOptions): InstanceBlotter;
//# sourceMappingURL=grid.d.ts.map