From 180af0f785d3ffbbec1723875ba2930c9e2a52db Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Tue, 6 Oct 2026 15:46:07 +0000 Subject: [PATCH] Site truth, 6 October 2026: the ledger's stated sentences merged, the bounty struck, draft (a) on the chip line, the measured prover tiers, the ledger page, the evidence page generated from its source, the live scene reading the live state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Branch site-truth-2026-10-06 = master 9519a95 + merge of ledger-text (the 45 conceded sentences of the 5 October close) + cherry-picks 6141e01, 8c5b02f (the bounty strikes) and 1a238bc (review round 4 reddit) + this commit. The hero chip line follows the owner's pick of 16:25 UTC (draft (a) of docs/plans/counter-asic-3-status.md section 6 with the owner's last sentence). Every number carries its source beside it. No em dashes. Site build, identity-check.sh (0 hits over 224 files) and the private-string sweep of the built pages pass. Changed sentences, before and after (lines are master's where the sentence existed): site/index.html:343 hero before: A custom chip gains under 2x, and the model is public. after: The strongest recompute chip we can price, holding the whole 256 MiB cache on-die, reaches under 1x per chip against an RTX 5090. A memory-controller chip that stores the whole dataset reaches 1.2x per chip and, in our model, 5x to 9x per joule; the Ethash chips of this class reached 2.1x to 4.8x. The lever against it, program work in the latency shadow, is measured and in its gates: it brings the chip to about 2x. The model is public: the numbers. before: An NVIDIA card with 24 GB or more proves every block and gets paid for it; AMD and Apple cards mine. after: Every NVIDIA card from 8 GB proves and is paid for it; 12 GB and up mine and prove; 24 GB on the stock server (eleven rented cards, RTX 3060 to RTX 5090, 6 October 2026, docs/analysis/prover-tiers-real-cards.md). AMD and Apple cards mine. site/index.html:372 before: miners active after: vote keys active in 10 min (a card runs several) site/index.html:400 and the chain scene script before: the "proven" and "locked" counters counted the simulation while the scene carried the live label after: in live mode the counters read the observer (proven = blocks in the window every shard of which is verified, "not active" while the proving layer is off; locked = locked checkpoints in the window) and the simulated shard sparks stop site/index.html:484 before: One click. The card mines; an NVIDIA card with 24 GB proves too. after: One click. The card mines; every NVIDIA card from 8 GB proves, 12 GB and up mine and prove. site/index.html:492 and site/miner.html:266 before: (the app is still labelled Igneum Miner until 0.3.6) after: (the app window still says Igneum Miner at 0.3.13) site/litepaper.html:301 abstract before: A custom chip gains under 2x, and the model is public; the claim is tested by paid independent cryptanalysis and the public benchmark. after: draft (a) as on the hero, then the sources (chip-model-v3.md section 5; the Ethash rows of asic-resistance-history.md; Counter ASIC 3.0 item 8), then "The model is public; the claim is tested by paid independent cryptanalysis and the public benchmark." site/litepaper.html:396 before: About one a second after: About one a second with the full fleet; 0.65 a second over the hour to 16:00 UTC on 6 Oct 2026 with one PC off (the live page's hour count, 2,325 blocks) site/litepaper.html:400 before: version 0.3.5; 0.3.6 staged after: version 0.3.13 (6 Oct 2026); the app window still says Igneum Miner site/litepaper.html:412 added after "not on maths or bandwidth.": Measured: an RTX 5090 hashes at 95 GB/s of useful 4-byte loads against 1,638 GB/s of sequential writes (engineering log, the RTX 5090 entries). site/litepaper.html:424 before: It claims the gain is small, the response takes a week, and both are measured. after: It states the gain its own model finds, the response takes a week, and both are measured. site/litepaper.html:440 (vs RandomX, Useful work) before: NVIDIA cards with 24 GB or more prove every block and sell proofs to other chains; AMD and Apple cards mine, ... after: Every NVIDIA card from 8 GB proves; 12 GB and up mine and prove; 24 GB on the stock server (eleven rented cards, RTX 3060 to RTX 5090, 6 October 2026, docs/analysis/prover-tiers-real-cards.md); they sell proofs to other chains. AMD and Apple cards mine, ... site/litepaper.html:452 before: Proving needs an NVIDIA card with 24 GB or more (32 GB until the fee switch of 6 October 2026; ...). AMD and Apple cards mine. A prover for them lands when a zkVM ships one. after: Proving: every NVIDIA card from 8 GB proves; 12 GB and up mine and prove; 24 GB on the stock server. Measured on eleven rented cards ...: the RTX 3060 (12 GB) mines at 23.78 MH/s and proves the v1 shard beside its miner at an 8.9 GB peak in 37.5 s; the RTX 4060 (8 GB) proves it alone at 7.4 GB in 18.4 s; the RTX 4090 (24 GB) proves it on the stock SP1 server in 5.6 s at 17.4 GB. The patched server that fits the smaller cards is not yet in the shipped app. AMD and Apple cards mine. A prover for them lands when a zkVM ships one. site/litepaper.html:454 before: The old 12 GB gate on the roadmap is withdrawn until a prover build with a smaller floor is measured. after: ... was withdrawn on 5 October until a prover build with a smaller floor was measured; on 6 October a patched server proved the same shard at 7.4 to 8.0 GB alone on eleven rented cards from the RTX 3060 to the RTX 5090 (the real-card table), so the gate returns as measured and the patched server is not yet in the shipped app. site/litepaper.html:562 (Hardware) before: 24 GB proves full shards (measured on a 32 GB card's allocation; a 24 GB card has not run it yet) and 32 GB mines and proves on one card, measured 5 October 2026 on this prover build (a 12 GB card does not prove on it: the GPU prover's floor is 13.9 GB). after: Every NVIDIA card from 8 GB proves; 12 GB and up mine and prove; 24 GB on the stock server (eleven rented cards, RTX 3060 to RTX 5090, 6 October 2026, docs/analysis/prover-tiers-real-cards.md). site/litepaper.html:645 (Governance, admin keys) appended: On the devnet the activation heights and one execution-state restart (6 October 2026) reach every node through the signed update manifest, so on the devnet the release key acts as the operator; the sentence above holds for mainnet consensus only once that path is closed, and the public testnet terms will say which parameters still travel that way. site/litepaper.html, Questions miners ask added: the entry "Don't ASICs make a chain safer?" (three parts and a five-row table; the rental row cites the fleet's bench entry that lands tonight and the 50-miner wave row reads "measurement tonight") site/litepaper.html:733 (What Igneum does not claim, the chip item) before: ... approximate; the claim is under 2x, the margin is stated on the numbers page, and the next lever is named there. No hash has stayed free of chips forever; Igneum does not claim to. Monero's seven years without a public chip are precedent, not proof. after: ... approximate. The same model, drawn out to the chip that stores the dataset (6 October 2026): draft (a) with its sources. No hash has stayed free of chips forever; Igneum does not claim to. Monero's seven years without a public chip are precedent, not proof, and a small prize: they say nothing about the price of a chip with the 256 MB cache on its die, and that price is a cost model, not a measurement. site/litepaper.html, the four bounty sentences (301, 424, 684, 686): struck as on ca2-coord 6141e01 and 8c5b02f site/litepaper.html, the 45 sentences of the 5 October close: as on ledger-text a795b02 (merged) site/miner.html:7, 13, 21 (meta) before: and an NVIDIA card with 24 GB proves. after: and every NVIDIA card from 8 GB proves. site/miner.html:252 before: Install. Start. The card mines. An NVIDIA card with 24 GB proves too. after: Install. Start. The card mines. Every NVIDIA card from 8 GB proves; 12 GB and up mine and prove. site/miner.html:308 before: ... and, on an NVIDIA card with 24 GB or more, the prover. AMD and Apple cards mine; after: ... and, on an NVIDIA card, the prover: every NVIDIA card from 8 GB proves; 12 GB and up mine and prove; 24 GB on the stock server (eleven rented cards, ...); the patched server for the smaller cards is not yet in the shipped app. AMD and Apple cards mine; site/evidence.html before: hand-kept, "30 claims · 4 Oct 2026", row 21 "unwritten" after: generated by site/build.mjs from docs/evidence.md (31 rows, the counts, the date), scrubbed as /bench is docs/evidence.md row 17 before: The chip resistance target: a chip gains under 2x over a GPU after: The chip resistance claim: the strongest recompute chip under 1x per chip against an RTX 5090; the stored-dataset chip 1.2x per chip and 5x to 9x per joule in the model (2.1x to 4.8x by the Ethash precedent); the latency-shadow lever, measured and in its gates, brings it to about 2x docs/evidence.md the card-lifetime row numbered 22 under "What moved on 5 October" becomes row 31 of the table; "Hetzner VMs" becomes "cloud VMs", "recommended to the project lead" becomes "recommended to the owner" docs/fud-ledger.md, docs/fud-fixes.md taken from fud-close c6b0bad (167 entries); two lines reworded for the identity check (the log key, the log intake) site/ledger.html new: every ledger entry with the critic's words, what was done, the status and the date, the count table on top (53 conceded, 54 fixed or built, 27 closed by rule or decided, 13 answered with evidence, 13 by design, 7 open); generated by tools/ledger-page.mjs site/vercel.json the /ledger redirect removed site/partials/footer.html "Ledger: every criticism" added under Read (so every page's footer changed) Co-Authored-By: Claude Fable 5.1 --- docs/evidence.md | 10 +- docs/fud-fixes.md | 1 + docs/fud-ledger.md | 291 +++++++++++++++++++++++++++++++------- site/404.html | 1 + site/address.html | 1 + site/bench.html | 194 ++++++++++++++++++++++++- site/block.html | 1 + site/build.mjs | 37 +++++ site/evidence.html | 36 ++--- site/explorer.html | 1 + site/faucet.html | 1 + site/index.html | 19 +-- site/ledger.html | 1 + site/litepaper.html | 31 ++-- site/live.html | 1 + site/metamask.html | 1 + site/miner.html | 25 ++-- site/miners.html | 1 + site/partials/footer.html | 1 + site/vercel.json | 2 +- site/wallet.html | 1 + 21 files changed, 548 insertions(+), 109 deletions(-) diff --git a/docs/evidence.md b/docs/evidence.md index 6aad93f1..17248e4c 100644 --- a/docs/evidence.md +++ b/docs/evidence.md @@ -17,7 +17,7 @@ Four rules for reading the table: 1. Nothing on this chain has been reproduced externally or reviewed independently. Every row's last column says "none yet". The repository is private until the public testnet (decision of 5 October 2026), so the first three labels are the ceiling today. 2. A status applies to the exact version in the row. An audit of one version never covers a newer one; when the version changes, the status falls back to "tested by the team" until the new version is reproduced or reviewed again. 3. "Tested by the team" on one machine is one machine. The rows say which. Discrete AMD, Intel and a 2019-class CPU core have not run anything. -4. The 12-node cloud network of 4 October 2026 (`infra/cloud-devnet`, Hetzner VMs in five locations) is the project's own. Rows that cite it are tested by the team, not reproduced externally. +4. The 12-node cloud network of 4 October 2026 (`infra/cloud-devnet`, cloud VMs in five locations) is the project's own. Rows that cite it are tested by the team, not reproduced externally. Versions in the table: `igneum-pow` is the Rust crate at `igneum-pow/Cargo.toml`, version 0.2.0 since 4 October 2026 (generator version 2; 0.1.0 rows are marked). "Repo" commits are this repository's. "Fork" commits are `vendor/igneum-node` and its worktrees (`-v4`, `-diff`, `-exec`, `-harness`, `-fin-fixes`), which are not in this repository's history; the row names the fork commit or branch as the bench log does. The live devnet is devnet v4 (genesis 10:05 BST, 4 October 2026, branch `devnet-v4`). The spec is `docs/spec/` version 0.1. @@ -41,7 +41,7 @@ Versions in the table: `igneum-pow` is the Rust crate at `igneum-pow/Cargo.toml` | 14 | Ethereum bytecode runs unchanged, with the documented differences of spec 7.1 | Homepage Build card; litepaper Building | tested by the team | as row 13; fixes `F-exec-A`, `F-exec-B` (spec 7.5) | `tools/evm-smoke/smoke.mjs`: deploy via viem, `increment`, `hashLoop`, `eth_estimateGas`, `eth_getLogs`; `tools/exec-attacks` scenarios 1 and 3; bench-log "execution layer attack fixes" | Deployment, calls, reverts, logs and gas estimates behave as viem expects; chain id 4463; the prototype pgas table gives 0.0095 to 0.028 pgas per gas, below the design's band before calibration, 3 October 2026. 4 October 2026: a transaction that would cross the block's proving budget is refused by the mempool and, if forced in, aborted and charged with its nonce advanced (25 of 25 checks; 30 of 30 malformed cases). Apple M5 Max. The `Prover` precompile, proof records and the shard planner are not in the node | none yet | | 15 | Every block is proven, with the proof landing within about a minute at launch | Homepage stats ("~60 s to a proof"); litepaper Proving; roadmap phase 3 gate | implemented | repo `d7e1f89` (GPU proof), `e01a3cc`, `292e800`, `eedd136` (`proving/igneum-prove`: shard cutter, MPT witnesses, shard and aggregator guests); SP1 6.8.1; spec 7.2, 7.6 | `proving/windows-wsl2` (SETUP-PROVER, PROVE-BLOCK) on the RTX 5090; `igneum-prove-host --mode block` on `proving/fixtures/`; bench-log "proving v0 on the RTX 5090" and "proving: devnet v4 shards" | First GPU proof of an Igneum block, 4 October 2026, RTX 5090 (WSL2, SP1 cuda, mining paused): fixture `block-78-increment` (2 transactions), core proof 1.4 s (7.3 MB, verify 0.221 s), compressed proof 2.7 s (1.27 MB, verify 0.038 s), post-state and receipts roots identical to the node's; 15.7x and 20.6x faster than a loaded M5 Max CPU. The same day on that CPU (load 38 to 47): a three-shard block proved shard by shard and aggregated by recursion, 19 min (1,139 s) end to end, 245 to 337 s per compressed shard proof, every proof verified. What is not there: no proof is produced, carried or checked on the chain (the devnet prover is a stub that signs claims), the proving pool pays nobody (row 21), the block proven is far below one shard, and the 60-second figure remains a design target; the pass mark is the standard in `docs/benchmarks/proving-e2e.md`. Second RTX 5090 run, 4 October 2026 evening (job run-20261004-173115): a full shard at the provisional S_p (6.75 M pgas, 60.8 M cycles) executed in 1.63 s, core proof 8.3 s (18.1 MB), compressed proof 10.9 s (1.27 MB, verify 0.040 s); a two-shard block (13.5 M pgas) proved shard by shard (11.7 s and 10.0 s) and aggregated in 2.2 s, 24 s of GPU stages end to end, every proof verified, six tampered witnesses rejected. The two host defects (an abort after the upload, an idle wait that turned out to be an unbuffered 18 MB proof save through the WSL2 file bridge, 24 minutes) are fixed (ledger P20) 5 October 2026, live devnet with real transactions (bench-log "real transactions, the first non-empty shard proven and paid"): block 72704 shard 0, 29 transfers, 5,800 pgas, proven on PC 2 in 34 s, verified on the Mac in 0.297 s and paid 1.7623 IGN, 53 s after the chain block executed; of about 1,400 blocks in the 20-minute window 36 were proven (the one prover takes the newest shard assigned to it), so "every block" is not yet true; a second content shard (72803, all copies skipped) failed the native-execution veto on the exporter's block structure, fixed with fixtures the same day, the node side pending the 0.3.9 rollout 5 October 2026, evening (bench-log "proving v1"): the aggregated segment record, the chain rule and the unproven rule are implemented behind `proving_v1_activation_daa` (branch proving-v1, not on the devnet before 0.3.11); on the RTX 5090 a chain of 8 consecutive live blocks proved and aggregated by recursion in 135.6 s with the miner on the card (17 s a block, one proof of 1,272,909 bytes attesting all 8, verified in 0.04 s); the 3-node fast-time harness paid a segment record 1.0 s after submission and refused a late one after its deadline (21 checks); the devnet itself, with one prover, carried proofs for 2.4% of blocks over 30 minutes at a block-to-record latency p50 44 s, p99 52 s. The "within about a minute" holds per proven block; "every block" needs 18 mining 5090s or 6 proving-only cards at empty blocks on the measured rates, and the mandatory rule stays off until the share is one | none yet | | 16 | A 12 GB card proves one shard in about 20 s (WITHDRAWN 5 October 2026: a 24 GB card proves a full shard at the adopted size in 4.3 s; 32 GB mines and proves) | Litepaper Proving ("The proving budget"); roadmap gate 2 | designed | spec 5.1 (Target), 7.6 (`S_p` provisional, 7,500,000 pgas = `B_p` / 4) | `PROVE-SHARD.bat` on the RTX 5090 (pending); the end-to-end standard in `docs/benchmarks/proving-e2e.md`; bench-log "proving: devnet v4 shards" | Measured on a 32 GB card, not yet on a 12 GB card. A shard at the provisional `S_p` is 60.8 M SP1 cycles on the prototype pgas table (9 cycles per pgas, 44 per EVM gas; the modexp entry about 100x its SP1 cost); on an RTX 5090 (4 October 2026 evening, job run-20261004-173115) it executed in 1.63 s and its compressed proof took 10.9 s, verified in 0.040 s, so the 32 GB card is inside the 20 s target with margin. Whether a 12 GB card proves it at all, and in what time, is the next measurement (an RTX 3060 and an RTX 5060 Ti 16 GB are on order). A per-shard time can be met by shrinking the shard, so the project does not use it as a pass mark 5 October 2026, evening (bench-log "proving v1", the S_p curve): measured on the RTX 5090 with SP1 6.8.1's GPU prover, the card to itself, 1-s nvidia-smi samples: an empty shard 13,874 MiB and 2.2 s; a full shard at the ADOPTED v1 budget (30,000 pgas, 4.7 M cycles) 20,434 MiB and 4.3 s; the full prototype shard (6.75 M pgas, 60 M cycles) 28,307 MiB and 10.8 s; beside the miner 15,670 and 30,039 MiB. No environment knob of SP1 moves the 13.9 GB floor and the GPU server has no options of its own, so on this build a 12 GB card proves nothing, a 16 GB card only empty shards, a 24 GB card the adopted full shard alone and beside the miner (22,210 MiB and 13.2 s, measured on the 32 GB card: the 5090's allocation pattern, not yet a run on a 24 GB card) and a 32 GB card the prototype shard beside the miner with 2.5 GB spare. The litepaper line now says so; the 12 GB gate returns when a prover build with a smaller floor is measured on a 12 GB card | none yet | -| 17 | The chip resistance target: a chip gains under 2x over a GPU | Homepage hero and litepaper abstract ("a custom chip gains under 2x, and the model is public"), litepaper "What Igneum does not claim" | tested by the team (the model), designed (the target) | program class v3 (Counter ASIC 2.0, 5 October 2026): branches ca2-v3 d233fa1 and after, ca2-mixer 1ab8b21, ca2-era 78c0ee4; `docs/analysis/chip-model-v3.md`, `docs/analysis/sram-mirror.md`, `docs/analysis/scratch-soundness.md` | The m16 recompute model re-run on the measured v3 rates and verifier times; the on-die-cache chip row | The on-die-cache recompute chip against the RTX 5090's measured 136.1 MH/s: class v2 2.4x; class v3 (mixer x8) 0.31x bare, 0.92x with a 3x fixed-function allowance (approximate), 0.76x at equal silicon; margin 8% on the allowance, 9% on the budget. 5 October 2026, M5 Max, RTX 5090, RX 9070 XT. The 2x target is a target: no chip has been built; the bounty stands (O-1.17) | none yet | +| 17 | The chip resistance claim: the strongest recompute chip under 1x per chip against an RTX 5090; the stored-dataset chip 1.2x per chip and 5x to 9x per joule in the model (2.1x to 4.8x by the Ethash precedent); the latency-shadow lever, measured and in its gates, brings it to about 2x | Homepage hero and litepaper abstract (draft (a) of `docs/plans/counter-asic-3-status.md` section 6, chosen 6 October 2026), litepaper "What Igneum does not claim" | tested by the team (the model), designed (the target) | program class v3 (Counter ASIC 2.0, 5 October 2026): branches ca2-v3 d233fa1 and after, ca2-mixer 1ab8b21, ca2-era 78c0ee4; `docs/analysis/chip-model-v3.md`, `docs/analysis/sram-mirror.md`, `docs/analysis/scratch-soundness.md` | The m16 recompute model re-run on the measured v3 rates and verifier times; the on-die-cache chip row | The on-die-cache recompute chip against the RTX 5090's measured 136.1 MH/s: class v2 2.4x; class v3 (mixer x8) 0.31x bare, 0.92x with a 3x fixed-function allowance (approximate), 0.76x at equal silicon; margin 8% on the allowance, 9% on the budget. 5 October 2026, M5 Max, RTX 5090, RX 9070 XT. The 2x target is a target: no chip has been built; the bounty stands (O-1.17) | none yet | | 18 | The chip resistance measurements: the program is latency-bound (random reads), not bandwidth-bound, on every card we own, and sits beyond a card's on-chip cache | Litepaper Mining ("waits on memory latency, not on maths or bandwidth"), vs RandomX; the numbers page | tested by the team | readwidth e752fc7 (`docs/plans/read-width.md`), ca2-era 78c0ee4, ca2-cache 2de19e5 (`docs/plans/hot-table.md`) | The dependent-read probes at 32 to 1,024 MiB and the hash rate per class on the three cards; the latency-bound share = rate over the probe ceiling per load | Latency-bound share at the 1 GiB dataset: RTX 5090 0.96 (v2) and 1.01 (v3), RX 9070 XT 0.87 and 0.95, M5 Max 1.01 and 1.06; wider reads do not close the AMD gap (the 9070 XT does 2.4 G dependent reads per second at every width; the 5090 goes bandwidth-bound at 64 B, share 0.58); a 32 to 96 MiB hot table is not kept resident by any card while the dataset streams (g 0.80 to 0.87 in the added form). 5 October 2026 | none yet | | 19 | The lottery hash is sound as a hash: uniform output, deterministic, no out-of-bounds read, fuzzed; class v3 bit-exact on the three vendors | Litepaper vs RandomX ("Every number above is measured and logged"), the numbers page | tested by the team | ca2-mixer 1ab8b21 (`tests/mixer.rs`, `tests/scratch.rs`), ca2-era 78c0ee4, ca2-soundness a465881 (`docs/analysis/scratch-soundness.md`), `igneum-pow/tests/packs.rs` | The crate suite (53 + 4 + 19 + 7), the Metal fuzz, edge, stats and determinism runs on the v3 construction, the pack vectors and 2^24 fingerprints on Metal, Apple OpenCL, the RTX 5090 and the RX 9070 XT, the 1,024-hash CPU re-check per card | Class v3 (mixer x8 + era): 200-program fuzz 200 of 200 on Metal, every tenth on Apple OpenCL; the pinned v3 packs 3/3 + 3/3 and 96 of 96 lanes on Metal and Apple OpenCL; the six era packs' fingerprints equal on the three vendors (PC 1 job run-ca2-era-pc1-20261005, 5 October 2026); the v2 exports byte-identical on the v3 crate; the final-class PC rows and the G2 re-check: job run-ca2-era-pc1b-20261005 (pending at the time of writing) | none yet | | 20 | No premine, no pre-sale, no allocation: every coin is minted by the schedule and every coin goes to the block producer (80%) and the proving pool (20%) | Homepage stats and Economics tiles; litepaper Supply, Economics | implemented | repo `6ac80a3`; fork "igneum-node devnet v0"; `consensus/core/src/igneum.rs`, `coinbase.rs` | `cargo test -p kaspa-consensus-core igneum` (8 pass: subsidy table, ramp, split, cap) and `cargo test -p kaspa-consensus coinbase` (8 pass); `igneum-miner inspect 40`; bench-log "igneum-node devnet v0" | Coinbases on the devnet: 80/20 exact on 39 of 39 single-payee blocks, the 20% to the `igneum-proving-pool-v0` output; the per-second schedule sums to under the 4,000,000,000 cap by less than 100 coins; 3,168,808,781 units per DAA second in years 0 to 2, halving at 63,115,200 DAA s. 3 October 2026, Apple M5 Max. The devnet genesis carries no allocation; the mainnet genesis does not exist yet, so the claim is about the code and the stated rule, not a launch that has happened | none yet | @@ -53,8 +53,9 @@ Versions in the table: `igneum-pow` is the Rust crate at `igneum-pow/Cargo.toml` | 26 | A phone or browser verifies the chain from a locked checkpoint, at about 3.44 MB per day in checkpoint mode | Homepage "Browser checks Igneum" card; litepaper Building ("Light clients"), firsts row 6 | designed | spec 10 (10.5 bytes per day: 3.44 MB at 1,000 voters, 6.68 MB at 10,000, derived, approximate); repo `f874f80` for the browser card; `site/api/checkpoint.mjs` | None for the byte figure; `site/verify/` for the card against `/api/checkpoint`. BLS verification on a phone and in WebAssembly is O-10.3; the full-header mode on a phone is O-10.4 | Since 12:03 BST on 4 October 2026 the homepage card verifies the live devnet's own certificates in the tab (index 522 with 27 voters at 13:42 UTC), BLS aggregate against the voter list the node serves, light client v0; before that it verified the 3 October test network's. The byte figure is arithmetic on designed sizes (header 400 bytes, proof 400 bytes), measured nowhere; the execution proof the card would also check is not on the chain (row 15) | none yet | | 27 | The node survives malformed input, floods, withholding, partitions and eclipses | Litepaper Speed ("GHOSTDAG, the BlockDAG consensus proven on Kaspa"); spec 2 | tested by the team | repo `394030c`, `8dae48b`, `6b5bd92`; fork worktree `vendor/igneum-node-harness` and `devnet-v4`; `tools/harness/`; `infra/cloud-devnet/experiments/partition.sh` | `tools/harness/` against a private `igneumd` test network; the merged node's harness scenarios 2 and 5; the cloud network's 10-minute partition of Singapore (`results/2026-10-04/partition-sin-20261004-110906/partition.md`); bench-log "consensus attack harness", "devnet-v4 integration" | 3 October 2026, Apple M5 Max: 63 malformed cases, node up on every one; withholding at 10% to 45% within 2 sigma of share; partitions of 120 s to 3,700 s healed to one chain in 10 s; eclipse victims rejoined in 10 s; 50x floods left template p95 under 4 ms; one FAIL, a 45% withholder releasing every 20 blocks took 50.7% of blues (bound 47.4%). Merged node, 4 October 2026: 63 cases, node up, 0 cache builds; the 10 s timestamp floor and future bound exact. Cloud network, 4 October 2026: 12 nodes in five locations on their own chain, Singapore cut off by iptables for 10 minutes; the two minority nodes adopted the majority chain 10 and 14 s after the heal with reorgs of 445 and 516 blocks, the majority's deepest reorg was 2 blocks, 0 conflicting locks (none were possible: the weight window stood at DAA 3,030 of 7,200). CPU miners only; the finality rules under partition are row 10 | none yet | | 28 | Headers are validated cheaply before the lottery engine runs, so forged timestamps cannot force 256 MiB cache builds | Spec 2.4; ledger M15 | tested by the team | repo `0953ec7`, `8dae48b`; fork worktree `vendor/igneum-node-r3` branch `r3-fixes` at `5166ee26`, merged into `devnet-v4` | `measure_m15_attack_before_and_after` (ignored test, release, `--features igneum-pow`); kaspa-pow 8, header_processor 1, p2p `pow_guard` 2 tests; harness scenario 5 on the merged node | 50 forged headers: before, 50 cold builds in 10,595 ms and the live day evicted; after, 0 builds, all 50 rejected in 14 ms, 3 October 2026, Apple M5 Max under load 60 to 110. Merged node, 4 October 2026: 63 harness cases with 0 cache builds (the node log shows one build, the honest day) and the M15 p2p cases disconnected by the strike guard; the live devnet v4 runs it. Measured through the validate path with `skip_proof_of_work`, not the daemon RPC | none yet | -| 29 | Blocks reach every node well inside GHOSTDAG's delay bound across continents | Litepaper Speed (GHOSTDAG at one block a second); spec 03 C1 (lock latency); `infra/cloud-devnet/README.md` | tested by the team | repo `6b5bd92`; `infra/cloud-devnet/experiments/latency.sh`, `analyze.py`; the Linux cross-build `infra/cross/build-linux.sh` | 12 `igneumd` nodes on Hetzner VMs in Helsinki, Falkenstein, Ashburn, Hillsboro and Singapore (own chain `igneum-devnet-20`, one CPU trickle miner each), a ping matrix, then 10 minutes of per-node arrival logs joined on block hash; `results/2026-10-04/latency/propagation.md` and `rtt-by-region.md` | 644 blocks in the window, 642 seen by at least 80% of nodes; arrival at a node minus the first arrival anywhere: p50 343 ms, p90 497 ms, p99 666 ms, max 2,313 ms; by region p50 239 ms (Falkenstein) to 413 ms (Singapore), p90 455 to 632 ms; inter-region RTT 35 ms (Helsinki to Falkenstein) to 289 ms (Ashburn to Singapore); first arrival minus header time median 490 ms. 4 October 2026. The network is the project's own: 12 nodes not 20 (a new account's limits), CPU hash rate only, clocks by chrony, one evening of data; the 5 s bound behind GHOSTDAG k is a design parameter this run did not challenge | none yet | +| 29 | Blocks reach every node well inside GHOSTDAG's delay bound across continents | Litepaper Speed (GHOSTDAG at one block a second); spec 03 C1 (lock latency); `infra/cloud-devnet/README.md` | tested by the team | repo `6b5bd92`; `infra/cloud-devnet/experiments/latency.sh`, `analyze.py`; the Linux cross-build `infra/cross/build-linux.sh` | 12 `igneumd` nodes on cloud VMs in Helsinki, Falkenstein, Ashburn, Hillsboro and Singapore (own chain `igneum-devnet-20`, one CPU trickle miner each), a ping matrix, then 10 minutes of per-node arrival logs joined on block hash; `results/2026-10-04/latency/propagation.md` and `rtt-by-region.md` | 644 blocks in the window, 642 seen by at least 80% of nodes; arrival at a node minus the first arrival anywhere: p50 343 ms, p90 497 ms, p99 666 ms, max 2,313 ms; by region p50 239 ms (Falkenstein) to 413 ms (Singapore), p90 455 to 632 ms; inter-region RTT 35 ms (Helsinki to Falkenstein) to 289 ms (Ashburn to Singapore); first arrival minus header time median 490 ms. 4 October 2026. The network is the project's own: 12 nodes not 20 (a new account's limits), CPU hash rate only, clocks by chrony, one evening of data; the 5 s bound behind GHOSTDAG k is a design parameter this run did not challenge | none yet | | 30 | One click: install, press start, the card mines; the app looks after its node | Homepage Mine section ("One click: install, press start"); litepaper "One click, for everyone else"; journey phase 5 | tested by the team | repo `3bb50d6`, `2c4b30f`, `6461540` (package 0.3.0: prebuilt NVRTC CUDA worker and generic OpenCL worker, driver only), `a1a33cb`, `7c794df`, `0d4498e`, `6c083db` (Igneum Miner 0.3.0), `78903cd` (0.3.1, over-the-air updates) | `Igneum-Miner-Setup-0.3.0.exe` (runner-built, unsigned) on a Windows PC with an RTX 5090 and no toolchain; `proto-cuda/nvrtc/emu/serve-check.sh` on the Mac; `proto-cuda/windows-app/TEST.md`; bench-log "one-click Windows workers", "first machine on the Igneum Miner app", "a node 60 s behind the clock is silently dead", "the gfx1036 worker fault" | Four machines by 15:45 BST on 4 October 2026: PC 2, then PC 1 (RTX 5090 at 110 MH/s under the 80% power cap), the project's Apple M5 Max (25 MH/s) and the outside Apple silicon laptop (row 29), all on Igneum Miner 0.3.1. The NVRTC worker compiled the pack on the card with no toolchain installed and mined at 124.2 MH/s, equal to the nvcc-built worker, 0 rejected, CPU re-check clean; inside the app 117 to 119 MH/s with 34 accepted blocks in the first minute, the integrated AMD chip at 3.3 MH/s beside it (row 9). Two defects found by the install, both fixed the same hour: a clock 62 s slow after a power cut made the node reject every relayed block for 12 minutes with no visible reason (the app now reads the skew from the node's warnings, the block timestamps over the EVM RPC and an HTTPS Date header, warns over 5 s and blocks Start over 10 s, with a one-click clock sync; checked on the Mac with a fake 60 s skew; a one-line node warning is filed), and the node card said "syncing" while the miner was already accepted. The Mac could only emulate the NVIDIA path (17 of 17 sampled hashes) and the AMD path on Apple OpenCL (15 of 15). Over-the-air updates were dry-run on a private devnet (0.3.0 to 0.3.1 and back), not on a user's machine. The installer is unsigned (SmartScreen "run anyway"). Second machine, the same afternoon: a friend of the project installed Igneum Miner 0.3.1 from the DMG on an Apple silicon laptop with no toolchain and no instructions beyond five steps; the node synced from the seed, the Metal worker reported ready, 33 accepted blocks and 0 rejected in 7 minutes at 21.0 MH/s average, CPU re-check OK on every share, uploads arriving every minute under its per-install id. That laptop is not the project's hardware, but the result is observed through the project's own log intake and reported by the project, so it stays tested by the team until an outsider publishes a run of their own. The devnet's other GPU machines (PC 1 and the Mac) run the same workers through the launcher, not the app | none yet | +| 31 | Card lifetime: a 4 GB card mines about four years and an 8 GB card about twelve, under the dataset's step schedule (2 GB at genesis, doubling at years 4, 12, 28, 60) with the cache freed after the daily build | Litepaper Hardware and vs RandomX ("Dataset" row); homepage Mine card and "Memory" row | designed | `docs/analysis/card-lifetime-2026-10-05.md` (branch card-lifetime 1fecfe2); spec 1.13.3 option (b) recommended to the owner 5 October 2026 (`docs/plans/counter-asic-2-rollout.md` 6c) | The per-tier working-set arithmetic of that document (GTX 1650, RTX 3050, RTX 3060, RTX 4090 tiers) against the step schedule | A design claim: under the continuous mapping (a) a 4 GB card is out within 1 to 1.5 years and an 8 GB card at 6 to 7.5 years, so the sentence is true only under the step schedule (b), which the spec has not yet fixed (O-1.13) | none yet | ## Count by status @@ -66,7 +67,7 @@ Versions in the table: `igneum-pow` is the Rust crate at `igneum-pow/Cargo.toml` | reproduced externally | 0 | | reviewed independently | 0 | -30 rows. The rendered page is `site/evidence.html`, kept in step by hand with this file; the bench page is generated, this one is not, because its text is judgement, not a log. +31 rows. The rendered page is `site/evidence.html`, generated from this file by `site/build.mjs` (since 6 October 2026); the text is judgement, so this file is edited by hand and the page follows. ## What moved on 4 October 2026 @@ -87,7 +88,6 @@ Versions in the table: `igneum-pow` is the Rust crate at `igneum-pow/Cargo.toml` |---|---|---|---| | 15 | implemented | implemented, with a live result | the first non-empty shard (block 72704, 29 transfers) proven, verified and paid on the devnet; not every block is proven yet | | 21 | designed | tested by the team | 388 shards paid from the pool on the live devnet, the rule in `proving.rs`, the numbers in the bench log | -| 22 | Card lifetime: a 4 GB card mines about four years and an 8 GB card about twelve, under the dataset's step schedule (2 GB at genesis, doubling at years 4, 12, 28, 60) with the cache freed after the daily build | Litepaper Hardware and vs RandomX ("Dataset" row); homepage Mine card and "Memory" row | designed | `docs/analysis/card-lifetime-2026-10-05.md` (branch card-lifetime 1fecfe2); spec 1.13.3 option (b) recommended to the project lead 5 October 2026 (`docs/plans/counter-asic-2-rollout.md` 6c) | The per-tier working-set arithmetic of that document (GTX 1650, RTX 3050, RTX 3060, RTX 4090 tiers) against the step schedule | A design claim: under the continuous mapping (a) a 4 GB card is out within 1 to 1.5 years and an 8 GB card at 6 to 7.5 years, so the sentence is true only under the step schedule (b), which the spec has not yet fixed (O-1.13) | none yet | ## What would move a row diff --git a/docs/fud-fixes.md b/docs/fud-fixes.md index d969ca60..114a7a0d 100644 --- a/docs/fud-fixes.md +++ b/docs/fud-fixes.md @@ -385,3 +385,4 @@ Nothing below is optional. The history, not just the working tree, carries the n 9. Put the GitHub links back on HP and the /bench page (row 1) on the day the repository opens, at the public testnet. What is already clean: `docs/bench-log.md` and the /bench page name machines, not people (commit 1769eda); the live site returns 404 for everything under `docs/` and 307 for `/ledger`; `site/.env.local`, `site/.vercel/` and `vendor/` are ignored; no tracked file carries a home-directory path; no connection string or token appears anywhere in the history. +| 128 | P23 | The EVM pool has `on_chain_block` and no reorg hook, so a transaction unwound by a selected-chain reorg leaves the node until its sender resends (found by the P17 conformance run, 6 October 2026) | A reorg hook: unwound transactions handed back to the pool as pending with the usual checks; unit test; the conformance driver's `reorged out` case ends in `executed` without a resend (2 h) | execution engineer (round 3 `ledger-rebase` carries it) | before a public RPC | no | diff --git a/docs/fud-ledger.md b/docs/fud-ledger.md index 90d36db2..8e162a2c 100644 --- a/docs/fud-ledger.md +++ b/docs/fud-ledger.md @@ -29,7 +29,8 @@ Evidence locations referenced below: `docs/bench-log.md`, `proto-metal/TESTS.md` ### M1. The program space is tiny "Eleven integer ops, 64 instructions, 8 iterations, a splitmix register init. That is not RandomX. RandomX leans on a superscalar out-of-order CPU with floating point and branches. Yours is a sea of 32-bit ALUs and a memory bus. A chip for that is a weekend." -Status: Open, program space counted, the claim stands as a target (5 October 2026, evening sweep). Was: Open, experiment scheduled. Sweep (5 October 2026): nothing runnable; the bounty, the public benchmark and a chip design are M22's decisions and hardware. The nearest number stays M16's arithmetic. +Status: Decided (6 October 2026, 17:35 UTC, by the owner; decisions item 1, corrected): no standing bounty. A team with a real 2x chip earns more by mining than any bounty pays, so a device bounty attracts nobody; the tiers announced at 17:25 UTC are withdrawn. The claim "under 2x" is backed by the paid independent cryptanalysis (the Monero route: four paid reviews, no bounty) and by the public benchmark with M22's metrics. Optional, the owner's call later: one cryptanalysis prize of USD 50,000 for a published 2x or better shortcut in the mixer, the chained cache or the acceptance rule, escrowed before it is named; nothing public before that. The claim stays a target until the audit and the benchmark have reported. Was: Open, program space counted, the claim stands as a target (5 October 2026, evening sweep). Was: Open, experiment scheduled. Sweep (5 October 2026): nothing runnable; the bounty, the public benchmark and a chip design are M22's decisions and hardware. The nearest number stays M16's arithmetic. +Decision owner: the project lead, decided 6 October 2026 (`docs/plans/ledger-decisions.md`, outcomes section). Sweep (5 October 2026, evening): the program space, swept as arithmetic from the version 2 generator (`igneum-pow/src/generator.rs`: 16 load slots as a uniform 16-subset of instructions 1 to 63, then nine draws per instruction, 592 draws per program; 10 non-load operations with weights 12/10/8/8/8/7/6/6/6/4; 8 registers; a 31-way rotation, a 32-way bit and a 5-way mask per instruction; two 32-bit immediates). Counting choices: the slot subset is 48.4 bits; the operation draw carries 3.26 bits of entropy (of log2 10 = 3.32); operations and registers alone give about 770 bits per program; with the rotation, bit and mask fields about 1,550 bits; with the immediates about 5,650 bits, all capped by the 256-bit seed, so the space a chip has to serve is 2^256 distinct programs drawn from a structure of about 2^1550 shapes, and the critic is right that it is a small instruction set: 12 operations, 8 registers, no floating point, no branches, by design (vendor-identical rounding). What the sweep adds to the ledger's answer is the number that matters for a fixed-function design, the spread a chip must absorb: under generator version 2 every accepted program does 120 to 128 distinct loads per hash (median 128.00, 20,000-program census), so the per-program hash-rate spread on a memory-bound device is the 1.10x residual the census measured, not the 2.7x of version 1; the chip's advantage therefore cannot come from the program (it is one fixed memory-bound shape) and must come from the memory system or from the recompute route, which is M16's cost model (`docs/analysis/m16-recompute-attacker-2026-10-05.md`: 1.5x to 2.4x at equal integer budget before any fixed-function factor, 3x to 6x with one, and the mixer-cost lever that cuts it below 1x). The experiment that closes M1 is unchanged: the bounty and the public benchmark (M22, decision owner the project lead). @@ -102,7 +103,8 @@ Sweep (5 October 2026, evening): stated. `site/litepaper.html`, Mining section, ### M8. Only two vendors, two programs, one day "'Any card, any vendor, bit-exact' rests on 192 vectors across two programs on one Apple chip and one NVIDIA card, all run on the same day. AMD is untested. Intel is unmentioned." -Status: Answered with evidence for what was measured; Open for AMD and Intel. Sweep (5 October 2026): Intel is now run. A Windows laptop with only an Intel UHD integrated GPU mined on the live devnet through the OpenCL worker at 1.46 MH/s, found one block that the network accepted, and its votes on checkpoints 1202 and 1203 were accepted (`docs/bench-log.md`, "first machine in the United States"). Discrete AMD is the remaining gap (hardware, O-1.15). +Status: Decided (6 October 2026, 17:25 UTC, by the owner; decisions item 12): a discrete AMD card (9070 XT) and a 12 GB NVIDIA card (4070) are on order for PC 2; the measurement runs on arrival. Was: Answered with evidence for what was measured; Open for AMD and Intel. Sweep (5 October 2026): Intel is now run. A Windows laptop with only an Intel UHD integrated GPU mined on the live devnet through the OpenCL worker at 1.46 MH/s, found one block that the network accepted, and its votes on checkpoints 1202 and 1203 were accepted (`docs/bench-log.md`, "first machine in the United States"). Discrete AMD is the remaining gap (hardware, O-1.15). +Decision owner: the project lead, decided 6 October 2026 (`docs/plans/ledger-decisions.md`, outcomes section). Answer: 192 of 192 vectors matched across Metal and CUDA on two programs, standalone and in batch. That is the measurement and it is small. AMD (ROCm or OpenCL) is the next run, then the full 10,200-program fuzz set on NVIDIA and AMD with the 14 edge-case programs, and the shuffle, mulhi and shift semantics must agree bit for bit on every vendor. Intel Arc after that. The litepaper says "Any card, any vendor" and should say what was measured. @@ -131,7 +133,8 @@ Evidence: `docs/bench-log.md`, RTX 5090 sections. Fix: overclaims list, item 14. ### M11. Hourly JIT on real rigs "50 ms compile is a Mac number. On a HiveOS rig the miner has to ship NVRTC or a ROCm compiler, compile for eight cards of mixed generation, and do it every hour without crashing. Every miner that tried runtime codegen had a bad year." -Status: Answered with evidence on the fleet that exists, Open for a multi-card rig and ROCm (5 October 2026, evening sweep). Was: Open, experiment scheduled. Sweep (5 October 2026): partly measured. One RTX 5090 compiled the hourly program at runtime (nvcc in the background) on the live devnet in 1,285 ms with no pause and 0 rejected (bench-log, "first hourly program swap"). A multi-card mixed rig and ROCm remain unmeasured (hardware, O-1.16). +Status: Decided (6 October 2026, 17:25 UTC, by the owner; decisions item 12): the mixed-generation rig is borrowed from a farm operator later, at the HiveOS package's first test; the 9070 XT on order gives the ROCm half on PC 2. Was: Answered with evidence on the fleet that exists, Open for a multi-card rig and ROCm (5 October 2026, evening sweep). Was: Open, experiment scheduled. Sweep (5 October 2026): partly measured. One RTX 5090 compiled the hourly program at runtime (nvcc in the background) on the live devnet in 1,285 ms with no pause and 0 rejected (bench-log, "first hourly program swap"). A multi-card mixed rig and ROCm remain unmeasured (hardware, O-1.16). +Decision owner: the project lead, decided 6 October 2026 (`docs/plans/ledger-decisions.md`, outcomes section). Sweep (5 October 2026, evening): hourly runtime codegen measured on five machines, four compilers and three vendors over the live devnet's boundaries of 5 October 2026 (miner logs through the intake, DAA 82,800 to 111,600, from each machine's 0.3.5 start; `docs/bench-log.md`, "FUD ledger sweep round 6", M11). NVRTC on the two RTX 5090s: prepare 580 to 1,074 ms in all (nvrtc 147 to 180 ms, cache, dataset, 96-lane self-test), 22 of 22 boundaries swapped with no pause, 0 rejected. OpenCL on the two integrated Radeons: prepare 6.9 to 11.7 s on PC 2 and 55 to 124 s on PC 1 (its 1 GiB dataset build on the iGPU runs beside today's WSL build jobs), the two late boundaries on PC 1 (82,800 and 93,600, the prepare sent 156 to 160 DAA before the boundary instead of 449) compiled inline, the rest swapped. OpenCL on the Intel UHD laptop: prepare 7.3 to 11.7 s (build 3.0 to 6.4 s), 7 of 7 swapped with no pause. Metal on the two Macs: program 0 to 444 ms, prepare 34 to 40 s because the hourly race runs inside it, 9 of 9 swapped with no pause. The failure the critic predicts did happen, on the 0.3.4 miner: a wrong prepared pack at DAA 61,200 made both PCs' NVIDIA workers refuse the prepare every 0.7 s for two hours (4,299 and 4,233 `prepare-failed` lines) and cross two boundaries by inline compile; the 0.3.5 miner's rate limit ended it (M27). The variant race on the 5090 (the job of `docs/plans/miner-perf.md`, run on PC 1 at 15:52 UTC with the miners stopped): 17 NVRTC variants, 3 rounds, twice; base won both runs at 139.75 and 139.65 MH/s, gain +0.00%, every variant within -1.5% (`ldcs`) and +0.05% of base, compile 232 to 300 ms for the 17, 112 s of timing per run; the Mac fleet records agree that base wins on the M5 Max with the GPU to itself (10 records, g256 at -4.2%, against +17% under 4 October's contention). The race is therefore switched off as a default worth nothing on this program class: 40 s an hour of paused mining on the Macs for a base winner. Still unmeasured: a multi-card mixed-generation rig and ROCm (hardware, O-1.16). @@ -172,6 +175,8 @@ Answer: Correct, and this is the most dangerous entry in the ledger. With the ac Evidence: arithmetic above (not yet in `sim/`); design doc, hostile review table row "No stake exists in the first month". Simulation of the launch month: not yet. +Fix (5 October 2026, night), the harness text only: `tools/finality-attacks/run.mjs` names the 2/3-of-total floor in the s6 comments and criterion and in the s5 result line, where it still said 56.7%; the scenario logic is untouched. Branch `ledger-fork`. + ### F2. The two-hour presence window is an eclipse vector "Cut the big pools' vote gossip for two hours, not their blocks, and the remaining keys become 100% of active weight. A faction with a fifth of the weight locks alone. You chose liveness over safety and called it a feature." @@ -184,12 +189,15 @@ Evidence: `sim/results.md` table E and "What the simulation cannot tell us"; des ### F3. Participation grinding through the bitmap "The aggregator picks which votes go in the certificate once quorum is reached. A block producer carries the certificate it likes. Drop a rival pool's votes from your bitmaps for two hours and its participation factor falls, your share rises." -Status: Closed by rule (3 October 2026), parameter open. Spec section 3.3 Q2 and 3.4.1: participation is computed from every vote seen in blocks over the presence window (votes are block payload), never from the certificates an aggregator chose; the per-block vote bound is O-3.3. Was: Open, experiment scheduled. Sweep (5 October 2026): the block reading is exercised on the fork by harness s3 (block-carried votes give participation; 35 of 35 locked on each of 3 nodes) and s4 (a producer dropping the finality section from 40% of its blocks adds 0 ms to lock latency, 35 locks), bench-log "finality v2 attack harness"; the per-block vote bound and the hostile-aggregator simulation of O-3.3 are still owed. Re-run on the `finality-fixes` build under fast time (5 October 2026, 01:13 UTC, `run.mjs s4 --fast-time`, 2 nodes, 223 s): node B locked 14 checkpoints with a 40% vote-dropping producer, median lock latency 1,042 ms against 1,042 ms for the control, 0 ms added. PASS. +Status: Decided (6 October 2026, 17:25 UTC, by the owner; decisions item 13): the per-block vote bound and the bitmap wire bound of spec 3.4.2 items 2 and 3 are adopted for gate 3; the spec moves them from Proposed to Decided at the next spec edit. Was: Closed by rule (3 October 2026), parameter open. Spec section 3.3 Q2 and 3.4.1: participation is computed from every vote seen in blocks over the presence window (votes are block payload), never from the certificates an aggregator chose; the per-block vote bound is O-3.3. Was: Open, experiment scheduled. Sweep (5 October 2026): the block reading is exercised on the fork by harness s3 (block-carried votes give participation; 35 of 35 locked on each of 3 nodes) and s4 (a producer dropping the finality section from 40% of its blocks adds 0 ms to lock latency, 35 locks), bench-log "finality v2 attack harness"; the per-block vote bound and the hostile-aggregator simulation of O-3.3 were run and proposed in round 2 (5 October 2026, night, below; decision at gate 3). Re-run on the `finality-fixes` build under fast time (5 October 2026, 01:13 UTC, `run.mjs s4 --fast-time`, 2 nodes, 223 s): node B locked 14 checkpoints with a 40% vote-dropping producer, median lock latency 1,042 ms against 1,042 ms for the control, 0 ms added. PASS. +Decision owner: the project lead, decided 6 October 2026 (`docs/plans/ledger-decisions.md`, outcomes section). Answer: This is a new finding from writing this ledger and it is not in the design doc. The participation factor is "observed certified votes over P divided by expected votes". If "observed" means votes present in certificates carried in blocks, then whoever aggregates and whoever produces blocks can shape it. Candidate fixes: participation computed from all votes seen in blocks (votes as transactions, not only certificates), or a certificate must include every valid vote the aggregator received above a size bound, or participation falls only on checkpoints where the key's vote appears in no certificate and no block. Goes to the cryptographer for phase 1 and to the gate 3 simulation. Evidence: design doc Finality v2, Quorum item 2 and Checkpoints item 3. Fix: not yet. +Round 2 (5 October 2026, night): the hostile aggregator is simulated and the per-block vote bound is proposed. Simulation (`sim/finality_v2.py` scenario O, new tonight with `--pmode block` for spec 3.3 Q2 and `P.hostile`; `sim/results_v2.md`, "Hostile aggregator"; bench-log "ledger close round 2: F3"): a pool holding 20.0% of total weight, a chosen aggregator that drops its votes from every certificate it builds for two hours, its certificate carried whenever the other 80% reach quorum, seeds 7, 11, 13. Under the cert reading the simulation used until tonight the attack works as the critic says: the pool's participation falls to 0.000 to 0.025 and its share of active weight from 20.2% to 0.0 to 0.6%, recovering 120 min after the attack. Under the block reading of Q2, participation 1.000 and active share 20.3% in every seed, the same as without the attack, because the pool's votes are in blocks whatever the aggregator kept; its weight share is 20.0% in every row (weight is blocks). The attack's only cost under either reading is lock latency, median 3.7 to 3.8 s against 3.4 s and p99 4.7 to 5.0 s against 4.3 to 4.4 s, because the hostile certificate needs two thirds of total from the 80% outside the pool; 0 stalls, 0 conflicting locks. With the floor at two thirds of total (O-3.15) participation enters no lock test, so the A, C, D and F1 re-run O-3.3 named would reproduce the floor-2/3 tables cell for cell. The per-block vote bound, from spec 3.4 and the measured sizes (vote item 281 B from the fork; live devnet payload max 6,580 B with 22 keys, 22 votes being 6,182 of it): at the 8,192-voter switch a checkpoint's votes are 2,301,952 B, 4.6x one block's compute mass, so they must spread over the 30-block interval, 274 votes per block on average. Proposed (decision at gate 3), written in spec 3.4.2 item 2: `max_votes_per_block` 384 on mainnet (48 on the devnet as today), 107,904 B and 21.6% of the compute mass per block, a checkpoint drained in 21.3 blocks with 1.41x headroom; a finality section budget of 128 KiB; aggregated carriage (one BLS signature and a 1,024-B bitmap per checkpoint, 0.24% of the mass) as the mainnet producer's default. Status stays Closed by rule; parameter proposed. + ### F4. It is proof of stake with extra steps "A two-thirds BLS committee that overrides the heaviest chain is a checkpoint committee. Bitcoin's entire point is that nothing overrides work. You built a PoS finality gadget and weighted it by past work instead of coins." @@ -222,12 +230,14 @@ Evidence: design doc Finality v2, Checkpoints item 4 and Residual risks bullet 1 ### F7. A 2-minute checkpoint on a DAG with a 1-hour merge bound "Kaspa treats an hour as the merge-depth bound at 1 bps. You vote on the selected-chain block at blue score 30i once the tip is 60 blocks past. Under real latency honest nodes will disagree on that block often enough to split votes at the same index and lose quorum." -Status: Answered with evidence at 1 block/s (4 October 2026, cloud devnet: 12 `igneumd` in 5 locations; propagation p50 343 ms, p99 666 ms, max 2.3 s; reorg depth over 4 hours on every node, 37,113 chain removals: p50 1, p99 3, max 5 outside the two heals, 443 to 516 at the heals; `docs/bench-log.md`, "cloud devnet"). The devnet's d = 20 is 4x the observed maximum and mainnet's d = 60 is 12x; no vote split at one index was observed (0 conflicting locks). Other block rates stay open (O-3.2). Was: Open, experiment scheduled. +Status: Answered with evidence at 1 block/s (4 October 2026, cloud devnet: 12 `igneumd` in 5 locations; propagation p50 343 ms, p99 666 ms, max 2.3 s; reorg depth over 4 hours on every node, 37,113 chain removals: p50 1, p99 3, max 5 outside the two heals, 443 to 516 at the heals; `docs/bench-log.md`, "cloud devnet"). The devnet's d = 20 is 4x the observed maximum and mainnet's d = 60 is 12x; no vote split at one index was observed (0 conflicting locks). Other block rates measured in round 2 (5 October 2026, night, below: 2 and 5 blocks/s on the fast-time 3-node network, 0 conflicting locks, reorg max 3 and 7 blocks against d = 20); O-3.2 keeps the WAN run at those rates. Was: Open, experiment scheduled. Answer: Fair. The depth d is "set from the devnet reorg-depth distribution, 60 at one block a second", and that distribution has not been measured. The devnet experiment in gate 3 runs with regional latency and records the reorg-depth distribution at each block rate; d is chosen so that a vote split at one index is rare and self-heals at the next. Until then 60 is a placeholder. The chain also runs without the finality module (plain GHOSTDAG) so a wrong d can be corrected without a stop. Evidence: design doc Finality v2, Checkpoints item 1 and "Three experiments before gate 3". +Round 2 (5 October 2026, night): the other block rates, measured on the fast-time 3-node network with proxied 100-ms links at 1, 2 and 5 blocks/s, 330 s each after a 120-s warm-up, the `blockrate` object set to the fork's own `Bps` constants and every DAA window scaled by B (`tools/finality-attacks/f7.mjs`, bench-log "ledger close round 2: F7"). Reorg depth (every `virtualChainChanged` removal on every node): p50 1 / 1 / 1, p99 2 / 3 / 6, max 2 / 3 / 7 blocks at 1 / 2 / 5 blocks/s over 114 / 254 / 690 removals, so d = 20 is 10x / 6.7x / 2.9x the observed maximum. Propagation to the last node p50 614 / 615 / 613 ms and p99 803 / 938 / 811 ms (the rate does not move it; the 1 block/s row matches M21's 616 / 814 and sits under the cloud's tail). No vote split at any rate: 0 conflicting locks at one index, 0 CONFLICTING certificates, 0 re-determinations, every checkpoint after the window filled locked on all three nodes (10 / 20 / 55 locks). k from the fork's `calculate_ghostdag_k` at the measured p99: 5 / 9 / 15 against the fork's 18 / 31 / 67 at D = 5 s, 5.3x to 6.2x of delay headroom. By C1's rule that d scales with the rate, d = 60 B keeps the determination 60 s behind the checkpoint and is 40x tonight's maximum at 2 blocks/s and 43x at 5. What O-3.2 still owes is the same measurement on a WAN at 2 and 5 blocks/s (the cloud devnet ran 1 block/s only) and with bodies near the mass limit. + ### F8. The simulation has no network in it "No latency, no DAG, no red blocks, no partitions, no VRF noise, perfect retarget. You published 'ten days' and 'twenty days' from that." @@ -313,7 +323,7 @@ Evidence: design doc "Unit economics of a proof"; litepaper "What Igneum does no ### P3. A phone verifies in milliseconds is a SNARK-wrapper claim "Hash-based STARK proofs are hundreds of kilobytes and take real work to verify. Milliseconds on a phone means a Groth16 or Plonk wrapper, and wrapping SP1 proofs needs a big machine for minutes." -Status: Open (the wrapper on consumer hardware, phase two), text stated (5 October 2026, night): `site/litepaper.html`, Proving, "Wrapped for light clients, a phone checks it in milliseconds; the wrapping cost is a phase two measurement", followed by the certificate-half numbers (139 to 155 ms cold, 58 to 68 ms warm, laptop core, no phone) from `docs/bench-log.md` "FUD ledger sweep round 6", P3. Was: Open, the certificate half measured in a phone-sized tab, the wrapper half unmeasured and unbuilt (5 October 2026, evening sweep). Was: Open, experiment scheduled. Sweep (5 October 2026): hardware item (the wrapper on consumer hardware); not runnable here. +Status: Open, blocked on phase 2 (the Groth16 or Plonk wrapper of the SP1 compressed proof is unbuilt; the certificate half is measured): next measurement the phase 2 benchmark, design R4 (Nov 2026 to Jan 2027 per the litepaper roadmap), a wrapped segment proof timed on a 12 GB and a 24 GB card and verified on a phone. Was: Open (the wrapper on consumer hardware, phase two), text stated (5 October 2026, night): `site/litepaper.html`, Proving, "Wrapped for light clients, a phone checks it in milliseconds; the wrapping cost is a phase two measurement", followed by the certificate-half numbers (139 to 155 ms cold, 58 to 68 ms warm, laptop core, no phone) from `docs/bench-log.md` "FUD ledger sweep round 6", P3. Was: Open, the certificate half measured in a phone-sized tab, the wrapper half unmeasured and unbuilt (5 October 2026, evening sweep). Was: Open, experiment scheduled. Sweep (5 October 2026): hardware item (the wrapper on consumer hardware); not runnable here. Sweep (5 October 2026, evening): what the homepage verifier measures is a BLS certificate, not a SNARK: `site/verify/core.js` recomputes 21 header hashes (BLAKE2b), checks the voter list's canonical order, sums the 16 signers' G1 keys and checks one BLS12-381 aggregate signature, in pure JavaScript (`@noble/curves` 2.4.0). Measured tonight on `https://igneum.network/verify/test.html` against the live checkpoint 3668 (16 of 21 signers, 72.3% of weight): in the built-in browser pane's mobile emulation (375 x 812, an Android user agent, three loads) the genuine certificate verified in 139.1, 150.2 and 155.3 ms cold and 68.3, 58.4 and 64.8 ms warm; the same page at desktop size on the same machine 151 and 63.3 ms. Emulation changes the viewport and the user agent and nothing else: the CPU is this M5 Max under a load average above 100 (two builds and the C4 harness running), so the mobile and desktop numbers are the same number, and the 15 to 66 ms of `docs/plans/morning-2026-10-04.md` is the same laptop idle. What is NOT measured: any phone (a 2024 phone core is 2x to 4x slower than this laptop core on scalar JavaScript, approximate, so 150 to 600 ms cold for the certificate alone); and the thing the critic names, the wrapped block proof. No wrapper exists: the light verifier of the pinned SP1 compressed proof takes 1.3 to 2.1 s of setup plus 2 to 108 ms per verify on this Mac (bench-log 5 October, "the program id split"), is a 58 MB native binary, and a Groth16 or Plonk wrap of it is unbuilt (phase 2 benchmark). The litepaper's phone claim stays "wrapped for light clients" until the wrapper is measured on a phone. @@ -321,6 +331,8 @@ Answer: Correct. The light-client proof is the aggregated block proof wrapped on Evidence: not yet. Fix: overclaims list, item 25. +Round 2 (5 October 2026, night): status made terminal-explicit. Blocker: the wrapper (design 5.6 `wrap`, R4) does not exist in the repository; the light verifier of the pinned compressed proof is a 58 MB native binary (bench-log 5 October, "the program id split"). Next date: the phase 2 benchmark. Nothing else in the entry changes. + ### P4. Trustless light clients need a consensus proof you do not have "Checking 'one proof and one locked checkpoint' means verifying a BLS certificate against two thirds of active 30-day weight. Computing that weight needs 30 days of headers. Your own review scoped the consensus proof as phase two. The litepaper sells it at launch." @@ -375,7 +387,8 @@ Evidence: design doc "Proving speed on consumer GPUs" risk item and Finality v2 ### P9. Shard griefing "Claim a shard with a small bond and never prove it. Repeat. Finality waits on you." -Status: Answered by design, parameter table written from the live numbers (5 October 2026, evening sweep). Was: Answered by design, parameters open. Sweep (5 October 2026): the parameters (O-5.6) are phase 4 devnet work; the economy simulator's lever study found the claim timeout a market parameter and recommends starting the devnet at 120 s (`docs/analysis/economy-2026-10-04.md` section 6). +Status: Decided (6 October 2026, 17:25 UTC, by the owner; decisions item 10): the parameter table's values are the phase 4 devnet's starting values (8 assignees, a 25-s exclusive window, a 120-s job claim timeout, no shard bond, the external job bond set on the devnet); the devnet measurement moves them. Was: Answered by design, parameter table written from the live numbers (5 October 2026, evening sweep). Was: Answered by design, parameters open. Sweep (5 October 2026): the parameters (O-5.6) are phase 4 devnet work; the economy simulator's lever study found the claim timeout a market parameter and recommends starting the devnet at 120 s (`docs/analysis/economy-2026-10-04.md` section 6). +Decision owner: the project lead, decided 6 October 2026 (`docs/plans/ledger-decisions.md`, outcomes section). Sweep (5 October 2026, evening): shards carry no bond (spec 7.2, P13), so shard griefing is a prover sitting on an exclusive window; the only bond is the external job's. The table, from the live devnet at 16:00 UTC (`igneum_getProvingStatus` on the Mac node: 352 shards paid, pool 19 entries, 0 failed, 0 pending, 154 verified; the task's figure of 215 paid was the morning's) and the measured shard times: @@ -621,8 +634,6 @@ Evidence: design doc Finality v2, Fork choice items 1 to 4; `sim/results.md` fin Sweep (5 October 2026, evening): the module-on against module-off comparison of O-3.8, run on the fast-time harness with the live node line (`tools/finality-attacks/c4.mjs`, fork 2b6d23ef, 3 nodes, 100-ms proxied links; raw tables in `docs/bench-log.md`, "FUD ledger sweep round 6", C4). The scenario separates weight from work: side B (n1, n2, four keys) holds 70% of the weight table and side A (n0, two keys) 30% when the link is cut; from the cut A mines at 0.6 blocks/s and B at 0.4, so A's chain is the heavier one by blue work while only B can certify under rule v3 (A holds 30% of the frozen table). Module off (`min_daa` never, so no certificate can form, fork choice bare GHOSTDAG): after a 150-s split the three nodes converged on A's heavier chain within 36 s of the heal, B's nodes re-determined their two split-time checkpoints onto it (F24), 0 conflicts. Module on (rule v3 from checkpoint DAA 0), 90-s split, n0 back on the link 6 s after the heal, A's chain at about 58 DAA of its own time, well inside the 120-DAA frozen table: during the split A locked nothing and B locked indices 7 and 8 on its own blocks, as designed; after the heal n0 did not switch. Its log: B's certificates for 8 and 9 arrived and were "kept pending until the chain decides (no lock at this index)" (the F24 path), n0's chain never changed because GHOSTDAG prefers its heavier tip and nothing in the node turns a verified certificate over an off-chain block into a fork-choice constraint, and one window after n0's last lock (index 7 at DAA 209, so from DAA 329) the frozen table no longer applied on A's chain ("no frozen table (no lock on this chain inside the window)"), A's two keys were 100% of A's own window table (B's post-cut blocks are red there and earn nothing), and n0 locked 10, 11 and 12 alone; B's certificates for 10 and 11 then logged CONFLICTING on n0, and B's nodes kept their certified chain. End state: sinks apart, 2 locked indices disagreeing across the nodes, a finality fork from a 96-s honest partition with no attacker and the frozen table intact at the heal; the same shape with a 150-s split (the table expired at the heal) and under rule v2 (the control: 1 conflict, sinks apart). So the answer to the critic is sharper than conceded: the overlay is specified to override blue work (spec 3.5, "GHOSTDAG among tips through all certified checkpoints") but the shipped node applies a certificate only to a block on its own chain, holds the rest pending a reorg that GHOSTDAG alone never produces, and after one window the heavier side certifies its own chain. Two honest views never reconcile. What closes it: a verified certificate over a block the node does not have on its selected chain must verify against the weight table at THAT block (its signers' weight there) and, when valid, constrain fork choice to tips through it, forcing the reorg (a certificate-driven reorg, bounded by the finality depth), with the node's own unlocked records re-determined on the new chain (F24); until then the exchange guidance of 3.9 (a node partitioned for more than a minute treats its locks as proof of work until it has seen the network's certificates agree with its own) is the only protection, and the 3.11.7 row for this case ("a certificate over a chain the node is not on") is missing. On the live devnet the window is 7,200 DAA (two hours) and the cliff is two hours after a side's last lock; a miner who joins with more hashrate than the weight table credits is the realistic work-majority side. The trace-driven adversary of O-3.8 is still owed. Spec rows: 3.5, 3.11.4, 3.11.7; node: `processes/finality.rs` (`ingest_certificate`'s pending branch, `fork_choice_lock`). Decision owner: the project lead (gate 3; a rule change to the node's fork choice). -Fix (5 October 2026, night): the certificate-driven reorg, built, unit-tested and measured; fork branch `c4-fix` on release-0.3.6 (a24ab01a), main branch `c4-fix`. The cause in the code: `processes/finality.rs` `ingest_certificate` verified a certificate only over the node's own determination and sent every other block to `hold_pending`; `fork_choice_lock` reads `state.locks`, which only `evaluate` filled over the node's own chain; so a certified block off the chain never became a lock. A second cause only the harness showed: the block relay (`protocol/flows/src/v10/blockrelay/flow.rs`) skips a relayed block lighter than the virtual's merge-depth root, and the certified chain is the lighter one by construction, so the heavier side never even received it. The fix: `ingest_off_chain` verifies a certificate against the voter table at its own block (canonical list, aggregate BLS, 2/3 of active and of total there, the frozen table under v3, the first-month gate), checks the block lies on the chain through the node's nearest locks (else CONFLICTING, 3.11.4, no lock withdrawn), locks the index on that block and asks the virtual processor to resolve (`VirtualStateProcessingMessage::Resolve`), so the sink search keeps only tips through it, whatever the blue work and whatever the merge depth (finality outranks merge depth; the depth-based finality point still bounds it, Kaspa's pruning safety, logged once); pending certificates over blocks the node lacks are retried on every virtual change; `evaluate` locks the node's own determination only on the chain through its locks; and while a pending certificate names a block the node lacks (`finality_wants_blocks`), the relay takes the lighter block, which orphans, falls out of range and triggers IBD of the certified chain. Not gated on v3: the live devnet's rule v2 took the same pending path (unit test `the_certificate_driven_reorg_holds_under_rule_v2`). Spec 3.5 carries the rule in one paragraph, 3.2 C4 and the 3.10 rows C4 and F1/F2 the implementation. Measured (bench-log "the C4 fix", `c4.mjs` with `WINDOW=240` so a 130-s split plus the 84-s p2p reconnect stays inside the window; the sweep's 120-DAA framing crosses F21's bound before any certificate can arrive once the real reconnect time is counted): under rule v2 side B locked index 12 during the split, n0 took B's first relayed block through the hook, locked 12, 13 and 14 by certificate within 2 s, re-determined 11, and all three nodes ended on B's certified chain with 0 CONFLICTING and 0 disagreeing locked indices (was: sinks apart, 5 conflicts on each node, 2 disagreeing); the module-off control is unchanged (heavier chain, 0 conflicts); under rule v3 (frozen table on, 140-s split, n0 reconnected 3 s after the heal) B locked 11 and 12 during the split, n0 adopted 12 by certificate and verified 11 on the new chain, all three nodes on B's chain, 0 CONFLICTING, 0 disagreeing; the mirror case (B certified nothing, A certified after the heal) had B's nodes adopt A's certificates and move before IBD. Unit tests on PC 2: `kaspa-consensus` 97 passed, `kaspa-consensus-core` 101 passed. Still owed: the live-devnet partition test of O-3.6 and the trace-driven adversary of O-3.8. What the fix does not cover, by design: a partition that outlasts the bound before the certificate arrives (the side has locked alone, 3.11.4 keeps it, the late certificate is CONFLICTING for the operator), which on the devnet means over two hours. Rollout: a consensus-behaviour change in the node with no params-digest change; a mixed fleet disagrees only in the state the old node already got wrong (an old node holds the certificate pending and stays on its heavier chain while new nodes move), and converges once every node is new; ship in the next node release with every node restarted on it. - ### C5. vs Ethereum: you compare inclusion to finality "'Included in about one second, against twelve on Ethereum.' Inclusion in a DAG is not confirmation. Ethereum's twelve seconds is a slot, its finality is about thirteen minutes, and you compare your two-minute lock to that as if a two-minute lock by a pool committee were the same thing." @@ -712,7 +723,8 @@ Evidence: CLAUDE.md rules (privacy rejected). Fix: overclaims list, item 68. ### L1. It is a security under Howey "A founder's company earns a dev fee, runs a pool and a proving business, seeds the DEX, pays 'launch grants', and the roadmap ends in 'exchange listings after'. Expectation of profit from the efforts of others, in writing." -Status: Open, counsel not yet engaged. Sweep (5 October 2026): counsel; nothing runnable. +Status: Open, counsel engaged (6 October 2026, 17:25 UTC, by the owner; decisions item 6, in progress). Was: Open, counsel not yet engaged. Sweep (5 October 2026): counsel; nothing runnable. +Decision owner: the project lead, decided 6 October 2026 (`docs/plans/ledger-decisions.md`, outcomes section). Decision owner (5 October 2026, evening sweep): the project lead, with counsel; nothing runnable here. Answer: There is no sale, no premine, no allocation and no promise of return, and nothing in consensus is controlled by the team and no protocol fee reaches it (the development fund was removed on 3 October 2026), which is the structure that regulators have treated most favourably (approximate: compare the SEC's own framework on sufficiently decentralised networks and MiCA's exemption for tokens created automatically as a reward for maintaining a distributed ledger, approximate quotation). The weak points a lawyer will circle are the ones quoted: founder-run pool and proving business, founder-seeded DEX, launch grants, and the phrase "exchange listings after". None is in consensus; all are promotional. The litepaper must drop the listing sentence and counsel must review the founder-business paragraph before v0.2. The legal entity is "offshore, parked" in the design doc, which is not an answer. @@ -722,7 +734,8 @@ Evidence: design doc "Legal" paragraph. Fix: overclaims list, items 75 and 76. ### L2. Financial promotion rules "Several jurisdictions now treat a cryptoasset promotion to their consumers as regulated: the UK since October 2023 needs an authorised approver, the EU under MiCA has its own marketing rules, the US has the Howey test. 'The people who show up early get the most' on a domain you own is a promotion wherever the reader sits." -Status: Open, counsel not yet engaged (decision owner the project lead, with counsel); text half stated (5 October 2026, night): `site/litepaper.html`, Economics, Supply, "Nearly a quarter of all supply is mined in the first year and half in the first two." with no "so" clause (overclaims 54 and 76, fud-fixes row 6); "Half of all IGN" absent from `site/index.html`. Was: Open, counsel not yet engaged. Sweep (5 October 2026): counsel; nothing runnable. +Status: Open, counsel engaged (6 October 2026, 17:25 UTC, by the owner; decisions item 6, in progress); the text half is stated below. Was: Open, counsel not yet engaged (decision owner the project lead, with counsel); text half stated (5 October 2026, night): `site/litepaper.html`, Economics, Supply, "Nearly a quarter of all supply is mined in the first year and half in the first two." with no "so" clause (overclaims 54 and 76, fud-fixes row 6); "Half of all IGN" absent from `site/index.html`. Was: Open, counsel not yet engaged. Sweep (5 October 2026): counsel; nothing runnable. +Decision owner: the project lead, decided 6 October 2026 (`docs/plans/ledger-decisions.md`, outcomes section). Decision owner (5 October 2026, evening sweep): the project lead, with counsel; nothing runnable here. Answer: A litepaper describing how to mine a coin that does not exist is arguably not an invitation to engage in investment activity, and the regime has carve-outs for information that is not an inducement (approximate; this needs an opinion from counsel in the jurisdiction the project is established in, which is offshore and not yet named). Sentences that read as inducements to acquire ("show up early get the most", "half of all supply in the first two years") should be rewritten as schedule facts before v0.2. Country-code domains such as igneum.co.uk redirect to igneum.network and carry no separate content. @@ -732,7 +745,8 @@ Evidence: none. Fix: overclaims list, item 77. ### L3. GoDaddy domains are a seizure risk "Fifteen domains at a US registrar on US nameservers behind a US host. One court order and igneum.network is a parking page." -Status: Conceded, mitigation scheduled. Sweep (5 October 2026): a deSEC token now sits in `~/.config/igneum` (mode 600), so the nameserver move of fud-fixes row 44 has started; the registrar move waits for December. +Status: Decided (6 October 2026, 17:25 UTC, by the owner; decisions item 7): the nameserver move to deSEC in one sitting with every domain's Vercel verification checked afterwards; a non-US registrar in December 2026 when the transfer lock ends. Was: Conceded, mitigation scheduled. Sweep (5 October 2026): a deSEC token now sits in `~/.config/igneum` (mode 600), so the nameserver move of fud-fixes row 44 has started; the registrar move waits for December. +Decision owner: the project lead, decided 6 October 2026 (`docs/plans/ledger-decisions.md`, outcomes section). Decision owner (5 October 2026, evening sweep): the project lead, with counsel; nothing runnable here. Answer: True. GoDaddy and Vercel are both US companies and have both complied with takedowns. Mitigations: an ENS or equivalent name and an IPFS mirror of the site and litepaper, the site's content hash published in the repository and in the genesis block, at least one non-US registrar for a second TLD, and the chain itself never depending on any domain (seed nodes are addresses in the client, not DNS only). Phase 5. @@ -742,7 +756,8 @@ Evidence: CLAUDE.md "Domains". Mitigation: not yet. ### L4. Paying testnet miners real money is a payment before launch "'Testnet miners are paid real money for real proofs from phase five.' That is a business paying contractors in crypto across borders with no entity." -Status: Open. Sweep (5 October 2026): counsel and entity; nothing runnable. +Status: Open, counsel engaged (6 October 2026, 17:25 UTC, by the owner; decisions item 6, in progress). Was: Open. Sweep (5 October 2026): counsel and entity; nothing runnable. +Decision owner: the project lead, decided 6 October 2026 (`docs/plans/ledger-decisions.md`, outcomes section). Decision owner (5 October 2026, evening sweep): the project lead, with counsel; nothing runnable here. Answer: Correct that it needs an entity, terms and tax treatment before it happens. The payments come from the customer rollup on its own chain, not from Igneum, but the arrangement is organised by the project. Counsel before phase 5. @@ -752,7 +767,8 @@ Evidence: design doc "The first six months". ### L5. Trademark "Igneum. Have you checked EUIPO, USPTO and the UK IPO? There is no evidence you did." -Status: Open. Sweep (5 October 2026): a person's search, recorded outside the repository; nothing runnable. +Status: Open, counsel engaged (6 October 2026, 17:25 UTC, by the owner; decisions item 6, in progress): the clearance search is recorded in the repository as a dated one-line result per register when it returns. Was: Open. Sweep (5 October 2026): a person's search, recorded outside the repository; nothing runnable. +Decision owner: the project lead, decided 6 October 2026 (`docs/plans/ledger-decisions.md`, outcomes section). Decision owner (5 October 2026, evening sweep): the project lead, with counsel; nothing runnable here. Answer: No clearance search is recorded in the repository. One is required before the name is used commercially, in all three registers and in Nice classes 9, 36 and 42, approximate. Until then the name is provisional and the litepaper should not claim otherwise. @@ -817,7 +833,8 @@ Evidence: litepaper "Roadmap"; design doc "Team". ### X5. 1,000 independent miners is a Sybil number "Your testnet gate is 1,000 independent miners for 30 days. One person with a script is 1,000 miners." -Status: Conceded, measurement defined from the vote-key window and today's numbers (5 October 2026, evening sweep); decision owner the project lead (O-X.1). Was: Conceded, measurement to define. +Status: Decided (6 October 2026, 17:25 UTC, by the owner; decisions item 3): the independence definition as written, with the silent-fleet addition (a key with no fingerprint counts as its own class only when its address is in an autonomous system no other key uses); the observer columns on `ledger-observer` (O-X.1) ship with the next cut; measurement scheduled. Was: Conceded, measurement defined from the vote-key window and today's numbers (5 October 2026, evening sweep); decision owner the project lead (O-X.1). Was: Conceded, measurement to define. +Decision owner: the project lead, decided 6 October 2026 (`docs/plans/ledger-decisions.md`, outcomes section). Sweep (5 October 2026, evening): the definition, measurable from chain data plus two attestations, and today's reading. Unit: a vote key with at least the dust count of blue blocks in the 30-day weight window (W3), which is the smallest thing the chain can count. Independence: two keys are independent when they differ in all three of (a) the autonomous system of the address their blocks' nodes announce (seed and peer tables, the observer's address field), (b) the machine fingerprint the miner app sends with its log uploads (`machine_id`, already in every STATUS line's run id), and (c) the pool attestation, a signed statement by a pool operator listing the keys it runs (absent for solo keys). N_ind = the number of distinct (ASN, fingerprint, pool) classes among eligible keys; the gate of `site/journey.json` phase 5 reads "N_ind >= 1,000 over the same 30 days with top-10 share of window weight under 50%". Today's reading from the live window (Mac node, `getFinalityWeights` at DAA 112,395): 22 keys, 21 voters above dust (dust 5 on the devnet), total weight 7,196 of 7,200 blue blocks; top-1 share 8.3%, top-3 20.3%, top-5 31.9%, top-10 60.3%; the console counts 5 machines and 21 identities in 10 minutes, so the fleet runs 4.2 keys per machine (the launcher's one key per worker, F17's client default) and N_ind by fingerprint alone is 5, by ASN at most 3 (two home networks and one US household, approximate). That is the Sybil ratio the critic means, measured: 21 "miners" are 5 machines. The hashing concentration of X14 (top-1 12.8%, top-3 34.5% over 8,090 blocks on 4 October) and tonight's weight shares agree within the window's drift. What the observer must add (O-X.1): the ASN per announcing address, the fingerprint per key (the app already has both), and the pool statement format. @@ -827,6 +844,8 @@ Evidence: `site/journey.json` phase 5 gate. Cross-reference (external review, 3 October 2026, night): the definition and the four concentration metrics are X14, O-X.1. +Round 2 (5 October 2026, night), the observer columns (O-X.1), built on branch `ledger-observer` and NOT deployed; the running observer is untouched and the definition stays this decision (item 3). `tools/observer/observer.mjs` on that branch adds four tables and three timers (`tools/observer/README.md`, "Independence columns and the nightly table"): (a) `live_peer_asn`, the autonomous system per announcing peer address from `getConnectedPeerInfo` against an offline prefix table (`tools/observer/asn-table.txt`, empty tonight, to be filled from a dated BGP dump: RIPEstat, Team Cymru bulk whois or a pyasn dump of RouteViews; no third party is asked at run time; private ranges read `local`, a miss stays `source = 'none'`); (b) `live_key_machines`, the machine fingerprint per vote key from the log intake (`miner_logs.machine`, the id8 every STATUS line's run id carries, joined to the miner's `identity N 'label' vote_key_hash=...` line in the same upload); (c) `live_pool_statements`, the pool statement format: a signed JSON `{format: "igneum-pool-statement-1", pool, keys[], signed_at, pubkey, sig}`, Ed25519 over canonical bytes, verified against `pool-statements/registry.json` (pool label to key; empty tonight), refused when signed by another key, older than 35 days, with repeated keys or a malformed shape, and stored with the reason when it fails; (d) `live_concentration`, one row a day at 00:05 UTC with top-1, top-3 and top-10 shares for hashing (`getFinalityWeights`), signing (the stored `live_certificates` bitmaps over their voter tables), proving (`live_proofs` paid shards per prover) and aggregation (`certificateAggregator` over the window's checkpoints), plus `n_ind` with `n_ind_definition = 'proposed'`: distinct (ASN, fingerprint, pool) classes among keys above dust, the silent-key rule of the decision request applied (a key with no fingerprint is its own class only when its ASN is used by no other key), and `n_ind_unattributed` counting keys with no attribute at all. Pure functions in `tools/observer/lib/concentration.mjs` and `lib/nightly.mjs`; 9 unit tests under node's test runner (`node --test 'tools/observer/test/*.test.mjs'`: the payload decoder against hand-built fixtures, the voter-table rebuild rule, shares, N_ind on the 21-keys-5-machines reading of this entry (5) and the silent-fleet rule, the pool statement's signing and every refusal, the ASN table's longest prefix, the nightly row), all passing on the Mac. Open: a block names its producer by vote key and a peer announces an address, and nothing ties the two, so the ASN per key is null until the app reports its public address with its uploads (an app-owner item); the ASN table and the pool registry are empty until filled by hand. Tonight's reading from X14's round 2 (23:00 UTC, DAA 138,542): 27 keys above dust over 5 machines in the window, 3 of them live at the reading, so N_ind by fingerprint is at most 5 (approximate, from the console; the fingerprint column will give the exact figure once deployed) and the top-10 share of window weight is 60.1%, against the gate's "under 50%". + ### X6. The one-click app is a honeypot vector "An installer that creates a wallet, holds keys and mines, promoted to people who have never run a miner. Fake copies will be the first Google result. Defender flags every miner as malware." @@ -1149,12 +1168,14 @@ Added by `docs/review/round-3-2026-10-03.md`, which holds the full argument for ### M14. A pulsed rental against the block-count DAA buys weight at a discount "Bring 50x the hashrate for two minutes once an hour. Kaspa's window keeps the 661 most recent samples, so you mine thousands of blocks at the old target before it moves, and when you leave the honest network crawls for hours at your difficulty. Weight is blocks over a window of blocks. You get a third of the window in a week for the price of a 1.6x average." -Status: Answered with evidence for the controller half (5 October 2026 sweep); the finality run with the DAA inside `finality_v2.py` (O-3.14) is still owed (fud-fixes row 123). Chain model, `sim/difficulty/attacks/attacks.py --scenario pulse --rules 'igneum:ref_window=600+long_min=100000,kaspa' --seeds 3` (rule v2, the live rule since DAA 33,000, and Kaspa's DAA; 36 s, 5 October 2026): a 50x pulse for 10 min of every hour earns 3.7% of the always-on base's blocks per hash under rule v2 (weight per hash 0.262, worst seed 0.266) and 85.5% under Kaspa's rule (0.983); a single pulse earns 2.8% (0.130) and 56.8% (0.871). Under neither rule does a pulse earn more blocks per hash than steady mining, so the amplifier the critic describes is at most 1.0 in the chain model and the pulse is a loss; the cost it imposes on others is the crawl afterwards (rule v2: the base's blocks per hash down 36% in the hour after, worst gap 199 s, peak 185 blocks a minute; Kaspa's rule: peak 1,734 blocks a minute, 70 to 88% of blocks to the pulser for 81 to 89% of hashes). On the fork itself, `tools/finality-attacks` s5 (10x for 20 s of every 120 s under Kaspa's DAA, 4 October) measured weight share 35.3% against block share 35.3%, ratio 0.999. The hop profiles are in `sim/difficulty/results.md` (hop3, hop10, polluted). Was: Open, experiment scheduled as O-3.14 (3 October 2026). +Status: Answered with evidence (5 October 2026, night, ledger close round 1: the finality run with the DAA in the loop, O-3.14, fud-fixes row 123; bench-log "5 October 2026 (night), ledger close round 1: M14 and F14 the 50x pulse against a lagging retarget inside the finality simulator, both W2 forms"). Was: Answered with evidence for the controller half (5 October 2026 sweep); the finality run with the DAA inside `finality_v2.py` (O-3.14) is still owed (fud-fixes row 123). Chain model, `sim/difficulty/attacks/attacks.py --scenario pulse --rules 'igneum:ref_window=600+long_min=100000,kaspa' --seeds 3` (rule v2, the live rule since DAA 33,000, and Kaspa's DAA; 36 s, 5 October 2026): a 50x pulse for 10 min of every hour earns 3.7% of the always-on base's blocks per hash under rule v2 (weight per hash 0.262, worst seed 0.266) and 85.5% under Kaspa's rule (0.983); a single pulse earns 2.8% (0.130) and 56.8% (0.871). Under neither rule does a pulse earn more blocks per hash than steady mining, so the amplifier the critic describes is at most 1.0 in the chain model and the pulse is a loss; the cost it imposes on others is the crawl afterwards (rule v2: the base's blocks per hash down 36% in the hour after, worst gap 199 s, peak 185 blocks a minute; Kaspa's rule: peak 1,734 blocks a minute, 70 to 88% of blocks to the pulser for 81 to 89% of hashes). On the fork itself, `tools/finality-attacks` s5 (10x for 20 s of every 120 s under Kaspa's DAA, 4 October) measured weight share 35.3% against block share 35.3%, ratio 0.999. The hop profiles are in `sim/difficulty/results.md` (hop3, hop10, polluted). Was: Open, experiment scheduled as O-3.14 (3 October 2026). Answer: Correct in mechanism and unmeasured in size. `sim/results_v2.md` runs every scenario with a perfect retarget (its assumption table) and no finality run has a DAA model (O-3.9). Tonight's honest step on the devnet showed the lag: 5.67 blocks a second in a two-minute bucket after the first retarget, 2,248 blocks in eight minutes against 480 expected, and 1.5 blocks a second an hour later (`docs/review/round-3-2026-10-03.md`, "Tonight's devnet"). The review's estimate is that a pulse buys under two windows of blocks (about 5,000) and the chain crawls after each, so the amplifier over the formula is about 2x at the cost of a visible attack; the estimate is not a simulation. The same lag is the farm operator's hop profit (`sim/difficulty/sim.py` profiles `hop3`, `hop10`, `polluted`), for which no result is in the bench-log. Fix in two parts: the controller (gate 2, O-2.1, with the simulation results logged) and the weight rule (F14). Evidence: `node1.log` of 3 October 2026 and `sim/difficulty/devnet-2026-10-03.csv`; `sim/results_v2.md` assumptions. Experiment: `finality_v2.py` with the Kaspa DAA and the two-lane candidate in the loop against a 50x pulsed renter, reporting the day it crosses a third; `sim/difficulty/sim.py` results in the bench-log. Review id R3.1. +Run (5 October 2026, night, one run for M14 and F14): `tools/lock/with-lock.sh run python3 sim/finality_v2.py --scenarios N --seeds 7,11,13 --days 30` (new: `sim/daa_trace.py` puts Kaspa's sampled DAA and the Igneum rule v2 of `sim/difficulty/sim.py` inside the finality simulator's block supply; scenario N counts the weight under both W2 forms), 382 s wall. A renter at 50x the honest hashrate for 10 minutes of every hour (89.3% of all hashes) for 30 days, signing every checkpoint. Weight share over hash share, the amplifier the critic names, is under 1.0 in every cell. Kaspa's DAA: 87.4% of the blocks (0.96 of par), 1,716 to 1,753 blocks in the peak minute, gaps to 262 s; under the DAA-second window the renter holds a third on day 12 and 86.0% on day 30; under the median-time form 16.5% on day 30 and never a third. Igneum rule v2: 23.3% of the blocks (0.036 blocks per hash against the base's, 0.22 of par), 201 blocks in the peak minute, gaps to 444 s; the renter never reaches a third under either form (19.6% DAA form, 16.8% median form at day 30). 0 stalled checkpoints and 0 conflicting locks in all four cells, 3 seeds within 0.1 point of each other. So the controller fix (rule v2, live since DAA 33,000) alone keeps a 50x pulse under a third for the price of 89% of the hashes, and the F14 median-time form caps it at 17% under either controller. Bench-log heading: "5 October 2026 (night), ledger close round 1: M14 and F14 the 50x pulse against a lagging retarget inside the finality simulator, both W2 forms". + ### M15. A header with any past timestamp or any claimed DAA score makes the node build a 256 MiB cache "Your PoW check runs after GHOSTDAG and before the checks that validate `daa_score` and the past-median timestamp. The engine keys the program on the header's own `daa_score` and the cache on its own `timestamp`, and keeps three entries. I send headers with random past days. Each one costs you a 0.18-second ChaCha12 fill and evicts the honest epoch." @@ -1167,7 +1188,7 @@ Evidence: the files and lines above. Fix: review's first of five. Review id R3.2 ### M16. The 256 MiB cache fits on a die, so the recompute attacker is compute bound "Your 4.8x-slower shortcut ran with the cache in DRAM behind a chip that cannot hold it. Put 256 MiB of SRAM on a die and the dataset is never needed: 128 items per hash at about 1,170 integer operations and 8 near-free reads each. That is 150,000 operations per hash, and integer operations per dollar is where silicon beats a GPU." -Status: Open, cost model written, the on-die emulation still a PC job (5 October 2026, evening sweep). Was: Open, experiment scheduled. Sweep (5 October 2026): not runnable on this Mac; the on-die emulation needs the RTX 5090 (an inline kernel at a 64 MiB cache inside its 96 MiB L2). The only newer number is the loaded-Mac reconfirmation of 3 October (inline 17x slower at a 256 MiB cache, bench-log "R3.26 / M15", M16 note), which does not price a die. Hardware item. +Status: Answered with evidence (6 October 2026, night, ledger close round 2; bench-log "ledger close round 2: M16 the inline-cache kernel on the RTX 5090"): on the 5090 the recompute attacker with the cache inside the 96 MiB L2 (the SRAM emulation, 64 and 32 MiB masks, bit-exact against the stored construction) runs at 33.9 Mhash/s against 132.2 honest for the same version-2 program, 0.256x at equal silicon and 5.1x worse per joule (431 W at the power limit against 327 W); the cost model's "50 T op/s" row was arithmetic and the measurement puts the integer engine at about 6 T op/s on this chain, bound by the 1,024 dependent cache-line reads per hash. Open for gate 1: a die's own SRAM latency (approximate), the O-1.6 curve, the mixer doubling. Was: Open, the kernel written and bit-exact on the Mac, the PC 2 run queued behind the 0.3.11 rollout. Was: Open, cost model written, the on-die emulation still a PC job (5 October 2026, evening sweep). Was: Open, experiment scheduled. Sweep (5 October 2026): not runnable on this Mac; the on-die emulation needs the RTX 5090 (an inline kernel at a 64 MiB cache inside its 96 MiB L2). The only newer number is the loaded-Mac reconfirmation of 3 October (inline 17x slower at a 256 MiB cache, bench-log "R3.26 / M15", M16 note), which does not price a die. Hardware item. Sweep (5 October 2026, evening): `docs/analysis/m16-recompute-attacker-2026-10-05.md` prices the device from the specification and the measured rates. Per hash the attacker recomputes 128 items at 9 mixer applications of about 130 operations and 8 dependent 64-byte cache reads each: about 150,000 integer operations and 1,024 dependent SRAM reads (65 KB). To match one RTX 5090 at its measured 229 Mhash/s the chip needs 34 T integer op/s and 15 TB/s of SRAM bandwidth beside 256 MiB of SRAM (100 to 300 mm^2 on a current node, approximate). At the 5090's own integer budget (about 50 T op/s, approximate) that is 0.33 Ghash/s: 1.5x the measured closed-form rate, 2.4x the 141 Mhash/s projected for version 2 programs, before any fixed-function factor; with a 3x factor (approximate) 3x to 6x at equal die area. The lever: the mixer cost is paid by the honest miner once a day (13.4 ms per 1 GiB on the 5090, measured) and by the attacker per hash, so doubling it halves the attacker's rate at zero honest cost, 4x puts the equal-silicon gain at 0.36x and the factored gain near 1x, bounded by the CPU verify gate (0.41 to 1.2 ms per warp today, 10 ms the gate, so about 8x of headroom on the M5 Max core). What is still unmeasured: the inline kernel on the 5090 with a 64 MiB cache inside its L2 (the SRAM emulation, a PC job), the time-memory curve of O-1.6, and any cryptanalysis of the mixer. Decision at gate 1 (owner the project lead): cache size and mixer cost against the verify gate. @@ -1175,6 +1196,10 @@ Answer: Correct as arithmetic, unmeasured as a device. From spec 1.8.4 and 1.8.5 Evidence: spec 1.8, 1.16; `proto-metal/MEMHARD.md` 2.2 (Apple only). Experiment: `--inline-dataset` on the RTX 5090 at a 64 MiB cache (inside its 96 MiB L2, the SRAM emulation) and at 256 MiB against the honest 1 GiB kernel; the O-1.6 time-memory curve; a CPU fill and verify time at a 1 GiB cache. Decision at gate 1: cache size "exceeds what one die can hold, and grows". Review ids R3.5 and the chip designer's pricing. +Round 2 (6 October 2026, night): the CUDA inline path did not exist (the shipped worker reads the dataset only; `--inline-dataset` was Metal), so it was written as a benchmark beside the worker, never inside it: `proto-cuda/inline-bench/` (`gen.py` derives `kernel_inline.cu` and `memhard_inline.h` from the pack by counted text substitution, the 16 dataset loads of the devnet-v4 epoch-0 program becoming `mhi_word(cache, x & mask, lineMask)` with the cache-line mask a kernel argument; `inline_bench.cpp` loads the driver API and NVRTC at run time as the worker does, compiles the pack's texts, runs three bit-exact checks and then fixed-time windows for honest 1 GiB, inline at 256 MiB, inline at 64 MiB (the first quarter of the cache, inside the 5090's 96 MiB L2: the on-die SRAM emulation) and inline at 32 MiB, with an `nvidia-smi` sampler per window for E17). Mac check (host threads through the project's CUDA emulation shim, build lock, 12.3 s): check 1 the pack's self-test PASS (96 of 96 lanes); check 2 the inline kernel at the 256 MiB mask equals the pack's vectors on all 96 lanes, the dataset never read (this is what proves the substitution and the derivation); check 3 at the 64 MiB and 32 MiB masks a stored dataset built at that mask and read by the honest kernel equals the recomputed path on 8,288 lanes each, and differs from the pack's vectors as a smaller cache must. The Windows exe (mingw, 355,840 bytes, sha256 2e6a21de...) and the pack with the inline texts went to the downloads host as `igneum-inline-bench-kit.zip` (202,138 bytes, sha256 80ce0290...); the PC 2 job (one `run` job, the app's miners paused and the live prover off for about 4 minutes on the card, both restored, two passes at 1 and 8 warps per block, 15 s per setting) waits on the scheduler's go behind the 0.3.11 rollout. What the number will test: the analysis's "50 T op/s" row, 1.5x the measured 229 Mhash/s and 2.4x the projected 141 at equal integer budget; the inline64 rate IS the attacker's rate on this silicon with the cache in L2, so the gain is inline64 over honest, before any fixed-function factor. The CPU fill and verify at a 1 GiB cache and the O-1.6 curve are not part of this job. + +The PC 2 run (6 October 2026, 00:38 to 00:43 UTC, job `m16-inline-pc2-1`, the card taken whole with the app's miners paused and the prover off, both restored, nothing else on the card; the three checks PASS on the 5090 as on the Mac): honest 1 GiB 132.20 Mhash/s at 326.6 W median, 3,060 MHz; inline at the 256 MiB cache in VRAM 11.26 Mhash/s (0.085x) at 415.7 W; inline at the 64 MiB mask inside the L2 33.88 Mhash/s (0.256x) at 431.0 W, the power limit, clocks 2,835 MHz; inline at 32 MiB 33.87 (0.256x), the same rate, so the L2 plateau is the SRAM-class bound. Eight warps per block: 131.15 / 10.89 / 29.32 / 29.46. Reading: the attacker's rate with the cache in SRAM-class memory is a quarter of the honest rate on the same silicon, because the inline path runs 1,024 dependent cache-line reads per hash (34.7 G per second here, 2.2 TB/s of line traffic) and reaches only about 6 T integer operations per second of the card's 50 T (approximate): the cost model's equal-budget row (1.5x to 2.4x) assumed the arithmetic was the bound; it is not. With the model's approximate 3x fixed-function factor the equal-area gain is about 0.8x, before the 256 MiB SRAM's area is paid; the entry's "3x to 6x" becomes about 0.8x to 1.5x. Consequence for every GPU tier: no exposure to this device at the current parameters beyond that approximate factor; the mixer doubling stays the lever (halves 0.256x again at zero honest cost, 27 ms daily build, 0.8 to 2.4 ms per warp to verify) and is the gate-1 question for the project lead. Unmeasured: a die's own dependent-SRAM latency (a chip with the SRAM beside the ALUs shortens the chain; approximate), the O-1.6 partial-store curve, mixer cryptanalysis, the AMD tier (owed: the same kernel through OpenCL on the RX 9070 XT when PC 1 is back). + ### M17. Every ahead-of-time miner stops at the epoch boundary; whoever compiles in process mines alone "Your log: last block of epoch 0 at 21:12:14, nothing for the next 91 seconds while the Windows launcher killed eight identities, re-exported, rebuilt two binaries and restarted them. The Metal worker compiles in 129 ms. The first 2.5% of every hour goes to whoever does not use your launcher." @@ -1216,21 +1241,25 @@ Evidence: the files above. Test: sync a fresh node from the 30-hour devnet. Revi ### M21. GHOSTDAG k is Kaspa's table value for Kaspa-sized bodies "k = 18 assumes a 5-second delay bound measured with Kaspa's blocks. Yours carry EVM transactions and recursive proof records." -Status: Answered with evidence for today's bodies, Open for proof-bearing bodies (5 October 2026, evening sweep). Sweep (5 October 2026, evening): block sizes measured on the live devnet and k derived from them. The last 60 chain blocks at DAA 112,433 (Mac node, wRPC, sizes summed from the RPC fields, approximate serialisation): p50 723 bytes, p90 1,022, max 6,908 (a block carrying a certificate section), 1 transaction per block (the coinbase), coinbase payload p50 395 bytes, max 6,580; the proof records in the coinbase are 274 bytes each (unit test `largest_coinbase_fits_on_every_network`), the SP1 proof itself (1.27 MB per shard, bench-log 5 October) stays in the pool and never enters a block. Serialisation of the largest observed block on a 100 Mbit/s link is 0.6 ms per hop, so the delay bound is the propagation alone: with the fork's `calculate_ghostdag_k` (delta 0.01, x = 2 D at 1 block/s) the cloud devnet's p50 343 ms gives k 3, p90 497 ms k 4, p99 666 ms k 5, max 2.3 s k 10, and k = 18 corresponds to D = 5 s, 7.5x the measured p99. For mainnet-sized bodies: the fast-time profile's mass limits (500,000 compute mass at 1 mass per transaction byte) bound a body near 500 KB, 40 ms per hop at 100 Mbit/s and about 120 ms over the 3 hops of the cloud topology, which moves the p99 to about 0.8 s and k to 6, still 3x inside k = 18; a 5-s bound holds bodies up to about 50 MB per hop at that bandwidth. So k = 18 is Kaspa's value and it carries 3x to 7x of headroom on the measured network for any body the mass limits allow; the proof-bearing run of O-2.2 decides whether the red rate under real bodies stays near the model (bench-log "FUD ledger sweep round 6", M21). Was: Open, extends O-2.2. Sweep (5 October 2026): k re-derived with the fork's own function (`vendor/rusty-kaspa/consensus/core/src/config/bps.rs`, `calculate_ghostdag_k`, delta 0.01) at 1 block/s: a delay bound of 2 s gives k 9, 5 s gives 18, 10 s gives 31, 20 s gives 55, 30 s gives 79. Measured propagation on the 12-node, 5-region cloud devnet of 4 October with today's bodies: p99 0.67 s, max 2.3 s, which the function maps to k 5 and k 10. So k = 18 carries about 7x headroom on today's bodies; the run with proof-bearing bodies (O-2.2) is still owed and decides whether that headroom survives. +Status: Answered with evidence for the largest body the rules allow (5 October 2026, night, ledger close round 1: 490 KB coinbase bodies on the fast-time 3-node network with 100-ms proxied links, k re-derived with the fork's function, bench-log "5 October 2026 (night), ledger close round 1: M21 block propagation with bodies at the mass limit, k re-derived"); the red rate under such bodies is not measured. Was: Answered with evidence for today's bodies, Open for proof-bearing bodies (5 October 2026, evening sweep). Sweep (5 October 2026, evening): block sizes measured on the live devnet and k derived from them. The last 60 chain blocks at DAA 112,433 (Mac node, wRPC, sizes summed from the RPC fields, approximate serialisation): p50 723 bytes, p90 1,022, max 6,908 (a block carrying a certificate section), 1 transaction per block (the coinbase), coinbase payload p50 395 bytes, max 6,580; the proof records in the coinbase are 274 bytes each (unit test `largest_coinbase_fits_on_every_network`), the SP1 proof itself (1.27 MB per shard, bench-log 5 October) stays in the pool and never enters a block. Serialisation of the largest observed block on a 100 Mbit/s link is 0.6 ms per hop, so the delay bound is the propagation alone: with the fork's `calculate_ghostdag_k` (delta 0.01, x = 2 D at 1 block/s) the cloud devnet's p50 343 ms gives k 3, p90 497 ms k 4, p99 666 ms k 5, max 2.3 s k 10, and k = 18 corresponds to D = 5 s, 7.5x the measured p99. For mainnet-sized bodies: the fast-time profile's mass limits (500,000 compute mass at 1 mass per transaction byte) bound a body near 500 KB, 40 ms per hop at 100 Mbit/s and about 120 ms over the 3 hops of the cloud topology, which moves the p99 to about 0.8 s and k to 6, still 3x inside k = 18; a 5-s bound holds bodies up to about 50 MB per hop at that bandwidth. So k = 18 is Kaspa's value and it carries 3x to 7x of headroom on the measured network for any body the mass limits allow; the proof-bearing run of O-2.2 decides whether the red rate under real bodies stays near the model (bench-log "FUD ledger sweep round 6", M21). Was: Open, extends O-2.2. Sweep (5 October 2026): k re-derived with the fork's own function (`vendor/rusty-kaspa/consensus/core/src/config/bps.rs`, `calculate_ghostdag_k`, delta 0.01) at 1 block/s: a delay bound of 2 s gives k 9, 5 s gives 18, 10 s gives 31, 20 s gives 55, 30 s gives 79. Measured propagation on the 12-node, 5-region cloud devnet of 4 October with today's bodies: p99 0.67 s, max 2.3 s, which the function maps to k 5 and k 10. So k = 18 carries about 7x headroom on today's bodies; the run with proof-bearing bodies (O-2.2) is still owed and decides whether that headroom survives. Answer: Correct. Spec 2.1 takes k, max parents and the mergeset limit from Kaspa's table at 1 BPS. O-2.2's two-miner devnet measures the parallel and red rate; it should run with proof-bearing bodies of the size section 5.4 of the execution design implies, and k should be re-derived from the measured delay. Evidence: spec 2.1; `docs/design/execution-layer.md` 5.4. Review id R3.4. +Run (5 October 2026, night): `tools/lock/with-lock.sh run node tools/finality-attacks/m21.mjs` (new; the live node line `target-036` at `a24ab01a`, fast time, three nodes, proxies holding every byte 100 ms one way, no bandwidth limit, `max_coinbase_payload_len` 600,000 in the override), 375 s wall. The harness produced the blocks itself (`getBlockTemplate` with 0 and then 490,000 zero bytes of `extraData`, 180 s per size, 0.7 blocks/s on n0 and 0.3 on n2) and stamped every node's `blockAdded` notification; 490,000 B of padding is the largest body the 500,000 compute-mass limit allows (one mass per coinbase byte), and proof-bearing bodies larger than today's do not exist on this line (records 274 B, proofs never in a block). Two-hop propagation p50 / p90 / p99 / max: 626 / 824 / 1,093 / 2,099 ms with 59-byte payloads (163 blocks) and 641 / 696 / 812 / 857 ms with 490,059-byte payloads (188 blocks); one hop 318 and 329 ms at p50 (the relay is inv, request, block: three link traversals per hop); own-node processing 6 and 16 ms at p50. k from the fork's `calculate_ghostdag_k(2 D, 0.01)`: 5 from the big-body p99 (6 from the baseline's p99, whose tail fell under two other agents' jobs starting), 6 with 39 ms per hop of 100 Mbit/s serialisation added to the max. So the largest body the rules allow moves the delay bound by about 1% at p50 on emulated links and k = 18 keeps 5.3x to 5.6x of headroom here, against 7.5x on the cloud devnet with 723-byte bodies. Not measured: the red rate (one sink and 351 blocks on every node; red counts need a per-block walk). Bench-log heading: "5 October 2026 (night), ledger close round 1: M21 block propagation with bodies at the mass limit, k re-derived". + ### F14. Weight in blocks over a window in blocks under a lagging retarget "Your day counts assume the block supply is capped at one a second. It is not during a retarget lag, and weight is counted in blocks." -Status: Rule written (3 October 2026): spec 3.1 W2 and 3.3 Q1 are denominated in past-median time, weight as a key's share of each 60-s bucket summed over 30 days; the simulated DAA-score form is kept beside it. O-3.14 (added the same evening) confirms or reverts it at gate 3. Was: Open, rule change proposed. Sweep (5 October 2026): the simulated DAA-score form shows no amplification under either controller (`sim/difficulty/attacks` scenario 2: weight per hash 0.26 under Igneum, 0.98 under Kaspa; harness s5 on the fork: 0.999), so the median-time form is defence in depth whose own run, both forms with the DAA in the loop (O-3.14), is still owed. On the current node line (s5 under fast time, 5 October 2026): weight share over block share 0.864, below 1, so the window bought the pulse nothing. +Status: Answered with evidence (5 October 2026, night, ledger close round 1: both W2 forms with the DAA in the loop, O-3.14; the median-time form caps the renter at 17% under either controller and the DAA form crosses a third on day 12 only under Kaspa's controller; gate 3 confirms or reverts the rule with these numbers; bench-log "5 October 2026 (night), ledger close round 1: M14 and F14 the 50x pulse against a lagging retarget inside the finality simulator, both W2 forms"). Was: Rule written (3 October 2026): spec 3.1 W2 and 3.3 Q1 are denominated in past-median time, weight as a key's share of each 60-s bucket summed over 30 days; the simulated DAA-score form is kept beside it. O-3.14 (added the same evening) confirms or reverts it at gate 3. Was: Open, rule change proposed. Sweep (5 October 2026): the simulated DAA-score form shows no amplification under either controller (`sim/difficulty/attacks` scenario 2: weight per hash 0.26 under Igneum, 0.98 under Kaspa; harness s5 on the fork: 0.999), so the median-time form is defence in depth whose own run, both forms with the DAA in the loop (O-3.14), is still owed. On the current node line (s5 under fast time, 5 October 2026): weight share over block share 0.864, below 1, so the window bought the pulse nothing. Answer: Correct; this is the finality half of M14. Spec W2 counts blue blocks over a window of 2,592,000 DAA seconds, and DAA seconds are blocks, so a burst both inflates a key's count and ages the window. Proposed change: denominate the vote window (W2) and the presence window (Q1) in past-median time, and define weight as a key's share of the blue blocks in each 60-second median-time bucket summed over the trailing 30 days, so 50x the blocks in one minute is one minute of weight. The simulation of M14 decides. Evidence: spec 3.1 W2, 3.3 Q1; `sim/results_v2.md` assumptions. Experiment: the M14 run under both definitions. Review id R3.1. +Run (5 October 2026, night, one run for M14 and F14): `tools/lock/with-lock.sh run python3 sim/finality_v2.py --scenarios N --seeds 7,11,13 --days 30` (new: `sim/daa_trace.py` puts Kaspa's sampled DAA and the Igneum rule v2 of `sim/difficulty/sim.py` inside the finality simulator's block supply; scenario N counts the weight under both W2 forms), 382 s wall. A renter at 50x the honest hashrate for 10 minutes of every hour (89.3% of all hashes) for 30 days, signing every checkpoint. Weight share over hash share, the amplifier the critic names, is under 1.0 in every cell. Kaspa's DAA: 87.4% of the blocks (0.96 of par), 1,716 to 1,753 blocks in the peak minute, gaps to 262 s; under the DAA-second window the renter holds a third on day 12 and 86.0% on day 30; under the median-time form 16.5% on day 30 and never a third. Igneum rule v2: 23.3% of the blocks (0.036 blocks per hash against the base's, 0.22 of par), 201 blocks in the peak minute, gaps to 444 s; the renter never reaches a third under either form (19.6% DAA form, 16.8% median form at day 30). 0 stalled checkpoints and 0 conflicting locks in all four cells, 3 seeds within 0.1 point of each other. So the controller fix (rule v2, live since DAA 33,000) alone keeps a 50x pulse under a third for the price of 89% of the hashes, and the F14 median-time form caps it at 17% under either controller. Bench-log heading: "5 October 2026 (night), ledger close round 1: M14 and F14 the 50x pulse against a lagging retarget inside the finality simulator, both W2 forms". + ### F15. Merge depth is not the reorg bound; the finality depth is "You tell exchanges that in month one the one-hour merge-depth bound limits a reorganisation. `check_bounded_merge_depth` only forbids merging an old red. The virtual switches to any heavier chain until the finality point, which you kept at 12 hours." @@ -1243,7 +1272,8 @@ Evidence: the files above. Review id R3.2. ### F16. A lock can become uncertified after a heal "Section 3.5: two certificates at one index, strike the equivocators, re-evaluate, and if neither or both still lock the index is uncertified. So the lock my node reported and I credited on is revocable." -Status: Open, the two options priced, one recommended (5 October 2026, evening sweep); decision owner the project lead (gate 3, O-3.17). Was: Open, decision at gate 3 (extends O-3.6). Sweep (5 October 2026): a decision item (O-3.17); nothing runnable. +Status: Decided (6 October 2026, 17:25 UTC, by the owner; decisions item 2): option B, a verified certificate is never withdrawn (spec 3.11.4); the 3.5 paragraph is replaced by 3.11.4's text after `c4-fix` merges, `finality_conflict` and the `finality_active` clear go into the node, the forced double-certificate test of 3.11.7 follows; fix scheduled, consensus engineer. Was: Open, the two options priced, one recommended (5 October 2026, evening sweep); decision owner the project lead (gate 3, O-3.17). Was: Open, decision at gate 3 (extends O-3.6). Sweep (5 October 2026): a decision item (O-3.17); nothing runnable. +Decision owner: the project lead, decided 6 October 2026 (`docs/plans/ledger-decisions.md`, outcomes section). Sweep (5 October 2026, evening): the two options, with their measured cost. @@ -1257,8 +1287,6 @@ Sweep (5 October 2026, evening): the two options, with their measured cost. Recommendation: Option B, which spec 3.11.4 already states and O-3.17 names; it is Kaspa's rule for a finality conflict (`vendor/rusty-kaspa/consensus/notify/src/notification.rs`, `FinalityConflict`), it is the only reading under which an exchange can credit on a lock, and its cost falls on a state that needs a 34% equivocator or a 30-day partition. What it needs: the 3.5 paragraph replaced by 3.11.4's text, `finality_conflict` and the `finality_active` clear in the node, and the forced-double-certificate devnet test of 3.11.7. Decision owner: the project lead (gate 3). -What the C4 fix changes for option B (5 October 2026, night): the honest-partition row above is gone. Before the fix a 96-s partition with the table intact put two certified chains on the network with no equivocator (C4: the work-majority side held the other side's certificates pending, then certified its own chain), and option B would have paused finality on every node of that side for an operator. With the certificate-driven reorg (spec 3.5, `ingest_off_chain`) a node that receives a valid certificate for a chain it is not on adopts it and moves, so after a heal shorter than a window there is one chain of locks and nothing to withdraw: the module-on harness ended with 0 conflicting certificates and 0 disagreeing locked indices on all three nodes, under rule v3 and under v2 (bench-log "the C4 fix"). What remains for option B is exactly the states 3.11.4 names: an equivocator at one third or more, and a partition longer than a window (both sides certify their own chain before the heal; the node then holds a lock at a higher index on the other chain, `off_lock_chain`, and the late certificate is CONFLICTING, kept for the operator, no lock withdrawn). The node still does not clear `finality_active` or expose `finality_conflict` (O-3.17). - Answer: Correct as the proposal stands. For an exchange "locked" must be irrevocable or it is a confirmation count. The alternative is Kaspa's: a verified certificate is never re-evaluated; two certificates at one index are a chain split that halts `finality_active` until an operator intervenes, and the node never reports a lock it may withdraw. Equivocation costing history and not coins (F6) means the attacker who caused the split keeps the deposit either way. Decision at gate 3; the devnet partition-and-heal test of O-3.6 measures whichever rule is chosen. Evidence: spec 3.5, 3.9. Review id R3.17. @@ -1268,12 +1296,15 @@ Cross-reference (external review, 3 October 2026, night): what holds during a pa ### F17. Keys are free and the official client mints eight per card "Your launcher runs 8 identities per vendor, each with its own vote key. For the vote that is harmless by design. For shard sortition, which ranks every eligible key and takes 8, it is the whole game: 1% of hashrate holds 259 keys above dust. And a few thousand PCs cross your 8,192-voter switch, whose construction is open." -Status: Rule fixed (3 October 2026): spec 7.2 step 2 draws the 8 assignees by weight (blue blocks drawn uniformly from the window, their keys assigned, with the 1-key-versus-1,000-keys test in O-5.1), and spec 3.1 W6 states that keys are free and weight is the only Sybil-resistant quantity. Still open: the client's one-key default, S2 (O-3.5) and the bitmap size (O-3.12). P8 stays closed. Was: Open, rule change proposed. Reopens P8. +Status: Decided (6 October 2026, 17:25 UTC, by the owner; decisions item 13): the client defaults to one vote key per machine, identities share it (spec 3.4.2 item 4); the bitmap bound as item 3. Was: Rule fixed (3 October 2026): spec 7.2 step 2 draws the 8 assignees by weight (blue blocks drawn uniformly from the window, their keys assigned, with the 1-key-versus-1,000-keys test in O-5.1), and spec 3.1 W6 states that keys are free and weight is the only Sybil-resistant quantity. The client's one-key default (O-3.5) and the bitmap size (O-3.12) are proposed in spec 3.4.2 (round 2, 5 October 2026, night, below), decision at gate 3. P8 stays closed. Was: Open, rule change proposed. Reopens P8. +Decision owner: the project lead, decided 6 October 2026 (`docs/plans/ledger-decisions.md`, outcomes section). Answer: Correct. Spec 7.2 step 2 ranks per key and eligibility is 100 blue blocks in 30 days (0.004% of hashrate at one block a second), so a miner with share s holds up to s x 2,592,000 / 100 keys and the draw of 8 is dominated by whoever splits most. `proto-cuda/windows-miner/start-mining.ps1` derives a key per identity (`MINERS` default 8). O-5.1's acceptance test (fastest prover under 25% of shards) does not catch a splitter, who wins by count. Fix: draw the 8 assignees by weight (8 blue blocks uniformly from the window, take their keys), so splitting changes nothing; the client defaults to one key per operator; specify S2 (O-3.5) and the bitmap size (O-3.12) before the count can cross 8,192. Evidence: spec 7.2, 3.4; the launcher. Cross-reference added to P8. Review id R3.14. +Round 2 (5 October 2026, night): the two tails are written as proposals in spec 03, section 3.4.2 (items 1, 3 and 4; the decision is gate 3's), and O-3.5 and O-3.12 in spec 06 point at them. The key default (3.4.2 item 4): tonight's fleet runs 4.2 vote keys per machine (X5, 21 identities on 5 machines) because `app/igneum-app/src/detect.rs` `apply_defaults` gives a card with 8 GiB or more 8 identities and a smaller card 2 (1 on Apple silicon and integrated GPUs), stored per card as `CardPref.identities` in the app's `settings.json` (`config.rs`), passed to the worker as `--identities N` (`engine.rs`), with a key per identity derived from the card's label `--`, so a machine holds at least one key per card; the Windows launcher's `MINERS` default is 8 per vendor. Proposed: `identities` 1 on every card and one vote label per machine, so one vote key per machine; keys per operator then equal machines per operator, the unit X5 counts, and the 8,192 switch is reached at 8,192 machines, not 1,024 eight-key cards. Rewards do not change (weight is blocks; the shard and aggregator draws are by weight); dust gets easier (100 blue blocks in 30 days is 0.0039% of the network, which a small card clears as one key and not as eight); a home miner with one card holds 1 key instead of 8 or 2, a 6-card rig 1 instead of 48, a pool one per server. No app code changed tonight. The bitmap (3.4.2 items 1 and 3): sizes measured from the fork, vote item 281 B, certificate 273 B plus ceil(V/8) B of bitmap (1,024 B at the switch, 1,250 B at 10^4 keys), evidence 561 B, the wire bound 1 MiB today; proposed bound 8,192 B (65,536 voters, 8x the switch), which with 8 certificates per block is 67,720 B inside the 128 KiB section budget of F3's proposal. The S2 VRF construction and the binomial sampling stay with O-3.5. + ### F18. "A silent minority cannot freeze finality" is false under the floor "Your own simulation: 45% silent stalls finality for as long as they stay silent, 40% gives 138 stalls in three days, 50% churn stalls 4.1 days. The litepaper says a silent minority cannot freeze it and a lock never waits for miners who have left." @@ -1324,12 +1355,16 @@ Evidence: spec 5.1; `docs/design/execution-layer.md` 4.1, 4.3, 9.1. Review id R3 ### P15. RPC blocks are segments, so `gasUsed` can exceed `gasLimit` "A segment holds up to 180 blocks and your RPC block is the segment. Indexers assert `gasUsed <= gasLimit`." -Status: Open, minor, extends R10. Sweep (5 October 2026): confirmed in code on the `proving` branch (`igneum/exec/src/rpc.rs:355-356`: `gasLimit` is the single-block `BLOCK_EXECUTION_GAS_LIMIT` while `gasUsed` is the segment record's total). Not exercised: a segment over the limit needs about 1,400 transfers inside 180 blocks. Fix row in section 2.5. +Status: Fixed on a branch, pending merge (5 October 2026, night): fork branch `ledger-fixes-0311` fbb0082a (b6f381e2 rebased onto the 0.3.11 fork tip 89dfcb95 in round 3), suites PC 2 jobs `build-20261005-200049` (kaspa-consensus 95 passed, 0 failed, 3 ignored) and `build-20261005-200606` (kaspa-consensus-core 101/0, kaspa-mining 52/0, igneum-exec 13/0, igneum-miner 17/0, kaspa-p2p-flows 32 passed 1 failed: the new clock-skew test's own arithmetic, corrected in bd1b676a and 33/0 on the Mac), both on 815c7d64; the tip is fbb0082a. Was: Open, minor, extends R10. Sweep (5 October 2026): confirmed in code on the `proving` branch (`igneum/exec/src/rpc.rs:355-356`: `gasLimit` is the single-block `BLOCK_EXECUTION_GAS_LIMIT` while `gasUsed` is the segment record's total). Not exercised: a segment over the limit needs about 1,400 transfers inside 180 blocks. Fix row in section 2.5. Answer: Correct; spec 7.1 states that a segment's total can exceed `gaslimit`. Fix: report the segment's limit as `k x B_e` in the RPC block, or document the invariant break for Blockscout (R10). Evidence: spec 7.1; `docs/design/execution-layer.md` 8.2. Review id R3.12. +Fix (5 October 2026, night): `igneum/exec/src/rpc.rs` reports `gasLimit` as k x `BLOCK_EXECUTION_GAS_LIMIT` for a k-block segment (k = the record's mergeset length, at least 1), beside the segment's `gasUsed`, so `gasUsed <= gasLimit` holds for an indexer; the per-block limit and k sit under `igneum.blockGasLimit` and `igneum.segmentBlocks`. Unit test `rpc_block_gas_limit_is_the_segment_limit` (a three-block segment with `gasUsed` over one block's limit). Fork commit b6f381e2. + +Round 3 (6 October 2026, night): the fork branches `ledger-fixes` (bd1b676a) and `ledger-fixes-2` (b1e98b79) merged onto the 0.3.11 fork tip 89dfcb95 as `ledger-fixes-0311` (merge 99ea7d97, fallout 7d4c8b3c, P23 fbb0082a, the tip), built on the Mac against `igneum-pow` as release-0.3.11 ships it (the fork resolves `../../../../igneum-pow` from the checkout it sits under; `ledger-rebase` carries that crate at 42be745 and the fork worktree moved under it). `igneum/exec/src/rpc.rs` merged without conflict; the `rpc_block_gas_limit_is_the_segment_limit` test's record initializer gained 0.3.11's `carried_segments` field (7d4c8b3c, test code only, no behaviour change). Suites on the rebased fork, the Mac run (`cargo test --release -j 4` under the build lock, labelled a Mac run: PC 2 was queued behind the Counter ASIC 2.0 chain and no go came inside 30 minutes; the PC 2 slot for the same job still stands with the coordinator): PC 2 job `build-20261006-012543` (published by the Counter ASIC 2.0 coordinator at 01:25:43Z, done 01:32:33Z, every stage ok): fork fbb0082a built for Linux (igneumd 49,245,928 bytes, igneum-miner 9,905,848) and Windows (igneumd.exe 51,380,736, igneum-miner.exe 11,044,864), the seven suites exit 0 in 46 s, but without `--features igneum-pow` (build-job.mjs passes none), so the PC run is the no-feature evidence and the Mac run with the feature is the suite evidence; the feature flag for build-job is on the 0.3.12 list. kaspa-consensus 99 passed, 1 failed, 4 ignored (the failure is 0.3.11's own `igneum_m20_tests::witnesses_are_checked_in_epoch_order_under_their_own_seeds`, the era-0 stand-in of `pruning_proof/igneum_pow.rs:114` against `EpochSeeds::v2`'s zero era, both from 89dfcb95, neither file touched on the ledger branches; owned by the Counter ASIC 2.0 coordinator), kaspa-consensus-core 108 passed, 0 failed, 2 ignored (db_compat 7 of 7), kaspa-mining 52 of 52, kaspa-p2p-flows 36 of 36, kaspa-pow 14 of 14, kaspad 2 of 2, igneum-exec 23 of 23, igneum-miner 20 of 20. + ### E9. The specification's year is 365 days; the code's is 365.25 "Spec 2.5: 31,536,000 DAA seconds a year, halving every 63,072,000, about 31.7098 IGN a second. `igneum.rs`: 31,557,600, 63,115,200, 31.688 IGN. Which one is the money?" @@ -1396,16 +1431,18 @@ Evidence: spec 8.2. Review id R3.21. ### G10. The signalling default on first run "8.3 says the default is the choice the user last made. On first run there is none." -Status: Open, minor. Sweep (5 October 2026): the app carries no signalling control today (`grep -i signal app/igneum-app/src`: none), so nothing is signalled on first run; the rule binds when the control is built. +Status: Rule written (5 October 2026): spec 8.3 item 2; the control is unbuilt in the app. Was: Open, minor. Sweep (5 October 2026): the app carries no signalling control today (`grep -i signal app/igneum-app/src`: none), so nothing is signalled on first run; the rule binds when the control is built. Answer: Correct. Fix: first run signals nothing until the user chooses, shown in the interface. Evidence: spec 8.3 item 2. Review id R3.22. +Fix (5 October 2026, night): `docs/spec/08-client-security.md` 8.3 item 2 now ends: on first run there is no last choice, the client signals nothing until the user chooses, and the interface shows that nothing is being signalled. The app carries no signalling control today, so the rule binds the control when it is built; nothing to test until then. Branch `ledger-fork`. + ### X12. Tonight's numbers are quoted before they are logged, and the worker efficiency gap is unexplained "The 50x step, the trough near 9 million, 5.5 blocks a second and two-thirds efficiency over eight processes are in the brief and not in the bench-log. And the chain saw 70 to 83 MH/s from a card that benches 229, which is a third, not two thirds." -Status: Conceded, fix now. +Status: Fixed, logged (5 October 2026, night, ledger close round 1): bench-log "5 October 2026 (night), ledger close round 1: X12 the 3 October devnet run from its record"; the launcher half (the eight processes' summed status) stays open until the PC's log is read. Was: Conceded, fix now. Answer: Correct. The bench-log is append-only and the project's rule is that a number exists when it is logged with its command. Tonight's run needs its entry: the step profile, the retarget trajectory from the CSV (134.2 M to 14.2 M expected hashes by DAA 812, further per the brief), the 2-minute block-rate buckets, the epoch-boundary gap, and the launcher's summed status against the block rate, with the gap explained (template age, sibling blocks dropped by the one-block-per-job rule, or queue stalls across eight processes). @@ -1417,10 +1454,13 @@ Evidence: `/tmp/igneum-devnet/node1.log`, `sim/difficulty/devnet-2026-10-03.csv` Added by `docs/review/external-2026-10-03.md`, which holds the reviewer's text verbatim and the point-by-point classification (13 already answered, 15 new, 1 wrong). The reviewer is a general-purpose AI assistant; its claims about third parties are approximate. Entries are placed under their section letters and numbered on from the last entry of each section. Count after this block: 122 entries (107 plus 15). Every entry is Open with its experiment or decision named. +Run (5 October 2026, night): `python3 sim/difficulty/record_report.py devnet-2026-10-03.csv /tmp/igneum-devnet/node1.log` (new, a file analysis). From the CSV (3,682 headers to DAA 3,680, 1,655 chain blocks) and node 1's log (3,896 `PoW accepted` lines inside the span, within 4 of the CSV in every 2-minute bucket): the step profile is 0.07 to 0.17 blocks/s with the Metal worker alone (19:08 to 19:28 UTC), 5 headers in the idle 14 minutes, 0.38 to 0.62 blocks/s after the PC joined at 19:41, all at the genesis 134,217,727 expected hashes; the retarget at DAA 600 (19:56:12) eased x4.79 at once to 28.0 M, 14.2 M at DAA 812, the trough 8,553,182 at DAA 1,614 (20:00:01, x15.7 easier than genesis), back to 26.5 M by DAA 2,848 and a 38.75 M peak at DAA 3,352; the 2-minute buckets peaked at 2.84, 5.18, 5.75 and 4.85 blocks/s from 19:55:49 (355 headers in the peak minute) and sat at 1.3 to 1.7 blocks/s for the next eight minutes; the epoch boundary gap is 160.1 s by header timestamps (DAA 3,599 at 20:12:14 to DAA 3,602 at 20:14:54) and 160.9 s of silence in node 1's log. Of the brief's numbers the record supports the trough near 9 million (8.55 M) and 5.5 blocks a second (5.2 to 5.75 per 2-minute bucket); it does not support a 50x step (the chain's implied hash rate stepped 3x to 8x, from 10 to 23 MH/s to 51 to 83 MH/s, and no file here holds the PC's bench against the Metal worker's) and it cannot check two-thirds efficiency over eight processes (the chain implies 22% to 36% of the 229 MH/s bench; the launcher's summed status is on the PC, unreachable tonight). Bench-log heading: "5 October 2026 (night), ledger close round 1: X12 the 3 October devnet run from its record". + ### M22. The ASIC challenge has no scoring rules, and 2x is not the economic line "Your bounty says 'beats a GPU by more than 2x'. Per what? Hashes per second, per joule, per dollar, on the average program or the worst hour? A chip at 1.6x with half the capital cost wins. And nobody has published eligible hardware, funding or a judge." -Status: Open, decision for the project lead (terms, judge and funding) and experiment scheduled (extends O-1.17). Sweep (5 October 2026): nothing runnable; the terms, judge and funding are the project lead's decision. +Status: Decided (6 October 2026, 17:35 UTC, by the owner; decisions item 1, corrected): no bounty, so no bounty terms; M22's metrics (hashes per second and per joule per program over at least 100 epochs as a distribution, capital cost per unit of hash rate at a stated volume, the longevity term, the shortcut classes scored separately) become the public benchmark's scoring rules and the brief of the paid cryptanalysis; the optional USD 50,000 cryptanalysis prize, if ever set, is escrowed before it is named. Was: Open, decision for the project lead (terms, judge and funding) and experiment scheduled (extends O-1.17). Sweep (5 October 2026): nothing runnable; the terms, judge and funding are the project lead's decision. +Decision owner: the project lead, decided 6 October 2026 (`docs/plans/ledger-decisions.md`, outcomes section). Answer: Correct. M1 and O-1.17 name a bounty for "more than 2x" without a metric, a judge or a fund, and 2x is a design target for the hash, not an economic threshold: a chip at 1.5x per joule and 3x per dollar of capital is an economic ASIC whatever the hash-rate ratio says. The scoring rules go out with the January 2027 benchmark: hashes per second and per joule measured per program over a published set of at least 100 epochs, reported as a distribution (worst decile, median), never as one average; capital cost per unit of hash rate at a stated volume; a longevity term against the instruction-family reserve and the dataset growth of spec 1.13; and the shortcut classes (recomputation, partial storage, weak-program selection) scored separately. Eligible hardware assumptions, the judge, the reward and the payer are the project lead's decisions (fud-fixes row 50: the payer is the entity). The supportable public claim until a design has been scored: across the tested workloads and the stated economic assumptions, consumer GPUs remain competitive against the best independently proposed specialised design. Extends M1, M16 and C13. @@ -1438,12 +1478,14 @@ Evidence: spec 3.1 W5 and W6, 3.6; `sim/results_v2.md` (renter scenarios only). ### F20. During a finality pause the program must keep advancing, and nothing says which guarantees survive "Your epoch seed is a VDF of a certified checkpoint. When finality pauses for four days, your own 50% churn figure, which checkpoint seeds hour 50? And when the pause ends, what exactly was still guaranteed in between?" -Status: Open, decision scheduled at gate 3 (O-3.16, with O-4.3). Sweep (5 October 2026): the seed half is decided (spec 4.3, from O-4.3: the seed checkpoint is the selected-chain block at the lead's blue score, certified or not, so mining never waits for a certificate) and spec 06 marks O-3.16's text closed; the devnet test through three epoch boundaries under a 45% silent set is still owed (devnet, person). +Status: Answered with evidence for the test half (5 October 2026, night, ledger close round 1: the fast-time run through four epoch boundaries under a 47.5% silent set, bench-log "5 October 2026 (night), ledger close round 1: F20 finality pause under a 45% silent set through four epoch boundaries"); the gate-3 wording of the four guarantees (O-3.16, O-4.3) stays a decision for the project lead. Was: Open, decision scheduled at gate 3 (O-3.16, with O-4.3). Sweep (5 October 2026): the seed half is decided (spec 4.3, from O-4.3: the seed checkpoint is the selected-chain block at the lead's blue score, certified or not, so mining never waits for a certificate) and spec 06 marks O-3.16's text closed; the devnet test through three epoch boundaries under a 45% silent set is still owed (devnet, person). Answer: Correct on the gap. Spec 4.3 proposes that the seed checkpoint may be the uncertified selected-chain block at the checkpoint blue score, so a pause does not stop mining, and O-4.3 leaves the decision to gate 3; the design document still says an epoch cannot start without a valid proof. No text states what holds during a pause: that blocks, execution and proofs continue (3.7 item 2 says proof of work in practice), that every lock before the pause stands (3.5), that `finality_active` is false and exchanges wait on the 12-hour finality depth (3.9), and that the seed pipeline advances from uncertified checkpoint blocks with the reorg exposure that implies (a 1,200-DAA-s lead plus d). Gate 3 takes the uncertified option or states the stop; this ledger recommends uncertified, as spec 4.3 does, and the four guarantees go into spec 3.7. Test: the devnet with the finality module stalled by a 45% silent set (3.3.1 row C) through at least 3 epoch boundaries, recording that the program advanced on schedule, that no node forked on the seed, and that the pre-pause locks survived the heal. Evidence: spec 4.3 (O-4.3), 3.3.1, 3.5, 3.7 item 2, 3.9. Experiment: O-3.16. Review: external, point 2. +Run (5 October 2026, night): `tools/lock/with-lock.sh run node tools/finality-attacks/f20.mjs` (new scenario file; fast-time 3-node network, 100-ms proxied links, the live node line `target-036` at `a24ab01a`), 592 s wall. Six keys at 1 block/s; after 230 s of warm-up (locks to index 7 on every node) the two keys holding 47.5% of the 120-DAA window (57 of 120 blocks) were restarted mining without votes for 200 s (DAA 231 to 448), then voting again for 150 s. During the pause: 0 new locks on any node and 7 checkpoints left proposed (52.5% signing is under the 2/3 floor, so finality paused as the rule says); the program epoch advanced at DAA 240, 300, 360 and 420 on all three nodes, each new index first seen inside one 2-s poll of its boundary, with one seed per index on all three (seeds db32303e55cd..., 4071e7c0c759..., 35179dfc4d2a..., 0f9e517c1920...); the three sinks agreed at the end. After the heal: locking resumed 2 s after the silent pair voted again and reached index 19; all 12 (index, hash) locks held before the pause were held unchanged by every node; 0 conflicting certificates. So on this line a finality pause stops certificates and nothing else: blocks, the hourly program and the pre-pause locks all carry through, which is the uncertified-seed option of spec 4.3 measured. Bench-log heading: "5 October 2026 (night), ledger close round 1: F20 finality pause under a 45% silent set through four epoch boundaries". + ### F22. Certificates carry 8 to 10 of 12 votes on a healthy network, so locks sit a hair above the floor "Two of your cloud checkpoints locked at 66.8% against a 66.7% floor with every node connected. One slow aggregator and finality pauses." @@ -1458,21 +1500,30 @@ Evidence: `infra/cloud-devnet/results/2026-10-04/partition-sin-20261004-140305/p ### P16. The proving gate can be passed by shrinking the shard "'A mid-range GPU proves a shard in under 20 s.' Your own R2 says: if missed, halve the shard and re-measure. That is the trap. Fix the workload first, measure the whole journey, and have strangers reproduce it." -Status: Open, experiment scheduled (O-7.1). The journey's phase 2 gate was rewritten the same night. Sweep (5 October 2026): hardware item (the 12 GB card end to end); the standard is written. +Status: Decided (6 October 2026, 17:25 UTC, by the owner; decisions item 12): a 12 GB NVIDIA card (4070) is on order for PC 2; O-7.1 runs end to end on it when it arrives, inside the phase 2 gate. Was: Open, blocked on a 12 GB card (decisions item 12, already pointed: a 3060-class NVIDIA part for PC 2 before the public benchmark): next measurement O-7.1 end to end on that card when it arrives, inside the phase 2 gate (Nov 2026 to Jan 2027 per the litepaper roadmap). Was: Open, experiment scheduled (O-7.1). The journey's phase 2 gate was rewritten the same night. Sweep (5 October 2026): hardware item (the 12 GB card end to end); the standard is written. +Decision owner: the project lead, decided 6 October 2026 (`docs/plans/ledger-decisions.md`, outcomes section). Answer: Correct. P1 conceded that the 20-s figure is a target; this is about how the target is tested. `docs/design/execution-layer.md` 9.1 R2 passes at any shard size by halving `S_p` until the time fits, so a pass says nothing about throughput, and R4 measures the wrapper only. The phase 2 benchmark now has an acceptance standard: a fixed published workload (real transactions, never empty blocks or tiny shards) with its shard plan, proven end to end from job received to proof accepted, including queueing, transfers, aggregation, verification and payment; the median and the slowest 5% and 1%; failure and retry rates; full cost (electricity, host, bandwidth, aggregation, failed work, hardware); results per advertised card with mining and proving compatibility stated separately; sustained with no growing backlog; reproduced by at least three unrelated operators from the published code and configuration. A halved shard is a new declared workload, never a pass. The reviewer's figure for SP1's cluster requirement (NVIDIA, 24 GB, approximate; not checked, SP1 is not in `vendor/`) is why a 12 GB card has to show the whole pipeline, which R2 and R4 already target. Evidence: P1; execution-layer 9.1 R2 and R4; `docs/bench-log.md` (no shard has been proven on any card). Experiment: O-7.1. Review: external, point 1. +Round 2 (5 October 2026, night): status made terminal-explicit. Blocker: no 12 GB card is on the fleet (the cards measured so far are listed in `docs/bench-log.md`; the 5090 is not the gate's card, litepaper Proving). The acceptance standard in the Answer is unchanged and is what the card runs when it arrives. Next date: the phase 2 gate. + ### P17. Interfaces must show four states, and the design shows three "Included, executed, proven, finalised are four different facts. Your status call returns executed, proven, locked and a list of blocks. A wallet that shows a balance at 'included' is lying by omission." -Status: Open, rule written (3 October 2026, night) in `docs/design/execution-layer.md` 2.4; experiment scheduled (O-7.2). Sweep (5 October 2026): the conformance set is devnet work; not run. +Status: Fixed on a branch, pending merge (6 October 2026, night, ledger close round 2): fork `ledger-fixes-0311` fbb0082a (b1e98b79 rebased onto the 0.3.11 fork tip 89dfcb95 in round 3), suite igneum-exec 16 of 16 on the Mac (labelled a Mac run), the O-7.2 conformance run PASSED on a fast-time 3-node network (bench-log "ledger close round 2: P17"). Was: Answered with evidence for what the RPC returns today (5 October 2026, night, ledger close round 1: report only, no code change); the four-state word in the response and the conformance run (O-7.2) are round 2. Was: Open, rule written (3 October 2026, night) in `docs/design/execution-layer.md` 2.4; experiment scheduled (O-7.2). Sweep (5 October 2026): the conformance set is devnet work; not run. Answer: Correct. Design 2.3 defines executed, proven and locked; `igneum_getTransactionStatus` carries `included_in` as a list and never as a state; the phone app (phone-app 3 and 9) shows three words. A transaction in a block not yet on a selected chain, or in a merged block waiting its turn in the sequence, is included and nothing more, and on a DAG that gap is routine. The rule now in 2.4: every RPC, wallet, explorer and app reports exactly one of included, executed, proven, finalised (the user-facing word for locked), never a stronger word than the chain's own state, and shows "finality not active" in place of finalised while `finality_active` is false (3.9). Proven says nothing about availability: full blocks are what every full node holds (F13) and a light client takes data from nodes under spec 10.1. Test: a wallet and RPC conformance set on the devnet, one transaction through each state and the three failure paths (skipped, reorged out, finality paused). Evidence: execution-layer 2.3, 2.4, 8.2; phone-app 3 and 9; spec 3.9, 10.1. Experiment: O-7.2. Review: external, point 2. +Run (5 October 2026, night, report only, no bench-log entry because nothing ran): on the running fork line (`vendor/igneum-node-036`, release-0.3.6 at `a24ab01a`, the binary node 1 runs) `igneum_getTransactionStatus` (`igneum/exec/src/rpc.rs:739-751`) returns one object: `includedIn`, a list with one entry per block that carries the transaction (block hash, `chainBlockNumber`, `executed`, `skipReason`); `executingCopy`, the block whose copy executed, or null; `executed`, true once the hash is in the executor's index; `proven: false` and `locked: false`, both constants in the source, never true on this line whatever proof records or certificates the chain holds; and `inMempool`. The states a caller can tell apart are therefore: in the mempool only (`inMempool` true, `includedIn` empty); included and not executed (`includedIn` non-empty, `executed` false: a block off the selected chain, or a merged block waiting its turn in the sequence); executed (`executed` true, `executingCopy` set); skipped (an `includedIn` entry carrying `skipReason`, `executed` false). Proven and finalised cannot be read from this call at all. The block tags of the EVM calls resolve in `resolve_block` (`rpc.rs:251-262`): the arm at line 257 maps `latest`, `pending`, `safe` and `finalized` all to the tip, and the comment at lines 226 to 228 says no certified checkpoint exists yet and the RPC must not pretend otherwise. That comment predates the first live lock (bench-log 4 October 2026, checkpoint 242), so today `eth_getBlockByNumber("finalized")` returns the tip of a chain that holds locked checkpoints below it: the tag overstates. Round 2 (code): the one-word state (included, executed, proven, finalised, or `finality not active`) in the response, `finalized` bound to the last locked checkpoint's chain block, then the O-7.2 conformance run. + +Round 2 (6 October 2026, night): implemented on the fork branch `ledger-fixes-2` (b1e98b79, from `ledger-fixes` bd1b676a). `igneum_getTransactionStatus` now carries one `state` word, exactly one of `included`, `executed`, `proven`, `finalised`, with `finality not active` in place of finalised while `finality_active` is false (design 2.4; `pending` for a mempool-only transaction, `unknown` when no block and no mempool holds it), and a `failure` field naming the path: `skipped` (every copy skipped by rule), `reorged out` (unwound by a selected-chain reorg, `reorgedFrom` the height; a bounded memory of 10,000 unwound hashes, cleared on re-inclusion), `finality paused` (executed, no lock covers it, the flag false). `proven` is true when the shard holding the executed copy has a paid proof record carried by a chain block (the first true value this call has ever returned; it was a constant). The `finalized` and `safe` block tags resolve through one rule (`finalized_height`): the latest locked checkpoint's chain block when the executor holds it (a certificate stays binding through a pause, spec 3.9), else the fallback spec 3.9 gives for `finality_active` false, the highest chain block at least the consensus finality depth (spec 02 section 2.1, 43,200 DAA s on mainnet, 720 blocks on the fast-time profile) below the tip, genesis while the chain is younger; never the tip, and `finalizedSource` says which. A new `igneum_getFinalityView` reports the flag, its reason, the latest lock and what the tag resolves to; the chain follower reads the node's finality report after every pass, so the RPC never touches consensus. Unit tests (3 new, 16 of 16 in the crate on the Mac under the build lock, labelled a Mac run because PC 2 was queued behind the 0.3.11 rollout). Conformance (O-7.2, `tools/p17-conformance/run.mjs`, 3 nodes at 1 block/s behind 50 ms proxies, three voters, 437.5 s, PASSED): before the first lock the tag resolved to genesis by the depth rule while `latest` was 8; the first lock at 168.9 s (index 5, chain block 129) moved the tag to 129 against tip 146; one transfer went pending, executed (147), through a routine 1-block reorg (`reorged out` for about 2 s, then executed again in 149) to finalised at 198.3 s with the tag at 153 under a tip of 173; two copies of one nonce sent to two nodes in one instant gave one `executed` and one `included` with failure `skipped` (NonceTooLow); a node cut off alone executed a transfer in its own chain block 183, and when the link healed and the heavier 2/3 chain won (11 reorg lines) the transfer reported `unknown` with failure `reorged out` from 183; 2/3 of the weight silenced paused finality at 399 s (reason `paused`), the finalised transfer flipped to `finality not active` with `lockedCovered` true, a fresh transfer executed with failure `finality paused` and the tag held at the last lock (294) against tip 339, and both reached `finalised` within 25 s of the voters signing again. Not exercised: `proven` on the network (no shard is proved on it; the unit test covers the paid-shard rule). Findings beside the fix: (1) an unwound transaction does not return to the EVM mempool (the pool has `on_chain_block` and no reorg hook), so after a reorg it must be resent; the RPC says `reorged out` and a wallet knows to resend, but the pool half is the execution engineer's (not changed here); (2) with the fast profile's presence window of 1 the flag flickers to `paused` for 0.6 s at every checkpoint determination (240 on mainnet hides it); (3) the phone app and the explorer still show three words and need the `state` field (phone-app 3 and 9; a text-and-app item for the next round). Design 8.2's RPC row updated on `ledger-pc2`. + +Round 3 (6 October 2026, night): the fork branches `ledger-fixes` (bd1b676a) and `ledger-fixes-2` (b1e98b79) merged onto the 0.3.11 fork tip 89dfcb95 as `ledger-fixes-0311` (merge 99ea7d97, fallout 7d4c8b3c, P23 fbb0082a, the tip), built on the Mac against `igneum-pow` as release-0.3.11 ships it (the fork resolves `../../../../igneum-pow` from the checkout it sits under; `ledger-rebase` carries that crate at 42be745 and the fork worktree moved under it). `igneum/exec/src/service.rs` conflicted once: a union, the finality view, the finality depth and the 10,000-hash reorged memory beside proving v1's `paid_segments`; the p17 test record helper gained `carried_segments` (7d4c8b3c). The O-7.2 conformance run again on the rebased binaries (`tools/p17-conformance/run.mjs`, 3 nodes at 1 block/s behind 50 ms proxies, ports 30010 and up because another agent's process held 29999, network igneum-devnet-2010, under the run lock): PASSED in 409.9 s; before the first lock the tag resolved to genesis by the depth rule, the happy path, the skipped copy and the pause-and-resume as in round 2. The `reorged out` case now ends in `executed` without a resend (P23): tx3, executed alone on n2 in chain block 0xed at 281.7 s, reported `pending` with failure `reorged out` from 0xed at 334.0 s when the healed link brought the heavier chain, n2's log at the same second says `reorg: 1 unwound transactions handed back to the pool as pending, 0 refused`, and the transaction was `executed` again in chain block 0x117 at 336.4 s on n2 and 337.4 s on n0 (the driver never resends; round 2 saw it stay `unknown` for 60 s). One line for the record: during the heal n2's flag read `paused` for a pass, the fast profile's presence-window flicker of round 2's finding (2). Suites on the rebased fork, the Mac run (`cargo test --release -j 4` under the build lock, labelled a Mac run: PC 2 was queued behind the Counter ASIC 2.0 chain and no go came inside 30 minutes; the PC 2 slot for the same job still stands with the coordinator): PC 2 job `build-20261006-012543` (published by the Counter ASIC 2.0 coordinator at 01:25:43Z, done 01:32:33Z, every stage ok): fork fbb0082a built for Linux (igneumd 49,245,928 bytes, igneum-miner 9,905,848) and Windows (igneumd.exe 51,380,736, igneum-miner.exe 11,044,864), the seven suites exit 0 in 46 s, but without `--features igneum-pow` (build-job.mjs passes none), so the PC run is the no-feature evidence and the Mac run with the feature is the suite evidence; the feature flag for build-job is on the 0.3.12 list. kaspa-consensus 99 passed, 1 failed, 4 ignored (the failure is 0.3.11's own `igneum_m20_tests::witnesses_are_checked_in_epoch_order_under_their_own_seeds`, the era-0 stand-in of `pruning_proof/igneum_pow.rs:114` against `EpochSeeds::v2`'s zero era, both from 89dfcb95, neither file touched on the ledger branches; owned by the Counter ASIC 2.0 coordinator), kaspa-consensus-core 108 passed, 0 failed, 2 ignored (db_compat 7 of 7), kaspa-mining 52 of 52, kaspa-p2p-flows 36 of 36, kaspa-pow 14 of 14, kaspad 2 of 2, igneum-exec 23 of 23, igneum-miner 20 of 20. Owed, unchanged: `proven` on a network with the proving loop; the phone app and the explorer still need the `state` field. + ### E12. Selfish operators under a price shock "Outside proving pays ten times more and IGN halves in a week. Every rational operator leaves hashing for jobs. Do your internal proofs go unproven, do queues grow, does anything bring them back? Assume nobody runs your client's scheduler." @@ -1494,7 +1545,8 @@ Evidence: spec 2.5, 5.1 to 5.4; `docs/commercial/prover-customer-brief.md`; P10, ### E14. No funding table "Who pays for development, the independent review, the infrastructure and an incident response, from what, and what happens if revenue is late? You have no fund by design, which means you have no table either." -Status: Open, with a placeholder table: `docs/plans/funding.md` (3 October 2026, marked PLACEHOLDER on 4 October) lists the sources (the founder's own means today, the 1% client fee, the team's own mining and proving, no protocol fee) and the cost lines; the project lead parked funding on 4 October 2026 and the decision stays his. Was: Open, decision for the project lead. +Status: Decided (6 October 2026, 17:25 UTC, by the owner; decisions item 4): the funding table stays internal until counsel has read it; one public sentence in the litepaper names the unfunded lines (the second client, the external reviewers, the bounty before escrow). Was: Open, with a placeholder table: `docs/plans/funding.md` (3 October 2026, marked PLACEHOLDER on 4 October) lists the sources (the founder's own means today, the 1% client fee, the team's own mining and proving, no protocol fee) and the cost lines; the project lead parked funding on 4 October 2026 and the decision stays his. Was: Open, decision for the project lead. +Decision owner: the project lead, decided 6 October 2026 (`docs/plans/ledger-decisions.md`, outcomes section). Answer: Correct. The fund was removed on purpose (E4) and the team earns from the 1% client fee, its pool, its provers and the app share (E5); none of that is costed, and the second client has no funder (fud-fixes row 47), nor do the external reviewers (G1), the bounty (M22), the seed nodes or the public infrastructure. The table: each cost line (development, independent review, infrastructure, incident response, the bounty, the second client) against its source (the entity's own money, the client fee, the proving business, a grant mechanism added by signalling), labelled funded, dependent on future revenue, or unfunded, with the consequence if revenue is late. It assumes a flat IGN price, which is E15's test. The table is internal until counsel has read it (L1, L2); the litepaper states which lines are unfunded. @@ -1521,7 +1573,8 @@ Evidence: X1; `docs/fud-fixes.md` section 5. Decision: the project lead. Review: ### X13. One paying customer for a stated reason "'One rollup signs for testnet' is a letter of intent with no money. A customer who pays once, pays again without a rebate, and then a second unrelated customer, is evidence. A signature is not." -Status: Open, experiment scheduled (the pilot itself), decision for the project lead on timing and terms; extends L4 and the customer brief. Sweep (5 October 2026): a decision and a customer; nothing runnable. +Status: Decided (6 October 2026, 17:25 UTC, by the owner; decisions item 5): the paid pilot stays in phase 5, the phase 4 gate stays the signature, nothing moves earlier before counsel answers L4. Was: Open, experiment scheduled (the pilot itself), decision for the project lead on timing and terms; extends L4 and the customer brief. Sweep (5 October 2026): a decision and a customer; nothing runnable. +Decision owner: the project lead, decided 6 October 2026 (`docs/plans/ledger-decisions.md`, outcomes section). Answer: Correct. The phase 4 gate is a signature and the brief says so ("a signed letter of intent with no payment"). The progression is adopted and the brief carries it at its next version: agree the workload, proof format, deadline, failure rate and price before the pilot; publish the outcome and the customer's own reason for buying; then repeat purchases without reimbursement; then several unrelated customers. The reviewer places the paid pilot before public testnet; the journey has it in phase 5. Phase 4 keeps the signature as its gate and phase 5's line gains the paid pilot; moving it earlier is the project lead's call and needs the entity, terms and tax treatment of L4 first. @@ -1530,21 +1583,28 @@ Evidence: `site/journey.json` phases 4 and 5; `docs/commercial/prover-customer-b ### X14. Concentration is unmeasured in four places "Define independent for the 1,000-miner gate, then report concentration in hashing, checkpoint signing, proving and aggregation, because a thousand miners behind two pools is two." -Status: Open, measurement scheduled (O-X.1); extends X5. Sweep (5 October 2026): hashing concentration computed from the devnet record (`sim/difficulty/records/live-2026-10-04.csv`, 8,090 blocks, 18 vote keys): top-1 12.8%, top-3 34.5%, top-9 98.0%, the nine being devnet v4's nine identities run by three machines (approximate), so by machine the devnet is three parties. Signing, proving and aggregation concentration need certificate and proof-record extracts the observer does not keep yet (O-X.1). +Status: Answered with evidence for all four (5 October 2026, night, ledger close round 2: signing concentration read from the certificates and votes the chain blocks carry in their coinbase finality section, top-1 10.0%, top-3 29.1%, top-10 77.3% of signed weight over the heaviest certificate at each of 126 indices in the window; bench-log "5 October 2026 (night), ledger close round 2: X14 signing concentration from block payloads"); the independence definition stays the project lead's (X5). Was: Answered with evidence for hashing, aggregation and proving, Open for signing (5 October 2026, night, ledger close round 1: no RPC exposes a certificate's signer set, so the signing concentration needs the observer extract of O-X.1; bench-log "5 October 2026 (night), ledger close round 1: X14 concentration in hashing, signing, proving and aggregation from the Mac node's RPCs, and E16 one live block"); the independence definition stays the project lead's (X5). Was: Open, measurement scheduled (O-X.1); extends X5. Sweep (5 October 2026): hashing concentration computed from the devnet record (`sim/difficulty/records/live-2026-10-04.csv`, 8,090 blocks, 18 vote keys): top-1 12.8%, top-3 34.5%, top-9 98.0%, the nine being devnet v4's nine identities run by three machines (approximate), so by machine the devnet is three parties. Signing, proving and aggregation concentration need certificate and proof-record extracts the observer does not keep yet (O-X.1). +Decided (6 October 2026, 17:25 UTC, by the owner; decisions item 3): the independence definition and the four concentration reports as X5 states; the observer columns ship with the next cut. Answer: Correct. X5 conceded that "independent" needs a measurable definition (distinct ASNs, benchmark hardware fingerprints, pool attestations) and left it to phase 4. The four concentrations can each be computed from chain data: blue blocks per vote key and per pool (hashing), signed weight per key in certificates (checkpoint signing), proof records per prover key (proving, once P12's fix puts the key in the statement), and certificates and proof records per aggregator key (aggregation). The gate reports all four as top-1, top-3 and top-10 shares over 30 days, beside the independence count, on the live page. Transaction choice inside pools is a separate measurement and is already scheduled: whether members of the reference pool use declared templates (spec 9.4.2, mode C) is recorded under O-9.5. Evidence: X5, F10, P12, spec 9.4.2. Experiment: O-X.1. Review: external, point 6. +Run (5 October 2026, night): `tools/lock/with-lock.sh run node tools/finality-attacks/x14-concentration.mjs` (new; the Mac observer node's wRPC and exec RPC, read-only, 7 s) at DAA 125,005, window 7,200 DAA, plus `node tools/console.mjs machines`. Hashing (`getFinalityWeights`, 29 keys, 25 above dust, 6,734 blocks): top-1 25.9%, top-3 37.3%, top-10 67.0%. Aggregation (`certificateAggregator` over 210 certified or locked checkpoints, 187 named, 23 anonymous, 20 keys): top-1 17.1%, top-3 43.3%, top-10 85.0%; sortition eligibility (1,492 namings over 225 checkpoints, 27 keys): top-1 7.1%, top-3 20.4%, top-10 61.9%. Proving (`igneum_getSegment.proofRecords` over 4,474 chain blocks, 275 records carried, 131 paid, 144 rejected): one key and one payout address hold 100% of the paid shards (PC 2's prover; 519 shards paid on the chain in all). Signing: NOT exposed; `RpcCheckpoint` carries `signedWeight`, `votesSeen`, `voters`, `aggregators` and `certificateAggregator` and no signer set or bitmap, so per-key signing concentration cannot be computed from any RPC on this line; what is exposed over the 210 locked checkpoints is `signedWeight` over `totalWeight` p50 71.1%, min 38.8%, max 100% (a locked checkpoint at 38.8% shows the two fields are not the pair the lock test used) and `votesSeen` p50 16 of 25. Key-to-machine ratio: 29 keys against 4 machines on the console at 19:14 UTC (5.8 to 7.3 keys per machine, depending on whether the evening's fifth machine is counted). Bench-log heading: "5 October 2026 (night), ledger close round 1: X14 concentration in hashing, signing, proving and aggregation from the Mac node's RPCs, and E16 one live block". + +Round 2 (5 October 2026, night): the signing half, from block payloads. No RPC exposes a certificate's signer set, but every block carries its certificates and votes in the coinbase extra data (spec 03 C2, C3, Q2: `items || len_le32 || "IGNF"` at the end of the payload; `consensus/core/src/finality.rs` `encode_section`, `Certificate::write`, `Vote::write`, the same bytes on 0.3.6 and 0.3.10), and a certificate's bitmap indexes the canonical voter list at its checkpoint. `getFinalityWeights` reports that list for the latest checkpoint only, so `tools/finality-attacks/x14-concentration.mjs` (extended, not a second script) rebuilds the list at every checkpoint in the window from headers the way the node does (`compute_weights`: the checkpoint plus every chain block's mergeset blues back along the selected chain, `window_start < daa <= daa(C)`, dust, sorted by key hash) and maps every bitmap through it; votes carry the public key and the key hash is BLAKE2b-256 keyed `IgneumVoteKeyHash` (`lib/blake2b.mjs`, RFC vectors plus every `IGNK` reveal in the window as the check). Run: `tools/lock/with-lock.sh run node tools/finality-attacks/x14-concentration.mjs --node-build ... --since-daa 134300`, read-only, 10 s, at 23:00:44 UTC on the Mac observer node (`vendor/igneum-node-0310` 21d4c73c, `target-integration/release/igneumd`, `serverVersion` 2.1.0, restarted for 0.3.10 at 21:49:38 UTC, about DAA 134,276, so the window straddles that restart and the reading carries a second row from DAA 134,300), DAA 138,542 at the start and 138,555 at the end, window 7,200 DAA, weights at checkpoint 4,522. Fleet at the reading (console, read-only): Mac and PC 1 apps on node 2.1.0-a24ab01a (PC 1 stopped 33 min before), PC 2 and PC 37ba0461 on node 2.1.0 (the 0.3.10 build), Sam's Mac stopped 2 h before; the chain bytes are the same whichever node reads them. Checks: 240 of 240 rebuilt voter lists agree with the node's `voters` count, 194 of 194 certificates mapped (every `voter_count` equals the rebuilt list), 27 reveals against BLAKE2b with 0 mismatches, 0 evidence items, 0 items naming a checkpoint outside the window. Result, signed weight per key over the heaviest certificate at each of 126 indices (the certificate the lock test reads; 194 distinct certificates carried 250 times by 5,731 chain blocks): 27 keys, top-1 10.0%, top-3 29.1%, top-10 77.3%; over every distinct certificate 10.5%, 30.5%, 77.6%; over every carriage 10.1%, 29.5%, 76.3%; votes carried (4,469 distinct, weighted by the key's weight at C_i) 8.4%, 24.4%, 70.0%, unweighted 4.7%, 13.5%, 42.5%. Beside the other three at the same reading: hashing (27 keys, 7,200 blocks) 6.4%, 19.2%, 60.1%; aggregation (10 named keys, 69 certificates over 132 certified or locked checkpoints, 63 anonymous) 44.9%, 84.1%, 100%; proving (52 paid shards) 100%, 100%, 100%. Since DAA 134,300 (after the observer node's restart, 88 indices): 9.9%, 28.7%, 75.9%. Signing is more concentrated than hashing (top-10 77.3% against 60.1%) because the node sees a median 18 of 27 voters per checkpoint: five keys signed all 126 certificates and eight signed 98 or more, and those eight hold 70.8% of the lock weight (per-key table in the bench-log); the other 19 keys sign 85 to 92 of 126 and carry the rest. What it means: the phase 5 gate ("top-10 share of window weight under 50%") fails tonight on all four measures, as a four-live-machine devnet must (27 keys against 3 machines live at the reading, 5 over the window: 5.4 to 9 keys per machine, approximate from the console); the gate is a public-testnet test and the observer now has the columns to read it (X5, round 2). A `getFinalityCertificate(index)` RPC returning the bitmap and the voter list at C_i would make the reading a few calls instead of a 13,171-block walk; not needed for the ledger, noted for the operator page. An earlier reading at 22:58:20 UTC (DAA 138,377) gave hashing 6.5%, 19.5%, 60.8% and aggregation 42.1%, 77.6%, 97.4% (12 keys, 76 certificates); its signing rows were unreadable (a formatting fault in the script, fixed before the second reading) and both readings are kept in the bench-log. + ### X15. Remove the founders from a test network and show what continues "'The chain runs without its founders' is a sentence. Take the team's miners, provers, aggregators, seed nodes, observer and site off a running testnet and show what keeps producing blocks, proofs and locks." -Status: Open, experiment scheduled (O-X.2). Sweep (5 October 2026): a public-testnet experiment; not runnable before it exists. +Status: Open, blocked on the public testnet (August 2027 per the litepaper roadmap): next step O-X.2 run at a published time on that testnet, with the protocol already in the Answer below (every project-run node, miner, prover, aggregator and seed stopped, the observer and live page down, 24 hours of blocks per second, proof lag, certificates per hour and a fresh sync from the shipped seed list). Was: Open, experiment scheduled (O-X.2). Sweep (5 October 2026): a public-testnet experiment; not runnable before it exists. Answer: Correct, and it is the right test for the litepaper's sentence (Governance). The test: on the public testnet, at a published time, stop every node, miner, prover, aggregator and seed node the project runs, take the observer feed and the live page down, and record for 24 hours: blocks per second, proof lag, certificates per hour, and a fresh node syncing from the seed list in the client (spec 10.6). What continues is what the sentence may claim. Dependencies the test will expose: the seed list, the release key (G7), the reference pool, the VDF evaluators (every node ships one, 4.5) and the founders' own hashrate share (E2). Evidence: `site/litepaper.html` Governance; spec 10.6, 4.5; G7, E2. Experiment: O-X.2, before mainnet. Review: external, point 6. +Round 2 (5 October 2026, night): status made terminal-explicit. Blocker: the test needs a network the project does not run alone, which exists from the public testnet (phase 5, Aug to Oct 2027 on the litepaper roadmap). Next date: a published time in that window, before mainnet. The devnet cannot stand in: its nodes are all the project's (developer-adoption section 5, RPC providers row). + ### X16. An evidence page with four labels "Every claim needs a status, a software version, the test that produced it, the result and whether anyone outside reproduced it. 'Implemented', 'tested by the team', 'reproduced externally' and 'reviewed independently' are four different things, and your bench-log uses one voice for all of them." @@ -1557,12 +1617,14 @@ Evidence: `docs/bench-log.md`; `docs/spec/README.md` labels; G2. Publication: O- ### X17. The miner app must show net earnings and keep jobs away from keys "Show me what a card earns after my electricity tariff, mining and proving separately, which jobs failed and why, which release I am on and whether I accepted it, and promise that a proving job can never read my wallet. Your spec covers the update and the seed, and nothing else on that list." -Status: Open, design and measurement scheduled (O-8.2, O-8.3); update control and the seed are answered by design (spec 8.2 item 4, 8.5). Sweep (5 October 2026): design and devnet items (O-8.2, O-8.3); nothing runnable. +Status: Designed (5 October 2026, night): spec 8.8 and phone-app 4.1; measurement O-8.2 and the escape test O-8.3 scheduled for the phase 4 devnet. Was: Open, design and measurement scheduled (O-8.2, O-8.3); update control and the seed are answered by design (spec 8.2 item 4, 8.5). Sweep (5 October 2026): design and devnet items (O-8.2, O-8.3); nothing runnable. Answer: Update control and the seed are decided (spec 8.2 item 4: no silent updates, the user accepts each release; 8.5: seed confirmed, hardware wallet). The litepaper promises earnings "in IGN and in your currency" and M13 promised projected earnings before mining starts; neither nets off power. New requirements for the official client and the phone monitor: (a) net earnings per card after an electricity tariff the user enters, the gross beside it; (b) mining income and proving income reported separately, per card and per day; (c) hardware compatibility and power limits per card, with mining and proving capability stated separately as the benchmark reports them (P16); (d) every failed or retried job visible with its reason; (e) the running release, its hash and any pending release the user has not accepted; (f) isolation: proving jobs run guest programs supplied by strangers, so the prover process holds no wallet key, no seed and no vote key, runs under a separate OS user or sandbox, and reaches the signer only through a local socket that signs payout claims and nothing else, designed and reviewed before the first external job runs. The phone app carries (a), (b), (d) and (e) as display rules (phone-app 4.1). Evidence: spec 8.2, 8.5; `site/litepaper.html` For miners; M13; `proto-cuda/windows-app/README.txt`. Experiment: O-8.2 (display rules measured against the pool protocol's `stats` on the phase 4 devnet), O-8.3 (isolation design reviewed, then an escape test with a hostile guest program). Review: external, point 7. +Round 2 (5 October 2026, night): the isolation rule is written as `docs/spec/08-client-security.md` 8.8, labelled Designed: the prover process holds no wallet key, seed or vote key; it runs under a separate OS user or sandbox (a WSL2 distribution without the data directory on Windows); it reaches the signer only through one local socket that signs proof records and payout claims for work the engine handed out and nothing else; the escape test is a hostile guest program on the phase 4 devnet that tries the wallet file, the environment, the engine's memory, outbound connections and the signer's refused messages, passing when every attempt fails and the wallet file is byte-identical; the user is told on the tile and in Settings. The six display rules are written in `docs/design/phone-app.md` 4.1 against what Ember 0.3.9 already shows (hash rate per card and total, blocks, cards with VRAM, worker and the off-by-default reason, the 80% NVIDIA power cap with the slider and the efficiency sweep, the proving tile's assigned, submitted, paid and failed counts, the running version, the update card with version, size and notes) and what is new (the tariff and net earnings per card per day with the gross beside it; mining and proving income in separate columns per card per day; a proving line per card stating can prove, CPU only or cannot, with the measured shard time or "not measured"; the failed-job list with reasons and retries; the release hash on the card and the pending release's hash; the isolation statement with the escape-test date). Fact found while reading the app: in 0.3.9 the engine spawns the prover host and the record signer under the same OS user as itself (`app/igneum-app/src/prover.rs`), the wallet is `wallet.json` under that user (`src/keys.rs`) and the vote keys derive from the worker label the engine passes `igneum-miner` (`src/engine.rs`), so a guest program today runs as a user that can read all three; 8.8 changes that before the first external job. No app code was written in this round. + ## Execution attack findings (4 October 2026): fixed ### P18. The mempool queues transactions no block can carry @@ -1608,17 +1670,22 @@ Evidence: `docs/bench-log.md`, 4 October 2026 "difficulty rule: timestamp attack ### P21. The SP1 proof is not what consensus checks in proving v0 "Your proof records pay provers, and the node pays a record whose statement matches its own execution whether or not the SP1 proof behind it verifies. A prover can sign the native statement without proving anything." -Status: Open, stated in spec 7.7 item 4 (4 October 2026). Branch `proving` of the fork, `igneum/exec/src/proving.rs`. Sweep (5 October 2026): stated; the in-consensus verifier is a build item (execution engineer). +Status: Decided (6 October 2026, 17:25 UTC, by the owner; decisions item 11): proving v0 (every producer verifies off the consensus path) through the public testnet; the in-consensus verifier is the execution engineer's plan item for after it; the litepaper sentence labelled Open stands. Was: Open, stated in spec 7.7 item 4 (4 October 2026). Branch `proving` of the fork, `igneum/exec/src/proving.rs`. Sweep (5 October 2026): stated; the in-consensus verifier is a build item (execution engineer). +Decision owner: the project lead, decided 6 October 2026 (`docs/plans/ledger-decisions.md`, outcomes section). Answer: Correct for v0, and by design for now. The consensus check on a carried record is the native-execution veto (spec 7.2 item 5): the statement must equal the node's own 328-byte shard statement for that shard and payout address, so no record can move state or pay for a wrong claim. The SP1 proof is verified off the consensus path by the proof pool's verifier (`igneum-prove-host --mode verify`), and a producer offers only verified records to its templates; a producer that includes unverified records (trust mode, test networks only) can pay a prover who did not prove. The damage is bounded to that prover's payout. What closes it: the aggregated segment record of design 5.4 verified in consensus, which needs the SP1 verifier inside the node (the SDK dependency the node does not carry today) or a bounded in-consensus verification budget. Until then the devnet runs v0 with every producer verifying. +Round 2 (5 October 2026, night): the public text now carries the v0 fact, labelled Open: `site/litepaper.html`, Proving, "How a block gets proven": "Open: in proving v0 the SP1 proof itself is checked off the consensus path, by every block producer before it carries a record, and the native-execution check is what consensus enforces; whether the SP1 verifier moves inside consensus is a decision before the public testnet." Status unchanged: decision owner the project lead, decisions item 11. + ### P22. The rewards and payouts are inputs to the shard proof, not outputs "The shard guest takes the segment's rewards and the prover payouts as data and commits the post-root after them. A host can feed any list and the proof still verifies." -Status: Open, stated in spec 7.7 item 6 (4 October 2026). Sweep (5 October 2026): stated; nothing runnable. +Status: Open, blocked on the phase 2 consensus proof (design 7: the aggregator derives the rewards and payouts from consensus data it verifies, so they become outputs of the proof): next step that consensus-proof work, in phase 2 (Nov 2026 to Jan 2027 per the litepaper roadmap), no earlier date. Was: Open, stated in spec 7.7 item 6 (4 October 2026). Sweep (5 October 2026): stated; nothing runnable. Answer: Correct, and already true of the rewards since devnet v4 (`BlockFixture.rewards`, `proving_pool_credit`): the shard statement is "from this pre-root, these transactions, these rewards and payouts, the post-root is X". The node checks the statement against its own execution, which used the rewards and payouts consensus derived, so a proof over a different list does not match any node's statement and pays nothing. Closing it in the proof itself means the aggregator deriving the rewards and payouts from consensus data it verifies (the mergeset's blue blocks and the carried records), which is the consensus-proof work of design section 7. +Round 2 (5 October 2026, night): status made terminal-explicit. Blocker: until the consensus proof of design 7 exists, the rewards and payouts stay data inputs to the shard statement (spec 7.7 item 6) and the node's own derivation is the check. Next date: phase 2. The D6 review of this round names the same class for job outputs, where no consensus derivation exists to check against (`docs/review/d6-forged-job-result-2026-10-05.md`, section 1). + ## Status updates, 4 October 2026 (branch fin-fixes, commit da1eb889) - **F17** (keys are free, the draw is per key). Status: Fixed in the node (4 October 2026). `is_aggregator` draws the 8 aggregators by weight, `output x total < 8 x weight x 2^64`, so a splitter holds the tickets its weight buys and no more; spec 3.10 S1 row; unit test `sortition_is_by_weight_not_key_count` (200 dust keys plus 6 real ones); attack harness scenario 2 re-run: honest keys drew 1.61 seats per crowded checkpoint against 1.55 expected by weight, where master drew 0.32 against 0.33 per key (`docs/bench-log.md`, "finality fixes F17 and F1"). Still open from this entry: the client's one-key default, S2 (O-3.5), the bitmap size (O-3.12). Was: Rule fixed (spec 7.2 and W6), node per key. @@ -1689,21 +1756,25 @@ Evidence: spec 7.3; ledger E7; `docs/review/round-3-2026-10-03.md` line 344. ### D5. I cannot debug a revert "No `eth_subscribe`, no `debug_traceTransaction`, no `eth_getProof`, no explorer, no public RPC, no faucet, `finalized` resolves to the executed tip. You are inviting builders to a chain they cannot inspect." -Status: Conceded, scheduled. Sweep (5 October 2026): unchanged on the `proving` branch (no `debug_*`, `eth_subscribe` or `eth_getProof` in `igneum/exec/src/rpc.rs`); scheduled work, execution engineer. +Status: Conceded, scheduled (5 October 2026, night): `docs/design/developer-adoption.md` section 5, owner and gate named (the execution engineer; no outside team is invited before step 2 is done). Was: Conceded, scheduled. Sweep (5 October 2026): unchanged on the `proving` branch (no `debug_*`, `eth_subscribe` or `eth_getProof` in `igneum/exec/src/rpc.rs`); scheduled work, execution engineer. Answer: Correct on every item on 4 October 2026 (`docs/design/execution-layer.md` 10.3 items 1, 6, 7). The order in `docs/design/developer-adoption.md` section 5: docs and the Hardhat and Foundry templates first; `debug_*`, `eth_subscribe` and `eth_getProof` second, because the Blockscout fork and Foundry's debugger need them; a public devnet RPC, the chain-id listing on ethereum-lists/chains, wallet tests (R11) and a faucet third; the explorer fourth. No outside team is invited before the second step is done. Evidence: `docs/design/execution-layer.md` 10.1 (RPC table, "Missing"), 10.3; design 8.1, 8.4, R10, R11. +Round 2 (5 October 2026, night): the order in `docs/design/developer-adoption.md` section 5 is confirmed and the paragraph "Owner and gate" added below its table: step 1 the docs and the Hardhat and Foundry templates; step 2 `debug_traceTransaction`, `trace_block`, `eth_subscribe` and `eth_getProof` with the four-state tags; step 3 a public devnet RPC, the chain-id listing, the wallet tests of R11 and a faucet; step 4 the Blockscout fork. Owner: the execution engineer for every step, the docs site also waiting on the public-repository decision G11. Gate: no outside team is invited to build on the devnet before step 2 is done, with done meaning the methods answer on the devnet nodes under Foundry's debugger and the Blockscout fork, not on a branch. + ### D6. A forged job result reaches my contract and nobody vetoes it "Segments have the native-execution veto. Jobs do not: full nodes cannot re-run an arbitrary program, so for a precompile job the proof is the only check. A soundness bug in SP1 writes whatever the attacker wants into my callback." -Status: Conceded, contained by rule, review scheduled. Sweep (5 October 2026): a review item (R12 with the cryptographer); nothing runnable. +Status: Conceded, contained by rule, reviewed (5 October 2026, night): `docs/review/d6-forged-job-result-2026-10-05.md`. Next step: the three devnet checks of that review's section 6 (containment under a deliberately broken verifier; the version gate and the overlap; the callback boundary), on the phase 4 devnet once the precompile of design 6 exists (design 10.3 item 5). Was: Conceded, contained by rule, review scheduled. Sweep (5 October 2026): a review item (R12 with the cryptographer); nothing runnable. Answer: Correct. Design 6 says it in those words. The containment: a job output cannot mint IGN or touch system contracts (R12), jobs are gated behind the proof-system version with the three-month overlap and the 90% signal (design 5.6), and the emergency path for a live soundness bug is the version bump of spec 5.7. The rule for an app, the same one the customer brief gives rollups: anything that acts irreversibly on a job output keeps its own fallback. R12 is reviewed with the cryptographer before devnet v2. Evidence: `docs/design/execution-layer.md` 6, 5.6, 9.1 R12; spec 5.7; ledger P7; `docs/commercial/prover-customer-brief.md` "Risks". +Round 2 (5 October 2026, night): reviewed by the cryptographer agent, `docs/review/d6-forged-job-result-2026-10-05.md`. The attack as reviewed: a soundness bug in the proof system version in force lets a prover sign a job statement with a chosen output; the native-execution veto cannot catch it because every full node consumes the output as an input to `onProof` and computes the same root (design 6, 5.5), so the chain is consistent and wrong in one place. What the rules guarantee: no IGN is minted (emission and the pool are state transitions from consensus data, design 1.1 and 4.4; the only IGN moved is the job's escrow, 90% to the forger and 10% burned, design 6); no system contract is written except the job's own result slot in `Prover` (design 4.5, 6), so R12's "touch system contracts" wording needs that narrower sentence; the version gate (design 5.6, steps 1 to 5) and the emergency bump (design 5.5, spec 5.7) close a bug for good. What they do not: the callback's own state and everything downstream of it; the window between disclosure and activation, in which nothing pauses jobs and the 3-month overlap keeps a known-broken verifier reaching callbacks unless job records of the old version are cut at activation (the review's recommendations 2 and 3); the forger's payout; light clients, which agree with full nodes here. The rule for an app (review section 4): a job output is one party's word, and anything irreversible it drives keeps a fallback the app controls (a delay longer than the emergency activation time, a value cap, a second check, or a human veto). Design changes asked: the containment as a normative rule with the precise boundary; job records of version N invalid from the activation of N+1; the emergency release may cut jobs at activation while keeping the segment overlap; the prover is paid when the callback reverts. Devnet checks named (review section 6, phase 4): a job forged against a deliberately broken verifier, with the IGN total, the registry and `Prover` storage compared before and after; the swap procedure in fast time with version-N job records at each stage, the exposure window counted in blocks; four callbacks at the boundary (re-entrant request, past the stipend, reverting, and the app rule with a delay and a second check). + ## Round 4 entries (4 October 2026, afternoon): what is live Review: `docs/review/round-4-2026-10-04.md`. Scope: devnet v4 through `a21ff239` (HEAD `3bfe346f`), the prebuilt workers, the Igneum Miner app 0.3.1 to 0.3.3, the relay, the Windows CI, the downloads host, the live site and the economics after the day's measurements. No secret value appears in any entry; comparisons were count-only. @@ -1711,57 +1782,69 @@ Review: `docs/review/round-4-2026-10-04.md`. Scope: devnet v4 through `a21ff239` ### X23. One shipped key is an administrator channel to the founder's PCs "Your relay accepts either the URL token or the `x-igneum-key` header for everything, including queuing PowerShell that the PC agent runs as administrator. The key is the log intake key, a literal in six tracked files and inside every Windows and prover package you have handed out. And the zip with both relay secrets sits on the downloads host behind the dl token, which is in your git history and in every installed app. One token, four hops, no privilege boundary." -Status: Open, fatal as an operational fact (4 October 2026). The agent was live and elevated on PC 1 at 13:41 UTC (`GET machines`, read-only). Sweep (5 October 2026): the relay token was rotated on 4 October (`~/.config/igneum/relay-token.old-2026-10-04` sits beside the new one); `POST task` with `kind: run` still needs only the token (`relay/api/relay.mjs:114-119`, no per-machine secret or signature), so the operational half stands. The 401 test needs the deployed relay and PC 1 (relay owner; rotation is the project lead's). +Status: Fixed on a branch, pending merge (5 October 2026, night): ledger-relay 28c028b, tests 47 of 47 (relay, 6 suites) + 16 of 16 (packaging/windows/test-inputs-signing.sh) + 2 CI class checks. Was: Open, fatal as an operational fact (4 October 2026). The agent was live and elevated on PC 1 at 13:41 UTC (`GET machines`, read-only). Sweep (5 October 2026): the relay token was rotated on 4 October (`~/.config/igneum/relay-token.old-2026-10-04` sits beside the new one); `POST task` with `kind: run` still needs only the token (`relay/api/relay.mjs:114-119`, no per-machine secret or signature), so the operational half stands. The 401 test needs the deployed relay and PC 1 (relay owner; rotation is the project lead's). Answer: Correct. `relay/lib/relay.mjs:33-42` returns a truthy value for either secret and `relay/api/relay.mjs:111-124` accepts `kind: run` with `flags.elevated` from it; `relay/clients/igneum-agent.ps1:165-166` runs every item returned, as administrator, within 20 s. `README.md:7` and `make-clients.sh:8` make `RELAY_KEY` the intake key. The hosted `igneum-relay-clients.zip` carries the relay token and the key in four files; the dl token that guards it is 0644 on the Mac, in commit `c47ff03`, and in `igneum-app.json` of every install. Fix, in order: the zip off the host; rotate the relay token; a relay key of its own; a second per-machine secret or an Ed25519 signature over `{id, to, body}` for `run`; rotate the intake key and repackage. Review ids R4.4.1, R4.4.2, R4.5.1. Evidence: the files above; `docs/review/round-4-2026-10-04.md` sections 4 and 5. Experiment: after the fix, `POST task` with the old key and with a key-only header must return 401, and `GET machines` must show the rotated agent on PC 1. +Fix (5 October 2026, night): three tiers in `relay/lib/guard.mjs` (`authVia`): the console token (header or the phone page's path), the relay's own key (`RELAY_KEY`: reads and reports, never `task`, `run`, `name`, `role`, `secret`, `delete`), and the intake key (`the log key`, `_NEXT`) as a tier of its own that may only `upload` and `drop` a file or a note, no reads; it exists because the 0.3.6+ apps upload build-job outputs with it (`app/igneum-app/src/jobrun.rs`, `relay_upload`), and `RELAY_INTAKE_COMPAT=0` on the project closes it the day the apps carry a relay key (that app change is owed, not in this branch). A `run` task now needs, on top of the token, `flags.sig`, an Ed25519 signature by the Mac's run key (`~/.config/igneum/relay-run-key`, `node tools/relay.mjs keygen`) over `runCanon` = {machine, nonce, body sha256, elevated, reboot_continue, reboot}, verified by the relay with `RELAY_RUN_PUB` (401 without it or with a wrong one; 409 on a reused nonce; every run refused while `RELAY_RUN_PUB` is unset), and `flags.mac`, an HMAC-SHA256 tag with the target PC's own secret that `igneum-agent.ps1` (`Check-Task`) and `agent.sh` (`check_task`) verify before anything runs (exit 77 and a result when it fails; Windows PowerShell 5.1 has no Ed25519, so the agent's check is the HMAC). The console and the wake POST refuse the intake tier (`authedNoIntake`). Tests: `relay/test/handler.test.mjs` (a token-only `POST task` kind `run` is 401; a signed one is stored; a changed body, flag or target, another key, or no `RELAY_RUN_PUB` is 401; the relay key gets 403 on `task`; the intake key gets 403 on everything but `upload` and a file drop), `relay/test/guard.test.mjs` (the signature, the tag, `checkRun`). Owed to the project lead: `keygen` and `RELAY_RUN_PUB` on the project, one `secret` per PC with the zip carried by hand, the hosted `igneum-relay-clients.zip` off the downloads host (its values are dead since the 4 and 5 October rotations, the file remains), and the deploy (`relay/README.md`, "Rotation"). The 401 against the deployed relay and `GET machines` on PC 1 run after that deploy. + ### X24. The relay token rides in the URL on every request "Every poll of every agent and every page refresh puts the token in the path, so it is in Vercel's request logs, in browser history and in every terminal that ran `tools/relay.mjs`. You built an `x-relay-token` header and nobody uses it." -Status: Open (4 October 2026); the print lines fixed: `tools/relay.mjs` shows `/r/` in `list` and `watch` (only `url` prints the real one). Sweep (5 October 2026): `x-relay-token` is accepted (`relay/lib/relay.mjs:38`) but no client sends it (no match in `relay/clients`, `tools/relay.mjs` or `app/igneum-app/src`), so every request still carries the token in the path. The Vercel log check needs the deployment (relay owner). +Status: Fixed on a branch, pending merge (5 October 2026, night): ledger-relay 28c028b, tests 47 of 47 (relay, 6 suites) + 16 of 16 (packaging/windows/test-inputs-signing.sh) + 2 CI class checks. Was: Open (4 October 2026); the print lines fixed: `tools/relay.mjs` shows `/r/` in `list` and `watch` (only `url` prints the real one). Sweep (5 October 2026): `x-relay-token` is accepted (`relay/lib/relay.mjs:38`) but no client sends it (no match in `relay/clients`, `tools/relay.mjs` or `app/igneum-app/src`), so every request still carries the token in the path. The Vercel log check needs the deployment (relay owner). Answer: Correct. `relay/vercel.json:6` rewrites `/r//api/` to a query string; `igneum-agent.ps1:14`, `send.ps1:26`, `send.sh:11`, `agent.sh:10` and `tools/relay.mjs:24` all build the tokened URL, and `tools/relay.mjs:83,88,125` print it. `Referrer-Policy: no-referrer` and `X-Robots-Tag` are set (`vercel.json:12-13`); there is no HSTS. Fix: the header in every client, the URL token kept for the phone's page only, HSTS, and the print lines masked. Review id R4.4.3. Evidence: the files above. Experiment: the Vercel log view for `igneum-relay` after the change shows no token in any path. +Fix (5 October 2026, night): every client and Mac tool calls `/api/relay?fn=` with `x-relay-token` (and `x-igneum-key`) as headers: `igneum-agent.ps1` and `send.ps1` (`Api-Url`), `agent.sh` and `send.sh` (through a 0600 curl config file, `-K`, so the headers are on no command line either), `tools/relay.mjs`, `tools/console.mjs` (`/api/console?fn=`), `tools/build-job.mjs` (the token, else the relay key; the intake key reads nothing now). `igneum-agent.bat` and `send.bat` build no URL. The path token stays for the phone's page only: `/r//` (`ui.html`) and the calls that page makes (`/r//api/`, `/r//c/`, `/r//wake`), documented in `relay/README.md`. Print lines: `tools/relay.mjs` shows `/r/` everywhere but `url` (unchanged). Tests: `handler.test.mjs` (a request with the header and no token in the path is the token tier; a wrong header is 401), `clients.test.mjs` (every client and tool sends the header and none builds a tokened API path). Owed: the Vercel log view after the deploy (relay owner). + ### X25. The PC agent installs itself at every logon, at highest privilege, on every start "Double-click once and the agent writes a scheduled task with `/RL HIGHEST` and a RunOnce key. Your README says it only re-arms for a reboot. Closing the window does nothing." -Status: Open (4 October 2026). Sweep (5 October 2026): unchanged (`relay/clients/igneum-agent.ps1:72`, `schtasks /SC ONLOGON /RL HIGHEST`). The `schtasks /Query` check needs PC 1. +Status: Fixed on a branch, pending merge (5 October 2026, night): ledger-relay 28c028b, tests 47 of 47 (relay, 6 suites) + 16 of 16 (packaging/windows/test-inputs-signing.sh) + 2 CI class checks. Was: Open (4 October 2026). Sweep (5 October 2026): unchanged (`relay/clients/igneum-agent.ps1:72`, `schtasks /SC ONLOGON /RL HIGHEST`). The `schtasks /Query` check needs PC 1. Answer: Correct. `Arm-Restart` (`igneum-agent.ps1:68-79`) runs at `:154` on every start; `README.md:42` describes it as the `reboot_continue` path. Fix: arm only when a task asks for a reboot, and remove the task and the key on a clean exit. Review id R4.4.4. Evidence: `relay/clients/igneum-agent.ps1`. Experiment: `schtasks /Query /TN IgneumRelayAgent` on PC 1 before and after. +Fix (5 October 2026, night): `igneum-agent.ps1` calls `Arm-Restart` only on the two paths that end in `shutdown.exe /r` (a task that printed `RELAY-REBOOT` on its own line AND was queued with `--reboot` or `--reboot-continue`), sets `$script:KeepArmed` for that one exit, and `Disarm-Restart` (`schtasks /Delete /F /TN IgneumRelayAgent`, `Remove-ItemProperty` on the RunOnce key) runs on every start and in the main loop's `finally` (Ctrl+C included; a closed window skips `finally`, so the next start disarms again). The top-level `Arm-Restart` is gone. Tested on the Mac in parsing terms only (no `pwsh` here): `relay/test/clients.test.mjs` asserts `Arm-Restart` is called exactly twice, never at top level, each within 4 lines of the restart, and that `Disarm-Restart` runs at start and in `finally`; braces and here-strings balance; the 5.1 parse runs in `windows.yml` on the next push. Owed: `schtasks /Query /TN IgneumRelayAgent` on PC 1 before the new agent starts (expected: the task exists) and after (expected: nothing); PC 1 is not touched tonight. + ### X26. The feed is a permanent transcript, and it holds the dl token by design "One secret pages the whole history: every task body and every result transcript, usernames, hostnames, the folder that holds the secrets. And `tools/relay.mjs` writes the tokened download URL into task bodies before posting, so a relay leak is a dl-token leak." -Status: Open (4 October 2026). Sweep (5 October 2026): unchanged in `relay/api/relay.mjs` (no retention or cap on `feed`). Relay owner. +Status: Fixed on a branch, pending merge (5 October 2026, night): ledger-relay 28c028b, tests 47 of 47 (relay, 6 suites) + 16 of 16 (packaging/windows/test-inputs-signing.sh) + 2 CI class checks. Was: Open (4 October 2026). Sweep (5 October 2026): unchanged in `relay/api/relay.mjs` (no retention or cap on `feed`). Relay owner. Answer: Correct. `ITEM_COLS` (`relay/lib/relay.mjs:92`) includes `body`; `feed` returns up to 500 per call with no retention and no cap; `delete` leaves blobs. `tools/relay.mjs:76-80` substitutes `__DL_BASE__` with the tokened base and `playbooks/miner-v4.ps1:12` and `prover-setup.ps1:12` print it into the transcript. Today's 12 items hold 0 copies (count-only). Fix: retention (30 days), a cap on `feed`, the dl base passed as an environment value the agent holds rather than text in the body, blob deletion with the row. Review id R4.4.5. Evidence: the files above. Experiment: `feed?limit=500&before=` after the change returns nothing older than the retention. +Fix (5 October 2026, night): retention 30 days (`relay/lib/handler.mjs` `expire`: `DELETE ... WHERE ts < now - 30 d RETURNING file_url`, blobs deleted with the rows through `@vercel/blob` `del`, run on a feed read at most every 10 minutes per instance); `feed` capped at 100 a call (50 by default; `FEED_LIMIT_MAX`); `delete` removes the blob with the row. The downloads base is no longer text in any body: `tools/relay.mjs run` posts the playbook as written and refuses a body that says `__DL_BASE__` or carries the dl token; `make-clients.sh` bakes the base into the agent, which hands it to every task as `RELAY_DL_BASE` (`$env:RELAY_DL_BASE` in the five playbooks); the two print lines name the zip, not the URL. Tests: `handler.test.mjs` (120 rows, a `limit=500` read returns 100 with `limit: 100` in the reply; a row dated August goes on the next sweep with its blob, a row dated 1 October stays; `delete` reports `blobs: 1`), `guard.test.mjs` (`feedLimit`, `retentionCutoff`), `clients.test.mjs` (no playbook carries `__DL_BASE__` or prints the URL; the agents export the base). Owed: `feed?limit=500&before=` against the deployed relay after the first sweep. + ### X27. The relay has no clean rotation and no sender binding "Rotate the token and the key path stays open; rotate the key and every shipped package stops uploading logs. Any holder posts a `result` from any machine name, or registers a machine, and the Mac's watch prints it as truth." -Status: Open (4 October 2026). Sweep (5 October 2026): unchanged (`from` is a free field in `relay/api/relay.mjs`; nothing binds a `result` to the caller's machine). Relay owner. +Status: Fixed on a branch, pending merge (5 October 2026, night): ledger-relay 28c028b, tests 47 of 47 (relay, 6 suites) + 16 of 16 (packaging/windows/test-inputs-signing.sh) + 2 CI class checks. Was: Open (4 October 2026). Sweep (5 October 2026): unchanged (`from` is a free field in `relay/api/relay.mjs`; nothing binds a `result` to the caller's machine). Relay owner. Answer: Correct. `authed()` has two independent secrets with equal power; `insertItem` takes `from` as free text (`relay/api/relay.mjs:30`); `register` creates rows for any hostname (`:148-162`). Fix: the relay's own key (X23), `from` bound to the registered machine for `result` and `register` by a per-machine secret, and a documented rotation (token, relay key, intake key) with what each breaks. Review ids R4.4.6, R4.4.7. Evidence: the files above. Experiment: a `result` posted with a `from` that does not match the caller's machine secret is refused. +Fix (5 October 2026, night): a per-machine secret (64 hex, `node tools/relay.mjs secret PC1`: written to `~/.config/igneum/relay-machines/PC1` at 0600, its sha256 bound on the relay with `POST secret` (token only), carried to the PC as `machine-secret.txt` by `make-clients.sh --machine PC1`). `register` with `x-machine-secret` names the machine whatever the hostname says (both PCs report DESKTOP-KMCV30N), drops `info.user` and `info.dir`, and a bound hostname without the secret is 403; a `result` with the secret is stored under the machine it proves and a `from` that does not match is 403; a result without the secret from a bound machine is 403; from a machine with no secret yet it is accepted with `flags.unbound` (the compatibility window, visible in the feed). `done` records `done_by`. The rotation of every secret (token, relay key, intake key, run key, machine secret: how, what stops, in what order) is the table "Rotation" in `relay/README.md`. Tests: `handler.test.mjs` (the forged `from` is refused; the matching one stored; unknown secret 403; bound hostname 403; the compatibility case marked unbound; `done` with a wrong secret 403), `guard.test.mjs` (`machineForSecret`). Owed: one `secret` per PC, the zips by hand, and `ADD COLUMN IF NOT EXISTS secret_hash` runs on the first `secret` or `feed` call after the deploy. + ### X28. Relay hygiene, minor "`===` on secrets, no HSTS, a GET that acks, a reboot on any output containing `RELAY-REBOOT`, orphaned blobs, no rate limit anywhere, a WSL user `igneum`/`igneum` with NOPASSWD sudo, the username and secret folder posted on register, and a file in `~/.config/igneum` whose name is a token." -Status: Open, minor (4 October 2026); two of the points fixed: secrets compared in constant time (`relay/lib/auth.mjs`, `sameSecret`, unit test in CI) and HSTS on the relay (`relay/vercel.json`). Sweep (5 October 2026): the remaining points unchanged; relay owner. +Status: Fixed on a branch, pending merge (5 October 2026, night): ledger-relay 28c028b, tests 47 of 47 (relay, 6 suites) + 16 of 16 (packaging/windows/test-inputs-signing.sh) + 2 CI class checks. The stray file is gone. Was: Open, minor (4 October 2026); two of the points fixed: secrets compared in constant time (`relay/lib/auth.mjs`, `sameSecret`, unit test in CI) and HSTS on the relay (`relay/vercel.json`). Sweep (5 October 2026): the remaining points unchanged; relay owner. Answer: Correct on each point: `relay/lib/relay.mjs:38,40`; `relay/vercel.json:8-16`; `relay/api/relay.mjs:85`; `igneum-agent.ps1:133`; `:145`; no limiter in either function; `relay/playbooks/wsl-setup.ps1:39-40` and `prover-setup.ps1:21`; `igneum-agent.ps1:41, :113`; the stray file next to `desec-token` (3 Oct 19:33). Fix when convenient; the stray file today. Review ids R4.4.9 to R4.4.13. Evidence: the files above. +Fix (5 October 2026, night): the remaining points. The GET that acks: `GET inbox` marks nothing (`ack=1` is ignored); `POST inbox {machine, kind, ack:true}` returns the list and marks it, and every client uses the POST. The reboot trigger: the agent restarts only when `RELAY-REBOOT` stands on a line of its own (`(?m)^RELAY-REBOOT\r?$`; `wantsReboot` in `guard.mjs`) AND the task was queued with `--reboot` or `--reboot-continue` (`flags.reboot`, part of the signed text); a marker inside other output, or in a task without the flag, is logged and refused. The rate limit: 120 calls a minute per IP and 10 failed authentications a minute per IP, 429 with `Retry-After` (`RateLimit` from `lib/wake.mjs`). The register payload: no username and no folder from either agent, and the relay strips `info.user` and `info.dir` whatever a client sends. The NOPASSWD line: `wsl-setup.ps1` writes `igneum ALL=(root) NOPASSWD:SETENV: /usr/bin/apt-get, /usr/bin/dpkg` (what `setup-wsl.sh` runs under sudo: lines 20, 21, 27, 28, 31) and checks it with `visudo -cf`; `prover-setup.ps1` no longer echoes the password into `sudo -S` and tests `sudo -n apt-get --version` instead. The `igneum`/`igneum` password itself stays (the user exists to be unattended). The stray file: `ls -la ~/.config/igneum` tonight (read-only) lists no file whose name is a token; the 28-character file beside `desec-token` is gone, so nothing is left for the project lead to delete there. Tests: `handler.test.mjs` (GET inbox with `ack=1` leaves `read` false, POST acks; 429 after the limit, a second IP unaffected, failed auths on their own counter; registration stripped), `guard.test.mjs` (`wantsReboot`), `clients.test.mjs` (the agents' marker regex and flag gate, no GET ack in any client, the sudoers line, no `sudo -S`). Review ids R4.4.9 to R4.4.13 closed; the WSL user's password is the one point kept by design. + ### G12. The PoW schedule comes from the environment on every network, including mainnet "Your mainnet gate refuses the override file. It does not refuse `IGNEUM_POW_EPOCH_BLOCKS`. A node without a file installs the schedule from the environment and `Params.pow_epoch_blocks` is never consulted." @@ -1778,21 +1861,26 @@ Evidence: the files above. Experiment: start a node with `IGNEUM_POW_EPOCH_BLOCK ### G13. The update signature covers binaries that nobody signed "The runner fetches `payload-inputs.zip` and its sha256 from the same host, builds the installer, and the Mac signs the manifest over whatever the latest green run produced. A compromised dl project or runner ships as a genuine update." -Status: Open (4 October 2026). +Status: Fixed on a branch and verified locally (5 October 2026, night): ledger-relay 28c028b, tests 47 of 47 (relay, 6 suites) + 16 of 16 (packaging/windows/test-inputs-signing.sh) + 2 CI class checks. The GitHub run is owed (no push tonight). Was: Open (4 October 2026). Answer: Correct. `.github/workflows/windows.yml` (step "payload inputs") checks the zip against a sha256 served beside it; `packaging/windows/fetch-ci-artifacts.sh` takes the latest green run and calls `packaging/ota/publish-manifest.sh` by default; the node fork is not in the repository the runner builds, so spec 08 item 4 has nothing to reproduce from. Fix: a detached Ed25519 signature over `payload-inputs.zip` made on the Mac and verified in CI before the build; `OTA_SKIP=1` by default with the signing step naming the run id it signs. Review id R4.5.2. Evidence: the files above. Experiment: alter one byte of a hosted `payload-inputs.zip` on a test folder and run the workflow; it must fail before the build. +Fix (5 October 2026, night): the chain already on master was read end to end and run, not asserted. `packaging/windows/push-inputs.sh` writes `payload-inputs.json` (the zip's sha256 and size, every file's, the node fork commit and branch, the repository commit) and signs it on the Mac with the OTA key (`igneum-ota-sign sign-inputs`); `.github/workflows/windows.yml` step "payload inputs" verifies the signature with the key compiled into the app, the zip's hash, every unpacked file and the pinned node commit (`packaging/windows/node-source.pin`) before anything is built from the inputs (the engine step runs first only because it builds the verifier, from git); `packaging/windows/fetch-ci-artifacts.sh` leaves the manifest alone by default (`OTA_SKIP=1` is the default; `--sign-manifest` needs an explicit run id, re-downloads that run's `igneum-windows-inputs` artifact, re-verifies the signature and the pin at the run's commit on the Mac, checks the runner's record names that run, that commit and that key, then signs). The local test the ledger asked for: `IGNEUM_OTA_SIGN=
/app/igneum-app/target/release/igneum-ota-sign packaging/windows/test-inputs-signing.sh`, tonight 16 passed, 0 failed, including "one byte appended to the zip: refused (sha256 ...)", a changed manifest byte, a changed unpacked file, an unlisted file, a missing file, a wrong and a short pin, another key, the embedded key against a throwaway signature, and the real OTA key verifying against `embedded`. Owed: the workflow run itself on GitHub (nothing is pushed tonight); the experiment on a hosted test folder stays as written. + ### G14. Secrets and identity in the history of a repository with a public date "The intake key is in six files across eight commits, the dl token in one, the review and ledger files are tracked, 51 tracked files carry the founder's first name, and every commit today is stamped with the local-time offset. The 3 October sweep said zero hits." -Status: Open (4 October 2026); extends `docs/fud-fixes.md` section 5. +Status: Decided (6 October 2026, 17:25 UTC, by the owner; decisions item 8): the history rewrite runs the morning after the last of the close's branches merges, with every worktree removed first and both secrets rotated regardless. Was: Fixed on a branch, pending merge (5 October 2026, night), the tooling part: ledger-relay 28c028b, tests 47 of 47 (relay, 6 suites) + 16 of 16 (packaging/windows/test-inputs-signing.sh) + 2 CI class checks. Decision owner: the project lead for the rewrite date (`docs/plans/ledger-decisions.md`). Was: Open (4 October 2026); extends `docs/fud-fixes.md` section 5. +Decision owner: the project lead, decided 6 October 2026 (`docs/plans/ledger-decisions.md`, outcomes section). Answer: Correct, count-only. The key: `packaging/mac/packaged-config.sh`, `infra/gpu-bench/upload.sh`, `proving/windows-wsl2/prove-block.sh`, `prove-shard.sh`, `proto-cuda/windows-miner/upload-log.bat`, `proto-cuda/windows-app/upload-log.bat`, commits `78df757` to `4c9810f`. The token: `docs/plans/morning-2026-10-04.md:49`, commit `c47ff03`. `git check-ignore` returns nothing for the ledger, fixes and review files. The CI identity grep covers the public export list, by design. Fix: both secrets join section 5 step 4's rewrite list (and are rotated regardless); `TZ=UTC` in the commit path now. Review ids R4.4.8, R4.5.3, R4.5.4. Evidence: `git ls-files | xargs grep -lF ` counts, `git log -S`. Experiment: section 5 step 7 re-run after the rewrite returns nothing. +Fix (5 October 2026, night): `TZ=UTC` in every commit path the tooling owns: `tools/ship-app.mjs` (`git()` runs with `env: { TZ: 'UTC' }`), `packaging/ota/publish-jobs.sh` (`export TZ=UTC`, found by the class check), `tools/repo/fresh-repo.sh` (already). The class check `tools/ci/commit-tz-check.sh` (self-test first) fails CI on any script under `tools/`, `packaging/`, `infra/` or `.github/` that invokes `git commit` without `TZ=UTC`, and prints the count of commits on the branch with a non-UTC offset: 417 tonight, 0 after the rewrite. The two secrets on the rewrite list: `docs/plans/history-rewrite.md` section 2 already names the intake key and the dl token in `replace.txt`; added tonight: after the 5 October rotation the values IN THE HISTORY are the ones in `~/.config/igneum/the log key.old-2026-10-05` and `dl-token.old-2026-10-05`, so `replace.txt` must be written from the `.old` files, not the live ones; the relay key, token, run key and machine secrets are in 0 files and 0 commits. The commit of this branch carries `+0000`. The rewrite itself (and its day) is the project lead's decision. + ### X18. Two nodes with two override files connect, and only some mismatches fork "Your handshake compares the network name and nothing else. A PoW or difficulty mismatch forks and bans; a `finality` mismatch is a WARN; `rollout-v2.sh` throws the finality block away when it writes the file; the app rewrites the packaged file on every start." @@ -1848,30 +1936,42 @@ Evidence: the first run's `/tmp/igneum-redteam-fin/n0/node.log` parse line (kept ### X19. Operational knobs and silences in the shipped node "A slow-clock node disconnects every peer on every relayed block and never says why; the handshake's `time_offset` is computed and unused; `IGNEUM_ATTACK_TS_OFFSET_MS` and `IGNEUM_POW_STRIKES` are compiled into the live binary; `timestamp_deviation_tolerance` is dead and still accepted." -Status: Open, minor (4 October 2026). Sweep (5 October 2026): the app half is done (bench-log, "a node 60 s behind the clock is silently dead": the node card shows the skew with a Sync clock button, Start is blocked past 10 s, checked with `IGNEUM_APP_FAKE_SKEW=-60`); the node's one WARN line is filed in `docs/plans/node-changes.md` section 1 and not written; `faketime` is not installed on this Mac, so the node experiment was not run. +Status: Fixed on a branch, pending merge (5 October 2026, night): fork branch `ledger-fixes-0311` fbb0082a (fc0cb938 rebased onto the 0.3.11 fork tip 89dfcb95 in round 3), suites PC 2 jobs `build-20261005-200049` (kaspa-consensus 95 passed, 0 failed, 3 ignored) and `build-20261005-200606` (kaspa-consensus-core 101/0, kaspa-mining 52/0, igneum-exec 13/0, igneum-miner 17/0, kaspa-p2p-flows 32 passed 1 failed: the new clock-skew test's own arithmetic, corrected in bd1b676a and 33/0 on the Mac), both on 815c7d64; the tip is fbb0082a. Was: Open, minor (4 October 2026). Sweep (5 October 2026): the app half is done (bench-log, "a node 60 s behind the clock is silently dead": the node card shows the skew with a Sync clock button, Start is blocked past 10 s, checked with `IGNEUM_APP_FAKE_SKEW=-60`); the node's one WARN line is filed in `docs/plans/node-changes.md` section 1 and not written; `faketime` is not installed on this Mac, so the node experiment was not run. Answer: Correct. `blockrelay/flow.rs:201`, `router.rs:215-224`, `flow_context.rs:819`, `peer.rs:13`; `virtual_processor/processor.rs:1663-1670` (merged in `baa8bc8a`); `pow_guard.rs:28`. The 10 s bound itself is right in shape (two constants, both directions, not overridable). Fix: one WARN from `time_offset` at handshake, the attack switches behind a feature flag, the dead field refused. Review ids R4.1.6 to R4.1.8. Evidence: the files above. Experiment: `igneumd` under `faketime -60s` logs one clear line and does not churn. +Fix (5 October 2026, night), the node half, fork commit fc0cb938. (a) `protocol/flows/src/flowcontext/clock_skew.rs`: the relay path (`charge_pow_strikes`, which sees every block result) keeps the (header timestamp minus local now) of the headers refused as `TimeTooFarIntoTheFuture` over the last minute and logs ONE WARN per minute, `clock skew: local time is N s behind the median peer block time (blocks are being refused; set the clock)`, with the count refused and the tolerance; the per-block error text is unchanged, so the app's parser keeps working (`docs/plans/node-changes.md` section 1). The mirror case (local clock ahead) is refused on the peers and not visible here; not written. (b) `IGNEUM_ATTACK_TS_OFFSET_MS` (both template-time sites) and `IGNEUM_POW_STRIKES` (the PoW guard) are read only under the new cargo feature `attack-switches` (`kaspad` forwards it to `kaspa-consensus`, `kaspa-mining`, `kaspa-p2p-flows`); a release build returns the clock's time and the default strike limit and never reads the environment. (c) `OverrideParams` refuses a file that carries `timestamp_deviation_tolerance` at load, with a message naming the field, and never writes it; `infra/fast-time/override-60x.json` on branch `ledger-fork` no longer carries it (a node from this line refuses the master copy of that file until the two merge together). Tests: `clock_skew` unit tests (a 60 s skew gives one line, nothing more inside the minute, the median after it), `release_build_ignores_the_strike_env` (compiled only without the feature), the override refusal in `params.rs`. The two-node fast-time run with one node's clock offset was not run (the offset needs an `attack-switches` build of the node, a second build); the WARN path is covered by the unit test on the monitor and by review of the hook, which runs on every relayed block result. + +Round 3 (6 October 2026, night): the fork branches `ledger-fixes` (bd1b676a) and `ledger-fixes-2` (b1e98b79) merged onto the 0.3.11 fork tip 89dfcb95 as `ledger-fixes-0311` (merge 99ea7d97, fallout 7d4c8b3c, P23 fbb0082a, the tip), built on the Mac against `igneum-pow` as release-0.3.11 ships it (the fork resolves `../../../../igneum-pow` from the checkout it sits under; `ledger-rebase` carries that crate at 42be745 and the fork worktree moved under it). `clock_skew.rs`, the `attack-switches` feature and the `timestamp_deviation_tolerance` refusal merged without conflict. One coupling surfaced by the suites: kaspa-consensus-core's `fast_time_60x_file_is_the_devnet_at_60x` reads `infra/fast-time/override-60x.json` from the checkout beside the fork and requires every `OverrideParams` field; release-0.3.11's copy still carries `timestamp_deviation_tolerance: 132` (a node from this line refuses it at load) and fud-close's copy lacked 0.3.11's six fields (`program_class_v3_activation_daa`, `pow_genesis_dataset_log2`, `proving_v1_activation_daa`, `proving_v1_segment_blocks`, `proving_v1_unproven_daa`, `proving_v1_aggregator_share_bps`). `ledger-rebase` 2bbc12f adds the six with release-0.3.11's values and keeps the dead field out; the test passed on it (kaspa-consensus-core 108 of 108). The cut that merges fud-close with release-0.3.11 must take this copy of the file, not 0.3.11's. Suites on the rebased fork, the Mac run (`cargo test --release -j 4` under the build lock, labelled a Mac run: PC 2 was queued behind the Counter ASIC 2.0 chain and no go came inside 30 minutes; the PC 2 slot for the same job still stands with the coordinator): PC 2 job `build-20261006-012543` (published by the Counter ASIC 2.0 coordinator at 01:25:43Z, done 01:32:33Z, every stage ok): fork fbb0082a built for Linux (igneumd 49,245,928 bytes, igneum-miner 9,905,848) and Windows (igneumd.exe 51,380,736, igneum-miner.exe 11,044,864), the seven suites exit 0 in 46 s, but without `--features igneum-pow` (build-job.mjs passes none), so the PC run is the no-feature evidence and the Mac run with the feature is the suite evidence; the feature flag for build-job is on the 0.3.12 list. kaspa-consensus 99 passed, 1 failed, 4 ignored (the failure is 0.3.11's own `igneum_m20_tests::witnesses_are_checked_in_epoch_order_under_their_own_seeds`, the era-0 stand-in of `pruning_proof/igneum_pow.rs:114` against `EpochSeeds::v2`'s zero era, both from 89dfcb95, neither file touched on the ledger branches; owned by the Counter ASIC 2.0 coordinator), kaspa-consensus-core 108 passed, 0 failed, 2 ignored (db_compat 7 of 7), kaspa-mining 52 of 52, kaspa-p2p-flows 36 of 36, kaspa-pow 14 of 14, kaspad 2 of 2, igneum-exec 23 of 23, igneum-miner 20 of 20. The two-node run with one clock offset is still owed (needs an `attack-switches` build). + ### X20. Cold-sync checkpoint determination is indices times chain length "A fresh node starts `next_index` at 0 and walks the selected chain from the sink for every index. At mainnet length it never finishes its first resolution." -Status: Open, minor now (4 October 2026). Sweep (5 October 2026): unchanged on `finality-fixes` (`processes/finality.rs:204` starts `next_index` at 1 and walks the chain per index). A 10^6-block simnet is 11.6 days of chain at 1 block/s and was not built. Fix row in section 2.5. +Status: Fixed on a branch, pending merge (5 October 2026, night): fork branch `ledger-fixes-0311` fbb0082a (9e109c65 rebased onto the 0.3.11 fork tip 89dfcb95 in round 3), suites PC 2 jobs `build-20261005-200049` (kaspa-consensus 95 passed, 0 failed, 3 ignored) and `build-20261005-200606` (kaspa-consensus-core 101/0, kaspa-mining 52/0, igneum-exec 13/0, igneum-miner 17/0, kaspa-p2p-flows 32 passed 1 failed: the new clock-skew test's own arithmetic, corrected in bd1b676a and 33/0 on the Mac), both on 815c7d64; the tip is fbb0082a. Was: Open, minor now (4 October 2026). Sweep (5 October 2026): unchanged on `finality-fixes` (`processes/finality.rs:204` starts `next_index` at 1 and walks the chain per index). A 10^6-block simnet is 11.6 days of chain at 1 block/s and was not built. Fix row in section 2.5. Answer: Correct. `processes/finality.rs:413-421`. About 3 x 10^12 store reads at a 10^7-block chain, approximate. Fix: start from the last certified index carried in headers, walk once. Review id R4.1.10. Evidence: the file above. Experiment: a fresh node against a 10^6-block simnet chain, time to first resolution. +Fix (5 October 2026, night): `consensus/src/processes/finality.rs` `on_virtual_changed` resolves every index the sink can determine in ONE descending walk of the selected chain (`chain_blocks_at`, targets highest first), where it walked from the sink once per index. Cost per cold sync from indices x chain length store reads to one pass over the chain. Locked indices above the next one (F24) are passed over as before. On this line headers carry no certified index (certificates ride in coinbase payloads and are ingested as blocks arrive), so the walk starts at `next_index`; the ledger's "start from the last certified index carried in headers" has no field to start from and is noted here, not built. Unit test `cold_sync_determines_every_index_in_one_walk`: 150-block chain, interval 5, depth 2, 29 indices; the one walk takes at most 150 steps against a per-index sum over 10 times larger, and names the same block as `chain_block_at` for every index. The fast-time simnet timing was not run: a simnet chain is a few hundred blocks, where the two walks differ by milliseconds; the 10^6-block chain of the experiment line is still owed. Fork commit 9e109c65. + +Round 3 (6 October 2026, night): the fork branches `ledger-fixes` (bd1b676a) and `ledger-fixes-2` (b1e98b79) merged onto the 0.3.11 fork tip 89dfcb95 as `ledger-fixes-0311` (merge 99ea7d97, fallout 7d4c8b3c, P23 fbb0082a, the tip), built on the Mac against `igneum-pow` as release-0.3.11 ships it (the fork resolves `../../../../igneum-pow` from the checkout it sits under; `ledger-rebase` carries that crate at 42be745 and the fork worktree moved under it). `consensus/src/processes/finality.rs` merged without conflict; the one-walk determination and its unit test `cold_sync_determines_every_index_in_one_walk` are unchanged on the rebased line. Suites on the rebased fork, the Mac run (`cargo test --release -j 4` under the build lock, labelled a Mac run: PC 2 was queued behind the Counter ASIC 2.0 chain and no go came inside 30 minutes; the PC 2 slot for the same job still stands with the coordinator): PC 2 job `build-20261006-012543` (published by the Counter ASIC 2.0 coordinator at 01:25:43Z, done 01:32:33Z, every stage ok): fork fbb0082a built for Linux (igneumd 49,245,928 bytes, igneum-miner 9,905,848) and Windows (igneumd.exe 51,380,736, igneum-miner.exe 11,044,864), the seven suites exit 0 in 46 s, but without `--features igneum-pow` (build-job.mjs passes none), so the PC run is the no-feature evidence and the Mac run with the feature is the suite evidence; the feature flag for build-job is on the 0.3.12 list. kaspa-consensus 99 passed, 1 failed, 4 ignored (the failure is 0.3.11's own `igneum_m20_tests::witnesses_are_checked_in_epoch_order_under_their_own_seeds`, the era-0 stand-in of `pruning_proof/igneum_pow.rs:114` against `EpochSeeds::v2`'s zero era, both from 89dfcb95, neither file touched on the ledger branches; owned by the Counter ASIC 2.0 coordinator), kaspa-consensus-core 108 passed, 0 failed, 2 ignored (db_compat 7 of 7), kaspa-mining 52 of 52, kaspa-p2p-flows 36 of 36, kaspa-pow 14 of 14, kaspad 2 of 2, igneum-exec 23 of 23, igneum-miner 20 of 20. The 10^6-block chain of the experiment line is still owed. + ### M25. The miner takes the day length from its environment, and the schedule global can tear "The template carries epoch and lead but not the day; the miner reads `IGNEUM_POW_DAY_MS` from its environment. And `install_pow_schedule` stores day, lead, epoch while `pow_schedule` loads epoch, lead, so a miner switched between schedules can wrap `pow_epoch_seed_score`." -Status: Open, minor (4 October 2026). Sweep (5 October 2026): the schedule now rides in the override file as consensus params (`a5ef8b07`, in `devnet-v4`); the mismatch run was done (5 October 2026, 01:05 UTC, `scratchpad/runs/batch3.sh` under the run lock: one `finality-fixes` node with real PoW at genesis bits 2^16 on ports 29410 to 29412, `pow_day_ms` 86,400,000 in its override file; a control miner, then a miner started with `IGNEUM_POW_DAY_MS=1440000`, 2 CPU threads, 60 s each). Confirmed: the miner still takes the day from its environment (it built its cache for day 1,243,862 while the node and the control miner were on day 20,731); control 7 blocks accepted, 0 rejected; mismatched 0 accepted, 4 rejected, each as `Reject(BlockInvalid)` on the miner and `block has invalid proof-of-work` on the node, so the miner says that it is rejected and not why. Fix row 127: the day length in the template beside the epoch and lead, and a rejection reason that names the day. The environment fallback is G12, owned by the fud-consensus branch. +Status: Fixed on a branch, pending merge (5 October 2026, night): fork branch `ledger-fixes-0311` fbb0082a (3d4ec451 and fc0cb938 rebased onto the 0.3.11 fork tip 89dfcb95 in round 3), suites PC 2 jobs `build-20261005-200049` (kaspa-consensus 95 passed, 0 failed, 3 ignored) and `build-20261005-200606` (kaspa-consensus-core 101/0, kaspa-mining 52/0, igneum-exec 13/0, igneum-miner 17/0, kaspa-p2p-flows 32 passed 1 failed: the new clock-skew test's own arithmetic, corrected in bd1b676a and 33/0 on the Mac), both on 815c7d64; the tip is fbb0082a. Was: Open, minor (4 October 2026). Sweep (5 October 2026): the schedule now rides in the override file as consensus params (`a5ef8b07`, in `devnet-v4`); the mismatch run was done (5 October 2026, 01:05 UTC, `scratchpad/runs/batch3.sh` under the run lock: one `finality-fixes` node with real PoW at genesis bits 2^16 on ports 29410 to 29412, `pow_day_ms` 86,400,000 in its override file; a control miner, then a miner started with `IGNEUM_POW_DAY_MS=1440000`, 2 CPU threads, 60 s each). Confirmed: the miner still takes the day from its environment (it built its cache for day 1,243,862 while the node and the control miner were on day 20,731); control 7 blocks accepted, 0 rejected; mismatched 0 accepted, 4 rejected, each as `Reject(BlockInvalid)` on the miner and `block has invalid proof-of-work` on the node, so the miner says that it is rejected and not why. Fix row 127: the day length in the template beside the epoch and lead, and a rejection reason that names the day. The environment fallback is G12, owned by the fud-consensus branch. Answer: Correct. `igneum/miner/src/main.rs:590-596`; `consensus/core/src/igneum.rs:156-172, 198-204`. Fix: the day length in the template; one atomic struct swap. Review id R4.1.9. Evidence: the files above. Experiment: `igneum-miner` with `IGNEUM_POW_DAY_MS=1440000` against a default node accepts zero blocks and says why. +Fix (5 October 2026, night). Read on `release-0.3.6` first: the template already carries `day_ms`, `day_index` and `next_day_index` beside the epoch fields (`RpcPowEpochInfo`, G12 merged into 0.3.6), the miner installs the node's three values from every template and never reads `IGNEUM_POW_DAY_MS` (only the node does, on devnet and simnet). Two gaps remained and are closed: `next_pair` in `igneum/miner/src/main.rs` took the devnet constant `DAY_MS` for the day-change lead instead of the live `pow_day_ms()` (wrong on any non-default day length, fork commit 3d4ec451); and the node's rejection named nothing (`PoW rejected ... (daa, nonce)`, `RuleError::InvalidPoW` bare). Now `RuleError::InvalidPoW { header_day, engine_day, day_ms }` reads `block has invalid proof-of-work (header day D from its timestamp at M ms per day, engine day E; a miner on another day length or epoch seed computes another dataset)` and the log line adds the epoch seed (fork commit fc0cb938). Mismatch re-run (the batch3 recipe: one `ledger-fixes` node with real PoW at genesis bits 0x1f010000 on ports 29410 to 29412, `pow_day_ms` 86,400,000, a control miner then a miner started with `IGNEUM_POW_DAY_MS=1440000`, 2 CPU threads, 60 s each, under the run lock): the miner started with `IGNEUM_POW_DAY_MS=1440000` installed the node's schedule from the first template (`node PoW schedule: 60 DAA per epoch, lead 10, day 86400000 ms`), built its cache for day 20,731 like the node and the control, and was accepted: control 65 found, 0 rejected; mismatched 65 found, 0 rejected; node 130 `PoW accepted`, 0 `PoW rejected` (19:07 to 19:09 UTC). The environment is ignored, so the rejection path was not exercised live; its text is the unit-level evidence (`RuleError` message and the log line). Bench-log, "5 October 2026 (night), ledger close round 1". + +Round 3 (6 October 2026, night): the fork branches `ledger-fixes` (bd1b676a) and `ledger-fixes-2` (b1e98b79) merged onto the 0.3.11 fork tip 89dfcb95 as `ledger-fixes-0311` (merge 99ea7d97, fallout 7d4c8b3c, P23 fbb0082a, the tip), built on the Mac against `igneum-pow` as release-0.3.11 ships it (the fork resolves `../../../../igneum-pow` from the checkout it sits under; `ledger-rebase` carries that crate at 42be745 and the fork worktree moved under it). In `next_pair` the live day length (`pow_day_ms()`, never the devnet constant) stays, with 89dfcb95's carry of the class and the era seed into the next pair (`..*seeds` for the day change, `info.next_class()` and the same era for the epoch change); the `RuleError::InvalidPoW { header_day, engine_day, day_ms }` text merged without conflict. Suites on the rebased fork, the Mac run (`cargo test --release -j 4` under the build lock, labelled a Mac run: PC 2 was queued behind the Counter ASIC 2.0 chain and no go came inside 30 minutes; the PC 2 slot for the same job still stands with the coordinator): PC 2 job `build-20261006-012543` (published by the Counter ASIC 2.0 coordinator at 01:25:43Z, done 01:32:33Z, every stage ok): fork fbb0082a built for Linux (igneumd 49,245,928 bytes, igneum-miner 9,905,848) and Windows (igneumd.exe 51,380,736, igneum-miner.exe 11,044,864), the seven suites exit 0 in 46 s, but without `--features igneum-pow` (build-job.mjs passes none), so the PC run is the no-feature evidence and the Mac run with the feature is the suite evidence; the feature flag for build-job is on the 0.3.12 list. kaspa-consensus 99 passed, 1 failed, 4 ignored (the failure is 0.3.11's own `igneum_m20_tests::witnesses_are_checked_in_epoch_order_under_their_own_seeds`, the era-0 stand-in of `pruning_proof/igneum_pow.rs:114` against `EpochSeeds::v2`'s zero era, both from 89dfcb95, neither file touched on the ledger branches; owned by the Counter ASIC 2.0 coordinator), kaspa-consensus-core 108 passed, 0 failed, 2 ignored (db_compat 7 of 7), kaspa-mining 52 of 52, kaspa-p2p-flows 36 of 36, kaspa-pow 14 of 14, kaspad 2 of 2, igneum-exec 23 of 23, igneum-miner 20 of 20. + ### M26. The interval fault guard freezes its baseline and loops "On a trip you skip the STATUS print, so the baseline it would have updated stays frozen, and you roll the counters back to it. Any healthy rate over ten times a slow first interval trips again every interval, forever, with no STATUS line and no `faults=` for the app to read." @@ -1897,12 +1997,18 @@ Evidence: the files above. Experiment: a fast-time simnet node patched to flip ` ### M28. The kernel text is bound only to its own directory "The worker compiles whatever `kernel_bound.cu` it finds in a directory whose `seeds.txt` matches; the self-test checks the GPU against a `vectors.h` from the same directory. Nothing commits the text to what the generator would emit for the seed. 'Source check PASS' is a prefix equality." -Status: Open, minor (4 October 2026). The writer is the local miner and the directory is the user's own, so no privilege boundary is crossed. Sweep (5 October 2026): no kernel hash in `program.json` on any branch (`git grep -i 'kernel_hash|program_hash'` on `miner-reliability` finds nothing); the tampered-pack test needs a GPU worker. Fix row in section 2.5. +Status: Fixed on a branch, pending merge (5 October 2026, night): fork branch `ledger-fixes-0311` fbb0082a (miner; 3d4ec451 rebased onto the 0.3.11 fork tip 89dfcb95 in round 3) and branch `ledger-fork` (workers), suites PC 2 jobs `build-20261005-200049` (kaspa-consensus 95 passed, 0 failed, 3 ignored) and `build-20261005-200606` (kaspa-consensus-core 101/0, kaspa-mining 52/0, igneum-exec 13/0, igneum-miner 17/0, kaspa-p2p-flows 32 passed 1 failed: the new clock-skew test's own arithmetic, corrected in bd1b676a and 33/0 on the Mac), both on 815c7d64; the tip is fbb0082a. Was: Open, minor (4 October 2026). The writer is the local miner and the directory is the user's own, so no privilege boundary is crossed. Sweep (5 October 2026): no kernel hash in `program.json` on any branch (`git grep -i 'kernel_hash|program_hash'` on `miner-reliability` finds nothing); the tampered-pack test needs a GPU worker. Fix row in section 2.5. Answer: Correct. `packfile.h:~262-283, 306-345`; `worker.cpp:414-416, 596-620`; `emu/test.sh:57-66`. The CPU re-check (`main.rs:1250-1256`) stops a wrong program from earning, not from running. Fix: a hash of the emitted kernel in `program.json`, derived from the seed by the miner and checked by both workers; one sentence in the docs that the chain commits to the seed, not the text. Review id R4.2.4. Evidence: the files above. Experiment: a tampered pack with matching vectors must be refused. +Fix (5 October 2026, night). The miner stamps `program.json` with `kernel_sha256`, the SHA-256 of every kernel file it emitted from the seed (`kernel.cu`, `kernel_bound.cu`, `kernel.cl`, `kernel_bound.cl`, `program.h`, `memhard.h`), on `export-pack` and on every `prepare` pack (`stamp_kernel_hashes`, fork commit 3d4ec451). Both workers check the text before anything compiles: `proto-cuda/nvrtc/packfile.h` `pf_check_kernel_hashes` (a SHA-256 in C, checked against python's on three vectors) runs inside `pf_load`, so the NVRTC worker's `--pack`, `--check` and `prepare` paths and the OpenCL worker's `--pack` start refuse a pack whose files do not hash to the stamp, or that carries no stamp; the OpenCL `prepare` path now calls `pf_load` and fails the prepare with the reason (before it only skipped the self-test). One sentence in `proto-cuda/README.md`: the chain commits to the seed, not to the text. Tests: the miner's `tampered_kernel_text_is_refused_by_the_stamp` (stamp, verify, re-stamp is idempotent, one constant edited in `kernel_bound.cu` is refused with the file named, a pack without the stamp is refused); the NVRTC worker's CPU emulation test (`proto-cuda/nvrtc/emu/test.sh`, Mac, 5 October 2026, 19:50 UTC) stamps packs A and B as the miner does and adds pack T, pack A with a line appended to `kernel_bound.cu` after the stamp: pack A `check PASS` as before, pack T refused with `kernel_bound.cu does not hash to the value the miner derived from the seed` and no `source check PASS` line (the text never reached the compiler), the serve round unchanged (`PASS: ready + prepare 1; 64 + 64 + 32 found on pack A, prepared B ... 32 found on B`, 15 sampled hashes equal to `igneum-pow hash-bound`). Owed: the same tampered pack against the real worker on PC 2's RTX 5090 (the `build` job tooling compiles crates and runs cargo suites, it does not run a script on the PC); the vectors still match on pack T by construction, so the only thing the GPU run adds is that the real NVRTC path shares `pf_load`, which it does by inclusion. A pack from `igneum-pow export` (the CLI, not the miner) carries no stamp and is refused by the one-click workers until it is stamped; the emu test shows the stamping. + +Closer's note (5 October 2026, 23:10 UTC): the worker half of this fix (`proto-cuda/nvrtc/packfile.h`, `proto-opencl/host.c`, on `fud-close`) refuses any pack whose `program.json` carries no `kernel_sha256`, and only the miner commit on the fork branch `ledger-fixes` (3d4ec451) stamps it. The two halves ship in the same cut or the worker half is held back; the 0.3.11 cut closed at 23bc2b2 without either, so `fud-close` heads the next cut with `ledger-fixes` rebased onto the 0.3.11 fork tip 89dfcb95 (two conflicting files, `igneum/miner/src/main.rs` and `protocol/flows/src/ibd/proof.rs`, rebase owed). + +Round 3 (6 October 2026, night): the fork branches `ledger-fixes` (bd1b676a) and `ledger-fixes-2` (b1e98b79) merged onto the 0.3.11 fork tip 89dfcb95 as `ledger-fixes-0311` (merge 99ea7d97, fallout 7d4c8b3c, P23 fbb0082a, the tip), built on the Mac against `igneum-pow` as release-0.3.11 ships it (the fork resolves `../../../../igneum-pow` from the checkout it sits under; `ledger-rebase` carries that crate at 42be745 and the fork worktree moved under it). The rebase moved the stamp to where 0.3.11 writes every pack: `stamp_kernel_hashes` runs inside `write_pack_checked` (after the kernel files and `seeds.txt`, before the pack is read back and checked against the seeds), and `verify_kernel_hashes` reads the stamp back after that check, so the prepare path, the rebuild after a refused pack and `export-pack` all leave `kernel_sha256` in `program.json`; `export-pack` prints `stamped .../program.json with kernel_sha256 over 6 files`. End to end on the rebased miner: `igneum-miner export-pack grpc://127.0.0.1:30010 ` against node 0 of the round-3 fast-time network (epoch 0, day 1,243,919, class v2, generator 2, attempt 0, `checked`) wrote 6 stamped files; `proto-cuda/nvrtc/emu/test.sh ` on the Mac (build slot, 59 s), with the test now keeping a miner-written stamp instead of re-stamping (ledger-rebase 67990d0): pack A `check PASS` with the miner's own stamp (2 `source check PASS` lines, self-test PASS, 96 of 96 vector lanes), pack T (one line appended to `kernel_bound.cu` after the stamp) refused with `kernel_bound.cu does not hash to the value the miner derived from the seed` and no `source check PASS` line, the serve round PASS (64 + 64 + 32 found on A, prepared B, 32 found on B, job 5 refused), 15 sampled hashes equal to `igneum-pow hash-bound`. So the fud-close worker half accepts a pack from the 0.3.11 miner and refuses the tampered one. Suites on the rebased fork, the Mac run (`cargo test --release -j 4` under the build lock, labelled a Mac run: PC 2 was queued behind the Counter ASIC 2.0 chain and no go came inside 30 minutes; the PC 2 slot for the same job still stands with the coordinator): PC 2 job `build-20261006-012543` (published by the Counter ASIC 2.0 coordinator at 01:25:43Z, done 01:32:33Z, every stage ok): fork fbb0082a built for Linux (igneumd 49,245,928 bytes, igneum-miner 9,905,848) and Windows (igneumd.exe 51,380,736, igneum-miner.exe 11,044,864), the seven suites exit 0 in 46 s, but without `--features igneum-pow` (build-job.mjs passes none), so the PC run is the no-feature evidence and the Mac run with the feature is the suite evidence; the feature flag for build-job is on the 0.3.12 list. kaspa-consensus 99 passed, 1 failed, 4 ignored (the failure is 0.3.11's own `igneum_m20_tests::witnesses_are_checked_in_epoch_order_under_their_own_seeds`, the era-0 stand-in of `pruning_proof/igneum_pow.rs:114` against `EpochSeeds::v2`'s zero era, both from 89dfcb95, neither file touched on the ledger branches; owned by the Counter ASIC 2.0 coordinator), kaspa-consensus-core 108 passed, 0 failed, 2 ignored (db_compat 7 of 7), kaspa-mining 52 of 52, kaspa-p2p-flows 36 of 36, kaspa-pow 14 of 14, kaspad 2 of 2, igneum-exec 23 of 23, igneum-miner 20 of 20. Owed, unchanged: the tampered pack against the real worker on PC 2's RTX 5090; the PC 2 run of these suites. Coupling for the closer: the cut that carries fud-close needs `igneum-pow` at release-0.3.11 and the fast-time file of 2bbc12f (X19). + ### X21. A wrong program burns power with a green rate "The CPU re-check counts mismatches and does nothing: no threshold, no stop. The app reads `hash`, `now`, `template_age` and `synced` from STATUS and nothing else, so `mismatched=` and `WORKER FAULT` never reach the card." @@ -1916,21 +2022,27 @@ Evidence: the files above. Experiment: one constant edited in `kernel_bound.cu` ### X22. Worker restart paths, minor "Two miners truncate the same `packs\devnet` while workers read it; every restart begins on the stale first pack; the restart loop has no cap; the 60 s stall guard wraps the self-heal build; a node can crash the miner through an `expect`; a worker without prepare support loops on export during IBD." -Status: Open, minor (4 October 2026). Sweep (5 October 2026): two of the six fixed on `miner-reliability` (`501363e0`: a dead worker's stdin no longer spins the fill loop; `945153ab`: a silent worker still runs the guards and STATUS); the shared `packs\devnet` truncation, the stale first pack, the `expect` crash and the IBD export loop remain; restart timing needs the PCs. +Status: Fixed on a branch, pending merge (5 October 2026, night): fork branch `ledger-fixes-0311` fbb0082a (miner; 3d4ec451 rebased onto the 0.3.11 fork tip 89dfcb95 in round 3) and branch `ledger-fork` (app), suites PC 2 jobs `build-20261005-200049` (kaspa-consensus 95 passed, 0 failed, 3 ignored) and `build-20261005-200606` (kaspa-consensus-core 101/0, kaspa-mining 52/0, igneum-exec 13/0, igneum-miner 17/0, kaspa-p2p-flows 32 passed 1 failed: the new clock-skew test's own arithmetic, corrected in bd1b676a and 33/0 on the Mac), both on 815c7d64; the tip is fbb0082a. Was: Open, minor (4 October 2026). Sweep (5 October 2026): two of the six fixed on `miner-reliability` (`501363e0`: a dead worker's stdin no longer spins the fill loop; `945153ab`: a silent worker still runs the guards and STATUS); the shared `packs\devnet` truncation, the stale first pack, the `expect` crash and the IBD export loop remain; restart timing needs the PCs. Answer: Correct on each: `engine.rs:~2047-2055` and `emit.rs:1156-1163`; `main.rs:1206-1228`; `worker.cpp:684-703`; `main.rs:~581, 893`; `main.rs:1373-1380` with `engine.rs:~1405-1411` (the 14:20 export during IBD, bench-log). Each costs a restart, none loses the run. Review ids R4.2.5 to R4.2.10. Evidence: the files above. Experiment: time from worker restart to first accepted job on both PCs. +Fix (5 October 2026, night), the four remaining paths. (1) The shared `packs\devnet` truncation: the app exports one pack directory per card, `packs\devnet-` (`pack_dir_name`, `export_pack`, `build_worker_from_source`, `miner_args` in `app/igneum-app/src/engine.rs`), so an export for one card never truncates what another card's worker is reading; app test `pack_directories_are_per_card` (passed on the Mac, 1 of 1). (2) The stale first pack: a restarted worker is spawned with `--pack` pointing at the pack of the CURRENT seeds under `--prepare-packs` when the miner wrote one (`worker_args_with_pack`, `pack_dir_for`), not at the launcher's first pack, which cost a build of the old program and then a foreground self-heal build of the current one; unit test `restart_worker_args_take_the_current_pack`. (3) The `expect` crash: `template()` skips a template whose block does not convert and the legacy seed walk returns `None` on any RPC error or missing verbose data (the three call paths skip the template, the two one-shot commands exit with a message); no `expect` on the node's answers remains in the mining loops (the ones left are on the user's own address and on process start). (4) The IBD export loop: a worker without prepare support no longer makes the miner exit 42 on a seed change while the template is not synced (the change is printed once, `last_seeds` keeps the worker's pair, so the first change after the sync completes still exits 42 once); the app waits 60 s before restarting a miner that exited 42 while the node is not synced. Fork commit 3d4ec451 (miner), branch `ledger-fork` (app). The restart timing on both PCs is still owed (hardware). + +Round 3 (6 October 2026, night): the fork branches `ledger-fixes` (bd1b676a) and `ledger-fixes-2` (b1e98b79) merged onto the 0.3.11 fork tip 89dfcb95 as `ledger-fixes-0311` (merge 99ea7d97, fallout 7d4c8b3c, P23 fbb0082a, the tip), built on the Mac against `igneum-pow` as release-0.3.11 ships it (the fork resolves `../../../../igneum-pow` from the checkout it sits under; `ledger-rebase` carries that crate at 42be745 and the fork worktree moved under it). `igneum/miner/src/main.rs` conflicted in seven hunks; 89dfcb95's structure was kept (`EpochSeeds` with `class` and `era`, `seeds_from_info`, `write_pack_checked`) and path (3), the `expect` crash, was reconciled by reading both sides: 89dfcb95's `seeds_for` still panics on `getBlockDagInfo` (`expect("dag info")`) and its `template_seeds` returns a value; the ledger side returns `None` on an RPC error or a block without verbose data, and the three mining loops and the two one-shot commands already skip the template or exit with a message on `None` (callers outside the conflict). The path that cannot panic on a node answer is the `Option` one, so `template_seeds` returns `Option` and wraps `seeds_from_info`, `seeds_for` fills 89dfcb95's `class` (from `program_class_for_epoch`) and `era` (the genesis stand-in) in both returns, and `mine_cpu_legacy` skips the template on `None` (merge 99ea7d97, the choice in its message). Paths (1), (2) and (4) merged without conflict; the restart test's seed gained class v2 and a zero era (7d4c8b3c, test code). Suites on the rebased fork, the Mac run (`cargo test --release -j 4` under the build lock, labelled a Mac run: PC 2 was queued behind the Counter ASIC 2.0 chain and no go came inside 30 minutes; the PC 2 slot for the same job still stands with the coordinator): PC 2 job `build-20261006-012543` (published by the Counter ASIC 2.0 coordinator at 01:25:43Z, done 01:32:33Z, every stage ok): fork fbb0082a built for Linux (igneumd 49,245,928 bytes, igneum-miner 9,905,848) and Windows (igneumd.exe 51,380,736, igneum-miner.exe 11,044,864), the seven suites exit 0 in 46 s, but without `--features igneum-pow` (build-job.mjs passes none), so the PC run is the no-feature evidence and the Mac run with the feature is the suite evidence; the feature flag for build-job is on the 0.3.12 list. kaspa-consensus 99 passed, 1 failed, 4 ignored (the failure is 0.3.11's own `igneum_m20_tests::witnesses_are_checked_in_epoch_order_under_their_own_seeds`, the era-0 stand-in of `pruning_proof/igneum_pow.rs:114` against `EpochSeeds::v2`'s zero era, both from 89dfcb95, neither file touched on the ledger branches; owned by the Counter ASIC 2.0 coordinator), kaspa-consensus-core 108 passed, 0 failed, 2 ignored (db_compat 7 of 7), kaspa-mining 52 of 52, kaspa-p2p-flows 36 of 36, kaspa-pow 14 of 14, kaspad 2 of 2, igneum-exec 23 of 23, igneum-miner 20 of 20. The restart timing on both PCs is still owed (hardware). + ### E16. The 20% pool is burned on the live chain, and the text says it pays provers "Your coinbase sends the 20% to an OP_RETURN tagged `igneum-proving-pool-v0`. Your own comment says provably burned. Your cap test counts it as supply. Your litepaper says, present tense, that it pays a standing prover population." -Status: Open (code half: the single coinbase payout, group D); text half stated (5 October 2026, night): `site/litepaper.html`, Economics, emission table 20% row, "the coinbase's 20% output goes to an unspendable script tagged igneum-proving-pool-v0 and is burned there. Provers are paid from a separate escrow in the execution state, credited by rule with the same 20% of each blue block's subsidy" (from the fork at `release-0.3.6` a24ab01a: `consensus/core/src/igneum.rs:86-98`, `consensus/src/processes/coinbase.rs:113`, `igneum/exec/src/executor.rs:160-176` `PROVING_POOL_ADDRESS`, `igneum/exec/src/proving.rs` `carried_payouts`); the same sentence under the bar on `site/index.html`. Was: Open (4 October 2026). Sweep (5 October 2026): confirmed in code: `devnet-v4` `consensus/core/src/igneum.rs:93` burns the 20% under the tag `igneum-proving-pool-v0`; the `proving` branch pays `proving_pool_credit` from shard records (`igneum/exec/src/proving.rs:304`) and is not on the devnet. The live-block test needs the proving branch rolled out; the text belongs to the testnet-prep branch. +Status: Answered with evidence and stated (5 October 2026, night). Code half (5 October 2026, night, ledger close round 1: the 20% is burned on the UTXO ledger and paid on the EVM ledger from an escrow the executor credits by rule with the same 20%; one live block shows both; bench-log "5 October 2026 (night), ledger close round 1: X14 concentration in hashing, signing, proving and aggregation from the Mac node's RPCs, and E16 one live block"). Text half stated (5 October 2026, night): `site/litepaper.html`, Economics, emission table 20% row, "the coinbase's 20% output goes to an unspendable script tagged igneum-proving-pool-v0 and is burned there. Provers are paid from a separate escrow in the execution state, credited by rule with the same 20% of each blue block's subsidy" (from the fork at `release-0.3.6` a24ab01a: `consensus/core/src/igneum.rs:86-98`, `consensus/src/processes/coinbase.rs:113`, `igneum/exec/src/executor.rs:160-176` `PROVING_POOL_ADDRESS`, `igneum/exec/src/proving.rs` `carried_payouts`); the same sentence under the bar on `site/index.html`. Was: Open (4 October 2026). Sweep (5 October 2026): confirmed in code: `devnet-v4` `consensus/core/src/igneum.rs:93` burns the 20% under the tag `igneum-proving-pool-v0`; the `proving` branch pays `proving_pool_credit` from shard records (`igneum/exec/src/proving.rs:304`) and is not on the devnet. The live-block test needs the proving branch rolled out; the text belongs to the testnet-prep branch. Answer: Correct for the live devnet-v4 line. `coinbase.rs:112-113`; `consensus/core/src/igneum.rs:86-98, 329-333`; evidence row 21. Proving v0 on the `proving` branch carries payouts in the shard statement (P21, P22) and the live chain does not run it. Until it does, a prover earns 0 from the pool and the spendable cap is 3.2 billion. Fix: one sentence in the litepaper Economics table (`site/litepaper.html:396, 414`) and under the homepage bar (`site/index.html:306, 446-448`): burned until the payout ships, no prover paid today; a burned-so-far figure on the live page; a decision on whether the payout reclaims the burned share or pays from new emission. Review ids R4.7.1, R4.7.2. Evidence: the files above; `docs/review/round-4-2026-10-04.md` section 7. Experiment: one live devnet block whose pool output reaches a named prover key. +Run (5 October 2026, night, code half): on release-0.3.6 (`vendor/igneum-node-036` at `a24ab01a`, the binary every live node runs) `consensus/core/src/igneum.rs:79-101` still splits the subsidy 80/20 (`proving_pool_share` at 79, `producer_share` at 84) and builds the 20% output as OP_RETURN `igneum-proving-pool-v0` (`proving_pool_script_public_key` at 91, comment at lines 88-90: "provably burned on devnet v0"); the coinbase builder (`consensus/src/processes/coinbase.rs`) emits it in every block. The execution layer applies the subsidy a second time as a state transition (`igneum/exec/src/executor.rs:160-176`): for every blue block of the segment, 80% in wei to the block's miner address and 20% to `PROVING_POOL_ADDRESS` (0x...0220, `igneum/exec/src/config.rs:50`), summed into the segment's `proving_pool_credit`; `igneum/exec/src/proving.rs:306` reads that credit when a carried record is checked, and `carried_payouts` (`proving.rs:323-346`) pays the first valid record per (segment, shard) its share of that credit from the escrow to the record's payout address once `cfg.active_at` holds (activation DAA 84,100 on the live devnet, `igneum_getProvingStatus`). So the credit is funded by new issuance on the EVM ledger, not by the coinbase: the UTXO 20% is burned and the EVM 20% is minted into the escrow and paid out. Live block (read-only, 19:12 UTC): chain block 81,217 carries a valid record for block 81,197 shard 0 paid 2.726179 IGN to 0xcafc6e74... from the escrow (its own segment credit 1.818 IGN), while the same block's coinbase has outputs 363,523,103 and 363,522,223 sompi to the two producers and 181,761,330 sompi to `6a16 igneum-proving-pool-v0`, exactly 20% of both subsidies rounded down. Truth for the ledger: on the live chain the coinbase's 20% is still burned under the tag; provers are paid, 519 shards and 639.458 IGN so far, from the EVM escrow the executor credits with the same 20% in wei; a cap test that counts the UTXO burn as supply or the EVM credit as a transfer from the coinbase is wrong on one ledger or the other. Bench-log heading: "5 October 2026 (night), ledger close round 1: X14 concentration in hashing, signing, proving and aggregation from the Mac node's RPCs, and E16 one live block". + ### L9. "100% to miners and provers", "0% anyone else", and no word that devnet coins have no value "The homepage says 100% to miners and provers and 0% to anyone else, beside a 1% client dev fee disclosed only in the litepaper. Nowhere on the site does it say the devnet's coins have no value or that the chain may be reset, and the Get the miner button is live." @@ -1978,12 +2090,16 @@ Evidence: session scratchpad `rt/logs/exec_b/miner_node1.log` (the template erro ### E17. Unlogged inputs behind the economics, minor "The cap's 110 MH/s and its draw are not in the bench-log; the Mac's draw is not logged; the economy sim's one measured input is a 229 MH/s card against today's 124; mining-versus-pool flips from 4.9x for mining on today's devnet to 930x for proving at 10,000 cards and no document says it depends on fleet size; the app-share text omits '100,000-gas calls' and the open base unit; emission ran at up to 2x schedule; shard-scale prover cost is unmeasured on any GPU; the iGPU default off is right." -Status: Open, minor (the draw lines need the machines); text half stated (5 October 2026, night): `site/litepaper.html`, Building, Why build here, "a million 100,000-gas calls a day at a 1 gwei tip pays about 7,300 IGN a year, with 1 gwei taken as a billionth of an IGN (the base unit is Open)"; For miners, "Which of the two in-chain streams pays more per GPU-second depends on the size of the fleet" with the 4.9x and 930x arithmetic marked approximate. Was: Open, minor; the simulator half re-run (5 October 2026 sweep). `sim/economy/sim.py` with the 5090 class at 124 MH/s (the devnet's measured rate) in place of 229, scenarios a and b, 2 seeds, 111 s: baseline profit USD 5.59 per 5090 card-day (6.37 at 229), 3090 2.73 (1.66), 3060 1.34 (0.78), small 0.74 (0.39); under the b shock 4.52 / 2.25 / 1.46 / 0.30; no backlog, every block proven within 60 s, hash trough 75% of pre-event under b (82% at 229), 5% of cards off (10%), oscillation flag in 1 of 2 seeds. The direction is as the review said: a slower flagship card shifts income toward the smaller classes and makes the fleet more sensitive to the price shock. The draw lines (`nvidia-smi` on both PCs, `powermetrics` on the Mac) need the machines (person). Was: Open, minor (4 October 2026). +Status: Answered with evidence for PC 2 (6 October 2026, night, ledger close round 2, bench-log "ledger close round 2: M16", the E17 columns): RTX 5090 honest 132.2 Mhash/s at 326.6 W median, 3,060 MHz, 50 to 54 C, 100% utilisation (0.40 Mhash/J); 346.9 W at 8 warps per block; the inline settings 415.7 W and 431.0 W (the power limit). Open, minor: the PC 1 line (the 9070 XT and the 5090 under the app's own cap) and the Mac's `powermetrics` line (sudo) are owed. Was: Open, minor: the PC 2 draw lines are in the queued M16 job. Was: Open, minor (the draw lines need the machines); text half stated (5 October 2026, night): `site/litepaper.html`, Building, Why build here, "a million 100,000-gas calls a day at a 1 gwei tip pays about 7,300 IGN a year, with 1 gwei taken as a billionth of an IGN (the base unit is Open)"; For miners, "Which of the two in-chain streams pays more per GPU-second depends on the size of the fleet" with the 4.9x and 930x arithmetic marked approximate. Was: Open, minor; the simulator half re-run (5 October 2026 sweep). `sim/economy/sim.py` with the 5090 class at 124 MH/s (the devnet's measured rate) in place of 229, scenarios a and b, 2 seeds, 111 s: baseline profit USD 5.59 per 5090 card-day (6.37 at 229), 3090 2.73 (1.66), 3060 1.34 (0.78), small 0.74 (0.39); under the b shock 4.52 / 2.25 / 1.46 / 0.30; no backlog, every block proven within 60 s, hash trough 75% of pre-event under b (82% at 229), 5% of cards off (10%), oscillation flag in 1 of 2 seeds. The direction is as the review said: a slower flagship card shifts income toward the smaller classes and makes the fleet more sensitive to the price shock. The draw lines (`nvidia-smi` on both PCs, `powermetrics` on the Mac) need the machines (person). Was: Open, minor (4 October 2026). Answer: Correct on each point; `docs/review/round-4-2026-10-04.md` section 7 holds the arithmetic. Fix: one `nvidia-smi` draw line per setting with the rate beside it on both PCs; one `powermetrics` line on the Mac; the sim rerun at 124 MH/s with the comparison stated as a function of fleet size; "a million 100,000-gas calls a day" in the litepaper. Review ids R4.7.7 to R4.7.13. Evidence: the files above. Experiment: the three draw lines. +Round 2 (6 October 2026, night): the draw line rides inside the M16 job on PC 2 (`proto-cuda/inline-bench/inline_bench.cpp`, a sampler thread running `nvidia-smi --query-gpu=power.draw,clocks.sm,temperature.gpu,utilization.gpu --format=csv,noheader` every 2 s during each timed window, every sample printed with the setting's name, the median of the first field in the row beside the hash rate; the playbook pauses the app's miners and switches the prover off first and prints the compute apps left on the card, so a shared-card run is labelled as such). The lines land here and in the bench-log when the job's RESULT lines are in. PC 1 is off limits tonight (the 0.3.10 and 0.3.11 rollout and its app outage), so its line is owed; the Mac's `powermetrics` line needs sudo and is owed to a person. + +The lines (PC 2, job `m16-inline-pc2-1`, 00:41 to 00:43 UTC, the card otherwise idle, 7 samples 2 s apart per window, `nvidia-smi --query-gpu=power.draw,clocks.sm,temperature.gpu,utilization.gpu`): honest 1 GiB at 1 warp per block 132.20 Mhash/s, 326.6 W median (325.9 to 328.5), 3,060 MHz, 50 to 54 C, 100%; honest at 8 warps 131.15 Mhash/s, 346.9 W, 3,037 MHz, 66 C; inline 256 MiB 11.26 Mhash/s, 415.7 W, 3,052 MHz; inline 64 MiB 33.88 Mhash/s, 431.0 W (the limit, clocks 2,835 MHz); inline 32 MiB 33.87, 431.0 W; idle before the run 66 W at 847 MHz and 5%. Consequence: the economics input for the 5090 class is 132 Mhash/s at 327 W for a version-2 program, 0.40 Mhash/J (the simulator's 229 Mhash/s row is a version-1 figure); the power cap at 431 W did not bind the honest kernel. The draw under the app's own cap and the 9070 XT line are PC 1's (owed); the Mac's line is a person's (sudo). + ### E18. The dev fee is a protocol fee with better PR "A 1% dev fee in the official miner is 1% of the chain's hashrate paid to one company for as long as miners run it. Call it what it is: a founder allocation, hidden in the client, and nobody can tell how often it really fires." @@ -1996,12 +2112,15 @@ Evidence: `docs/design/miner-dev-fee.md`; the unit tests in `igneum/miner/src/ma ### X29. Host and file hygiene, minor "The Mac's live node binds its gRPC to every interface. Four secrets or pointers in `~/.config/igneum` are world-readable, one token is a filename, and the intake key rides on `curl`'s command line. The manifest answers CORS `*` and the clock source is a cacheable page's Date header." -Status: Open, minor (4 October 2026). Sweep (5 October 2026): read-only checks on this Mac: every secret under `~/.config/igneum` is now mode 600 (only `ota-signing-key.pub` is world-readable, as it should be), so that half is fixed; the live node still listens on every interface (`lsof`: `igneumd` on `*:26610`). The `curl` command line and the clock source were not re-checked. +Status: Decided (6 October 2026, 17:25 UTC, by the owner; decisions item 9): node 1 binds its RPC to localhost at its next planned restart, and the wallet's node too; PC 2 on its own node or a tunnel. Was: Fixed on a branch, pending merge (5 October 2026, night), the curl part: ledger-relay 28c028b, tests 47 of 47 (relay, 6 suites) + 16 of 16 (packaging/windows/test-inputs-signing.sh) + 2 CI class checks. Open: the live node's `--rpclisten` (decision, operator, group E) and the app's clock source (round 2). Was: Open, minor (4 October 2026). Sweep (5 October 2026): read-only checks on this Mac: every secret under `~/.config/igneum` is now mode 600 (only `ota-signing-key.pub` is world-readable, as it should be), so that half is fixed; the live node still listens on every interface (`lsof`: `igneumd` on `*:26610`). The `curl` command line and the clock source were not re-checked. +Decision owner: the project lead, decided 6 October 2026 (`docs/plans/ledger-decisions.md`, outcomes section). Answer: Correct. `--rpclisten=0.0.0.0:26610` on pid 33114 (no `--unsafe-rpc`, `--disable-upnp`); `ls -la ~/.config/igneum`; `app/igneum-app/src/update.rs` (`https_time`, `upload_log`); the dl host's headers. Vercel rewrote `Date` to now on a cache hit today, so the cached-Date failure did not show. Fix: RPC on loopback with PC 2 on a tunnel or its own node; `chmod 600`; the stray file removed; the key passed to `curl` through `-K` or a header file; an uncacheable path for the clock source. Review ids R4.5.5 to R4.5.7. Evidence: `lsof`, `ls`, `curl -I`. +Fix (5 October 2026, night), the curl part: `infra/gpu-bench/upload.sh` writes `header = "x-igneum-key: ..."` to a 0600 temporary config and calls `curl -K`; `proto-cuda/windows-app/upload-log.bat` and `proto-cuda/windows-miner/upload-log.bat` do the same with a `%TEMP%` config deleted with the body; `relay/clients/agent.sh` and `send.sh` keep every secret header in a 0600 `headers.cfg` and use `-K`; `prove-block.sh` and `prove-shard.sh` already send the key from inside python's `urllib` (no command line). The class check: `tools/ci/curl-header-check.sh` (self-test first) fails CI on any `.sh`, `.bat`, `.cmd` or `.ps1` line that passes `x-igneum-key`, `x-relay-token` or `x-machine-secret` as a curl `-H` argument; tonight's tree: 0 hits. Not in this branch: the app's own `curl` calls still put the key on the command line (`app/igneum-app/src/update.rs:91`, `jobrun.rs` `relay_upload`); that is app code, owed to the app's next cut, named here so it is not lost. The mode half was fixed on 5 October (every secret 600); the `--rpclisten` half is the project lead's; the clock source is a round 2 candidate. + ### X30. The live page and the bench page exposed operational detail "The engineering log page rendered the bench log with private strings; `/api/live` returned peer addresses, full key hashes and payout addresses; the mobile menu did not open." @@ -2030,3 +2149,65 @@ Evidence: the commits above. Experiment: `curl https://igneum.network/api/live` - **Open with new evidence and a fix row (fud-fixes section 2.5):** M20 (the stub is still in the pruning-proof path on `devnet-v4`; it goes live the moment the devnet passes its pruning depth), M21 (the k table from the fork's own function), M28, X20, P15, X29 (half fixed: file modes), X14 (hashing concentration measured), M25 (confirmed live in the sweep: a mismatched day length is rejected as `BlockInvalid` with no reason named, 0 of 4 against 7 of 7), M14 and F14 (no amplification in the chain model under rule v2 or Kaspa's rule, nor on the finality-fixes node under fast time, s5 ratio 0.864; the finality-with-DAA run still owed). - **Open, needs hardware, a person or the devnet:** M1, M11 (a rig), M16 (the 5090), M22, X19 (the node line; `faketime`), X23 to X28 (the relay owner and PC 1; the token is rotated, the run-task binding is not), E13, E14, E16, E17 (the draw lines), F16, F20 (the devnet test), C4 (module off), P3, P14, P16, P17, P21, P22, X13, X15, X17, G10, L1 to L5, L8, D5, D6. - **Nothing became worse.** Two things are closer than they look: M20 becomes a live failure for every fresh node once the devnet's pruning point leaves genesis, which at the devnet's 1.05 DAA/s (DAA 33,000 at 17:37 UTC on 4 October) is between DAA 108,000 (`PRUNING_DURATION`, about 14:00 UTC on 5 October) and DAA 151,200 (the first finality point a full pruning depth below the tip, about 01:00 UTC on 6 October), approximate; X23's operational half (a run task on the PCs needs only the relay token) is unchanged after the rotation. + +### P23. An unwound transaction leaves the node's view until its sender resends it +"Your pool learns about chain blocks (`on_chain_block`) and about nothing else. A selected-chain reorg unwinds a transaction out of the executed set and the pool never gets it back. The RPC can say `reorged out` all it likes; the transaction is gone unless the wallet resends, and most wallets do not." + +Status: Fixed on a branch, pending merge (6 October 2026, night, ledger close round 3): fork `ledger-fixes-0311` fbb0082a (the P23 commit, on the merge of `ledger-fixes` and `ledger-fixes-2` onto the 0.3.11 fork tip 89dfcb95); `EvmPool::on_chain_removed` (igneum/exec/src/pool.rs) and `ExecService::requeue_unwound` (service.rs) with `ExecState::unwound` collected by `truncate_to`; unit tests `pool::tests::a_reorg_hands_the_unwound_transactions_back_to_the_pool_in_nonce_order` and `rpc::p17_tests::a_reorg_collects_the_unwound_transactions_in_chain_order_for_the_pool`, igneum-exec 23 of 23 on the Mac (labelled a Mac run); the O-7.2 conformance run on the rebased binaries PASSED (409.9 s) with the `reorged out` case ending in `executed` 2.4 s later without a resend (n2's log: `reorg: 1 unwound transactions handed back to the pool as pending, 0 refused`; bench-log "ledger close round 3"); PC 2 job `build-20261006-012543` built fbb0082a for Linux and Windows and ran the seven suites, exit 0 in 46 s, without the igneum-pow feature, so the Mac run is the suite evidence. Was: Open, found in round 2 (6 October 2026, night, the P17 conformance run on `ledger-fixes-2`); fix named, owner the execution engineer; round 3 (`ledger-rebase`) carries it with the fork rebase. Found by: the ledger-pc2 agent's O-7.2 conformance driver (`tools/p17-conformance/run.mjs`, the "reorged out" path), recorded as finding (1) in the P17 round-2 paragraph. + +Answer: Correct. `igneum/exec/src/pool.rs` has `on_chain_block` and no reorg hook, so a transaction unwound by a selected-chain reorg is neither re-queued nor re-executed; the new `state` word reports `reorged out` with `reorgedFrom`, which tells a wallet to resend and tells nobody else. Fix: on every `virtualChainChanged` removal the executor hands the unwound transactions back to the pool as pending (nonce order kept, the same validity checks as a fresh submission, the 10,000-hash memory of P17 cleared on re-inclusion); a unit test that unwinds a block and sees its transactions re-queued; the conformance driver's `reorged out` case then ends in `executed` again without a resend. + +Evidence: `igneum/exec/src/pool.rs` (`on_chain_block`), `docs/bench-log.md` "ledger close round 2: P17 conformance", the P17 paragraph above. Fix row: `docs/fud-fixes.md` section 2.7. + +## Count by status, 5 October 2026 (night, round 1 of the ledger close merged into `fud-close`) + +The earlier count table above is kept as history (it counts the 80 entries of version 0.1). This count reads the first Status line of every entry and buckets it by its leading words; a status that carries two halves is counted by its first words. + +| Bucket | Count | Entries | +|---|---|---| +| Fixed, rolled out, or rule written | 54 | M5 M6 F1 M15 M17 M19 M20 F15 F17 F18 P11 P12 P13 P14 P15 E9 E10 E11 L7 G9 G10 X12 F22 X16 P18 P19 P20 M23 M24 X23 X24 X25 X26 X27 X28 G12 G13 G14 X18 F23 F24 F25 X19 X20 M25 M26 M27 M28 X21 X22 M30 M31 X29 X30 | +| Conceded, stated, or terminal (no experiment possible, contained by rule) | 52 | M2 M4 M7 M9 M13 F5 F6 F8 F10 P1 P2 P4 P6 P7 P10 E1 E5 E6 E8 G1 G2 G4 G5 G6 G8 C2 C3 C5 C6 C7 C8 C10 C11 X1 X2 X3 X4 X7 X8 X9 X10 M18 C13 L8 E13 D1 D2 D3 D4 D6 L9 M29 | +| Answered by design or with evidence | 27 | M3 M8 M10 M11 M12 F4 F7 F9 F11 F12 F13 P9 E2 E3 C1 C12 L6 M14 M21 F14 F19 F20 P17 E12 X14 E16 E18 | +| Decided or closed by rule | 12 | F2 F3 P5 P8 E4 E7 G3 G7 C9 X6 E15 G11 | +| Open, decision owner the project lead (`docs/plans/ledger-decisions.md`) | 11 | M1 M22 F16 E14 X13 L1 L2 L4 L5 P21 X5 | +| Open, blocked on hardware, a customer or a later phase | 6 | P3 (wrapper, phase 2) M16 (PC 2 job, round 2) P16 (a 12 GB card) X15 (public testnet) P22 (phase 2) X17 (design, round 2) | +| Conceded, scheduled or mitigation in progress | 2 | L3 D5 | +| Open, minor | 1 | E17 (the draw lines) | +| Another agent's tonight | 1 | C4 | + +Total 166. + +## Count by status, 6 October 2026 (00:10 UTC, rounds 1 and 2 of the ledger close merged into `fud-close`) + +Same rule as the count above. 167 entries (P23 added by round 2). + +| Bucket | Count | Entries | +|---|---|---| +| Fixed, rolled out, rule written, or designed | 56 | the 54 of the count above plus P17 (four-state RPC on `ledger-fixes-2`) and X17 (spec 8.8, phone-app 4.1) | +| Conceded, stated, or terminal | 52 | unchanged; D6 now carries its review (`docs/review/d6-forged-job-result-2026-10-05.md`) and D5 its owner and gate | +| Answered by design or with evidence | 26 | the 27 above less P17, with X14 now answered for all four concentrations | +| Decided or closed by rule | 12 | unchanged; F3 and F17 carry the spec 3.4.2 proposals for gate 3 | +| Open, decision owner the project lead (`docs/plans/ledger-decisions.md`, items 1 to 13) | 11 | M1 M22 F16 E14 X13 L1 L2 L4 L5 P21 X5 | +| Open, blocked on hardware, a customer or a later phase, blocker and next date in the Status line | 5 | P3 (phase 2 wrapper) P16 (a 12 GB card) X15 (public testnet) P22 (phase 2 consensus proof) M16 (the kernel is written and bit-exact on the Mac; the PC 2 run is queued behind the 0.3.11 rollout) | +| Conceded, scheduled or mitigation in progress | 2 | L3 D5 | +| Open, minor | 1 | E17 (the draw lines ride in the queued M16 job) | +| Open, found tonight, fix in round 3 | 1 | P23 | +| Another agent's tonight | 1 | C4 | + +## Count by status, 6 October 2026 (17:30 UTC, round 3 merged and the owner's decisions applied) + +Same rule as the counts above. 167 entries. + +| Bucket | Count | Entries | +|---|---|---| +| Fixed, rolled out, rule written, or designed | 57 | the 56 of the 00:10 count plus P23 (the pool reorg hook on `ledger-fixes-0311` fbb0082a); every fork item now sits on `ledger-fixes-0311`, rebased onto the 0.3.11 fork tip 89dfcb95 | +| Conceded, stated, or terminal | 52 | unchanged | +| Answered by design or with evidence | 28 | the 26 above plus M16 (the inline-cache kernel on PC 2's RTX 5090: inside the L2 at 64 MiB the recompute route runs at 0.256x of the honest rate, 5.1x worse per joule) and E17 (the 5090 draw lines: 132.2 Mhash/s at 326.6 W median, 0.40 Mhash/J) | +| Decided or closed by rule | 29 | the 12 above plus the owner's decisions of 6 October 2026, 17:25 UTC: M1 M22 F16 X5 E14 X13 L3 G14 X29 P9 P21 M8 M11 P16 F3 F17 (F3 and F17 already counted; X14 carries the decision line beside its Answered status) | +| Open, counsel engaged (in progress) | 4 | L1 L2 L4 L5 | +| Open, blocked on a later phase, blocker and next date in the Status line | 3 | P3 (phase 2 wrapper) X15 (public testnet) P22 (phase 2 consensus proof) | +| Conceded, scheduled | 1 | D5 | +| Another agent's | 1 | C4 | + +The bucket "Decided or closed by rule" counts each entry once: M8, M11 and P16 move there from Answered, so Answered is 28 less those three plus M16 and E17, as the table states; the sum of the rows is 167 with M8, M11, P16 and F3, F17 counted in Decided only. + diff --git a/site/404.html b/site/404.html index 076e9b21..0a71bd05 100644 --- a/site/404.html +++ b/site/404.html @@ -160,6 +160,7 @@ p{margin:0;color:var(--ink-2);max-width:52ch} Built on the shoulders Engineering log Evidence + Ledger: every criticism