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.
106 lines • 7.3 kB
TypeScript
/**
* # frame/kernel-walk — the ONE cockpit-kernel walk + the shared kernel helpers (ADR-0052 §1)
*
* The SAFETY / CONTROL cockpit kernel has exactly ONE traversal: {@link walkKernel} visits the
* optional mandate/brief prefix and then the 8 fixed-order {@link ./types.ts KERNEL_SECTION_LABELS}
* sections, IN ORDER, calling a {@link KernelSink} method for each. Every section method is ALWAYS
* called (absent-not-hidden is a structural property of the walk — a section can never be silently
* skipped), and the SECTION ORDER lives here once. The two shipped renderers are format ADAPTERS
* over this one walk: the canonical text sink ({@link ./render.ts}) materializes the delta-anchored
* cell-lines, the token-optimal ARM sink ({@link ./render-arm.ts}) materializes the compact ASCII
* lines. A new section, or a reordering, lands in BOTH renderers from a single edit here.
*
* This module also owns the kernel helpers both adapters share — the engine-log bucket set +
* classification, the resting-order state label, and the action id token — parameterized by the
* small vocabulary each adapter differs on, so the LOGIC is single-source while the BYTES stay each
* adapter's own. PURE: no wall clock, no RNG (the whole render path is deterministic, RUNTIME §0).
*/
import type { Brief, Claim, EngineAction, EngineActionKind, Kernel, Mandate, OwnerAct, Position, RestingOrder, VehicleHealth, WakeRef } from "./types.ts";
/**
* A format adapter for the cockpit kernel: {@link walkKernel} calls these in the fixed cockpit order
* and each implementation accumulates its own line representation (canonical cell-lines, arm strings).
* A section method is called EVEN WHEN its data is empty (absent-not-hidden) — the adapter renders the
* explicit `none`/`UNKNOWN` placeholder, never a dropped section. The `mandate`/`brief` methods are
* called ONLY when present (they are the optional standing-context prefix, not one of the 8 sections).
*/
export interface KernelSink {
/** The lead block: the kernel sentinel (canonical) / the `#KERNEL <kind>` banner (arm). */
sentinel(frameKind: "OPEN" | "WAKE"): void;
/** The `frame=<kind>` line (canonical only; the arm folds the kind into its sentinel). */
frameLine(frameKind: "OPEN" | "WAKE"): void;
/** MANDATE — the hard, machine-checkable admission channel (ADR-0026). Present-only. */
mandate(mandate: Mandate): void;
/** BRIEF — the soft, directional English channel; NOT an admission input (ADR-0026). Present-only. */
brief(brief: Brief): void;
/** §1 WAKE — reason / severity / RELATIVE deadline. */
wake(wake: WakeRef | null | undefined): void;
/** §2 DATA-HEALTH per vehicle + the NAMED unavailable capabilities. */
dataHealth(rows: readonly VehicleHealth[], unavailable: readonly string[]): void;
/** §3 POSITIONS / INVENTORY-CLAIMS. */
positions(positions: readonly Position[]): void;
/** §4 RESTING ORDERS. */
resting(resting: readonly RestingOrder[]): void;
/** §5 BUDGET / REMAINING-R + the sizing headroom. */
budget(envelope: BudgetEnvelopeArg): void;
/** §6 OWNER ENVELOPE + ACTS (the envelope echo reads the same budget as §5). */
ownerActs(envelope: BudgetEnvelopeArg, acts: readonly OwnerAct[]): void;
/** §7 L0/L1 ENGINE LOG — bucketed fired | cancelled | rejected | clamped (+ catch-all `other`). */
engineLog(elog: readonly EngineAction[]): void;
/** §8 PREDICTOR / REGIME CLAIMS. */
claims(claims: readonly Claim[]): void;
}
/** The budget-envelope argument §5 and §6 share (the cockpit risk envelope, or absent). */
export type BudgetEnvelopeArg = Kernel["budgetEnvelope"];
/**
* The ONE cockpit-kernel traversal: mandate/brief prefix (present-only) then the 8 fixed-order
* sections, each ALWAYS visited. This is the single source of the kernel's SECTION ORDER and its
* absent-not-hidden completeness — both format adapters get an identical structure from it. PURE.
*/
export declare function walkKernel(kernel: Kernel, frameKind: "OPEN" | "WAKE", sink: KernelSink): void;
/** The four engine-log buckets, in fixed render order — shared by both adapters. */
export declare const ENGINE_LOG_BUCKETS: readonly EngineActionKind[];
/** The engine log classified into the four fixed buckets (in order) + a catch-all `other` for any
* kind outside the closed union (arrived across an untyped/JSON/`as` boundary — surfaced, never
* dropped: absent-not-hidden). The classification is single-source; each adapter formats it. */
export interface EngineLogBuckets {
readonly buckets: readonly {
readonly kind: EngineActionKind;
readonly items: readonly EngineAction[];
}[];
readonly other: readonly EngineAction[];
}
/** Classify an engine log into the fixed buckets (order-preserving) + the catch-all `other`. PURE. */
export declare function bucketEngineLog(elog: readonly EngineAction[]): EngineLogBuckets;
/** The per-adapter label vocabulary for {@link restingLabel} — `live` and `clamped` are INDEPENDENT
* flags, so a live+clamped order surfaces BOTH (a `live` label can never mask a premium-band clamp). */
export interface RestingLabels {
readonly live: string;
readonly liveClamped: string;
readonly clamped: string;
readonly off: string;
}
/** The resting-order state label under an adapter's vocabulary. `live`/`clamped` independent
* (fail-closed honesty: a clamped price is never hidden by a LIVE label). PURE. */
export declare function restingLabel(o: RestingOrder, labels: RestingLabels): string;
/** The per-adapter shape of an engine action's id token (canonical `id@seqN (reason)`, arm
* `id@N(reason)`). `seqPrefix` sits between `@` and the ordinal; `reasonSpace` inserts a space
* before the `(reason)` group. Reason-when-present: no reason ⇒ byte-identical to the id@seq alone. */
export interface ActionTokenStyle {
readonly seqPrefix: string;
readonly reasonSpace: boolean;
}
/** An engine action's render token `id@<seqPrefix><ordinal>` plus `(reason)` WHEN present (the
* engine-authored cause — never-naked / plan-budget / regime-UNKNOWN — that must not be silently
* dropped at the render seam, kestrel-75n). PURE. */
export declare function actionToken(e: EngineAction, style: ActionTokenStyle): string;
/**
* A bucket's action tokens with each CONSECUTIVE RUN of items sharing an identical `(id, reason)`
* collapsed to `<count>x <exemplar token>` instead of N near-duplicate tokens (kestrel-7bip). A plan
* whose STATE trigger holds every tick emits the SAME refusal (`uncovered sell refused: never naked`)
* once per tick — 24 byte-identical entries in one frame — flooding the very percept the token-optimal
* renderer exists to conserve. The de-dup is a RENDER-time collapse ONLY (the engine still authors and
* counts every action; the bucket's `items.length` count is unchanged): a run of one renders as the
* bare token (byte-identical to pre-collapse, so no existing frame churns), and the exemplar keeps its
* real `@seq` so the collapsed line stays a concrete, addressable receipt. Order-preserving; PURE. */
export declare function collapseActionTokens(items: readonly EngineAction[], style: ActionTokenStyle): string[];
//# sourceMappingURL=kernel-walk.d.ts.map