Commit graph

57 commits

Author SHA1 Message Date
igneum-labs
e1c555568f CI and boxes: the simulators job runs on master and release-* pushes and pull requests into them only (a feature-branch code push runs the igneum-pow tests alone; tools/ci/sims-branch-check.sh); the box lock self-tests run in parallel in one ssh; build-2 and build-3 join the runner pool bounded to 32 cores; the 0.3.20 first-wave script (seeds, hands, RPC-filter lift; dry run by default)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-07 13:46:42 +00:00
igneum-labs
935c4b61d6 Merge remote-tracking branch 'origin/master' into build-server 2026-10-07 13:33:24 +00:00
igneum-labs
6f5787ed71 Build boxes: the measure file is retired; a pinned measurement leases its cores only (lease.sh cores), a whole-box quiet measurement is its own class (refused beside a slot or a lease, 20-minute cap, named owner), bounded suites never take it, every run keeps off leased cores, stopped holders are reaped after 5 minutes by every keeper, every waiter has a label file; the box-side self-tests in the gate; provision installs the lease tool and the headless Chromium libraries
Main, 7 October 2026, 15:07 UK: one global exclusive measure flock across unrelated measurements stalled build-1 at load 120 with
free slots (a stopped probe held it 5.5 h; an exclusive waiter queued every new shared taker) and build-2 behind a one-core VDF
bench. lease.sh (installed at /srv/builds/_bin/lease by provision.sh and by hand on both boxes) takes one flock per core for a
pinned measurement and the quiet file for a whole-box one; remote-run.sh takes quiet shared only for unbounded runs, excludes
leased cores from its set, and its keeper refreshes the holder file and calls lease reap (a STOPPED holder of a lease, quiet or a
slot for 5 minutes is killed with a line in _log/reaped.log). Keepers close the lock descriptors they inherit (an orphaned sleep
held a slot and the worktree lock 20 s past the release; the slot self-test had rotted on that since the worktree lock landed).
tools/ci/box-locks-check.sh runs lease.sh --self-test and remote-run.sh --self-test-slots on build-1. provision.sh also carries
the 16 libraries headless Chromium needs (installed by hand on both boxes at 14:5x UK) and a headless self-test step.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-07 13:30:40 +00:00
igneum-labs
0deaa5489a CI queue: a second self-hosted runner (igneum-build-2 joins the pool label), docs-only pushes skip the compile jobs, the red watcher pinned to the box that posts
31 runs were queued on igneum-build-1's one runner at 13:15 UK on 7 October 2026 and nothing had concluded since 13:03Z, so no lane could read a conclusion.
- ci.yml: a `changes` job (ubuntu-latest) classifies the push with tools/ci/docs-only-check.sh (docs/, site/, *.md only = code=false; a new branch, a pull request, a force push or an API error = code=true); pow and sims need it and run only on code=true. The site job is unchanged on ubuntu-latest for every push. The classifier's self-test is in the gate.
- provision.sh and runner/register.sh: `--host <ip>` registers another box, forwarding BOX_HOSTNAME, RUNNER_NAME, RUNNER_LABELS, RUNNER_CPUS and RUNNER_JOBS (plain words only); RUNNER_CPUS writes AllowedCPUs into the service drop-in beside Nice=10, so igneum-build-2's runner is bounded like a suite (32 cores). The pool label is igneum-build-1 (both boxes carry it); ci-red marks the box with the record file and the poster, the default labels carry it, and igneum-build-1 got it through the runners API today.
- ci-red.yml runs on the ci-red label, so the red line always lands where the poster reads it.
- CLAUDE.md: the rule reads "read the conclusion when it lands, own a red before the next push"; pushes are never held.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-07 13:20:18 +00:00
igneum-labs
caff656593 Build boxes: the box probe carries its own ssh options (bash 3.2 under set -u refused the unset BS_SSH_OPTS array before bs_host built it; every unpinned route on the Mac died, the pool lane 7 Oct 2026); the router check runs the ssh path under /bin/bash
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-07 13:16:39 +00:00
igneum-labs
b04c4b3ac9 Build boxes: the class router is a preference with spill-over (a held or overloaded box hands the job to the other one); build-2 gets a third slot and every run there is bounded on its own 32-core band; the spill decision in the first route line, the slot label and the JSONL row
the project lead, 7 October 2026 15:02 UK: build-1 at load 139 / 114 / 90 with both slots held and a 1 h 40 min queue while build-2 read 4.5 with
free slots, because the class router pinned each class to its box. Now lib.sh bs_route_spill reads the preferred box (free slots,
1-minute load) with one ssh and hands the job to the other box when the preferred one has no free slot or sits above load 64 and the
other qualifies; neither qualifying queues on the class's own box. The decision travels as BR_ROUTE_* into the JSONL "route" object
for the dashboard. build-2's slots file reads 3; everything on box 2 runs at nice 10 / 32 cores / -j 32, and a bounded run takes
the band its slot owns so three never share a core. Self-test tools/ci/route-spill-check.sh (thirteen cases) in the gate.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-07 13:08:19 +00:00
igneum-labs
97255a4e8f Build boxes: the slot holder keeps its own line (a keeper, with its self-test in the gate); an explicit --jobs is clamped for bounded classes; one git remote per box; the host-file double suffix
The dashboard lane, 7 October 2026 10:39Z: both slots of build-1 flock-held and EMPTY while two suites ran. Cause: a run from a
worktree without last night's append-mode fix opens a busy sibling's slot file with > on every probe. The holder now keeps its own
line: a keeper re-writes it within BR_KEEP_S (20 s) whenever the file is empty, until release; remote-run.sh --self-test-keeper
(in the gate) truncates a held line and sees it return, and sees nothing written after release; live on build-1 at 11:19Z (the
line came back in 25 s). The first version deadlocked the runner's bare wait with the keeper (build-2's first run hung 15 min
after its test passed): the keeper stops before the wait. The two running suites' -j 90 came from explicit --jobs 90: a bounded
class now clamps it to its cap with a log line (pass --priority gate for the full set). run-from-mac.sh --box N: the host file
was suffixed twice (build-server-2-2) and every box's mirror would have shared one remote name; one remote per box (build-N).
build-2's first green run: a suite at nice 10 on 32 cores, jobs 32, 986 s cold.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-07 11:22:12 +00:00
igneum-labs
74eb671c65 Merge remote-tracking branch 'origin/workers-dash-2'
# Conflicts:
#	tools/workers/page/workers.html
2026-10-07 10:43:34 +00:00
igneum-labs
9a6f2606b8 Worker dashboard: one server section per box, per-box live feeds, installer and pusher take build-2 and build-3
The build-server agent has igneum-build-2 and -3 on order (suites and benches; proving and the fast-time nodes). The
installer takes a host argument (N reads ~/.config/igneum/build-server-N, or build@<ip>); the pusher drops the Mac and
PC facts on every box it has a host file for, pulls each box's file and publishes boxes[] (box stays the first for the
old shape); the page draws one server section and one crew card per box, reads every box's Caddy feed in parallel
(build, build-2, build-3.igneum.network) with the edge copy filling any box that does not answer, and merges every
box's builds into the lanes, the timeline and the analytics. Nothing changes for build-1 until the host files exist.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-07 10:37:33 +00:00
igneum-labs
8b0bfb8e39 run-from-mac.sh --box N: the box's dashboard feed name build-N.igneum.network travels to provision as WORKERS_HOST
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-07 10:35:45 +00:00
igneum-labs
b6e5dffa32 Build boxes: one host file per box and a route by class (suites and benches to build-2, proving to build-3, the rest to build-1); the no-mining rule in a box README and as a guard in the capacity layer
Main's order of 7 October 2026 (igneum-build-2, AX162-1, and igneum-build-3, AX102-1, on order). lib.sh: bs_box_file N and
bs_route <class>; a class whose box has no host file yet falls back to box 1 and says so. run-from-mac.sh --box N <ip> provisions
igneum-build-N and writes build-server-N. tools/build-remote.sh --box N overrides the route; --priority gate always runs on box 1;
the proving crate routes to box 3. README.md: the kind map and the project lead's rule, no mining on any Hetzner box, ever (nodes, builds, tests,
benchmarks and CPU proving only; the pool's fast-time network mines on rented GPU pods, never on build-3). capacity/run.sh refuses a
job that would start igneum-miner mine or a GPU worker, whatever SEQUENCE says.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-07 10:34:16 +00:00
igneum-labs
69034dc071 Build box scheduling: suites and benches at nice 10 on 32 cores with -j 32; a gate kind at nice 0 on the full set ahead of queued suites; kind, nice and cores on the slot label and the JSONL line; the default-class CI check
Main's order of 7 October 2026 after a load of 190 on 96 threads (a release join bench and the 0.3.19 app gate starving each
other, 'builds' of 16 minutes). tools/build-remote.sh resolves a class from the cargo subcommand and --priority: test and bench are
the bounded class (nice 10, the last 32 cores, -j 32) unless --priority gate (nice 0, the full set, the box's own jobs rule);
builds and checks are unchanged. remote-run.sh applies renice and taskset to the command's subshell, caps the jobs, lets a queued
gate (gate-pending-<pid>) take the next slot ahead of suites and benches, and prints nice and cores in the RESULT line and the
JSONL line (nice, cores, priority). The slot label carries '; kind=<k> nice=<n> cores=<c>' before '; agent=', so the dashboard's
job card shows why a job is slow. --plan prints the resolved class without the box; tools/ci/build-kind-default-check.sh (in the
gate) holds the five shapes. Smoke on the box: a suite at jobs=32 nice=10 cores=32, a gate at nice=0 cores=96.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-07 10:29:26 +00:00
igneum-labs
210084b0e5 build server: the remote checkout's clean spares a lane's scratch (AP-H1, the lost-scratch class)
remote-run.sh checkout_tree ran `git clean -fd` on the box mirror before every build from any agent, so the attack rows
lost attack-f3/, attack-f1-venv/ and tools/attack/*/target to each other's builds (7 October 2026, 09:2x UK). The clean now
also spares the fixed prefixes attack-*, scratch-*, target-attack-*, .build-remote.log and every glob in the mirror-local
.igneum-scratch-spare (one per line, # comments, the file itself spared), keeps the target and stamp excludes and still runs
without -x. The clean-tree test asks `git clean -nd` with the same excludes instead of filtering the status list, so a spared
dir is not "not clean". --self-test: a fixed-prefix dir at the root and nested, a declared dir and the spare file survive, an
undeclared dir is removed. tools/ci/scratch-spare-check.sh in the pre-push gate fails when the clean line loses the spare
arguments, spare_args stops reading the file, a fixed prefix goes, or -x appears. docs/plans/build-server.md R4a says how a
lane declares its prefix.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-07 08:24:07 +00:00
igneum-labs
02d7f5ab81 Observer sync follows GitHub: the deploy-key probe captured before grep (ssh -T exits 1 under pipefail); plan 5c done
the project lead added the read-only deploy key on 7 October 2026 (SHA256:51ice3W8...). The sync still said 'mirror' because ssh -T to GitHub
exits 1 after its greeting and observer-sync.sh runs under pipefail, so su ... | grep -q reported failure although grep had
matched (the same line by hand, without pipefail, said authenticated; shown under the unit's environment with systemd-run -v).
The probe's output is captured first. First github pass 07:30:54 UTC: the clone moved from the mirror's d79f4a6 to origin/master
8b878ba4, the observer restarted on it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-07 07:31:42 +00:00
igneum-labs
3cc5e5c2f0 Hands mover: on 0.3.18 trees the restart read-back takes powEngine and the blockrate object from igneum_getNodeInfo; a stub answer stops the sequence
The shipper's read-back for 0.3.18 (7 October 2026): igneum_getNodeInfo exists again and must answer powEngine igneum-pow (a stub
is a FAIL) with a blockrate object, which the mover prints; a tree before 0.3.18 answers -32601 and the engine is still read from
the binary's igneum-pow source paths. The parser is checked against the three answer shapes.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-07 06:25:12 +00:00
igneum-labs
fd4785d2bc lib.sh: bs_pin gives an empty pin for a tree without rust-toolchain.toml (a failed sed under pipefail ended the caller silently)
The b3c228fa builds under the 0.3.16 app tree 5d118f58 (no rust-toolchain.toml yet) died right after the pairing line with no
message: sed on the missing file failed, pipefail carried its status into the assignment, set -e ended the script. A guard and a
tolerant pipeline; checked alive against a tree without the file.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-07 03:44:26 +00:00
igneum-labs
db6475def5 Build tools: whole-body blocks (the edited-while-running class, with its check), the igneum-pow pairing line, move-hand.sh restart with its readbacks
Three classes from the 0.3.17 night. (1) bash reads a script incrementally: tools/build-remote.sh was edited while a four-minute remote
build ran, the running copy continued at shifted bytes and died with a syntax error after the build had succeeded on the box; the
four long-running tools (build-remote, cross-remote, workers-remote, move-hand) now keep their body in one brace block ending in exit,
parsed whole before a line runs; tools/ci/whole-body-check.sh (in the gate, self-test with a block-less copy) holds the shape.
(2) A fork build pairs with the igneum-pow of the igneum worktree it sits in: a fork at 12153428 under a master worktree failed in
kaspa-pow four minutes in (no chain_program_shadow; master's igneum-pow predates release-0.3.17's); build-remote.sh says the
pairing on its first line ('pairs with igneum 6f8d7a7e (detached): igneum-pow 0.2.0') and the JSONL line carries pairs_with.
The first version of that line used '[ -n ... ] && echo' inside an assignment's $( ) and set -e ended the script on the false
status; fixed. (3) move-hand.sh restart <hand> [--digest <hex>] [--go]: after binary installed a release, restart ONE unit and read
it back (first exec line, commit string in the running binary, digest against the wanted one, igneum_getNodeInfo powEngine over the
node's loopback EVM RPC); the digest readers tolerate a missing line.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-07 03:12:51 +00:00
igneum-labs
3720c40bce glibc ceilings per artefact class: hive and rig 2.31, seed and linux 2.35, native unchecked; proven in ubuntu:20.04 and 22.04 on the box
Main's order of 7 October 2026 after RunPod's Ubuntu 22.04 canaries (glibc 2.35) refused the box's GLIBC_2.38 binaries and HiveOS
turned out Ubuntu 20.04 based (2.31). The table lives once, in tools/ci/glibc-ceiling-check.sh (--class, --ceiling-of; self-test
covers the table, an unknown class and a 2.34 need against hive); tools/build-remote.sh --ship hive|rig|seed|linux (default seed)
and tools/workers-remote.sh --class (default rig) build with zig at the class's glibc and check against it. provision.sh installs
docker.io (user build in the docker group) for the proof. Proof: fork 3bfe346f at class hive, igneumd and igneum-miner need
GLIBC_2.30; the workers at class rig need GLIBC_2.17; all four run in ubuntu:20.04 (ldd 2.31) and ubuntu:22.04 (ldd 2.35) and
print their version or usage lines (the OpenCL worker its own no-libOpenCL message, the binary running in a GPU-less container).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-07 00:35:18 +00:00
igneum-labs
01aa9fae83 Deploy key: the plan's section 5c (the project lead's four steps and the public half) that 9215d624 named but did not carry; observer-sync.sh runs git as build
The previous commit's plan edit aborted on a changed anchor, so section 5c was missing; written now with the public half
(ssh-ed25519 ... igneum-build-1 observer read-only) and the CI-runner row closed. observer-sync.sh ran git rev-parse as root
against the build-owned clone (safe.directory refused it, 'up to date at' with no commit); every git call runs as build now.
Verified on the box: one sync pass prints 'source: mirror (the deploy key is not accepted by GitHub yet ...)' and the commit.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-06 23:49:20 +00:00
igneum-labs
9215d624d2 Observer clone: a read-only deploy key made on the box, GitHub preferred over the mirror once accepted; the project lead's steps in the plan
Main's order of 7 October 2026. install-hands.sh creates /srv/observer/.ssh/deploy_igneum (ed25519, user build, mode 600; the private
half never leaves the box and nothing prints it) and the ssh alias github-igneum-observer; observer-sync.sh tests the key with
ssh -T on every pass, pulls from GitHub when it is accepted and from the mirror otherwise, saying which. docs/plans/build-server.md
5c: the four steps for the project lead (print the public half, Settings > Deploy keys > Add, read-only, start one sync pass) and the public
half itself. Verified on the box: key created, alias written, one sync pass reads 'source: mirror (the deploy key is not accepted by
GitHub yet)'. The CI-runner row is closed (the box-work agent's runner service).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-06 23:47:10 +00:00
igneum-labs
49ca718c9c rust-toolchain.toml: one pin for every side (1.99.0, the two cross targets); the mismatch refusal reads it
Main's order of 7 October 2026. The repo root carries rust-toolchain.toml (channel 1.99.0, targets x86_64-pc-windows-gnu and
x86_64-unknown-linux-gnu); rustup resolves the nearest file walking up from the crate, so the fork worktrees under vendor/ are
covered, and the fork's master carries its own copy (vendor/igneum-node 37f1206b). lib.sh bs_toolchain_check reads the pin
and refuses a build when the pin, the Mac's rustc as resolved in the crate dir, or the box's rustc differ (the message says
the three commands that align them); run-from-mac.sh passes the pin to provision.sh as RUST_TOOLCHAIN. The 1.99.0 toolchain
with both targets is installed on the Mac so no agent's build stalls on rustup's auto-install. Verified: the Mac resolves
1.99.0 in a fork worktree, the box runs 1.99.0, the check prints 'pinned 1.99.0 by rust-toolchain.toml'.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-06 23:44:20 +00:00
igneum-labs
7089aa161f Build server: zig and cargo-zigbuild on the box; build-remote.sh --ship builds glibc 2.36 Linux artefacts for seeds and HiveOS; the glibc ceiling check
Main's order of 7 October 2026 after a seed took 14 restarts and three minutes down on a glibc 2.39 binary. provision.sh:
step_zig (zig 0.17.0 from ziglang.org, sha256 from the official download index) and cargo-zigbuild 0.23.4 in the cargo tools.
tools/build-remote.sh --ship [--glibc 2.36]: cargo zigbuild --target x86_64-unknown-linux-gnu.2.36 with zig as the C/C++
toolchain (the Mac's infra/cross/build-linux.sh recipe), artefacts from the target-triple dir, each checked by
tools/ci/glibc-ceiling-check.sh (need at most the ceiling; self-test fires on 2.38 against 2.36, passes 2.34 and 2.36;
--symbols reads a saved objdump -T text so CI needs no ELF tools). tools/workers-remote.sh builds the two GPU workers with
zig at 2.36 by default (GLIBC=native for clang). Proof on the box: fork 3bfe346f igneumd needs GLIBC_2.34 (47,023,120 B,
sha256 345dfb95...), igneum-miner GLIBC_2.34 (9,248,808 B, d09dc27b...), 3 min 17 s cold through zig; the workers at 2.36.
Rule: anything that ships to a seed or a HiveOS rig is built with --ship; a plain build (glibc 2.39) is for the box and
Ubuntu 24.04 hosts only.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-06 23:37:33 +00:00
igneum-labs
95281941af Hands moved to igneum-build-1 (run log); the overlay carries directories a crate reaches by include_bytes!; two mover fixes
docs/plans/hands-on-build-1.md section 6: the move of 6 October 2026 23:06 to 23:22 UTC, observer node, observer, node 1, unload,
each hand's first executing line, digest eada4bda MATCH, IBD and acceptance, the open readback (the Mac's Miner app has not
started its own node since 26610/26611 were freed). lib.sh: the shipper's class from the 0.3.17 tree, the fork's igneum-exec
embeds proving/igneum-prove/elf/*.vk by include_bytes! five levels up, which is no path dependency; every .rs in the trees that
travel is scanned for include_bytes!/include_str! paths leaving the crate's repository and their directories join the overlay;
proving/igneum-prove/elf is the fixed fallback for a fork build. move-hand.sh: igneumd --version exits 1 (tolerated; it ended
the binary step before the override was written), and the launchd pid lookup used \s in macOS awk (printed 'pid none').

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-06 23:25:36 +00:00
igneum-labs
3e8e7a5dfc Hands mover: the node tree defaults to the Mac agent's own build, a digest readback per hand against the Mac hand, a 16-field guard on the override
Main's hold of 6 October 2026 (23:xx UK): the hands move only on the shipper's 'publish 2 live: digest <x>' line, each hand read back by
commit string and consensus digest. move-hand.sh binary now derives --node from the fork tree behind the Mac's node1 launchd agent
(igneum-wt-ship0315/vendor/igneum-node-0315 at f1ea7a38 tonight; the box's igneumd rebuilt from it is sha256 7f0bde70...), warns when the
Mac's override still has 13 fields (publish 2 writes the sixteen-field object when it restarts the hands), and after each hand's first
executing line prints the box binary's commit string and the hand's digest against the Mac hand's last digest (MATCH or DIFFER, DIFFER
stops the sequence). Dry run clean against the live Mac.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-06 22:51:06 +00:00
igneum-labs
11c4426a96 Kill by exact command line or pid file, never by a name: tools/ci/kill-by-name-check.sh in the gate; the 36 pgrep/pkill literals in the tree fixed
The fleet's 22:09 UK incident (a Mac-side pkill -f <log file name> matched nothing, the roll-everything script lived on and wiped a held box) and the day's two pgrep self-matches are one class. The check flags pgrep -f / pkill -f with a plain literal (every one on a line), any pgrep/pkill on a file-name shape, and ps | grep with a literal; it allows the bracket form, -x, -F pidfile, kill $(cat pidfile), a variable and a full path; 11 banned and 16 allowed shapes in its self-test; 0.15 s over the tree. The 25 pkill -f sp1-gpu-server inside bash -c bodies (which matched the calling bash) are pkill -x; the other 11 literals take the bracket form; prover-socket-check accepts both. Row R in the record; the CLAUDE.md rule names the check and covers pkill and file names.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-06 22:10:31 +00:00
igneum-labs
27ce42aab5 Merge ci-hardening b2262e5: one gate script for the hook and CI, the research exclusion list, the Windows paths check, the red watcher and the box's red-row classes with pre-flight
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-06 21:43:37 +00:00
igneum-labs
b2262e5dc6 Build box: every red run classified and kept, pre-flight before the slot, one run per worktree, box reds in the red-run file, a 09:00 UK digest
The box's 34 red rows of 6 October classified (docs/analysis/ci-failures-2026-10-06.md section 6): 22 iterations, 12 in three real classes (instant deaths with nothing kept, a shared worktree directory, an unread dry run). remote-run.sh now: pre-flight (subcommand, manifest, -p package, --features) refuses in a second with exit 3 and a class; the last 400 lines of every run kept in /srv/builds/_log/runs; a class on every row (compile-error, link-error, test-failure, instant, no-test-matched, slot-timeout, no-dir, preflight-*); a cargo test whose filter matched no test exits 3; a per-worktree lock in checkout and run mode; every red row appended to /srv/ci-red/red.jsonl as source box. red-watch.mjs never posts a box row alone and sends one digest a day (counts per class with each class's guard); the timer runs tick. Shared group cired on the box so the runner and build append to one file. Shown in a sandbox on the box: pass, failing test, empty filter, bad package, bad feature, missing subcommand, compile error, broken manifest, two concurrent runs of one worktree.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-06 21:40:07 +00:00
igneum-labs
89391d0052 Merge box-capacity 58dacf6: the builder's background capacity layer (fuzz, sims, sweeps, clippy; yields to builds)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-06 21:35:54 +00:00
igneum-labs
58dacf6f38 Capacity layer: fixes from the smoke runs
- pow-fuzz: list saved mismatches from the directory, not an ls|node pipe (pipefail ran
  the || echo too, giving invalid JSON [][]); drop the dead inner accumulation line
- sync-fuzz: merge the override with python, not node (node rounds the u64::MAX activation
  fields to a float the Rust parser rejects); retention-period-days 2 (the 2-day minimum);
  grep -c without || echo (pipefail doubled the count)
- clippy-audit: cap_cargo_t (timeout cannot run the cap_cargo shell function); grep -c fix
- all jobs sync the checkout unconditionally and lib.sh defaults the branch vars so a
  standalone job or smoke never trips set -u on CAP_NODE_BRANCH

Smokes on igneum-build-1, all 0 panics: pow-fuzz 98 rounds / 19,600 programs / 78,400
units; sync-fuzz 142,883 requests, node alive, every kind disconnected or answered;
sim-sweeps 5 rows; model-sweeps 7 sections; clippy-audit 69 branches, 1,192 warnings,
1 error (ca2-coord), 0 advisories.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-06 21:32:55 +00:00
igneum-labs
eb5d798070 remote-run.sh: a stale index.lock is one older than 30 s, not one with no git anywhere on the machine; the self-test backdates its fixture lock
pgrep -x git over the whole machine kept the lock whenever any git ran (the pre-push hook's own git push, another agent's build) and the checkout died with "index.lock: File exists". The fact is the lock's age. Class Q in docs/analysis/ci-failures-2026-10-06.md with the GIT_DIR leak of the previous commit.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-06 21:11:30 +00:00
igneum-labs
60eb06ec24 CI hardening: one gate script for the hook and CI, the research exclusion list, the Windows paths check, the red watcher, the box runner switch, the failure classification
168 non-green runs since the first workflow run were classified (docs/analysis/ci-failures-2026-10-06.md): 102 were tree checks that finish in under 25 s on the pushing machine, 40 were GitHub-side refusals nobody saw.

tools/ci/pre-push.sh is the one list of fast checks; ci.yml's site job calls it with --ci and the pre-push hook with --hook (full gate for master and release-*, structural checks for other refs; never writes into the worktree). tools/ci/export-exclude.txt lists research documents outside the public export list, pruned by identity-check.sh and by the mirror's sync.sh (self-test: an excluded path may quote the patterns, an exported one may not); polish.md and this record are its first entries, which makes master green. tools/ci/windows-paths-check.sh (colon, trailing dot or space, reserved names, over 240 characters) runs as the pre-commit hook on staged paths and in the gate. tools/ci/red-watch.mjs plus the red job on the box's runner record one line per failed master or release-* run to /srv/ci-red/red.jsonl; igneum-ci-red.timer posts each once to the updates channel. pow and sims read IGNEUM_CI_RUNNER for the box. no-foreign-tree-writes.sh no longer exits silently on its warning pipeline under pipefail.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-06 20:58:54 +00:00
igneum-labs
6836115d65 Capacity layer: idle-core background workload on igneum-build-1 that yields to builds
infra/build-server/capacity: igneum-capacity.service (user build, Nice 19, SCHED_IDLE,
CPUQuota leaving 8 threads free) runs run.sh, a controller over a priority queue of jobs
that pauses (SIGSTOP) the instant a build slot or the measure hold is taken (5 s poll of
/srv/builds/_locks) and resumes after. Jobs, each with a dry-run and a 10-min smoke:
pow fuzz (continuous, seed base advances), sync-request fuzz against a throwaway pruned
node on loopback (the Horizon 28-unwrap gate, igneum-p2p-probe sync-fuzz), GHOSTDAG and
finality sweeps seeds 1 to 1,000, model.py sweeps cached, clippy+audit per recent branch.
Summaries to /srv/workers/capacity.json; the worker dashboard gains a Background lane
(collect.mjs doc.background, page renderBackground). Night battery stops and restarts the
layer. docs/plans/build-server.md section 8. igneum-pow fuzz tests and ghostdag_sim.py /
attacks.py gain a seed-base knob for the continuous sweeps.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-06 20:58:42 +00:00
igneum-labs
4754900628 Repro check: sccache really off (RUSTC_WRAPPER=/usr/bin/env, an empty value falls back to the box's config), the author-time epoch of lib.sh bs_sde, and the re-stamp line the copied-sources check reads
The build-server agent's two findings on rebuild-on-box.sh (6 Oct 2026, 20:1xZ): tools/ci/copied-sources-check.sh named it
(a tar on a code line plus cargo build with no touch), and `RUSTC_WRAPPER=` did not switch sccache off, so some passes of the
first runs took hits. Both 0.3.14 and 0.3.15 are re-run with this version before their evidence files are trusted.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-06 20:13:43 +00:00
igneum-labs
67ae1e4c6d Reproducible builds: SOURCE_DATE_EPOCH from the commit's author time, TZ=UTC and one fixed target path in every build path; self-test
Main's rule of 6 October 2026 from the 0.3.14 repro (docs/evidence/reproduced/0.3.14.md): prost's protowire.rs embeds OUT_DIR,
libmimalloc-sys embeds __DATE__/__TIME__, sccache hid both. lib.sh bs_repro_env exports SOURCE_DATE_EPOCH=<author time> TZ=UTC in
front of every remote command (build-remote.sh, cross-remote.sh, workers-remote.sh); remote-run.sh exports BR_SDE too and logs it
as source_date_epoch; proto-cuda/windows-node/cross-build.sh exports the same; the PC job carries node.commit_time in the manifest
(push-build-inputs.sh) and exports it before every cargo build of a stage (jobbuild.rs, unit test asserts it; 4 of 4 pass on the
box). Target dirs stay one fixed path per target. tools/build-remote.sh --self-test-repro [--full] from a fork worktree, run on
the box: igneum-miner twice a minute apart without sccache (RUSTC_WRAPPER=/usr/bin/env, an empty value is unset to cargo) MATCH
91e130f5..., a per-run target path differs (OUT_DIR shown); --full: kaspad with libmimalloc-sys recompiled a minute later MATCH
70219bc2..., without the epoch differs (__DATE__ shown).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-06 20:09:23 +00:00
igneum-labs
56282f9ce6 Repro 0.3.15: the box matches itself on all four again; the shipped HiveOS pair is the Mac's zig build (GLIBC_2.34, /Users paths, a build clock); the reason column reads facts off both binaries
- rebuild-on-box.sh: the DIFFER reason comes from the binaries (glibc need of both, the build path each embeds, the
  mimalloc clock string, the PE timestamp, the commit string), never from an assumed story; the three string helpers run
  their producer under `|| true` so a consumer that stops early (grep -m1, awk exit) no longer trips pipefail into the
  fallback and a second line in a table cell.
- docs/evidence/reproduced/0.3.15.md, and the 0.3.14 file re-reported with the same column.
- docs/plans/build-server.md 7.3: the 0.3.15 row and what the two files mean for shipping from the box.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-06 20:04:14 +00:00
igneum-labs
1c8b6563ce Repro 0.3.14: the box reproduces itself on all four artefacts (A vs B MATCH), the shipped bytes DIFFER by toolchain; two non-determinisms found and fixed in the check; night battery dry run recorded
- infra/build-server/repro/rebuild-on-box.sh: one target path per target with each pass's artefacts copied aside (prost's
  protowire.rs embeds its OUT_DIR path, so a pass in a dir of another name differs), SOURCE_DATE_EPOCH from the node commit
  and TZ=UTC (libmimalloc-sys compiles mimalloc's C with __DATE__ and __TIME__), --reuse for a re-report, reason text
  for a shipped file that is not on hand (innoextract 1.9 cannot open the Inno Setup 6 installer; the 0.3.14 HiveOS
  tarball left dl/public when 0.3.15 published).
- tools/repro/rebuild-release.sh: the plan's hashes always travel (the miners' 8-hex prefixes too), bash 3.2 empty-array
  fix, the box half's exit code is the script's.
- docs/evidence/reproduced/0.3.14.md: igneumd 03f35e05..., igneum-miner 900c1f0b..., igneumd.exe 166e604e...,
  igneum-miner.exe fefd266c... identical across two clean passes; DIFFER against the shipped 934f393c... (zig, glibc 2.36)
  and 44fa74c0... (Homebrew mingw before the timestamp fix, from a worktree).
- docs/plans/build-server.md 7.2 (night battery: timer, dry run 3 min 54 s, 10 pass, the fork's 22 cargo-audit
  advisories as the one FAIL and what follows) and 7.3 (repro: results, the two classes, SOURCE_DATE_EPOCH proposed for
  every build script).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-06 19:55:09 +00:00
igneum-labs
069ff4540b Box: the night battery (02:00 London timer, one slot, every suite, fuzz, sims, harnesses, clippy, audit, report on branch night-battery) and the reproducible-build check
- infra/build-server/night/night-battery.sh: checkout of master and the newest release-*-node fork branch under
  /srv/builds/_night, cargo test --release --no-fail-fast per crate (repo and fork), igneum-pow fuzz at 10x, the three
  simulators in full, the fast-time harnesses (finality-attacks, harness s3 s4, exec-sync reorg) on binaries built into
  target-integration, clippy per crate dir, cargo audit per Cargo.lock; docs/benchmarks/night/<date>.md with a pass/fail
  table and "new since last night"; committed as igneum-labs on night-battery and pushed to the mirror, never master.
  NIGHT_SUBSET=1 is the dry-run subset. The unit runs it through remote-run.sh so the slot spans the invocation.
- igneum-night-battery.{service,timer}: 02:00 Europe/London, User build, Nice 19, idle IO, 8 h limit, not Persistent.
- provision.sh: step_cargo_tools (cargo-audit), step_night (files from the mirror at NIGHT_REF, timer enabled), innoextract.
- tools/repro/rebuild-release.sh + infra/build-server/repro/rebuild-on-box.sh: pins from docs/plans/release-<v>.md
  ("(node <sha>, app <sha>)"), shipped hashes from the public downloads (the HiveOS tarball, the installer via
  innoextract) or --shipped, a clean clone of repo and fork on the box, two passes per target without sccache under build
  slots, MATCH or DIFFER per artefact against the shipped bytes and against the other pass, with the reason read off the
  binaries (glibc version needed, PE timestamp, commit string); evidence into docs/evidence/reproduced/<version>.md.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-06 19:40:32 +00:00
igneum-labs
7184e5bfc7 Box: GitHub Actions runner as user runner, two build slots with 90 or 45 jobs, the measure hold, the CPU prover trial
- provision.sh step_runner: actions/runner 2.338.0 (sha256 checked) at /opt/actions-runner under a dedicated user `runner`
  (no sudo, not in build's group), rustup 1.99.0 pinned with both targets, sccache against /srv/sccache in READ_ONLY mode
  on its own server port, Node 22 and mingw from the system, GitHub's svc.sh unit with a Nice 10 drop-in; registered on
  igneum-network/igneum as igneum-build-1 (labels self-hosted, linux, x64, igneum-build-1) through
  infra/build-server/runner/register.sh (gh as igneum-labs, the token on ssh stdin, never logged). Idempotent after
  the env files moved behind svc.sh install (its env.sh rewrites them). libicu74 and python3-numpy added to APT.
- main's slots ruling: SLOTS default 2; remote-run.sh sets CARGO_BUILD_JOBS 90 when it holds the only taken slot and 45
  when both are held, BR_MEASURE=1 takes the `measure` file exclusively and excludes builds (builds hold it shared),
  lock files open in append mode (the old `exec {fd}>` truncated a busy slot's holder line on every probe), env
  IGNEUM_BUILD_SLOTS_DIR and IGNEUM_BUILD_LOG_DIR win over the profile, `--self-test-slots` with five cases (the old
  script fails it with JOBS=none); build-remote.sh and cross-remote.sh pass -j only when --jobs is given.
- infra/build-server/prover/cpu-trial.sh: the SP1 CPU prover on one fixture shard under the measure hold with a VmHWM
  poller; 6 Oct 2026 run: core 34.2 s, compressed 85.9 s, peak RSS 28.2 GB on 96 threads, so no standing CPU prover.
- docs/plans/ci-self-hosted.md: the proposed runs-on change for ci.yml behind the repository variable IGNEUM_CI_RUNNER
  (GitHub-hosted is the fallback), and why windows.yml cannot move to a Linux box. Workflows untouched.
- docs/plans/build-server.md section 7.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-06 19:32:43 +00:00
igneum-labs
af5db68f21 Merge discord-hooks: partial credentials accepted, install finishes, the hand commands doc
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-06 19:12:15 +00:00
igneum-labs
9508c939c8 Build server: CUDA 12.8 headers on the box and tools/workers-remote.sh (the GPU workers' Linux build for the class v4 rehearsal)
provision.sh step_cuda: NVIDIA's ubuntu2404 apt repository, cuda-nvrtc-dev-12-8, cuda-cudart-dev-12-8, cuda-driver-dev-12-8
(the libcuda stub) and opencl-c-headers; no nvcc (no build file calls it), no driver. tools/workers-remote.sh builds
igneum-worker-cuda and igneum-worker-opencl on the box from proto-cuda and proto-opencl with clang++ (static libstdc++),
prints sha256 and the glibc ceiling (2.38: fine for Ubuntu 24.04 hosts, not for 22.04 containers or HiveOS, where the Mac's
zig build stays). Proof: igneum-worker-cuda 1,613,992 B sha256 6db8a9ad..., igneum-worker-opencl 124,904 B sha256 0dea75bb...
remote-run.sh evaluates the command string in a subshell (a leaked set -e killed the runner after a successful build).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-06 19:11:19 +00:00
igneum-labs
e29038f78a Discord webhooks: install.sh finishes on a partial credentials file (the check step exits 1 by design)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-06 19:07:26 +00:00
igneum-labs
afe6f02169 Discord webhooks: a partial credentials file installs; the tick logs the missing keys; the watcher advances without posting
Main's ruling (6 October 2026, 20:1x UK): the box installs with the NUMBERS key alone so the 21:00 UK pulse comes from
it. install.sh accepts at least one key and names the missing ones; every tick's log line ends with "missing <keys>"; the
watcher without an incidents webhook logs its open or resolve and still advances its state, so the key landing later
does not flood the channel. Test added (31 passing).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-06 19:06:57 +00:00
igneum-labs
1c8c4f81ae Merge discord-hooks: network pulse, digest, weekly, release and incident posts to Discord from igneum-build-1
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-06 19:03:13 +00:00
igneum-labs
1a6c88631b Discord webhooks: the bot's pulse, digest, weekly, release and incident embeds, a watcher, a timer on the box
tools/community/discord-hooks.mjs (Node 22, standard library): one ember embed per post to #numbers, #announcements and
#incidents. Network pulse every 6 h (03/09/15/21 UK) from /api/stats, /api/live, /api/supply with the 6 h window from its
own snapshot and a Devnet 2 line that uses the fleet file's numbers and gate word only; a 24 h digest and the reddit kit's
weekly template at 09:00 UK; a release subcommand for the shipper (three downloads with sha256, node commit, digest, up to
five plain "what changed" lines read from the release plan); incident open and resolve by hand; a watcher that opens one
incident per condition (finality paused 5 min, median proof lag 15 min, observer silent 3 min) and resolves after 2 clear
minutes, and never opens on a condition already firing when it first looks (the pulse says "finality paused since" instead).

Guards before every post: the founder's name and logins, hosts, machine ids, paths, IP addresses, standalone 32-hex
tokens, dl.igneum.network outside /public/, webhook URLs, mentions, the tools/ci/forbidden-strings.txt patterns; Discord's
limits refused rather than cut; idempotency keys per slot in a state file; exponential backoff on 429; dry run by default
with a Discord-like preview in tools/community/out/preview.html. 30 tests on fixtures cut from the live API.

infra/build-server/discord-hooks: a tick every minute on igneum-build-1 (the Mac sleeps). install.sh copies the webhook file
to /srv/discord-hooks/env (mode 600, over ssh stdin) and refuses without IGNEUM_SECRET_ON_BOX_OK=1; the recorded exception
to rule R6 is in docs/plans/build-server.md (main's ruling, 6 October 2026).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-06 19:02:05 +00:00
igneum-labs
ce772fac41 Hands mover: --override-json takes the shipper's exact override object for the cut (checked as restart-hand-nodes.sh checks its argument)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-06 19:00:43 +00:00
igneum-labs
8561fadb33 Build server: the devnet hands' move to igneum-build-1 (plan, installer, mover), a per-worktree lock, the nested-stamp checkout fix
the project lead's decision of 6 October 2026: the Mac runs nothing the network depends on. docs/plans/hands-on-build-1.md plans node 1
and the observer (its node and tools/observer) as systemd units on the box, one hand at a time, with ports, DNS names,
exec recovery, rollback and the decisions for main; infra/build-server/hands/install-hands.sh writes users, dirs, run
scripts and units (inert, run on the box); move-hand.sh (dry run by default) builds 0.3.15 on the box, copies the override
and snapshot, rsyncs each data dir hot then stopped, starts the unit and prints the hand's first executing line, copies the
observer env by scp (mode 600), stops the Mac's observer first, unloads the launchd agents last. CLAUDE.md's running-agents
rule carries the decision. lib.sh: a per-worktree lock on the box across sync, build and fetch (the shipper's collision at
18:48:56Z). remote-run.sh: the clean-tree test excuses stamps and target dirs at any depth with --untracked-files=all (a
nested stamp failed every checkout of /srv/builds/igneum for twenty minutes) and removes a stale .git/index.lock; the
self-test covers both. Plan rows for the three and the cuda prover pair built for the shipper.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-06 18:58:14 +00:00
igneum-labs
d191906f6d Build server: the remote checkout's clean-tree check accepts the sha stamps and target dirs at any depth
The second build of every repo-kind crate in a subdirectory failed (6 October 2026, 18:51 UTC, the pool build: "tree not
clean after reset: ?? pool/.build-remote-sha-target"): checkout_tree keeps the stamps with `git clean -e` at any depth but
its status check matched them at the root only. The check now reads `git status --porcelain --untracked-files=all` (an
all-untracked directory is listed file by file, not as "?? sub/") and accepts target dirs, sccache and both stamps under
any path. The self-test carries the subdirectory case (stamp and target dir kept, overlay file removed) and the known-failed
case (a stray untracked file still fails the check).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-06 18:55:41 +00:00
igneum-labs
08e469ff65 Build server: a path dependency inside a vendor repository is synced as a whole repository (the shipper's proving build)
proving/igneum-prove depends on vendor/igneum-node-exec/igneum/evm-types, a member of the fork's workspace that inherits
from the fork's root manifest; syncing that one directory left cargo without a workspace root on the box. lib.sh now groups
path dependencies by git top level: a repository under vendor/ is pushed to its mirror (a fork worktree to
/srv/igneum-node.git, a repository of its own to /srv/<name>.git, created on first use), checked out whole at
/srv/builds/<worktree>/vendor/<name> and overlaid whole; run-from-mac.sh wires every vendor repository the Cargo.toml files
reach. libprotobuf-dev added (sp1-prover-types imports google/protobuf/empty.proto). build-remote.sh no longer fails on a
default artefact the caller's own -p selection did not build. Proof on the box: igneum-prove-host 71,943,192 B, sha256
e9213e3a6c979512d7859f6d8e848105bab53f4355e99fb0d30fb4a72c2d5714, 1 min 05 s warm. Plan: gotcha rows for the case, the
protoc miss and one lost ssh session (collector cleared by test).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-06 18:36:39 +00:00
igneum-labs
9df9688b59 Build server: the remote checkout discards the previous overlay first (the stale-overlay class, PC 1 worker, 6 October 2026)
remote-run.sh gains a checkout mode used by lib.sh: git checkout -- . and git clean -fd (target dirs, the sha stamps and
ignored files kept), fetch, branch at the commit, then a clean-tree check; the overlay follows. Before this, the rsync of
uncommitted files stayed in the box's tree and the next commit's git checkout -B refused with 'local changes would be
overwritten'. remote-run.sh --self-test reproduces the dirty tree (edited tracked file, untracked file, target dir, sha
stamp), shows the plain checkout refusing and the mode landing clean on the new commit; it runs in ci.yml and passed on the
Mac and the box; a live dirty-then-clean pair on the fork worktree passed too. Plan: section 5, gotchas of the first day.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-06 18:16:27 +00:00
igneum-labs
dbdfda0d21 Merge workers-dash: the worker dashboard on the fleet URL (collector on igneum-build-1, Mac pusher, workers.html)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-06 17:59:54 +00:00