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.
69 lines (68 loc) • 4.99 kB
JavaScript
/**
* # session/wake-frontier — the band-parameterized wake floor + the frontier's wake shapes
*
* The safety floor + the pending-wake / per-wake-context types the agent-driven wake frontier
* (kestrel-5zl.4) is built from, extracted from the Simulate driver ({@link import("./simulate.ts")}) so
* the band → floor table lives beside its own interface. After the T-5 OPEN baseline the AGENT drives its
* own monitoring cadence via `scheduleWake`; the platform FLOORS it (never replaces it) with the
* {@link WakeFloor} resolved here from the cell's timescale band.
*
* - {@link wakeFloorForBand} / {@link WakeFloor} — the pure `band → floor` table (kestrel-5zl.16.7); the
* DAY row reproduces today's day-shaped constants byte-for-byte (the no-churn anchor);
* - {@link FrontierWake} — a wake pending on the frontier (a dateless sim-time instant + its provenance);
* - {@link WakeCtx} — the per-wake context the driver knows that the snapshot does not.
*
* PURE: {@link wakeFloorForBand} is a total function of the band alone (no wall clock, no RNG) — same band
* ⇒ identical floor ⇒ byte-identical wake schedule. Safety can never be silenced (CLAUDE fail-closed); the
* floors are author-tunable config, never removable by the agent.
*/
import { assertNever } from "../lang/index.js";
// ── The band-parameterized wake floor (kestrel-5zl.16.7) ──────────────────────────────────────────
// The three wake-frontier controls below WERE day-shaped module constants; they are now the `day`
// row of a pure {@link wakeFloorForBand} table keyed on the cell's timescale band (`carry.band`, the
// multi-session horizon Axis A). The DAY row REPRODUCES today's exact defaults byte-for-byte (the
// no-churn anchor); the other rows scale the same three controls to their timescale. Threaded once at
// the top of `runSimulateSession` from `openingCarry.band` (default `day`), so a standalone /
// flat-open run is byte-identical to today. See the design note on kestrel-5zl.16.7.
/** The DAY staleness-backstop deadline (minutes): a gap longer than this after any delivered vantage
* forces a platform safety wake, so a book is never left unattended (CONTEXT "Staleness backstop").
* This is ALSO the universal fail-closed floor — a HELD book in a WIDER band whose backstop lands past
* settle still gets a safety wake before settle (never a silent no-wake window while exposed). */
export const DAY_STALENESS_BACKSTOP_MIN = 30;
/** The DAY minimum spacing (minutes) between DELIVERED wakes: an agent wake closer than this to the
* last vantage is FOLDED (coalesced) and surfaced on the retained delivery's `attention.coalesced` —
* never a separate turn, never a silent drop. The staleness/structural floors are exempt. */
const DAY_MIN_WAKE_SPACING_MIN = 1;
/** The DAY per-session ceiling on delivered wakes: past it the agent's wakes are folded (downgraded to
* safety-only) so a runaway cadence can't exhaust attention — the staleness/structural floors still fire
* (safety is never capped away). A generous default; the budget algebra proper is scoped to b3l. */
const DAY_MAX_WAKES = 512;
/**
* The band → {@link WakeFloor} table (kestrel-5zl.16.7). Pure + total (every {@link TimescaleBand} maps).
*
* band backstop spacing (coalesce) ceiling
* scalp 2 min 0.25 min (15 s) 4096 — seconds-scale, tick cadence
* day 30 min 1 min 512 — TODAY'S EXACT DEFAULTS (the no-churn anchor)
* swing 240 min (4 h) 5 min 512 — intraday → multi-day
* position 1440 min (~1 d) 15 min 512 — a ~1-day backstop + daily cadence
*
* The DAY row is the identity of today's day-shaped constants (byte-for-byte); the scalp/swing/position
* rows are the minimal shape consistent with `carry.band` + those defaults (design note on 5zl.16.7).
* The fail-closed floor (a HELD book in a WIDE band always keeps a backstop before settle — never a
* silent no-wake window while exposed) is enforced in `runSimulateSession`'s `armStaleness`, not
* by widening this table: widening cadence by band must never create a silent exposed window.
*/
export function wakeFloorForBand(band) {
switch (band) {
case "scalp":
return { stalenessBackstopMin: 2, minWakeSpacingMin: 0.25, maxWakes: 4096 };
case "day":
return { stalenessBackstopMin: DAY_STALENESS_BACKSTOP_MIN, minWakeSpacingMin: DAY_MIN_WAKE_SPACING_MIN, maxWakes: DAY_MAX_WAKES };
case "swing":
return { stalenessBackstopMin: 240, minWakeSpacingMin: 5, maxWakes: DAY_MAX_WAKES };
case "position":
return { stalenessBackstopMin: 1440, minWakeSpacingMin: 15, maxWakes: DAY_MAX_WAKES };
default:
return assertNever(band, "simulate: unknown timescale band");
}
}