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.4 KB · 98 lines typescript
Raw Blame History
1/**2 * earth-now.co3 * Author:  Simon-Pierre Boucher4 * Contact: contact@spboucher.ai5 * File:    apps/web/test/tiers.test.ts6 * Purpose: Display-tier classification — fast tickers lead, slow stocks land in the reference strip, RT and countries route to their sections7 */89import { describe, expect, it } from "vitest";10import type { CounterModel } from "@earth-now/counter";11import type { MetricSummary } from "../lib/api";12import { secondsPerVisibleTick, tierFor, LIVE_TICK_THRESHOLD_S } from "../lib/tiers";1314const T = Date.parse("2026-08-09T12:00:00Z");1516function model(perSecond: number): CounterModel {17  return {18    metricId: "m",19    anchorValue: 0,20    anchorTime: "2026-01-01T00:00:00.000Z",21    rateFn: { kind: "linear", perSecond },22    observedAt: "2026-01-01T00:00:00.000Z",23    sourceId: "s",24    modelVersion: "test-v1",25    displayHints: { decimals: 0, unit: "u" },26  };27}2829function metric(over: Partial<MetricSummary>): MetricSummary {30  return {31    id: "some_metric",32    name: { fr: "x", en: "x" },33    domain: "population",34    priority: "mvp",35    kind: "cumulative",36    level: 1,37    model: "seasonal-ytd-v1",38    unit: "people",39    sources: [],40    display: { decimals: 0, unit: { fr: "u", en: "u" } },41    windows: ["ytd"],42    stale: false,43    ...over,44  };45}4647describe("secondsPerVisibleTick", () => {48  it("computes the visible tick interval from rate, decimals and display scale", () => {49    // 4 units/s at 0 decimals → last digit changes every 0.25 s.50    expect(secondsPerVisibleTick(model(4), { decimals: 0 }, T)).toBeCloseTo(0.25, 9);51    // 1027 MWh/s displayed in TWh (scale 1e-6) with 2 decimals → 0.01 TWh per tick.52    expect(secondsPerVisibleTick(model(1027), { decimals: 2, scale: 1e-6 }, T)).toBeCloseTo(53      0.01 / (1027e-6),54      6,55    );56    expect(secondsPerVisibleTick(model(0), { decimals: 0 }, T)).toBe(Infinity);57  });58});5960describe("tierFor", () => {61  it("fast tickers are live, slow stocks are reference", () => {62    expect(tierFor(metric({}), model(4.2), T)).toBe("live");63    // CO₂ ppm style: 2.6 ppm/yr, 2 decimals → hours per tick → reference.64    expect(65      tierFor(66        metric({ id: "co2_ppm", kind: "stock", display: { decimals: 2, unit: { fr: "ppm", en: "ppm" } } }),67        model(2.6 / 31_556_952),68        T,69      ),70    ).toBe("reference");71  });7273  it("routes hero, countries and RT metrics to their sections regardless of rate", () => {74    expect(tierFor(metric({ id: "world_population" }), model(2.2), T)).toBe("hero");75    expect(tierFor(metric({ id: "country_population_india" }), model(0.37), T)).toBe("country");76    expect(tierFor(metric({ id: "earthquakes_24h", level: "rt" }), model(0), T)).toBe("realtime");77  });7879  it("rate-of and depletion displays read as static → reference", () => {80    const rateOf = metric({81      id: "co2_rate",82      kind: "derived",83      derived: { op: "rate-of", inputs: [{ id: "co2_emissions_ytd", weight: 1 }] },84    });85    expect(tierFor(rateOf, model(1200), T)).toBe("reference");86  });8788  it("no model → reference (stale metrics never fake liveness)", () => {89    expect(tierFor(metric({}), undefined, T)).toBe("reference");90  });9192  it("threshold boundary respects LIVE_TICK_THRESHOLD_S", () => {93    const boundaryRate = 1 / LIVE_TICK_THRESHOLD_S;94    expect(tierFor(metric({}), model(boundaryRate * 1.01), T)).toBe("live");95    expect(tierFor(metric({}), model(boundaryRate * 0.99), T)).toBe("reference");96  });97});98