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%
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