eleven / messenger Public

Clone
git clone https://amadan.net/eleven/messenger

Plain git — no account needed to clone.

Download

Download this file

1// 🤖 Contract test for the public status dashboards: the fields each page in
2// web/status/ declares it reads (its FIELDS manifest) must exist in the JSON
3// deploy/status-publish.sh generates. The fixtures in test/status-fixtures/
4// are the script's own --dry-run output (fleet.json, books.json,
5// books-no-expenses.json, books-hetzner-constant.json; regenerate with
6// `./deploy/status-publish.sh --dry-run <dir>` after changing the generator —
7// the no-expenses variant via STATUS_DRY_EXPENSES=omit, the hetzner-constant
8// one via STATUS_DRY_EXPENSES=hetzner-constant) plus the hand-pinned degraded
9// shape (books-unavailable.json, matching books_unavailable()). If this
10// fails, page and generator have drifted — fix whichever side changed, then
11// the fixtures.
12//
13// The security ledger rides the same pattern with its own generator:
14// test/status-fixtures/security.json is deploy/security-scan.sh's --dry-run
15// output (the ATTENTION shape, folded from a fixture govulncheck stream full
16// of fake CVE/GHSA/GO ids — regenerate with
17// `./deploy/security-scan.sh --dry-run test/status-fixtures`), and
18// web/status/security.json is the committed real scan. Both must satisfy the
19// redaction contract below: status + counts + sha + timestamp, NEVER an
20// advisory id or package path (an unpatched-vuln inventory is an attacker
21// roadmap — see the scan script's disclosure header).
22// node test/status-contract.test.mjs
23import assert from "node:assert/strict";
24import { readFileSync } from "node:fs";
25
26let failures = 0;
27async function test(name, fn) {
28 try {
29 await fn();
30 console.log("PASS " + name);
31 } catch (e) {
32 console.log("FAIL " + name + " — " + (e && e.message));
33 failures++;
34 }
35}
36
37const read = (p) => readFileSync(new URL("../" + p, import.meta.url), "utf8");
38const fleet = JSON.parse(read("test/status-fixtures/fleet.json"));
39// One dry-run fixture per capacity band (STATUS_DRY_CAPACITY=… regenerates
40// them) — the abstract derivation is pinned at every level.
41const fleetGF = JSON.parse(read("test/status-fixtures/fleet-getting-full.json"));
42const fleetAC = JSON.parse(read("test/status-fixtures/fleet-at-capacity.json"));
43// STATUS_DRY_MESH_PEER=1 regenerates this one — a second, live mesh peer's
44// self-published stats merged into hosts.boxes alongside the local box.
45const fleetMH = JSON.parse(read("test/status-fixtures/fleet-multi-host.json"));
46const books = JSON.parse(read("test/status-fixtures/books.json"));
47const booksDown = JSON.parse(read("test/status-fixtures/books-unavailable.json"));
48const booksNoExp = JSON.parse(read("test/status-fixtures/books-no-expenses.json"));
49const booksHzConst = JSON.parse(read("test/status-fixtures/books-hetzner-constant.json"));
50
51// Pull the FIELDS manifest out of a page's inline script.
52function fields(html) {
53 const m = html.match(/const FIELDS = \[([\s\S]*?)\];/);
54 assert.ok(m, "page declares a FIELDS manifest");
55 return [...m[1].matchAll(/"([^"]+)"/g)].map((x) => x[1]);
56}
57
58// Resolve a dotted path against an object; "seg[]" descends into a non-empty
59// array — ANY element carrying the rest of the path satisfies it (the
60// expenses providers are heterogeneous by design: month-to-date providers
61// carry month_to_date_cents, flat-rate ones monthly_cents).
62function resolve(obj, path) {
63 const segs = path.split(".");
64 function walk(cur, i) {
65 if (i === segs.length) return cur;
66 if (cur === null || typeof cur !== "object") return undefined;
67 const seg = segs[i];
68 if (seg.endsWith("[]")) {
69 const arr = cur[seg.slice(0, -2)];
70 if (!Array.isArray(arr) || arr.length === 0) return undefined;
71 for (const el of arr) {
72 const v = walk(el, i + 1);
73 if (v !== undefined) return v;
74 }
75 return undefined;
76 }
77 return walk(cur[seg], i + 1);
78 }
79 return walk(obj, 0);
80}
81
82const indexHtml = read("web/status/index.html");
83const booksHtml = read("web/status/books.html");
84// The carbon page reads TWO shapes. `built` is COMMITTED data (accrued by
85// tools/carbon-tally.mjs) — the real web/status/carbon.json is its own fixture,
86// and carries only { updated_at, methodology, built:{…} } (run absent → page
87// shows "pending"). The live `run` block is injected by deploy/status-publish.sh
88// at upload; its shape is pinned by the dry-run fixture test/status-fixtures/
89// carbon.json (built + run — regenerate with `./deploy/status-publish.sh
90// --dry-run <dir>` then copy <dir>/carbon.json here).
91const carbon = JSON.parse(read("web/status/carbon.json"));
92const carbonRun = JSON.parse(read("test/status-fixtures/carbon.json"));
93const carbonHtml = read("web/status/carbon.html");
94// The contributors index is COMMITTED data too (tools/contributors.mjs).
95const contributors = JSON.parse(read("web/status/contributors.json"));
96const contributorsHtml = read("web/status/contributors.html");
97// The tier-economics snapshot is COMMITTED data (re-derived by hand from
98// docs/tier-economics.md when prices or input rates change) — the real
99// web/status/economics.json is its own fixture, like the carbon ledger.
100const economics = JSON.parse(read("web/status/economics.json"));
101const economicsHtml = read("web/status/economics.html");
102// The music ledger is COMMITTED data too (tools/music-ledger.mjs):
103// an index plus one shard per month, so the page never fetches more than a
104// month at a time.
105const music = JSON.parse(read("web/status/music.json"));
106const musicHtml = read("web/status/music.html");
107const musicShards = music.months.map((m) => [m, JSON.parse(read("web/status/music-" + m + ".json"))]);
108// The security ledger: the dry-run fixture (attention shape — proves the
109// dirty path redacts) plus, when present, the committed real scan. The real
110// file may legitimately be absent (the page then shows "scan pending", never
111// a fake clean), so it's checked only when it exists.
112const securityFix = JSON.parse(read("test/status-fixtures/security.json"));
113const securityHtml = read("web/status/security.html");
114let securityLive = null;
115try { securityLive = JSON.parse(read("web/status/security.json")); } catch { /* absent = pending, honest */ }
116const securityShapes = [["security fixture", securityFix]]
117 .concat(securityLive ? [["committed security.json", securityLive]] : []);
118
119await test("fleet page fields all exist in the generator's fleet.json", () => {
120 for (const f of fields(indexHtml)) {
121 assert.notEqual(resolve(fleet, f), undefined, "fleet.json is missing " + f);
122 }
123});
124
125await test("books page fields all exist in one of the two books shapes", () => {
126 for (const f of fields(booksHtml)) {
127 const hit = resolve(books, f) !== undefined || resolve(booksDown, f) !== undefined;
128 assert.ok(hit, "neither books.json shape has " + f);
129 }
130});
131
132await test("carbon page fields resolve — built in committed carbon.json, run in the live fixture", () => {
133 for (const f of fields(carbonHtml)) {
134 if (f.startsWith("run.")) {
135 // run.* is absent from the committed file by design — pinned by the fixture.
136 assert.notEqual(resolve(carbonRun, f), undefined, "run fixture is missing " + f);
137 } else {
138 assert.notEqual(resolve(carbon, f), undefined, "committed carbon.json is missing " + f);
139 }
140 }
141});
142
143await test("contributors page fields all exist in the committed contributors.json", () => {
144 for (const f of fields(contributorsHtml)) {
145 assert.notEqual(resolve(contributors, f), undefined, "contributors.json is missing " + f);
146 }
147});
148
149await test("economics page fields all exist in the committed economics.json", () => {
150 for (const f of fields(economicsHtml)) {
151 assert.notEqual(resolve(economics, f), undefined, "economics.json is missing " + f);
152 }
153});
154
155await test("music page fields all exist in the committed music.json index", () => {
156 for (const f of fields(musicHtml)) {
157 assert.notEqual(resolve(music, f), undefined, "music.json is missing " + f);
158 }
159});
160
161// The music ledger publishes deliberately-chosen content, so its own
162// hygiene is structural: month shards that match the index and their own
163// filenames, no external art (data URIs only, deduped in the shard's albums
164// map — the contributor-avatars rule), skip-filtered rows only (≥60s apart
165// per listener, checked across shard boundaries), and signal words from the
166// fixed vocabulary — a bare catalog stream carries none, because Music
167// can't tell a direct pick from autoplay.
168await test("music shards are well-formed, sorted, art self-contained", () => {
169 assert.match(music.updated_at, /^\d{4}-\d{2}-\d{2}T/, "index updated_at is ISO");
170 assert.deepEqual(music.months, [...music.months].sort().reverse(), "index months newest-first");
171 const artKey = (t) => t.album_id != null ? String(t.album_id) : t.track + " — " + t.artist;
172 let total = 0;
173 const lastBy = new Map(); // per listener, across shards oldest→newest
174 for (const [m, s] of [...musicShards].reverse()) {
175 assert.equal(s.month, m, "shard month matches its filename");
176 for (const uri of Object.values(s.albums)) {
177 assert.match(uri, /^data:image\//, m + ": album art must be a data URI");
178 }
179 let prev = "";
180 for (const t of s.tracks) {
181 assert.ok(t.ts >= prev, m + ": not sorted oldest-first at " + t.ts);
182 prev = t.ts;
183 assert.equal(t.ts.slice(0, 7), m, "row " + t.ts + " outside its shard month");
184 assert.ok(t.track && t.artist && t.album && t.listener, "row is complete");
185 assert.ok(["Apple Music", "local file", "library"].includes(t.source), "source word: " + t.source);
186 assert.ok(Array.isArray(t.signals) && t.signals.every((x) => ["queued", "radio", "shuffle"].includes(x)),
187 "signals ⊆ {queued,radio,shuffle}: " + JSON.stringify(t.signals));
188 assert.ok(!(artKey(t) in s.albums) || typeof s.albums[artKey(t)] === "string", "art key resolves");
189 const last = lastBy.get(t.listener);
190 if (last && last.track !== t.track) {
191 assert.ok(Date.parse(t.ts) - Date.parse(last.ts) >= 60_000,
192 "skip leaked: " + last.track + " held under 60s before " + t.track);
193 }
194 lastBy.set(t.listener, t);
195 }
196 total += s.tracks.length;
197 }
198 assert.equal(music.totals.tracks, total, "index totals.tracks is the shard sum");
199});
200
201await test("security page fields all exist in the scanner's security.json", () => {
202 for (const [name, s] of securityShapes) {
203 for (const f of fields(securityHtml)) {
204 assert.notEqual(resolve(s, f), undefined, name + " is missing " + f);
205 }
206 }
207});
208
209// Contributor entries stay well-formed as the tool regenerates them: known
210// kinds, positive commit counts, sorted by the metric, humans carry a profile
211// link + self-contained data-URI avatar (the pages allow no external hosts),
212// and no email address ever reaches the published JSON.
213await test("contributors entries are well-formed, sorted, and email-free", () => {
214 let prev = Infinity;
215 for (const c of contributors.contributors) {
216 assert.ok(["human", "ai"].includes(c.kind), "kind: " + c.kind);
217 assert.ok(Number.isInteger(c.commits) && c.commits > 0, c.id + ": commits");
218 assert.ok(c.commits <= prev, "not sorted by commits at " + c.id);
219 prev = c.commits;
220 assert.ok(c.name && c.id, "name + id present");
221 if (c.kind === "human") {
222 assert.match(c.url, /^https:\/\/github\.com\//, c.id + ": profile url");
223 assert.match(c.avatar, /^data:image\//, c.id + ": avatar must be a data URI");
224 }
225 }
226 assert.ok(!/[\w.+-]+@[\w-]+\.[\w.]+/.test(JSON.stringify(contributors).replace(/data:image\/[^"]+/g, "")),
227 "an email address leaked into contributors.json");
228});
229
230// The tier-economics snapshot must stay internally consistent as it's
231// re-derived (docs/tier-economics.md: the formulas are the contract, the
232// numbers a snapshot): net follows the Stripe fee line exactly (the two fee
233// constants below mirror the input-rates table — update both together),
234// profit ≈ net − cost within the doc's ~rounding, margin is profit over
235// GROSS, and every tier's included allowance sits below its break-even —
236// the "no tier can structurally lose money" claim the page makes in prose.
237await test("economics snapshot arithmetic + structurally-profitable claim hold", () => {
238 assert.match(economics.as_of, /^\d{4}-\d{2}-\d{2}$/, "as_of is a date");
239 assert.equal(economics.currency, "eur");
240 const q = economics.free_spaces_per_account;
241 assert.ok(Number.isInteger(q) && q >= 1, "free-space quota is a positive integer");
242 assert.ok(economics.price_book.length > 0 && economics.storage_allowances.length > 0
243 && economics.input_rates.length > 0 && economics.estimates.length > 0, "all four tables non-empty");
244 for (const p of economics.price_book) {
245 assert.ok(Number.isInteger(p.yearly_cents) && p.yearly_cents > 0, p.tier + ": yearly_cents is integer cents");
246 if ("monthly_cents" in p) {
247 assert.ok(Number.isInteger(p.monthly_cents) && p.monthly_cents > 0, p.tier + ": monthly_cents is integer cents");
248 // A monthly toggle must cost more per year than the annual price, or
249 // the annual default the page defends would be the worse deal.
250 assert.ok(12 * p.monthly_cents >= p.yearly_cents, p.tier + ": 12×monthly ≥ yearly");
251 }
252 }
253 const allowance = new Map(economics.storage_allowances.map((s) => [s.tier, s.gb]));
254 for (const s of economics.storage_allowances) {
255 assert.ok(Number.isInteger(s.gb) && s.gb > 0, s.tier + ": allowance is a positive GB integer");
256 }
257 for (const e of economics.estimates) {
258 const label = e.plan + " · " + e.billing;
259 const charges = e.billing === "monthly" ? 12 : 1;
260 // Stripe fee constants (1.5% + €0.25 per charge) from the input-rates table.
261 const net = e.gross_year_cents - 25 * charges - 0.015 * e.gross_year_cents;
262 assert.ok(Math.abs(e.net_year_cents - net) <= 1,
263 label + ": net must follow the fee model (" + e.net_year_cents + " vs " + net.toFixed(1) + ")");
264 assert.ok(e.cost_year_cents > 0 && e.cost_year_cents < e.net_year_cents, label + ": cost sits inside net");
265 const tol = Math.max(5, Math.round(e.gross_year_cents * 0.005)); // costs are ~ estimates
266 assert.ok(Math.abs(e.profit_year_cents - (e.net_year_cents - e.cost_year_cents)) <= tol,
267 label + ": profit ≈ net − cost (" + e.profit_year_cents + ")");
268 assert.ok(Math.abs(e.margin_pct - (100 * e.profit_year_cents) / e.gross_year_cents) <= 1,
269 label + ": margin is profit over gross");
270 const gb = allowance.get(e.plan);
271 assert.ok(Number.isInteger(gb), label + ": plan has a storage-allowance row");
272 assert.ok(e.break_even_gb > gb, label + ": allowance must sit below break-even (structurally profitable)");
273 }
274});
275
276// A manifest entry nobody reads is drift too: each leaf property must appear
277// in the page's render code, not just the manifest.
278await test("every declared field is actually read by its page", () => {
279 for (const [html, fs] of [[indexHtml, fields(indexHtml)], [booksHtml, fields(booksHtml)], [carbonHtml, fields(carbonHtml)], [contributorsHtml, fields(contributorsHtml)], [securityHtml, fields(securityHtml)], [economicsHtml, fields(economicsHtml)], [musicHtml, fields(musicHtml)]]) {
280 const body = html.slice(html.indexOf("];") + 2);
281 for (const f of fs) {
282 const leaf = f.split(".").pop().replace("[]", "");
283 assert.ok(body.includes(leaf), "manifest field " + f + " is never used");
284 }
285 }
286});
287
288// The degraded shape must be renderable: available flips the page, reason is
289// the message.
290await test("degraded books shape carries available:false + reason", () => {
291 assert.equal(booksDown.available, false);
292 assert.equal(typeof booksDown.reason, "string");
293});
294
295// Privacy re-check on the committed fixtures (the dry-run asserts this too —
296// belt and suspenders on what's in git): no fixture hostname, subscription,
297// customer, transaction, or provider-account/workspace id may appear in
298// published output.
299await test("fixtures contain no per-payer ids or hostnames", () => {
300 for (const j of [fleet, fleetGF, fleetAC, books, booksDown, booksNoExp, booksHzConst, carbon, carbonRun, contributors, economics, ...securityShapes.map(([, s]) => s)]) {
301 const s = JSON.stringify(j);
302 assert.ok(!/sub_|cus_|txn_|wrkspc_|req_fixture|ce_fixture|dnsfix|hzfix|\.example|\.sock/.test(s), "leak in " + s.slice(0, 80));
303 }
304});
305
306// ---- the security ledger: redacted by contract --------------------------------
307// The disclosure line (deploy/security-scan.sh header): the published block is
308// a STATUS + COUNT only. The schema is an ALLOWLIST — any extra key fails, so
309// an advisory id, package path, or version list can't ship by accident.
310await test("security ledger carries only the redacted hygiene schema", () => {
311 for (const [name, s] of securityShapes) {
312 assert.deepEqual(Object.keys(s).sort(), ["dependencies", "generated_at", "go_modules", "scanned_sha"], name + ": keys");
313 assert.match(s.generated_at, /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/, name + ": generated_at is ISO UTC");
314 // The build sha is already public via the signed release feed — the one
315 // version identifier the page may carry.
316 assert.match(s.scanned_sha, /^[0-9a-f]{7,40}$/, name + ": scanned_sha is a git sha");
317 assert.ok(Number.isInteger(s.go_modules) && s.go_modules > 0, name + ": go_modules is a positive count");
318 assert.deepEqual(Object.keys(s.dependencies).sort(), ["advisories_under_remediation", "status"], name + ": dependency keys");
319 assert.ok(["clean", "attention", "pending"].includes(s.dependencies.status),
320 name + ": status is a vocabulary word, got " + s.dependencies.status);
321 const n = s.dependencies.advisories_under_remediation;
322 assert.ok(Number.isInteger(n) && n >= 0, name + ": count is an integer ≥ 0");
323 // Status and count must agree — "clean" beside a nonzero count (or the
324 // reverse) would be a lie in one direction or the other.
325 assert.equal(n > 0, s.dependencies.status === "attention", name + ": status agrees with the count");
326 }
327});
328
329// The redaction guard: no advisory id in ANY grammar (Go vulndb GO-…, CVE,
330// GHSA) — an unpatched finding publishes as a count, never a name. The
331// fixture was folded from a stream FULL of such ids, so this proves the
332// generator strips them, not merely that the input was clean.
333await test("security ledger never names an advisory", () => {
334 for (const [name, s] of securityShapes) {
335 const t = JSON.stringify(s);
336 assert.ok(!/CVE-\d{4}-\d+|GHSA-|GO-\d{4}-\d+/i.test(t), name + " carries an advisory id: " + t.slice(0, 120));
337 }
338});
339
340// Pin the dirty path end-to-end: the dry-run's fixture stream carries two
341// advisories with symbol-level findings (one of them twice — findings dedupe
342// by advisory) plus a module-level-only informational one that must NOT
343// count. Redacted result: attention + 2, and nothing else.
344await test("security dry-run fixture folds to attention + count 2", () => {
345 assert.equal(securityFix.dependencies.status, "attention");
346 assert.equal(securityFix.dependencies.advisories_under_remediation, 2);
347 assert.equal(securityFix.scanned_sha, "abc1234");
348 assert.equal(securityFix.go_modules, 42);
349});
350
351// Expenses publish ITEMIZED by design — decision #19's other half (income
352// aggregates, expenses itemize; the amounts are public on purpose). The
353// schema is still an ALLOWLIST: provider word + EXACTLY ONE amount key
354// (month_to_date_cents for metered providers, monthly_cents / yearly_cents
355// for flat subscriptions, to_date_cents for a cumulative operator-attested
356// lifetime figure — each as billed: a yearly fee is never divided into a
357// fake monthly, a lifetime figure never smeared across months) + its own
358// billing currency, nothing else — so an account id, invoice id, or
359// resource-level line can't ship by accident. Currencies stay per-provider,
360// never FX-converted, and only usd/eur exist today.
361await test("expenses carry only the allowed itemized schema", () => {
362 const exp = books.expenses;
363 assert.ok(exp, "books fixture carries expenses");
364 assert.deepEqual(Object.keys(exp).sort(), ["month", "providers"], "expenses keys");
365 assert.match(exp.month, /^\d{4}-\d{2}$/, "expenses.month is YYYY-MM");
366 // Each provider's key set carries exactly one of the four amount keys —
367 // the deepEqual below enforces the exactly-one rule per provider.
368 const allowed = {
369 "aws": ["currency", "month_to_date_cents", "provider"],
370 "hetzner": ["currency", "monthly_cents", "provider"],
371 "anthropic": ["currency", "month_to_date_cents", "provider"],
372 "claude.ai": ["currency", "provider", "to_date_cents"],
373 "dnsimple": ["currency", "month_to_date_cents", "provider"],
374 "apple": ["currency", "provider", "yearly_cents"],
375 };
376 // The dry-run's fixed fixture exercises every provider, in publish order.
377 assert.deepEqual(exp.providers.map((p) => p.provider),
378 ["aws", "hetzner", "anthropic", "claude.ai", "dnsimple", "apple"], "fixture exercises all providers");
379 for (const p of exp.providers) {
380 assert.ok(p.provider in allowed, "unknown provider " + p.provider);
381 assert.deepEqual(Object.keys(p).sort(), allowed[p.provider], p.provider + " keys");
382 assert.ok(["usd", "eur"].includes(p.currency), p.provider + " currency ∈ {usd,eur}, got " + p.currency);
383 const cents = p.month_to_date_cents ?? p.monthly_cents ?? p.yearly_cents ?? p.to_date_cents;
384 assert.ok(Number.isInteger(cents) && cents >= 0, p.provider + " amount is integer cents ≥ 0");
385 }
386});
387
388// No providers resolve → the whole expenses object is omitted (degrade, never
389// zero, never guess). The degraded income shape needn't carry it either.
390await test("expenses omit entirely when no provider resolves", () => {
391 assert.ok(!("expenses" in booksNoExp), "no-expenses fixture must omit the key");
392 assert.equal(booksNoExp.available, true, "omission is independent of income availability");
393});
394
395// Hetzner's figure is API-computed when the operator constant is unset: the
396// default fixture pins the servers-API math (two dry-run fixture pages, each
397// server priced by the ONE server_type.prices[] entry matching its own
398// location — gross monthly EUR 16.4288 + 4.5100 = 20.9388, rounded once at
399// the total to 2094 cents). And when STATUS_HETZNER_MONTHLY_CENTS is set the
400// constant wins over a resolvable API path — operator truth beats computed.
401// Either way the key shape is identical (monthly_cents, eur).
402await test("hetzner: API-computed cents with rounding; constant overrides", () => {
403 const hz = books.expenses.providers.find((p) => p.provider === "hetzner");
404 assert.deepEqual(hz, { provider: "hetzner", monthly_cents: 2094, currency: "eur" },
405 "API path: location-matched gross sum, rounded");
406 const hzc = booksHzConst.expenses.providers.find((p) => p.provider === "hetzner");
407 assert.deepEqual(hzc, { provider: "hetzner", monthly_cents: 1400, currency: "eur" },
408 "constant override: the operator figure publishes, same shape");
409});
410
411// The carbon tally must stay internally consistent as entries accrue — the
412// totals are the sum of the ledger, each entry's kg derives from its output
413// tokens × the published factors, and each SOURCE's periods are chronological
414// and non-overlapping (tools/carbon-tally.mjs appends strictly after that
415// source's last period_end; an overlap means two branches double-counted the
416// same window — drop the younger entry and re-run --write). Sources are
417// anonymous name-pair labels, same rule as the fleet's box labels: the tally
418// is public, so never a hostname or username.
419await test("carbon tally arithmetic + per-source chronology hold", () => {
420 const b = carbon.built;
421 const f = b.factors_mg_co2e_per_output_token;
422 assert.ok(f.low < f.central && f.central < f.high, "factors ordered");
423 let out = 0, kg = { low: 0, central: 0, high: 0 };
424 const prevEnd = new Map();
425 for (const e of b.entries) {
426 assert.match(e.source, /^[a-z]+-[a-z]+$/, "source must be a name-pair label, got " + e.source);
427 assert.ok(["measured", "extrapolated"].includes(e.basis), "basis word: " + e.basis);
428 assert.ok(Date.parse(e.period_start) < Date.parse(e.period_end), "period runs forward");
429 assert.ok(Date.parse(e.period_start) >= (prevEnd.get(e.source) ?? -Infinity),
430 e.source + " periods overlap at " + e.period_start);
431 prevEnd.set(e.source, Date.parse(e.period_end));
432 for (const band of ["low", "central", "high"]) {
433 const want = (e.output_tokens * f[band]) / 1e6; // mg → kg
434 assert.ok(Math.abs(e["kg_" + band] - want) <= 0.06,
435 "entry kg_" + band + " ≠ tokens × factor (" + e["kg_" + band] + " vs " + want.toFixed(2) + ")");
436 kg[band] += e["kg_" + band];
437 }
438 out += e.output_tokens;
439 }
440 assert.equal(b.totals.output_tokens, out, "built.totals.output_tokens is the ledger sum");
441 for (const band of ["low", "central", "high"]) {
442 assert.ok(Math.abs(b.totals["kg_" + band] - kg[band]) <= 0.05,
443 "built.totals.kg_" + band + " is the ledger sum");
444 }
445 assert.equal(Date.parse(carbon.updated_at), Math.max(...b.entries.map((e) => Date.parse(e.period_end))),
446 "updated_at is the newest built period_end");
447});
448
449// The injected run block: an ALLOWLIST schema (any extra key fails, so a needle
450// can't ship by accident), banded low≤central≤high, aggregates only — no
451// hostname/IP/socket, and the per-space denominator is the public instance
452// count, NEVER per-member.
453await test("run block carries only the allowed operational schema, banded, no needles", () => {
454 const r = carbonRun.run;
455 assert.deepEqual(Object.keys(r).sort(),
456 ["cumulative_kg", "daily_kg", "generated_at", "grid_g_per_kwh", "per_space_daily_kg",
457 "pue", "services", "since", "spaces", "vcpus", "watts"], "run keys");
458 assert.match(r.generated_at, /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/, "generated_at is ISO UTC");
459 assert.match(r.since, /^\d{4}-\d{2}-\d{2}$/, "since is a date");
460 assert.ok(Number.isInteger(r.spaces) && r.spaces > 0, "spaces is a positive instance count");
461 assert.ok(Number.isInteger(r.vcpus) && r.vcpus > 0, "vcpus is a positive count");
462 assert.ok(typeof r.pue === "number" && r.pue >= 1, "pue is a real ≥ 1");
463 for (const band of ["watts", "grid_g_per_kwh", "daily_kg", "cumulative_kg", "per_space_daily_kg"]) {
464 assert.deepEqual(Object.keys(r[band]).sort(), ["central", "high", "low"], band + " is banded");
465 assert.ok(r[band].low <= r[band].central && r[band].central <= r[band].high, band + " ordered low≤central≤high");
466 }
467 for (const s of r.services) {
468 assert.deepEqual(Object.keys(s).sort(), ["daily_kg_central", "name"], "service " + s.name + " keys");
469 assert.ok(typeof s.name === "string" && s.name.length > 0, "service name");
470 assert.ok(typeof s.daily_kg_central === "number" && s.daily_kg_central >= 0, s.name + " daily kg ≥ 0");
471 }
472 const t = JSON.stringify(r);
473 assert.ok(!/\d+\.\d+\.\d+\.\d+|[a-z0-9-]+\.(sock|example|com|net|chat|at)\b/i.test(t),
474 "run block reads like a hostname/IP: " + t.slice(0, 80));
475});
476
477// The run math folds server_type + region grid → watts → kg exactly, so the
478// generator's arithmetic can't drift (mirrors deploy/status-publish.sh's
479// carbon_run_object + its dry-run assertions). 6 vCPUs (cpx31=4 + cx22=2), the
480// Germany fixture grid 350 g/kWh, W/vCPU central 3.5, PUE 1.15, 10-day span, 6
481// spaces.
482await test("run fixture folds server_type + grid to the asserted watts→kg math", () => {
483 const r = carbonRun.run;
484 assert.equal(r.vcpus, 6, "vCPUs summed across the servers fixture");
485 assert.equal(r.watts.central, 21, "6 vCPU × 3.5 W");
486 assert.equal(r.grid_g_per_kwh.central, 350, "Germany fixture grid");
487 assert.equal(r.pue, 1.15);
488 // 6 × 3.5 × 24 × 350 × 1.15 / 1e6 + 0.001 (AWS) + 0.005 (inference) = 0.20886.
489 assert.equal(r.daily_kg.central, 0.20886, "daily central kg");
490 assert.equal(r.cumulative_kg.central, 2.0886, "cumulative = daily × 10 days");
491 assert.equal(r.per_space_daily_kg.central, 0.03481, "per space = daily ÷ 6 spaces");
492 // The service breakdown's central terms sum to the daily central (router term
493 // is the watts→kg piece; AWS + inference are the small explicit terms).
494 const sum = r.services.reduce((a, s) => a + s.daily_kg_central, 0);
495 assert.ok(Math.abs(sum - r.daily_kg.central) <= 1e-6, "services sum to the daily central");
496});
497
498// Capacity + hosts publish ABSTRACT levels only (Paul's call: bucketed words,
499// never needles). The schema is an ALLOWLIST — any extra key under hosts /
500// capacity fails, so a precise number (remaining slots, GB, percentages, cap
501// values) can't ship by accident, and the level/load words themselves must be
502// digit-free vocabulary entries.
503const fleetShapes = [
504 ["fleet", fleet], ["fleet-getting-full", fleetGF], ["fleet-at-capacity", fleetAC],
505 ["fleet-multi-host", fleetMH],
506];
507await test("hosts + capacity carry only the allowed abstract schema", () => {
508 for (const [name, f] of fleetShapes) {
509 assert.deepEqual(Object.keys(f.capacity).sort(), ["level"], name + ": capacity keys");
510 assert.ok(["plenty", "getting-full", "at-capacity"].includes(f.capacity.level),
511 name + ": capacity.level is a band word, got " + f.capacity.level);
512 assert.deepEqual(Object.keys(f.hosts).sort(), ["boxes", "count"], name + ": hosts keys");
513 assert.equal(f.hosts.count, f.hosts.boxes.length, name + ": count matches boxes");
514 for (const b of f.hosts.boxes) {
515 // region is optional (omitted when the operator sets none). When present
516 // it must be a coarse public area — continent + country — and must never
517 // read like an IP or hostname (no dots-and-digits / label.tld shapes).
518 // always_on is likewise optional: a REMOTE mesh peer's self-published
519 // snapshot (mesh_peer_boxes) never carries it — that's a local-box-only
520 // concept — so a peer's key set is the "required" set on its own,
521 // while the LOCAL box always adds always_on.
522 const required = ["asleep", "awake", "label", "load"];
523 const keys = Object.keys(b).sort();
524 const allowed = required.concat(["always_on", "region"]).sort();
525 assert.ok(required.every((k) => keys.includes(k)), name + ": box missing a required key: " + keys);
526 assert.ok(keys.every((k) => allowed.includes(k)), name + ": box carries a disallowed key: " + keys);
527 if ("region" in b) {
528 assert.equal(typeof b.region, "string", name + ": region is a string");
529 assert.ok(!/\d+\.\d+|[a-z0-9-]+\.[a-z]{2,}/i.test(b.region),
530 name + ": region reads like an IP/hostname: " + b.region);
531 }
532 // Labels are anonymous ordinals — never a hostname, IP, or URL.
533 assert.match(b.label, /^[a-z]+-[a-z]+$/, name + ": box label must be a name-action pair");
534 assert.ok([null, "comfortable", "busy", "critical"].includes(b.load),
535 name + ": box load is a band word or null, got " + b.load);
536 }
537 // No digit may ride in the capacity subtree — the band word is the entire
538 // public surface.
539 assert.ok(!/\d/.test(JSON.stringify(f.capacity)), name + ": capacity carries a number");
540 }
541});
542
543// The multi-host fixture specifically: a second, live mesh peer merges into
544// hosts.boxes without displacing the local box, and count reflects both.
545await test("multi-host fixture merges the local box with a live mesh peer", () => {
546 assert.equal(fleetMH.hosts.count, 2, "hosts.count reflects both boxes");
547 assert.equal(fleetMH.hosts.boxes.length, 2);
548 const [local, peer] = fleetMH.hosts.boxes;
549 assert.ok("always_on" in local, "the local box still reports always_on");
550 assert.ok(!("always_on" in peer), "a remote peer never reports always_on (a genuinely local-box-only concept)");
551 assert.equal(peer.region, "UK · London", "a peer's own LCHAT_BOX_REGION rides through the merge verbatim");
552 assert.notEqual(local.label, peer.label, "the two boxes must have distinct labels");
553});
554
555// The local box's own row must prefer its self-published, ownership-filtered
556// snapshot (mesh-self-stats.json in the dry-run fixture: awake=1) over its
557// raw local `ss` sweep (which would show awake=2, see the single-box `fleet`
558// fixture) — otherwise this box's own row still overlaps a peer's, even once
559// the peer's row is correctly filtered.
560await test("the local box's own row prefers its self-published stats over its raw ss sweep", () => {
561 const [local] = fleetMH.hosts.boxes;
562 assert.equal(local.awake, 1, "local.awake must come from the self-published snapshot, not the unfiltered ss sweep (2)");
563 assert.notEqual(local.awake, fleet.hosts.boxes[0].awake,
564 "a regression would make the mesh-off and mesh-on local rows identical again");
565});
566
567// A host genuinely running on a mesh peer has no local socket on this box, so
568// the top-level instances.awake/asleep must sum every box's own verified
569// split, not just this box's — otherwise a peer-hosted instance reads as
570// "asleep" fleet-wide even while it's actually awake there.
571await test("top-level awake/asleep are fleet-wide, not just the local box", () => {
572 const [local, peer] = fleetMH.hosts.boxes;
573 assert.equal(fleetMH.instances.awake, local.awake + peer.awake,
574 "instances.awake must sum every box's own awake count");
575 assert.equal(fleetMH.instances.asleep, fleetMH.instances.hibernating - fleetMH.instances.awake,
576 "instances.asleep must be hibernating minus the fleet-wide awake total");
577 assert.notEqual(fleetMH.instances.awake, local.awake,
578 "a regression would silently drop back to only the local box's awake count");
579});
580
581// Each committed fixture set derives its band — pins the 70/90 thresholds and
582// the disk-floor rule in the generator (see dry_run's capacity fixtures).
583await test("capacity fixtures derive plenty / getting-full / at-capacity", () => {
584 assert.equal(fleet.capacity.level, "plenty");
585 assert.equal(fleetGF.capacity.level, "getting-full");
586 assert.equal(fleetAC.capacity.level, "at-capacity");
587 assert.equal(fleet.hosts.boxes[0].load, "comfortable");
588 // getting-full is driven by the registered ratio, not memory — capacity and
589 // box load are independent signals.
590 assert.equal(fleetGF.hosts.boxes[0].load, "comfortable");
591 assert.equal(fleetAC.hosts.boxes[0].load, "critical");
592 // The STATUS_BOX_REGION seam: the dry-run's fixed coarse region rides
593 // through to the box row verbatim.
594 assert.equal(fleet.hosts.boxes[0].region, "EU · Germany");
595});
596
597// ---- the shared masthead + nav (status-nav.js): one copy, no drift ------------
598// The pages drifted while each carried its own copy of the masthead + nav
599// (stale link lists, bare h1 overrides quietly moving the masthead between
600// pages). Now every dashboard ships two empty mounts filled by the one
601// builder — so no page may carry an inline copy, no page CSS may reach the
602// shared masthead with a bare h1 selector, and the builder's GROUPS must
603// cover exactly the dashboard pages that exist.
604await test("status pages all mount the shared masthead + nav, no inline copies", () => {
605 const navJs = read("web/status/status-nav.js");
606 const navPages = [...navJs.matchAll(/\["([a-z-]+\.html)"/g)].map((m) => m[1]);
607 const pages = ["index.html", "hardening.html", "security.html", "books.html", "economics.html",
608 "funding.html", "carbon.html", "contributors.html", "prompts.html", "ssh.html", "music.html",
609 "roadmap.html", "milestones.html"];
610 assert.deepEqual([...navPages].sort(), [...pages].sort(), "GROUPS covers exactly the dashboard pages");
611 for (const p of pages) {
612 const html = read("web/status/" + p);
613 assert.match(html, /<header data-title="[^"]+"><\/header>/, p + ": masthead mount missing");
614 assert.ok(html.includes('<nav class="status-nav" aria-label="Status"></nav>'), p + ": empty nav mount missing");
615 assert.ok(html.includes('src="./status-nav.js"'), p + ": shared include missing");
616 assert.ok(!html.includes("group-label"), p + ": carries an inline nav copy");
617 assert.ok(!html.includes('class="brand"'), p + ": carries an inline masthead copy");
618 const style = (html.match(/<style>([\s\S]*?)<\/style>/) || [, ""])[1];
619 assert.ok(!/(^|[^-\w#.])h1\s*\{/m.test(style), p + ": a bare h1 selector reaches the shared masthead");
620 }
621});
622
623if (failures > 0) {
624 console.error(failures + " failure(s)");
625 process.exit(1);
626}
627