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.
83 lines (75 loc) • 4.21 kB
text/typescript
/**
* # react/frame-fields — reading the json Rendering HONESTLY (ADR-0052 §3/§4)
*
* Shared helpers for the `/react` components. They read the typed Frame `json` Rendering
* ({@link ../frame/render-json.ts}) the way a Rendering must: an UNKNOWN Field is UNKNOWN (never a
* zero, never interpolated), and a `MODEL` Field must PROVE its receipt (source + model version +
* confidence) or it is REFUSED — the honest-chart claim is that the chart invents nothing and hides
* no provenance, so a `MODEL` Field arriving without its receipt is a fail-closed error, not a badge
* we quietly drop.
*
* ## Isolation (ADR-0052 §3, a HARD requirement — the trust substrate ships this)
* Every engine import here is `import type` — ERASED at build. The `/react` runtime graph reaches
* NOTHING in the engine (no tokenizer, no sha256, no Bun/node built-in); the only runtime coupling is
* the optional `react` peer, resolved by the components, not this module. The two runtime CONSTANTS
* that must agree with the engine — the {@link UNKNOWN} marker and the arm-id registry
* ({@link ./arms.ts}) — are declared locally and pinned to the engine's TYPES at typecheck, so a
* drift reds `bun run typecheck` rather than shipping a browser bundle that disagrees with the wire.
*/
import type { FieldJson, JsonUnknown, Maybe } from "../frame/render-json.ts";
/**
* The explicit UNKNOWN marker, pinned to the engine's {@link JsonUnknown} at typecheck. The engine
* carries a null/absent Field across the `json` wire as this literal (never an omitted key, never a
* defaulted `0`); the components compare against THIS constant to decide "gap, not candle". The
* annotation is the drift guard: if the engine ever changes its marker string, `"UNKNOWN"` stops
* being assignable to {@link JsonUnknown} and this line reds — a type-only coupling, zero runtime edge.
*/
export const UNKNOWN: JsonUnknown = "UNKNOWN";
/** Is this {@link Maybe} value the explicit UNKNOWN marker (⇒ render a GAP, never a value)? */
export function isUnknown<T>(v: Maybe<T>): v is JsonUnknown {
return v === UNKNOWN;
}
/** The finite value of a {@link Maybe}, or `null` when it is UNKNOWN — a `null` is the caller's cue to
* leave a GAP (never substitute `0`, never interpolate a neighbour). */
export function valueOr<T>(v: Maybe<T>, fallback: null = null): T | null {
return isUnknown(v) ? fallback : v;
}
/** Raised when a `MODEL` Field arrives WITHOUT its receipt — the honest chart refuses to draw a
* model-derived value it cannot attribute (fail-closed, ADR-0052 §3). */
export class HonestChartError extends Error {
constructor(message: string) {
super(message);
this.name = "HonestChartError";
}
}
/** A `MODEL` Field's receipt, extracted once it has been proven honest. */
export interface FieldReceipt {
readonly source: string;
readonly modelVer: string;
readonly confidence: number;
}
/**
* Prove a `MODEL` {@link FieldJson} carries its full receipt (source + modelVer + confidence), or
* THROW — mirroring the engine's seam-side honesty gate ({@link ../frame/types.ts assertClaimHonest})
* on the reading side, because a `json` Rendering can be hand-built by a consumer and arrive
* degraded. Returns the receipt so the badge renders it. Fail-closed: a `MODEL` value with no receipt
* is never silently rendered as if honest.
*/
export function assertModelReceipt(field: FieldJson, label: string): FieldReceipt {
if (field.attribution !== "MODEL") {
throw new HonestChartError(
`${label} is attributed ${field.attribution}, not MODEL — only a MODEL Field carries a receipt`,
);
}
const { source, modelVer, confidence } = field;
if (typeof source !== "string" || source === "") {
throw new HonestChartError(`MODEL ${label} is missing its \`source\` receipt`);
}
if (typeof modelVer !== "string" || modelVer === "") {
throw new HonestChartError(`MODEL ${label} is missing its \`modelVer\` receipt`);
}
if (typeof confidence !== "number" || !Number.isFinite(confidence)) {
throw new HonestChartError(`MODEL ${label} is missing a finite \`confidence\` receipt`);
}
return { source, modelVer, confidence };
}