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.

109 lines (108 loc) 6.39 kB
/** * kestrel.markets/protocol — the OVERSIGHT contract (protocol v0.3). * * The cross-repo seam between the CLI (OSS `kestrel` — `ascii`/Ink Rendering) and * the Web dashboard (platform `kestrel.markets` — `html` Rendering). ADR-0035: the * human never places a ticket — the human mode is PM/Pod OVERSIGHT (positions, * plans, P&L, risk envelope) plus chat. "The agent's ASCII screen and the human's * HTML chart are two Renderings of one Frame" (CONTEXT.md, *Rendering*) — so if the * Web dashboard can show a number the CLI cannot, that number was fetched OUTSIDE * this contract, and the protocol is broken. This module owns the shared model; * both Renderings consume it, neither invents a value. * * Normative source: docs/design/oversight-protocol-contract.md §3–§5 (owner-approved * 2026-07-14). The model has exactly EIGHT parts and nothing else belongs in it. * * HARD CONSTRAINTS (identical to src/protocol/index.ts — see its header): * - ZERO RUNTIME dependencies. The ONLY imports are intra-protocol type-imports * (`./session.ts`, `./index.ts` — both dependency-free); this module pulls in NO * engine / session / blotter / fill / lang / grade / frame / render / ledger / * cli code and must typecheck with `chdb` uninstalled. The import-graph boundary * is an automated CI invariant (tests/protocol.boundary.test.ts). Hence the * acting Kernel is a STRUCTURAL MIRROR of `src/frame/types.ts` `Kernel` — never * an import of it (§3.2). CONFORMANCE, HONESTLY: today this leaf is a * HAND-MAINTAINED parallel of `src/frame/types.ts` with NO compiler link — its * field-for-field correspondence is verified by audit, not yet by a witness. The * total projector `src/oversight/project.ts` (bead kestrel-telx.2, NOT YET * LANDED) is the PLANNED conformance point: it will carry a `Record<keyof Kernel, * true>` key-witness on the `src/frame` side so that a section added to `Kernel` * breaks the build until this mirror handles it. Until it lands, adding a field * to `src/frame/types.ts` `Kernel*` and forgetting it here does NOT auto-red — so * any `Kernel*` edit must be reconciled against this leaf by hand. * - SHAPES ONLY. No signing keys, no Stripe/commerce logic. Every signed, * replayable artifact carries an opaque `*Ref` HANDLE, never a key or a signing * routine (`OversightAct` 'fund' carries `authorizationRef`, never a credential). * - GENERIC INSTRUMENTS ONLY. No founding-app tickers or strategy names in types, * comments, or examples. Illustrative fixtures use SPX/SPY/QQQ (ARCHITECTURE §7); * product symbols ride INSIDE opaque `symbol` fields at runtime. * * Version: `major.minor`. This leaf first landed at PROTOCOL_VERSION 0.3 (bumped 0.2 → 0.3, purely * additive). It now bumps 0.3 → 0.4 for the `ActReceipt` `state` field (kestrel-ysqj): `submitAct`'s * receipt gains an explicit queued-vs-bound stamp so 'admitted' and 'in force' are distinguishable to a * remote caller — a shape change to an existing type, hence a minor bump (index.ts owns the constant; * this note records why it moved). The schema tag `kestrel.session/<PROTOCOL_VERSION>` and the * content-addressed view/rendering identities track it; the graded-bus conformance root does NOT (it is * decoupled, ENGINE_VERSION-gated), so only the catalog-records bake re-pins, never a conformance root. * * NAMING: index.ts re-exports leaves with `export *` and already exports * `Position`/`Instrument`/`Order`/`Fill`/`Side`, so every oversight type here is * PREFIXED (`KernelPosition`, `KernelRestingOrder`, `KernelFill`, …). A collision is * a compile error, not a style question. * * CLOSED-VOCABULARY IDIOM (mandatory): every union ships its runtime tuple + the * both-ways exhaustiveness guard (`SESSION_DIAGNOSTICS` / `_SessionDiagnosticsExhaustive` * in session.ts), so a member added to (or removed from) a union without editing its * tuple BREAKS THE BUILD. That is what makes "an event outside the enum is a protocol * violation" enforceable rather than aspirational. */ export const CALLER_KINDS = ["agent", "human"]; export const CALLER_DETECTIONS = ["flag", "env", "ci", "tty"]; export const MODES = ["sim", "paper", "live"]; export const ATTRIBUTIONS = ["OBS", "CALC", "MODEL"]; export const PLAN_LIFECYCLES = [ "authored", "armed", "fired", "managing", "done", ]; export const PLAN_OUTCOMES = ["filled", "expired", "invalidated"]; export const WAKE_SEVERITIES = ["routine", "elevated", "urgent"]; export const ENGINE_ACTION_KINDS = [ "fired", "cancelled", "rejected", "clamped", ]; export const CLAIM_TYPES = ["predictor", "regime"]; export const AGENT_TIERS = ["strategist", "watcher"]; export const ESCALATION_REASONS = [ "mandate-edge", "brief-flag", "regime", "uncertainty", ]; export const AUTHOR_TIERS = [ "runtime", "watcher", "strategist", "human", ]; export const TURN_DISPOSITIONS = [ "armed", "revised", "pass", "stood-down", "failure", ]; export const OVERSIGHT_ACT_KINDS = [ "allocate", "arm", "de-arm", "coverage", "fund", "de-fund", "pause", "veto", ]; /** The acts that only NARROW authority. These are ALWAYS admitted — de-risking is never gated, * never queued behind an approval, never refused for want of capital. */ export const NARROWING_ACTS = [ "de-arm", "de-fund", "pause", "veto", ]; export const ACT_STATES = ["queued", "bound"]; export const MESSAGE_AUTHORS = ["owner", "pm", "trader"]; export const INPUT_RESOLUTION_KINDS = [ "grammar", "shortcut", "act", "chat", "parse-error", ]; export const OVERSIGHT_EVENT_TYPES = [ "oversight.snapshot", "oversight.delivery", "oversight.turn", "oversight.act", "oversight.escalation", "oversight.message", "oversight.journal", "oversight.diagnostic", "oversight.finalized", "oversight.failed", ]; /** The two TERMINAL event types that end the stream (mirror of the `operation.completed` / * `operation.failed` pair). `oversight.finalized` ends it cleanly; `oversight.failed` throws. */ export const OVERSIGHT_TERMINAL_TYPES = [ "oversight.finalized", "oversight.failed", ]; /** True iff `t` is a contract event type. Anything else is a protocol violation the client MUST * fail closed on (mirror of `isSseEventType`). */ export function isOversightEventType(t) { return OVERSIGHT_EVENT_TYPES.includes(t); }