UNPKG

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.

112 lines (111 loc) 7.2 kB
/** * # bus/anchor-ledger — the SPOT-anchor UNKNOWN-window ledger + fail-closed under-report validator (ven.4) * * The de-arm PRIMITIVE already lives in the series layer: an unresolvable value anchor reads * UNKNOWN (`CanonicalState.spot: number | Unknown`) and any statement/detector referencing it * de-arms with a logged reason — it can never fire on a value it does not have (fail-closed, * RUNTIME §3/§8). What was missing is a **LEDGER** of those value gaps: a past-only record a * consumer can read so it is never misled into thinking a gapped/dead-feed window carried a real * value. * * ## ONE TRUTH — the ledger records EXACTLY the de-arm's windows (never a forked concept) * The value anchor is UNKNOWN precisely while no SPOT for the signal instrument has been folded — * the exact condition `CanonicalState.applyEvent` uses to set `spotVal` (a `TICK`/`SPOT` event for * the matching instrument; RUNTIME §2). This module re-derives THAT SAME predicate at the bus layer * — it does not import the series layer (the module spine is `series → bus`, never the reverse), so * the equivalence is proved event-by-event by the ven.4 suite rather than by a cross-layer call. * The ledger's covered seqs therefore equal the seqs where `CanonicalState.spot === UNKNOWN`: the * detectors de-arm across exactly the windows the ledger records. One truth, not two. * * ## PAST-ONLY / NO-LOOKAHEAD (RUNTIME §0) * A window is derived by a single forward replay; every `{start,end,dur}` bound is an * already-elapsed event. A window that resolves ends at the LAST still-UNKNOWN event — the event * *before* the resolving SPOT — never the resolver and never a synthetic future sentinel. A window * still open at end-of-tape ends at the last elapsed event. `dur = end.ts - start.ts`. No wall * clock, no RNG: same bus ⇒ byte-identical ledger (the determinism invariant). * * ## NO UNDER-REPORT — honest BY CONSTRUCTION (kestrel-voy9) * The ledger can never under-report the gaps, because {@link spotAnchorUnknownWindows} IS the sole * derivation: it replays the de-arm predicate forward and records EXACTLY the seqs the anchor read * UNKNOWN (a dropped window, a later start, an earlier end, a shortened `dur` are all unrepresentable * — the derivation emits the real span or nothing). The ONE-TRUTH property is proved end-to-end in * the ven.4 suite by driving this real derivation and asserting its covered seqs BYTE-MATCH the * series-layer `CanonicalState.spot === UNKNOWN` primitive, event-by-event, across a resolving, a * never-resolving, and a px-blind bus. There is NO standalone under-report validator: a guard that * only ever re-checks this same constructor's own honest output is a tautology (it can never fire), * and no production path SUPPLIES a foreign ledger to validate — so the honesty lives in the * construction, not in an unreachable export. */ /** * The de-arm predicate, re-derived at the bus layer to be BYTE-EQUAL to `CanonicalState.spot`'s fold * condition (ONE TRUTH — not a forked concept that could diverge). The series primitive folds a value * into the anchor via `onSpot(ev.ts, ev.px)` — reached only for a `TICK`/`SPOT` of the matching signal * instrument — and then reads `spot === spotVal ?? UNKNOWN`. So the anchor RESOLVES iff such a SPOT * carries a `px` that is neither `undefined` nor `null` (`spotVal ?? UNKNOWN` stays UNKNOWN when * `spotVal` is nullish; a `NaN` or a real number both fold to a non-nullish `spotVal` and read known). * The `ev.px != null` guard reproduces that exactly: a reader-accepted SPOT whose `px` is missing/null * (a torn/partial TICK the envelope validator lets through — {@link ../bus/read.ts}) leaves the window * OPEN, matching the primitive that stays UNKNOWN there; only a `px`-bearing (NaN/number) SPOT closes * it. A SPOT for any OTHER instrument never reaches `onSpot` and so never resolves this anchor (it is * instrument-scoped) — the window stays open, exactly as the series-layer primitive behaves. */ function isAnchorSpot(ev, instrument) { return (ev.stream === "TICK" && ev.type === "SPOT" && ev.instrument === instrument && ev.px != null); } /** * Derive the SPOT-anchor UNKNOWN-window ledger from a bus, purely and deterministically * (RUNTIME §0). A single forward replay: the anchor is UNKNOWN until the first px-bearing SPOT for * `instrument` is folded, at which point it resolves. * * The value anchor is **STICKY**: `CanonicalState.spotVal` is set once by `onSpot` and, on a * well-formed tape, never reverts (barring a `CanonicalState` reset, which this replay does not * model), so the `anchorKnown` latch below likewise never resets. This replay therefore records * **exactly the LEADING window** — the pre-first-spot gap — and, when no SPOT ever resolves the * anchor, the whole tape as one window. It does NOT record a mid-session lapse back to UNKNOWN: that * "gapped/dead-feed mid-session staleness" is a SEPARATE primitive concern (a staleness/heartbeat * backstop over `spotTs`, not the value-anchor de-arm this ledger mirrors) and is out of scope here — * mirroring it would be forking a second window concept, which ONE TRUTH forbids. Every bound is * past-only. The input is never mutated. * * @param events the bus, in `seq` order (as the writer emits it). * @param instrument the signal instrument whose value anchor is tracked (mirrors * `CanonicalStateConfig.instrument`). * @returns the leading window the anchor was UNKNOWN (0 or 1 windows), in `seq` order — the same span * the value-anchor de-arm covers. */ export function spotAnchorUnknownWindows(events, instrument) { const windows = []; let start; // the first event of the current open UNKNOWN run let last; // the most recent still-UNKNOWN event of that run let anchorKnown = false; // has a px-bearing SPOT for `instrument` been folded? (spotVal != null) const close = () => { if (start !== undefined && last !== undefined) { windows.push({ start, end: last, dur: last.ts - start.ts }); } start = undefined; last = undefined; }; for (const ev of events) { // Fold this event FIRST — the resolving SPOT resolves the anchor AT its own seq, so it is KNOWN // there and the window ended at the previous (last still-UNKNOWN) event. This matches the series // primitive, where `state.spot` is already known once `applyEvent(spot)` returns. if (isAnchorSpot(ev, instrument)) anchorKnown = true; if (anchorKnown) { close(); // the anchor is known at ev → close any run that was open through the previous event. } else { const at = { seq: ev.seq, ts: ev.ts }; if (start === undefined) start = at; last = at; } } // A run still open at end-of-tape never resolved — it ends at the last ELAPSED event (no future // sentinel; past-only). A fully-UNKNOWN session is thus one window spanning the whole tape. close(); return windows; }