igneum/docs/analysis/horizon/polish.md
igneum-labs 351fad2521 Horizon: lane 6 (polish) lands: 95 ledger rows against the best in class, the ten the project lead will notice first
Every shipped surface audited against a named comparator with the file or screen: the pause of
6 October had no cause on any surface for two hours (the node reports no frozen-table reason,
the observer copies the flag alone, /live computes the silent share from the sliding table,
Ember has no pause state); a fresh machine meets two warnings before the first screen (ad hoc
codesign, no notarisation, unsigned Windows installer); every update has been urgent since the
0.3.14 manifest (fork_is_close treats any passed activation as close). Rows Q1 to Q105 with
severity, hours, owner and gate; cross-cutting: one formatter table for every number, the five
6 October rule rows without a tools/ci check, the forbidden-string scope gaps.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-06 20:19:36 +00:00

108 KiB

Horizon lane 6: polish. Every shipped system against the best in its class

Date: 6 October 2026, evening UK (written 20:00 to 21:00Z, while the live devnet's finality was still paused). Lane 6 of the Horizon programme. Worktree /Users/joshm/Projects/igneum-wt-horizon (branch horizon, HEAD c3aa502). Output: this file only. No file outside it was edited; nothing was built, deployed, posted or started; the installed app and every live service were read, never touched.

the project lead's bar: "a level of polish that has not been seen before." This file is the honest audit: what each shipped system does, the named comparator and the exact screen or feature it has that we lack or do worse, the ledger rows that close the gap (95 rows, ids Q1 to Q105 with gaps, each with a file or screen, a severity, hours of agent work, an owner and a gate), and what is already better than the comparator. The first ten rows are what the project lead will notice first when he opens each product tomorrow.

0. What was read and run

Read, in the worktree: app/igneum-app (src, ui, tests), app/mac/IgneumMiner.swift, app/windows/host.cpp, docs/plans/miner-ui-2.md, miner-ui-3.md, miner-ui-3-audit.md, ember-tune.md, release-0.3.14.md, docs/design/app-screens/, docs/design/miner-tuning.md, docs/fud-ledger.md (X17, X19, X21 to X28, M25 to M29, G7, G10, G13), site/ (every page, api/, lib/, verify/, build.mjs read not run, scrub.mjs, forbidden-strings.txt, downloads.json, journey.json, vercel.json, sitemap.xml), docs/design/site-polish-2026-10-04.md, docs/plans/site-ui-3-shots/, docs/plans/site-miner-2026-10-06.png, docs/review/round-4-reddit-2026-10-06.md, docs/plans/explorer.md and explorer/, relay/ (ui, api, lib, clients, playbooks, tests), tools/relay.mjs, tools/console.mjs, tools/jobs.mjs, docs/design/relay/, docs/design/console/, pool/ (src, web, tests, README), docs/plans/pool.md, docs/spec/09-pool-protocol.md, tools/community/discord-hooks.mjs and its tests and fixtures, docs/community/discord-hooks.md, tools/fleet/, tools/build-job.mjs, tools/build-remote.sh, tools/ci/, docs/plans/build-job.md, build-server.md, hands-on-build-1.md, node-changes.md, packaging/README-ship.md, packaging/ota/README.md, packaging/mac/README.md, packaging/windows/README.md, tools/observer/ (observer.mjs, README), docs/spec/03 section 3.9, and this lane's siblings finality-and-weight.md (3.1, 6) and frontier.md (3.7).

Read, read-only, in other agents' worktrees: /Users/joshm/Projects/igneum-wt-ship0315/docs/plans/release-0.3.15.md (the newest release notes; release-0.3.15.md does not exist on horizon or master), /Users/joshm/Projects/igneum-wt-wallet* (wallet 0.1.4 source, UI 3 branch), /Users/joshm/Projects/igneum-wt-gpu-fleet/tools/fleet/, /Users/joshm/Projects/igneum/vendor/igneum-node-0310/consensus/src/processes/finality.rs (the node's finality_reason).

Run (nothing live, nothing built): node --test app/igneum-app/ui/*.test.mjs (35 pass), node --test relay/test/*.test.mjs per file (24 pass), node --test tools/community/discord-hooks.test.mjs (31 pass, every live poster stubbed), one curl -s https://igneum.network/ (the allowed single fetch; saved to the scratchpad), and one read-only SQL pass over the observer's Neon tables (live_checkpoints, live_events, live_state) through the same HTTPS SQL endpoint site/api/_neon.mjs uses, to see what every surface had to render during tonight's pause. No browser automation.

Comparator claims are from memory unless a repository or page is named, and are labelled approximate.

1. The ten rows the project lead will notice first

Rank Id Row File or screen Severity Hours Owner Who it hits Gate
1 Q1 The pause has no cause anywhere. The node reports finality_reason (active, window filling, N of M, paused) but not the frozen-table share that held tonight's pause; the observer drops even the reason; the API has no reason field; /live computes "N% of weight silent" from the sliding table, which read 11 percent silent at 20:05Z while finality was paused (held by the table frozen at lock 6842, 57.3 percent signing). Add finality_reason, held_by (frozen index, its signing share, its expiry DAA) and lane 3's finality_provisional end to end vendor/igneum-node-0310/consensus/src/processes/finality.rs:1794-1807 (reason exists, no frozen share), tools/observer/observer.mjs:720 (copies finalityActive only), site/api/live.mjs:114-122 (no reason), site/live.html:520 (the silent percentage) the project lead-visible 4 (node 1.5, observer and API 1, /live and /api/stats copy 1, spec 3.9 row 0.5) consensus-engineer (node), site owner (observer, API, page) holder, exchange: the one line that says whether a pause is a silent third, a split, or a table waiting to expire; miner: nothing lost, but the app can finally explain itself; operator: a pause with a cause and an end time A forced pause on Devnet 2 (one slice over a third stopped): /api/live.finality carries reason, held_by, provisional; /live reads "finality paused since 18:40Z: 89% of the sliding weight is signing, held by the table frozen at lock 6842 (57% signing) until DAA 216,402 (about 20:40Z)"; the exchange guidance in spec 3.9 carries the provisional row (lane 3 proposal 4)
2 Q2 Ember never says "paused". The engine keeps only last_lock, last_lock_at, age_s, votes; the node line showed "#6842 · 1 h ago" under "a point the miners agreed can never be undone" for the whole two-hour pause. No finality_active anywhere in the app app/igneum-app/src/state.rs:247-248, src/engine.rs:3495-3497, 3896-3902 (lock parsed from the miner's LOCK checkpoint line only), ui/app.js:1350-1351 the project lead-visible 3 app owner (engine reads getFinalityCheckpoints or the miner's FINALITY line, spec 3.9 row; UI state and view test) home miner and rig: the app tells them finality is paused and why, instead of a lock age that climbs; pool user: the same on the pool page later Mock state with finality_active:false, reason:"paused" renders "Finality paused since 18:40Z, 89% of the 30-day weight signing, held by the frozen table until about 20:40Z" on the node line and in the pill; view.test.mjs case; seen on the Devnet 2 forced pause
3 Q3 A fresh machine's first 60 seconds start with a warning. macOS: ad hoc signature, no Developer ID, no notarisation; the engine strips com.apple.quarantine from its own bundle on start; the README's "Right-click > Open" bypass is gone on macOS 15 (approximate). Windows: installer and exes unsigned, SmartScreen "Windows protected your PC", then a UAC prompt for the firewall rule 20 to 50 s in before any screen explains it packaging/mac/build-dmg.sh:118-122, packaging/mac/README.md:51-53, app/igneum-app/src/main.rs:78, packaging/windows/README.md:76, 111, packaging/windows/build-installer.ps1:188, app/igneum-app/src/ota.rs:981-1015 the project lead-visible 6 (Developer ID signing plus notarytool and stapling in build-dmg.sh 3; Authenticode signtool step in windows.yml and build-installer.ps1 2; firewall step after setup_done with a sentence on the Cards screen 1), plus the project lead: an Apple Developer account and an OV or EV code-signing certificate (purchases, hours of the project lead's time, approximate) app owner; the project lead (the certificates) every new miner on every tier, Windows and macOS: Signal's and Tailscale's installers open with no warning (approximate); today ours open with two Fresh macOS 15 VM: the DMG's app opens on double-click, spctl -a -vv says accepted and notarised; fresh Windows 11 VM: no SmartScreen interstitial, signtool verify /pa passes; the first UAC prompt appears after the Cards screen names it
4 Q4 Every update is "urgent" once an activation height is behind the node: fork_is_close(Some(198000), 209000) is true, so the manifest's stale activation 198000 turned the 0.3.14 update into "the node is 0 blocks away. Installing now", stripped Later and skipped every safe-moment guard (the PC 1 install under a measurement job at 17:52:54Z). The same path has no finality input: an update applies through a pause app/igneum-app/src/manifest.rs:350-355 (daa + 1800 >= h), :322-347 (safe_to_apply, no finality), src/ota.rs:484, ui/app.js:217, docs/plans/release-0.3.14.md:79, release-0.3.15.md section 6 the project lead-visible 3 (close means within 1,800 blocks ahead and not behind 1; the publisher drops a passed activation_height 0.5; Moment.finality_paused holds a non-urgent update 1.5) app owner home miner, rig: no surprise restart mid-measurement or mid-pause; operator: an activation that has passed is not an emergency Unit tests: behind by any amount is not close; publish-manifest.sh refuses a passed height; a paused mock holds the update with the words "finality is paused; installing when it resumes"; the 0.3.16 manifest carries no stale height
5 Q5 The homepage says "final" while finality is paused, in a 90-word hero, under a share card that renders as a thumbnail. The chain scene takes src.locked and draws the dashed line labelled "final" at the newest locked block with no finality.active check (R4.6.3 was fixed on /live only); the hero is one 90-word paragraph with two bench deep links and "ships when the packaging row lands"; the miner section still says "a 24 GB NVIDIA card proves as well" while the hero and litepaper say 8 GB; home, litepaper, live and explorer share a 256 px og-small.png with summary cards site/index.html:810, 838 (final label), :345 (hero), :494 and site/miner.html:7, 13, 21, 265, 382 (24 GB), site/index.html:15-19 (OG) the project lead-visible 3 (final label 0.5, hero 1, 24 GB sentence 0.5, four 1200x630 cards 1) site owner every visitor; a holder or exchange reading "final" during a pause is the worst of them No "final" label while finality.active is false (the /live rule); hero under 40 words with one link; one proving-tier sentence on every page; every page's shared card is 1200x630
6 Q6 The hub shows stale data as live, said "active" for the first 20 unlocked checkpoints, says "paused" with no since or cause, and buried the pause under 401 miner_quiet and miner_back events. After the first load an API failure only changes the header to "offline: ..."; tiles, cards and "Refreshed" keep the old values. finality_active flips only after presence_window (20 on the devnet) indices without a lock, so 18:42 to 18:50Z read "active" in white with no lock forming. No finality_paused or finality_resumed event exists; live_events between 18:25Z and 21:30Z holds 203 miner_quiet, 198 miner_back, 55 difficulty, 30 checkpoint_locked (the last at 18:42:10Z) and no pause row. The checkpoint table also showed "% of active" above 100 (102.4 to 113.4 percent on indices 6900 to 6930) relay/ui.html:564 (stale), :367-368 (tile), relay/api/console.mjs:214, vendor/igneum-node-0310/consensus/src/processes/finality.rs:1794 and vendor/igneum-node/consensus/core/src/finality.rs:63, 75 (presence_window 240 mainnet, 20 devnet), tools/observer/observer.mjs:652 (the only finality event), live_checkpoints.fraction_active rows 6900 to 6930 the project lead-visible 4 (dim every panel with "last data N min ago" 1; amber on the first under-2/3 checkpoint 0.5; finality_paused and finality_resumed events, and collapse quiet/back pairs under 5 min 1.5; clamp or explain the active fraction 1) fleet agent (hub), consensus-engineer (observer events, the fraction) operator: the hub is the project lead's first screen; a holder reading the public API gets the same events Cut the network: every hub panel dims within 15 s; a forced Devnet 2 pause turns the tile amber on the first checkpoint under two thirds, posts one finality_paused event with the cause and one finality_resumed with the duration; no fraction above 100 percent on any row for 24 h
7 Q7 Discord said nothing. The bot has no credentials file and its timer is not installed, so tonight's pause produced zero posts; had it been live, a condition already firing at the watcher's first look is marked preexisting and never opens an incident; the pulse hides the pause in its description with no colour or title change docs/community/discord-hooks.md:81-82, tools/community/discord-hooks.mjs:481-485, :252-255, :158, infra/build-server/discord-hooks/install.sh the project lead-visible 3 (install and one live pulse 1; a pre-existing condition opens with "since at least " 1; paused pulse in a distinct colour with a title suffix 1) miner-community-lead (community owner) every Discord reader, which on launch day is every miner check prints three "set"; one live pulse in #numbers; a fixture where the pause predates the first tick opens an incident; the paused pulse renders amber with "(finality paused)" in the title
8 Q8 The relay's security fixes are not on master. Commit 28c028b (X23 to X28: relay/lib/guard.mjs, handler.mjs, run signatures, retention) is on fud-close and the ledger-* branches only; git merge-base --is-ancestor 28c028b master is false. On this tree any of the three intake keys (one ships in every miner app) can post, sync and delete console items, read the whole feed, and every client puts the token in the URL path relay/api/console.mjs:249, 283-301, relay/lib/relay.mjs:34-46, relay/clients/agent.sh:10, igneum-agent.ps1:13, 72, 154, tools/relay.mjs:24 operator-visible (security) 2 (merge or cherry-pick with the 47 relay tests 1; handler test that an intake key gets 403 on post, sync, delete 1) fleet agent (relay owner) operator: the console is the control plane for every PC and the fleet; a miner app's intake key is in every install 28c028b is an ancestor of the deploying branch; 47 relay tests pass; the handler test above passes; relay/README.md names the deployed commit
9 Q86 The fleet page is blind to the standing fleet, to death and to finality. page.py:43-47 publishes standing and devnet2 and the page references neither (grep 0); a dead box reads "running" for up to 20 minutes because state comes from boxes.json and standing.jsonl is never read; no fleet or console script reads finality_active, so tonight's pause was found by hand. The night the project lead ruled that 22 boxes stay up permanently, the page that shows them cannot show them igneum-wt-gpu-fleet/tools/fleet/page.py:38-47, dlsite index.html:243, lib/standing.py:54-56, tools/console.mjs:124 the project lead-visible 6 (standing block with USD per day and the Devnet 2 gate line 2; "unreachable since HH:MM" within 2 minutes 2; finality on the page and in console.mjs chain 2) fleet agent operator (the project lead reads this page every evening); every tier indirectly: a dead standing box is weight that left silently, the class of tonight's pause the page shows the standing count and spend; a box killed by hand reads "unreachable since" within 2 minutes; a forced Devnet 2 pause reads on the page and in the console
10 Q9 The wallet page describes 0.1.4 while UI 3 (five state words, light mode, pounds line) sits unmerged on wallet-ui-3; the MetaMask guide's testnet RPC is still labelled a placeholder, its devnet RPC port is the miner's node (26790) while a wallet-only Mac runs 26800, and wallet_addEthereumChain carries blockExplorerUrls: [] and no iconUrls, so MetaMask shows no explorer link and a blank icon site/wallet.html:261-266, 312, igneum-wt-wallet-ui/docs/plans/wallet-ui-3.md:93, 112, site/metamask.html:197, 225, 233, 285-286, igneum-wt-wallet/app/igneum-wallet/src/node.rs:24-26 the project lead-visible 6 (wallet 0.1.5 with UI 3 published and the page rewritten 4; guide: both ports, the placeholder line removed, explorer URL and icon in the request 2) app owner (wallet), site owner (guide) holder: the first non-miner product; a wrong port or a placeholder RPC is a dead end at the first step downloads.json wallet-mac 0.1.5; the page names pending, included, executed, proven, finalised; eth_chainId returns 0x116e from the guide's URL; MetaMask shows the explorer link after the add-chain button

Next in line, outside the ten: Q10 (the explorer knows nothing about finality and swallows failures after first load, 3 hours), Q80 (the Windows installer pipeline is dead on GitHub billing) and Q12 (Ember's light mode fails contrast on the private key and every live state).

Hours for the ten: 40 agent hours, plus the project lead's certificate purchases for Q3.

2. Tonight's pause on every surface (the ledger row the project lead asked for)

Times UTC. The chain-side facts are lane 3's (finality-and-weight.md 3.1) and the observer's own rows, read tonight: last lock 6842 at about 18:39:40Z; 6843 proposed at 53.1 percent of total; finality_active false from about 18:50Z (index 6862, twenty indices without a lock, presence_window 20); no lock after 6842 as of 20:05:03Z (live_state.updated_at), total_weight 7,167, active_weight 6,346 (88.5 percent signing on the sliding table), voters 85, and no finality_reason key in the stored JSON. Sampled live_checkpoints rows:

Index First seen State Signed, percent of total Signed, percent of active Votes
6820 18:28:30 locked 88.8 100.0 80
6840 18:42:10 (ingested after the hub came back) locked 79.5 98.6 83
6850 18:43:41 proposed 55.2 76.8 75
6880 19:00:22 proposed 50.1 81.2 49
6910 19:13:55 proposed 67.4 107.4 55
6920 19:19:07 proposed 74.8 113.4 78
6960 19:40:19 proposed 86.0 100.0 78
7010 20:04:32 proposed 87.7 99.1 73

From 6910 (19:13:55Z) every proposed checkpoint carried over two thirds of the sliding total and did not lock: the frozen table of Q5 held it (lane 3, 3.1). No surface could say so, because no field carries it. The "percent of active" above 100 on 6900 to 6930 is a display bug on the hub's checkpoint table (the active denominator lags the signers).

Surface What it showed 18:40Z to 20:05Z (from the code path and the rows above) Honest? Fix row
Ember (app.js:1350) "last lock #6842 · 1 h 25 min ago" with "a point the miners agreed can never be undone; locks at 2/3 of the 30-day weight". No pause word anywhere No: the age climbed and the note contradicted the state Q2
Site /live (live.html:512-520) Status LIVE, blocks flowing, finality bar grey, "finality paused: 45% of weight silent" at 18:50Z falling to "11% of weight silent" by 20:05Z, no final region, no checkpoint ticks; "last lock #6842, 1 h ago" in the stats (:404, no active check); a hovered checkpoint block still read "locked" (:450) Half: the pause is named (R4.6.3) but the percentage says the opposite of why it is paused once the stayers passed two thirds Q1
Homepage (index.html:810, 838, 879) Counter "last lock: paused"; the chain scene still drew the dashed line labelled "final" at the newest locked block No: "final" and "paused" on one screen Q5
Explorer (explorer.html, block.html) Identical to a normal hour; stars on locked checkpoint rows; block pages of ordinary blocks "not a checkpoint" No: nothing marked the pause Q10
Hub (relay/ui.html:367-368) 18:30 to 18:42Z: "observer STALE N s" in red, tiles frozen, finality "active" (the hub itself was down with the Mac). 18:42 to about 18:50Z: "active" in white, no lock forming. About 18:50Z onward: "paused" in amber, "last lock #6842" in amber, eight rows "proposed" at 53 to 89 percent, Events card full of miner_quiet and miner_back Half: paused, but no since, no cause, no end; active for ten minutes of no lock Q6
Discord Nothing: the bot is not live. Had it been: the 20:00Z pulse would have read "Finality paused since 2026-10-06 18:4x UTC: nothing is final until two thirds of the 30-day weight signs again; mining and proving are paid as usual" in the description, and the watcher would have marked the pause preexisting and never opened an incident No Q7
Wallet 0.1.4 (igneum-wt-wallet app.js:185, 340) Node card "paused" when a local node reports finality_active false, or "not checkpoint-checkable without a node" on the public RPC; transaction rows stay "in block N" with no mention Half Q35
Pool page (pool/web/index.html) Not deployed; the code has no finality concept; it would have confirmed and paid on blueness throughout n/a (a design choice, stated in Q50) Q50

The row for the ledger: Q1 plus Q2, Q5, Q6, Q7, Q10: every public and operator surface either hid the pause, named it without a cause, or contradicted it, for two hours, during the first finality pause the project has had in public. The gate across all of them is one forced pause on Devnet 2 with a screenshot of each surface, before the public testnet opens.

3. Per system

3.1 Miner app (Ember)

What it does today. A Rust engine (app/igneum-app/src/) runs igneumd and one GPU worker per card, serves a tokenised dashboard on 127.0.0.1 (src/server.rs:11-33, routes :184-359: api/state, api/log, detect, setup, key/saved, key/reveal, start, pause, resume, cards, tune/goal, settings, prove, update/check|install|auto|open, jobs/allow|check, power/apply|control, sweep/*, clock/*, quit). Screens (ui/index.html): Welcome (line 71), Cards (102), Address (127), the one-time key sheet (438), then a rail with Mine, Earnings, Prove, Settings (164 to 413), a log drawer (460), a status strip (Notices, ui/app.js:7-140) and an update card (UpdateCard, app.js:154-243). Ember Tune (src/ember.rs, src/sweep.rs, docs/plans/ember-tune.md) tunes power and clocks per card against a goal. Updates are Ed25519-signed manifests (src/ota.rs, src/manifest.rs). Hosts: app/mac/IgneumMiner.swift (WKWebView, menu bar), app/windows/host.cpp (WebView2, tray). The shipped build is 0.3.14 with miner-ui-3; 0.3.15 (miner-ui-4: the big-number hero and the chain scene) is staged, its canary failed on block version 1026 and was rolled back (release-0.3.15.md section 5). UI tests: 35 pass.

Comparators and the exact gap (all approximate, from memory of the products).

Comparator Their screen or feature Ours, and where it falls short
NiceHash QuickMiner Profitability per day in fiat on the main screen; Rig Manager web view of your own rigs Earnings reads "£0.00 earned: nothing is bought or sold on devnet" (index.html:250); mined IGN is never shown, only proving paid_wei (app.js:1364); no owner-facing remote view (the console is the operator's)
HiveOS Hash rate and temperature charts over hours; Telegram or Discord alert on a GPU fault or a rig offline; per-GPU fan and memory clock A 10-minute blocks strip only (app.js:1052-1127); no outbound alert; manual control is the power slider (app.js:1255); the memory knob exists in the engine with no control
lolMiner, T-Rex consoles Per-GPU accepted, rejected, invalid and faults on every status line Per card only "N blocks" (app.js:306); rejected_session a total in the hero sub-line (app.js:1290); mismatched= and faults=, which X21 made the engine read, never reach the row
Nanominer Restart-on-hash-drop watchdog with a visible threshold src/watchdog.rs exists; the row says "stopped after repeated faults" (app.js:296) with no count or threshold

Rows.

Id Row File or screen Severity Hours Owner Gate
Q2 Finality pause invisible (section 1) state.rs:247, engine.rs:3495, app.js:1350 the project lead-visible 3 app owner section 1
Q4 Every update urgent once the activation is behind; no finality hold (section 1) manifest.rs:322-355 the project lead-visible 3 app owner section 1
Q11 Offline start says "The update failed." A check error with no held manifest calls set_error; the cached manifest is loaded for the floor but never into self.manifest; the notice offers "Try again", which POSTs install ota.rs:649-654, 195-200, app.js:29, 1198 user-visible 1 app owner notices test: a check-class error renders "Could not check for updates" with no install action
Q12 Light mode fails contrast on every live text: molten #B8731F on white 3.81:1, on bone 3.38:1; ember #E04A14 on bone 3.61:1; molten carries the private key, the address and the live states. miner-ui-3.md section 9 claims 4.5:1 everywhere app.css:29, 263, 338, 431 user-visible 1 app owner a node script over the token pairs asserts 4.5:1 for every text token in both schemes; CI runs it
Q13 Per-card rejects and faults never reach the row (the lolMiner line) app.js:291-309, 1290 the project lead-visible on PC 1 2 miner-community-lead row meta "N rejected · M faults" when nonzero; view test
Q14 Windows first run raises a UAC prompt (firewall rule) before any screen explains it (part of Q3) ota.rs:981-1015, index.html:71-99 user-visible 1 app owner the firewall step runs after setup_done; the Cards screen names it
Q15 Mac first-run instruction stale: "Right-click > Open" (part of Q3) packaging/mac/README.md:51, site/miner.html download copy the project lead-visible on a fresh Mac 1 app owner the download page and README name the Privacy and Security step until the certificate lands
Q16 No rate history: a 10-minute strip against HiveOS's hours app.js:1052-1127 user-visible 4 app owner one-hour per-card sparkline from an engine ring buffer; view test
Q17 Hill climb hidden until tune_climb is on the state index.html:341, app.js:1407 operator-visible 1 app owner the row shows whenever the engine answers tune/goal
Q18 Earnings never shows mined IGN; "£0.00 earned" is the first number on the tab index.html:250, app.js:1364 user-visible 2 miner-community-lead the tab shows blocks mined and the subsidy they earned in IGN, with the devnet line under it
Q19 10 px type in five places, 9 px ruler app.css:196, 271, 272, 302, 491, 531 cosmetic 1 app owner no font-size under 11 px except the ruler
Q20 Design screens in docs/design/app-screens/*.png are a UI 1 app (v0.3.0 tiles, a Finality card the shipped UI lacks) docs/design/app-screens/ cosmetic 1 app owner screens regenerated from ?screen= on the current build
Q21 AMD step line prints a percent as watts ("owed: a unit word for AMD") ember-tune.md:278 operator-visible 1 miner-community-lead the line reads "70% (an offset)"; unit test
Q22 A code comment naming the founder ships in the UI bundle (// The list is ordered by performance (the project lead, 6 October 2026)), and the ui bundle is outside every forbidden-string check app/igneum-app/ui/app.js:270, tools/ci/identity-check.sh cosmetic (identity rule) 0.5 app owner tools/ci forbidden-string check covers app/igneum-app/ui/; the comment reads "(ruling of 6 October 2026)"
Q23 Two copy-law slips: "Votes lock the chain; leave it on." (aphorism), "The window can close. The miner keeps going" (two-beat) index.html:404, 81 cosmetic 0.5 app owner reworded; the grep below stays at 0 em dashes

Error states, exact strings. Engine down (four failed polls): pill "engine away" (app.js:1437); node line "Node: no answer", sub "the engine is not answering; the window reconnects by itself"; Mac host "The engine stopped. Quit and open Igneum Miner again." (IgneumMiner.swift:233); Windows "The engine stopped. Close this window and open Igneum Miner again." (host.cpp:301). Node down: "the node could not start" or the engine message, "the node is not running", "the external node went away" (app.js:452-453, engine.rs:3163); pill "node failed" (app.js:1428); digest box "the node is not running" (app.js:1341); canvas "waiting for the node to sync" (app.js:1099). Finality paused: nothing (Q2). Update server unreachable: "The update failed. Manifest signature: ." (app.js:1360, Q11). GPU lost: "Card removed: . Its worker stopped." (app.js:95), row word "removed", sub "unplugged; its worker stopped. The row goes in five minutes." (app.js:303); Code 43: ": not usable (Code 43). No worker runs on it." with "reboot with the card attached; if it persists, reinstall the driver with the card attached" (app.js:100, detect.rs:55).

Already better than the comparators. Automatic efficiency tuning against a goal with the money consequence on screen (app.js:408-419; 37 to 41 percent more hashes per watt measured on PC 1, ember-tune.md:254, 271). Signed, hash-checked, rolled-back updates with a safe-moment rule and machine slots (ota.rs, manifest.rs). A reason word on every zero rate and hot-plug words (ember-tune.md 6a). A virtualised log drawer with time jump and error marks (app.js:880-1050). Confirmations in place, no dialogs. A tokenised local API with origin checks (server.rs:102-125). Dark-scheme contrast is good: bone 17.4:1, ash 7.0:1, ember 5.6:1, molten 11.0:1 on obsidian (app.css:19). Focus rings, aria-live strip, labelled switches and sliders, reduced motion honoured on every animation (app.css:67, 113, 142, 148, 157, 420, 437, 466; app.js:1137). None of the four comparators ship the first two.

3.2 Wallet

What it does today. One desktop wallet (Igneum Wallet, Rust engine plus a local window; igneum-wt-wallet/app/igneum-wallet/: engine.rs, vault.rs, hd.rs, tx.rs, finality.rs, node.rs, updater.rs, server.rs; ui index.html, app.js, lock-screen.js, update-card.js), shipped as 0.1.4 (site/downloads.json wallet-mac, 19.6 MB; release-0.3.15.md:90). 0.1.5 (bundled 0.3.14 node, RPC on localhost) has a DMG and is unpublished (release-0.3.14.md:82). UI 3 is commit ab8dfdc on wallet-ui-3 and wallet-0.1.5, not on master. No wallet inside the miner app (it holds the payout key, wallet.json, and a button "Open the wallet" to the site, app/igneum-app/ui/app.js:826). No web wallet. A MetaMask guide (site/metamask.html), an address page (site/address.html, noindex, balance plus blocks mined), a marketing page (site/wallet.html). Keys: BIP-39 (12 to 24 words, hd.rs:23), BIP-44 Ethereum path; vault Argon2id 64 MiB, 3 passes, XChaCha20-Poly1305 (vault.rs:14-81); key zeroised on lock (engine.rs:392); 24 words shown once, three typed back (engine.rs:321); raw key export behind password or Touch ID (ui/index.html:271-275). Chain ids 4461, 4462, 4463 (metamask.html:233). Signing: EIP-1559 value transfers only; no EIP-712, no personal_sign, no contract calls, no dapp provider, no hardware wallet (spec 8.5 item 2 decided, not built; docs/fud-ledger.md:2058).

Comparators and the exact gap (approximate unless a standard is named).

Comparator Their feature Ours
MetaMask Account list and HD derivation; address book; speed up and cancel a pending tx; window.ethereum provider; eth_signTypedData_v4 One account (engine.rs:343 refuses a second import); an address field only (ui/index.html:177); no replace-by-fee; no provider; no EIP-712
Rabby Pre-sign simulation and recipient risk flags Review shows amount, fee and total (app.js:293-295)
Frame Ledger, Trezor, GridPlus signers; injected provider for any browser Neither (spec 8.5 "MUST offer", no code)
Monero GUI View-only wallet; subaddresses; a settable node address with status Node source engine-chosen, no settable endpoint (wallet-ui-3.md:112)
KDX, Kaspium Sync bar with peer count; per-transaction DAA score "reading the chain, N of M blocks" (app.js:175), no peer count
EIP-1193 request provider Used on the guide (metamask.html:294)
EIP-6963 Multi-provider discovery Absent; the guide falls back to whichever extension owns window.ethereum (:292)
EIP-3085 wallet_addEthereumChain with blockExplorerUrls, iconUrls blockExplorerUrls: [], no icon (:225, 285-286)

Rows.

Id Row File or screen Severity Hours Owner Gate
Q9 Page vs UI 3; guide placeholders; empty explorer URL (section 1) site/wallet.html, site/metamask.html the project lead-visible 6 app owner, site owner section 1
Q30 Private key export copies to the clipboard with no clear and no timer igneum-wt-wallet/.../ui/app.js:129, 463 user-visible 2 app owner clipboard cleared after 60 s by the host; unit test on the timer
Q31 Wallet OTA trusts one key; no revoked_keys, unlike the miner's updater docs/plans/consequences-2026-10-05.md:36, updater.rs:7, 729 operator-visible 3 app owner updater carries OTA_PUBLIC_KEYS [K1, K2] and honours revoked_keys; the three-key test of the rig installer
Q32 No hardware wallet path despite spec 8.5 "MUST offer" docs/spec/08-client-security.md:36 the project lead-visible 24, or 0.5 to relabel app owner (cryptographer reviews) a Ledger signs one devnet transfer through the Ethereum app at chain id 4463; or the spec row reads "Designed, not shipped"
Q33 Single account, no second address, no address book engine.rs:343, ui/index.html:177 user-visible 6 app owner two derived accounts, a saved recipient reused in Send
Q34 confirm() on Remove wallet never renders in the Mac host app.js:598, wallet-ui-3-audit.md:189 user-visible 1 app owner in-page two-step card; snapshot test
Q35 Finality pause: node card "paused" or "not checkpoint-checkable without a node", rows stay "in block N"; public-RPC mode never says what to do wallet app.js:185, 321, 340 user-visible 2 app owner the row reads "in block N; finality is paused on the network" and the public-RPC line names the fix with a button
Q36 Reorged-out transaction: "in a block" then the row vanishes; no resend hint app.js:340, docs/fud-ledger.md:2154-2158 user-visible 3 execution-engineer (node side), app owner (the row) a transfer unwound in the P23 conformance run shows "reorged out, resending" and ends executed
Q37 The address page shows no finality state and "n/a" with a bare reason for balance site/address.html:205-209, 242-252 cosmetic 2 site owner the page shows the latest locked checkpoint and whether finality is active
Q38 The permanent phishing sentence differs between surfaces ("words or your key" on the wallet, "your key" in the miner) against spec 8.5's one verbatim sentence site/wallet.html:366, wallet ui/index.html:54, app/igneum-app/ui/index.html:97, 08-client-security.md:39 cosmetic 0.5 site owner, app owner one sentence, grep-identical on all three
Q39 Vault file permissions not set explicitly (no 0o600 in vault.rs) vault.rs operator-visible 0.5 app owner the file is created 0600; test

Error states. Node down: pill "no node", balance note "waiting for a node" (app.js:160, 176), the node line's raw engine message (:186; UI 3 replaces it with "the node stopped answering; trying again", wallet-ui-3.md:199). Pending versus final: "PENDING, waiting for a block", "IN A BLOCK, chain block N; final once a verified checkpoint covers it", "FINAL, under checkpoint N, certificate verified by this wallet", "FAILED, the execution failed; the fee was still paid" (app.js:340). Address page: "The API did not answer: " (address.html:270), "Not found." (:247). MetaMask page: "No Ethereum wallet found", "Waiting for the wallet...", "Cancelled in the wallet.", "The wallet refused: " (metamask.html:292-296).

Security notes. Plaintext key only in engine memory, zeroised on lock and after each sign (engine.rs:392, 563); the window never holds the key (nonce-gated reveal, server.rs:108); local API on 127.0.0.1 with a random port, per-run token path and a host token (server.rs:1, 39, 71); chain id checked at quote and send (engine.rs:549). Testnet RPC is https (testnet-go.md:13); devnet is http to 127.0.0.1. Chain ids 4461 to 4463 were absent from chainid.network on 3 October (docs/design/execution-layer.md:354), not yet registered (frontier.md:645); from memory no listed chain uses them (approximate).

Already better. The wallet verifies finality certificates itself with the node's consensus code (finality.rs:101-121) and never trusts the RPC's "locked"; MetaMask and Rabby trust the RPC's block tag (approximate). Touch ID is bound to the exact quote (address, value, nonce, chain id) with a 30 s one-use nonce (engine.rs:539). Argon2id at 64 MiB is above MetaMask's PBKDF2 default (approximate). The QR is drawn locally as SVG with the ethereum: URI and a checksummed address (server.rs:140). The MetaMask page says plainly that nothing on it asks for a seed (metamask.html:172).

3.3 Hub and relay

What it does today. One Vercel project (igneum-relay, Neon database, Blob store; relay/README.md:3-5). relay/ui.html (583 lines) is the console at /r/<token>/ (relay/vercel.json:5-8); relay/index.html is a placeholder. Functions: relay/api/relay.mjs (feed, items, files, inbox, register, name, role), relay/api/console.mjs (machines, jobs, builds, chain, log, results, tuning), relay/api/wake.mjs (public long-poll for the apps' jobs file, 30 a minute per IP, relay/lib/wake.mjs:15, 42-54). Auth: the 20-character token in the path or x-relay-token, or any of RELAY_KEY, LOG_INTAKE_KEY, LOG_INTAKE_KEY_NEXT in x-igneum-key (relay/lib/relay.mjs:34-46); only task, a run or task drop, name, role, delete demand the token (relay/api/relay.mjs:114-115). Two job models: relay run items polled every 20 s by relay/clients/igneum-agent.ps1:165 and executed as administrator; and signed app jobs in igneum-jobs.json, whose status the console derives from miner_logs rows (relay/api/console.mjs:172-188). Seven tabs (relay/ui.html:186-192): Machines, Jobs, Builds, Chain, Work log, Results, Relay; refreshed every 15 s when visible (:577), server cache 10 s (console.mjs:21). Chain tiles: blocks, identities, hash estimate, difficulty, last lock, finality, peers, blocks per second (:363-370). Mac tools: tools/relay.mjs, tools/console.mjs, tools/jobs.mjs. Tests: 24 pass per file (node --test relay/test as a bare directory fails under Node 22.23.2 with MODULE_NOT_FOUND; the README's command needs the glob).

Comparators and the exact gap (approximate).

Comparator Their screen Ours
Tailscale admin console, Machines Last seen, OS and version, key expiry with "Disable key expiry", tags; an ACL editor with tests Last seen and a red card after 180 s (relay/ui.html:270, 273); no credential state (one static token, relay/lib/relay.mjs:36), no per-machine key, no revoke; roles are labels never checked (relay/api/relay.mjs:191-195)
GitHub Actions job view Live streaming log with line anchors, per-step timing, re-run, artefacts, annotations at the top One text blob in a modal (relay/ui.html:319); duration_s and the error lines that tools/jobs.mjs:41-44 already parses are discarded by console.mjs:184-187; no re-run; results are separate items
Vercel deploy log Build steps, deployment list, instant rollback, diff between deployments Builds tab shows the current manifest, the last CI fetch, 40 posts and a folder listing (relay/ui.html:323-341); no rollback, no manifest history, no diff

Rows.

Id Row File or screen Severity Hours Owner Gate
Q6 Stale shown as live; "active" for 20 unlocked indices; "paused" with no since or cause; event flood (section 1) relay/ui.html:564, 367-368 the project lead-visible 4 fleet agent, consensus-engineer section 1
Q8 X23 to X28 fixes off master; intake key can write and delete; token in URL (section 1) relay/api/console.mjs:249, relay/lib/relay.mjs:44 operator-visible 2 fleet agent section 1
Q40 A hung job reads "running" forever: no elapsed time, no timeout, no "last line N min ago" relay/api/console.mjs:182-187, relay/ui.html:317 the project lead-visible 2 fleet agent a killed job reads "no report for 12 min" in red within one refresh
Q41 Jobs tab trusts the unsigned igneum-jobs.json while the apps verify the signed file relay/api/console.mjs:170 vs tools/jobs.mjs:57-60 operator-visible 1.5 fleet agent the tab shows the envelope's signature state per file
Q42 Job result modal: no error lines first, no duration, no anchors (the Actions view) relay/ui.html:319, console.mjs:184-187 the project lead-visible 3 fleet agent a failed run opens with its five error lines and its duration first
Q43 Machines: no per-machine key state, no revoke, roles never enforced (the Tailscale view) relay/lib/relay.mjs:14, relay/api/relay.mjs:191-195 operator-visible 3 (after Q8) fleet agent a revoked PC's register is 403 and its card says "key revoked"
Q44 Builds: no rollback, no manifest history (the Vercel view) relay/ui.html:328-341 operator-visible 4 fleet agent one tap republishes the previous manifest and the fleet's OTA state shows it
Q45 "live feed unreachable: live feed unreachable" doubled; the whole Chain tab empties, losing Events and the infra card relay/api/console.mjs:210, relay/ui.html:357 cosmetic 0.5 fleet agent live feed down: tiles grey, Events and infra card still render
Q46 Replay: register and task have no nonce; a captured task POST re-queues a run relay/api/relay.mjs:153-167 operator-visible (security) 1 fleet agent a replayed task is refused; test

Error states. Relay API unreachable: header "offline: Failed to fetch" and a grey dot (relay/ui.html:564, :32); the panel is replaced only while it still shows "loading". Node down: a machine card goes red after 180 s with "silent 4h" (:270, 273; SILENT_S, console.mjs:35); a deliberate stop reads "stopped (quit) 2h ago" (relay/lib/parse.mjs:134-140); the live API down reads "live feed unreachable: " (:357); the observer stale reads "observer STALE N s" in red after 30 s (:361, site/api/live.mjs:8) while every tile keeps its last value. Finality paused: tile('finality', f.active ? 'active' : 'paused', ...) in amber #FFB35C (:368, :17, :65); the "last lock" tile amber too (:367); eight checkpoint rows with state and fraction (:374). Job hang: "running" until a SUMMARY with finished_at arrives (console.mjs:179-182); relay run items show "read" and never "done" (tools/relay.mjs:58).

Security, X23 to X28 on this tree. X23: the tier split exists (relay/api/relay.mjs:114-115), no run signature, no per-machine HMAC, the intake key still writes the console (console.mjs:249). X24: every client builds /r/$TOKEN/api (agent.sh:10, send.sh:11, igneum-agent.ps1:13, tools/relay.mjs:24, tools/console.mjs:27). X25: Arm-Restart at top level and /RL HIGHEST (igneum-agent.ps1:154, 72). X26: feed to 500 with no retention; delete leaves blobs (relay.mjs:48, 148-152); __DL_BASE__ substituted into bodies (tools/relay.mjs:79). X27: from is free text, register for any hostname (relay.mjs:30, 153-167). X28: constant-time compare and HSTS present (relay/lib/auth.mjs:5-11, relay/vercel.json:38-41); still a GET that acks (relay.mjs:85), RELAY-REBOOT anywhere in output (igneum-agent.ps1:133), no rate limit, NOPASSWD:ALL (wsl-setup.ps1:40), sudo -S with the password (prover-setup.ps1:21). All of this is what Q8 merges.

Already better. One phone-first page, no login flow, seven tabs, 15 s refresh (relay/ui.html:5, 577); Tailscale, Actions and Vercel each take several screens on a phone (approximate). The machine card fuses miner STATUS, node log, app telemetry and OTA state and remembers an OTA line after it scrolls out (console.mjs:61-84); no comparator shows workload telemetry. Stale marking at 180 s drops the card from the total; stopped and silent are distinct words (parse.mjs:16-21, 134-140). Drop-anywhere upload direct to Blob with a progress bar and a 50 MB cap (ui.html:506-534). The wake long-poll is dependency-free and tested with a fake clock (relay/lib/wake.mjs). Headers: nosniff, frame DENY, noindex, no-referrer, no-store, HSTS on every path (relay/vercel.json:21-43).

3.4 Site

What it does today. Thirteen static pages plus 404 (site/index.html, litepaper.html, live.html, bench.html 611 KB rendered from docs/bench-log.md, evidence.html, ledger.html 312 KB generated, miner.html, miners.html from miner-bench.json, wallet.html, metamask.html, faucet.html, explorer.html, block.html, address.html). site/build.mjs:49-50, 357-372 injects partials/head.html (self-hosted fonts, tokens), nav.html, footer.html, stamps download links from downloads.json, inlines journey.json. scrub.mjs runs on bench and miners only (build.mjs:171, 401). Live data: index polls /api/live every 2 s (index.html:704; 10 s while off); the light client fetches /api/checkpoint and imports two noble libraries from cdn.jsdelivr (verify/verify.js:5-6); live.html polls every 2 s (:665-666); faucet POSTs /api/faucet. APIs (site/api/): live, stats, supply, explorer, checkpoint, faucet, log, all reading Neon tables written by tools/observer. Edge cache: live 1 s, stats and supply 10 s, explorer 5 s (vercel.json). The live HTML (one curl, 20:02Z) is 60,009 bytes, served with HSTS (preload), X-Frame-Options: DENY, nosniff, Referrer-Policy: strict-origin-when-cross-origin, no CSP; download buttons stamped "v0.3.14 · 45.4 MB"; "Public testnet: not yet open; the devnet build is here for people who want to look."

Comparators and the exact gap (approximate unless a page is named).

Comparator Their page or element Ours
kaspa.org, ethereum.org A Developers or Docs nav item Nav is Litepaper, Live devnet, Engineering log, Miner, Wallet, Evidence, GitHub (partials/nav.html:14-21); builders land on a litepaper section (index.html:335)
getmonero.org/downloads Every platform, hashes and signing keys on one page Split across index.html:363-365, /miner#get, /wallet; the homepage's Linux and HiveOS button links /miner#get, not a file; sha256 shown only for the HiveOS package (miner.html:558), none beside the Windows and Mac buttons, no signing key, no verify line
z.cash, aztec.network Named people, a transparency page "one founder, pseudonymous" once in the litepaper; the Reddit review's key-powers table (round 4, section 3 row 8) absent
kaspa.org, getmonero.org Media kit, press kit, language switch, newsletter None (site/ has no /press or /brand)
ethereum.org, kaspa.org Light and dark Dark only; only the litepaper honours prefers-color-scheme
succinct.xyz, aztec.network 1200x630 share cards Home, litepaper, live, explorer use 256 px og-small.png with summary (index.html:15-19); miner, wallet, bench, evidence use the large card

Lighthouse, estimated from source (approximate; no run). Common: lang="en", a skip link (partials/nav.html:1), one :focus-visible ring (head.html:22), self-hosted fonts with font-display:swap, two preloads and fallback metrics (head.html:1-19), no render-blocking third-party CSS, canonical, description, OG and twitter tags on every page.

Page Performance Accessibility Best practices SEO What holds it down
index.html 78 to 85 88 95 92 89 KB HTML, 35.0 KB inline JS, 24.0 KB CSS; two rAF canvas loops at display rate with no visibility or intersection stop (:790, 853, 857); 2,880 px webp with no srcset; h3 before the first h2 (:344, 359); ember on bone 3.08:1 at 15 px in the light section (:119-120), eyebrow #7A776F on bone 3.97:1 at 12 px (:130); 256 px OG card
explorer.html 88 to 93 90 100 85 32 KB, no images, no third party; aria-live="polite" on an 8-tile strip refreshed every 10 s (:222); not in the sitemap
live.html 85 to 90 88 100 85 64 KB, 35.6 KB JS; the canvas loop is capped at 30 fps and stops off screen (:605-612), good; aria-live="polite" on the 8-cell strip every 2 s (:225); canvas aria-hidden with no text alternative (:241)

Rows.

Id Row File or screen Severity Hours Owner Gate
Q5 "final" during a pause; 90-word hero; 24 GB contradiction; thumbnail OG (section 1) index.html:345, 494, 810, 838, 15-19 the project lead-visible 3 site owner section 1
Q50 No downloads page: hashes only for HiveOS, no signing key, no verify line, the Linux button goes to an anchor index.html:363-365, 516, miner.html:549-558 user-visible 2 site owner /download lists every artefact with version, size, sha256, the OTA key fingerprint and a verify command per OS; the Linux button links the file
Q51 /miners has 6 rows, two card models, "not measured" MH/W on every row; the eleven-card fleet table is not ingested miners.html:183, miner-bench.json user-visible 2 miner-community-lead rows carry W and MH/W for every measured card
Q52 dl\.igneum in forbidden-strings.txt matches the public download host on three built pages; the scrub guards only bench and miners forbidden-strings.txt:25, build.mjs:171, 401 operator-visible 0.5 site owner the pattern becomes dl\.igneum\.network/dl/(?!public/) or /dl/[0-9a-f]{12,}, and the check runs on every built page
Q53 Sitemap misses /miner, /explorer, /faucet, /ledger; every lastmod is 4 or 5 Oct; 404 says "These four pages are everything the site has" sitemap.xml, 404.html:138 cosmetic 0.5 site owner the sitemap is generated by the build from the page list
Q54 aria-live="polite" on strips refreshed every 2 s and 10 s (a screen reader hears eight values every refresh) live.html:225, explorer.html:222 user-visible 0.5 site owner aria-live="off" on the strips plus one polite status line on state change
Q55 Homepage canvases never stop off screen or cap their rate index.html:790, 853, 857 user-visible 1 site owner 30 fps cap and IntersectionObserver as live.html:605-612
Q56 Light-section contrast fails (3.08:1 links, 3.97:1 eyebrow) index.html:119-120, 130 cosmetic 0.5 site owner AA on every token pair; the same node script as Q12
Q57 "devnet v0" eyebrow on the live page; the chain is v4 live.html:219 cosmetic 0.1 site owner matches the app's network word
Q58 Heading order (h3 before the first h2) index.html:359 cosmetic 0.2 site owner h2 or a styled div
Q59 No team, custody or key-powers page (Reddit round 4 artefact 8); "0 admin keys in consensus" tile unchanged index.html:611; no file user-visible 1 (plus the project lead's policy call) site owner the key-powers table published; the tile links it
Q60 Roadmap dates versus the testnet: the journey says "Public testnet, Aug to Oct 2027" and the litepaper "Pools and the public testnet are August 2027", while docs/plans/testnet-go.md has igneum-testnet-1 seeds up and a go checklist dated 5 October 2026 index.html:679, litepaper.html:719, docs/plans/testnet-go.md:1-4 the project lead-visible 0.5 (after the project lead decides which is true) site owner one date for the public testnet on the journey, the litepaper and the download notice
Q61 No Content-Security-Policy header on the site (the relay has none either); inline scripts throughout, two pinned CDN modules on the homepage site/vercel.json:7, relay/vercel.json:31-43, verify/verify.js:5-6 operator-visible (security) 2 site owner a CSP with hashes or nonces for the inline scripts and script-src limited to self and cdn.jsdelivr; every page renders with no console violation
Q62 Copy-law borderline headlines: "Mined by GPUs. Proven by fire." (the brand line, the project lead's call), "GPUs are back · for good", "Last hour's chip is already obsolete.", "Your coins. Final means final.", "Dates slip. Gates do not.", "Install. Start. The card mines and proves.", "Nothing is mined here." index.html:343, 344, 424, wallet.html h1, litepaper.html:678, miner.html h1, 404.html h1 cosmetic 1 site owner (the project lead rules on the brand line) each either kept by the project lead's word or reworded

Reddit round 4, still open in the HTML. Finding 6 (24 GB): half fixed (Q5). Finding 7 (eleven-card table): open (Q51). Finding 8 (admin keys): sentence added to the litepaper (:659), tile unchanged, no table (Q59). Finding 15 ("Monero's idea, finished for GPUs"): open (index.html:444, litepaper.html:429). Finding 16 ("devnet v0"): open (Q57). Finding 22: /ledger present, no nav item. Findings 2, 3, 5, 9, 10, 12, 13, 17, 19: fixed in the current files. "0% anyone else in the protocol" legend still live (index.html:604).

Error states, exact strings. API unreachable: /live after three failed polls shows "OFFLINE", "api unreachable", the canvas frozen with "api unreachable, scene frozen" (live.html:665, 600); /explorer writes the fetch error into the table on first load and is silent after (:342-345); /block "The API did not answer: " (:328); the homepage "simulated preview · live feed unavailable" and "Live feed unavailable. This is a simulation and its counters count simulated blocks." (index.html:870-872). Observer stale over 30 s: "OFFLINE", "observer updated N min ago", "observer offline, last update N min ago" (live.html:663); explorer eyebrow "observer offline, last known" (:318); homepage "simulated preview · observer offline, last update N s ago" (:708). Finality paused: section 2.

Already better. Self-hosted latin subsets with preloads and computed fallback metrics (head.html:1-19); ethereum.org and kaspa.org load heavier bundles (approximate). Zero third-party scripts except the two pinned noble modules; no analytics, no cookie banner. Honest live states: "simulated preview · observer offline", "finality paused: N% of weight silent", "api unreachable, scene frozen"; Etherscan shows nothing when its indexer lags (approximate). A browser-side BLS certificate verifier on the homepage (verify/core.js), which no comparator homepage has. A public API with a CI field contract (api/stats.mjs:10-14) and supply derived from the emission rule with an hourly coinbase check. HSTS with preload, frame DENY, nosniff, immutable font caching, skip link, reduced-motion rule on every page. A dated journey with pass or fail gates inlined at build, and a ledger page of every criticism; none of the six site comparators publish the equivalent.

3.5 Explorer

What it does today. explorer.html polls /api/explorer?blocks=50 every 5 s and /api/stats plus /api/supply every 10 s (:342-343); block.html fetches ?block= or ?height= once (:276); address.html fetches ?address= once; /block/:id and /address/:addr are Vercel rewrites. Search classification is client-side (lib/explorer.mjs:19-27: hash, 0x address, bech32, height) with a server fallback for tx hashes (api/explorer.mjs:49-59). The data window is 24 hours of observer rows; balance needs EXPLORER_EVM_RPC, unset on the devnet deployment (docs/plans/explorer.md section 7).

Comparators and the exact gap (approximate).

Comparator Their feature Ours
Etherscan, Blockscout A transaction page: decoded input, logs, status, fee None; a tx hash lands on /block/<hash>#tx-<hash> (api/explorer.mjs:57); block.html:310 lists hash, from, to, value, bytes, with from and to "needs an EVM RPC" when unset
Etherscan, Blockscout Address page with transactions, token transfers, nonce, contract tab Blocks mined, 24-hour earnings, balance only with an RPC (address.html:209, 281)
Blockscout Hosted API reference (Swagger), rate-limit statement A card on /explorer (explorer.html:232-240) and docs/api/public-stats.md in the repo
explorer.kaspa.org DAG view inside the explorer; merge-set order per block DAG view lives on /live; block page has blue work, parents, children, mergeset blues and reds (block.html:285-325), no prev and next navigation
mempool.space Mempool as the product, fee charts Mempool count is one tile on /live (live.html:233); no charts on the explorer
All four Per-block status (final, confirmations) None for an ordinary block (Q10)

Rows.

Id Row File or screen Severity Hours Owner Gate
Q10 No finality state; failures swallowed (named under the ten in section 1) api/explorer.mjs:16-25, explorer.html:222, 309, 342-345 user-visible 3 site owner during a forced pause every block row carries "paused" and the strip tile reads the Q1 reason; cut the API: the table dims with "api unreachable, last update N s ago" within 10 s
Q63 No tx page, no hosted API reference api/explorer.mjs:57, explorer.html:232-240 user-visible 4 site owner /tx/<hash> with status, fee, from, to, input bytes, shard and proof state; /api page with every field and the cache times
Q64 Address page: no transaction list, no finality (Q37 covers the finality half) address.html user-visible 3 site owner the last 50 transfers in and out, each with its block and state word
Q65 No prev and next block navigation; no block-by-height neighbours block.html cosmetic 1 site owner two links from selected_parent and the first child
Q66 Blocks per second inverted against the other pages ("1.2 s per block" vs "0.9 blocks / s") and difficulty "126.81 M" with a space against "126.81M" on /live explorer.html:330-331, live.html:329 cosmetic 0.5 site owner section 4.3's one formatter

Already better. Block page depth for a DAG: parents, children, mergeset blues and reds, selected parent, shards with prover and lag, checkpoint weight fractions and certificates (block.html:285-325); explorer.kaspa.org shows less of the mergeset (approximate). Client-side search that accepts a height, a hash, an 0x or bech32 address with no round trip (lib/explorer.mjs:19-27). Five-second edge cache with a stale flag from the observer, so a stale page says so on first load.

3.6 Pool

What it does today. igneum-pool, a Rust crate (pool/Cargo.toml, 12 source files) speaking the spec 09 protocol in its v0 form: newline JSON over plain TCP (pool/src/server.rs:1-2, protocol.rs:1-9), the project's own message set (hello, welcome, authorize, seeds, template, job, share, share_result, solution, stats; protocol.rs:21-170). Every share is CPU-verified on the node's warp verifier (verify.rs:52-64; 1.35 ms isolated, 2.1 ms under load, docs/plans/pool.md section 5). PPLNS only, window in blocks of weight, default 2 (pplns.rs:1-5, config.rs:67); fee 1 percent, minimum payout 1 IGN (config.rs:65-66); EIP-1559 transfers from the pool's coinbase key, at most 16 per round, failed receipts re-credited (payout.rs:197-299). One page, pool/web/index.html, baked into the binary (api.rs:166-174): a stat strip, connect card, address lookup, blocks, payments, API card. Stats API /api/stats, /api/blocks, /api/payments, /api/miners/<addr>, /api/pool-stats, /health (api.rs:185-200) with fixture-pinned field contracts (api.rs:255-272). Operator surface: a STATUS line every 30 s on stdout (main.rs:152-174). Deployment: a written, unexecuted systemd unit behind Caddy (pool/README.md:75-116; "not executed", docs/plans/pool.md section 8). Nothing is deployed. The horizon tree equals igneum-wt-pool-rebase HEAD 269364a.

Comparators and the exact gap.

Comparator Their feature Ours
2miners Per-worker hash rate charts over time; payout history per miner; worker-offline alerts by email or Telegram; estimated earnings per day; luck A single 10-minute and 1-hour number, samples kept 15 minutes and not persisted (state.rs:704-705, 779-781); the API returns 50 payments and the page renders none of them (api.rs:148, web/index.html:181-194); no contact field (protocol.rs:50-60); no earnings estimate; luck defined inverted against MiningPoolStats' convention (api.rs:72-74)
WoolyPooly Solo mode; worker offline alerts scheme hard-coded "pplns" (server.rs:53, api.rs:80); no alerts
Kaspa acc-pool (approximate) Prometheus and Grafana No /metrics; stdout only
Stratum v2 reference (github.com/stratum-mining/stratum, not cloned, approximate) Noise-encrypted transport, job negotiation, binary framing, header-only mining Plain TCP while spec 9.3 demands TLS 1.3 and binding is sent empty (server.rs:1-2, protocol.rs:58-60, 09-pool-protocol.md:37, 43, 49); mode A only; JSON lines, and the template ships the whole RpcRawBlock to every member every second (node.rs:147-164)

Rows.

Id Row File or screen Severity Hours Owner Gate
Q67 Member transport is plaintext TCP against spec 9.3's TLS 1.3 with session binding; binding ignored server.rs:1-2, 115, protocol.rs:58-60 user-visible (hijack risk) 8 consensus-engineer rustls listener; a replayed authorize on a second connection is refused (O-9.7)
Q68 Node down shows "difficulty 0, DAA 0" and a ramp-day-0 reward; no "node unreachable" state node.rs:350-368, web/index.html:163-164 the project lead-visible (once deployed) 2 miner-community-lead the page renders "Node unreachable since
Q69 Raw integers (DAA, block count, shares) with no separators; difficulty uses toLocaleString() with no locale, so it varies by browser; hash rate 2 decimals against the site's 1 web/index.html:152, 163, 172, 190 the project lead-visible 1 miner-community-lead every number formatted as section 4.3 says
Q70 Ledger is a JSON file rewritten every 15 s; hash-rate samples and check cost not persisted, so a restart zeroes every rate tile and the 24-hour luck state.rs:704-710, main.rs:131-144 user-visible 4 miner-community-lead restart test: tiles recover within one sample window; README names the loss window
Q71 Address lookup never shows the payment history the API returns api.rs:148, web/index.html:181-194 user-visible 1 miner-community-lead payments table under the lookup
Q72 No per-miner history, no charts, no worker-offline notice, no /metrics; /health always ok state.rs:779-781, web/index.html:187, main.rs:152-174, api.rs:195 user-visible, operator-visible 4 + 4 + 2 + 1 miner-community-lead hourly buckets per address kept 7 days with a sparkline; opt-in webhook after 10 min silence; Prometheus text endpoint; health reflects net.synced and template age
Q73 Finality: the pool confirms and pays on blueness and has no finality concept; the page says nothing during a pause (a design choice to state) node.rs:279-345, server.rs:9 user-visible 1 miner-community-lead the page carries the network's finality state and the sentence "payouts follow blue confirmation, not finality"

Already better. Every share CPU-verified at the node's own engine, no sampling (verify.rs:52; spec 9.8 item 5); most pools trust the miner's claim for low-difficulty shares (approximate). The member's vote key rides in every header it hashes (node.rs:47), so pool concentration does not become vote concentration; no Stratum pool does this. PPLNS split snapshotted at find time, credited only on blue confirmation, orphans pay nobody (state.rs:821-852). Failed payout receipts re-credit the balance (payout.rs:288-292). Exact binary share weights (vardiff.rs:138-140). Field contracts pinned by fixture tests.

3.7 Discord

What it does today. tools/community/discord-hooks.mjs (798 lines, Node 22, no dependencies). Webhook URLs in ~/.config/igneum/discord (:18-19, 41, 520); state in ~/.config/igneum/discord-hooks-state.json. Posts: network pulse to #numbers at 03:00, 09:00, 15:00, 21:00 UK (shapePulse :236-273); daily digest 09:00 (:276-299); weekly numbers Monday 09:00 (:302-352); release to #announcements by the shipper (:394-409); incident open and resolve to #incidents by hand or by the watcher (:412-433). Watcher conditions: finality_paused (5-minute hold), proof_lag (900 s), observer_silent (180 s) (WATCH :37, :437-472); one incident per condition, resolved after 120 s clear (:490-503). Idempotency keys per post (:562, 569); 429 backoff (:534-551); a forbidden-string guard before every post (:47-96); allowed_mentions: {parse: []}. Runner: a systemd timer on igneum-build-1, tick --live every minute (infra/build-server/discord-hooks/). Per docs/community/discord-hooks.md:81-82, no live post has been made and the install has not run. Tests: 31 pass; every live poster is stubbed.

Comparators and the exact gap (approximate).

Comparator Their feature Ours
Ethereum, Kaspa, Monero Discords Ticker bots renaming channels with height, hash rate, price None; a webhook cannot rename a channel, a bot token is needed
The same Embed colour by severity; a pinned current-status message; "resolved" as an edit of the open message Single ember colour for every kind (:33, 158); no pin; resolve posts a second message (:706-712)
The same Explorer links per block or lock Only /live and /miner links (:271, 297, 350, 420, 432)
The same Reorg or stall alerts No condition for a block-production stall (the fixture shows 11 zero minutes at 18:30 to 18:41Z) or a reorg (:437-472)

Rows.

Id Row File or screen Severity Hours Owner Gate
Q7 Bot not live; pre-existing never opens; pulse hides the pause (section 1) discord-hooks.mjs:481-485, 252-255, 158 the project lead-visible 3 miner-community-lead section 1
Q74 No block-production stall condition, the actual first signal of tonight's 18:30Z gap :437-472, fixtures/discord/live.json user-visible 2 miner-community-lead blocks_stalled condition, 3 minutes, fixture test
Q75 Resolve posts a new message instead of editing the open one :706-712 cosmetic 2 miner-community-lead PATCH /messages/<id> with the resolve fields
Q76 Embeds link only /live and /miner; the last lock could link /block/<hash> :271, 297, 350 cosmetic 1 miner-community-lead last lock links its block page
Q77 "Last lock" names 93 voters while the hash-rate field says 56 vote keys active; readers will ask :259, 262 user-visible 1 miner-community-lead one clause explains the two counts, or one number
Q78 Four semicolon-balanced two-beat sentences in the shipped incident texts ("Blocks keep being produced; the chain is not locking checkpoints", "finality pauses rather than locks on a minority", "Vote keys are not machines; the machine count is owed", "Blocks are produced and final as usual; their proofs arrive late") :347, 448, 452, 458 cosmetic 0.5 miner-community-lead reworded as single statements

Already better. Release embeds carry the full sha256 of every artefact plus the exact verify commands (:399-406); most project bots post a link. Every post passes a guard that refuses the founder's name, hosts, IPs, paths, webhook URLs and mentions (:47-96). Every number names its API field and the posts link the raw JSON (:314-341). Incident texts state who is affected per tier (:449, 458, 467). A dry-run HTML preview renders the exact card before anything goes live (:602-634).

3.8 Fleet tooling

What it does today. On the gpu-fleet branch (/Users/joshm/Projects/igneum-wt-gpu-fleet/tools/fleet/, read-only; the horizon tree holds only publish-fleet.sh): providers vast.py (console.vast.ai v0: filtered bundle search :47-54, rent with optional onstart :61-72, instances, destroy, a price-stamped ledger.jsonl :88-102) and runpod.py (:27-44); the orchestrator fleet.py (rent-card, wait, setup, status, run, pull, destroy, tail, sh, dn2-version, list; :5-13, 183-187); the shared library the 6 October rule demands, lib/box.py (Box.run/put/alive, install_payload sha-checked, stop_node/start_node, height/daa/peers/synced/wait_synced, exec_status/exec_tip/proving_status/paid_segments/paid_shards/state_root, node_version, rejects_since, max_reorg_since, start_miner/stop_miners/start_prover/stop_all, destroy; Registry) and lib/standing.py (roster, install, check, update, rerent, loop, weight_check); lib/test_box.py runs against dn2-3 with one known-failed case (:10-12) and a PASS line (:37), by hand, not in CI. Box side: 20 box-*.sh scripts (setup, matrix, ember, prover, dn2, standing supervisor, node-swap, exec-snapshot, wave, wave-pool, pool, rig, rig-prover, rehearsal, kill, datadir, floor-v5, segal-host) plus dn2-kill.sh, dn400-worker.sh, rehearsal-kill.sh. Collectors: collect.py, bps-collect.py, night.py (60 s probe, 15-minute rows, exec-reset re-run :45-55), autorun.py, restage.py, swap.py. Gates: devnet2-gate.sh (PASS = zero rejects, max reorg under 4, version equal, exec roots equal at a common height, one paid segment; :92-100), canary.sh, canary-next.sh. Page: page.py builds fleet.json; publish-fleet.sh copies it and runs a full Vercel production deploy (:10); publish-0315.py is the first standing publish. PC job runner tools/build-job.mjs (run, publish, watch, fetch, verify; targets ae432dc7 and 1ccfe586; signed kinds run, fetch, collect, restart, update-now, shard-benchmark, build; --stop-miners becomes stop_miners_first, consumed at app/igneum-app/src/jobrun.rs:563). Console tools/console.mjs (post, log, machines, chain, jobs, builds, tuning, results, sync, url). CI checks in tools/ci (22): bash-body, check-workflow-shell, commit-string, copied-sources, identity-check, install-hooks, kit-path, link-check, no-conflict-markers, no-foreign-tree-writes, no-secrets, override-json, pinned-guests, playbook-quit, prover-socket, ps-drive-ref, public-api-check, second-engine, signer-pipe, windows-spawn, plus fixtures; pgrep-self-match-check.sh exists on gpu-fleet only (its ci.yml:82-83), not on horizon or master.

Comparators and the exact gap (approximate unless cited).

Comparator Their feature Ours
Vast CLI search offers with any filter expression; create instance --onstart; logs without ssh A fixed filter set (vast.py:47-52); rent-card never passes onstart (fleet.py:79), so install is a second ssh step (:102-109); tail needs ssh (:180)
SkyPilot Declarative task YAML, autostop -i, spot recovery, sky status, sky logs Imperative; one-shot boxes have no autostop (the caps at page.py:45 are display only; 59 boxes running at 20:02Z); recovery is standing.loop after two dead checks at 600 s (lib/standing.py:126-140); check prints raw dicts (:148)
Nomad Restart policy: attempts, interval, delay, mode; allocation health in the UI box-standing.sh restarts every 60 s with pkill -9, no cap, no backoff, no failure count (:33, 46-49, 70)
HiveOS farm view Per-rig cards: hash, temps, fan, accepted and rejected, last seen, flight sheets, bulk actions The fleet page card shows card, state pill, "doing", USD/h, hours only (dlsite index.html:176); standing.py:56 strips the miner= field the supervisor writes (box-standing.sh:64 has MH/s, accepted and rejected, GPU util, watts); console.mjs:114-116 has the HiveOS-style row for the app machines, not for rented boxes

Rows.

Id Row File or screen Severity Hours Owner Gate
Q86 The fleet page is blind to the standing fleet, to death and to finality. page.py:43-47 publishes standing and devnet2, and the page's index.html references neither (grep 0; it reads boxes, results, phases, night, log, :243); a dead box reads "running" for up to 20 minutes because state comes from boxes.json (page.py:38) and standing.jsonl is never read; no fleet or console script reads finality_active (only bps-collect.py:30 tails "Finality:" log lines), so tonight's pause was found by hand (CLAUDE.md, the standing-fleet rule) page.py:38-47, dlsite index.html:243, lib/standing.py, tools/console.mjs:124 the project lead-visible 6 (standing block, USD per day, Devnet 2 height and last gate line 2; "unreachable since HH:MM" from standing.jsonl within 2 minutes 2; getFinalityCheckpoints in the standing check and "finality paused since, reason" on the page and the console 2) fleet agent the page shows the standing count and spend; a box killed by hand reads "unreachable since" within 2 minutes; a forced Devnet 2 pause reads on the page and in console.mjs chain
Q87 rerent does not set up or supervise the new box: the docstring promises both (lib/standing.py:14-16), the code rents and patches rows (:78-91); a re-rented card bills idle lib/standing.py:78-91 the project lead-visible (spend) 2 fleet agent the new label shows synced and mining on the page within the install time
Q88 One-shot boxes have no autostop; cap_vast 1000 and cap_runpod 500 enforce nothing (page.py:45; vast.py:61-72 has no cap check) page.py:45, vast.py:61-72, autorun.py the project lead-visible (spend) 1.5 fleet agent autorun destroys a one-shot box N minutes after its done line; rent refuses above the cap
Q89 Supervisor restart loop without backoff or a failure line box-standing.sh:46-49 operator-visible 1.5 fleet agent after N failures a standing_node_failed line and a page flag
Q90 Dropped miner and GPU facts: standing.py:56 strips miner=; gpu= never parsed lib/standing.py:56, box-standing.sh:64 operator-visible 1 fleet agent MH/s, accepted and rejected, watts per box on the page (the HiveOS card)
Q91 A transient ssh drop counts as death: Box.run returns 124 on timeout (lib/box.py:49), check_one marks dead on any rc (standing.py:54), the loop never asks the provider (fleet.py:48-60 refresh_ssh unused); Vast proxy drops are known (canary.sh:41) lib/box.py:49, lib/standing.py:54 operator-visible 1 fleet agent provider status consulted before a dead check counts
Q92 lib/test_box.py pins a stale binary and digest (:31 igneumd-0313, :34 digest 4a0b8726; 0.3.15 is 06211d55, publish-0315.py:15) and is not scheduled lib/test_box.py:31-34 operator-visible 1.5 fleet agent a nightly PASS line on the page
Q93 The Devnet 2 gate reads no peers, no finality, no exec blocked (read_box, devnet2-gate.sh:51-53; night.py:15 reads blocked, the gate does not) devnet2-gate.sh:51-53 operator-visible 2 fleet agent FAIL on 0 peers or finality paused at step 4
Q94 publish-0315.py hard-codes one worktree and release (:14-18); page.py:13 points at the master checkout's publish script; every publish is a full Vercel deploy publish-0315.py:14-18, page.py:13, publish-fleet.sh:10 cosmetic 2 fleet agent publish.py reads paths and sha from the release manifest; the page deploys as one file
Q95 Five 6 October rule rows have no tools/ci check and are therefore OPEN by the project's own rule (table below) CLAUDE.md 6 October rules, tools/ci/ operator-visible 5 (1 each) fleet agent (consensus-engineer for the gate check) each check fires on a known-failed fixture and passes a known-good one

The 6 October rules against their checks.

Rule (CLAUDE.md, 6 October 2026) Check today What the check is
pgrep -f with a literal pattern is banned pgrep-self-match-check.sh on gpu-fleet only; absent from horizon and master merge it; wire it in ci.yml on master
Box operations live in one tested library none; devnet2-gate.sh:40-41 and canary.sh:32-33 define their own SSH() and SCP() past lib.box fail any file outside tools/fleet/lib that runs ssh -i ~/.ssh/igneum-fleet
A watcher verifies the chain-side fact and is trusted only after a known-finished and a known-failed case none; devnet2-gate.sh and canary.sh have no --self-test a --self-test flag on every gate with both fixtures
A standing box never leaves the live chain for an experiment; never remove over 10 percent of weight in an hour weight_check exists (standing.py:108-125) but nothing enforces its call; Box.destroy (box.py:136) has no standing guard destroy refuses standing rows; CI greps that scripts calling stop_miners on a label call weight_check first
No live build before the Devnet 2 PASS line none; devnet2-status.json last_gate reads "not run during the block-rate experiment" the ship script requires PASS <sha16> in devnet2-status.json, as commit-string-check runs inside build-remote.sh
Have checks commit-string, override-json, ps-drive-ref, no-foreign-tree-writes, playbook-quit, second-engine

Error states, exact strings. Console machines (tools/console.mjs:114): STOPPED (<reason>) <ago> ago, SILENT, live, then seen <ago> ago, synced or not synced; cards (stale, not in the total) and | <fault> (:115). Console chain (:124): last lock #N (blue N) | lag Ns STALE; no "paused" word in console.mjs (the web tile has it). fleet.py: no ssh (:116), ssh timeout (:118), scp failed (:106, 133), pull failed: ... (:145). lib/box.py: (124, "", "timeout") (:49), SshError("<label>: rc N: <err>") (:53). standing.py: re-renting <label> -> <new> (:134), behind: <label> <sha> wanted <sha> (a publish script moves it; the loop only reports) (:137; "behind" is the binary sha, never height), standing check: N boxes, N alive, N synced, N behind (:138). Fleet page: the state pill (renting, installing, running, done, failed) and doing text only; no dead, behind or finality string exists. devnet2-gate.sh: FAIL <box>: N rejected blocks, FAIL <box>: a selected-chain reorg of depth N, FAIL <box>: version V, FAIL <box>: exec root at height H ... differs, FAIL no segment record paid on any box during the run (:92-100).

Already better. Every rent and destroy writes a price-stamped ledger line (vast.py:43-45, runpod.py:25-26), which Vast's CLI does not (approximate). The Devnet 2 gate compares exec state roots across every box at one height (devnet2-gate.sh:98-99), beyond any SkyPilot or Nomad health check. Gates read chain facts (height, paid segments, reorg depth), not process names. The supervisor runs the exec-recovery recipe by itself (box-standing.sh:66-67). The 10 percent weight rule is a real function (standing.py:108-125). The console distinguishes stopped-on-purpose from silent (parse.mjs:134-140).

3.9 The node's operator surface

What it does today. Fork-added flags (igneum-wt-ship0315/vendor/igneum-node-0315/kaspad/src/args.rs): --devnet-suffix, --evm-rpclisten (default 26790), --evm-disable, --override-params-file, --igneum-exec-snapshot (:297), --ua-rule (:440), --rocksdb-wal-dir (:502), --devnet alias --igneum-devnet. Kept from kaspad: --loglevel with per-subsystem <subsystem>=<level> (kaspad/src/args.rs:262-271), --perf-metrics (:446, debug lines only), --utxoindex, --rpclisten-borsh, --rpclisten-json, --externalip, --appdir. Env knobs: IGNEUM_PROOF_VERIFIER, IGNEUM_PROOF_VERIFY, IGNEUM_DEVNET_GENESIS_BITS, IGNEUMD_DEVNET_BPS, IGNEUM_POW_STRIKES and IGNEUM_ATTACK_TS_OFFSET_MS (feature-gated after X19). Finality logs (consensus/src/processes/finality.rs): Finality: checkpoint {i} determined: block {h} (blue score, daa) (:625), Finality: certificate at index N received: X of Y voters, weight A of B (:1127), Finality: CONFLICTING certificate at index N (:1023), Finality: no body tip passes through locked checkpoint ...; fork choice falls back to depth finality (:1448). No pause or resume log line; "paused" exists only as the polled RPC reason (window filling, N of M, active, paused; igneum-node-0310 finality.rs:1794-1807); the conflict reason is "O-3.17, not reported yet". RPC getFinalityCheckpoints returns finality_active, finality_reason, window_filled_daa, window_full_daa, latest lock (rpc/core/src/model/finality.rs:293-299); no provisional field, no frozen-table share. Exec JSON-RPC on one listener: igneum_getExecStatus (executedTip, blocked, startedFrom), igneum_getProvingStatus, igneum_getFinalityView, igneum_submitProofRecord (igneum/exec/src/rpc.rs:858-979). Metrics: no Prometheus endpoint (no hit in the fork's Cargo files). X19 (docs/fud-ledger.md:1936-1946): a slow clock disconnecting peers silently, time_offset unused, attack env compiled in, a dead override field; fixed on branch ledger-fixes-0311 fbb0082a (one WARN per minute clock-skew line, attack env behind attack-switches, override refuses the field), pending merge; not done: the local-ahead mirror case, the faketime run, the skew field in getBlockDagInfo (docs/plans/node-changes.md:18-19).

Comparators and the exact gap. kaspad parity holds (vendor/rusty-kaspa/kaspad/src/args.rs:241 loglevel, :259 rpclisten-borsh, :348 utxoindex, :392 externalip, :401 perf-metrics) but the fork's own subsystems (finality, exec, proving) got no new knobs. geth (approximate): --metrics with Prometheus or InfluxDB, --log.format json, --http.api allowlist; the fork has none, and writes on the EVM listener share it with reads (rpc.rs:920). reth (approximate): --metrics, RUST_LOG env filter, reth db stats, Grafana dashboards in the repo; the fork has no DB tool or dashboards. monerod (approximate): status, runtime set_log, limit_rate, sync_info; the fork's log level is start-only, no bandwidth limit, status is igneum-miner watch plus getConnectedPeerInfo.

Rows.

Id Row File or screen Severity Hours Owner Gate
Q96 No log line on a finality flip: an operator tailing the log never sees the pause begin or end consensus/src/processes/finality.rs (no pause line) operator-visible 1.5 consensus-engineer fast-time simnet prints Finality: paused (<reason>) and Finality: resumed at index N, one line per flip
Q97 finality_reason says paused and nothing else: no share that left, no frozen-table hold, no expiry, no conflict reason (O-3.17) (the node half of Q1) finality.rs:1794-1807 the project lead-visible (through every surface) 1.5 (counted in Q1) consensus-engineer tonight's pause reads "paused: 42.7 percent of weight left the window; held by the table frozen at lock 6842 until DAA 216,402"
Q98 No /metrics: finality_active, latest lock, exec tip, blocked, paid segments, peers, DAA as Prometheus gauges (the axum listener exists) igneum/exec/src/rpc.rs operator-visible 3 execution-engineer curl :26790/metrics scraped by a Grafana dashboard committed under infra/
Q99 Log level is start-only; no runtime change (monerod set_log, reth env filter) kaspad/src/args.rs:262-271 operator-visible 2 consensus-engineer an RPC or SIGHUP changes the level without a restart
Q100 Clock-skew field in getBlockDagInfo and the local-ahead mirror case still owed after X19 docs/plans/node-changes.md:18-19 operator-visible 2 (after the ledger-fixes-0311 merge) consensus-engineer faketime -60s gives one WARN and the field
Q101 No --evm-rpc-api allowlist: submit and export share the listener with eth_ reads rpc.rs:920 operator-visible (security) 2 execution-engineer a public listener answers eth_ and refuses igneum_submitProofRecord
Q102 No JSON log format: collectors grep four reject patterns (lib/box.py:119) kaspad logger operator-visible 2 consensus-engineer --log-format json; the gate reads a field, not a pattern
Q103 No igneumd db subcommand (column sizes, exec snapshot tip, finality blob layout) none operator-visible 3 execution-engineer igneumd db stats on a devnet datadir
Q104 Merge ledger-fixes-0311 (X19) into 0.3.16 docs/fud-ledger.md X19 operator-visible 1 consensus-engineer the faketime WARN on the shipped binary
Q105 Eleven fork .rs files carry an em dash, one inside a log or help string (upstream origin not verified, approximate) igneum-node-0315 (a grep for the character) cosmetic 0.5 consensus-engineer 0 in any string the operator can see

Already better. finality_active ships with a reason string, which kaspad, geth and reth have no analog for. --ua-rule version admission (args.rs:440-445) is beyond kaspad. A fixed-height activation is refused by rule; the override file is refused on a dead or duplicate field. Every build binary carries its commit or fails CI.

3.10 Downloads, install and the update flow

What it does today. site/downloads.json (updated 2026-10-06T17:48:20Z) lists four artefacts: Windows installer 0.3.14 (45.4 MB), Mac DMG 0.3.14 (41.9 MB), HiveOS package 0.3.14 (24.7 MB), Mac wallet 0.1.4 (19.6 MB), with sha256 and size, under https://dl.igneum.network/dl/public/ and four stable aliases under /public/ (packaging/README-ship.md, "The public downloads path"). tools/ship-app.mjs cuts a version in eleven checked, resumable steps (preflight, bump, inputs, commit, ci, fetch, dmg, copy, manifest, deploy, verify, console; README-ship.md). The Windows installer is built only by windows.yml on GitHub-hosted runners; since 19:24Z tonight every hosted job dies at start ("recent account payments have failed or your spending limit needs to be increased", release-0.3.15.md 6a), so no Windows installer can be cut until billing is fixed. 0.3.15 is staged with --until manifest; its Devnet 2 canary failed (block version 1026 on the thirteen-field file) and was rolled back. The ship tool's commit step pushed the release tree to master although the run had --branch release-0.3.15 (release-0.3.15.md 6a).

Signing and notarisation state. macOS: codesign -s - (ad hoc) on every binary and the bundle (build-dmg.sh:118-122); no Developer ID, no notarisation, no stapling; the engine strips com.apple.quarantine from its own bundle on start (main.rs:78, packaging/mac/README.md:51-53). Windows: unsigned installer and exes; SmartScreen "Windows protected your PC" (packaging/windows/README.md:76, 111; build-installer.ps1:188); the installer is per-user (PrivilegesRequired=lowest) so no UAC for install; the firewall rule asks once, 20 to 50 s in (ota.rs:981). Comparators: Signal and Tailscale ship Developer ID-signed, notarised DMGs and Authenticode-signed installers; both open with no interstitial (approximate).

The update flow today, precisely (the baseline for frontier 3.7, reproducible-build attestations with N of M).

Step What happens Where
1. Build Node fork and workers built on igneum-build-1 (Linux, Windows cross) and the Mac (macOS); Windows exes reproducible (-Wl,--no-insert-timestamp); a binary whose strings lack its commit fails tools/ci/commit-string-check.sh. The Windows installer and payload zip are built by windows.yml on GitHub-hosted windows-latest from payload-inputs.zip, whose payload-inputs.json (sha256 and size of the zip and every file, fork commit, repo commit) is signed on the Mac with the OTA key and verified in CI against the key compiled into the app and the pin packaging/windows/node-source.pin before anything is built (G13, fixed 5 October; 16 local tests pass) tools/build-remote.sh, cross-remote.sh, packaging/windows/push-inputs.sh, .github/workflows/windows.yml, docs/fud-ledger.md G13
2. Sign One Ed25519 key, generated once on the Mac (4 October 2026), seed in ~/.config/igneum/ota-signing-key (0600), never in the repo or CI; public key the constant OTA_PUBLIC_KEY_HEX in app/igneum-app/src/manifest.rs:28; igneum-ota-sign sign over the canonical manifest bytes (64-byte detached signature, igneum-app-latest.json.sig); publish-manifest.sh refuses to sign when the embedded key is not the one in ~/.config/igneum. Rotation = a bridge build with the new constant signed by the old key. The wallet's updater trusts one key with no revocation list (Q31). Key not in hardware (G7 says it will be) packaging/ota/README.md "Keys", publish-manifest.sh
3. Publish Manifest (version, per-platform url, sha256, size, kind, min_supported_version, notes, activation_height) and .sig to dl.igneum.network/dl/<token>/igneum-app-latest.json, public copy under dl/public/; the apps' long-poll on the relay's /wake fetches it within seconds; the igneum-jobs.json channel uses the same key packaging/ota/publish-manifest.sh, publish-public.sh, relay/api/wake.mjs
4. Check On start (20 to 50 s in) and hourly with jitter; both files through curl; signature verified over the manifest bytes before parsing; a bad signature reads "manifest signature does not verify" and the manifest is never parsed; a version not newer, or a manifest without this platform, ends the round ota.rs:144, 628, 1038-1048, manifest.rs:114-120, 175-178
5. Download and verify Into <app data>/app/updates/ with resume and --retry 3; size and sha256 from the manifest ("sha256 mismatch: the file is not what the manifest signed"); the Mac re-hashes before mounting ota.rs:1054-1079, 1124
6. Stage macOS: mount, copy to .Igneum Miner.app.new, run its engine with --version and demand the manifest's version; an unwritable folder gives manual and "Open the download". Windows: the installer is the staged file ota.rs:1096, packaging/ota/README.md "Stage"
7. Safe moment Not urgent: network has not lost over 30 percent of identities in 10 minutes, this machine's minute of the hour, node synced, no hourly boundary within 180 s, no worker starting; a ready update applies anyway after 6 hours. Urgent (fork within 1,800 blocks, unsupported version, Install now) skips every guard. Q4: a passed activation counts as close; no finality input; 0.3.15 adds "never while a remote job is active" manifest.rs:322-355
8. Apply The engine writes update-pending.json, starts the helper and exits through its quit path (miners 8 s, node 30 s, last log upload). macOS helper swaps bundles, strips quarantine, reopens, restores .previous on failure. Windows helper runs the per-user installer /VERYSILENT ... /IGNOTA=1 first, with the engine still mining, then the installer stops the engine and relaunches packaging/ota/README.md "Apply", ota-apply.sh, ota-apply.ps1
9. Rollback The new engine counts starts in update-pending.json; a third start without 90 healthy seconds restores the previous version ("rolled back" in Settings); the first Windows update from 0.3.0 has no rollback target ota.rs:371
10. What the user sees "Igneum Miner X is available.", "Downloading X: N%.", "X is ready.", "Installing X. The app restarts itself. Mining continues until then.", "X did not stay up and was rolled back.", "updated to X from Y" in the event feed; Settings: Check now, Install now, automatic switch, the key fingerprint under "Allow remote jobs from Igneum (signed)" ui/app.js:29-52, index.html Settings
11. Second engine, paused finality A sweep or IGNEUM_APP_NO_OTA=1 engine never runs the updater (engine.rs:601, 778; the 5 October rule). Nothing in the update path reads finality (Q4)

So the trust today is one key, one builder (the box and the Mac, both the project's), one manifest, no attestation by anyone else, no on-chain record, and the client installs whatever that one key signs at the moment the safe-moment rule allows. That is the baseline frontier 3.7 moves from: N of M attestations in a registry contract, the updater refusing under N, and no install while finality is paused.

Rows.

Id Row File or screen Severity Hours Owner Gate
Q3 Signing and notarisation; first-run prompts (section 1) build-dmg.sh:118-122, windows.yml the project lead-visible 6 plus certificates app owner, the project lead section 1
Q80 The Windows installer pipeline is dead: every GitHub-hosted job fails at start on billing; the installer and payload zip have no other builder, so 0.3.15 and every hotfix are Mac and HiveOS only until the project lead fixes Billing & plans, or the installer step moves to igneum-build-1 (Inno Setup under Wine, or a self-hosted Windows runner on PC 1) release-0.3.15.md 6a, .github/workflows/windows.yml, packaging/windows/build-installer.ps1 the project lead-visible 0 (the project lead: billing) or 4 (installer step on the box or PC 1 as a signed job) app owner; the project lead a green windows.yml run, or tools/ship-app.mjs --dry-run showing the fetch step satisfied from the new builder
Q81 The ship tool pushes master whatever --branch says (the 19:30Z push of the release tree to master) tools/ship-app.mjs commit step operator-visible 1 app owner --branch X pushes X; a test on a scratch repo
Q82 The download page shows no hash for Windows and Mac, no OTA key fingerprint, no verify command; the stable aliases are not explained (Q50 covers the page; this row is the artefact side) miner.html:549-558, packaging/ota/publish-public.sh user-visible 1 site owner igneum-downloads.json carries the fingerprint; the page prints it with shasum -a 256 and certutil -hashfile lines
Q83 The update key is one software key on one Mac, not in hardware, against G7's "held in hardware and its policy published" packaging/ota/README.md "Keys", docs/fud-ledger.md G7 operator-visible (security) 3 (a YubiKey or Secure Enclave signer behind igneum-ota-sign, the policy page) cryptographer, app owner a release signed with the hardware key installs; the key policy is a public page; the software seed is retired
Q84 An activation height in the manifest outlives its activation and turns every later update urgent (the Q4 class, publisher side) publish-manifest.sh --activation-height operator-visible 0.5 app owner the publisher refuses a height at or below the live DAA and drops a stale carried-over one

First 60 seconds, fresh Windows PC (from the code and the READMEs): download Igneum-Miner-Setup-0.3.14.exe from /miner, SmartScreen interstitial "Windows protected your PC" (More info, Run anyway), per-user install with no UAC, "Start Igneum Miner now" (Igneum-Miner.iss:86), tray "Igneum Miner: starting", Welcome, Cards (detect runs on entry, app.js:641), Address, the one-time key sheet, "Start mining"; between 20 and 50 s in, a UAC prompt for the igneumd.exe inbound firewall rule arrives on top of whatever screen is up (ota.rs:981; declined = the node dials out, never asked again); closing the window gives "Igneum Miner keeps mining" (host.cpp:354). Fresh Mac: DMG, drag to Applications, Gatekeeper refuses the ad hoc app (macOS 15 has no Right-click > Open; the user must find Privacy and Security > Open Anyway, approximate), "Starting the engine" (IgneumMiner.swift:146), quarantine cleared from the bundle (main.rs:78), the same three screens, a menu-bar item with "Pause mining". Both tiers of card see the same screens; an 8 GB card gets two vote identities and a 24 GB card eight (detect.rs), which no screen explains (the "a card runs several" line lives on the site, not the app).

4. Cross-cutting

4.1 Accessibility (estimated from HTML and CSS)

Surface Contrast Keyboard Screen reader Motion
Ember dark bone 17.4:1, ash 7.0:1, ember 5.6:1, molten 11.0:1 on obsidian: passes :focus-visible ring (app.css:66), rail arrow keys, Escape on the card and quit (app.js:681-688, 979) aria-live="polite" strip (index.html:50), role="dialog" aria-modal (:419), radiogroup with aria-checked (:194), labelled switches and sliders; gaps: the blocks canvas aria-hidden with no text alternative (:241), the drawer a div with no landmark, user-select:none on body (app.css:36) reduced motion honoured everywhere (app.css:67, 113, 142, 148, 157, 420, 437, 466; app.js:1137)
Ember light molten #B8731F on white 3.81:1 and on bone 3.38:1; ember #E04A14 on bone 3.61:1: fails AA on the key, the address and every live state (Q12) same same same
Site dark passes (ash 6.97:1, ember 5.64:1 on obsidian); the homepage light section fails on links 3.08:1 and the eyebrow 3.97:1 (Q56) skip link and one focus ring on every page (nav.html:1, head.html:22); explorer rows clickable with the hash link as the keyboard target aria-live="polite" on strips refreshed every 2 and 10 s (Q54); aria-live="off" on the homepage live strip, correct; the DAG canvases aria-hidden with no alternative reduced-motion rule on every page (head.html:62); live.html caps 30 fps and stops off screen; the homepage does not (Q55)
Hub amber #FFB35C and red on graphite pass (approximate from the tokens, relay/ui.html:17, 65) buttons and tabs are native elements; no skip link no live regions; the console is an operator tool none needed
Pool page default light tokens, not audited beyond the formats native none none

4.2 Copy law

The em dash character, counted per shipped file: 0 in every site/*.html and site/partials/*.html, 0 in app/igneum-app/ui/index.html and app.js, 0 in relay/index.html and relay/ui.html, 0 in pool/web/index.html, 0 in tools/community/discord-hooks.mjs, 0 in app/mac/*.swift and app/windows/host.cpp, 0 in every app/igneum-app/src/*.rs user-facing string, 0 in the wallet's ui/. The rule holds everywhere that ships.

Forbidden strings (site/forbidden-strings.txt, 25 patterns) per shipped file, with what each hit is:

File Pattern Count What it is
site/index.html dl\.igneum 2 the public download aliases (:514-515); the pattern is meant for the token path (Q52)
site/miner.html dl\.igneum 5 the same aliases and the HiveOS installation URL (:549-557)
site/wallet.html dl\.igneum 1 the wallet alias (:371)
site/downloads.json dl\.igneum 1 the base field
relay/ui.html Hetzner 1 the "Hetzner network" card title (:377); private console, rule does not apply, but one word
app/igneum-app/ui/app.js the project lead 1 a code comment (:270); the ui bundle is outside every check (Q22)
tools/community/discord-hooks.mjs MacBook, \+0100, tailscale, ts\.net, dl\.igneum 1, 1, 1, 1, 2 the guard's own regexes (:51, 59, 61), the read-only fleet URL (:31), and ts\.net matching "stats.net" in a template (:255): false positives, none posted
pool/README.md Hetzner, /opt/igneum, CLAUDE\.md 5, 2, 1 the deploy section; not a site page, but it would fail the scrub if copied

Every other pattern is 0 on every file. Two-beat antithesis and aphorisms in shipped copy: the headlines listed in Q62, the two Ember lines in Q23, the four Discord incident sentences in Q78.

4.3 Consistency of numbers across surfaces

Quantity Site home Site live Explorer Ember Hub Discord Pool page
Hash rate fmtHash: 1 decimal, MH/s or GH/s only, "pending" when null (index.html:719) 1 decimal, kH to TH, unit in <small> (live.html:329, 652) 1 decimal, kH to PH, integer under 1 kH/s (lib/explorer.mjs:62-67) 1 decimal MH/s (app.js:1450) 2 decimals GH/s, 1 decimal MH/s (relay/ui.html:246) 1 decimal MH/s, 2 decimals GH/s (discord-hooks.mjs:101-109) 2 decimals once scaled (web/index.html:152)
Blocks per second toFixed(1) "blocks / s" (index.html:375, 722) toFixed(2) (live.html:228, 650) inverted: "1.2 s per block" (explorer.html:331) not shown toFixed(2) (relay/ui.html:370) 6-hour window not shown
Height, counts toLocaleString('en-GB') "chain block" (index.html:377) compact() "110.0k blocks" (live.html:229, 651) full digits "Height" (explorer.html:212, 328) withCommas nf() separators en-GB separators (:99) raw integers, no separators (web/index.html:163, 172)
Difficulty not shown compact() "126.81M" "126.81 M" with a space compact() nf() 6-hour delta toLocaleString() with no locale
Miner count "vote keys active in 10 min (a card runs several)" (index.html:374) "Identities" (live.html:232), table heading "Miner" (:254) not shown "ids" per card "identities 10 min" "56 vote keys active" and "93 voters" in one post (Q77) "Miners / workers"
IGN not shown not shown reward 4 decimals, supply integer 4 decimals (app.js:1364) 2 decimals (fmtIgn) 4 on tiles, 6 in tables
Price none anywhere; "pounds a day" once (index.html:510); Ember has a priceNow() with a devnet zero
Finality "#N" or "paused" (index.html:879) "#N, 3 min ago" plus the bar (live.html:404, 512) none "#N · 1 h ago" (app.js:1350) "active" or "paused" "checkpoint 6,842 at 55.x% of weight, 1 h ago, 93 voters" none

Row Q85 (cross-cutting, 2 hours, site owner with the app owner): one shared formatter module (site/lib/format.mjs) for hash rate (1 decimal, unit ladder kH to PH), counts (en-GB separators, never compact() for the same quantity shown in full elsewhere), blocks per second (2 decimals, never inverted), difficulty (one spelling), IGN (4 decimals on tiles, 6 in tables), and one word for a vote identity ("vote key" on every surface); the app, hub, Discord and pool copy the same table as a Rust and a JS constant, with a test that renders the fixture values identically. Gate: the fixture renders byte-identical on all seven surfaces. Severity: the project lead-visible (he reads three of these side by side every evening).

4.4 Error states, one table

Condition Ember Site home Site live Explorer Hub Discord Wallet Pool
Node down "the node is not running", pill "node failed", "waiting for the node to sync" "simulated preview · observer offline" after 30 s "OFFLINE", "observer offline, last update N" "observer offline, last known" card red "silent 4h"; "observer STALE N s" observer_silent after 180 s (not live) "no node", "waiting for a node" "difficulty 0, DAA 0", no word (Q68)
API or relay unreachable "The update failed." (Q11) "live feed unavailable" "api unreachable, scene frozen" error on first load, silent after (Q10) "offline: Failed to fetch", stale panels (Q6) n/a "The API did not answer: ..." (address page) "stats unavailable"
Finality paused nothing (Q2) "paused" counter, "final" label (Q5) bar "finality paused: N% silent" (Q1) nothing (Q10) tile "paused", no cause (Q6) nothing (not live), preexisting (Q7) "paused" or "not checkpoint-checkable" nothing (Q73)
GPU lost "Card removed: . Its worker stopped." card telemetry drops member drops from the count
Job hung "job running" notice "running" forever (Q40)

4.5 First-run and update flow

Section 3.10 carries both in full. The two facts to carry forward: a fresh machine on either OS meets two warnings before the first screen (Q3), and the update flow is one software key, one builder, one manifest, with a stale activation height that makes every update urgent (Q4, Q84) and no attestation by anyone outside the project (the frontier 3.7 baseline).

5. Already best in class (honest both ways)

  1. Ember Tune: automatic per-card efficiency tuning with the money consequence on screen, measured 37 to 41 percent more hashes per watt on PC 1 (ember-tune.md:254, 271). No miner console ships it.
  2. The update path: Ed25519-signed manifest verified before parsing, sha256 of the artefact, staged swap, safe-moment rule, machine slots, automatic rollback after two failed starts (ota.rs, manifest.rs). HiveOS and NiceHash update without a safe-moment rule (approximate).
  3. The wallet verifies finality certificates itself with the node's consensus code (finality.rs:101-121); Touch ID is bound to the exact quote (engine.rs:539). No mainstream EVM wallet does either (approximate).
  4. The site: self-hosted fonts with fallback metrics, zero third-party scripts beyond two pinned modules, no analytics, no banner, HSTS preload, honest live states, a browser-side BLS verifier on the homepage (verify/core.js), a dated journey with gates and a public ledger of every criticism.
  5. The block page: parents, children, mergeset blues and reds, selected parent, shards with prover and lag, checkpoint fractions and certificates (block.html:285-325).
  6. The pool: every share CPU-verified at the node's own engine; the member's vote key in every header it hashes (node.rs:47), so pool share never becomes vote share.
  7. Discord: full sha256 and verify commands in every release post; a forbidden-string guard on every post; incident texts that say who is affected per tier.
  8. The hub: one phone-first page with every PC's miner, node, app and OTA state fused on one card, stopped and silent as different words, drop-anywhere uploads.
  9. The relay's wake long-poll: dependency-free, fake-clock tested, 30 a minute per IP.
  10. The ship pipeline: eleven checked, resumable steps with secrets scrubbed from every line and a signed inputs manifest verified in CI before any build (G13).

6. Open questions and what could not be run

  • The pause's end was not observed: at 20:05:03Z (live_state.updated_at) no lock after 6842 had formed. Lane 3 expects the frozen table to expire at DAA 216,402, about 20:40Z. Whoever reads this after 21:00Z should add the resume time and whether any surface showed it.
  • Which commit the deployed relay runs is unknown from this tree (relay/README.md does not name it); Q8 assumes master. The deployed site is master by the GitHub integration.
  • Lighthouse numbers are estimates from source; no browser run was allowed. The gate for every site row is a real run.
  • The comparator claims are from memory; where a repository or page is named it is cited, otherwise approximate. The Stratum v2 reference was not cloned.
  • The fleet and node sections depend on the gpu-fleet worktree and the vendor forks, read tonight; the fleet's own page was not opened.
  • Hours are agent hours (the project lead's rule); Q3 and Q80 also need the project lead (certificates, GitHub billing).

7. Summary for the coordinator

Every shipped system was audited against named comparators from the code and the design docs, with 95 ledger rows (ids Q1 to Q105), each with a file or screen, a severity, hours, an owner and a gate; the top ten total 40 agent hours; every row summed is about 230 agent hours. The three findings that matter most: (1) during tonight's two-hour finality pause no public or operator surface could say why, because the node's finality_reason is dropped at tools/observer/observer.mjs:720, the frozen-table share that held the pause is reported by nothing, Ember has no pause state at all, the homepage drew "final", the explorer showed nothing and Discord was not live; one forced pause on Devnet 2 with a screenshot per surface is the gate (Q1, Q2, Q5, Q6, Q7, Q10). (2) A fresh machine meets two warnings before the first screen (ad hoc Mac signature with a quarantine strip, unsigned Windows installer plus a UAC prompt 20 to 50 s in), and the Windows installer cannot be rebuilt at all tonight because GitHub-hosted runners are blocked on billing (Q3, Q80). (3) The update path treats any passed activation height as "within 1,800 blocks", so every update since 0.3.14's manifest has been urgent, skipping the safe-moment rule (the PC 1 install under a measurement job); the same path has no finality input and is one software key, one builder, one manifest, which is the baseline frontier 3.7 moves from (Q4, Q83, Q84). Rules for main: the observer and every API carry finality_reason, held_by and finality_provisional before the public testnet; the tools/ci forbidden-string check covers app/igneum-app/ui/; one formatter table for every number on every surface (Q85).