/** * NumericsQueryLayer — deterministic closed-whitelist numeric primitives (Phase 6, Sprint 4). * * ADR-3: The LLM NEVER performs arithmetic. All numeric computations are pure TypeScript * over a CLOSED whitelist: mean | min | max | latest | delta | slope | percentile | zscore. * Adding a computation requires extending NumericPrimitive (a code review event), not a * model decision. `sampleCount: 0` signals upstream abstention. * * NO async. NO fs. NO network. NO LLM import. NO dynamic execution. NO subprocess. * Identical input => identical output. * * Primitive formulas documented below (also satisfies contract assumptions line 75): * * mean — sum(values) / n * min — Math.min(...values) * max — Math.max(...values) * latest — value at the maximum t_start (last element of ASC-ordered array) * delta — latest − earliest = values[n-1] − values[0] * slope — least-squares slope over (t, value) where t = Date.parse(r.tStart) epoch-ms. * formula: (n·Σ(t·v) − Σt·Σv) / (n·Σ(t²) − (Σt)²) * degenerate: denominator === 0 (all same timestamp) → value: null, sampleCount: n * percentile — linear interpolation between closest ranks (sorted ascending): * rank = (p/100) · (n−1); lo = floor(rank); hi = ceil(rank); * result = v[lo] + (rank − lo) · (v[hi] − v[lo]) * (for p50, [10,20,30,40] → rank=1.5 → 20 + 0.5·10 = 25) * zscore — (latest − mean) / populationStddev * populationStddev = sqrt(Σ(v − mean)² / n) * sampleCount < 2 → abstain (stddev undefined for n=1, zero for n=0) * ([10,20,30,40]: mean=25, popStd=√125≈11.1803, z=(40-25)/11.1803≈1.3416) */ import type { HealthDataStore } from "./health-store.js"; import type { NumericPrimitive, NumericResult, MetricWindow, LabTrend } from "./types.js"; /** * Provides deterministic, LLM-free numeric aggregations over HealthDataStore. * * All methods are SYNCHRONOUS. No async, no fs, no network, no LLM import. * The LLM never performs arithmetic — this layer does. */ export declare class NumericsQueryLayer { private readonly store; constructor(store: HealthDataStore); /** * Compute a numeric primitive over the observations in the given time window. * * Abstain conditions (return { value: null, sampleCount: 0 } without throwing): * - Empty window (no rows in the time range) — sc-4-6 * - Heterogeneous units across rows — sc-4-7 (cross-unit refusal) * * Partial abstain (value: null, sampleCount: n): * - zscore with sampleCount < 2 (stddev undefined) * - slope with degenerate denominator (all same timestamp) * * @param window — metric + ISO-8601 time range * @param primitive — one of the 8 whitelisted NumericPrimitive values * @param percentile — percentile p ∈ [0,100], used only for "percentile" primitive (default 50) */ getMetric(window: MetricWindow, primitive: NumericPrimitive, percentile?: number): NumericResult; /** * Build a LabTrend summary for a biomarker series. * * Abstains (latestValue: null, slope: null) when sampleCount === 0 (sc-4-6). * slope is null when sampleCount < 2 (not enough data for least-squares). */ getLabTrend(biomarker: string): LabTrend; } //# sourceMappingURL=numerics.d.ts.map