PC 2, 8 October 2026, 21:24 UK: api/quit on 2.0.1 left all four processes up 90 s later while the node sat in initial
sync. Now: a quit guard armed at the ask (the server's /api/quit and the engine's Cmd::Quit alike) ends the node and
the workers by the pids the state records, never by name, 45 s after the ask when the engine has not left by itself,
prints the exit line and leaves; the node's grace is 10 s then the kill; the last log upload waits 10 s at most; the
window reads the stage ("quitting: the node is being stopped") on the pill and the big button.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Rights are by id and a changed script re-asks nothing, so without this a 2.0.1 install would have kept its task on the
LOCALAPPDATA exe for ever. power-helper-task@protected is helper-takeable: an update by job takes it through the
running helper's reregister (the copy under the signed manifest's engine hash, no click); otherwise the next
interactive start asks once.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The one elevated step copies igneum-app.exe and its runtime DLLs into %ProgramData%\Igneum\helper with inheritance cut
(Administrators and SYSTEM full, Users read and execute, owner Administrators) and registers the task against that copy;
the per-user install under LOCALAPPDATA is never what the scheduler runs elevated. The helper's reregister refreshes
the copy only when the signed update manifest names the installed exe's sha256 (platforms.windows.engine_sha256,
publish-manifest.sh --win-engine); anything else is refused with its reason in helper.log. rights.ps1 and
register-power-task.ps1 are no longer read from user-writable folders: every elevated script travels inline through
-EncodedCommand. quit and remove carry a sequence like every verb and pass the rising-sequence guard; a stale line
re-added to the file is skipped. The window host declares asInvoker. The prove host's lease is the lesser of the
grant and the free reading (the V6-07 sub-lane's 12 GB row).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
PRODUCT=public|lab (the founder's word at 20:21 UK): one variable in packaging/mac/packaged-config.sh that every packager
reads: Igneum-Miner.iss AppId, AppName, folder and file name (/DProduct from build-installer.ps1 -Product), make-payload.sh
and make-hive-package.sh names (payload folder, Hive CUSTOM_NAME and archive), build-dmg.sh bundle id, app and dmg names,
the channel (igneum-2.0-devnet stays the public string), the manifest name and the signing root; the packager writes
edition, channel and ota_root_hex into igneum-app.json and the engine names a mismatch on its update card.
The job runner refuses a run-script body that ends a process by name (Stop-Process -Name, taskkill /IM, Get-Process |
Stop-Process, pkill, killall): exit 77 with the matched line, in the signer and in the runner; a pid is the only way.
Every igneum-prove-host spawn carries IGNEUM_PROVE_DEVICE, IGNEUM_PROVE_WORKLOAD, IGNEUM_PROVE_MEM_FREE_MB,
IGNEUM_PROVE_MEM_BUDGET_MB and IGNEUM_PROVE_DEADLINE_S (the V6-07 contract); exit 78 reads "proving needs N GB free".
The manifest check runs every ten minutes. A staged update applies at once on a synced node with an idle miner and
within two minutes of the sync otherwise; Install now passes the finality guard; publish-manifest.sh --urgent.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
packaging/release-manifest.json for release 2.0.1 on igneum-devnet-4, with tools/ci/release-manifest-check.sh (every component's own pin must equal it) and tools/ci/build-from-manifest.sh (every component built from it on a box). The shipper lands it on release-2.0.1 at the next cut; the manifest's miner_app sha then moves to that cut and the check reads it.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
infra/build-server/lib.sh: bs_repro_env forwards IGNEUM_LAB_PUBLIC_KEY to the box when the caller set it, so the lab
build (`--features lab`) compiles its root through tools/build-remote.sh without the key in the tree. The prover
logs `DEVICE event=free|not-free used_mib=<n> waited_s=<s> holder=prover` around the time-share gate: the line the
fleet lane's INT-11 rows read (the device free memory confirmed, not dispatch paused).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
F14, the founder's ruling of 19:57 BST (docs/analysis/review-2026-10-08-b, the shipper's and the relay lane's names):
one tree, two builds, by the cargo feature `lab` (src/edition.rs). The public miner (the default) runs no remote
jobs: no signing root for them, no jobs url, the routes /api/jobs/* compiled out, the wake listener compiled out, the
Settings switch hidden, POST /api/jobs/allow refused with a line; its update choice is honoured: with automatic
updates off nothing installs until Install now, an urgent manifest included (manifest::safe_to_apply, the first
rule), and an unsupported version pauses mining with the reason on every card (update.hold_mining, the engine's
unsupported_hold); a manifest's consensus override is ignored (the node's rules come from the node; a compromised
update key activates nothing). The lab build (our fleet, `IGNEUM_LAB_PUBLIC_KEY=<hex> cargo build --features lab`)
verifies its OTA manifest, its interface bundles and its jobs feed against the lab root the relay lane generated
(never in the repo; the build fails without the variable), reads channel igneum-2.0-devnet-lab, names itself
"Igneum Miner Lab"; the public build reads igneum-2.0-devnet (the 2.0.0 and 2.0.1 manifests' "devnet" accepted
until the publisher renames it) and refuses a manifest of the other channel before staging. api/state carries
edition, product and channel; the IGNEUM-APP intake line carries channel= and edition=. The update choice is asked at
install: the welcome screen's "Update automatically" switch (on by default) and the Windows installer's task, which
writes install-choices.json for the engine's first start (config.rs).
F07: src/device.rs, the per-device coordinator. The mode per NVIDIA card from the measured rows (coexist-rows.md,
8 October 2026): simultaneous only on a tested configuration (24 GB and up, with 10% headroom over the measured
peaks), time-share where the compressed shard proof (7,532 MiB) fits alone, mining-only where no complete paid proof
fits; a lease table across the miner, the prover, an aggregation, a benchmark and the next-epoch preparation, where
pausing dispatch is not releasing memory (a lease ends only after the holder's process exits and nvidia-smi reads the
device under 1,024 MiB), and admission counts transfer, startup, proof, aggregation, rebuild and the payment deadline.
Wired: provedefault reads the modes (16 to 24 GB alternates, no longer "together"), state.proving.modes carries one
line per card for the Proving section, and the time-share prover waits up to 60 s for the card to read free after the
miner steps off before a shard, leaving the shard for another prover with the reading when it does not.
F04: the window's block inspector reads "finalised by a recovery lock" and the strip "recovery lock" with its why,
from igneum_getProvingStatus's lockKind and lockWhy once the node lane's field lands; the pause word stands until then.
Tests: edition.rs (the roots and channels per build), manifest.rs (off stays off, known-failed first), config.rs (the
installer's choice taken once), device.rs (the modes per row, the full cycle with no leaked reservation, the
simultaneous and mining-only rules, the deadline), provedefault.rs (the modes and the refusal), detect.rs parse; the
public crate 327 green on build-1; the once-tests for the window (F14, F07, F04); 133 UI tests green on build-2.
Captures in ~/Desktop/igneum-previews-2026-10-08/reviewb-202. The lab build's test run needs the key in the box's
build environment (tools/build-remote.sh does not forward it yet); the public build is the gate's.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The founder's call at 19:25 BST on the mini (8 October 2026): with the node at 0 peers the worker idled for lack of
templates and the watchdog blamed the worker ("did not come back within 180 s of the miner restarting it (seed
mismatch...)"): the restart grace ran before the node's readiness was read. Now CardWatch::tick takes `no_peers`
(the engine reads state.node.peers == 0, once the node is past starting) and, whenever the node has no peers or the
miner's last word was a template timeout (templates_blocked), every clock holds, the restart grace included, the
verdict is None, and `held_by_node()` names the cause: "no block templates: the node has no peers" or "no block
templates: the node answers none for the window". The engine writes that cause onto the card's row while it holds,
and the waiting card of a node with no peers reads it too. The node line on Mine reads "Node: no peers, dialling the
seeds" and the words under it end "mining waits for block templates". F6 in the window audit doc (master).
Tests known-failed first: watchdog.rs (the founder's case: a worker restart on a node with no peers, the grace long
past, Action::None and the cause; the template-timeout window; the old grace rule with peers and templates), the
once-test (the node line, the cause in the watchdog, the engine reading it). The crate: 320 tests green on build-1;
130 UI tests green on build-2.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The founder's calls of 18:1x BST, 8 October 2026 (through the shipper), recorded as F1 to F5 in the window audit doc.
F1. The Cards tab is back in the rail as its own page (View.PAGES: mine, cards, tune, earnings, settings); every card
row moved out of Mine into it: the state, the hash rate, the power, the temperature, the tune state (one line, the Tune
page's words, View.cardsRowWords), the enable switch, the 16 GB proving note on an NVIDIA card under 16 GB. Mine keeps
the headline rate and the chain status (the hero tiles, the chain scene, the node line, Activity).
F2. The first-block celebration shows once per payout address, ever: settings.json keeps first_block_shown[address]
= {hash, at} (config.rs FirstBlockMark), written when a window reports the card seen (POST /api/card/seen), so it
survives runs, updates and a reinstall that keeps the wallet; a new address shows it once again (the engine passes
the address's mark to Ladder::on_block_for, which raises the card whenever the address has none); an install that
showed it under the machine rule takes the mark for its current address once at start. Never on a dev-fee block: the
miner's "dev-fee block <hash>" line follows the fee block's ACCEPTED line, and Ladder::on_fee_block withdraws a first
card that block raised; the engine now counts fee blocks from that line (fee_session, fee_total) as well.
F3. The four interface words (docs/spec/finality-guarantees.md section 9) on the window: the block inspector reads
included or excluded or pending, executed as chain block N, proven, finalised (View.blockState); a block under the lock
is finalised even while the network's finality is paused (the pause is said after the block's own words and on the
status strip), and no block reads "not active" or "(reported)"; the scene's hover words say finalised and executed
(scene/live-dag.js 2.0.8, the copies synced).
F4. One positioning line: the hero keeps it; #s-positioning under Updates is gone.
F5. The watchdog's words when the node serves no epoch state stream: "waiting for the node's execution state for this
epoch: no program to load 300 s after starting", never "the worker did not load its program".
Tests known-failed first: once.test.mjs (the Cards page with the home page's contents, the inspector's words), the
view tests' page list, ladder.rs (the first card follows the address mark; a dev-fee line withdraws it; the 0.3.21
wrapper keeps the machine rule), watchdog.rs (the waiting words). The crate: 319 tests green on build-1; 129 UI tests
green on build-2. Captures: ~/Desktop/igneum-previews-2026-10-08/cards-201.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The engine already sends every wei value as a decimal string (u128 on the Rust side), but the window turned three of them into a Number for the IGN figure (the proving paid line, the segment paid line, the wallet balance). A 2.0 block subsidy is 9.5e18 wei, past 2^53, so the IGN figure is now cut from the string (weiParts, ignText): whole units and the first four decimals, no wei value in a Number anywhere; only the IGN figure is a Number, for the pounds line and the thousands check. The 61 view tests hold.
The DMG README's step 2 says the build is unsigned tonight and gives the two-step (open once, then System Settings, Privacy and Security, Open Anyway); Developer ID signing and notarization follow with the Apple enrolment.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Found by the net-20 capture: .screen is display:none and only the ids in app.css's phase rule display; screen-network
(the network step, 0.3.23) was never in that rule, so a fresh install reached step 3 of 4 as a blank page with no
Continue button, on every build from 0.3.23 to 0.3.26 (the forced ?screen=network capture read the same). The rule
lists it now. The once-test reads every screen id in index.html against the rule, known-failed first (five of six).
127 UI tests green on build-2; the step captured with its one card.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The net-20 capture of the network step (?screen=network, the forced start the screenshots use) read empty: show('network')
renders the step only when a state is already held, and the first poll shows the forced screen before render() stores
the state; later polls render the dashboard pages only. render() now renders the step whenever the phase is network,
the same way it renders the cards step. 126 UI tests green on build-2; the step captured with its one card.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>