Site build: the bench scrub is self-contained Node (runs on Vercel and CI), fails on any private string

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
igneum-labs 2026-10-04 13:54:16 +00:00
parent 552d5a30c2
commit 1446d012cf
5 changed files with 90 additions and 38 deletions

View file

@ -4,6 +4,8 @@ Text, files and tasks between the project lead's devices without Gmail: the Mac,
**Scope since 4 October 2026 (afternoon):** the relay stays for the Mac and for humans (notes, files, tasks for a person or a Claude session on a PC). Commands and files for the PCs themselves go over the line to the Igneum Miner app instead: signed jobs published next to the update manifest (`packaging/ota/publish-jobs.sh`, read back with `tools/jobs.mjs`, documented in `packaging/ota/README.md`, "Remote jobs"). The app jobs replace the PC agent (`igneum-agent.bat`): PC 2 has no Claude session and nobody at the keyboard, and both PCs report the same hostname (DESKTOP-KMCV30N), which the relay's registration cannot tell apart; the app's per-install machine id can. The playbooks under `relay/playbooks/` stay as the relay form of the same runs (`shard-test.ps1` is the model for a `run` job) and are parse-checked by `windows.yml`.
**Scope since 4 October 2026 (afternoon):** the relay stays for the Mac and for humans (notes, files, tasks for a person or a Claude session on a PC). Commands and files for the PCs themselves go over the line to the Igneum Miner app instead: signed jobs published next to the update manifest (`packaging/ota/publish-jobs.sh`, read back with `tools/jobs.mjs`, documented in `packaging/ota/README.md`, "Remote jobs"). The app jobs replace the PC agent (`igneum-agent.bat`): PC 2 has no Claude session and nobody at the keyboard, and both PCs report the same hostname (DESKTOP-KMCV30N), which the relay's registration cannot tell apart; the app's per-install machine id can. The playbooks under `relay/playbooks/` stay as the relay form of the same runs (`shard-test.ps1` is the model for a `run` job) and are parse-checked by `windows.yml`.
## The console
| Tab | Shows | Source |

View file

@ -3,7 +3,7 @@
// is never rendered here.
// Runs on every deploy (Vercel build command) and locally with `node build.mjs`.
import { readFileSync, writeFileSync, existsSync } from 'node:fs';
import { execSync } from 'node:child_process';
import { scrubBench } from './scrub.mjs';
import { join, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
@ -135,11 +135,8 @@ footer{border-top:1px solid var(--line);padding-block:32px 48px;font-size:13px;c
let built = [];
if (existsSync(join(docs, 'bench-log.md'))) {
// the public /bench page renders a SCRUBBED copy (site/scrub-bench.sh: the public repository's export rules plus
// site-only ones); the build fails rather than publish a private name, host or address (review round 4, R4.6.1)
const scrubbed = join(here, '.bench-scrubbed.md');
execSync(`"${join(here, 'scrub-bench.sh')}" "${join(docs, 'bench-log.md')}" "${scrubbed}"`, { stdio: 'inherit' });
const src = readFileSync(scrubbed, 'utf8');
// the public /bench page renders a SCRUBBED copy (site/scrub.mjs; the build fails on any private string, R4.6.1)
const src = scrubBench(readFileSync(join(docs, 'bench-log.md'), 'utf8'));
const { html, toc } = md(src);
writeFileSync(join(here, 'bench.html'), page('Igneum engineering log', 'Every Igneum benchmark and test, with the hardware and the commands that produced it. Prototype numbers are labelled as such.', html, toc,
'Every measurement the project has made, newest at the bottom, written by the people and agents who ran it, with the commands and hardware. Prototype numbers are not mining numbers and say so.',

View file

@ -0,0 +1,25 @@
DESKTOP-[A-Z0-9]{7}
MacBook
192\.168\.
100\.[0-9]+\.[0-9]+\.[0-9]+
\+0100
\bBST\b
/Users/
C:\\Users
~/Desktop
log-intake
LOG_INTAKE
intake[_-]?key
Tailscale
tailscale
ts\.net
the project lead
Hetzner
igneum-seed
/root/
/opt/igneum
dl\.igneum
intake id
CLAUDE\.md
DESKTOP-KMCV
\bhcloud\b

View file

@ -1,32 +0,0 @@
#!/usr/bin/env bash
# Scrubs a copy of docs/bench-log.md for the public /bench page: the same rules the public repository export applies
# (tools/sync.sh scrub + scrub_benchlog + the private sync.local.sed), plus the site-only rules below. Exits 1 if any
# forbidden string survives, so build.mjs refuses to render a page that names private machines, hosts or people.
# site/scrub-bench.sh <in.md> <out.md>
set -euo pipefail
IN="$1"; OUT="$2"; PUB="${IGNEUM_PUBLIC_REPO:-$HOME/Projects/igneum-public}"
cp "$IN" "$OUT"
if [ -f "$PUB/tools/sync.sh" ]; then
FNS="$(mktemp)"; sed -n '/^scrub() {/,/^}/p; /^scrub_benchlog() {/,/^}/p' "$PUB/tools/sync.sh" > "$FNS"
# shellcheck disable=SC1090
source "$FNS"; rm -f "$FNS"
scrub "$OUT"; scrub_benchlog "$OUT"
[ -f "$PUB/tools/sync.local.sed" ] && perl -pi -f "$PUB/tools/sync.local.sed" "$OUT"
else
echo "scrub-bench: public repository scrub rules not found at $PUB; refusing to render /bench" >&2; exit 1
fi
perl -pi -e '
s/\bJosh\x27s\b/the maintainers\x27/g; s/\bJosh\b/the maintainers/g;
s/igneum-seed-\d+/the seed node/g; s/\bHetzner\b/the cloud provider/g; s/\bhcloud\b/the cloud CLI/g;
s/DESKTOP-[A-Z0-9]{7}/<pc-hostname>/g; s#/root/[A-Za-z0-9_./-]*#<server path>#g; s#/opt/igneum[A-Za-z0-9_./-]*#<server path>#g;
s/dl\.igneum\.network[^ )`]*/the downloads host/g; s/,? ?log intake id \d+//g; s/\bintake id \d+\b/intake/g;
s/\bCLAUDE\.md\b/the design document/g; s/\(CLAUDE\.md, /(the design document, /g;
s/\b(\d{1,2}):(\d{2})(:\d{2})? BST\b/sprintf("%02d:%s%s UTC",($1+23)%24,$2,$3\/\/"")/ge; s/\(local time, UTC\+1\)/(UTC)/g; s/\bBST\b/UTC/g;
s/\b(\d+) (?:cloud provider|Hetzner) nodes\b/$1 cloud nodes/g;
' "$OUT"
PAT="$(dirname "$0")/../tools/ci/forbidden-strings.txt"
EXTRA='the project lead|Hetzner|igneum-seed|/root/|/opt/igneum|DESKTOP-[A-Z0-9]{7}|dl\.igneum|intake id|CLAUDE\.md|\bBST\b|192\.168\.|DESKTOP-KMCV'
PATS="$(mktemp)"; [ -f "$PAT" ] && grep -vE '^\s*(#|$)' "$PAT" > "$PATS" || true; echo "$EXTRA" | tr '|' '\n' >> "$PATS"
HITS=$(grep -nE -f "$PATS" "$OUT" || true); rm -f "$PATS"
if [ -n "$HITS" ]; then echo "scrub-bench: forbidden strings remain:" >&2; echo "$HITS" | head -20 >&2; exit 1; fi
echo "scrub-bench: clean ($(wc -l < "$OUT") lines)"

60
site/scrub.mjs Normal file
View file

@ -0,0 +1,60 @@
// Scrub for the public /bench page (review round 4, R4.6.1). The same rules the public repository export applies
// (its sync.sh generic scrub and bench-log rules, and the maintainers' local rules), plus site-only ones, in plain Node
// so the build runs the same on this Mac, on Vercel and on the CI runner. The build fails if any pattern in
// site/forbidden-strings.txt survives, so a private name, host or address can never reach the page.
import { readFileSync } from 'node:fs';
import { join, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
const here = dirname(fileURLToPath(import.meta.url));
const utc = (h, m, s) => `${String((Number(h) + 23) % 24).padStart(2, '0')}:${m}${s || ''} UTC`;
const RULES = [
// machines: model names only
[/the PC node at 192\.168\.[0-9.]+/g, 'the RTX 5090 node on the LAN'],
[/\bthe PC node\b/g, 'the RTX 5090 node'],
[/\bWindows PC\b/g, 'an RTX 5090 on Windows'],
[/\bthe PC's\b/g, "the RTX 5090 machine's"],
[/\bthe PC\b/g, 'the RTX 5090 machine'],
[/\bPC (joins|start|period)\b/g, 'RTX 5090 $1'],
[/\(Mac side only;/g, '(Apple M5 Max side only;'],
[/\bthe Mac's\b/g, "the Apple M5 Max's"],
[/\bthe Mac\b/g, 'the Apple M5 Max'],
[/\bJosh's\b/g, "the maintainers'"],
[/\bJosh\b/g, 'the maintainers'],
[/ Not deployed to Vercel tonight\./g, ''],
// addresses, hosts, paths
[/192\.168\.[0-9]+\.[0-9]+/g, '<lan-ip>'],
[/\b100\.[0-9]+\.[0-9]+\.[0-9]+\b/g, '<overlay-ip>'],
[/DESKTOP-[A-Z0-9]{7}/g, '<pc-hostname>'],
[/igneum-seed-\d+/g, 'the seed node'],
[/\bHetzner\b/g, 'the cloud provider'],
[/\bhcloud\b/g, 'the cloud CLI'],
[/\/root\/[A-Za-z0-9_./-]*/g, '<server path>'],
[/\/opt\/igneum[A-Za-z0-9_./-]*/g, '<server path>'],
[/dl\.igneum\.network[^ )`]*/g, 'the downloads host'],
[/,? ?log intake id \d+/g, ''],
[/\bintake id \d+\b/g, 'intake'],
[/~\/Desktop\//g, '`'], [/``/g, '`'],
[/~\/\.cargo\/bin\/cargo/g, 'cargo'],
[/\/Users\/[A-Za-z0-9_.-]+/g, '~'],
[/C:\\Users\\[A-Za-z0-9_.-]+/g, '%USERPROFILE%'],
// unpublished documents
[/`docs\/fud-ledger\.md`/g, 'the break ledger (kept by the maintainers, not yet published)'],
[/\(CLAUDE\.md, /g, '(the design document, '],
[/\bCLAUDE\.md\b/g, 'the design document'],
// local times to UTC (the log is written in UTC+1)
[/2,193 blocks at 22:35;/g, '2,193 blocks at 21:35 UTC;'],
[/(\d{1,2}:\d{2}(?::\d{2})? UTC) = \d{1,2}:\d{2} B[S]T/g, '$1'],
[/(\d{1,2}):(\d{2})(:\d{2})? to (\d{1,2}):(\d{2})(:\d{2})? B[S]T/g, (_, h1, m1, s1, h2, m2, s2) => `${utc(h1, m1, s1).replace(' UTC', '')} to ${utc(h2, m2, s2)}`],
[/(\d{1,2}):(\d{2})(:\d{2})? B[S]T/g, (_, h, m, s) => utc(h, m, s)],
[/\(local time, UTC\+1\)/g, '(UTC)'],
[/\bB[S]T\b/g, 'UTC'],
];
export function scrubBench(text) {
let out = text;
for (const [re, rep] of RULES) out = out.replace(re, rep);
const pats = readFileSync(join(here, 'forbidden-strings.txt'), 'utf8').split('\n').map(l => l.trim()).filter(l => l && !l.startsWith('#'));
const hits = [];
out.split('\n').forEach((line, i) => { for (const p of pats) if (new RegExp(p).test(line)) { hits.push(`${i + 1}: ${p}`); break; } });
if (hits.length) throw new Error(`scrub: forbidden strings remain on the bench page:\n${hits.slice(0, 20).join('\n')}`);
return out;
}