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 • 5.24 kB
TypeScript
/**
* # frame/seat — the pod SEAT roster: the closed `role` axis of the TemplateRecord cell key
* (ADR-0041 §2, Amendment A1 / kestrel-wa0j.52)
*
* A **Seat** is a role in the pod org, fixed by the deliberation budget it can afford (CONTEXT.md
* "Seat"): a PM allocates + discovers, a Strategist frames + authors, a Watcher manages + escalates.
* ADR-0041 §2 makes `role` a first-class axis of the evidence cell key **because a pane's sign is
* role-dependent** — a restraint pane can be passivity for the strategist (whose authored exit
* already prices the fakeout) yet correct for the watcher managing a stop-less trap. Pooling grades
* across seats is therefore ill-typed, and the roster is the schema of that phantom index.
*
* ## Why the roster is pinned NOW, closed, while the ledger is empty (kestrel-wa0j.52)
* ADR-0041 §2 pins `instrumentClass` NOW on the argument that a cell-key axis VALUE added after the
* first TemplateRecord is an evidence-splitting migration. Amendment A1 applies the SAME argument to
* the `role` axis's VALUE ROSTER: the ledger currently writes `role ∈ {strategist, watcher}`, but the
* PM-seat percepts (scan-fire read-why, the aggregates cockpit) are beaded, and if `pm` is added to
* the roster after pm-cell grading starts under a workaround key, the evidence splits exactly the way
* the ADR forbids. So the roster is pinned to the full seat set **`{pm, strategist, watcher}`** now,
* CLOSED — opened only by ceremony — while it costs one enum value and zero migration.
*
* ## What is NOT a seat (the seat-vs-mechanism distinction, kestrel-wa0j.52 reconciliation)
* `risk` is the **L0 layer**, not a seat — strictly subtractive (clamps/vetoes, never opens risk),
* its rendered surface the kernel safety block; a `riskmgr` persona is a Brief style on a seat, not a
* seat. `Trigger` is a non-LLM reflex TIER with no judgment cells to grade. `Historian` works
* off-tape on the policy (Brief) channel, not perception. `risk` stays a ceremony-addable VALUE if an
* auditing/reading agent seat is ever earned — adding a value later does not split evidence (old
* records stay keyed; a new value opens new cells by ceremony), which is exactly why only the AXIS
* (not each value) had to be pinned pre-ledger, and the seat roster is pinned to what shipped doctrine
* names today.
*
* ## Distinct from the cost-tier `Tier` ({@link ../session/harness/roster.ts})
* `harness/roster.ts` has its own `Tier = "strategist" | "watcher"` — the **serving-lane cost tier**
* (few-expensive-turns vs the large zero-cash fan-out). That is a DIFFERENT concept from this pod
* SEAT: the values overlap but the axes do not. This module owns the pod-org role axis; nothing here
* imports the cost tier and nothing there should import this.
*/
/**
* The closed pod-seat roster — the `role` axis of the TemplateRecord cell key (ADR-0041 §2 / A1).
* CLOSED at any instant; opened only by ceremony (a later `risk` reading-seat would be added HERE,
* with its own cells + matched sets). This array is the ONE source; {@link SeatId} is its element type
* and {@link isSeatId} its runtime guard, so the type and the runtime roster can never drift.
*/
export declare const SEAT_IDS: readonly ["pm", "strategist", "watcher"];
/** A pod seat — the closed `role` axis of the evidence cell key (ADR-0041 §2, Amendment A1). */
export type SeatId = (typeof SEAT_IDS)[number];
/** Runtime membership in the closed {@link SEAT_IDS} roster. Fail-closed callers use this to REFUSE an
* unknown role rather than coerce it (the ledger keys on the role — an unknown value must never be
* silently admitted into a cell, ADR-0041 §2 no-coercion). Pure. */
export declare function isSeatId(value: unknown): value is SeatId;
/**
* The **founder-View opt-in policy** — the config axis that decides whether a driver consults a seat's
* founder View at all (ADR-0041 §2 / A1, kestrel-wa0j.26). Founder Views are graded SEEDS, never
* blessed defaults, so they are OFF unless a config OPTS IN:
* - `phase-default` — the frame kind's default panes (byte-identical to before the role axis); the
* driver passes NO seat, so `resolveView` never reaches the founder branch. This is the default.
* - `founder` — the driver passes the acting tier's seat into `resolveView`, so a seat with a
* founder seed for the frame reads it (a DIFFERENT experimental subject → a distinct ConfigId).
*
* A `founder` run is a distinct grid column BECAUSE the agent perceives different screens; it folds
* into `deriveConfigId` automatically (like `clockHonest`/`cachePolicy`), never an a57.14 envelope
* field. Absent on a config ⇒ `phase-default` semantics ⇒ that config's ConfigId is byte-identical to
* before this axis existed (the drop-undefined canonicalizer).
*/
export type SeatViewsPolicy = "founder" | "phase-default";
/** Assert a value is a member of the closed seat roster, or THROW naming the roster (never a silent
* default — the same fail-closed discipline the parser and the pane catalog carry). Returns the
* value narrowed to {@link SeatId}. */
export declare function assertSeatId(value: unknown): SeatId;
//# sourceMappingURL=seat.d.ts.map