igneum/CLAUDE.md
igneum-labs ff263245ac Igneum: design docs, Metal lottery-hash prototype, CUDA test pack, finality simulation
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 15:06:01 +00:00

27 KiB

Igneum

A GPU-mined layer 1 whose miners are also the ZK provers for its own zkEVM and for other chains. The founder's project, started 3 October 2026. Named Igneum (Latin: fiery, proven by fire) on 3 October 2026. Repo, Vercel project and Neon database are all "igneum".

Source of truth

The design document (Claude Doc "Igneum", formerly "GPU Prover Network") plus the public litepaper (https://claude.ai/code/artifact/edcf47f6-e918-48c7-95c3-b98e0d65583f) and the brand canvas (https://claude.ai/artifact/CPixnvctTKbrwBwWck3iFj): https://claude.ai/code/artifact/08fa9e06-9240-4964-96f4-76ff1d2f796c Read it with the docs tools before any design discussion. Decisions already taken live there (hard cap 4 billion halving every two years, 80/20 lottery/proving split, NO emission treasury, NO dev fund (removed 3 Oct 2026: the protocol carries no fee to any team, foundation or fund; priority fee 80/20 miners-and-provers/app, external jobs 90/10 provers/burn, 60% signalling kept only for parameters genesis leaves to miners), no stake, miner-only self-contained finality (NO Bitcoin anchoring), 1 block/s at launch, SP1 behind a swappable proving interface, Taiko as first proving customer, 30-day launch ramp).

The design in one paragraph

Leader election by a random-program GPU hash (RandomX idea rebuilt for GPUs, new kernel each ~1h epoch, era parameters drawn automatically every 6 months from chain state inside rules fixed at genesis, NO scheduled human releases; dataset grows on a genesis-fixed schedule and instruction families unlock by height from a genesis reserve (automatic schedule changes against fixed datapaths and human forks; against a chip that stores the dataset every drawn parameter is firmware, and the defence is the latency-shadow work of class v4 and the price per joule, per the Horizon algorithm lane, 6 October 2026); only writing new code is human, via miner signalling (the three thresholds, one sentence everywhere: 60% for a parameter, 90% for an upgrade, 95% with a floor height for a class change, the P2 mechanism), never required; warp-unit CPU-verifiable). Ordering by a GHOSTDAG BlockDAG forked from rusty-kaspa. Execution by a zkEVM. Every block ZK-proven by miners in chunks, aggregated 20 to 60 s behind the tip at launch (target under 10 s as provers improve). Finality is miner-only and self-contained: FINALITY RULE V2 (review round 2, 3 Oct 2026): vote weight = blue blocks per BLS vote key (in header) over a flat 30-day DAA window, no damping (the 2x cap was Sybil-void), dust threshold 100 blocks; every voter signs every 30-s checkpoint (VRF picks 8 aggregators only); lock = 2/3 of ALL 30-day weight (DECIDED 4 Oct 2026, O-3.15: the floor was raised from 56.7% of total to 2/3 of total, which makes the 2/3-of-active test implied; finality pauses whenever under 2/3 of the window is connected and signing, and the node reports it; the old floor 0.85 x 2/3 had been added after sim v2 showed the bare active denominator locks both sides of a 50/50 partition after 60 min; with the floor: 0 conflicting locks in every partition and eclipse scenario); equivocation evidence strips weight 30 days; fork choice = GHOSTDAG among tips through all certified checkpoints under Kaspa merge-depth 3,600 s; NO hidden-block n^2 penalty (removed, breaks DAG determinism); epoch seed = 10-min class-group VDF of a certified checkpoint, era draw = 1-h VDF; dataset = 256 MB RandomX-style cache, 8 dependent reads per item (not closed-form, not 64 MB); fees: base fee burned in full on both gas dimensions, priority fee 80/20 (miners and provers / app, attributed per call frame, unregistered share burned), external jobs 90/10 (provers / burn), no dev fund and no fee to any team. Headline: 10 days of 100% hashrate to reach 1/3 of weight, 20 days for 2/3; 51% never reaches 2/3 while honest miners stay. NO stake and NO other chain anywhere in consensus (Bitcoin anchoring was considered on 3 Oct 2026 and REJECTED by the founder: no reliance on Bitcoin). The same prover network sells proofs to rollups and bridges, priced in dollars, settled in the token. The lottery and the proving are kept separate on purpose (Aleo lesson).

The team, as agents

Each role from the design doc's build plan is an agent in .claude/agents/. Ask them by name.

  • cryptographer: lottery hash, chunked proving protocol, proof systems, finality on a DAG. Owns gates 1 and 3.
  • consensus-engineer: Rust, rusty-kaspa fork, GHOSTDAG, difficulty, P2P, the hash swap. Owns gate 2.
  • execution-engineer: Rust, Ethereum clients, zkEVM integration, SP1, the proving interface, external job market.
  • miner-community-lead: miner software, pools, launch ramp, what GPU miners will and will not accept. Owns gate 4. They review each other's work. A claim about another chain must cite the repo and file, or be labelled approximate.

Rules that apply to every agent and every file here

  • The founder's copy law: no em dashes, no two-beat antithesis, no aphorisms. Short sentences. Numbers in tables.
  • Figures from memory are labelled approximate. Figures from a source cite the source.
  • The project is Igneum. Never claim an ASIC gain, a proving time or a market size without a measurement or a citation.
  • Vendor source lives in vendor/ (git clones of rusty-kaspa, RandomX, SP1, decred dcrd, etc.). Read real code before describing it.
  • Nothing here is a token sale and nothing should become one.
  • Transactions are public, like Ethereum. Privacy features and shielded pools were considered and REJECTED by the founder on 3 October 2026. Do not add them.

Infrastructure (no URLs yet, by the founder's instruction)

  • GitHub: https://github.com/igneum-network/igneum (organisation igneum-network, created 3 Oct 2026; owners igneum-labs (the founder's igneum.network login, renamed 5 October 2026; the noreply id 337424239 is unchanged) and the second owner login; private, branch master). Commit as igneum-labs 337424239+igneum-labs@users.noreply.github.com (standing rule 3 Oct 2026: the organisation owner is never publicly visible, so no personal name or email in the history; the commits before the rename carry the login's earlier spelling and the fresh-repository step rewrites them, tools/repo/fresh-repo.sh). Push only when the founder asks. gh on this Mac still stores the token under the login's pre-rename spelling: that name is in ~/.config/igneum/gh-user (never in the repository; gh auth status lists it), and the scripts that need it read that file. This checkout's .git/config (shared by every worktree) resets credential.helper and then adds one helper that returns username igneum-labs with that token, so git pushes from here work whichever gh account is active. Before any gh call: gh auth status must show the stored entry as the ACTIVE account (gh auth switch --user $(cat ~/.config/igneum/gh-user) if not); the second owner login on this Mac belongs to other projects and has no access to this repository.
  • Vercel project: igneum in the other business's team, because Vercel refuses the personal account as a scope. Move it to its own team when the venture is named. For the site, explorer and job-market API later.
  • Neon database: igneum, id soft-voice-31914738, London (aws-eu-west-2), Postgres 17. Connection string in ~/.config/igneum/env, never in the repo.

Domains (purchased by the founder, 3 October 2026, registrar with "Full Protection"; nothing pointed yet)

igneum.net, igneum.io, igneum.network, igneum.info, igneum.store, igneum.online, igneum.app, igneum.co.uk, igneum.xyz. Also bought 3 Oct 2026 (the founder: "bought all the other domains"): igneum.org and igneum.com, so the full set is held. Applied 3 Oct 2026: all 15 Igneum domains at GoDaddy (also .art, .email, .pro, .shop, .vip) on Vercel nameservers (ns1/ns2.vercel-dns.com) and attached to the Vercel project igneum: igneum.network is the primary site, every other domain 308-redirects to it. igneum.com is still on Afternic nameservers (purchase in transit), attach when it arrives. Site source: site/ (static). Since the evening of 3 Oct 2026 the live site is the igneum project in the igneum team (igneum-labs login, ~/.config/igneum/vercel), deployed by the GitHub integration on every push to master; the other business's project of the same name only holds the 13 redirect domains. Link, env and hand-deploy commands: packaging/README-ship.md (checked 4 Oct 2026).

Browser profile (standing rule, 3 October 2026)

Every Igneum task in Claude in Chrome runs in the igneum.network Chrome profile. The founder also has profiles for other brands. Confirm the active profile before acting; if it is the wrong one, switch or stop and say so. Never carry Igneum sign-ins, posts or purchases through another brand's profile.

Running agents on this Mac (standing rule, 4 October 2026; builds moved to igneum-build-1 on 6 October 2026)

  • Code and documents in parallel; the Mac's own BUILDS and MEASUREMENTS one at a time through tools/lock/with-lock.sh build|measure|run <cmd> (measure blocks builds too: hash rate, latency in ms, power; run is for functional runs such as test networks, attack harnesses and simulators whose outputs are counts, locks, forks or seconds, and lets builds continue; use the MAIN checkout's script, /Users/joshm/Projects/igneum/tools/lock/with-lock.sh, from any worktree). A number taken while another build or simulation ran is not a number. ~/.config/igneum/build-slots (1 to 3) caps how many Mac builds run at once.
  • BUILDS GO TO THE BOX (standing rule, 6 October 2026, main's decision after the measurements in docs/plans/build-server.md): every Linux and Windows cargo build and every Linux test suite from every agent runs on igneum-build-1 (Hetzner AX162, 96 threads, 128 GB, ssh -i ~/.ssh/igneum_ed25519 build@188.40.146.49) through tools/build-remote.sh [-- cargo args] and tools/cross-remote.sh from the crate directory of the agent's own worktree. Measured 6 October: clean node build 1 min 27 s (Mac 12 to 18 min), incremental 7 s (Mac 2 to 15 min), Windows cross 1 min 44 s (Mac 4 min 49 s to 12 min 28 s). The box has its own slot files (/srv/builds/_locks/build-<k>, count in /srv/builds/_locks/slots, 1 today); a remote build takes one of those, never a Mac slot. Sources travel as HEAD through the bare mirrors /srv/igneum.git and /srv/igneum-node.git plus an rsync overlay of uncommitted changes (re-stamped); /srv/builds/<worktree> mirrors the worktree root; artefacts come back into <crate>/target-remote/, never target/ (they are x86_64 Linux and Windows binaries). Every run writes one line to /srv/builds/_log/builds.jsonl (the worker dashboard reads it); IGNEUM_AGENT=<name> tags it. The PCs keep only jobs that need their GPUs or the Windows runtime (measurements, Windows test suites, installer smoke runs: node tools/build-job.mjs run --target ae432dc7|1ccfe586 ..., PC 1 = ae432dc7, PC 2 = 1ccfe586). The Mac keeps macOS binaries, the DMG and Metal tests, under the build lock. THE MAC RUNS NOTHING THE NETWORK DEPENDS ON (the founder, 6 October 2026, evening): after the 0.3.15 cut the two devnet hands, node 1 and the observer (its node and tools/observer), run on the box as systemd units (igneum-node1, igneum-observer-node, igneum-observer; docs/plans/hands-on-build-1.md; infra/build-server/hands/), node 1's p2p on 26611 with --externalip, every RPC on loopback, the observer's Neon string in /srv/observer/env (mode 600, copied from the Mac, never in the repo); that file is the only secret the box holds. The Devnet 2 seed, when it starts, gets its own unit the same way. Setup and re-provision: infra/build-server/run-from-mac.sh <ip> (idempotent); the rustc pin is RUST_TOOLCHAIN in infra/build-server/provision.sh (1.99.0; there is no rust-toolchain file, add one) and build-remote.sh refuses a version mismatch. Nobody deletes another worktree's target dir on the box. Windows exes are reproducible (-Wl,--no-insert-timestamp in cross-remote.sh, the Mac's cross-build.sh and the PC job alike); a node binary whose strings lack its commit fails tools/ci/commit-string-check.sh (the empty-commit class, 6 October 2026: kaspa-build-info embeds the hash only from a .git directory on a branch and never re-runs once empty, so every Mac worktree build and every PC job build had shipped without it; build-remote.sh, cross-remote.sh, cross-build.sh and the PC job now carry the two-step: a branch or minimal .git, and cargo clean --release -p kaspa-build-info on a new commit).
  • Every agent works in its own git worktree (git worktree add ../igneum-wt-<name>), never the shared checkout, and stages only its own files. Mac builds (macOS binaries only): nice -n 19, at most 4 cargo jobs.
  • Never launch /Applications/Google Chrome.app headless (it blocks the owner's Chrome); use the built-in browser pane.
  • Keep the Mac on mains with the 140 W charger; on 4 October it hibernated at 1% battery and took node 1 and the observer down.
  • A source tree copied to another machine (rsync, zip, tar, scp) is re-stamped with touch before anything builds it, because cargo rebuilds by mtime and the far side keeps its target dir (the stale-build class: shard run 2 on 4 October, the 0.3.6 PC build on 5 October). tools/ci/copied-sources-check.sh fails CI on any script that copies and builds without it. When a bug is fixed, fix its CLASS: grep for every other script with the same shape the same day, and add a check that fails when the shape comes back (the founder, 5 October 2026: "we should not be having same bugs repeated").
  • A watcher or gate is trusted only after it has been shown to fire on one known-finished and one known-failed case (4 October 2026: three job watchers waited for a line the closing report never starts with, and a failed shard run reported exit 0; the failure was found by hand half an hour later). Every job's outcome and its error lines are read the moment it ends, done or not.

Every number carries its consequences (standing rule, 5 October 2026, 21:30 UTC)

The founder: "this question and answer should have not needed to be asked ... so that suggestions like this get made without me" (the 12 GB mine-and-prove question, which followed from the 15.6 GB measurement and should have been raised by the agent that measured it). Rule: an agent that measures or reports a number also states, in the same report, what the number means for each user tier and what it will do about it, before anyone asks. The tiers: a home miner with one 8 GB card, one 12 GB card, one 16 GB card, one 24 or 32 GB card; a rig; a pool user; each on Windows, Linux and macOS; each on NVIDIA, AMD and Apple (Intel when it exists). A report that says "peak 15.6 GB" without "so 12 GB cards cannot do both; here is the profile that fits them, measuring now" is incomplete and goes back. The same for hash rates (per watt and per pound for the tiers), times (what deadline it fits), sizes (what disk or memory it needs), and prices. A standing reviewer agent reads every status file, bench-log entry and plan for missed consequences and opens the work; the coordinator does not wait for the founder to notice.

A job never quits or restarts the installed app it did not start (standing rule, 5 October 2026, 23:05 UTC)

Ember Tune's PC 1 playbook started a second engine, that engine's own updater saw itself as 0.3.9 and launched the per-user installer, and the installer's stop step POSTed /api/quit to the installed app, taking PC 1 off the network from 22:31Z (141 MH/s gone, the 0.3.11 Windows build blocked) with nobody awake to relaunch (corrected 6 October 2026 from the collected log; the playbook's own quit never fired and pointed at its scratch engine; fixed at e600e63: a second engine never runs the updater). Rule: a test engine started by a job runs on its own port and data dir with its own URL file, and a job may quit, pause, resume or restart only an engine it started itself (the URL it created); the installed app is touched only through the signed restart and update-now job kinds, and a job that needs the installed app's miners out of the way uses the runner's --stop-miners (the runner stops them before the script and restarts them on any exit), never /api/pause or /api/resume from the script, not even with a finally block (ruling 6 October 2026: a script that dies before its finally leaves the box paused unattended). tools/ci carries a check (playbook-quit-check) that fails a playbook which reads %LOCALAPPDATA%\igneum\app\app.url or ~/Library/Application Support/Igneum/app/app.url and sends quit, pause or resume to it; the reviewer's row C35 is the record.

Devnet 2 gate and activation rules (standing rule, 6 October 2026, 16:4x UTC)

The founder's ruling after the DAA 198,000 incident (a fixed-height activation crossed while the fleet was still updating: a two-sided chain, a 229-block reorg, execution reset to genesis on every node, proving at zero for an hour): releases stay hourly; what changes is where they land first.

  • Devnet 2 is the rented fleet as its own staging chain (own genesis and network id, refused by live peers at the handshake). Every release, activation and tuning kit crosses Devnet 2 through tools/fleet/devnet2-gate.sh (PASS = zero rejected blocks across the activation, no reorg over depth 3, exec roots agreeing on every box, a segment record paid, every node on the new version) before the live devnet or any of the founder's machines sees it. The shipper does not build the live object before the PASS line.

  • No fixed-height activation on the live devnet. A consensus change flips when 95 percent of mining weight over a window signals the new object, with a floor height as the backstop; the class v4 cut is the first to carry it (status file gates P1 and P2).

  • No "clean day" waits (the founder, 6 October 2026, 19:3x UK: "we dont need a clean day for anything this is just delaying things"): a cut's only gate is the Devnet 2 crossing (the class v4 cut's gate is its P1 rehearsal on the fleet chain); digest moves are bundled into one cut (0.3.15 = class v4 + the fourteenth field), miners first, hands last.

  • A deep reorg never resets execution; a snapshot a node cannot read fails loudly; the p2p snapshot path refuses a snapshot below the node's tip or the restart; a hands script never pgreps its own command line.

  • Main checks an agent's number against the log or the chain before relaying it to the founder, or labels it unverified.

  • Never remove more than 10 percent of the live devnet's 30-day vote weight in any hour (Horizon finality lane, 6 October 2026: the class v4 rehearsal took 13 fleet keys off the live chain at 18:27Z; with seven earlier leavers that was 42.7 percent of the voter table frozen at the last lock, and rule v3 holds the pause for a full window; under v3 a sudden departure of a third of weight is a 30-day pause on mainnet). Experiments that borrow live miners do it in slices with an hour between. The protocol fix is the signed LEAVE item (0.3.16).

  • Every NODE cut's Devnet 2 gate includes a MINING new node beside an old node on the live file for ten minutes (the old node accepting the new node's blocks, the hub's reject count unchanged), and a new node restarted mid-window re-syncing from an old peer. Found 6 October 2026, 20:5x UK: 0.3.15's node stamped the class v4 signal bit into the block version (1026) on the thirteen-field file; every 0.3.14 node rejected it; the digest-compat test passed because the handshake peers while the block version splits; the canary caught it before any live box moved.

  • Standing fleet (the founder, 6 October 2026, 20:0x UK: "cant we keep rented cards up longer"): 16 live-devnet boxes and 6 Devnet 2 boxes are kept up permanently and re-rented on host death; only benchmark and wave boxes are one-shot; a standing box never leaves the live devnet for an experiment (the class v4 rehearsal took the 15 prover boxes and paused live finality at 18:42Z; experiments use wave boxes only). The Mac runs nothing the network depends on: node 1 and the observer move to igneum-build-1 as systemd units (docs/plans/hands-on-build-1.md).

  • Secrets on igneum-build-1: none that sign releases, move funds or reach the hands. Exception recorded 6 October 2026: Discord webhook URLs at /srv/discord-hooks/env (mode 600, rotatable in one click) for tools/community/discord-hooks.mjs.

Shared scratchpad and lane ownership (standing rules, 7 October 2026, 08:2x UK)

  • A lane never removes a directory under the shared scratchpad; it removes only files it wrote inside one. Each lane keeps its scratch under its own prefix (bs-<name> for the build-server lane, r03xx-ship for the shipper, and so on). At 07:23 and 07:56 UK the build-server lane removed r0317 and r0318 as superseded and the shipper's running 0.3.18 chain lost its log and staging copy mid-build.
  • Every wait keys on its own run's marker, never on a generic line in a shared log (the ten-member pool window mis-fired at 07:44 UK on the 0.3.17 cases' end marker). A presence check never shares a shell with the command it checks (the fleet's installer answered "already running" to its own command line and left pool-1's node down seven minutes).
  • A supervised node restart read back by a new lock line from the hub is not a weight removal under the 10 percent rule; a key that stops voting is. The fleet's table gate reads the folded certificate weight over the frozen table (mean of the last five checkpoints), not the lock-moment share.

Nothing heavy on the Mac (standing rule, 7 October 2026, 10:5x UK)

The Mac crashed and rebooted under agent load (about twenty lanes, local cargo tests and guest builds, several headless chromiums for captures and Playwright suites at once). The founder: "stop building on it unless its 100% necessary to build on a mac". Rule: the only Mac builds are the shipper's macOS binaries and the DMG, one at a time under the build lock. No cargo build or test on the Mac for any other lane; no guest builds, z3 or census runs; no Playwright suites; captures use one headless chromium at a time and never from several lanes at once. Every Linux and Windows build, every test suite and every benchmark runs on igneum-build-1 (tools/build-remote.sh) or as a PC job. The pre-push gate script stays (checks, not a build). Main keeps the number of concurrently running lanes near ten, the founder's waiting items first.

CI red is stop-the-line (standing rule, 6 October 2026, 22:0x UK)

  • Whoever's merge turns master or a release-* branch red owns the fix inside 15 minutes or reverts the merge; the red watcher posts every failed run to the hidden updates channel and to /srv/ci-red/red.jsonl on the box (tools/ci/red-watch.mjs); the box's own red builds land in the same file with a class (remote-run.sh pre-flight, kept run logs) and the 09:00 UK digest counts them per class with each class's guard.
  • The pre-push gate is the same script CI runs: tools/ci/pre-push.sh (installed by tools/ci/install-hooks.sh; --hook before a push to master or release-*, --ci in the workflow). A check is added there, never only in ci.yml. On a feature branch the hook runs the light gate: the two structural checks plus the two never-push classes, the no-secrets check and the identity grep (7 October 2026).
  • After every push, the pushing lane reads the conclusion when it lands (gh run list --branch <branch> --limit 1; gh run view <id> --log-failed on a red) and owns a red before the next push; pushes are never held for it. A red on any branch is reported to main the moment it is seen. The red watcher (.github/workflows/ci-red.yml, from master, every branch) posts each failed run with its branch, commit, red check and pushing author. Record: 7 October 2026, 11:26 to 12:47 UK, eight red runs on ca3-v4-node over three gate summaries carrying a 64-hex key, read by nobody; 31 runs queued on one runner at 13:15 UK, so igneum-build-2 joined the pool and docs-only pushes skip the compile jobs.
  • A code push (anything outside docs/, site/ and *.md) goes out only after that exact commit's crate suite is green on a build box (the suite's RESULT line in the push's own notes or the commit message); a test build the box never ran is not pushed. Record: 7 October 2026, 14:10 to 14:13 UK, four red runs in three minutes (a test-build compile error on ca3-v4-amend, the hidden-console check on miner-reliability, the installer's inputs pin on release-0.3.20), each a push ahead of its own box result, each emailed to the founder.
  • Master takes only what CI has already passed (7 October 2026, 17:2x UK): a merge lands only when the branch's own ci run is green on the exact commit being merged, read from the runs API (tools/ci/ci-state.mjs), never the local stamp alone; tools/ci/merge-to-master.sh pushes the branch for a run when there is none, waits for a queued one printing the clock, refuses a red one and refuses any merge onto a red master except the declared fix (--fixes-master); the pre-push hook refuses a push to master whose commit (or merge parent) has no green run; a feature-branch push prints the branch's previous red first. GitHub's branch protection is unavailable on the free plan for a private repository (the API answers 403), so the two scripts are the enforcement.
  • Research and operations documents live outside the public export list: name them in tools/ci/export-exclude.txt (read by the identity check and by the mirror's sync.sh). What stays in the list is read by the public and must pass the identity grep.
  • A path Windows cannot hold (colon, trailing dot or space, reserved name, over 240 characters) never enters a commit: the pre-commit hook runs tools/ci/windows-paths-check.sh --staged.
  • Record: docs/analysis/ci-failures-2026-10-06.md (168 non-green runs in three days classified; 126 on master; all but two classes were tree checks that the gate now runs locally first).

A rule row closes only with its check (standing rule, 6 October 2026, 18:4x UK)

The founder, after the pgrep self-match hit twice in one day (the shipper's hands script at lunchtime, the fleet's wave script at 17:1xZ: a pgrep -f "<pattern>" whose literal sat in the calling shell's own command line, so the check always passed and no node ever started): "again wasted time". Rules:

  • A bug class found today gets its tools/ci check merged on master the same hour, or the rule row stays OPEN and main says so. A rule row without a check is not closed.
  • Box operations (ssh to a rented box, install a payload, start a node, wait for sync, read height, peers and exec tip, start a miner or prover) live in ONE shared, tested library (tools/fleet/lib/), exercised against a Devnet 2 box by a test; agents call it and never write their own copy in bash or PowerShell.
  • A watcher or collector verifies the chain-side fact (height, peers, exec tip, paid records), never a reported rate or a process name.
  • pgrep -f / pkill -f / ps | grep with a literal pattern is banned in scripts; use the bracket form [i]gneumd, -x on the binary name, or a pid file (pkill -F, tools/fleet/fleet-bg.sh). Kill by exact command line or pid file, never by a name: at 22:09 UK on 6 October a Mac-side pkill -f <log file name> matched nothing (a redirect is not on the command line) and the roll-everything script wiped a box it had been told to hold (CI check and gate: tools/ci/kill-by-name-check.sh, which also flags a file-name shape under pgrep/pkill).