SPB Git

spb/earth-now Public License

earth-now.co — real-time planetary dashboard: live world metrics modeled, not streamed.

TypeScript 93% Shell 2.3% SQL 1.4% JavaScript 1.3% Dockerfile 1.2% CSS 0.8%
3.0 KB · 84 lines typescript
Raw Blame History
1/**2 * earth-now.co3 * Author:  Simon-Pierre Boucher4 * Contact: contact@spboucher.ai5 * File:    apps/web/test/consistency-shared.ts6 * Purpose: Shared fixture for the client/server consistency tests — models, instants and hand-derivable closed-form expected values7 */89import {10  SEASONAL_EPOCH_MS,11  YEAR_SECONDS,12  parseIsoUtc,13  type CounterModel,14} from "@earth-now/counter";1516export const ANCHOR_ISO = "2026-01-01T00:00:00.000Z";1718/** Simple linear model — closed-form value is hand-derivable. */19export const LINEAR_MODEL: CounterModel = {20  metricId: "consistency_linear",21  anchorValue: 8_231_613_070,22  anchorTime: ANCHOR_ISO,23  rateFn: { kind: "linear", perSecond: 2.3 },24  observedAt: "2025-07-01T00:00:00.000Z",25  sourceId: "un_wpp_2024",26  modelVersion: "linear-stock-v1",27  displayHints: { decimals: 0, sigFigs: 7, unit: "people" },28};2930/** Seasonal model with one annual harmonic — analytic integral, exact everywhere. */31export const SEASONAL_MODEL: CounterModel = {32  metricId: "consistency_seasonal",33  anchorValue: 0,34  anchorTime: ANCHOR_ISO,35  rateFn: {36    kind: "seasonal",37    base: 4.3,38    harmonics: [{ period: "year", order: 1, amplitude: 0.5, phase: 0.25 }],39  },40  observedAt: "2025-12-01T00:00:00.000Z",41  sourceId: "un_wpp_2024",42  modelVersion: "seasonal-ytd-v1",43  displayHints: { decimals: 0, unit: "births" },44};4546/** Five instants across the year, including the anchor itself. */47export const INSTANTS: readonly number[] = [48  Date.UTC(2026, 0, 1, 0, 0, 0),49  Date.UTC(2026, 1, 15, 12, 0, 0),50  Date.UTC(2026, 5, 30, 23, 59, 59),51  Date.UTC(2026, 7, 9, 7, 30, 0),52  Date.UTC(2026, 11, 31, 23, 59, 59, 999),53];5455/**56 * Closed-form linear value, replicating the exact arithmetic (and operation57 * order) of counterValue for kind=linear — provably v = a + r·Δt.58 */59export function linearClosedForm(tMs: number): number {60  const anchorMs = parseIsoUtc(LINEAR_MODEL.anchorTime);61  const rateFn = LINEAR_MODEL.rateFn;62  if (rateFn.kind !== "linear") throw new Error("fixture must be linear");63  return LINEAR_MODEL.anchorValue + (rateFn.perSecond * (tMs - anchorMs)) / 1000;64}6566/**67 * Closed-form seasonal value: v(t) = a + base·(τ₁−τ₀) + (A/ω)·(sin(ωτ₁+φ) − sin(ωτ₀+φ)),68 * with ω = 2π·order / YEAR_SECONDS and τ measured from the seasonal epoch —69 * the analytic integral of the declared rate, in the same operation order as the runtime.70 */71export function seasonalClosedForm(tMs: number): number {72  const rateFn = SEASONAL_MODEL.rateFn;73  if (rateFn.kind !== "seasonal") throw new Error("fixture must be seasonal");74  const anchorMs = parseIsoUtc(SEASONAL_MODEL.anchorTime);75  const tau0 = (anchorMs - SEASONAL_EPOCH_MS) / 1000;76  const tau1 = (tMs - SEASONAL_EPOCH_MS) / 1000;77  let v = SEASONAL_MODEL.anchorValue + rateFn.base * (tau1 - tau0);78  for (const h of rateFn.harmonics) {79    const omega = (2 * Math.PI * h.order) / YEAR_SECONDS;80    v += (h.amplitude / omega) * (Math.sin(omega * tau1 + h.phase) - Math.sin(omega * tau0 + h.phase));81  }82  return v;83}84