/** How a series answer buckets time. Engine vocabulary — a format picks. */ export declare const HISTORY_EVERY: readonly ["day", "week", "month"]; export type HistoryEvery = typeof HISTORY_EVERY[number]; /** What shape an answer has. `series` is a time axis; `distribution` is a * histogram of durations, which is a DIFFERENT x axis and may never share a * chart with the other (one chart, one x axis). */ export declare const HISTORY_KINDS: readonly ["series", "distribution"]; export type HistoryKind = typeof HISTORY_KINDS[number]; /** The five op spellings `op_event` uses. Unchanged by this program (P26). */ export type HistoryOp = 'append' | 'update' | 'archive' | 'restore' | 'migrate'; /** Caps, refused BY NAME rather than truncated: a truncated burndown is a * wrong number that looks right. The cloud's refusal strings are the same * words (history_window_too_wide · history_too_many_buckets · * history_too_many_events) so one declaration cannot pass one gate and fail * the other. */ export declare const HISTORY_MAX_WINDOW_DAYS = 366; export declare const HISTORY_MAX_BUCKETS = 400; export declare const HISTORY_MAX_EVENTS = 50000; /** The default day edges of a cycle-time histogram when a series declares * none. Engine chrome, like the timeline's tick labels. */ export declare const HISTORY_DEFAULT_BUCKETS: readonly [1, 3, 7, 14, 30]; /** * ONE compiled read. This is what the payload carries, what the query string * spells, and what the per-pass memo is keyed by — so it holds the AUTHORED * window (`-28d`), never a resolved instant. Resolution happens inside * evalHistory against the reader's own `now`, which is what lets a live * refresh add today's bucket instead of re-answering a window frozen at bake * time. */ export interface HistoryAsk { /** the operational block whose log answers */ block: string; /** the column key (lowercased, the compiled spelling) whose DECLARED values * are the states this ask walks */ of: string; /** every declared value of `of`, in DECLARED order — the format's own order, * which is the order a cumulative flow stacks in */ values: string[]; /** the three groups, each a subset of `values`. Disjoint, checked at load. */ open: string[]; done: string[]; cancelled: string[]; /** the window's left edge: `-d|w|m` or an ISO date/instant */ since: string; /** the window's right edge, or '' for "the reader's now" */ until: string; /** how a series answer buckets time (ignored by a distribution) */ every: HistoryEvery; kind: HistoryKind; /** distribution only: the day edges of the histogram */ buckets: number[]; } /** One record as the ledger hands it over: its CURRENT cells, which is where * the backward walk starts. `archived` records are included and must be — * a record that ended still spent its life in the window. */ export interface HistoryRecord { uuid: string; cells: Record; archived?: boolean; } /** One event of the log. `detail` is the op's own shape, unparsed: * update → {col: {from, to}} · append/migrate → the post cells · * archive → {doc} · restore → {}. */ export interface HistoryEvent { seq: number; at: string; op: HistoryOp; uuid: string; detail?: unknown; } /** What a host hands evalHistory: the block's records (live AND archived) and * its events. Events need only cover the window; records must be complete, * because the walk starts from NOW and reads backwards. */ export interface HistoryLedger { records: readonly HistoryRecord[]; events: readonly HistoryEvent[]; /** the operational stamp this ledger was read at, echoed into the answer */ readAt?: string; } /** * One read's answer. Counts, not rows: the client never re-aggregates and a * 50 000-event window still crosses the wire as a few hundred numbers. */ export interface HistoryAggregate { kind: HistoryKind; /** the window this answer actually used, resolved */ window: { since: string; until: string; }; /** series: one label per bucket, in time order. distribution: one label per * bin. Either way these ARE the chart's x categories. */ categories: string[]; /** series only: per bucket, how many LIVE records held each value at the * end of it. Prototype-free maps; read them with countOf. */ counts: Record[]; /** series only: live (present, unarchived) records per bucket */ live: number[]; /** distribution only: how many measured records fell in each bin */ bins: number[]; /** distribution only: the median duration in days, or null with no data */ median: number | null; /** distribution only: how many records were actually measured */ measured: number; /** every record this answer could NOT count, by reason — never silent */ omitted: Record; /** the instant the answer was computed */ at: string; /** the ledger's operational stamp, when it carried one */ readAt?: string; } /** * The seam a HOST fills (P31): given a compiled ask, the ledger's answer, or * `null` when the host declines — out of budget (P22), no store, no reach. A * null is never an error: the widget ships its `history:` with no data and * the live kick fills it in the browser. */ export type HistoryResolver = (ask: HistoryAsk) => HistoryAggregate | null; /** A cap refusal. Carries the CODE the door answers with, so the cloud maps * it to a refusal name rather than inventing a second vocabulary. */ export declare class HistoryError extends Error { code: string; constructor(code: string, message: string); } /** own-key read of a payload map (the store.ts `own` discipline, in core): * these maps are keyed by the VAULT's own cell values, and after a JSON * round-trip a value spelled "constructor" would otherwise answer with * Object's constructor. */ export declare function countOf(m: Record | undefined, value: string): number; /** ISO-8601 only — the one date grammar the engine speaks everywhere (the * timeline's ruling, restated). `YYYY-MM-DD` is midnight UTC. */ export declare function parseInstant(raw: string): number | null; /** `-28d` · `-12w` · `-6m` — a window measured backwards from the reader's * now, which is the spelling a dashboard wants (a report that says "the last * four weeks" must mean it every week). Returns null when `raw` is not * relative, so the caller falls through to the ISO reading. */ export declare function parseRelative(raw: string): { n: number; unit: 'd' | 'w' | 'm'; } | null; /** How many DAYS a relative window spans, measured with the SAME calendar * arithmetic the runtime resolver uses, so the load-time cap refuses exactly * what the door would refuse. `-12m` is 365 or 366 days — the natural annual * window — and it must not be refused by an estimate no window ever has. */ export declare function relativeWindowDays(raw: string, nowMs?: number): number | null; /** Resolve the authored window against a reader's `now`. Exported because the * door answers with the window it used and the load-time referee wants the * same arithmetic. */ export declare function resolveWindow(ask: HistoryAsk, nowMs: number): { since: number; until: number; }; /** * THE READ. Pure: same ask, same ledger, same `now` — same answer, on a * Worker or in a test. Throws HistoryError only for the three caps, which are * the honest alternative to a truncated answer. */ export declare function evalHistory(ask: HistoryAsk, ledger: HistoryLedger, nowMs?: number): HistoryAggregate; /** One compiled series of a history chart. `scope` is burnup's second line; * `buckets` was folded into the ask at compile (a distribution chart holds * exactly one series, so its edges ARE the read's). */ export interface HistorySeriesSpec { mark: HistoryMarkName; label?: string; scope?: boolean; } /** The four marks this landing adds. Time-series marks share one x axis; * `cycle-time` draws a DIFFERENT one, which is why mixing them is refused. */ export declare const HISTORY_MARKS: readonly ["burndown", "burnup", "flow", "cycle-time"]; export type HistoryMarkName = typeof HISTORY_MARKS[number]; export declare const HISTORY_DISTRIBUTION_MARKS: readonly HistoryMarkName[]; export declare function isHistoryMark(mark: string): mark is HistoryMarkName; /** Which shape a set of marks demands. Callers refuse a mixed answer. */ export declare function historyKindOf(marks: readonly string[]): HistoryKind | 'mixed'; /** One drawn series of the chart payload. `stack` and `colorKey` are the two * words a cumulative flow needs; NO HEX EVER ENTERS A PAYLOAD — `colorKey` * is the format's own value and the client resolves it through the same * declared colours every chip, lane and bar already use. */ export interface HistoryChartSeries { mark: HistoryMarkName; label: string; values: number[]; stack?: string; colorKey?: string; } export interface HistoryChartData { x: { label: string; categories: string[]; }; series: HistoryChartSeries[]; reference?: number; /** the honest footnote: the median of a distribution, and every record the * answer could not count, with its reason. Rendered under the chart. */ caption?: string; omitted?: Record; at?: string; readAt?: string; } /** * THE DRAW. Maps declared series onto one aggregate — pure arithmetic over * counts the read already produced, so the bake and a live refresh draw the * same picture from the same numbers. */ export declare function historyChart(ask: HistoryAsk, series: readonly HistorySeriesSpec[], agg: HistoryAggregate, xLabel?: string, reference?: number): HistoryChartData; /** The ask, as a query string. ENGINE-OWNED so the door and the client cannot * drift into two spellings of one question — the door parses with * historyAskFromQuery below, which is this function's exact inverse (pinned * by a round-trip test). */ export declare function historyQuery(ask: HistoryAsk): string; /** The inverse. Returns null for anything the serializer could not have * produced — a door refuses by name rather than guessing at a half-ask. */ export declare function historyAskFromQuery(params: URLSearchParams): HistoryAsk | null;