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.

158 lines 9.13 kB
/** * # grade/measurement — alpha measurements carry a KIND, and kinds never blend (kestrel-a57.6) * * A measurement of alpha is not one number; it is a number **plus the evidence semantics that produced it**. * The three kinds carry DIFFERENT evidence, so silently blending or ranking one against another is a category * error — the same class of error ADR-0006 forbids across measurement *versions* ("EVs across measurement * versions refuse naive comparison"). This module is the KIND-axis sibling of that rule: **alphas across KINDS * refuse naive comparison**, and the enforcement is the TypeScript compiler. * * 1. RULE ALPHA — a MECHANICAL TEMPLATE run over EVERY eligible opportunity on a tape (systematic, no * discretion). Its evidence is the template's realized measure over the whole universe. * 2. SELECTION ALPHA — POINT-IN-TIME CURATION (the author PICKED which opportunities to act on), measured * VS A FROZEN COUNTERFACTUAL on the SAME FUTURE TAPE (what those same picks, frozen, * would have realized). Its evidence is SELECTION skill: realized minus the frozen leg. * 3. DIAGNOSTIC — exploratory / inspection only. Carries an explicit `non_promotable: true` marker and * has NO ordering surface at all (no `compare`, no `rank`, no `promote`). * * ## The barrier (compile-time) * Each kind is a distinctly **branded** record (a private `unique symbol` phantom brand ⇒ nominal, mutually * non-assignable, even if fields ever coincided). `compare` / `rank` / `promote` are pinned with `NoInfer<M>`: * the measurement type `M` is inferred ONLY from the first parameter, so a second argument of a different kind * has nothing to unify with and fails to type-check. `PromotableAlpha` excludes diagnostics, so the diagnostic * kind has no accepting overload anywhere — its only surface is construction and inspection. * * ## Diagnostics never promote (dual gate — fail-closed) * (compile) `promote<M extends PromotableAlpha>` will not bind a `DiagnosticMeasurement`; (runtime) if a caller * bypasses the types (an `any` / erased boundary), {@link promote} returns a typed refusal — `{ ok: false, * reason, kind }` — never throws, never silently succeeds. This mirrors the module's fail-closed convention * ({@link bankableEv} floors by RETURN; the receipt projector degrades with a logged reason) rather than * inventing a new error style. * * Ranking is on ONE named scalar per kind — never a blended omnibus (honors the m9i no-omnibus rule). Pure and * deterministic: no wall clock, no RNG; off the runtime/record path (no bus/Blotter/grammar/golden bytes move). */ import type { MeasurementVersions } from "./receipt.ts"; declare const BRAND: unique symbol; /** A phantom, compile-time-only tag that makes two otherwise-structural records mutually non-assignable. */ type Brand<B extends string> = { readonly [BRAND]: B; }; /** The identity of a mechanical template (rule alpha) — the id plus a content hash of its definition. */ export interface TemplateRef { readonly template_id: string; readonly template_hash: string; } /** The future tape a measurement was realized on — the id plus a content hash of the tape's bytes. */ export interface TapeRef { readonly tape_id: string; readonly tape_hash: string; } /** * A realized alpha measure: ONE declared scalar (`realized_r`) plus the banked expected-$ and the sample size * behind it. Ranking within a kind is on the ONE named scalar, never a blended composite of these fields. */ export interface AlphaScore { readonly realized_r: number; readonly expected_dollars: number; readonly n: number; } /** The frozen leg of a selection measurement — what the SAME picks, frozen, realized on the SAME future tape. */ export interface FrozenCounterfactual { readonly realized: AlphaScore; readonly frozen_hash: string; } /** The honest fields of a rule-alpha measurement (the {@link ruleAlpha} builder stamps the kind + brand). */ export interface RuleAlphaInput { readonly template: TemplateRef; readonly tape: TapeRef; /** Every eligible opportunity the mechanical rule ran over — the systematic universe, no selection. */ readonly universe: number; readonly realized: AlphaScore; readonly measurement_versions: MeasurementVersions; } /** A rule-alpha measurement: mechanically applied over EVERY opportunity. Nominal (branded). */ export type RuleAlphaMeasurement = RuleAlphaInput & { readonly kind: "rule_alpha"; } & Brand<"RuleAlpha">; /** Build a {@link RuleAlphaMeasurement}. Pure: stamps the discriminant kind; no clock, no RNG. */ export declare function ruleAlpha(input: RuleAlphaInput): RuleAlphaMeasurement; /** The honest fields of a selection-alpha measurement (the {@link selectionAlpha} builder stamps kind + brand). */ export interface SelectionAlphaInput { /** The curation: how many opportunities existed vs how many the author PICKED to act on. */ readonly picks: { readonly universe: number; readonly picked: number; }; readonly tape: TapeRef; readonly realized: AlphaScore; /** Stored INLINE (not referenced): the same picks, frozen, realized on the SAME future tape. */ readonly frozen_counterfactual: FrozenCounterfactual; readonly measurement_versions: MeasurementVersions; } /** A selection-alpha measurement: discretionary curation vs its frozen leg. Nominal (branded). */ export type SelectionAlphaMeasurement = SelectionAlphaInput & { readonly kind: "selection_alpha"; } & Brand<"SelectionAlpha">; /** Build a {@link SelectionAlphaMeasurement}. Pure: stamps the discriminant kind; no clock, no RNG. */ export declare function selectionAlpha(input: SelectionAlphaInput): SelectionAlphaMeasurement; /** The honest fields of a diagnostic measurement (the {@link diagnostic} builder stamps the non-promotable marker). */ export interface DiagnosticInput { readonly probe: string; readonly observed: AlphaScore; readonly note: string; } /** * A diagnostic measurement: exploratory / inspection only. Carries an explicit literal-`true` `non_promotable` * marker and is NOT part of {@link PromotableAlpha}, so it has no `compare` / `rank` / `promote` surface. Nominal. */ export type DiagnosticMeasurement = DiagnosticInput & { readonly kind: "diagnostic"; readonly non_promotable: true; } & Brand<"Diagnostic">; /** Build a {@link DiagnosticMeasurement}. Pure: stamps the kind + the explicit non-promotable marker. */ export declare function diagnostic(input: DiagnosticInput): DiagnosticMeasurement; /** * The kinds that can be compared / ranked / promoted. Diagnostics are DELIBERATELY absent: they are the * category that must never be laundered into a promotable claim, so they have no ordering surface at all. */ export type PromotableAlpha = RuleAlphaMeasurement | SelectionAlphaMeasurement; /** The result of a same-kind comparison: the sign of the ordering PLUS the name of the scalar it ranked by. */ export interface Comparison { readonly order: -1 | 0 | 1; readonly measure: string; } /** * Compare two measurements OF THE SAME KIND on that kind's one named scalar. `M` is inferred solely from `a`; * `NoInfer<M>` pins `b` to the same kind, so a cross-kind second argument fails to compile. Diagnostics are not * in {@link PromotableAlpha}, so they have no `compare` overload at all. Pure, total, deterministic. */ export declare function compare<M extends PromotableAlpha>(a: M, b: NoInfer<M>): Comparison; /** * Rank measurements OF THE SAME KIND, descending by that kind's one named scalar. `M` is inferred solely from * the first element; every remaining element is pinned to the same kind via `NoInfer<M>`, so a mixed-kind list * (or a list containing a diagnostic) fails to compile. Pure: returns a sorted COPY; the input is never mutated. */ export declare function rank<M extends PromotableAlpha>(xs: readonly [M, ...NoInfer<M>[]]): M[]; /** * The typed outcome of a promotion attempt — a discriminated union, fail-closed by RETURN (never a thrown * error, never a silent default). `ok:false` carries the machine-readable `reason` and the offending `kind`. */ export type PromotionOutcome = { readonly ok: true; readonly candidate: PromotableAlpha; } | { readonly ok: false; readonly reason: string; readonly kind: string; }; /** * Promote a promotable alpha to a candidate. At compile time only {@link PromotableAlpha} binds `M`, so a * diagnostic has no accepting path. At RUNTIME this is defense-in-depth for a caller that bypassed the types * (an `any` / erased boundary): it inspects the actual object and FAILS CLOSED — a diagnostic, a non-promotable * marker, or any unrecognized kind returns a typed refusal with a logged reason. It never throws, never silently * succeeds. Pure and deterministic. */ export declare function promote<M extends PromotableAlpha>(candidate: M): PromotionOutcome; export {}; //# sourceMappingURL=measurement.d.ts.map