Pi.Lonics

The claims ledger

Every factual assertion rendered on this site has a row here naming the file it was checked against and how strong that evidence is. Written by Shane Pilon, and generated from claims.md in the site repository at build time, so this page cannot drift from the file it publishes.

What the check does

A verifier resolves every cited source and fails if one is missing, if a row is malformed, if the numbering has a gap, or if a result tries to ship on an evidence status the ledger forbids, which is a single-seed result or a proxy metric. It then writes a lock file recording each row as worded together with a hash of the file it cites. The site build re-derives the rows and refuses to compile if a row has no lock entry or has drifted from the wording it was locked in. 68 rows are locked as of 2026-08-08.

What the check does not do

Read the check itself, all 92 lines

This is scripts/verify-claims-lock.mjs in full, read off disk when this page was built. It runs in prebuild; if it exits non-zero this page does not deploy. It is the half of the gate that runs on a builder that has never seen the private research files, which is why it checks the lock rather than the sources: it proves that every row shipping today is a row that was checked against a real source, in the exact wording it was checked in.

#!/usr/bin/env node
// The half of the gate that runs everywhere, including on a Vercel builder that
// has never seen the palace.
//
// scripts/verify-claims.mjs resolves every cited source against the palace and
// writes claims.lock.json. That file cannot run on Vercel: the palace is a local
// Windows path. So the published sentence "the build fails if any of them loses
// that source" was false of the shipped build, because `build` was a bare
// `next build` with no hook, no vercel.json and no CI.
//
// This script closes that. It re-derives the active rows from claims.md and
// fails when:
//   - claims.lock.json is missing,
//   - an active row has no lock entry,
//   - a row's wording, source path or status has drifted from what was locked,
//   - the lock carries a row that claims.md no longer has.
//
// It does not, and cannot, prove that a palace file still exists on this
// machine. It proves that every row shipping today is a row that was checked
// against a real source, in the exact wording it was checked in. Re-run
// `npm run verify:claims` on the box with the palace to re-lock.
import { existsSync, readFileSync } from "node:fs";
import { join, resolve } from "node:path";
import { parseClaims, claimFingerprint } from "./claims-parse.mjs";

const LOCK_PATH = join(resolve(process.cwd()), "claims.lock.json");

if (!existsSync(LOCK_PATH)) {
  console.error("FAIL: claims.lock.json is missing. Run `npm run verify:claims` with the palace mounted.");
  process.exit(1);
}

let lock;
try {
  lock = JSON.parse(readFileSync(LOCK_PATH, "utf8"));
} catch (err) {
  console.error(`FAIL: claims.lock.json is not readable JSON — ${err.message}`);
  process.exit(1);
}

const { rows, tableRowCount } = parseClaims("claims.md");
if (rows.length === 0) {
  console.error("FAIL: no claim rows parsed from claims.md");
  process.exit(1);
}

let bad = 0;

if (tableRowCount !== rows.length) {
  console.error(
    `FAIL: ${tableRowCount} table row(s) found in the active section but only ${rows.length} parsed — a row is malformed`
  );
  bad++;
}

const byNumber = new Map((lock.claims ?? []).map((c) => [String(c.n), c]));

for (const row of rows) {
  const entry = byNumber.get(String(row.num));
  if (!entry) {
    console.error(
      `FAIL claim ${row.num}: no lock entry. An unlocked claim does not ship; run \`npm run verify:claims\` with the palace mounted.`
    );
    bad++;
    continue;
  }
  byNumber.delete(String(row.num));
  if (entry.claim !== claimFingerprint(row)) {
    console.error(
      `FAIL claim ${row.num}: wording, source or status has changed since it was locked against ${entry.source}. Re-verify it against its source, then re-lock.`
    );
    bad++;
  }
}

for (const [n, entry] of byNumber) {
  console.error(
    `FAIL: claims.lock.json still carries claim ${n} (${entry.source}) but claims.md no longer does — the lock is stale.`
  );
  bad++;
}

if (bad > 0) {
  console.error(`\n${bad} problem(s). The build refuses an unlocked or drifted claim.`);
  process.exit(1);
}

console.log(
  `OK: ${rows.length} claims, every one locked to a verified source${
    lock.generatedAt ? ` (locked ${lock.generatedAt})` : ""
  }.`
);

The external sources, in full

Three rows on this site cite something that is not mine: two reported external events, and one general property of the published literature. All three have public primary sources, and none of them is one of my own measurements.

The claims, as worded on the site

68 rows

What was refused

The more useful half of the ledger. These are claims that were considered and are not made, with the reason. Several of them shipped on the previous version of this site and are recorded here as overstated by their own sources.

This is the same discipline an engagement runs on. See what you can buy, or send me the number.