2353 lines
456 KiB
Markdown
2353 lines
456 KiB
Markdown
# Igneum FUD ledger
|
|
|
|
Version 0.1, 3 October 2026. A living document. Published with the repository at the public testnet (decision of 5 October 2026).
|
|
|
|
## What this is
|
|
|
|
Every serious criticism or attack we expect against Igneum, written the way it will be posted, with the honest answer next to it. Where the answer is a measurement, the file that holds the measurement is named. Where the answer is a design rule, the rule is quoted. Where there is no answer yet, the entry says "Open" and names the experiment that will settle it and when. Where the critic is right, the entry says so.
|
|
|
|
The ledger exists because the only way a design survives public scrutiny is for every pick to have been answered in public before anyone else makes it. It is written against litepaper v0.1 and the design document as of 3 October 2026. Entries are never deleted. When the status of an entry changes, the old status stays in the history of this file.
|
|
|
|
Statuses used:
|
|
|
|
| Status | Meaning |
|
|
|---|---|
|
|
| Answered with evidence | A measurement, simulation or cited precedent exists and is named |
|
|
| Answered by design | A consensus rule or a design decision answers it; no measurement is needed or possible yet |
|
|
| Open, experiment scheduled | We do not know. The experiment and its date are named |
|
|
| Conceded | The critic is right. "Stated" means the litepaper already says so; "not yet stated" means the litepaper must change, and the fix is in the overclaims list at the end |
|
|
| Closed by rule, Decided, Closed by removal | A rule now in `docs/spec/`, a decision by the project lead, or a removal answers it as of the date given, and the spec section is named. The status it replaced is kept on the line |
|
|
|
|
Submitting a criticism: email hello@igneum.network (Igneum Labs LTD, Unit IH-00-01-01-OF-01, Level 01, Innovation One, Dubai International Financial Centre), or open an issue on the repository once it is public, at the public testnet. Anything that is not already in this ledger, or that shows an entry here is wrong, gets added with credit if wanted.
|
|
|
|
Evidence locations referenced below: `docs/bench-log.md`, `proto-metal/TESTS.md`, `sim/results.md`, `sim/finality_sim.py`, `proto-cuda/`, the design document section "Finality rule, version 2, after the second hostile review" (called "design doc, Finality v2" here), its "Security model" table, and its "What the hostile review changed" table.
|
|
|
|
---
|
|
|
|
## 1. Mining and ASIC claims
|
|
|
|
### 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: 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).
|
|
|
|
Answer: Correct that the arithmetic is simple on purpose. Integer only, because floating point rounds differently per vendor and would split the chain (design doc, hostile review table, row 2). The defence is not the ALU work. It is random 4-byte reads over a dataset larger than any on-chip cache: the RTX 5090 runs the same program 5.8x faster when the dataset fits in its 96 MiB L2 (1,352 Mhash/s at 64 MiB against 229 at 1 GiB, bench-log, RTX 5090 sweep). A chip has to buy the same gigabytes of memory and loses the same latency. The honest target for a chip's gain is under 2x and it is a target, not a measurement. The experiment that tests it is the standing bounty for any chip design beating a GPU by more than 2x, live with the public benchmark in January 2027 (design doc, decisions table, row 1). Until a bounty has gone unclaimed for years the claim is a target.
|
|
|
|
Evidence: `docs/bench-log.md` (RTX 5090 dataset sweep), `proto-metal/TESTS.md` section 8 "Not demonstrated" item 2. Bounty: not yet.
|
|
|
|
Cross-reference (external review, 3 October 2026, night): the bounty's scoring rules, eligible hardware, judge and funding are M22; "under 2x" is a hash-rate target and not the economic threshold.
|
|
|
|
### M2. Your own prototype is not memory-hard
|
|
"Your TESTS.md says computing the dataset inline runs 110x faster than loading it. You put the 228 Mhash/s number on the website anyway."
|
|
|
|
Status: Conceded, stated (5 October 2026, night): `site/litepaper.html`, Monero's idea section, the "Measured so far" paragraph, "computing items on the fly runs 4.8x slower than loading them"; What Igneum does not claim, "A memory-hard prototype on every vendor". Was: Conceded, not yet stated in the litepaper.
|
|
|
|
Answer: True. The prototype dataset is a six-operation closed form, and `--inline-dataset` measured 4,888 Mhash/s against 44.6 honest on the M5 Max, about 110x. The litepaper quotes the 228 and 45 Mhash/s figures without that caveat. The fix is the 256 MB RandomX-style cache with eight dependent reads per item (design doc, Finality v2, Lottery seeds item 3), which is the next thing to build. The number that matters afterwards is the shortcut ratio, which must fall to about 1. The litepaper must carry the caveat until then.
|
|
|
|
Evidence: `proto-metal/TESTS.md` section 7. Fix: overclaims list, item 23.
|
|
|
|
Sweep (5 October 2026, evening): stated. `site/litepaper.html`, vs RandomX section, the "Measured so far" paragraph: the first dataset was closed-form (inline shortcut 111x faster on the Mac), the 256 MB cache replaced it on 3 October 2026, with the cache computing items runs 4.8x slower than loading them (Measured, Apple), the honest rate is unchanged on both vendors, and the NVIDIA and discrete AMD ratio is marked Open. "What Igneum does not claim" carries the same as "A memory-hard prototype on every vendor". Overclaims 23 and the first item of 78 applied with the cache facts.
|
|
|
|
### M3. Kaspa said ASIC resistant too
|
|
"Every GPU coin promised this. IceRiver shipped a Kaspa chip in eighteen months. Why are you different?"
|
|
|
|
Status: Answered by design, with a correction to our own text.
|
|
|
|
Answer: First the correction: Kaspa did not promise ASIC resistance. kHeavyHash was designed to be friendly to specialised and optical hardware, and the Kaspa community expected chips (approximate, from memory; cite the Kaspa docs before quoting). Our litepaper's "Kaspa said ASIC resistant too" misstates them and will be reworded. What differs here: the program changes hourly and is compiled from a generator fixed at genesis, the dataset is derived daily and grows on a fixed schedule, and instruction families unlock by height from a genesis reserve. A chip that handles the whole program space is a GPU with the graphics parts removed. Precedent: RandomX has run on Monero since November 2019 with no chip publicly shipped (approximate).
|
|
|
|
Evidence: design doc, "ASIC resistance" section. Fix: overclaims list, items 11 and 49.
|
|
|
|
### M4. ProgPoW already did this and you do not mention it
|
|
"A GPU program whose random maths changes every few blocks shipped on Ravencoin as KAWPOW in 2020. Your 'first' table says the GPU version was 'designed, discussed, never shipped'. That is false."
|
|
|
|
Status: Conceded, stated (5 October 2026, night): `site/litepaper.html`, precedents table row 1, "ProgPoW, as KAWPOW on Ravencoin since 2020". Was: Conceded, not yet stated in the litepaper.
|
|
|
|
Answer: Correct. ProgPoW, and KAWPOW on Ravencoin since May 2020 (approximate), regenerate a random maths sequence per period on GPUs. The design doc cites ProgPoW's fixed-footprint rule; the litepaper's firsts table does not. What Igneum adds over ProgPoW: a full kernel per hour compiled to native code, warp shuffles as the unit of work and verification, a daily dataset derived from a 256 MB cache, a verifiable delay between seed and program, automatic era draws from a genesis reserve, and a growing dataset. The row must be rewritten to name ProgPoW and KAWPOW as the closest precedent.
|
|
|
|
Evidence: none in the repository yet; the ProgPoW specification and the Ravencoin repository should be cloned into `vendor/` and cited. Fix: overclaims list, item 5.
|
|
|
|
Sweep (5 October 2026, evening): stated. `site/litepaper.html`, the precedents table (section id `firsts`, retitled "Precedents, and what Igneum adds"), row 1 names RandomX and ProgPoW/KAWPOW as the precedents and what Igneum adds, marked approximate; "Built on the shoulders" marks the ProgPoW and KAWPOW line as cited from memory until the clone. The clone and citation stay fud-fixes row 48.
|
|
|
|
### M5. Your load count varies 6x between programs
|
|
"TESTS.md: loads per hash ranged 40 to 232 across 10,000 programs. A 40-load program is ALU-bound and favours a chip for that hour. Your litepaper says the memory footprint and instruction count are fixed."
|
|
|
|
Status: Fixed (4 October 2026): generator version 2 draws exactly 16 load slots per program (spec 01 section 1.4.2, `igneum-pow/src/generator.rs`), and the fresh-source rule of 1.4.3 with the acceptance rule of 1.4.6 fixes the distinct count too, which the census showed is what the GPU pays for: every accepted program does 128 loads per hash of which at least 120 and typically 128 are distinct (20,000-program confirmation: mean 127.887, min 120.127). Apple OpenCL on the M5 Max runs every version 2 pack within 1 percent of the same rate (27.5 to 27.9 Mhash/s). Every vector was re-cut and all three workers re-checked (`docs/bench-log.md`, 4 October 2026 "generator version 2"). Still owed: the first RTX 5090 run on a version 2 pack. Was: Open, experiment scheduled.
|
|
|
|
Answer: Correct and a real gap. The instruction count is fixed (64 x 8); the load count is not, and the hash rate scales with it (104 loads gave 228 Mhash/s, 128 loads gave 185 on the 5090). The generator must fix the load count per program, or bound it tightly, so every hour is equally memory-bound and difficulty does not whiplash on the hour. This goes into the specification in phase 1 and is re-fuzzed. Until then the litepaper's sentence about fixed footprint is ahead of the prototype.
|
|
|
|
Evidence: `proto-metal/TESTS.md` section 1 (loads per hash 40 to 232), `docs/bench-log.md` (104 vs 128 loads). Fix: overclaims list, item 15.
|
|
|
|
### M6. Weak programs
|
|
"Some hours the generator will emit a program whose OR chain saturates a register or whose load addresses collapse. That hour is both biased and shortcut-able. You have measured 3 seeds for bias out of an infinite population."
|
|
|
|
Status: Fixed (4 October 2026): the acceptance rule of spec 01 section 1.4.6 (`igneum-pow/src/accept.rs`, mirrored in `proto-metal/main.swift`) rejects a candidate with a stale load source, a register without an injecting write, a nonce-independent register bit, a lane-constant load site, more than 1 percent saturated final values, an output bit past 6 sigma, or fewer than 120 distinct addresses per hash on average, over 64 fixed units on the seed-keyed closed-form dataset; a rejected candidate is replaced by the next attempt of the seed, so every node agrees. Measured: 5.225 percent of 20,000 candidates rejected (4.130 static, 1.095 dynamic), 1.055 candidates per epoch; the rule costs 1.3 to 3.4 ms. The remaining question, whether 6 sigma at 2,048 nonces is the right bias threshold, is a prototype value of spec 1.16. Was: Open, experiment scheduled.
|
|
|
|
Answer: Correct. Three seeds were measured for bias (max deviation 2.90 sigma over 192 bit positions, avalanche mean 32.0, std 4.0, zero duplicates) and the population was not. Nothing yet rejects a weak program. The scheduled experiment is a weak-program census of at least 10^5 programs on the CPU interpreter measuring bias, distinct load addresses, OR saturation and nonce-independent registers, then a rejection rule written into the generator. Phase 1, before the spec is final.
|
|
|
|
Evidence: `proto-metal/TESTS.md` section 3 and section 8, "next three tests" item 1.
|
|
|
|
### M7. No cryptographic analysis at all
|
|
"splitmix32(nonce ^ seed) ^ seed per register, then add-rotate-xor-multiply with OR. Nobody has looked at preimage, collision or seed-influence resistance. This is a toy hash that happens to be slow."
|
|
|
|
Status: Conceded, stated (5 October 2026, night): `site/litepaper.html`, Mining section, "The hash is a lottery, not a general-purpose cryptographic hash" and "Open: no analysis of the lottery properties exists yet". Was: Conceded, stated in the test report, not yet in the litepaper.
|
|
|
|
Answer: Correct. TESTS.md section 8 says exactly this. The lottery hash needs only to be a fair lottery: unpredictable output per nonce, no shortcut cheaper than honest evaluation, no bias a miner can exploit. It does not need to be a general-purpose cryptographic hash, and the design should say that explicitly and then prove the narrower property. The ad-hoc seed derivation (FNV-1a plus SplitMix) is to be replaced with a standard hash so the seed-to-program mapping is auditable. External review in phase 1.
|
|
|
|
Evidence: `proto-metal/TESTS.md` section 8, "Not demonstrated" item 1 and "next three tests" item 3.
|
|
|
|
Sweep (5 October 2026, evening): stated. `site/litepaper.html`, Mining section, a new paragraph after the verification sentence: the hash is a lottery and not a general-purpose hash, the three properties it needs, and the label Open: no analysis exists yet, the first job of the phase 1 review.
|
|
|
|
### 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: 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.
|
|
|
|
Evidence: `docs/bench-log.md` (RTX 5090 first run), `proto-metal/TESTS.md` section 8 "next three tests" item 3. Fix: overclaims list, items 20 and 59.
|
|
|
|
### M9. The 10 ms CPU verification gate is unmeasured
|
|
"0.02 ms per warp is with a six-op dataset formula. With a 256 MB cache and eight dependent reads per item it will be a different number, and you call it 'the measured gate'."
|
|
|
|
Status: Conceded, stated (5 October 2026, night): `site/litepaper.html`, Mining section, "Measured: 0.41 to 0.58 ms per warp on one Apple M5 Max core with the 256 MB cache"; vs RandomX "Light verification" row. Was: Conceded, not yet stated in the litepaper.
|
|
|
|
Answer: Correct. The 0.015 to 0.021 ms figures are with the cheap closed-form dataset. The design bounds a warp to at most 4,096 distinct dataset items, each from eight dependent cache reads, so the verifier does about 32,000 random reads in 256 MB per warp. At roughly 100 ns per miss that is about 3 ms, approximate, which is why 10 ms is the gate. It has not been measured, and the design doc lists it as a promise until measured. The experiment is scheduled on an M5 Max and on a 2019-class laptop core.
|
|
|
|
Evidence: `docs/bench-log.md` (first run, CPU verify column), design doc Finality v2 "Residual risks" last bullet and "Three experiments before gate 3". Fix: overclaims list, items 16 and 21.
|
|
|
|
Sweep (5 October 2026, evening): stated. `site/litepaper.html`, Mining section and the vs RandomX "Light verification" row: the 10 ms gate with the label Measured, 0.41 to 0.58 ms per warp on one Apple M5 Max core with the 256 MB cache (bench-log, igneum-pow crate, 3 October 2026), and the 2019-class core not yet measured. Overclaims 16 and 21.
|
|
|
|
### M10. "Bound by memory bandwidth" is wrong
|
|
"Your own log says random-access bound. The 5090 moves 95 GB/s of useful loads against 1,638 GB/s sequential. HBM cards and chips with wide random-access memory will beat consumer GDDR here."
|
|
|
|
Status: Answered with evidence, stated (5 October 2026, night): `site/litepaper.html`, Mining section, "bound by random memory access. Measured: an RTX 5090 hashes at 95 GB/s of useful 4-byte loads against 1,638 GB/s of sequential writes" (overclaim 14 applied tonight; the sentence was still "bound by memory bandwidth" at 18:20 UTC). Was: Answered with evidence, with a wording fix.
|
|
|
|
Answer: The log is right and the litepaper's word is wrong: the limit is random access latency, about 23.7 billion random 4-byte loads per second on the 5090 regardless of program. The wording will change. On the substance: a chip or a datacentre card still needs gigabytes of memory and still pays the random-access cost; HBM improves bandwidth more than it improves random 32-byte sector latency, approximate. Whether an H100-class card beats a 5090 per dollar on this workload is a measurement we have not made, and it belongs on the January 2027 leaderboard.
|
|
|
|
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: 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).
|
|
|
|
Answer: Correct that the compile figures (18 to 52 ms) are Metal on one Mac. The 5090 run used an offline nvcc build. Runtime compile with NVRTC and with ROCm on a multi-card rig is unmeasured. KAWPOW miners do ship runtime kernel generation on both vendors, so the problem is known to be solvable (approximate, from memory). Measured in phase 2 with the miner client prototype.
|
|
|
|
Evidence: `docs/bench-log.md` compile columns. Rig measurement: not yet.
|
|
|
|
### M12. Rentable hashrate is not just NiceHash
|
|
"You say rental is priced by the hour. Cloud GPUs are priced by the hour too. A thousand 5090-class cards for a day is a few thousand dollars."
|
|
|
|
Status: Answered by design for finality, Conceded for the lottery.
|
|
|
|
Answer: Both halves true. NiceHash and MiningRigRentals cannot list an algorithm whose kernel changes hourly without a stratum for it, so classic hashrate rental does not exist at launch. Cloud GPUs do, and they can out-mine a small chain's lottery cheaply. That is why finality is weighted by 30 days of blocks, not by today's hashrate: a renter with 60% of the network earns 59.9% of block rewards on day 1 and holds 0.0% of vote weight (sim, table B). What rental can do is take block rewards and stall finality after about three weeks. See F1 for the launch window, where this answer does not yet hold.
|
|
|
|
Evidence: `sim/results.md` table B.
|
|
|
|
### M13. Macs mine too is marketing
|
|
"An M5 Max does 45 Mhash/s against 228 on a 5090 and costs more. 'Macs mine too' is a line for people who will lose money."
|
|
|
|
Status: Conceded, stated (5 October 2026, night): `site/litepaper.html`, For miners, Hardware, "Macs mine too, at about a fifth of a flagship card: Measured, 26.7 against 123 million hashes a second" (confirmed by grep tonight; the projected-earnings half is not written because the app shows none, see M29). Was: Conceded, partly stated.
|
|
|
|
Answer: The measured ratio is about 5x in the 5090's favour, so a Mac is a poor miner per dollar. The litepaper says Macs mine; it should say Macs mine at about a fifth of a flagship card and that the one-click app shows projected earnings before it starts.
|
|
|
|
Evidence: `docs/bench-log.md`, two-card table.
|
|
|
|
Sweep (5 October 2026, evening): stated. `site/litepaper.html`, "For miners", Hardware: Macs mine at about a fifth of a flagship card, Measured 26.7 against 123 MH/s on the live devnet (4 October 2026), a poor miner per dollar. The projected-earnings sentence was not written: the app shows none (round 4 note), which is right for a devnet.
|
|
|
|
---
|
|
|
|
### M32. "Automatic anti-ASIC escalators" overstates what the era draw and the instruction reserve do
|
|
"You sell the era draw and the reserve unlock as anti-ASIC escalators, as if not knowing next era's parameters stops a chip. A chip that stores the dataset reads every drawn parameter as firmware: an address permute, a rotator, an immediate table. The families, the reserve order, the mixer, the dataset schedule and the class v4 shadow are all public at genesis. So what does the draw actually defend against?"
|
|
|
|
Status: Conceded, stated (6 October 2026, evening; the Horizon lane analysis `docs/analysis/horizon/algorithm.md` sections 5.4 and 8, lane 2): the era draw and the instruction reserve are automatic schedule changes against fixed datapaths and against human forks; against the stored-dataset chip every drawn parameter is firmware, and the defence against that chip is the latency-shadow work (class v4) and the price-per-joule model. Stated in `site/litepaper.html`, Mining section ("These are automatic schedule changes ... every drawn parameter is firmware") and the "A chip is impossible" item ("a chip wired for one program is a bad bet ... not the schedule"), the "Every six months" row of the comparison table, and `site/index.html`, the hourly-program note ("a chip wired for one program is useless"). The phrase "automatic anti-ASIC escalators" is withdrawn from public text; it stays in the internal design summary until that is next edited.
|
|
|
|
Answer: Correct. The draw hides (M, R, pos, the op weights within +-2, the fold rotations) until 2 hours before each era, and none of those needs silicon. Biasing the draw is priced at 20 days of 100 percent of the network's hash for one more sample of the same space (lane section 5.4), so the draw is unbiasable at any price that matters and that is its whole job: it is a fairness device and a fork-free schedule, not a chip defence. What a chip wired for one program loses to is the hourly program itself; what the stored-dataset chip loses to is the latency shadow (class v4, 2.1x per joule at k = 1 against the 5090 bench row, 0.9x against the Apple M5 Max) and the price per joule, which is where the public claim now rests.
|
|
|
|
Evidence: `docs/analysis/horizon/algorithm.md` sections 5.4 (the draw's randomness, the two routes priced) and 8 (the summary), 6 October 2026; the six-era hash-rate spread of 0.8 to 3.2 percent per card in bench-log "Counter ASIC 2.0, the numbers".
|
|
|
|
### M33. The FPGA ceiling rests on a tFAW the JEDEC HBM2 table does not give
|
|
"Your chip model's HBM random-read ceiling takes 8 activates per 12 ns per channel from O'Connor and gets 10.7 G reads/s a stack; the epoch-length page's bank-bound row gets 11.4 and a 12.2 ceiling. JEDEC HBM2 tFAW is 28 ns with 4 activates per channel per window: 2.3 G. The one measured HBM2 FPGA random-read rate (Shuhai, FCCM 2020) is 2.4 G, right on the JEDEC ceiling. Your 1.9x FPGA ceiling is arithmetic on a timing the part does not have."
|
|
|
|
Status: Conceded, stated (6 October 2026, evening; the Horizon lane analysis `docs/analysis/horizon/algorithm.md` section 5.1, the FPGA lane): the public FPGA line carries only the measured row, 2.4 G reads/s per card and 0.30x to 0.39x of the RTX 5090 per watt (Shuhai, FCCM 2020 Fig 7; the tFAW arithmetic from ICCAD 2021 Table I), and the 11.4 G bank-bound row and the 12.2 G ceiling are marked unmeasured until an AWS F2 hour measures them. Stated in `docs/analysis/chip-model-v3.md` section 5.3 (the activate-bound row marked UNMEASURED with the JEDEC figure beside it, and the FPGA paragraph after the table). The epoch-length analysis's 12.2 row is not on master yet and is corrected when it lands.
|
|
|
|
Answer: Correct. The measured 2.4 G/s had been read on 6 October as a mapping artefact ("the paper's point is that this mapping is the wrong one for random access"); the activate window says it is the DRAM's own limit, and a bank-interleaved mapping does not lift it because tFAW is enforced per channel by the die. The measurement that settles it is one AWS F2 hour (f2.6xlarge, Virtex UltraScale+ VU47P, 16 GB HBM2 in 2 stacks, 32 pseudo-channels, USD 1.98 an hour on demand): the chase kernel of `docs/benchmarks/repro.md` 2.2 ported to a Vitis HLS AXI master over the HBM IP at 1 GiB across all 32 pseudo-channels, 256 to 4,096 lanes in flight, board power at 1 Hz; pass line 15 to 25 M reads/s/W (0.3x to 0.5x of the 5090), alarm 27 (0.5x), over 54 (1.0x) a Counter ASIC 4.0 item. Consequence per tier: none today (no FPGA mines); on the measured row a soft-overlay FPGA mines at an RX 9070 XT's rate per watt for about 7x the price (approximate), so no home or rig tier is displaced.
|
|
|
|
Evidence: `docs/analysis/horizon/algorithm.md` section 5.1 (the ceiling table: measured 2.4, tFAW-bound 2.3, tRRD-bound 2.8, bank-bound 11.4, O'Connor 10.7 G reads/s, and the F2 measurement plan), 6 October 2026; JEDEC HBM2 timings as carried by ICCAD 2021 Table I; Shuhai, FCCM 2020, Fig 7.
|
|
|
|
### M34. The shadow size N is a constant of the binary, so the one lever against the dataset-storing chip needs a fork to move
|
|
"Your own Horizon lane says the reserve and the era draw buy nothing against a chip that stores the dataset, and that the only lever is the latency-shadow size N. N is 27 passes of a 256-instruction block, hard-coded in `V4_CLASS`. So when HBM4 doubles a chip's rate per stack in 2028, your answer is a hard fork, and a fork that retires the M5 Max at the first doubling. And now there is a shipping RandomX ASIC."
|
|
|
|
Status: Conceded, implemented (6 October 2026, night; `docs/design/latency-ladder.md`, branch `ladder`, fork branch `ladder-node`, the 0.3.17 feature tree, behind `latency_ladder_activation_daa`, never until set, 0 on the testnet when the project lead says): N is a genesis ladder of six rungs (27, 35, 53, 88, 173, 267 passes; about 102,100 to 1,001,600 counted ops) with a measured admissibility flag per rung (cold verify under 10 ms on the reference core with its SMT sibling loaded, igneum-build-1, 6 October 2026: rungs 0 to 2 pass at 8.77, 8.87 and 9.23 ms, rung 3 misses by 0.08 ms under a box load of 25 and is out until a quiet re-run, rungs 4 and 5 are out at 12.38 and 14.96), and the step is consensus state derived from two bits of the header version: up one rung when 90 percent of blue blocks in each of seven consecutive windows ask for it and the rung above is admissible, down one rung symmetrically, never two rungs inside seven windows (the oldest window must begin after the last step took effect), never unconditionally. Tests, the known-failed case first: a changed N today hashes another program under the same program id (a hard fork no pack line told apart); after, rung 0 is class v4 byte for byte, a rung above carries its pass count in the id, 8,999 bps in one window of seven does not move the step, a two-step jump is impossible, down never passes rung 0, an inadmissible rung is never entered. Stated in `site/litepaper.html`, Mining section ("The work that waits can grow").
|
|
|
|
Answer: Correct on both counts, and the second was the sharper one. The X9 (Bitmain, about 1 MH/s at 2,472 W, approximate, github.com/monero-project/monero/issues/10270) is a shipped 3x per-joule edge over a desktop CPU on the best-known latency-bound random-program design, seven years after launch; it makes the k = 0.3 column of the chip model a product class rather than an attacker's claim, and the public headline is now the range 2.1x (k = 1) to 3.9x (k = 0.33) over the RTX 5090 at class v4, with the ladder taking the X9 bracket to about 2.8x by rung 2 and the Apple tier's to about 1.1x by rung 3. The ladder does not close the gap; it is the chain's only automatic answer, it moves at the pace of the cards that pay for it, and the honest card's watts remain the lever that moves every row (algorithm lane proposal 7). What the ladder gives up by design: a chip holding over 10 percent of weight can stall it, and the status quo it stalls is a rung the cards already run.
|
|
|
|
Evidence: `docs/design/latency-ladder.md` (the rule, the hostile review, the measured verifier table, the X9 arithmetic); `igneum-pow/src/generator.rs` test `latency_ladder_known_failed_a_changed_n_was_a_hard_fork_and_rungs_are_class_v4`; the fork's `consensus/core/src/igneum.rs` test `latency_ladder_rule`, `consensus/pow/src/igneum.rs` test `latency_ladder_rungs_are_programs_of_their_own_over_one_day_cache`; `infra/fast-time/latency-ladder.mjs` (the step, no-step and known-failed cases).
|
|
|
|
## 2. Finality and attacks
|
|
|
|
### F1. Finality is attackable for the first month
|
|
"Vote weight is 30 days of blocks. At genesis there are zero days. For the first weeks weight equals hashrate share, so anyone with two thirds of a tiny launch hashrate locks checkpoints alone. You say 'no certificate in the first hour'. An hour."
|
|
|
|
Status: Rule implemented and measured; launch month simulated (5 October 2026 sweep). Rule: `min_daa = weight_window` (branch `fin-fixes`, 4 October 2026, merged into `devnet-v4`; 2,592,000 DAA s on mainnet, 7,200 on devnet, a unit test pins the equality); `evaluate` never locks and `ingest_certificate` refuses any certificate while the checkpoint's DAA score is under it; the node reports "window filling, N of M". Measured on the fork: harness s5 before the fix locked checkpoints 1 to 10 by one 20-s burster alone; after, 0 locks under `min_daa` and the first lock by 5 of 6 voters at 84.7% (`docs/bench-log.md`, "finality fixes F17 and F1"); the live devnet's first lock came at checkpoint 242, two hours after genesis, once the 7,200 window was full. Launch month under the gate (arithmetic, `docs/review/ledger-sweep-2026-10-05.md`): no certificate exists before day 30, and on day 30 an attacker producing share s of all blocks from day k holds s (31 - k) / 30 of the window, so the critic's 75% from day 2 holds 72.5% and would lock alone on day 30, 51% from day 1 holds 51% and cannot, and the share needed to lock alone on day 30 is 69% from day 2 and 95% from day 10; without the gate the old active-weight denominator crossed two thirds on day 9. The gate therefore turns the first month into the standing bound (an attacker over two thirds of all hashrate, which no proof-of-work rule resists) and nothing weaker. The v1 model's zero-history ramp (`sim/finality_sim.py --scenarios A`) is re-run in the sweep's batch. The litepaper statement is public text (testnet-prep). Was: Conceded, not yet stated in the litepaper. Zero-history ramp of the v1 model (`python3 sim/finality_sim.py --scenarios A --floors 1,100`, 5 October 2026): the network's total weight first reaches 99% of a full window on day 41 (floor 1) or day 35 (floor 100), so the gate's day 30 is the day the window is full by construction and the earliest a lock is possible. Live confirmation on the current node line (5 October 2026, 01:11 UTC, `tools/finality-attacks/run.mjs s5 --fast-time` on the `finality-fixes` build, ports 29300 to 29302, `min_daa` = window = 120 DAA, 126 s): the 10x burster's weight share was 27.5% against a block share of 31.8% (ratio 0.864, no amplification), it stayed under the floor and locked nothing alone, 0 locks carried by fewer than 2 votes, 0 conflicting certificates. PASS; the harness's own result text still names the 56.7% floor and needs the 2/3 wording.
|
|
|
|
Answer: Correct, and this is the most dangerous entry in the ledger. With the active-weight denominator and a one-day honest head start, an attacker producing 75% of blocks from day 2 holds 0.75k/(1+k) of weight after k days and crosses two thirds on day 9 of the chain's life; an attacker arriving in hour two crosses it the same day. The window is empty, so the defence is absent. The 30-day emission ramp (10% to 100%) lowers the incentive without removing the attack. The design doc's answer, the one-hour merge-depth bound protecting the first month, bounds the damage of a reorg and does nothing about a bad lock. The rule under consideration: no certificate may form until the window has 30 days of history, so the chain runs plain GHOSTDAG under the one-hour merge-depth bound for its first month, exchanges are told to treat it so, and listings follow launch in any case. This goes to the gate 3 simulation and the litepaper will state it either way.
|
|
|
|
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."
|
|
|
|
Status: Closed by rule (3 October 2026). Spec section 3.3.2: the 56.7%-of-total floor in Q3 is the answer; 0 conflicting locks at 1, 2 and 4 h against a 34% attacker (`sim/results_v2.md` F2); the devnet eclipse of O-3.7 is confirmation only. Was: Open, experiment scheduled. Sweep (5 October 2026): the floor named here (56.7% of total) was raised to two thirds of total on 4 October 2026 (O-3.15, spec 3.3 Q3); the eclipse scenario was re-run at the new floor (`sim/results_v2.md` L3 and F at 2/3: 0 conflicting locks and 0 locks on the eclipsed side in every seed and length), so the closure stands at the higher floor.
|
|
|
|
Answer: Correct that the presence window trades safety for liveness. The design doc says so: "any event that keeps honest keys from signing (eclipse, partition, targeted DoS) shrinks the denominator and lets a smaller faction lock," and the simulation recommends the fail-safe all-keys denominator while the design chose the presence window as the working default. The mitigation in the rule is that a lock requires the certificate's unscaled weight to reach two thirds of active weight, so an eclipsed set still has to be out for most of the 240 checkpoints before the denominator moves far, and votes travel in blocks as well as as their own messages. That is an argument, not a measurement. The gate 3 experiment is a devnet with regional latency and a single-node eclipse recording whether conflicting locks appear, plus the choice between a 2-hour and a 7-day silent-key rule. Until it runs, this entry stays open.
|
|
|
|
Evidence: `sim/results.md` table E and "What the simulation cannot tell us"; design doc Finality v2, Quorum item 4 and the "Simulation of the first version" paragraph.
|
|
|
|
### 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: 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."
|
|
|
|
Status: Answered by design, with the concession stated.
|
|
|
|
Answer: The committee's weight is blocks mined in the last 30 days. There is no coin to buy, stake, delegate or slash, and the weight cannot be acquired faster than by mining in public. The design concedes what follows: pools hold their hashers' votes, so vote concentration equals pool concentration, as on Bitcoin, and a 51% owner who drives half the honest miners away for a month owns finality thereafter, "same as Bitcoin, with a month's warning". It is a finality overlay on proof of work. Calling it that in the litepaper is more honest than "powered by miners alone".
|
|
|
|
Evidence: design doc Finality v2, "Residual risks" bullets 3 and 4; `sim/results.md` table F.
|
|
|
|
### F5. The headline arithmetic is misread on purpose
|
|
"'An attacker who brought the whole network's hashrate needs ten days for a third.' If I bring hashrate equal to the network I have half the blocks and need twenty days for a third and never reach two thirds. Your ten days assumes honest miners produce nothing."
|
|
|
|
Status: Conceded, stated (5 October 2026, night): `site/litepaper.html`, Finality, "an attacker producing every block on the chain, with honest miners gone" and "An attacker matching the honest network needs twenty days for a third and never reaches two thirds"; the same arithmetic in What Igneum does not claim. Was: Conceded, wording to fix.
|
|
|
|
Answer: Correct reading. The 10 and 20 day figures assume the attacker produces 100% of blocks, which is the strongest attacker and therefore a true lower bound, and the sentence should say "an attacker producing every block on the chain". With half the blocks: 1/3 at day 20 and 2/3 never. With 60%: 1/3 on day 18 to 26 depending on the (now removed) cap, 2/3 never. With 75%: 2/3 on day 27 to 34.
|
|
|
|
Evidence: `sim/results.md` tables B and C. Fix: overclaims list, item 32.
|
|
|
|
Sweep (5 October 2026, evening): stated. `site/litepaper.html`, Finality: "an attacker producing every block on the chain, with honest miners gone" for the 10 and 20 days, plus the matching-hashrate case (20 days for a third, two thirds never); the same arithmetic in "What Igneum does not claim". Overclaim 32.
|
|
|
|
### F6. Equivocation costs nothing that matters
|
|
"A pool that signs two checkpoints loses its vote for 30 days. Not its blocks, not its coins. If two thirds of pools collude to double-spend an exchange, the penalty is a month of not voting."
|
|
|
|
Status: Conceded, stated in the litepaper and the design doc.
|
|
|
|
Answer: True. "Equivocation costs history, not coins." There is nothing to slash without stake, and the design refuses stake. What bounds the damage is the one-hour merge-depth rule (a bad lock cannot reorganise deeper than an hour) and that two thirds of weight takes 20 days of 100% hashrate in public to acquire. A colluding two-thirds of pools is the same actor set that can attack Bitcoin, and the litepaper says so.
|
|
|
|
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 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<B>` 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."
|
|
|
|
Status: Conceded, stated in the simulation report.
|
|
|
|
Answer: Correct. `sim/results.md` lists every one of those omissions under "What the simulation cannot tell us". The day counts are arithmetic on the window and hold for any model where blocks are counted; the things the model cannot see (red blocks, partitions, eclipse) are what gate 3's devnet is for. The litepaper quotes the day counts as design facts; it should attribute them to the model.
|
|
|
|
Evidence: `sim/results.md`, final section.
|
|
|
|
### F9. Half the hashrate leaves and finality stalls for ten days
|
|
"Your own sim: 50% churn stalls the lock 10 to 11 days under the fail-safe rule. GPU coins lose half their hashrate in a week when the price halves. That is routine, not an attack."
|
|
|
|
Status: Answered by design.
|
|
|
|
Answer: That table is the all-keys denominator, which the simulation recommended for safety. Finality v2 chose the active-weight denominator with a 2-hour presence window instead, under which no churn level stalls more than two hours (sim table E, "active" column: 100% live share from day +1 at 30%, 35% and 50% churn). The price of that choice is F2. The two experiments in gate 3 decide the final rule; the litepaper states the 2-hour figure.
|
|
|
|
Evidence: `sim/results.md` table E; design doc Finality v2, Quorum item 4.
|
|
|
|
### F10. Pools hold the votes
|
|
"Two pools at 70% of hashrate is normal on a GPU coin. On Igneum that is two operators holding finality."
|
|
|
|
Status: Conceded, stated (5 October 2026, night): `site/litepaper.html`, Finality, "Pools carry their hashers' votes, so vote concentration equals pool concentration, and it is public"; Governance, "governed by the hashrate that powers it". Was: Conceded, stated in the design doc, not in the litepaper.
|
|
|
|
Answer: True. The vote key is named in the block header by whoever builds the block, which in a pool is the pool. The design doc states "Pools hold their hashers' votes. Vote concentration equals pool concentration, as on Bitcoin, and is public." Stratum v2 lets a hasher choose transactions when its pool supports it, and does nothing for the vote key. Solo mining is viable at one block a second (86,400 blocks a day), which widens the key set in a way Bitcoin's block rate does not, and the dust threshold of 100 blocks per 30 days is about 0.004% of hashrate. The litepaper's "governed by the people who power it, and by nobody else" must carry the pool sentence.
|
|
|
|
Evidence: design doc Finality v2, Residual risks bullet 3. Fix: overclaims list, item 44.
|
|
|
|
Sweep (5 October 2026, evening): stated. `site/litepaper.html`, Finality ends with the pool sentence (overclaim 33); Governance opens with "governed by the hashrate that powers it", pool concentration named as the governance risk with the devnet measurement, top-3 keys 34.5% of 8,090 blocks (ledger sweep, X14 run). Overclaim 43.
|
|
|
|
### F11. VDFs are exotic
|
|
"A class-group VDF with Wesolowski proofs in a consensus-critical path, in a project with no cryptographer. Chia needed years and still got timelord ASICs."
|
|
|
|
Status: Answered by design, with the dependency conceded.
|
|
|
|
Answer: The VDF is used for one thing: making the hourly program unknowable within the roughly two seconds a miner has to decide whether to publish a block, closing a withhold-or-publish grind the review measured at about 130 to 1 for a 30% miner. The VDF input is a certified checkpoint at least one epoch before the epoch starts, so honest nodes have about 50 minutes of slack to evaluate a 10-minute VDF, and an evaluator 300x faster than reference would still be needed to beat the two-second decision window. Chia has run class-group VDFs in production since 2021, with faster hardware evaluators existing and not breaking it (approximate, from memory). The design doc lists the VDF as a new dependency and ships the evaluator in every node. The grinding simulation with and without the VDF is scheduled before gate 3.
|
|
|
|
Evidence: design doc Finality v2, Lottery seeds items 1 and 2, Residual risks bullet 5, "Three experiments before gate 3".
|
|
|
|
### F12. Nothing outside the chain, except
|
|
"No Bitcoin anchoring, you say. You depend on Succinct's SP1, BLS12-381, a class-group VDF, NVIDIA's compiler and a fork of Kaspa's node."
|
|
|
|
Status: Answered by design.
|
|
|
|
Answer: Those are code dependencies, chosen because each is open source and replaceable, and none is another chain's consensus. "Nothing outside Igneum" in the litepaper means no other chain's state is read, and the sentence should be scoped that way. A soundness bug in the proof system is the one dependency that can hurt consensus; see P7.
|
|
|
|
Evidence: CLAUDE.md design paragraph; design doc "Decided" paragraph.
|
|
|
|
### F13. Why prove every block if every node executes anyway
|
|
"Every node runs the transactions natively, so full nodes do not need the proof. You pay 20% of emission for a proof that your own nodes ignore."
|
|
|
|
Status: Answered by design.
|
|
|
|
Answer: Full nodes execute natively so users see state in about a second. The proof is for everyone who is not a full node: light clients, bridges, exchanges syncing from a checkpoint, and the external market, which needs a standing prover population with hardware already running. It is also what lets a new node sync from a proven checkpoint instead of replaying history. The 20% is paid for capacity as much as for the proofs themselves, and the litepaper should say that.
|
|
|
|
Evidence: design doc, "Proving speed on consumer GPUs" risk item and "Who needs" paragraph.
|
|
|
|
---
|
|
|
|
### F26. "No stake" needs its one sentence: what is at stake, and what strips it
|
|
"You write 'no stake' and then run a vote whose weight can be stripped. Either nothing is at stake, in which case equivocation costs nothing, or something is, in which case say what it is and who can take it. One sentence, in the finality section and the summary, not an argument."
|
|
|
|
Status: Conceded, stated (6 October 2026, evening; the Horizon lane analysis `docs/analysis/horizon/frontier.md` section 4.1 and item I13 of its incremental list): `site/litepaper.html`, the finality section's "What is not here" paragraph and the "Igneum at a glance" Finality row carry the sentence verbatim: "No coin is staked. The only thing at stake is 30 days of public work: a vote key's weight is its blue blocks over the window, and equivocation strips it for 30 days." The spec sentence for 03 and 05 (I13) follows with the lane's commit.
|
|
|
|
Answer: Correct. The weight is a quantity that is at stake, earned by work alone over 30 days, not transferable, not purchasable, and already stripped in full for equivocation (spec 3.6). That is a slashable bond made of blocks, with no coin and no stake class; the "then it is stake" objection and its answer (the weight cannot be bought, borrowed or bridged, so capture by capital is removed; the last-days attack is bounded by the 30-day re-earn) are in the lane file, section 4.1. Extending the strip to execution-layer faults (the lane's 3.2) is an idea, not a rule, and the public text does not claim it.
|
|
|
|
Evidence: `docs/analysis/horizon/frontier.md` sections 3.2, 4.1 and the incremental list (I13), 6 October 2026; spec 3.6 (the equivocation strip).
|
|
|
|
## 3. Proving and the zkEVM
|
|
|
|
### P1. The 20-second shard is a number you made up
|
|
"'A 12 GB card proves one shard in about 20 seconds, measured on a mid-range card before launch.' So it is not measured. You wrote a target in the past tense."
|
|
|
|
Status: Conceded, stated (5 October 2026, night): `site/litepaper.html`, Proving, The proving budget, "Target: shard size will be set so a 12 GB card proves one shard in about 20 seconds. That number is the phase 2 gate". Was: Conceded, not yet stated in the litepaper. Sweep (5 October 2026): a full shard at S_p = 7.5 M pgas was proven on an RTX 5090: core 9.1 s, compressed 10.9 s, a two-shard block aggregated in 2.2 s, all verified (bench-log, "shard proving on the RTX 5090"). The gate card is a 12 GB mid-range card, not a 5090, so the 20-s figure stays a target on that card, under P16's standard.
|
|
|
|
Answer: Correct. It is the phase 2 gate, to be measured on a 3060-class card, and no SP1 shard has been proven on any card in this repository yet. The sentence must be rewritten as a target.
|
|
|
|
Evidence: `site/journey.json` phase 2 gate. Measurement: not yet. Fix: overclaims list, item 27.
|
|
|
|
Cross-reference (external review, 3 October 2026, night): the phase 2 gate now carries an end-to-end acceptance standard, P16 and O-7.1; design R2's halve-and-re-measure fallback is no longer a pass.
|
|
|
|
Sweep (5 October 2026, evening): stated. `site/litepaper.html`, Proving, "The proving budget": the sentence opens with the label Target and says the 20-s shard on a 12 GB card is the phase 2 gate, not measured on the card the gate names. Overclaim 27.
|
|
|
|
### P2. Real-time proving needs a hundred GPUs per block
|
|
"Succinct needed on the order of 160 consumer GPUs to prove Ethereum blocks in real time in 2025. You have one block a second. Your gas throughput will be a rounding error or your proofs will fall behind."
|
|
|
|
Status: Conceded, stated in the litepaper, with the dial explained.
|
|
|
|
Answer: True, and the litepaper says a full block needs a cluster of 100 to 200 consumer GPUs, approximate. Igneum's gas budget per block is a consensus constant set from measured prover throughput, so throughput is a function of how many cards are proving. With few provers at launch the chain carries little gas. The design treats that as a dial, not a failure, and the litepaper should publish the launch budget as a formula (cards proving times shards per card per minute) so builders can see it. Proving costs have fallen roughly an order of magnitude a year for three years, approximate, and the interface is swappable.
|
|
|
|
Evidence: design doc "Unit economics of a proof"; litepaper "What Igneum does not claim" item 1.
|
|
|
|
### 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, 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.
|
|
|
|
Answer: Correct. The light-client proof is the aggregated block proof wrapped once into a small curve-based proof, and wrapping is the aggregator's job. The cost and latency of that wrapper on consumer hardware is unmeasured and belongs in the phase 2 benchmark alongside the shard time. Until measured, the litepaper should say "wrapped for light clients".
|
|
|
|
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."
|
|
|
|
Status: Conceded, stated (5 October 2026, night): `site/litepaper.html`, precedents table row 6, "The consensus proof that makes the checkpoint self-verifying is phase two"; Building item 2, "Light clients". Was: Conceded, stated in the design doc, overclaimed in the litepaper.
|
|
|
|
Answer: Correct. The hostile review table says "One-proof light clients and committee-free bridges need a consensus proof, not just an execution proof. Scoped as phase two with honest cost." At launch a light client trusts a recent certificate it is given (as Ethereum light clients trust a sync committee checkpoint) and verifies execution from there. The firsts table row and the "Trustless light clients" paragraph must be re-scoped.
|
|
|
|
Evidence: design doc, hostile review table rows "Slashing an external prover" and "One-proof light clients". Fix: overclaims list, items 9 and 38.
|
|
|
|
Sweep (5 October 2026, evening): stated. `site/litepaper.html`, precedents table row 6: at launch one execution proof plus a certificate the client is given, the consensus proof phase two, label Designed; Building item 2 already carried the re-scope (overclaim 38). Overclaim 9.
|
|
|
|
### P5. EVM "unchanged" on a DAG is false
|
|
"block.number, block.timestamp, blockhash, coinbase, prevrandao. On a DAG none of these mean what Solidity assumes. Plus your 2D fee market: wallets estimate one gas, you charge two."
|
|
|
|
Status: Closed by spec (3 October 2026). Spec section 7.1 fixes block.number, timestamp and its monotonicity rule, blockhash, PREVRANDAO from the epoch VDF, coinbase, gas limit, chain id and the quoted gas price; "unchanged" is not claimed. Was: Open, specification scheduled.
|
|
|
|
Answer: Correct. The review listed this and the answer is "to be defined over the ordered sequence in the spec", phase 1. Timestamp and number come from the ordered sequence; blockhash and coinbase need a definition; prevrandao can be derived from the epoch VDF. The proving-cost dimension is folded into the quoted gas price by the node so `eth_estimateGas` keeps working, and a contract heavy in pairing or modexp precompiles will cost more here than on Ethereum. "Unchanged" should become "same bytecode, with these documented differences".
|
|
|
|
Evidence: design doc, hostile review table row "EVM semantics on a DAG". Fix: overclaims list, items 35 and 36.
|
|
|
|
### P6. The proving market is tiny
|
|
"Total rollup proving spend is low millions a year and Boundless, Succinct and the rollups' own clusters already fight for it. 'Igneum gives the proving market its cheapest supplier' is a line for miners who have not seen the numbers."
|
|
|
|
Status: Conceded, stated (5 October 2026, night): `site/litepaper.html`, The problem, "a supplier whose marginal cost is close to power"; "cheapest supplier" and "lowest cost" absent from the page (grep, tonight). Was: Conceded, stated in the litepaper, with one overclaim to fix.
|
|
|
|
Answer: The litepaper says the market is small three times and calls external proving "upside, not a promise". The design doc estimates total spend at low millions of dollars a year, approximate, and says a GPU fleet of any size swamps it. Igneum does not depend on it: in-chain proving is paid from emission and gas regardless. The overclaim is "cheapest supplier": Boundless already admits home GPUs, and Succinct's and Boundless's provers must stake their own tokens, which an Igneum miner would also have to hold to bid there. "Marginal cost close to power" is defensible; "cheapest" is not.
|
|
|
|
Evidence: design doc "Market size, honestly" and "Existing prover networks" table (labelled from memory). Fix: overclaims list, items 12 and 58.
|
|
|
|
Sweep (5 October 2026, evening): stated. `site/litepaper.html`: "cheapest supplier" is gone from The problem (overclaim 12); "lowest cost" from For miners, Questions miners ask and What Igneum does not claim (49, 55): marginal cost close to power, an edge over data-centre provers and nothing more.
|
|
|
|
### P7. A soundness bug in SP1 is a consensus failure
|
|
"SP1 has had disclosed soundness bugs. On Igneum a forged proof means 'a block with a wrong state cannot exist' becomes a wrong state that exists, and your upgrade path is a 90% miner vote with three months' notice."
|
|
|
|
Status: Conceded, stated (5 October 2026, night): `site/litepaper.html`, Abstract, "Writing new code, including an emergency fix to the proof system, is the one thing that takes a person"; Proving, "no node accepts a block with a wrong state root". Was: Conceded, not yet stated in the litepaper.
|
|
|
|
Answer: Correct that a live soundness bug cannot wait for a three-month release train. Full nodes execute natively, so a forged proof disagreeing with native execution is detectable by every full node, and the rule must be that a full node rejects a proof whose claimed state root differs from its own execution. That turns a soundness bug into a light-client problem rather than a chain split, and it must be written into the spec. The emergency path for the proof system version is a human one and the litepaper should say so, alongside the "nothing needs a human" sentence.
|
|
|
|
Evidence: design doc "Proof system churn" risk item. Rule: not yet. Fix: overclaims list, items 3 and 26.
|
|
|
|
Sweep (5 October 2026, evening): stated. `site/litepaper.html`, Abstract (overclaim 3): no scheduled human release, an emergency fix to the proof system takes a person and activates on signalling. Proving, "How a block gets proven" (overclaim 26): no node accepts a wrong state root, full nodes reject a proof record that disagrees with native execution, label Implemented with spec section 7 named, and the human emergency path stated. The rule this entry asked for is spec 7.2 item 5 and 7.4 item 3 (the native-execution veto), already in the spec.
|
|
|
|
### P8. Fastest prover wins all the shards
|
|
"Aleo's lesson was that proving as a race centralises to the fastest. Your shards are claimed first-come with a bond. The lowest-latency datacentre claims every shard before a home card sees it."
|
|
|
|
Status: Closed by rule (3 October 2026). Spec section 7.2: sortition keyed to the block assigns each shard to 8 eligible provers for a 10-s window, then open claiming; parameters measured at the phase 4 devnet (O-5.1). Was: Open, design change scheduled.
|
|
|
|
Answer: Fair, and the lottery/proving separation does not by itself fix it. If claims are first-come, latency wins. The candidate rule is sortition of shards: a VRF keyed to the block assigns each shard to a set of eligible provers, weighted by past proving or by a lottery, with fallback to open claiming after a timeout. This is a phase 1 specification item and a phase 4 devnet measurement. The 20% proving pool is paid per block as a fixed amount divided by consensus proving cost, so a prover's income is bounded by the shards it is assigned, not by how many it can grab.
|
|
|
|
Evidence: design doc "Proving speed on consumer GPUs" risk item and Finality v2 "Fees". Rule: not yet. Cross-reference (round 3, 3 October 2026): F17 reopened the per-key draw of spec 7.2, which a key-splitter sweeps by count; spec 7.2 step 2 was rewritten the same evening to draw by weight (blue blocks drawn uniformly from the window), so this entry stays closed.
|
|
|
|
### P9. Shard griefing
|
|
"Claim a shard with a small bond and never prove it. Repeat. Finality waits on you."
|
|
|
|
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:
|
|
|
|
| Parameter | Live devnet value (5 October 2026) | Proposed for the testnet | Why |
|
|
|---|---|---|---|
|
|
| Assignees per shard | 8 (`ASSIGNEES_PER_SHARD`, `consensus/core/src/proving.rs`) | 8 | 21 eligible keys today, so a shard's draw covers 38% of the fleet; at 1,000 keys 0.8%. Eight keeps one slow or absent assignee from costing more than one window |
|
|
| Exclusive window | 10 DAA s (`EXCLUSIVE_WINDOW_DAA`) | 25 s | The economy study's rule (the 90th percentile of the fleet's shard time plus one program swap, rounded up to 5 s): the 5090 proves a full 7.5 M pgas shard in 9.1 s core, 10.9 s compressed, and the swap is under 1.1 s (M11), so 10 s is at the 5090's median and loses the window for every slower card; 25 s covers a 12 GB card at the 20-s target |
|
|
| After the window | open to anyone, first verified record paid | unchanged | A griefing assignee costs the network one window and nothing else; there is no claim to hold |
|
|
| Shard budget `S_p` | 7,500,000 pgas (prototype) | 30,000 pgas (calibrated v1, `B_p / 4`) | Adopted 5 October 2026, spec 05 section 5.11 |
|
|
| Record window | 600 DAA s (`recordWindow` 0x258) | 600 | A record older than this is not paid; bounds the pool and the by-number history |
|
|
| Dust for eligibility | 5 blue blocks in the window (devnet), 100 (mainnet) | 100 | W3 of spec 03; a key below dust is never drawn |
|
|
| External job bond | none implemented (phase 4) | `maxPgas x f_p x 1.5` escrow with a 3,600-block expiry and full refund (design 4.6) | O-5.6 keeps the number; the premium 1.5 is a parameter open |
|
|
| Claim timeout, external jobs | none implemented | 120 s | The economy simulator's lever study (`docs/analysis/economy-2026-10-04.md` section 6): a market parameter, 120 s keeps jobs on 24 GB cards |
|
|
|
|
Execution and the 30-s lock never wait for a proof (unchanged); the cost of a griefed shard is proof latency, one window per absent assignee at most. Decision owner for the testnet values: the project lead (O-5.1, O-5.6).
|
|
|
|
Answer: The bond is slashed and the shard reopens; the proving fee rises until someone proves it (security model table, "Prover cartel withholding proofs"). The open parameters are the bond size, the timeout, and whether an un-proven block delays only the proof (it does; execution and the 30-second lock do not wait for the proof). Set in phase 4.
|
|
|
|
Evidence: design doc, Security model table row 3.
|
|
|
|
### P10. External jobs are paid off-chain, so where is the burn
|
|
"The Economics section says every outside customer pays in IGN and part is burned. The miner section says rollups pay in their own money and the income does not move with the IGN price. Both cannot be true."
|
|
|
|
Status: Conceded, stated (5 October 2026, night): `site/litepaper.html`, Economics, "Outside customers pay in their own currency on their own chain at launch; settlement in IGN with a 10% burn follows when the proof bridge lets Igneum see the payment"; the route table rows 4 and 5 (E13). Was: Conceded, contradiction to fix.
|
|
|
|
Answer: The litepaper contradicts itself. The design is: at launch external jobs are paid on the customer's chain, in the customer's currency, to a payout contract keyed by miner address, because Igneum cannot yet see Ethereum. The 10% burn in IGN applies when the job market settles on Igneum, which needs the proof bridge. The Economics section must say so.
|
|
|
|
Evidence: design doc "The first six months" risk item and hostile review table row "Slashing an external prover". Fix: overclaims list, item 55.
|
|
|
|
Sweep (5 October 2026, evening): stated. `site/litepaper.html`, Economics first paragraph (overclaim 52) and Proving, "Proving for everyone else": jobs paid on the customer's chain at launch, IGN settlement with the 10% burn when the proof bridge lands in phase two; "Where fees go" says "once they settle on Igneum"; the job market labelled Designed.
|
|
|
|
---
|
|
|
|
### P24. "20 percent of emission to provers" without the caveat that consensus does not verify the proof
|
|
"Your 20 percent pays whoever submits a proof record whose statement matches the node's own execution. The node never checks the SP1 proof behind it. So the block producer, who writes the record, can claim shard pay with a false proof today, in proportion to its hash. Say so next to the 20 percent."
|
|
|
|
Status: Conceded, stated (6 October 2026, evening; the Horizon security lane `docs/analysis/horizon/consensus-security.md` finding 3 and its proposal 1): `site/litepaper.html`, Economics, the 20% proving-pool row carries the caveat: consensus does not yet verify the carried proof, it checks the record's statement against native execution and its signature, so today a block producer could claim shard pay with a false proof (ledger P21; the in-consensus verifier is the 0.3.16 fix).
|
|
|
|
Answer: Correct; it is P21's finding read from the payer's side. The fix is the security lane's proposal 1: a record whose aggregated segment proof does not verify against the pinned aggregator key is invalid in consensus; the per-shard v0 record stays payout-only until then and is capped at the exclusive window. Consequence per tier: no honest miner loses anything today, since the pool is paid per valid record and the devnet's producers are the project's; the risk is a dishonest producer at the public testnet, which is why the fix lands in 0.3.16, before it.
|
|
|
|
Evidence: `docs/analysis/horizon/consensus-security.md` finding 3 and proposal 1, 6 October 2026; spec 07 7.7 item 4 and 7.8 item 8; ledger P21.
|
|
|
|
### P25. Unclaimed pool credit is stranded in the escrow
|
|
"Spec 5.3 pays the first valid proof included in a block; 7.7 refuses a record older than 600 chain blocks; 7.8 says an unproven segment's aggregator share stays in the escrow. Nothing says what happens to the shard credit nobody claims. It sits there for ever. A ten-day refusal strands millions of IGN."
|
|
|
|
Status: Conceded, stated (6 October 2026, evening; the Horizon economy lane `docs/analysis/horizon/economy-and-utility.md` section 4.2 and proposal 2): `site/litepaper.html`, Economics, the 20% proving-pool row carries the note: unclaimed pool credit is today stranded in the escrow, no rule returns it; the fix rolls an unproven shard's credit into the next proven segment's pool (0.3.16).
|
|
|
|
Answer: Correct. The lane's simulation puts a ten-day refusal at 5.5 M IGN stranded (section 4.2: the pool share paid falls to 0.67 with 0.33 stranded during the refusal, 182,387 IGN a day averaged); the devnet already burns the coinbase's 20% output at an unspendable script, so nothing is lost that was ever claimable today. The rule: an unproven shard's credit rolls forward into the next proven segment's pool instead of sitting in the escrow. Consequence per tier: a prover sees a larger pool after a refusal instead of a smaller one; nothing changes for a miner or a pool user.
|
|
|
|
Evidence: `docs/analysis/horizon/economy-and-utility.md` section 4.2 (the stranded share) and proposal 2, 6 October 2026; spec 5.3, 7.7 item 3, 7.8 item 7.
|
|
|
|
## 4. Economics and the coin
|
|
|
|
### E1. Hard cap plus burn is a security budget cliff
|
|
"Monero chose tail emission so miners are paid for ever. You chose a 4 billion cap, halvings every two years, and you burn fees on top. By year twelve emission is under 1% a year and shrinking. Who pays for hashrate then?"
|
|
|
|
Status: Conceded by decision, stated in the design doc.
|
|
|
|
Answer: True, and the design doc records the choice: "A 1% tail is the Monero model and the safer choice for security on its own." The argument for the cap is that Igneum miners keep earning from in-chain proving fees and external jobs after emission fades, which Monero's miners cannot, and that a hard cap is the number miners trust. Emission in years 9 and 10 is 62.5 million IGN a year, 1.6% of supply; in years 11 and 12 it is 31.25 million, 0.8%. Bitcoin's inflation at its own year 10 was about 3.7%, approximate. Whether fee income replaces emission is unknowable today. A tail could be added by a 90% miner-signalled upgrade; nothing in the design prevents it.
|
|
|
|
Evidence: design doc "Decision: hard cap". Litepaper: "Supply" section states the cap, not the trade-off.
|
|
|
|
Cross-reference (external review, 3 October 2026, night): the budget through halvings at low fees, no demand and a flat price is modelled under E15, O-5.11.
|
|
|
|
### E2. Half the coins in two years is an insider schedule
|
|
"Nearly a quarter of supply in year one, half by year two, founders mining from genesis with the software they wrote and a month's head start on the benchmark. That is a premine with a GPU."
|
|
|
|
Status: Answered by design, with the founder's edge conceded.
|
|
|
|
Answer: The schedule (1 billion a year halving every two years, 30-day ramp from 10% to 100%) is public, fixed at genesis and the same for every miner. The founders' only edge is familiarity with software that is public a month before launch with pools live on testnet. The founders mine from disclosed addresses, which nobody else is asked to do. What this does not answer is that early adopters of any fair launch hold a disproportionate share, as on Bitcoin and Kaspa. The litepaper says "the people who show up early get the most", which is both true and a sentence a lawyer will read twice (see L2).
|
|
|
|
Evidence: litepaper "Supply" and "Fair launch, announced".
|
|
|
|
### E3. The 20% developer share enables wash gas
|
|
"Deploy a contract, spam it with your own transactions, collect 20% of your own priority fee back. If you also mine the block you collect all of it."
|
|
|
|
Status: Answered by design, with a metrics caveat.
|
|
|
|
Answer: The base fee is burned in full, so every wash transaction loses its whole base fee. Of the priority fee a developer alone gets back 20% and loses 80%. A developer who also mines the block including its own transaction gets 80% plus 20%, the whole priority fee, and still loses the full base fee in both gas dimensions. Wash gas is a guaranteed loss. What it can do is inflate an app's "gas earned" figure on a leaderboard at a cost of 20% of the priority fee, so no explorer ranking should be built on raw developer share without a self-dealing filter. Attribution is per call frame by gas consumed, with factory-deployed contracts inheriting the factory's registration.
|
|
|
|
Evidence: design doc Finality v2 "Fees"; litepaper "What a builder gets for being early".
|
|
|
|
### E4. 5% of gas to the dev fund is a tax
|
|
"You say 100% of emission to miners, then take 5% of gas. Users are taxed instead."
|
|
|
|
Status: Closed by removal, 3 October 2026.
|
|
|
|
Answer: There is no development fund. The 5% of the priority fee and 5% of external job fees that earlier drafts routed to a fund contract under 60% miner signalling were removed on 3 October 2026. A switch that routes money to an address somebody controls is the first thing a critic points at, however it is gated, so the protocol carries no fee to any team, foundation or fund. The priority fee now splits 80% to the miner and provers of the block and 20% to the apps whose code ran; external jobs pay 90% to the provers who delivered and burn 10%. The team earns in the open by running provers in the job market and by the app share on the contracts it deploys. A grant mechanism can be added by miner signalling later if the community wants one.
|
|
|
|
Evidence: spec section 5.5; design doc "No development fund, so nothing to fight over". Fix: none outstanding; overclaims item 53 closed.
|
|
|
|
### E5. "Not one coin to a founder" is false
|
|
"The official miner carries a 1% dev fee to the founder's company. That is 1% of all hashrate paid to one company for as long as miners run it, which is a founder allocation with better PR."
|
|
|
|
Status: Conceded, stated (5 October 2026, night): `site/litepaper.html`, Economics, "No fund, no foundation, no fee to the team", "1 block in 100 pays the project"; `site/index.html`, Economics, "The one payment to the project is the Ember software's optional 1% dev fee". Was: Conceded, partly stated, homepage overclaims.
|
|
|
|
Answer: Correct in substance. The litepaper discloses the 1% dev fee and says any other client is welcome. The homepage says "Not one coin to a founder, a fund or a stake", which is true of emission and false of the dev fee. There is no development fund (removed 3 October 2026) and no protocol fee to the team; the team earns from the client dev fee, its pool, its provers in the job market and the app share on contracts it deploys, all in the open. All of that must be in one place in the litepaper under a heading a critic can quote.
|
|
|
|
Evidence: design doc "No development fund, so nothing to fight over". Fix: overclaims list, item 63.
|
|
|
|
Sweep (5 October 2026, evening): stated. `site/litepaper.html`, Economics, "No fund, no foundation, no fee to the team": the full list of what the project earns (the 1% Ember dev fee first, its provers, any pool, the app share), none of it in the protocol, "1 block in 100 pays the project" as the quotable line; precedents table row 5 says the same. `site/index.html`, Economics: the closing line names the dev fee beside "no fee to any team in the protocol". No company is named (fud-fixes row 8).
|
|
|
|
### E6. Two-year halvings bleed hashrate
|
|
"Every GPU coin that halved fast lost its miners at the second halving. You halve every two years for ever."
|
|
|
|
Status: Conceded, stated (5 October 2026, night): `site/litepaper.html`, Economics, Security after the subsidy, "The schedule is a bet, not a measurement: a halving halves emission income overnight if price and fees do nothing", with Kaspa's reduction marked approximate. Was: Conceded, no experiment possible.
|
|
|
|
Answer: True that a halving halves emission income overnight if price and fees do nothing. The schedule was chosen for the cap and for front-loading the fair launch. Kaspa's smooth monthly reduction is a precedent for a steep schedule that kept hashrate while price rose (approximate). Igneum's in-chain proving pay does not halve with emission since it is paid from gas as well. Nothing here is a measurement; it is a bet, and the litepaper should present it as one.
|
|
|
|
Evidence: none; decision in design doc "Supply".
|
|
|
|
### E7. No stablecoin liquidity without a trusted bridge
|
|
"USDC and USDT 'bridged through the proof bridge at genesis'. The bridge needs a consensus proof you have scoped as phase two. So genesis stablecoins either wait or run on a multisig you said you would never have."
|
|
|
|
Status: Decided (3 October 2026). Spec section 7.3: no bridged stablecoins at genesis, no bridge is called official, anyone may run one at their own risk, the proof bridge arrives with the consensus proof in phase two. Overclaims 38, 40 and 71 applied. Was: Open, design decision scheduled.
|
|
|
|
Answer: Correct. The Ethereum-side bridge contract verifying Igneum state at launch has to verify a lock certificate, which means knowing the voter set and weights; that is the consensus proof scoped as phase two. Options: a committee-attested bridge at launch, clearly labelled as such, with the proof bridge replacing it; or no bridged stablecoins at genesis. The litepaper must stop presenting the proof bridge as a genesis feature until the decision is made. Phase 4.
|
|
|
|
Evidence: design doc, hostile review table row "One-proof light clients and committee-free bridges". Fix: overclaims list, item 71.
|
|
|
|
### E8. Founders seeding the DEX is market making by insiders
|
|
"The founders seed the DEX with their own mined coins. That sets the first price and they hold the first liquidity."
|
|
|
|
Status: Conceded, stated.
|
|
|
|
Answer: True and stated in the litepaper. Mined coins are the only coins the founders can hold. The addresses are disclosed, so the seeding is visible. Whether to do it at all is a question for counsel (L1, L2).
|
|
|
|
Evidence: litepaper "Liquidity from the people who are there".
|
|
|
|
---
|
|
|
|
### E19. "Proving: a second income" without the arithmetic of how small it is
|
|
"You sell proving for other chains as the income that keeps cards on after the subsidy fades. Put a number on it. All of Ethereum L1's proving today costs tens of dollars a day. Your year-1 emission is tens of thousands a day at any price you dare print. Say which one pays the bills."
|
|
|
|
Status: Conceded, stated (6 October 2026, evening; the Horizon lane analysis `docs/analysis/horizon/frontier.md` section 3.11, `frontier_model.py` section 7): `site/litepaper.html`, "For miners", under the three-streams table: all of Ethereum L1's proving is about USD 36 a day at the September 2026 tracker cost (USD 0.005 a block x 7,200 blocks; the tracker figure is a secondary source) against about USD 13,700 a day of Igneum's year-1 emission at USD 0.005 per IGN (31.688 IGN a block x 86,400; the price is an input, not a forecast), so external proving is a small second income at launch and the lottery pays the bills; paid demand would have to grow about 1,000x in dollars for proving to become the main income. Figures the lane labels approximate (all rollup proving spend, USD 8,200 to 27,400 a day; Boundless's trailing day, USD 2) are not on the page.
|
|
|
|
Answer: Correct. The whole public proving market is three to four orders of magnitude under year-1 emission at any price input (the lane's table: Ethereum L1 at the Sep 2026 cost USD 36 a day, at the Dec 2025 cost 288; year-1 emission 13,700 at USD 0.005, 54,800 at 0.02, 273,800 at 0.10). The cost curve falls 3x to 30x a year, so dollars per proof fall as fast as volume rises. The design's own claim stays the defensible one: a second income that keeps cards on after the subsidy fades (spec 5.10.2), never the main one by 2030.
|
|
|
|
Evidence: `docs/analysis/horizon/frontier.md` section 3.11 and the summary (section 7), 6 October 2026; the tracker (ethproofs, "sub-half-cent" fields, September 2026, secondary); the emission schedule (31.688 IGN a block in year 1).
|
|
|
|
### E20. "Proofs at the cost of power" is the electricity, not the price
|
|
"Your cards' electricity is cheap, fine. The price a prover must charge is the lottery income it gives up while it proves, and that scales as one over the network's hash. At your devnet's 1.16 GH/s every quote is a hundred times the market. 'Marginal cost close to power' and 'priced in dollars per proof' are both unconditioned."
|
|
|
|
Status: Conceded, stated (6 October 2026, evening; the Horizon economy lane `docs/analysis/horizon/economy-and-utility.md` sections 3.1 and 4.1, proposal 3): `site/litepaper.html`, The problem ("a supplier whose electricity cost is close to power and whose price is the subsidy it forgoes, which falls as the network's hash grows"), Building on Igneum ("Proofs priced by the subsidy forgone", with the price as a formula in network hash: per shard, card hash over network hash x 0.8 x 31.688 IGN x shard seconds, plus electricity; 100 to 300x the published market rate at 1.16 GH/s, competitive near 100 GH/s beside the miner, approximate beyond the one card measured), the payment-routes row 4 ("at or above the subsidy the prover forgoes ... never a fixed number"), For miners, Economics and the questions list. The price is published as a formula, never a number. Supersedes P6's stated sentence ("a supplier whose marginal cost is close to power"), which the text check now carries in the conditioned form.
|
|
|
|
Answer: Correct. Electricity is under a cent per billion cycles on every card; the price is `h/N` x the subsidy per shard. At 100 GH/s a card proving alone is at 1 to 3x the published market and a card beside its miner at 0.2 to 0.4x, the only row where Igneum undercuts the market, and it rests on the 4% hash loss measured on one card. Consequence per tier: at launch a home miner earns more hashing than proving for outsiders at any card size; a rig the same; the proving market is upside for the fleet as a whole only as network hash grows.
|
|
|
|
Evidence: `docs/analysis/horizon/economy-and-utility.md` sections 3.1 (the cost model), 4.1 (the table per card and scale) and proposal 3, 6 October 2026; the Boundless median of USD 0.21 per billion cycles (`developer-adoption.md` 2b, approximate).
|
|
|
|
### E21. The dev fee is 1 percent of the producer share, and the funding plan's ceiling took all rewards
|
|
"Your funding plan says the 1 percent fee could be USD 48,000 to 963,000 a year on year-one rewards of 963 million IGN. The fee template only moves the producer payout. The pool is paid per record. Your ceiling is a quarter too high, and the litepaper never says which share the fee is of."
|
|
|
|
Status: Conceded, stated (6 October 2026, evening; the Horizon economy lane `docs/analysis/horizon/economy-and-utility.md` section 4.4 and proposal 7): `site/litepaper.html`, the payment-routes row 6 and the Ember section read "default-on, switchable, 1 percent of the producer share"; `docs/plans/funding.md` section 4's ceiling is 1 percent of the producer share, USD 38,520, 154,080 and 770,400 a year at USD 0.005, 0.02 and 0.10 per IGN with every miner on the official client, corrected from 48,000, 193,000 and 963,000.
|
|
|
|
Answer: Correct. The fee block carries the dev address in the producer output only; the 20% pool output and the per-record escrow are untouched, so the fee's base is 80% of emission. Consequence per tier: a miner on Ember with the fee on gives up 1 in 100 of its own block rewards and nothing of its proving pay; off with one flag, the same on every tier.
|
|
|
|
Evidence: `docs/analysis/horizon/economy-and-utility.md` section 4.4 (`devfee_out.md`) and proposal 7, 6 October 2026; the fee measured on a test network, 4 October 2026 (bench-log: 9 fee blocks in 785).
|
|
|
|
## 5. Governance and the founders
|
|
|
|
### G1. No cryptography team
|
|
"One founder. The design doc says phases one and two 'need one cryptographer or proof-systems engineer' and none is named. The reviewers for gate 3 are 'named' in the litepaper and nobody is named."
|
|
|
|
Status: Conceded, stated (5 October 2026, night): `site/litepaper.html`, Questions miners ask, "reviewers will be named and paid before gate 3"; What Igneum does not claim, "A cryptography team. Not yet". Was: Conceded, not yet stated in the litepaper.
|
|
|
|
Answer: Correct. No cryptographer has been hired. The litepaper's gate 3 refers to "named reviewers" who do not yet exist. The honest text is: the specification is written for external review; reviewers will be named and paid before gate 3; until then every security claim here is a design claim. The hostile reviews so far were run by the founder with AI assistance (G2).
|
|
|
|
Evidence: design doc "Team" paragraph. Fix: overclaims list, item 50.
|
|
|
|
Sweep (5 October 2026, evening): stated. `site/litepaper.html`, Questions miners ask, the finality answer (overclaim 48): reviewers will be named and paid before gate 3, every finality claim a design claim until then. "Who are you?" and "What Igneum does not claim" ("A cryptography team"): no cryptographer hired, one budgeted for phases 1 and 2.
|
|
|
|
### G2. An AI designed this
|
|
"The repo has `.claude/agents/cryptographer.md`. The commits are co-authored by a language model. The 'hostile review' was a chatbot role-playing a Kaspa researcher."
|
|
|
|
Status: Conceded, stated (5 October 2026, night): `site/litepaper.html`, cover, "Method one founder with AI systems"; Who are you?, "One founder, pseudonymous, working with AI systems". Was: Conceded, not yet stated in the litepaper.
|
|
|
|
Answer: True. The design, the reviews, the prototype code, the simulator and this ledger were produced by the founder working with AI models, and the commit history says so. What that does and does not mean: the measurements are measurements, reproducible from the commands in the logs; the simulation is code anyone can run; the design claims are design claims until external humans with names have tried to break them. The litepaper should disclose the method in one sentence and let the measurements stand on their own.
|
|
|
|
Evidence: `.claude/agents/`, commit trailers. Fix: add a disclosure sentence (overclaims list, item 73).
|
|
|
|
Sweep (5 October 2026, evening): stated. `site/litepaper.html`, cover meta line "Method: one founder with AI systems, external review before gate 3" (overclaim 72) and the "Who are you?" paragraph: one pseudonymous founder working with AI systems produced the design, the reviews, the code, the simulators and the document, the commit history says so, measurements are reproducible, design claims stay design claims, the criticism ledger exists with its conceded entries and is published with the node repository. No names. Decisions for the project lead: whether this ledger is published with the repository (G11), and whether the team page at public testnet names anyone (fud-fixes row 9).
|
|
|
|
### G3. Who are you
|
|
"Anonymous founder, GoDaddy domains, a Vercel site, a litepaper dated the same day as five 'milestones'. This is a template."
|
|
|
|
Status: Decided (5 October 2026): no team page for now; the litepaper says the team is pseudonymous and names no team page. Stated (5 October 2026, night): `site/litepaper.html`, Who are you?, "The team is pseudonymous and there is no team page". Was: Conceded, team page deferred by decision.
|
|
Decision owner (5 October 2026, evening sweep): the project lead (the team page at public testnet, fud-fixes row 9).
|
|
Was: Status: Conceded, team page deferred by decision. Decided 5 October 2026: no team page for now; the litepaper says the team is pseudonymous and names no team page.
|
|
|
|
Answer: The founder's name is on every commit. The litepaper defers the team page to public testnet by decision, with disclosed mining addresses at genesis. There are no coins to sell and no sale planned, so there is nothing to run away with before block one. The five log entries dated 3 October 2026 are day one of the project and should be presented as that.
|
|
|
|
Evidence: design doc, decisions table row "Who are you?". Journey: `site/journey.json`.
|
|
|
|
### G4. No admin keys, except in everything that matters
|
|
"'There are no admin keys.' The DEX, the lending market, the bridge and the dev fund contract all ship from your team. Bridges are where the admin keys live."
|
|
|
|
Status: Conceded, stated (5 October 2026, night): `site/litepaper.html`, Governance, "There are no admin keys in consensus"; `site/index.html`, tile "admin keys in consensus". Was: Conceded, wording fix needed.
|
|
|
|
Status: Conceded, stated (6 October 2026, later that night): the home page was restored to its fuller shape on the owner's word ("revert it but polish it") and carries the tile "admin keys in consensus" again, beside the litepaper's Governance sentence.
|
|
|
|
Status: Conceded, stated (6 October 2026, night): the home page was redrawn as one statement, the live scene, three facts and the downloads, so the tile "admin keys in consensus" is no longer on `site/index.html`; the sentence stands on `site/litepaper.html`, Governance ("There are no admin keys in consensus"). The 5 October line below is the history.
|
|
|
|
Answer: Correct. Consensus has no admin keys. The genesis apps are contracts and each will have an upgrade policy; the bridge's is the one that matters, and if it starts as a committee bridge (E7) it has keys by definition. The development fund contract named in the quote no longer exists: the fund was removed on 3 October 2026. The litepaper's sentence must be scoped to consensus and each genesis contract must publish its key policy before launch.
|
|
|
|
Evidence: litepaper "Governance". Fix: overclaims list, item 46.
|
|
|
|
Sweep (5 October 2026, evening): stated. `site/litepaper.html`, Governance bullet "There are no admin keys in consensus", the genesis apps' key policies before launch, label Designed, O-5.4 (overclaim 45 without the fund contract); `site/index.html` tile "0 admin keys in consensus".
|
|
|
|
### G5. No multi-client
|
|
"One node implementation, a rusty-kaspa fork with a zkEVM bolted on. A bug is a chain halt. Ethereum learned this in 2016."
|
|
|
|
Status: Conceded, stated in the litepaper.
|
|
|
|
Answer: True at launch. The litepaper names a second independent client as the first priority after launch; there is no development fund to pay for it (removed 3 October 2026), so whoever builds it pays for it. The finality module is separable and the chain runs on plain GHOSTDAG without it, which contains one class of bug. A second client before mainnet is not in the 13-month plan and the litepaper should not imply it is.
|
|
|
|
Evidence: litepaper "Governance", last bullet.
|
|
|
|
### G6. Stratum v2 does not make pools unable to censor
|
|
"Job declaration in Stratum v2 is optional for pools. 'Pools cannot censor' is false. And the vote key stays with the pool regardless."
|
|
|
|
Status: Conceded, stated (5 October 2026, night): `site/litepaper.html`, Governance, "Pools can be bypassed on transaction choice". Was: Conceded, wording fix needed.
|
|
|
|
Answer: Correct. Stratum v2 job declaration lets a hasher choose transactions when its pool supports it, and the official pool software will support it. Pools can still decline, and the vote key in the header is the pool's. The sentence becomes "Pools can be bypassed on transaction choice" with the vote-key caveat.
|
|
|
|
Evidence: none in repository. Fix: overclaims list, item 45.
|
|
|
|
Cross-reference (external review, 3 October 2026, night): whether members use declared templates is measured under O-9.5; concentration reporting is X14.
|
|
|
|
Sweep (5 October 2026, evening): stated. `site/litepaper.html`, Governance bullet "Pools can be bypassed on transaction choice", a pool may decline, vote keys stay with the pool, label Designed with spec section 9 (overclaim 44).
|
|
|
|
### G7. The one-click app is an update key over the network
|
|
"An app that auto-updates on ten thousand machines is an admin key. Whoever signs the update controls the miners, the wallets the app made, and the vote keys."
|
|
|
|
Status: Decided (3 October 2026). Spec section 8 (8.1 to 8.3): reproducible builds with hashes in the repository, every release signed by the key published in genesis and held in hardware, the client refuses a mismatched signature, no silent updates, consensus never changes through the app. Was: Open, policy scheduled.
|
|
|
|
Answer: Correct. The update channel is a key and will be named as one: signed, reproducible builds with published hashes; no silent updates; the app refuses an update whose signature does not match the key published at genesis; the key is held in hardware and its policy published. Consensus rules never change through the app, since activation needs 90% of blocks signalling. Phase 5.
|
|
|
|
Evidence: not yet.
|
|
|
|
### G8. Governance by hashrate is governance by two pools
|
|
"90% of blocks to activate an upgrade, 60% to spend the fund. Two pools decide both."
|
|
|
|
Status: Conceded, stated in the design doc.
|
|
|
|
Answer: True in the same way it is true on Bitcoin, where miner signalling activated SegWit and Taproot. The thresholds are high so that nothing passes without near-consensus. Since 3 October 2026 there is no fund to spend: the 60% threshold applies only to parameters that the genesis rules leave to miners, and 90% to upgrades. The litepaper should name pool concentration as the governance risk rather than imply every miner votes.
|
|
|
|
Evidence: design doc Finality v2, Residual risks bullet 3.
|
|
|
|
---
|
|
|
|
### G15. Three signalling thresholds, four numbers across the documents
|
|
"Spec 5.7 says 90 percent for an upgrade, 5.5 says 60 percent for a parameter, the class-change rule says 95 with a floor, the project rules file says 90 and 60, and the litepaper's Mining section says a 90 percent signal turns a spare defence on, which is a class change your own rule sets at 95. Pick one sentence and put it everywhere."
|
|
|
|
Status: Conceded, stated (6 October 2026, evening; the Horizon economy lane `docs/analysis/horizon/economy-and-utility.md` proposal 4, lane 3's signalling results): one sentence in `site/litepaper.html`, Governance ("Miners set what genesis leaves open") and Mining ("Miners hold the switch"): miners signal three things at three thresholds, 60 percent of blue blocks over two weeks for a parameter genesis leaves open, 90 percent for an upgrade (new code), and 95 percent with a floor height for a class change. The project rules file carries the same sentence (the coordinator's commit of 6 October 2026). Spec 5.5 (60) and 5.7 (90) agree with it; the 95-with-floor rule is the class v4 cut's P2 rule.
|
|
|
|
Answer: Correct. The three numbers are three different things: a parameter is a dial inside rules genesis fixed, an upgrade is new code every node must run, a class change moves the hash itself and so takes the highest bar with a floor height as the backstop against a holdout. The lane's game (section 4.3): a 6 percent holdout costs near zero and buys only delay to the floor; a 30 percent pool holds a veto over upgrades at 90 and over class changes until the floor.
|
|
|
|
Evidence: `docs/analysis/horizon/economy-and-utility.md` section 4.3 and proposal 4, 6 October 2026; spec 5.5, 5.7, 5.8; the class v4 cut's status file (gates P1 and P2).
|
|
|
|
## 6. Comparisons
|
|
|
|
### C1. vs Monero: GPUs were excluded on purpose
|
|
"RandomX runs badly on GPUs because a GPU is already specialised hardware that most people do not own. 'Monero's idea, finished for GPUs' misses the point of Monero's idea."
|
|
|
|
Status: Answered by design.
|
|
|
|
Answer: Monero chose the CPU for egalitarian reasons and accepted botnets as the price. Igneum chooses the GPU because the thesis is paid proving, which CPUs cannot do, and refuses a CPU lane because of botnets. It is a different trade, and the litepaper should say "Monero's technique, applied to GPUs" rather than "finished".
|
|
|
|
Evidence: litepaper "For miners", hardware paragraph. Wording: overclaims list, item 74.
|
|
|
|
### C2. vs Monero: "no chip in seven years" is not proof
|
|
"Absence of a public RandomX ASIC is not evidence one cannot exist. Monero is also a small prize."
|
|
|
|
Status: Conceded, stated (5 October 2026, night): `site/litepaper.html`, Mining, "no chip publicly shipped, approximate" and "Monero is precedent, not proof"; `site/index.html`, hero, "a chip gains too little to take your place". Was: Conceded, label needed.
|
|
|
|
Status: Conceded, stated (6 October 2026, later that night): the restored home page carries the RandomX paragraph again, "since 2019 (approximate)", beside the litepaper.
|
|
|
|
Status: Conceded, stated (6 October 2026, night): the home page no longer carries the RandomX paragraph; "since 2019 (approximate)" and "precedent, not proof" stand on `site/litepaper.html` (vs RandomX, Mining). The 5 October line below is the history.
|
|
|
|
Answer: True. "No chip publicly shipped, approximate" is the defensible phrasing. The argument from Monero is precedent, not proof, and the bounty exists because precedent is not proof.
|
|
|
|
Evidence: none. Fix: overclaims list, item 17.
|
|
|
|
Sweep (5 October 2026, evening): stated. `site/litepaper.html`, Mining: "no chip publicly shipped, approximate", Monero as precedent not proof, the 2x figure labelled Target; vs RandomX "Track record" row; the cover, abstract, glance figure and limits chip lines (overclaims 1, 2, 13, 17, 18, 19, 50). `site/index.html`: hero (59, 63) and the RandomX intro (67, "since 2019 (approximate)").
|
|
|
|
### C3. vs Kaspa: you misrepresent them
|
|
"Kaspa never claimed ASIC resistance and did not get 'captured'. It also has 10 bps in production and a GHOSTDAG you are forking. Say thank you."
|
|
|
|
Status: Conceded, stated (5 October 2026, night): `site/litepaper.html`, The problem, "Chips arrived, as on Kaspa, whose hash was designed to welcome them"; Speed, "Kaspa has run in production since 2021 (approximate), forked from rusty-kaspa"; precedents row 5, "Kaspa's fair launch." with no "with no utility". Was: Conceded, wording fix.
|
|
|
|
Answer: Correct on both counts. kHeavyHash was built to be hardware-friendly and Kaspa's ASIC transition was expected by its community (approximate). The litepaper's "captured by specialised chips within two years, as Kaspa was" and "Kaspa's fair launch, with no utility" are unfair and will be rewritten. Igneum forks rusty-kaspa and borrows the block-rate step plan from Crescendo; the litepaper should credit both.
|
|
|
|
Evidence: none in repository; `vendor/rusty-kaspa` to be cloned and cited. Fix: overclaims list, items 8, 11, 29 and 49.
|
|
|
|
Sweep (5 October 2026, evening): stated. `site/litepaper.html`, The problem: "Chips arrived, as on Kaspa, whose hash was designed to welcome them" (overclaim 11); Speed: GHOSTDAG "Kaspa has run in production since 2021 (approximate), forked from rusty-kaspa" with the block-rate step plan credited (29); precedents table row 5 drops "with no utility" (8); "Built on the shoulders" credits the step plan. Citations from the repositories stay fud-fixes row 49.
|
|
|
|
### C4. vs Kaspa: a finality overlay changes GHOSTDAG's guarantees
|
|
"GHOSTDAG's safety comes from blue work. A certificate that overrides blue work and a pruning point that never passes the latest lock are changes to the security model, not features on top."
|
|
|
|
Status: Measured on the live node line, and the overlay does NOT do what the spec says at a heal: a NEW SERIOUS FINDING (5 October 2026, evening sweep; owner: cryptographer and consensus engineer, decision owner the project lead). Was: Open, experiment scheduled. Sweep (5 October 2026): the overlay has now run on a real DAG (cloud devnet, 4 October): with the module on, two partitions produced 0 conflicting locks, the 15.8% side locked nothing, the 84.2% side locked every interval, and the minority reorganised 423 to 496 blocks at the heal and adopted the majority's certificates within 15 s; the same day's F21 finding (a long honest partition locks alone from day 10 at 50/50) is the one real change to GHOSTDAG's guarantees found so far, and rule v3 answers it. The module-off comparison and the trace-driven adversary of O-3.8 are still owed.
|
|
|
|
Answer: True. Among candidate tips (those passing through every certified checkpoint) GHOSTDAG selects by blue work under the 3,600-second merge-depth bound; a certified checkpoint removes other tips from candidacy. That is a change, and its interaction with pruning, with red blocks in the attacker's weight and with latency is exactly what the gate 3 devnet measures. The module is separable so GHOSTDAG alone remains the fallback.
|
|
|
|
Evidence: design doc Finality v2, Fork choice items 1 to 4; `sim/results.md` final section.
|
|
|
|
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).
|
|
|
|
### 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."
|
|
|
|
Status: Conceded, stated (5 October 2026, night): `site/litepaper.html`, Speed, "Inclusion is not confirmation on either chain". Was: Conceded, wording fix.
|
|
|
|
Answer: The numbers are approximately right and the framing is loose. Inclusion is not confirmation on either chain; Igneum's two-minute lock is a committee-of-miners finality with the limits in F4 and F6; Ethereum's finality is economic with slashing. The sentence should state both sides' mechanism, not just the minutes.
|
|
|
|
Evidence: litepaper "Speed". Fix: overclaims list, item 30.
|
|
|
|
Sweep (5 October 2026, evening): stated. `site/litepaper.html`, Speed: inclusion in the DAG against an Ethereum slot, the miner lock against Ethereum finality marked approximate, "inclusion is not confirmation on either chain", both mechanisms named in one sentence, no cross-reference to this ledger (overclaim 30).
|
|
|
|
### C6. vs Ethereum: every one of your components is a research project
|
|
"A random-program hash with no analysis, a VDF, BLS sortition, STARK recursion on consumer cards, a 2D fee market, a DAG with EVM semantics. Ethereum has a thousand researchers and shipped these one at a time over a decade."
|
|
|
|
Status: Conceded, stated (5 October 2026, night): `site/litepaper.html`, Roadmap, "the combination is the risk the gates price" and "Dates slip. Gates do not." Was: Conceded, not yet stated.
|
|
|
|
Answer: True. Each component has a precedent in production somewhere (RandomX, Chia, Algorand and Ethereum for BLS and VRF, SP1, Kaspa) and no chain combines them. That is the risk the gates exist to price. The roadmap's four gates are kill points and the litepaper says so; it should also say the combination is the risk.
|
|
|
|
Evidence: litepaper "Roadmap".
|
|
|
|
Sweep (5 October 2026, evening): stated. `site/litepaper.html`, Roadmap intro: each piece has a precedent, no chain combines them, the combination is the risk the gates price; "Dates slip. Gates do not." before the phase-two sentence (overclaim 69).
|
|
|
|
### C7. vs Bitcoin: hashrate that follows price is the design, you penalise it
|
|
"Bitcoin's miners come and go with price and the chain is fine. Your 30-day weight under-weights every honest newcomer for a month and lets old miners lock alone for 20 days after a doubling."
|
|
|
|
Status: Conceded, stated in the simulation.
|
|
|
|
Answer: Correct. Table D: a new honest cohort equal to the old one reaches 0.9x its hashrate share on day 28 to 31, and the old cohort can lock alone for 20 to 23 days. The design accepts this because a doubling overnight is indistinguishable from a rental burst. Rewards are unaffected; only the vote waits. The litepaper should say "a new miner votes after a month".
|
|
|
|
Evidence: `sim/results.md` table D.
|
|
|
|
### C8. vs Ergo, Ravencoin, Conflux: GPU mining has a home
|
|
"Ergo has been GPU-mined since 2019 with no ASIC. Ravencoin runs KAWPOW. Conflux is a GPU-mined DAG with an EVM space since 2020. 'GPU mining has no home' is false and your firsts table skips all three."
|
|
|
|
Status: Conceded, stated (5 October 2026, night): `site/litepaper.html`, The problem, "Ergo, Ravencoin and Conflux still mine on GPUs at a fraction of the 2022 fleet (approximate)"; precedents row 3 names Conflux. Was: Conceded, not yet stated.
|
|
|
|
Answer: Correct. Those chains exist and run on GPUs today (approximate). The accurate claim is that GPU mining lost its Ethereum-scale home in 2022 and that none of those chains proves its blocks or sells proving. Conflux in particular (GPU, DAG, EVM) belongs in the firsts table as the closest precedent for the combination, and the litepaper must name it.
|
|
|
|
Evidence: none in repository; to be cited from their repositories. Fix: overclaims list, items 10 and 11.
|
|
|
|
Sweep (5 October 2026, evening): stated. `site/litepaper.html`, The problem names Ergo, Ravencoin and Conflux as the chains that stayed small, approximate (overclaim 11); the pull quote reads "lost its largest home" and "built to make it hard to take away" (10); precedents table row 3 names Conflux.
|
|
|
|
### C9. vs Aleo: you will centralise the same way
|
|
"Aleo tried proofs as consensus and the fastest prover won. You keep the lottery separate but the proving pool is still a race."
|
|
|
|
Status: Closed by rule (3 October 2026). Spec section 7.2, with P8. Was: Open, design change scheduled.
|
|
|
|
Answer: See P8. The separation protects block production from prover centralisation; it does not by itself protect the proving pool. Sortition of shards is the scheduled fix.
|
|
|
|
Evidence: design doc "Existing prover networks" table, Aleo row.
|
|
|
|
### C10. vs Boundless and Succinct: you cannot bid there without their tokens
|
|
"'The Igneum miner client also bids on other proving networks.' Boundless provers post collateral in ZKC and Succinct provers stake PROVE. Your miner needs to buy their tokens to bid. And they already have home GPUs, so 'cheapest supplier' is false."
|
|
|
|
Status: Conceded, stated (5 October 2026, night): `site/litepaper.html`, Proving for everyone else, "Boundless provers post ZKC and Succinct provers stake PROVE (approximate, from their documentation)". Was: Conceded, wording fix.
|
|
|
|
Answer: Correct on both points (approximate, from memory; verify against their current docs). The client can bid where a miner chooses to hold the collateral; the litepaper should not imply free entry, and "cheapest supplier" becomes "a supplier whose marginal cost is close to power".
|
|
|
|
Evidence: design doc "Existing prover networks" table, labelled approximate. Fix: overclaims list, items 12 and 58.
|
|
|
|
Sweep (5 October 2026, evening): stated. `site/litepaper.html`, Proving, "Proving for everyone else": the client bids elsewhere where a miner chooses to hold the collateral, Boundless ZKC and Succinct PROVE named and marked approximate; "cheapest" gone (overclaims 12, 58).
|
|
|
|
### C11. vs everyone: "firsts" that are not
|
|
"'A chain your browser verifies by itself' is phase two by your own doc. 'The GPU version never shipped' ignores KAWPOW. 'Finality immune to rentals' is 'not moved by rentals'. Three of your six firsts are wrong on day one."
|
|
|
|
Status: Conceded, stated (5 October 2026, night): `site/litepaper.html`, precedents table, "We know of no chain that combines them"; Building, "that we know no other EVM chain offers". Was: Conceded, table to rewrite.
|
|
|
|
Answer: Correct. The firsts table is rewritten in the overclaims list: each row states the closest precedent accurately, including ProgPoW/KAWPOW and Conflux, and marks the light-client row as phase two. The claim that stands is that no chain combines GPU mining, per-block ZK proofs, an EVM and a mining-weighted finality overlay, and the table should say "we know of none" and invite correction.
|
|
|
|
Evidence: this ledger. Fix: overclaims list, items 4 to 9.
|
|
|
|
Sweep (5 October 2026, evening): stated. `site/litepaper.html`: the firsts table is the precedents table, heading "Precedents, and what Igneum adds", id `firsts` kept, four columns (piece, closest precedent, what Igneum adds, state with Measured, Implemented or Designed), a sources line, "We know of no chain that combines them" and the invitation to correct (overclaims 4 to 9). "Three things ... run nowhere else" and "No other EVM chain" became "we know no other" (36, 37), "No other proof-of-work chain has a seat" likewise (28), "the one useful GPU workload" became "a useful" (24).
|
|
|
|
### C12. vs Monero: you borrowed the hash idea and left out the point
|
|
"Monero's idea is privacy. You took RandomX and shipped a transparent ledger. Calling it 'Monero's idea, finished' is cheek."
|
|
|
|
Status: Answered by design.
|
|
|
|
Answer: Transactions on Igneum are public, as on Ethereum. Privacy features and shielded pools were considered and rejected on 3 October 2026, because the chain's purpose is an EVM whose state is proven and sold to other chains, which needs public state. The litepaper borrows one technique from Monero, the random program, and should say so plainly rather than "Monero's idea".
|
|
|
|
Evidence: CLAUDE.md rules (privacy rejected). Fix: overclaims list, item 68.
|
|
|
|
---
|
|
|
|
## 7. Legal and regulatory
|
|
|
|
### 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 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.
|
|
|
|
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 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.
|
|
|
|
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: 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.
|
|
|
|
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, 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.
|
|
|
|
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, 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.
|
|
|
|
Evidence: none.
|
|
|
|
### L6. A permissionless job market paid in dollars is money transmission
|
|
"Rollups pay dollars for proofs through your contract and your client picks the winner."
|
|
|
|
Status: Answered by design.
|
|
|
|
Answer: At launch jobs are paid on the customer's chain, in the customer's asset, by the customer's contract, to the prover's address; Igneum operates no custody and takes no cut off-chain. When the market settles on Igneum the fee split is consensus, not a company. Counsel confirms before phase 4.
|
|
|
|
Evidence: design doc "The first six months".
|
|
|
|
---
|
|
|
|
## 8. Launch and community
|
|
|
|
### X1. "Reproducible from the repository" and the repository is private
|
|
"Your site links to github.com/igneum-network/igneum. It 404s. 'Every number above is measured, published, and reproducible from the repository' is false today."
|
|
|
|
Status: Conceded, stated (5 October 2026, night): `site/litepaper.html`, vs RandomX "Track record" row, "The specification, reference hash, test vectors and simulators are public now (github.com/igneum-network/spec). The node, the miner and the wallet are in a private repository until the public testnet". Was: Conceded, fix now.
|
|
|
|
Answer: Correct. Either the repository goes public with the litepaper or the sentence and the GitHub link come off the site until January 2027. Publishing the bench logs, the simulator and the test report with the litepaper is the cheaper fix and the honest one.
|
|
|
|
Evidence: `site/index.html` footer link; CLAUDE.md says private. Fix: overclaims list, item 22.
|
|
|
|
Cross-reference (external review, 3 October 2026, night): publishing the harnesses, vectors, simulators and spec now, labelled experimental, is G11, a decision for the project lead.
|
|
|
|
Sweep (5 October 2026, evening): stated. `site/litepaper.html`, vs RandomX "Track record" row: the specification, reference hash, vectors and simulators are public at github.com/igneum-network/spec (confirmed public, 5 October 2026); the node, the miner and the wallet are in a private repository until the public testnet. "Built on the shoulders": the provenance table is published at the public testnet. The nav and footer GitHub links already pointed at the public spec repository. Decision for the project lead: the date. This entry, `docs/evidence.md` and the fud-fixes list say January 2027 with the benchmark; the public text now says the public testnet, as instructed; the miners-ask answer still says the benchmark tool is public in January 2027, which holds for a binary.
|
|
|
|
### X2. "Get the miner" with no miner
|
|
"A big button that says 'Get the miner' on a chain with no miner, no testnet and no benchmark. Vapourware CTA."
|
|
|
|
Status: Conceded, stated (5 October 2026, night): `site/index.html`, hero button "See the miner"; the Mine section's download buttons carry the shipped devnet build's version and size (v0.3.9) beside "Public testnet: not yet open; the devnet build is here for people who want to look" and the devnet no-value line; a miner exists, so the premise is gone. Was: Conceded, fix now.
|
|
|
|
Answer: Correct. The button should say what exists: "Benchmark: January 2027".
|
|
|
|
Evidence: `site/index.html`. Fix: overclaims list, item 61.
|
|
|
|
Sweep (5 October 2026, evening): stated. `site/index.html`: hero "See the miner" and the job card "About the miner" (both to the Mine section), the Mine section button "Downloads open at the public testnet" with a line that the miner runs on a private devnet of invited machines whose coins have no value; `site/partials/nav.html` CTA "The miner" (/miner) and `site/partials/footer.html` "Miner downloads: public testnet", rebuilt into every page. `site/miner.html` and `site/wallet.html`: hero buttons "Downloads: public testnet", the Get sections retitled "at the public testnet" with "No download is open yet", the platform buttons relabelled "public testnet" (they still lead to the journey). Overclaim 60 in its 5 October form, since a miner now exists.
|
|
|
|
### X3. "Proven by fire" when nothing has run
|
|
"Tagline: Proven by fire. Status: pre-specification, pre-testnet. 'Watch the chain prove itself' with nothing on the page."
|
|
|
|
Status: Conceded in part, labelled, stated (5 October 2026, night): `site/index.html`, the sentence "All of it will be on this page, live" is no longer on the page; the proofs feed now ends "Live rows arrive with the public testnet, August 2027" (overclaim 61). Was: Conceded in part, labelled.
|
|
|
|
Status: Conceded in part, labelled, stated (6 October 2026, night): the proofs feed moved to the litepaper's proving section with the home-page redesign and reads "Live rows arrive with the public testnet. The public testnet is weeks away: three seed nodes and the public RPC are up, and it opens when the go checklist closes." (X31). The 5 October line below is the history.
|
|
|
|
Answer: The tagline plays on "proven" as in ZK proofs and "cupel". The homepage marks every live panel "PREVIEW", "prototype" or "at testnet", which is honest. The sentence "All of it will be on this page, live" is a promise about a future testnet and should say when. The tagline stays; nothing in the ledger depends on it.
|
|
|
|
Evidence: `site/index.html`. Fix: overclaims list, item 62.
|
|
|
|
### X4. Thirteen months with one founder
|
|
"Kaspa took years with a research team. You schedule a spec, a devnet, a finality review, a job market, a one-click app, pools, a rollup customer and a mainnet in thirteen months."
|
|
|
|
Status: Conceded, stated.
|
|
|
|
Answer: The roadmap is aggressive and every phase is a gate that can repeat or stop the project, which the litepaper says. The design doc budgets six people at peak and none are hired. The honest addition: dates slip, gates do not.
|
|
|
|
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: 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.
|
|
|
|
Answer: Correct. "Independent" needs a definition that can be measured: distinct ASNs, distinct hardware fingerprints from the benchmark, or signed attestations from pool operators. Defined in phase 4, before the gate is tested.
|
|
|
|
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."
|
|
|
|
Status: Decided (3 October 2026). Spec section 8 (8.4 and 8.5): notarised builds on every platform, downloads only from the domain and the repository with the hash beside the button, seed shown and confirmed before mining, hardware wallet option, and the permanent line "Nobody from Igneum will ever ask for your seed." wherever the app appears. Was: Open, policy scheduled.
|
|
|
|
Answer: Correct on all three. Mitigations: signed, notarised builds on every platform; reproducible builds with hashes in the repository; downloads only from the domain and the repository with the hash shown; seed phrase shown and confirmed before mining starts, with a hardware-wallet option; a published list of the only official download locations and a standing note that nobody from the project ever asks for a seed. Antivirus flagging is a known cost of shipping a miner and the app will document it. Phase 5.
|
|
|
|
Evidence: not yet.
|
|
|
|
### X7. No community exists
|
|
"No Discord, no forum, no mailing list, no contact address on the site, and a ledger that says 'criticisms can be submitted'. Where?"
|
|
|
|
Status: Conceded, stated (5 October 2026, night): this ledger's submission line names hello@igneum.network and the spec issues route; `site/litepaper.html` last paragraph and the footer on every page carry both. Was: Conceded, fix now.
|
|
|
|
Answer: Correct. The site needs a contact route before the litepaper is shared, and the repository needs to be public or a public issue tracker needs to exist. Until then this ledger's submission line points at a route that does not exist.
|
|
|
|
Evidence: `site/index.html` (no contact route). Fix: overclaims list, item 78.
|
|
|
|
Sweep (5 October 2026, evening): stated in part. `site/partials/footer.html` on every page: "Report a flaw" to github.com/igneum-network/spec/issues (the public repository has issues enabled, checked 5 October 2026); the last paragraph of `site/litepaper.html` says the same and that a mailbox follows. Decision for the project lead: the mailbox on the igneum.network Workspace (fud-fixes row 3). The submission line at the top of this ledger still names a route that does not exist and is left for the ledger's owner.
|
|
|
|
### X8. Exchange listings as a roadmap item
|
|
"'Mainnet fair launch: Genesis with no premine, 30-day ramp, exchange listings after.' You put listings in the roadmap."
|
|
|
|
Status: Conceded, stated (5 October 2026, night): `site/litepaper.html`, Roadmap phase 6, and `site/journey.json` phase 6, "No listing is arranged, promised or sought by the project". Was: Conceded, fix now.
|
|
|
|
Status: Conceded, stated (6 October 2026, later that night): the restored home page shows the journey again; phase 6 reads "No listing is arranged, promised or sought by the project" there and in the litepaper's roadmap.
|
|
|
|
Status: Conceded, stated (6 October 2026, night): the home page's journey is no longer shown (the inlined feed remains in the page source); the sentence "No listing is arranged, promised or sought by the project" stands on `site/litepaper.html` Roadmap phase 6 and in `site/journey.json`. The 5 October line below is the history.
|
|
|
|
Answer: Correct. No listing is arranged, promised or sought by the project. The phrase comes off the roadmap and the homepage journey.
|
|
|
|
Evidence: litepaper "Roadmap", `site/journey.json`. Fix: overclaims list, item 75.
|
|
|
|
Sweep (5 October 2026, evening): stated. `site/litepaper.html` roadmap phase 6 and `site/journey.json` phase 6: "Genesis with no premine, 30-day ramp. No listing is arranged, promised or sought by the project" (overclaim 58); the home page's inlined journey rebuilt from it.
|
|
|
|
### X9. Launch hashrate will be trivial
|
|
"Day one of a GPU coin with a 10% emission ramp is a few hundred cards. Anyone with a cloud account out-mines it for the price of lunch, and your finality has no history to lean on."
|
|
|
|
Status: Conceded, stated (5 October 2026, night): `site/litepaper.html`, Finality, "In the chain's first 30 days no checkpoint locks at all"; Fair launch, "The first 30 days of mainnet run on proof of work alone". Was: Conceded, stated in part; see F1.
|
|
|
|
Answer: True. The lottery is as attackable as any new proof-of-work chain for as long as it is small, and finality adds nothing until the window fills. The protections are the one-hour merge-depth bound, no listings before launch, and the proposed rule that no certificate forms until the window has 30 days of history. The litepaper must say that the first month is proof of work only.
|
|
|
|
Evidence: `sim/results.md` table A (full weight only from day 32 to 41 from zero history). Fix: overclaims list, item 31.
|
|
|
|
Sweep (5 October 2026, evening): stated. `site/litepaper.html`, Finality: no checkpoint locks in the first 30 days, the first-month gate labelled Implemented and measured (bench-log "finality fixes F17 and F1", 4 October 2026), proof of work with the 12-hour depth meanwhile, the devnet's two-hour window explained. "Fair launch, announced" and "What Igneum does not claim" ("Finality in the first month") say the same; a deposit sentence replaces "exchanges are told" because no listing is sought (overclaims 31, 75, second item of 78).
|
|
|
|
### X10. Five milestones in one day
|
|
"Your Journey log shows five entries, all dated 3 October 2026. That is one day's work presented as a history."
|
|
|
|
Status: Conceded, stated (5 October 2026, night): `site/index.html`, journey section, "The log below is the engineering log's dated entries, newest first. Day one was 3 October 2026". Was: Conceded, label needed.
|
|
|
|
Answer: It is one day's work, and the log says the date on every line. The label "Day one" above the entries would remove the impression of theatre.
|
|
|
|
Evidence: `site/journey.json`.
|
|
|
|
Sweep (5 October 2026, evening): stated. `site/index.html`, journey section: a line above the log says it is the engineering log's dated entries, newest first, day one 3 October 2026, several entries per date because the work is logged as it is run. A "Day one" label alone would now mislead, since the log spans three days.
|
|
|
|
---
|
|
|
|
## Count by status
|
|
|
|
| Status | Count | Entries |
|
|
|---|---|---|
|
|
| Answered with evidence | 2 | M8, M10 |
|
|
| Answered by design | 13 | M3, M12, F4, F9, F11, F12, F13, P9, E2, E3, C1, C12, L6 |
|
|
| Open, experiment or decision scheduled | 9 | M1, M11, F7, P3, C4, L1, L2, L4, L5 |
|
|
| Fixed (4 October 2026, generator version 2) | 2 | M5, M6 |
|
|
| Closed by rule, Decided or Closed by removal (3 October 2026) | 9 | E4, F2, F3, P5, P8, C9, E7, G7, X6 |
|
|
| Conceded, stated in the litepaper or design doc | 13 | F6, F8, P2, P6, E1, E6, E8, G3, G5, G8, C7, X3, X4 |
|
|
| Conceded, not yet stated (fix in the overclaims list) | 32 | M2, M4, M7, M9, M13, F1, F5, F10, P1, P4, P7, P10, E5, G1, G2, G4, G6, C2, C3, C5, C6, C8, C10, C11, L3, X1, X2, X5, X7, X8, X9, X10 |
|
|
|
|
Several entries carry two statuses; the table counts each entry once by its leading status. Total entries: 80.
|
|
|
|
---
|
|
|
|
## Overclaims to remove from public text now
|
|
|
|
Each item quotes the current text exactly and gives the replacement. Sources: `site/litepaper.html` (LP), `site/index.html` (HP), `site/journey.json` (J).
|
|
|
|
1. LP cover: "A proof-of-work chain whose miners also prove every block, run Ethereum's apps, and built so no chip can ever take your place."
|
|
Replace with: "A proof-of-work chain whose miners also prove every block, run Ethereum's apps, and are protected from specialised chips by a program that changes every hour."
|
|
|
|
2. LP abstract: "Mining stays open to anyone with a GPU because the mining program itself changes every hour, so there is nothing for a specialised chip to be built for."
|
|
Replace with: "Mining stays open to anyone with a GPU because the mining program changes every hour, so a chip built for one program is useless for the next, and a chip for the whole program space is a GPU without the graphics parts."
|
|
|
|
3. LP abstract: "Nothing in it ever needs a human to keep it that way."
|
|
Replace with: "No scheduled human release is needed to keep it that way. Writing new code, including an emergency fix to the proof system, is the one thing that takes a person, and it activates only on miner signalling."
|
|
|
|
4. LP firsts: "Every piece of Igneum has a precedent somewhere. The combination has none, and six of the pieces are firsts on their own."
|
|
Replace with: "Every piece of Igneum has a precedent somewhere. We know of no chain that combines them. The table names the closest precedent for each piece and will be corrected when shown wrong."
|
|
|
|
5. LP firsts row: "A mining program that regenerates itself, for GPUs | RandomX does it for CPUs on Monero, since 2019 | The GPU version. Designed, discussed, never shipped"
|
|
Replace with: "A mining program that regenerates itself, for GPUs | RandomX on Monero since 2019 for CPUs. ProgPoW, as KAWPOW on Ravencoin since 2020, changes its maths sequence every few blocks on GPUs | A full kernel per hour, a daily dataset from a 256 MB cache, a verifiable delay before the seed, and era draws from a genesis reserve"
|
|
|
|
6. LP firsts row: "Ethereum apps on a GPU-mined chain whose state cannot be wrong"
|
|
Replace with: "Ethereum apps on a GPU-mined chain whose state is proven every block"
|
|
|
|
7. LP firsts row: "Finality held by miners and immune to hour-long rentals"
|
|
Replace with: "Finality held by miners and not moved by hour-long rentals"
|
|
|
|
8. LP firsts row: "Kaspa's fair launch, with no utility."
|
|
Replace with: "Kaspa's fair launch."
|
|
|
|
9. LP firsts row: "A chain your browser verifies by itself | Light clients trust a committee | One proof plus one locked checkpoint, no trust"
|
|
Replace with: "A chain your browser verifies by itself (phase two) | Light clients trust a committee | One execution proof plus one locked checkpoint at launch; a consensus proof that makes the checkpoint self-verifying is phase two"
|
|
|
|
10. LP: "GPU mining lost its home in 2022. Igneum is the first chain built so that it can never be taken away again: not by a chip, not by a merge to proof of stake, not by a rental attack, and not by a foundation."
|
|
Replace with: "GPU mining lost its largest home in 2022. Igneum is built to make it hard to take away: by a chip, by a merge to proof of stake, by a rental attack, or by a foundation."
|
|
|
|
11. LP: "Every chain that tried to take it in since has either been captured by specialised chips within two years, as Kaspa was, or has stayed too small to pay the power bill."
|
|
Replace with: "Since then the GPU chains have gone two ways. Chips arrived, as on Kaspa, whose hash was designed to welcome them. Or the chain stayed small: Ergo, Ravencoin and Conflux still mine on GPUs at a fraction of the 2022 fleet, approximate."
|
|
|
|
12. LP: "It gives the proving market its cheapest supplier."
|
|
Replace with: "It gives the proving market a supplier whose marginal cost is close to power."
|
|
|
|
13. LP glance: "New program every hour, so only a GPU runs it well"
|
|
Replace with: "New program every hour, so a chip for last hour's program is useless"
|
|
|
|
14. LP mining: "random reads over a multi-gigabyte dataset that changes daily, so the program is bound by memory bandwidth."
|
|
Replace with: "random reads over a multi-gigabyte dataset that changes daily, so the program is bound by random memory access. Measured: an RTX 5090 hashes at 95 GB/s of useful 4-byte loads against 1,638 GB/s of sequential writes."
|
|
|
|
15. LP mining: "The memory footprint and instruction count are fixed and only the maths sequence is random, so no hour favours one vendor's cards and nobody gains by grinding the seed."
|
|
Replace with: "The memory footprint, instruction count and load count are fixed by the generator and only the maths sequence is random, so no hour favours one vendor's cards. The prototype does not yet fix the load count (40 to 232 per hash across 10,000 programs); the specification will."
|
|
|
|
16. LP mining: "checks a hash on an ordinary CPU in about ten milliseconds by simulating one warp"
|
|
Replace with: "checks a hash on an ordinary CPU in under ten milliseconds by simulating one warp, the gate. Measured at 0.02 ms with the prototype's cheap dataset; the 256 MB cache version is not yet measured."
|
|
|
|
17. LP mining: "Igneum runs for ever on the generator fixed at genesis, exactly as Monero has run on RandomX since 2019 with no chip built."
|
|
Replace with: "Igneum runs on the generator fixed at genesis, as Monero has run on RandomX since 2019 with no chip publicly shipped, approximate."
|
|
|
|
18. LP mining: "A chip that dropped the graphics parts and kept the parallel cores and the memory would gain under 2x, approximate, which is below what pays for a tapeout, and that is the same margin that has protected Monero for seven years."
|
|
Replace with: "Our target is that a chip that dropped the graphics parts and kept the parallel cores and the memory gains under 2x, below what pays for a tapeout. That is a design target, not a measurement. Ethash chips reached roughly 1.5 to 2x, approximate, and the standing bounty exists to test the target."
|
|
|
|
19. LP mining: "Igneum is built so that day never comes, and it does not depend on it."
|
|
Replace with: "Igneum is built to make that day unlikely, and does not depend on avoiding it."
|
|
|
|
20. LP vs RandomX table: "GPUs. Any card, any vendor. Bit-exact on Apple and NVIDIA, measured"
|
|
Replace with: "GPUs. Bit-exact on Apple and NVIDIA across two programs, 192 of 192 vectors. AMD and Intel not yet run."
|
|
|
|
21. LP vs RandomX table: "256 MB cache on a CPU, one warp under 10 ms, the measured gate"
|
|
Replace with: "256 MB cache on a CPU, one warp under 10 ms, the gate. Not yet measured with the cache."
|
|
|
|
22. LP vs RandomX table: "Zero years. Every number above is measured, published, and reproducible from the repository"
|
|
Replace with: "Zero years. Every number above is measured and logged. The repository opens with the January 2027 benchmark." Or open the repository now and keep the sentence.
|
|
|
|
23. LP: "Measured so far: the same hourly program, generated on an Apple M5 Max, compiled by Apple's Metal and NVIDIA's CUDA on an RTX 5090, produced identical hashes on both, 192 of 192 across two programs. On a 1 GB dataset the 5090 ran at about 228 million hashes a second and the Mac at about 45 million, both bound by random memory access rather than arithmetic."
|
|
Append: "These are prototype numbers. The prototype dataset is a closed-form function and can be shortcut about 110x by computing items instead of loading them. The 256 MB cache construction replaces it, and the numbers will be re-measured."
|
|
|
|
24. LP proving: "Proving is the one useful GPU workload that is cheaply verifiable by construction."
|
|
Replace with: "Proving is a useful GPU workload that is cheaply verifiable by construction."
|
|
|
|
25. LP proving: "A proof is right or it is not, and a phone can check it in milliseconds."
|
|
Replace with: "A proof is right or it is not. Wrapped for light clients, a phone checks it in milliseconds; the wrapping cost is a phase two measurement."
|
|
|
|
26. LP proving: "Because the proof computes the state from the ordered sequence, a block with a wrong state cannot exist."
|
|
Replace with: "Because the proof computes the state from the ordered sequence, no node accepts a block with a wrong state root, and full nodes also execute natively and reject a proof that disagrees with their own execution."
|
|
|
|
27. LP proving: "Shard size is set so a 12 GB card proves one shard in about 20 seconds, measured on a mid-range card before launch and raised by schedule as hardware improves."
|
|
Replace with: "Shard size will be set so a 12 GB card proves one shard in about 20 seconds. That number is the phase two gate and is not yet measured. It rises by schedule as hardware improves."
|
|
|
|
28. LP proving: "No other proof-of-work chain has a seat in it."
|
|
Replace with: "We know of no other proof-of-work chain selling proofs to other chains."
|
|
|
|
29. LP speed: "Igneum orders blocks with GHOSTDAG, the BlockDAG consensus proven on Kaspa."
|
|
Replace with: "Igneum orders blocks with GHOSTDAG, the BlockDAG consensus Kaspa has run in production since 2021, forked from rusty-kaspa."
|
|
|
|
30. LP speed: "A transaction is included in about one second, against twelve on Ethereum, and locked in about two minutes against roughly thirteen."
|
|
Replace with: "A transaction is included in the DAG in about one second (an Ethereum slot is twelve) and locked by miners in about two minutes (Ethereum reaches finality in about thirteen, approximate). Inclusion is not confirmation on either chain, and the two finality mechanisms differ: see the FUD ledger."
|
|
|
|
31. LP finality: "A locked checkpoint overrides the heaviest chain, so no amount of fresh hashrate can reorganise past it."
|
|
Replace with: "A locked checkpoint overrides the heaviest chain, so fresh hashrate cannot reorganise past it. Two thirds of 30-day weight can, and the first month of the chain has no history to weigh, so the chain runs on proof of work alone until the window fills."
|
|
|
|
32. LP finality: "Even an attacker who brought the whole network's hashrate would need ten days of mining in public to hold a third of the weight, and twenty days to hold two thirds."
|
|
Replace with: "Even an attacker producing every block on the chain, with honest miners gone, would need ten days of mining in public to hold a third of the weight, and twenty to hold two thirds. An attacker matching the honest network needs twenty days for a third and never reaches two thirds."
|
|
|
|
33. LP finality: "which is the same limit Bitcoin lives with, with a month's warning attached."
|
|
Keep. Add after it: "Pools carry their hashers' votes, so vote concentration equals pool concentration, and it is public."
|
|
|
|
34. LP finality: "Only miners who are present count: a key that stops signing drops out of the denominator within two hours, so a silent minority cannot freeze finality and a lock never waits for miners who have left."
|
|
Append: "The same two hours are the exposure to a partition or an eclipse that stops honest votes without stopping honest blocks. The gate 3 devnet measures it."
|
|
|
|
35. LP building: "Anything that runs on Ethereum runs on Igneum unchanged. Same Solidity, same bytecode, same wallets, same tools, a different chain id."
|
|
Replace with: "Ethereum bytecode runs on Igneum. Same Solidity, same wallets, same tools, a different chain id, and block number, timestamp, blockhash, coinbase and prevrandao defined over the ordered sequence. Contracts that depend on those are told what changed, and contracts heavy in pairing or modexp precompiles pay more here because proving cost is metered."
|
|
|
|
36. LP building: "Three things run on Igneum that run nowhere else."
|
|
Replace with: "Three things Igneum offers at the base layer that we know no other EVM chain offers."
|
|
|
|
37. LP building: "No other EVM chain has a prover network in its base layer."
|
|
Replace with: "We know of no other EVM chain with a prover network in its base layer."
|
|
|
|
38. LP building: "Trustless light clients. Because every block is proven, a phone or a browser verifies Igneum's state by checking one proof and the latest locked checkpoint. Bridges built on that need no multisig, the piece that has failed in the biggest bridge hacks."
|
|
Replace with: "Light clients. Because every block is proven, a phone or a browser verifies Igneum's state from one proof and a locked checkpoint it is given. Making the checkpoint itself self-verifying, which is what removes the multisig from bridges, needs a consensus proof and is phase two."
|
|
Applied 3 October 2026 (E7 decided, spec 7.3).
|
|
|
|
39. LP building: "Canto and Blast proved builders come for this."
|
|
Replace with: "Canto's contract-secured revenue and Blast's gas sharing showed builders respond to it."
|
|
|
|
40. LP building: "Stablecoins at genesis. USDC and USDT bridged through the proof bridge, canonical versions on Igneum, the way Arbitrum and Base launched."
|
|
Replace with (decision of 3 October 2026, spec 7.3; the earlier replacement "decided in phase 4 and will be labelled" is superseded): "Stablecoins. None are bridged at genesis. No bridge is official, anyone may run one at their own risk, and the proof bridge that needs no multisig arrives with the consensus proof in phase two."
|
|
Applied 3 October 2026, with the builders-ask answer rewritten to match.
|
|
|
|
41. LP builders: "And the only user base a new chain has ever had that did not have to be paid to arrive."
|
|
Delete.
|
|
|
|
42. LP builders: "The afternoon is the hard part."
|
|
Delete.
|
|
|
|
43. LP governance: "Igneum is governed by the people who power it, and by nobody else."
|
|
Replace with: "Igneum is governed by the hashrate that powers it. Pools carry their hashers' votes, so pool concentration is the governance risk, and it is public."
|
|
|
|
44. LP governance: "Pools cannot censor. Igneum uses Stratum v2 from day one, so each miner chooses its own transactions even inside a pool."
|
|
Replace with: "Pools can be bypassed on transaction choice. Igneum ships Stratum v2 job declaration from day one, so a miner chooses its own transactions when its pool supports it. Vote keys stay with the pool."
|
|
|
|
45. LP governance: "There are no admin keys. Nothing in consensus can be paused, upgraded or reversed by any key."
|
|
Replace with: "There are no admin keys in consensus. Nothing in consensus can be paused, upgraded or reversed by any key. The genesis apps publish their own key policies before launch; the bridge's is the one to read."
|
|
|
|
46. LP governance: "Upgrades need a second independent node client, funded from the development fund as its first priority."
|
|
Replace with: "At launch there is one node client. A second independent client is the first priority after launch, anyone can build it, and it is not in the 13-month plan."
|
|
|
|
47. LP miners ask: "Kaspa said ASIC resistant too, and IceRiver shipped a chip in eighteen months."
|
|
Replace with: "Every GPU coin got a chip in the end. Kaspa got one in about eighteen months."
|
|
And in the answer: "Kaspa's hash was one fixed function, designed to be hardware-friendly, and simple enough to put on silicon."
|
|
|
|
48. LP miners ask: "Correct, and it is the first thing the external review is paid to break. The specification is public, the review is gate 3 with named reviewers and a bounty"
|
|
Replace with: "Correct, and it is the first thing the external review will be paid to break. The specification will be public, reviewers will be named and paid before gate 3, and a bounty is attached. Until then every finality claim here is a design claim backed by a simulation without a network in it."
|
|
|
|
49. LP miners ask: "What Igneum can promise is that its miners have the lowest cost in that market"
|
|
Replace with: "What Igneum can promise is that its miners' marginal cost in that market is close to power"
|
|
|
|
50. LP not claimed: "A chip is impossible. No. A chip is pointless, because the target moves before it ships."
|
|
Replace with: "A chip is impossible. No. A chip is a bad bet, because the target moves before it ships."
|
|
|
|
51. LP not claimed: "That is harder than attacking Bitcoin, where a majority can reorganise at once"
|
|
Replace with: "That is a different limit from Bitcoin's, where a majority can reorganise at once: Bitcoin's defence is the cost of the majority, Igneum's is the month in public."
|
|
|
|
52. LP economics: "It is gas, it is the proving currency, and it is what every outside customer pays in. Part of every payment is burned."
|
|
Replace with: "It is gas and the proving currency, and part of every payment on Igneum is burned. Outside customers pay in their own currency on their own chain at launch; settlement in IGN with a 10% burn follows when the proof bridge lets Igneum see the payment."
|
|
|
|
53. LP economics and governance: "5% of gas and 5% of external job fees go to a development fund"
|
|
Closed by removal, 3 October 2026: there is no development fund. The paragraph now reads "No fund, no foundation, no fee to the team" and the governance bullet names 60% signalling as the tool for parameters that genesis leaves to miners.
|
|
|
|
54. LP economics: "Nearly a quarter of all supply is mined in the first year and half in the first two, so the people who show up early get the most."
|
|
Replace with: "Nearly a quarter of all supply is mined in the first year and half in the first two. Emission halves every two years for ever."
|
|
|
|
55. LP miners: "so Igneum miners have the lowest marginal cost in the proving market and are the last provers to switch off"
|
|
Replace with: "so Igneum miners' marginal cost in the proving market is close to power, which is an edge over data-centre provers and nothing more"
|
|
|
|
56. LP miners: "NVIDIA and AMD both work, because the mining program is generated for the architecture both share"
|
|
Replace with: "NVIDIA is measured bit-exact against Apple. AMD is the next run. The program is generated for the warp architecture all three share."
|
|
|
|
57. LP miners: "The dataset starts at 2 GB and grows by half a gigabyte a year, so a 4 GB card mines for about four years and an 8 GB card for more than a decade, approximate."
|
|
Keep (labelled). HP equivalent "Any card with 4 GB today, 8 GB for the next decade." add "approximate".
|
|
|
|
58. LP roadmap: "Genesis with no premine, 30-day ramp, exchange listings after"
|
|
Replace with: "Genesis with no premine, 30-day ramp. No listing is arranged, promised or sought by the project."
|
|
Same change in J phase 6.
|
|
|
|
59. HP hero: "The first chain built so no chip can ever take your place."
|
|
Replace with: "A chain built so a chip gains too little to take your place."
|
|
|
|
60. HP: "Get the miner" (button, twice)
|
|
Replace with: "Benchmark: January 2027"
|
|
|
|
61. HP: "All of it will be on this page, live."
|
|
Replace with: "All of it will be on this page, live, from the public testnet." (the month was removed on 6 October 2026, X31)
|
|
|
|
62. HP economics: "Not one coin to a founder, a fund or a stake."
|
|
Replace with: "Not one coin of emission to a founder, a fund or a stake. The official client carries a 1% dev fee to the founder's company, as every GPU miner does; any client without it is welcome."
|
|
|
|
63. HP: "A mining program that rewrites itself every hour, so no chip can be built for it."
|
|
Replace with: "A mining program that rewrites itself every hour, so a chip built for one hour is useless the next."
|
|
|
|
64. HP: "No premine, no stake, no foundation, no merge to anything else, ever."
|
|
Replace with: "No premine, no stake, no foundation, no merge to proof of stake."
|
|
|
|
65. HP footer and nav: "GitHub" link to a private repository.
|
|
Make the repository public or remove the link until it is.
|
|
|
|
66. HP vs RandomX table: identical to LP items 20 to 22; same replacements.
|
|
|
|
67. HP: "RandomX proved that a random program beats a chip when the only hardware that runs it well is the hardware everyone already owns."
|
|
Replace with: "RandomX has kept chips off Monero since 2019 by making the program random, so the hardware everyone already owns runs it best, approximate."
|
|
|
|
68. LP vs RandomX: "Monero's idea, finished for GPUs"
|
|
Replace with: "Monero's technique, applied to GPUs"
|
|
|
|
69. LP roadmap: "Each gate is a measurement published whether it passes or fails. Miss it and the phase repeats or the project stops."
|
|
Keep. Add under the table: "Dates slip. Gates do not."
|
|
|
|
70. LP mining table: "Ethereum's growing dataset killed Bitmain's E3 miner in 2020 this way, with nobody doing anything"
|
|
Replace with: "Ethereum's growing dataset ran Bitmain's E3 out of memory in 2020, approximate, with nobody doing anything"
|
|
|
|
71. LP builders: "Stablecoins at genesis" heading and "the way Arbitrum and Base launched"
|
|
Covered by item 40; remove "at genesis" until E7 is decided.
|
|
Applied 3 October 2026: E7 decided (no bridged stablecoins at genesis, spec 7.3); the heading, the Arbitrum and Base comparison, "an Ethereum bridge, ship at genesis" and "bridged through the proof bridge at genesis" in the builders-ask answer are all gone.
|
|
|
|
72. LP cover status line: "Status pre-specification, pre-testnet"
|
|
Keep. Add: "Method: designed and prototyped by the founder with AI assistance; measurements reproducible from the logs; external review before gate 3."
|
|
|
|
73. LP "Who are you?" answer
|
|
Append: "The founder's name is on every commit. No cryptographer is yet hired; the design doc budgets one for phases one and two."
|
|
|
|
74. LP, every finality number quoted from the simulation (ten days, twenty days, two hours)
|
|
Add once, in the Finality section: "Day counts come from a model with no network latency, no DAG and no partitions (sim/results.md). The gate 3 devnet replaces them with measurements."
|
|
|
|
75. LP "Fair launch, announced": "Pools live on testnet."
|
|
Append: "The first month of mainnet runs on proof of work alone while vote weights build; exchanges are told to treat it so."
|
|
|
|
76. LP, anywhere a launch sentence reads as an inducement to acquire ("the people who show up early get the most", "Half of the 4 billion cap is mined in the first two years" as a chart caption)
|
|
Rewrite as schedule facts without the "so" clause (item 54), pending a promotions opinion from counsel in the project's jurisdiction.
|
|
|
|
77. HP and LP: no contact route anywhere.
|
|
Add one before sharing the litepaper, and point the FUD ledger's submission line at it.
|
|
|
|
78. LP "What Igneum does not claim"
|
|
Add three items: "A memory-hard prototype. Not yet: the current dataset can be shortcut 110x; the 256 MB cache replaces it." "Finality in the first month. Not until the 30-day window has history." "A cryptography team. Not yet; external reviewers are named before gate 3."
|
|
|
|
---
|
|
|
|
## Round 3 entries (3 October 2026, evening): the specification and the running code
|
|
|
|
Added by `docs/review/round-3-2026-10-03.md`, which holds the full argument for each, the reviewer who raised it, and the five to fix first. Entries are placed under their section letters below and numbered on from the last entry of each section. Existing entries are unchanged; where one is extended the new entry says so. Count after this block: 107 entries (80 plus 27). Of the 27: 0 fatal, 18 serious, 9 minor by the review's ranking (M18, M21, P13, P15, C13, L8, G10, X12 and the text half of E11 are the minor ones).
|
|
|
|
### 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 (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."
|
|
|
|
Status: Fixed (3 October 2026, branch `r3-fixes`; merged into `devnet-v4` on 4 October 2026, `45111405`; live on devnet v4). `validate_header` runs the DAA-score, difficulty and past-median checks before the PoW engine; `KEEP` is 4; at most one build per seed pair, 2 at once, a queue of 4; a per-peer strike guard disconnects a peer after more than 2 strikes in an hour. Measured (`docs/bench-log.md`, "R3.26 / M15"): 50 headers with bogus past days cost 50 cold builds and 10,595 ms before the fix, 0 builds and 14 ms after, the live day resident; harness scenario 5 on the merged node ("devnet-v4 integration"), 63 cases, 0 cache builds, the p2p cases disconnected by the strike guard. Was: Open, fix named.
|
|
|
|
Answer: Correct. `validate_header` (`consensus/src/pipeline/header_processor/processor.rs:293` to `301`) runs the isolation checks (timestamp against the future only, `pre_ghostdag_validation.rs:48`), GHOSTDAG, `check_pow_and_calc_block_level`, and only then `pre_pow_validation` with `check_difficulty_and_daa_score`. `epoch_seed` (`processor.rs:325`) reads `header.daa_score`; `day_index` reads `header.timestamp`; `IgneumEngine::KEEP` is 3. `docs/fork-divergence.md` flags the ordering as a GHOSTDAG cost; the cache thrash is the sharper form. Fix: run the DAA-score and past-median checks before the PoW check; derive the day from DAA score (spec 1.12) or from the selected parent's window; `KEEP` 4; a per-peer cap on cache builds.
|
|
|
|
Evidence: the files and lines above. Fix: review's first of five. Review id R3.26.
|
|
|
|
### 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: 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.
|
|
|
|
Answer: Correct as arithmetic, unmeasured as a device. From spec 1.8.4 and 1.8.5 an item costs 9 mixer applications of about 130 operations and 8 cache reads; under the proposed 16-load rule a hash derives 128 items. A 5090-class integer budget (about 50 T operations a second, approximate) gives about 0.33 Ghash/s against the honest 141 Mhash/s projection, about 2.4x at equal silicon before any chip-versus-GPU efficiency, and a 256 MiB SRAM is about 250 to 300 mm^2 on a current node (approximate, from wafer-scale parts). The cache size was set to beat a GPU's L2 (spec 1.16), not a die. The lever is the cache size and the mixer cost, both prototype values at gate 1. Monero's precedent does not price this (C13). An FPGA does not reach it (review, chip designer, attack 3).
|
|
|
|
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."
|
|
|
|
Status: Fixed (hot swap, `a4224689`, merged into `devnet-v4` on 4 October 2026) and measured on the live devnet at the DAA 3,600 boundary (`docs/bench-log.md`, "first hourly program swap"): prepare sent 449 DAA before the boundary; Metal compiled in 82 ms, CUDA ran nvcc in the background in 1,285 ms, the AMD OpenCL worker prepared; swap 0.00 to 0.01 ms with two programs resident; rates unbroken (26.7 / 26.7 and 121.8 / 123.4 MH/s); 0 rejected; the exit-42 rebuild path unused. Still owed: a multi-card rig through 24 boundaries (M11, O-1.16). Was: Open, fix named.
|
|
|
|
Answer: Correct for the devnet client. Under the v0 seed rule (the last block of the previous epoch) nobody can compile early and the gap is structural; under the spec's VDF pipeline the seed is known 1,200 DAA seconds ahead (spec 4.3) and an honest client compiles ahead, so the gap is a client defect, not consensus. Fix: in-worker NVRTC and runtime OpenCL compilation (listed in `docs/fork-divergence.md` as open), measured on a mixed rig through 24 epoch changes (O-1.16). Extends M11.
|
|
|
|
Evidence: `node1.log` 21:12:14 to 21:13:45; `proto-cuda/windows-miner/start-mining.ps1` (exit 42 handling); bench-log Metal compile figures. Review id R3.7.
|
|
|
|
### M18. The per-hash random data path is a one-bit select
|
|
"Your `add` picks one of two immediates by a bit of `r0`. A chip computes both and muxes. Calling that a data-dependent path next to ProgPoW is marketing."
|
|
|
|
Status: Conceded, stated (5 October 2026, night): `site/litepaper.html`, Mining table "Every hash" row, "The one-bit select inside the maths costs a chip nothing and is not a defence"; vs RandomX "Random program" row, "the 128 dataset addresses change with the nonce". Was: Conceded, wording fix.
|
|
|
|
Answer: Correct. Spec 1.4.1: `sel` is `r0` at the top of each iteration and each `add` selects `imm` or `imm2` by one bit of it. It costs a chip nothing and defends nothing; the defence is the random reads. The litepaper's vs RandomX row should drop "random data path" or say what it is.
|
|
|
|
Evidence: spec 1.4.1. Fix: `site/litepaper.html` vs RandomX row, "Random program" (review, RandomX author, sentence). Review id R3.8.
|
|
|
|
Sweep (5 October 2026, evening): stated. `site/litepaper.html`, vs RandomX "Random program" row drops the per-hash data path and says the 128 dataset addresses change with the nonce; the Mining table "Every hash" row says the one-bit select costs a chip nothing and is not a defence.
|
|
|
|
### M19. The census that justifies the generator rule has blank cells, and the spec still carries the free load count
|
|
"Section 7.1 of your census has `FRESH2_DIST`, `FRESH2_P` and `FRESH2_CAND` where the proposed generator's numbers go, section 7.2 is the word `FRESH2_ACCEPTED`, section 7.3 is `CF_AGREEMENT`, and the spec text you propose cites a rejection rate called `REJECT-RATE`. Until it is filled and adopted every hour is a different coin."
|
|
|
|
Status: Fixed (4 October 2026). `docs/analysis/weak-program-census-2026-10-03.md` section 7 holds the 100,000-seed run of the proposed generator (128 loads per hash, 127.7 distinct addresses on average, 1.57% of programs with a repeated load, 3.93% static rejects); spec 1.4.2 draws exactly 16 loads (Definition); generator version 2 with the acceptance rule is adopted (M5, M6); the RTX 5090 mined version 2 packs on the live devnet at 121.8 to 123.4 MH/s (bench-log, "first hourly program swap"). Was: Open, measurement in progress.
|
|
|
|
Answer: Correct. The current-generator census is complete (100,000 programs, 94.8% with a redundant load, hash rate tracking distinct loads 56 to 152 per hash at the 1st to 99th percentile); the `fixed16-fresh2` run that fixes the proposed rule's own rejection rate and candidate count is not in the document, and section 1.4.2 of the spec still draws the load count freely. Fix: finish the run, fill the cells, adopt G1 + G2 + R into spec 1.4 with new vectors (spec 1.16 schedules the re-cut), and run ten programs on the 5090 under the new generator. Extends M5 and M6.
|
|
|
|
Evidence: `docs/analysis/weak-program-census-2026-10-03.md` sections 7 and 9. Review id R3.6.
|
|
|
|
### M20. Pruning proofs are checked with the kHeavyHash stub
|
|
"Wait thirty hours, start a fresh node, and watch it reject the honest pruning proof: `validate.rs:192` runs kHeavyHash on headers mined under the lottery, which pass with probability 2^-28. And if you loosen that, I forge levels with an ASIC that already exists."
|
|
|
|
Status: Fixed in the node (rolled out 5 October 2026, 0.3.5: `m20-pruning` d35b00cf merged into fork 20139145 as its last merge, `cargo test -p kaspa-consensus --features igneum-pow -- pruning_proof` 4 passed at 03:15 UTC, `docs/plans/release-0.3.5.md` 1b and 3b: pruning proofs are checked with the Igneum lottery hash and the chain seeds; `pruning_proof/validate.rs`, the IBD proof flow and the p2p proof messages carry the seeds). Sweep (5 October 2026, evening): the live test is still owed and now possible: the Mac node's pruning point is still genesis at DAA 113,289 (`getBlockDagInfo` at 16:00 UTC, pruning point `edc4fa84...` with DAA score 0), so no node has yet served or checked a lottery-hashed pruning proof on the live devnet; the first fresh node to sync after the pruning point moves (expected between 14:00 UTC on 5 October and 01:00 UTC on 6 October by the entry's own arithmetic, approximate) is the measurement, and a fresh `igneumd` on this Mac against the live seed is read-only for the network and should be run then. Was: Open, acknowledged, fix named. Sweep (5 October 2026): still the stub on `devnet-v4` (`consensus/src/processes/pruning_proof/validate.rs:192` calls `calc_block_level_check_pow`; `apply.rs:74, 200` and `mod.rs:207` call `calc_block_level`). The test, a fresh node syncing a chain past its pruning depth, needs a network older than that depth; a fresh node against the live devnet is outside this sweep's rules, so it was not run. When it bites: the devnet's pruning depth is `PRUNING_DURATION` 108,000 DAA (`consensus/core/src/config/constants.rs:94`; the derived lower bound is 63,398), and the pruning point first leaves genesis once a finality point sits a full pruning depth below the tip, DAA 108,000 to 151,200, which at 1.05 DAA/s from DAA 33,000 at 17:37 UTC on 4 October falls between about 14:00 UTC on 5 October and 01:00 UTC on 6 October (approximate). From then on a fresh node receives a pruning proof and the stub rejects the honest headers with probability about 1 - 2^-28 each. Fix row in `docs/fud-fixes.md` section 2.5.
|
|
|
|
Answer: Correct. `consensus/src/processes/pruning_proof/validate.rs:192` calls `calc_block_level_check_pow`, which runs the stub, and `apply.rs` and `mod.rs` call `calc_block_level` the same way; `docs/fork-divergence.md` records that seeds must be threaded through pruning-proof validation before a pruning network. The devnet will pass its pruning depth (108,000 blocks, sooner after tonight's overshoot) and a fresh node will show it. Fix: derive the epoch and day for proof headers from the proof's own headers (fork map a4, O-2.5) and remove the stub from the proof path.
|
|
|
|
Evidence: the files above. Test: sync a fresh node from the 30-hour devnet. Review id R3.3.
|
|
|
|
### 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 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: 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."
|
|
|
|
Status: Spec fixed (3 October 2026): spec 2.1 names the finality depth as the reorg bound and merge depth as a merge limit only, spec 3.8 and 3.9 tell exchanges to wait 12 hours of past-median time when `finality_active` is false, and the simnet reorg test is written into 2.1 for gate 2. The litepaper Finality paragraph (first-month sentence and the merge-depth sentence) and "What Igneum does not claim" item 4 now name the 12-hour finality depth and call merge depth a merge limit (same evening). Was: Open, text and rule fix named.
|
|
|
|
Answer: Correct on reading the fork. `post_pow_validation.rs:79` bounds which reds a block may merge; the selected-chain switch is bounded by the finality point (`virtual_processor/processor.rs:1626`, `FINALITY_DURATION` 43,200 DAA seconds). So the month-one reorg bound is 12 hours of DAA time, not one hour, and spec 3.8, 3.9, litepaper "Finality" and "What Igneum does not claim" item 4 rest on the wrong constant. Fix: state the finality depth as the bound, in median time (M14 explains why not DAA time), or lower `FINALITY_DURATION` and accept Kaspa's finality-conflict handling at that depth; test with a heavier private chain forked 2, 6 and 13 hours back on simnet.
|
|
|
|
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: 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.
|
|
|
|
| | Option A: re-evaluate (spec 3.5 as proposed) | Option B: never withdraw (spec 3.11.4 as written) |
|
|
|---|---|---|
|
|
| Rule | Two certificates at one index: strike every key that signed both, re-evaluate both against Q3; follow the one that still locks; if neither or both, the index is uncertified | A verified certificate is never deleted, downgraded or re-evaluated; the node keeps following the one it verified first, publishes the pair, sets `finality_active` false with reason `conflict`, and an operator resolves the split with a trusted certificate (F5) |
|
|
| When the state arises | Only above the one-third bound: an equivocator holding 34% of total weight across a 50/50 split gives 2 to 54 conflicting locks in 150 to 360 min under v2 (`sim/results_v2.md` H at 2/3) and 21 to 69 from minute 14 to 78 under v3 (M5); 33% and below give 0 in every seed. Or an honest partition longer than a window (30 days on mainnet under v3; under v2 from day 10 at 50/50: the cloud devnet's 26 conflicting certificates and 23 disagreeing locked indices across three nodes, bench-log "finality floor 2/3"; tonight's C4 control run under v2: 1 conflicting certificate, sinks apart after the heal) | the same states |
|
|
| What an exchange sees | Every one of those 2 to 69 indices was reported locked and is then uncertified: a lock is a confirmation count, which is the critic's point. In the honest-partition case there is no equivocator to strike, both still lock, and every index of the split (23 on the devnet) is withdrawn on both sides | No reported lock is ever withdrawn; the node stops reporting new locks from the first conflict until the operator acts (minute 2 to 77 in H, minute 14 to 78 in M5), the chain runs on proof of work meanwhile, and the exchange guidance of 3.9 treats it as proof of work |
|
|
| Cost to the honest network | Recovery is automatic but every credit made on a withdrawn lock is exposed; the attacker who caused it keeps its deposit either way (F6) | A finality pause of operator length (hours) after an attack that costs the attacker ten days of a third of all hashrate in public (3.1) or a 30-day partition; the pause is the price of "locked" meaning irrevocable |
|
|
| What the shipped node does today | not implemented | half: a second certificate at a locked index is kept and logged CONFLICTING (`processes/finality.rs`, F24 wording), the node keeps the first (`fork_choice_lock`), but it does not yet clear `finality_active` or expose `finality_conflict` (spec 3.11.7 row C4); no `finality_conflict` symbol exists in the fork |
|
|
|
|
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).
|
|
|
|
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.
|
|
|
|
Cross-reference (external review, 3 October 2026, night): what holds during a pause, and the seed pipeline through it, is F20, O-3.16.
|
|
|
|
### 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: 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 `<platform>-<machine id8>-<card n>`, 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."
|
|
|
|
Status: Fixed (3 October 2026). `site/litepaper.html` Finality carries the replacement sentence and "What Igneum does not claim" carries the pause item ("Finality that never pauses"). Was: Conceded, not yet stated; text fix named.
|
|
|
|
Answer: Correct. The sentence was true of the active-only rule and was not updated when the 56.7% floor was added (spec 3.3.1 states the liveness cost honestly: liveness ends between 40% and 45% silent). Fix: the replacement sentence in the review (exchange engineer, sentence), and a line in "What Igneum does not claim".
|
|
|
|
Evidence: `sim/results_v2.md` C and D; spec 3.3.1; `site/litepaper.html` Finality. Review id R3.18.
|
|
|
|
### P11. The native-execution veto makes block validity depend on the node's current selected chain
|
|
"Section 5.5: a block is invalid if a proof record names a segment not on the node's selected chain, or disagrees with the node's own execution. Two honest nodes with different tips disagree on the same block. You removed the hidden-block penalty for this exact reason."
|
|
|
|
Status: Fixed (3 October 2026): spec 7.2 item 5 and `docs/design/execution-layer.md` 5.5 and D12 are relative to the carrying block's own selected-parent chain; the two-node reorg test is a row in the design document's 8.5. Was: Open, text fix named.
|
|
|
|
Answer: Correct. `docs/design/execution-layer.md` 5.5 (D12) and spec 7.2 item 5 reference the node's selected chain, which is a property of its virtual, not of the block's past. Fix: a proof record is valid if the chain block it names is on the carrying block's own selected-parent chain and its `post_root` and receipts equal the execution of that segment along that chain, which every node computes from the block's past. Add a two-node reorg test to section 8.5.
|
|
|
|
Evidence: the two sections. Review id R3.9.
|
|
|
|
### P12. An aggregator can name itself as every prover
|
|
"`ProofRecord.provers` is who is paid and nothing in a shard proof's statement says who proved it. I aggregate eight gossiped shard proofs and write my key eight times."
|
|
|
|
Status: Fixed in the proving code (4 October 2026, `proving/igneum-prove`): every shard proof's public values carry the prover's payout address (`ShardOutput.prover`), the aggregated block proof commits keccak over the provers in shard order and the shard program's verifying-key hash (`BlockOutput.provers`, `BlockOutput.shard_vk`), and the host verifier checks both before it accepts a claim. Still to do in the node: `ProofRecord.provers` must hash to `BlockOutput.provers` or the record is invalid (acceptance test A5); records are not on devnet v4 yet. Was: Open, format fix named.
|
|
|
|
Answer: Correct. Section 5.1's shard statement (pre-root, transactions, post-root, receipts) and the `ProofSystem` trait of 5.6 carry no prover identity; 4.4 credits the pool to the record's `provers`. Fix: each shard proof's public input includes the prover's payout key, aggregation carries the keys as public outputs, and a record whose list does not match them is invalid; acceptance test A5 checks the match, not only the credit.
|
|
|
|
Evidence: `docs/design/execution-layer.md` 5.1, 5.4, 5.6, 9.2 A5. Review id R3.10.
|
|
|
|
### P13. The litepaper still claims shards with a bond
|
|
"'Miners claim shards with a small bond.' Your spec 7.2 decided sortition with no bond the same day."
|
|
|
|
Status: Fixed (3 October 2026): `site/litepaper.html`, Proving, "How a block gets proven". Was: Conceded, fix now.
|
|
|
|
Answer: Correct. Fix: "Shards are assigned by lot to eight provers for ten seconds, then open to anyone; there is no bond." (`site/litepaper.html`, Proving, "How a block gets proven".)
|
|
|
|
Evidence: spec 7.2. Review id R3.13.
|
|
|
|
### P14. Two definitions of the proving base fee, and a quote that cannot know the ratio
|
|
"Spec 5.1 adjusts `f_p` from the unproven backlog smoothed over the difficulty window; design 4.1 adjusts it EIP-1559 style toward `B_p / 2`. And `eth_gasPrice` has no calldata, so your fold returns an average and a modexp-heavy transaction reverts on the budget and pays for it."
|
|
|
|
Status: Fixed in the spec (5 October 2026, evening sweep): one definition. Was: Open, decision named. Sweep (5 October 2026): decision item; spec 5.1 (backlog-smoothed) and design 4.1 (EIP-1559 toward B_p / 2) still differ.
|
|
|
|
Sweep (5 October 2026, evening): the fork has one controller and it is the EIP-1559 step. `next_base_fee(current, used, limit, floor, denominator)` in `igneum/exec/src/executor.rs:501` moves the fee toward `limit / 2` by `current x |used - target| / target / denominator`, never below the floor, and `service.rs:234-235, 310-311` applies it per chain block to both dimensions with the installed schedule's floor and denominator (8). Nothing reads the unproven backlog into `f_p`; the backlog rule of design 4.3 halves `B_p`, which raises `f_p` through the step. Nothing smooths over the difficulty window. Spec 05 section 5.1's proving row now says exactly that (this sweep's edit) and cites the function; section 5.11 already said "EIP-1559 toward half the limit, denominator 8, both dimensions". Design 4.1 still carries the words "smoothed over the difficulty window as the design document requires" and is now the odd one out: the smoothing was a design intention never implemented, and the litepaper is untouched. The quote half of the entry is unchanged: `eth_gasPrice` is a network-average fold and `eth_estimateGas` returns the limit that covers both charges (spec 7.1); R1's band measurement and R8 (the two fees against each other) remain the experiments.
|
|
|
|
Answer: Correct on both. Fix: one controller definition in both files; `eth_gasPrice` documented as a network-average fold with `eth_estimateGas` (which has the calldata) returning the limit that covers both charges; and the R1 band measurement (pgas / gas inside 0.1 to 10 for 95% of ethereum/tests) as the evidence that the average is usually close. R8 and R11 remain the experiments.
|
|
|
|
Evidence: spec 5.1; `docs/design/execution-layer.md` 4.1, 4.3, 9.1. Review id R3.11.
|
|
|
|
### 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: 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?"
|
|
|
|
Status: Fixed (3 October 2026): spec 2.5 follows the code (365.25-day year, 63,115,200-s halving, 31.688 IGN per DAA second, 8 decimals noted under O-2.6). The test that asserts the published numbers against `igneum.rs` is the code owner's row in `docs/fud-fixes.md`. Was: Open, decision now.
|
|
|
|
Answer: Correct. `consensus/core/src/igneum.rs` (`SECONDS_PER_YEAR = 31_557_600`, `HALVING_INTERVAL_SECONDS = 63_115_200`, `BASE_SUBSIDY_PER_SECOND_SOMPI = 3_168_808_781`) and spec 2.5 disagree; `docs/fork-divergence.md`'s per-second table follows the code. Fix: pick one (the code's values are tested and summed under the cap) and rewrite spec 2.5 and the litepaper's schedule to match, with a test that asserts the published numbers against the code.
|
|
|
|
Evidence: the two files. Review id R3.19.
|
|
|
|
### E10. Reds are paid in the code and "more blocks never means more coins" is false
|
|
"Spec 2.5: red blocks are unpaid, emission is keyed to DAA score so more blocks never means more coins. `coinbase.rs` pays a red's 80% to the merging miner and its 20% to the pool, and every blue block in the DAA window mints `E(daa)`. Tonight your chain minted 4.7x the schedule for eight minutes."
|
|
|
|
Status: Fixed (3 October 2026): spec 2.5 says reds inside the DAA window are paid to the merging miner (80%) and the pool (20%), that `E` is paid per block so coins are blocks times `E` under the controller's rate, and that the cap is unaffected; "more blocks never means more coins" is withdrawn. The litepaper Speed sentence ("never per block") was rewritten the same evening: emission per block on a schedule keyed to difficulty-adjusted time, reds in the window paid, coins track blocks within the controller's accuracy. Was: Conceded, text fix named.
|
|
|
|
Answer: Correct. `consensus/src/processes/coinbase.rs:102` to `109` follows Kaspa's rule for reds; `block_subsidy` is paid per blue (and red) block in the DAA window, so coins are blocks times `E` and the controller's rate sets the short-run emission, as on every proof-of-work chain. Timestamps still cannot mint. Fix: spec 2.5 to say what the code does (reds paid to the merger, emission per block under the controller's rate, the cap unaffected), or the code to say what the spec does; the review recommends the code's rule.
|
|
|
|
Evidence: the files; `docs/review/round-3-2026-10-03.md`, "Tonight's devnet". Review id R3.20.
|
|
|
|
### E11. The homepage burns job fees at launch
|
|
"'Jobs through Igneum's own market are paid in IGN and 10% of each fee is burned', with a tile 'IGN burned from jobs, at launch'. Your spec 5.4 settles launch jobs on the customer's chain with no burn. You fixed the litepaper (P10) and left the homepage."
|
|
|
|
Status: Fixed (3 October 2026): `site/index.html`, "Proofs sold to other chains" caption and the tile now read "phase two"; the quoted paragraph had already left the page when the homepage was trimmed (commit 047892e). Was: Conceded, fix now.
|
|
|
|
Answer: Correct. Fix: `site/index.html`, "Proofs sold to other chains": "Jobs are paid on the customer's chain at launch; settlement in IGN with a 10% burn follows the proof bridge in phase two", and the tile's label to "phase two". Extends P10 and overclaim 52.
|
|
|
|
Evidence: spec 5.4; `site/index.html`. Review id R3.24.
|
|
|
|
### C13. Monero's seven years do not price a 256 MiB SRAM die
|
|
"RandomX's cache is 256 MiB too. Nobody built the die for Monero because the prize was small. That is not evidence about the die."
|
|
|
|
Status: Conceded, stated (5 October 2026, night): `site/litepaper.html`, What Igneum does not claim, "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". Was: Conceded, label needed; extends C2.
|
|
|
|
Answer: Correct. The precedent argument transfers the cache size and not the economics; see M16 for the pricing and the lever.
|
|
|
|
Evidence: none beyond M16. Review id R3.16.
|
|
|
|
### L7. "Where the price comes from"
|
|
"A heading in a document that says it is not an offer, followed by 'both reduce supply as they happen'. That is a value-accrual argument under a heading about price."
|
|
|
|
Status: Fixed (3 October 2026): heading "Where fees go" and the sentence deleted, `site/litepaper.html` Economics. Counsel review of the section remains under L1 and L2. Was: Open, counsel; text fix now.
|
|
|
|
Answer: Correct as a reading. Fix: the heading becomes "Where fees go" and the sentence "Demand comes from use of the chain and from outsiders buying proofs, and both reduce supply as they happen" is deleted; counsel reviews the Economics section (L1, L2).
|
|
|
|
Evidence: `site/litepaper.html`, Economics. Review id R3.23.
|
|
|
|
### L8. Third-party names as implied outcomes
|
|
"'Native USDC is requested from Circle during public testnet.' 'Canto and Blast proved builders come for this.' Names of companies next to outcomes you do not control."
|
|
|
|
Status: Conceded, stated (5 October 2026, night): `site/litepaper.html`, Questions builders ask, "whether it is issued is Circle's decision"; Canto and Blast absent from the page (grep, tonight). Was: Conceded, wording fix. Sweep (5 October 2026): public text, testnet-prep branch.
|
|
|
|
Answer: Correct. Fix: "The project will ask Circle for native USDC during public testnet; whether it is issued is Circle's decision" and the Canto and Blast sentence as overclaim 39 already rewrites it.
|
|
|
|
Evidence: `site/litepaper.html`, Building, Questions builders ask. Review id R3.25.
|
|
|
|
### G9. The release-key steward is one person, and a lost key cannot be revoked
|
|
"Spec 8.2: the key that signs the software every miner runs is held by 'the steward named in the published key policy', policy deferred to testnet. And item 5 says a lost key is revoked by its own last signed release, which a lost key cannot sign."
|
|
|
|
Status: Rule fixed (3 October 2026): spec 8.2 item 5, rotation signed by the current key and revocation signed by the previous key (a pre-signed certificate for K0), both published in a block; item 2 moves the policy to before the client ships and adds the entity and jurisdiction. Steward disclosure itself remains (O-8.1, L1). Was: Open, policy and rule fix named; extends O-8.1.
|
|
|
|
Answer: Correct on both. The steward is the control point a regulator writes down, and the revocation path as written freezes the update channel for ever on a lost key. Fix: a pre-signed revocation certificate held apart from the signing key, or a 2-of-3 key set with the policy published before the client ships rather than before testnet; and the entity and jurisdiction that employ the steward named with it (L1).
|
|
|
|
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: 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: 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).
|
|
|
|
Evidence: `/tmp/igneum-devnet/node1.log`, `sim/difficulty/devnet-2026-10-03.csv`, the launcher log on the PC. Review id R3.15.
|
|
|
|
---
|
|
|
|
## External review entries (3 October 2026, night): the litepaper
|
|
|
|
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: 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.
|
|
|
|
Evidence: M1, O-1.17, spec 1.13 and 1.16, M16's arithmetic. Experiment: the scoring rules published with the benchmark, then the first scored submission. Review: external, point 4.
|
|
|
|
### F19. Old vote keys can be bought; fresh hashrate cannot buy weight
|
|
"Weight is 30 days of blocks per key, and keys are free to make and free to sell. I do not rent hashrate for 20 days. I buy, borrow or steal the vote keys of pools that already mined those 20 days. Your simulation models the renter and never the buyer."
|
|
|
|
Status: Answered with evidence (`sim/results_v2.md` scenario K, 4 October 2026, at the 0.85 and the 2/3 floor, seeds 7 to 19): a bought key is worth the blocks it holds and nothing more. Keys worth 20% of the window plus 30% of hashrate never reach a third; keys worth 40% hold the veto from purchase until day 19 to 20 and are worth 30% on day 30, the same as fresh hashrate; 0 conflicting locks in every row. The cost at the 2/3 floor: a silent 40% buyer stalls 63,307 to 68,716 of 86,400 checkpoints in 30 days (305 to 1,085 at the old floor). The 40/40/20 row is scenario I (0 conflicts). O-3.15 was decided on 4 October 2026 (the 2/3 floor). Not modelled: a seller who keeps a copy of the key and equivocates; the price of a pool's key against F5's hashrate cost is not a simulator question. Was: Open, experiment scheduled (O-3.15).
|
|
|
|
Answer: Correct, and the ledger had no entry for it. Spec 3.1 W6 says weight is the only Sybil-resistant quantity because it takes public mining to earn; it does not say what happens when an earned key changes hands. A compromised or sold key carries its whole 30-day history, so the 10-day and 20-day figures of F5 apply only to an attacker who mines; a buyer's day count is zero. What limits it today: W5 moves weight to a successor only by a message the old key signs (O-3.11), equivocation strips a key for 30 days (3.6), and pool keys are few and public (F10). What is missing: the acquisition cost of the top pools' keys against the hashrate cost of F5, whether weight should decay faster than 30 days when a key's blocks stop matching its earlier profile, and whether W5 should make the successor re-earn. Gate 3, in `finality_v2.py`: k% of weight changes hands at day 0 against the same k% arriving as fresh hashrate, for k in 20, 34 and 40, with the 40/40/20 partition row the reviewer asked for under the active-set rules and the floor, reporting time to a conflicting lock under each.
|
|
|
|
Evidence: spec 3.1 W5 and W6, 3.6; `sim/results_v2.md` (renter scenarios only). Experiment: O-3.15. Review: external, point 2.
|
|
|
|
### 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: 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."
|
|
|
|
Status: Fixed in the node and shipped, rule not yet activated on the live devnet (5 October 2026, evening sweep). Was: Fix built, pending rollout (4 October 2026, evening; branch `finality-fixes` of the node, behind `finality_v3_activation_daa`, `docs/plans/finality-v3-rollout-devnet.md`). Was: Open, found by the team (4 October 2026, 12-node cloud devnet, second partition run).
|
|
|
|
Sweep (5 October 2026, evening): the code is on every node since 0.3.4 (the 0.3.4 fork was `finality-fixes` 6aa69a45, which carries the fold and the frozen table; 0.3.5 to 0.3.8 keep it, `docs/plans/release-0.3.5.md` 1b) but the switch is not thrown: the live override file read by the 0.3.6 digest check is `{"difficulty_v2_activation_daa": 33000, "proving_v0_activation_daa": 84100}` (`docs/plans/release-0.3.6.md` 8g) and the default is never on every network (`consensus/core/src/config/params.rs`, `finality_v3_activation_daa: u64::MAX` on devnet), so the live devnet runs rule v2 and today's locks still carry 67.0% to 71.9% of active weight (node logs, 5 October 2026: PC 2 `checkpoint 2612 LOCKED ... 67.0% of active`, PC 1 `3080 LOCKED ... 71.9%`). Rollout is the operator step N3 of the plan (publish the switch in the manifest override and every hand node's file at once, as the proving activation did). Decision owner: the project lead (N3). Sweep (5 October 2026): nothing runnable without the devnet rollout; rule v3 is measured on the fast-time 3-node network (held certificates 6 of 6 at 11 of 11 indices, 0 conflicts, lock latency unchanged; bench-log "finality rule v3"). The rollout is an operator step.
|
|
|
|
Answer: True as measured, and the cause is not a cut-off at all: the node builds the certificate the instant the votes it holds meet Q3, and carries that one. Measured on the cloud logs of the healthy stretch 11:45 to 14:00 UTC (212 indices, `infra/cloud-devnet/results/2026-10-04/f22-vote-timing.md`, script `tools/finality-attacks/vote-timing.py`): the first certificate was built median 1.24 s (p99 1.71 s) after the first node determined the checkpoint, with 7 to 10 of 12 signers (mean 8.27); by then 10.24 votes had been issued on average, so about two were in flight (the miner's 1-s poll, a 250-ms gossip pump per hop, inter-region RTT up to 289 ms) and about two were issued later; the last of the 12 votes was issued median 1.45 s, p90 2.36 s after the first determination. Holding for 1 s after the first build would have carried all 12 votes at 192 of 212 indices; the other 20 are one event, miners 01, 06 and 11 down together for 10 minutes across indices 377 to 396 (the afternoon `hop.sh` restarts), not relay lag. The fix (spec Q4, rule v3): the first certificate still forms at quorum, so lock latency is unchanged; once every voter has signed, or `certificate_fold` DAA seconds after the determination (3 on devnet, 6 on mainnet), a node rebuilds the certificate from every vote it has seen and gossips the heavier one, and every node replaces a held certificate with a verified heavier one over the same block. Presence needs nothing: under the block reading of Q2 a late vote already counts once any block carries it. Unit test `fold_round_carries_late_votes_and_heavier_certificates_replace` (node, `processes::finality`). Network figures: `docs/bench-log.md`, "finality rule v3".
|
|
|
|
Evidence: `infra/cloud-devnet/results/2026-10-04/partition-sin-20261004-140305/partition.md`, `f22-vote-timing.md`; bench-log "Hetzner partition and hash-step", "finality rule v3"; spec 3.3 Q4, 3.10.
|
|
|
|
### 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: 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: 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."
|
|
|
|
Status: Simulation half run (4 October 2026, `sim/economy`, scenarios b, d and e: external pays 10x while the coin falls 70%, the 20% operator leaves, a 30% operator never fulfils its assignments; 5 seeds; every operator maximises its own profit): no backlog in any scenario, every block proven within 60 s in every hour, hash troughs at 82% of its pre-event level under b and 75% under d (80% at day 30), 10% of cards off under b (`docs/analysis/economy-2026-10-04.md` sections 3 and 7). The model is closed-form inside a tick and has no `f_p` controller, so the `f_p` and `B_p` paths are not shown; the phase 4 devnet half of O-5.9 is still owed. Was: Open, simulation and testnet experiment scheduled (O-5.9).
|
|
|
|
Answer: The premise that the design relies on voluntary scheduling is wrong; the stress test is missing. Nothing in spec 5.3 or 7.2 asks an operator to prove at a loss: the 20% pool is paid per block as a fixed amount divided by proving cost, shards go by sortition then open claiming, and an unproven block delays only its proof (P9). The two base fees re-price when provers leave (spec 5.1: `f_p` rises from the unproven backlog) and the backlog rule of design 4.3 halves `B_p` per 600 blocks of backlog, so the chain carries less gas rather than falling behind. What is not shown is the loop under the reviewer's shocks. R8 simulates `f_e`, `f_p` and the hash-or-prove switch against devnet fee traces; it has not run, and it models no external price ten times the internal one, no falling IGN price, no large operator leaving, no deliberately unfulfilled assignments and no profit-only clients. O-5.9 adds those five to the R8 simulation and then to the phase 4 devnet with profit-only prover clients, reporting backlog depth, time to clear, the `f_p` and `B_p` paths, and income per card under each shock. Extends P8, P9, E6 and R8.
|
|
|
|
Evidence: spec 5.1, 5.3, 7.2; execution-layer 4.3, 9.1 R8. Experiment: O-5.9. Review: external, point 3.
|
|
|
|
### E13. One diagram per payment route, or operator income and protocol income blur
|
|
"Your customer brief says dollars on the customer's chain; your economics section says IGN with a burn; your tiles said 'at launch'. Draw every route separately: currency, recipient, fee, any IGN purchase, any burn."
|
|
|
|
Status: Conceded, stated (5 October 2026, night): `site/litepaper.html`, Economics, "Every payment route", six rows (emission; base fee; priority fee; external job at launch; external job after the proof bridge; the official client's dev fee as operator income), columns currency, recipient, fee, burn; `docs/commercial/prover-customer-brief.md`, "Every payment route", the same six rows. Source: `docs/design/payment-routes.md` (3 October 2026), whose nine-row table the six rows condense; its section 4 states are of 3 October and the litepaper's labels supersede them (the dev fee and the escrow payout are implemented now). Was: Open, document scheduled (O-5.10). Sweep (5 October 2026): no route figure exists yet (the customer brief has no route table and the litepaper none); public text, testnet-prep branch.
|
|
|
|
Answer: Correct. P10 fixed the contradiction in words and E11 fixed the tile; no single figure shows the routes. There are five: emission (80% producer, 20% proving pool, per block); base fee (burned in full on both gas dimensions); priority fee (80% miner and provers, 20% called app, unregistered share burned); external jobs at launch (customer's chain, customer's currency, payout contract by miner address, no burn); external jobs after the proof bridge (IGN on Igneum, 90% provers, 10% burn). A sixth is the official client's 1% dev fee to the entity (E5), which is operator income and never protocol income. The diagram goes in the litepaper's Economics section and in the customer brief, one route per row with currency, recipient, fee and burn, and no row that adds operator revenue to protocol revenue. Boundless's documented lifecycle (request, bidding, verification, payment) is the reviewer's comparison and approximate (C10).
|
|
|
|
Evidence: spec 2.5, 5.1 to 5.4; `docs/commercial/prover-customer-brief.md`; P10, E5, E11. Decision: O-5.10. Review: external, point 5.
|
|
|
|
### 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: 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.
|
|
|
|
Evidence: E4, E5, G1, G5; fud-fixes rows 47, 50, 71. Decision: the project lead, before the repository goes public. Review: external, point 6.
|
|
|
|
### E15. The security budget through successive halvings with low fees and no external demand
|
|
"Walk the schedule forward: emission halves every two years, the base fee is burned, the priority fee is small on a quiet chain, and nobody buys proofs. What does a card earn in year 7, and at what price does hashrate leave? Report what reaches miners and provers apart from what is burned."
|
|
|
|
Status: Decided (5 October 2026, morning, by the owner): the 4,000,000,000 IGN hard cap stays absolute and there is no tail emission. The security budget after the subsidy fades is the proving market (external proof jobs, dollars-priced work settled in the token, 90% to provers, spec 5.4) plus fees (spec 5.2); provers' income does not depend on emission. Review trigger, spec 5.10.3, written as a rule: if external proving revenue is under one fifth of the block subsidy over any 90-day window after year 5, the tail-reward question goes to the miners' signalling vote (spec 5.7 and 5.8, encoding O-5.3), and the protocol itself never changes emission without that vote. Evidence: `python3 sim/economy/security_budget.py` (5 October 2026, defaults: USD 0.12 per kWh, 300 W, 124 MH/s a card): the subsidy to miners alone is under the USD 1,000,000 floor (the power of 3,169 cards) from year 7 at USD 0.005, year 11 at USD 0.02, never within 14 years at USD 0.10; at the crossing USD 500,000 powers 1,584 cards and a 51% attacker matches them for USD 1,369 of electricity a day, USD 27,379 over 20 days; no fee level in the grid moves a flat-price year; the -30% a year path crosses in year 5 (year 6 at 1 IGN of tips a block with launch demand), the +30% path never. Stated in spec 5.10 (table, decision, trigger), spec 06 O-5.11 (decided), the litepaper Economics section ("Security after the subsidy") and the homepage economics tile. Was: Answered with evidence (model; 5 October 2026 sweep). `docs/analysis/security-budget.md` (3 October) walks the schedule through six halvings at three flat prices: emission to miners falls below a USD 1,000,000 floor (the power of about 3,000 cards) in year 7 at USD 0.005, year 11 at USD 0.02, and not within 14 years at USD 0.10. `sim/economy/security_budget.py` (new tonight, `python3 sim/economy/security_budget.py`) adds a fee grid (0, 0.01, 0.1 and 1 IGN of tips per block; external demand 0 or USD 2,000 a day), a falling (-30% a year) and a rising (+30%) path, and the hashrate response at USD 0.12 per kWh, 300 W and 124 MH/s per card. Result: no fee level in the grid moves the crossing year (1 IGN per block of tips is 12.6 million IGN a year to miners, under a tenth of year-7 emission); the falling path crosses in year 5, the rising path never. What the budget buys at the crossing: at USD 0.005 in year 7 the miners' USD 500,000 pays the power of 1,584 cards (196 GH/s at today's 5090 rate), and a 51% attacker matches that fleet for USD 1,369 of electricity a day, USD 27,379 for the 20-day two-thirds campaign (year 1 at the same price: 12,206 cards, USD 10,546 a day, USD 210,924 for 20 days). Those are power-only upper bounds for the fleet and lower bounds for the attack. The litepaper sentence is public text (testnet-prep). Was: Open, simulation scheduled (O-5.11); extends E1 and E6.
|
|
|
|
Answer: Correct that the ledger concedes the cliff (E1) and the halving bet (E6) and has computed neither. O-5.11 is a model: emission per spec 2.5 through year 12; a fee grid (priority fee per block at low, medium and high use; external jobs at zero, low and the brief's launch assumption); hashrate as a function of income per card at a stated electricity price under a flat, a falling and a rising IGN price; reporting per year the payments to miners and to provers apart from the burn, the hashrate that income supports, and the cost of a 51% rental against it. The honest output is the year and the price at which the budget fails under the no-demand, flat-price case, stated in the litepaper's Supply section next to the tail-emission alternative. The flat-price column is the one that counts.
|
|
|
|
Evidence: spec 2.5, 5.1 to 5.4; E1, E6. Experiment: O-5.11. Review: external, point 6.
|
|
|
|
### G11. Publish the inspectable components now, labelled experimental
|
|
"The organisation has no public repository. Harnesses, test vectors, simulators and the specification could be public tonight, marked experimental. Waiting for January is a choice, and it reads as hiding."
|
|
|
|
Status: Decided (4 October 2026, 08:20 UTC): the specification subset is public as `igneum-network/spec` (`docs/plans/public-repo.md`), labelled; the node fork, the proving code and the harnesses stay private until the benchmark. Was: Open, decision for the project lead.
|
|
|
|
Answer: The fact is conceded in X1 (the repository is private and the site says reproducible) and the pre-publication steps are in `docs/fud-fixes.md` section 5 (ledger out of the tree, CLAUDE.md rewritten, history rewritten, licence). The reviewer asks for an earlier date than January 2027 and a narrower scope: the benchmark harnesses, the test vectors, the simulators and `docs/spec/`, each labelled experimental, with the node fork following when the gate-2 work is in. the project lead decides which components, under which licence, and when; section 5 runs first in any case. The reviewer's companion advice, one proof-request workflow and one reference application before any broader app set, is the same decision's scope: the genesis-app list (G4, O-5.4) is not a prerequisite for the benchmark or the testnet.
|
|
|
|
Evidence: X1; `docs/fud-fixes.md` section 5. Decision: the project lead. Review: external, point 7.
|
|
|
|
### 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: 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.
|
|
|
|
Evidence: `site/journey.json` phases 4 and 5; `docs/commercial/prover-customer-brief.md`; L4, L6. Experiment: the pilot, reported in the bench-log with the agreed numbers. Review: external, point 5.
|
|
|
|
### 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: 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, blocked on the public testnet (weeks away, when the go checklist closes; see X31): 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."
|
|
|
|
Status: Written (4 October 2026): `docs/evidence.md`, one row per public claim with five labels (tonight, counting the label column of the claims table: designed 9, implemented 8, tested by the team 26, reproduced externally 3, reviewed independently 2). Publication with the benchmark release is still O-X.3. Was: Open, publication scheduled (O-X.3).
|
|
|
|
Answer: Correct. The bench-log records machine, command and number; the spec labels rules Designed, Measured, Target or Decided; neither says who ran a test or whether anyone else has. The evidence page ships with the benchmark release and carries one row per public claim: the claim, its status, the exact version (commit and release), the reproducible test (command or script), the result with its bench-log entry, and one of the four labels, with audits and reviews tied to the version they read. "Tested by the team" is the only label any row can carry tonight; G2's disclosure applies to the whole page. The ledger's own statuses map onto the labels and are not replaced by them.
|
|
|
|
Evidence: `docs/bench-log.md`; `docs/spec/README.md` labels; G2. Publication: O-X.3. Review: external, point 7.
|
|
|
|
### 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: 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
|
|
"Send a transaction with a gas limit above the block limit and the node says thank you and keeps it. It can never be mined. Fill the queue with them."
|
|
|
|
Status: Fixed (4 October 2026). Spec 7.5 item 3; `igneum/exec/src/pool.rs` `EvmPool::add`.
|
|
|
|
Answer: Correct, and low: the queue slot was reserved against the sender's funds, so it was self-limited. The mempool now refuses `gas_limit > B_e` at admission with the error "gas limit N above the block execution gas limit B_e", as geth refuses `gas > block gas limit`. Measured: `gas_limit` 30,000,001 refused; 30,000,000 admitted and executed; unit test `pool::gas_limit_is_bounded_by_the_block_execution_limit`.
|
|
|
|
Evidence: `docs/bench-log.md`, 4 October 2026 "execution layer attack fixes"; the 3 October attack entry, F-exec-A.
|
|
|
|
### P19. An over-budget proving transaction runs for free, every time, and blocks its sender
|
|
"One big modexp costs more proving gas than a block allows. The node executes it in full, then skips it unpaid because it does not fit. Every node does that on every inclusion, and the sender's next nonces sit behind it forever. Free CPU on the whole network for the price of a signature."
|
|
|
|
Status: Fixed (4 October 2026). Spec 7.5 items 1 to 4; `igneum/exec/src/pgas.rs`, `executor.rs`, `pool.rs`, `rpc.rs`.
|
|
|
|
Answer: Correct, medium. The 3 October attack run showed it: a 9,000-call modexp loop ran 10.85 ms of native work, was skipped with `BlockProvingBudget`, paid nothing, and the sender's 14,000 and 20,000 loops were never includable behind it. Four rules now hold. (1) pgas is metered incrementally against the including block's remaining `B_p` and the transaction halts before the opcode or precompile that would cross it, so native work is bounded by `B_p`. (2) An aborted transaction is executed, not skipped: status 0, charged for the gas and pgas consumed to the abort, nonce advanced, so a later copy skips by the nonce rule at one account read and the sender's later nonces are free. (3) The mempool refuses a transaction whose estimated pgas exceeds `B_p` and the template packs by the estimate. (4) `eth_estimateGas` names the pgas when the cap is hit and `igneum_estimateGas` returns both dimensions. Measured after the fix: the same loop is refused by the mempool; a hostile miner's inclusion is cut at 29,998,593 pgas after 11.4 ms, the sender pays 0.0394 IGN, the nonce advances, a second inclusion costs 35 us, the next nonce executes; `igneum-exec-diff` 0 mismatches. What remains open is node policy, not consensus: the admission estimate costs up to `B_p` of simulation per heavy submission, under the RPC's state lock.
|
|
|
|
Evidence: `docs/bench-log.md`, 4 October 2026 "execution layer attack fixes" (before and after table); the 3 October attack entry, F-exec-B; unit tests `executor::over_budget_pgas_is_aborted_charged_and_the_nonce_advances`, `executor::the_cap_is_the_remaining_block_budget`, `executor::estimate_reports_the_cap`, `pool::estimated_proving_gas_is_bounded_by_the_block_proving_limit`, `pool::template_never_exceeds_the_remaining_proving_budget`.
|
|
|
|
## Difficulty attack findings (4 October 2026): fixed
|
|
|
|
### P20. The SP1 GPU client panics on shutdown and the compressed stage waited ten minutes
|
|
"Your first GPU proof run aborted with a core dump. What else aborts?"
|
|
|
|
Status: Fixed and confirmed (4 October 2026, third run `run-20261004-r3-shards`, 18:59 to 19:02 UTC): the buffered save closed the gap, the core proof finished at 19:00:38 UTC and the compressed stage started at 19:00:39; shard timings repeated within 0.3 s (core 9.1 s, compressed 10.5 s); a guest that returned 0 bytes on the second run was cleared by a forced rebuild and the package build now has a gate (`docs/bench-log.md`, "difficulty rule v2 activated", third-run paragraph). Was: (1) fixed in the host; (2) found on the second RTX 5090 run (4 October 2026, evening): the silence sits BEFORE the `STAGE compressed` line, so it is not the recursion setup.
|
|
|
|
Answer: Two separate things, neither in the proof. (1) After every proof was written, verified and uploaded, `sp1-cuda`'s client dropped its session key outside a Tokio runtime and panicked in its destructor (`sp1-cuda-6.8.1/src/pk.rs:63`, `client.rs:221`), so the host exited 134 with the results already on disk. Fix in our host: hold a runtime for the client's lifetime or drop the proof system inside one. (2) Between the core proof (08:49:10 UTC) and "Proving with mode: Compressed" (08:59:02 UTC) the host was silent for ten minutes while the card was idle; the compressed mode's recursion setup on first use is the suspect, and the second run must time it. Both go on the proving e2e benchmark standard as fixed overheads to measure, not hide.
|
|
|
|
Evidence: `docs/bench-log.md` "4 October 2026, proving v0 on the RTX 5090"; results file `block-78-increment-cuda-20261004-084838.json` on the PC; log intake id 10154. Experiment: O-7.4 (re-run with `--mode compressed` alone and a timestamp per stage).
|
|
|
|
### M23. Forge timestamps inside the rules and the controller mines you a 10x difficulty for free
|
|
"Your fast controller clamps every solvetime to 20 s both ways and says the next honest block cancels a forged one. Good: I stamp every block of mine at the earliest the past median allows, the honest block after me gets clamped to +20 s, the pair sums to zero, and your lanes measure 1 - 2a(1 - a) of real time at my share a. With half the hashrate your chain runs at a fifth of its rate and 9.9x the difficulty, on no extra hash. Kaspa's window only drifts 5 to 11%. And while I am at it, 85 blocks a second of PoW-less input drives your target below 2^64 and `calc_work` panics the node."
|
|
|
|
Status: Fixed (4 October 2026). Spec 2.3 rules 1 and 4 and the timestamp rules; `difficulty` branch of `vendor/igneum-node` (`consensus/core/src/igneum.rs` difficulty module, `consensus/src/model/stores/clock.rs`, `header_processor/{pre_ghostdag_validation,post_pow_validation,processor}.rs`, `processes/difficulty.rs`, `virtual_processor/processor.rs`); `sim/difficulty/sim.py`.
|
|
|
|
Answer: Correct on every point, and measured first by our own attack run (`sim/difficulty/attacks/README.md`, scenarios 3 and 7): in the simulator a 50% forger took the block rate to 0.12 (earliest stamp) and 0.56 (latest) of target; on a 3-node test network to 0.24 and 0.59 blocks/s at 3x and 1.9x difficulty on an unchanged hash rate; the flood underflowed the 192-bit work type after 4,142 blocks. Spec 2.3's "the next honest block cancels it" was the bug, not the defence. Three rules now hold. (A) A header may be at most 10 s ahead of the node's clock (`FUTURE_TOLERANCE_MS`, Kaspa's 132 s kept only as the past-median window size) and at least its selected parent's timestamp minus 10 s (`BACK_TOLERANCE_MS`) beside the past-median rule, so every forgery is inside half the solvetime cap. (B) Every chain step of the short and epoch lanes is measured on a sanitised clock stored per header, c(b) = max(c(p) + clamp(t(b) - c(p), -20 T, +20 T), t(b) - 60 T), step = min(c(b) - c(p), 20 T), so forged steps telescope and are paid back by the honest blocks after them instead of cancelling to zero. (C) Both rule paths bound the output at 2^128 (`bound_target`), so block work stays under 2^128. Measured after the fix, simulator, seeds 7 to 9: the forger at 30% or 50%, earliest, latest or alternating, drifts the rate +0.4% to +1.1% after an hour (worst seed +2.7%, difficulty ratio 1.00, worst gap 10 s); the base profiles move by under 10% on the 3-seed means (down50 faster, polluted peak 12x against 8x, hopping and the record unchanged within noise); the flood stops at 2^128 after about 2,630 blocks with no panic (unit test). Test network, 3 `igneumd` nodes, 50% forger for 15 minutes: earliest allowed stamps, chain rate 0.82 blocks/s in the honest phase and 0.88 during forging at difficulty 102k to 100k (last five minutes 0.83 at 106k); latest allowed, 0.78 to 0.89 at 102k to 97k; 0 rejected of 986 and 1,028 blocks, delivered hash unchanged (A 0.110 and 0.112 MH/s, F 0.109 and 0.111); the 3 October rule on the same schedule fell to 0.24 blocks/s at 275k and 0.59 at 170k. Either part alone fails: the bounds without the clock still lose 36% and 83% to past-stamping, the clock under Kaspa's 132 s bounds collapses at 50% (the clock's lag is a martingale once the forgery range exceeds half the cap).
|
|
|
|
Evidence: `docs/bench-log.md`, 4 October 2026 "difficulty rule: timestamp attack fixed"; `docs/analysis/difficulty-2026-10-03.md` addendum (before and after table); `sim/difficulty/attacks/README.md`; unit tests `igneum::tests::sanitised_clock_telescopes_a_forged_stamp`, `difficulty::tests::igneum_clock_steps_pay_a_forgery_back`, `difficulty::tests::igneum_flood_at_85_blocks_per_second_stops_at_the_minimum_target`, `difficulty::tests::both_rules_share_the_target_floor`. Review ids: attack README scenarios 3 and 7.
|
|
|
|
## Proving v0 findings (4 October 2026, afternoon): stated, not fixed
|
|
|
|
### 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: 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.
|
|
|
|
Round 4 (6 October 2026, 21:0x UTC, the 0.3.16 exec work): Fixed on a branch, pending merge. Fork `exec-sync-0313` da2d17ec puts the proof check on the consensus path: from `proving_consensus_verify_daa` (never by default; with `proving_shard_program_id` and `proving_aggregator_id` in the digest once set) body validation in context verifies every carried record's proof in-process (sp1-sdk's LightProver, the keys embedded from `proving/igneum-prove/elf`) against the pinned program id and the record's statement; a failing proof invalidates the block (`RuleError::IgneumInvalidProofRecord`, the relaying peer disconnected); a proof not held is fetched from the relaying peer (`IgneumRequestProofRecords`, payload 78) and the block retried once, never marked. Measured: 0.204 to 0.232 s a proof on one M5 Max core, 0.400 s on igneum-build-1, release, in-process; the harness `tools/exec-sync/forged.mjs` 8/8 in 23.6 s (an attacker with the rule off carries a forged record; the honest peer asks for the proof, refuses the block in 0.000 s of verify, pays nothing). A node whose embedded keys are not the pinned ids refuses to start. Open for 0.3.16.1: the finality-horizon skip (a block a certified checkpoint covers needs no proof check), so a fresh joiner's syncer serves proofs only for the unfinalised window.
|
|
|
|
### 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, 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.
|
|
- **F1** (finality is attackable for the first month). Status: Fixed in the node on spec 3.8's recommended rule (4 October 2026); the litepaper statement and the launch-month simulation (O-3.1) remain. `min_daa = weight_window` (2,592,000 DAA s on mainnet, 7,200 on devnet): no checkpoint certifies and no certificate is accepted while the window behind it is younger than its full length, and the node reports "finality not active, window filling, N of M"; spec 3.10 C5 row; unit test `no_certificate_while_the_window_is_filling`; attack harness scenario 5 re-run: master locked checkpoint 1 at DAA 29 by the burster's key alone (1 of 1 voters, 22 of 22 weight), fin-fixes locked nothing under the window and first at checkpoint 61 (DAA 1,829) with 5 of 6 voters (`docs/bench-log.md`, same entry). Was: Conceded, not yet stated in the litepaper; experiment and rule change scheduled.
|
|
|
|
## Status updates, 4 October 2026 (the floor raised to two thirds, O-3.15; branch devnet-v4)
|
|
|
|
the project lead's decision of 4 October 2026: the total-weight floor of Q3 is 2/3, not 17/30. A lock needs two thirds of all 30-day weight signing (the active test is implied), and finality pauses whenever less than two thirds of the weight is connected and signing; the chain continues on proof of work meanwhile and the node reports it. Spec 3.3, 3.3.1, 3.7, 3.9, 3.11; `sim/results_v2.md`, "Floor 2/3"; `docs/bench-log.md`, "finality floor 2/3"; litepaper Finality and "What Igneum does not claim".
|
|
|
|
- **F2** (the two-hour presence window is an eclipse vector). Status: Closed by rule, floor raised (4 October 2026). A lock needs two thirds of total weight whatever the presence window says, so an eclipsed faction can lock only with two thirds of the network inside the eclipse, which is the twenty-day public event of spec 3.1. Re-measured at the 2/3 floor: the poisoned eclipse (34% attacker plus a 20% pool, the eclipsed side at 54%) gives 0 conflicting locks and 0 locks on the eclipsed side at 1, 2 and 4 h in every seed (`sim/results_v2.md` L3 and F2's floor1.00 rows). Was: Closed by rule (the 56.7% floor).
|
|
- **F16** (a lock can become uncertified after a heal). Status: rule unchanged (spec 3.11.4: a verified certificate is never withdrawn, O-3.17 implements the conflict report). What the floor changes is how the state F16 describes arises: two certificates at one index now need equivocators holding at least one third of total weight in every scenario (two certificates need 4/3 of weight in signatures), not 13.3% across a partition that outlasts the presence decay (`sim/results_v2.md` H at 2/3: 0 conflicts and no lock on either side through a 33% equivocator, conflicts from minute 0 at 34%). Ten days of 100% hashrate in public, or the long-partition case of F21.
|
|
- **F18** ("a silent minority cannot freeze finality" is false under the floor). Status: Fixed again (4 October 2026). The litepaper now says a lock needs two thirds of all 30-day weight and that finality pauses whenever less than two thirds is connected and signing. The pause threshold moved from about 42% of weight silent to one third: in the model, whose keys are in outage 2.2% of the time, 30% silent locks every checkpoint, 32% locks 88%, 33% locks 11% and 34% locks none for as long as it stays silent (`sim/results_v2.md` L1). Was: Fixed (56.7% sentence).
|
|
- **F9** (half the hashrate leaves and finality stalls for ten days). Status: Conceded, stated (4 October 2026). Under the 2/3 floor the critic's number is back: 50% churn pauses finality for 10 days and 35% churn for 1.4 days, until the departed weight ages out of the window (`sim/results_v2.md` D's total column, which the 2/3 floor equals arithmetically, and L2). The chain runs on proof of work meanwhile, the node reports the pause, and the litepaper says so. This is the price of the one-third safety bound and was taken knowingly. Was: Answered by design (the active denominator recovered in two hours).
|
|
- **F21** (new, from attack scenario 6A). "Your floor is a fraction of a table each side computes for itself. Cut the network in half and leave it cut: after a while each half's window is full of its own blocks, each half holds two thirds of its own table, and both lock without any attacker at all. Your simulation never saw it because it kept the weights global." Status: Fixed in the node and shipped, rule not yet activated on the live devnet (5 October 2026, evening sweep: the code has shipped in every node since 0.3.4 and the switch `finality_v3_activation_daa` is absent from the live override file, default never; the F22 entry above carries the evidence; the overlay-against-GHOSTDAG run of C4 exercised rule v3 on the live node line on the fast-time harness tonight; decision owner for N3: the project lead). Was: Fix built, pending rollout (4 October 2026, evening): rule v3, spec 3.3 Q5, the frozen weight table, on the node's `finality-fixes` branch behind `finality_v3_activation_daa` (`docs/plans/finality-v3-rollout-devnet.md`). The rule: a certificate also needs its signers to hold two thirds of the weight table at the last certified checkpoint on C_i's chain, at that table's weights, while that checkpoint is less than one window old. Both sides of a partition share that table and neither can fill it, so no side under two thirds locks until 30 days have passed without a certified checkpoint; at the heal locking resumes on one chain. Proved first in `sim/finality_v2.py` scenario M (`sim/results_v2.md`, "Rule v3"): 50/50, 60/40 and 55/45 splits never lock in 12 days (v2: days 10.2, 5.2, 7.9), both sides of a 31-day split lock alone at day 30.00 when the frozen table expires, the 70/30 majority locks at once under both rules, every pre-heal lock is kept and the first lock after the heal comes 0 minutes in, the 34% equivocator still conflicts (the one-third bound of 3.11.2 is untouched). The price, stated in 3.7 item 2: a set of one third or more that stops mining and signing at once pauses finality for 30 days (v2: 1.7 days at 35%, 10.1 at 50%); a gradual departure costs nothing because every certified checkpoint re-freezes the table. A view still cannot count blocks it has never seen, so a partition longer than a window forks as before; the fix moves the bound from a third of the window to the whole of it. Node: `processes::finality` (`frozen_table`, the Q5 test in `evaluate`), unit test `frozen_table_holds_a_side_without_the_other_keys_for_one_window`; network figures in `docs/bench-log.md`, "finality rule v3". Was: Conceded, stated (4 October 2026): spec 3.3.1, 3.7 item 9, 3.9 guidance; `sim/results_v2.md` L4 (view-local weights). Correct. A side with pre-split share s holds s + (1 - s) t / 30 of its own table on day t and two thirds of it from day 30 (2/3 - s) / (1 - s): day 10 at 50/50 (day 4 under the old floor), day 5 for the 60 side of 60/40 (at once under the old floor). On the devnet the old floor fell at 84 s of a young 1,439-DAA window (`docs/bench-log.md`, "finality v2 attack harness", S6A); at 2/3 the same cut on a full 1,800-DAA window held for the whole 150-s split and fell at 205 s against a predicted W / (3R) = 200 s (`docs/bench-log.md`, "finality floor 2/3", 6A and 6A long heal). What the devnet adds to the simulation: after the heal the other side's blocks are merged red, so each side's own share jumps rather than drifts, both sides of a 50/50 split certify their own checkpoints within 10 s of each other, and F1 then pins each node to its own certified chain: 26 conflicting certificates and 23 disagreeing locked indices across three nodes, no equivocation, a finality fork that the network heal did not undo and that only an operator's trusted certificate (F5, not implemented) can resolve. No rule removes it, because a view cannot count blocks it has never seen; the floor at two thirds moved the day from 4 to 10, and the exchange guidance treats a node partitioned for more than a day as proof of work until it has rejoined. A rule option for gate 3, not adopted: evaluate the floor against the table of the last locked checkpoint while no newer lock exists, which trades F9's 10-day recovery for a manual override.
|
|
|
|
### M24. Your two-lane controller oscillates for an hour when a second miner joins mid-epoch
|
|
"Watched your devnet this morning. The second 5090 came in at 10:12 and the difficulty never settled: 102M to 164M for forty minutes, 54 to 81 blocks a minute, three or four clamp steps stacked inside a second. Your fast lane and your slow lane disagree by a hair under the trigger and the rule flips between them every two minutes. One card joining is the mildest event a chain can see."
|
|
|
|
Status: Rolled out (4 October 2026, 18:37 BST): rule v2 activated on the live devnet at DAA 33,000 by the height switch after a 12-node cloud rehearsal (settle 157 to 272 s, no swing); node 1, the seed, the observer and the three app machines crossed the height on one chain with no fork and no restart of the chain (`docs/bench-log.md`, "difficulty rule v2 activated"). Still owed: the first v2 measurement on the devnet's own two-large-miner regime once PC 2 is back from proving. Was: Fix built, pending rollout (4 October 2026).
|
|
|
|
Answer: Correct, measured on the live chain and reproduced in the simulator (`docs/analysis/difficulty-2026-10-04-oscillation.md`). The cause is the reference lane: spec 2.3 of 3 October gave it the whole epoch, so a hash-rate step inside an epoch left it polluted by the pre-step blocks for the rest of the hour; the short lane read the true rate 11 to 25% above it, the 25% trigger flipped between the two on the short lane's noise, and the per-block clamps turned every flip into a ramp (3% a block up, 10% a block down). The DAG replay (`sim/difficulty/sim.py --live`, miners on two nodes with `igneum-miner`'s template staleness, GHOSTDAG, the rule as the node runs it) reproduces the record: std of log difficulty 0.115 against 0.134, 4.3 peaks of 1.31x against 4 of 1.37x, 104M to 169M against 102M to 164M, 54 to 77 blocks a minute against 54 to 81. The brief's five candidates (longer short lane, 3% ease clamp, one clamp per DAA second, hysteresis, median of three) each leave it between 0.09 and 0.13 because none of them cleans the reference lane. Rule v2 caps the reference lane at the newest 600 DAA score of the epoch (the epoch lane only; Kaspa's sampled window is not consulted): 0.026 with 0 lane flips and the target on the true level (142.6M against 139M) on all three seeds; the chain-only simulator agrees (0.14 to 0.19 against 0.02 to 0.08). Cost on the synthetic set (seed 7): steady std of the block rate 0.049 against 0.038 (blocks per minute CV unchanged, 0.130 against 0.135), the 50x step-up settles in 65.5 s against 61.7 s, the 50x step-down 753 s against 629 s, hops slightly faster, the polluted window's overshoot halved. Under attack (`attacks.py`, seeds 7 to 9): the greedy hopper gains one more point (at most +2.5% against +1.5%), the forger's drift falls to within 1% (worst seed 1.5% against 2.7%), the pulsed rental, the epoch games and the polluted window are unchanged, the 50x step-down is 8% slower and the steady estimate a quarter noisier. Built behind a height switch, `difficulty_v2_activation_daa` (a consensus parameter, default never, set by the override file), so the devnet moves to v2 at a chosen DAA score on the same chain. The epoch boundary itself clears the pollution, which the live chain showed at 11:02 UTC (DAA 7,200: within 1.3% per minute from 11:07 with no flips, the hash rate having also stepped down there).
|
|
|
|
Evidence: `sim/difficulty/records/live-2026-10-04.csv` and `live-2026-10-04-hashrate.csv`; `sim/difficulty/results.md` "Live replay"; `docs/bench-log.md`, 4 October 2026 "difficulty rule v2"; unit tests `difficulty::tests::reference_window_switches_at_the_activation_height`, `difficulty::tests::v2_reference_window_follows_a_step_inside_the_epoch_where_v1_eases_into_it`, `difficulty::tests::v1_and_v2_agree_in_a_steady_epoch`, `params::tests::override_params_carry_the_difficulty_v2_activation`. Rollout: the bench-log entry names the binaries and the order (Hetzner chain first, then the devnet nodes with the activation DAA in their override file).
|
|
|
|
---
|
|
|
|
## 9. Developers and apps (4 October 2026)
|
|
|
|
Added 4 October 2026 from `docs/design/developer-adoption.md` (section 6, ten reasons a founder says no). Only the conceded objections are entered; the answered ones are in that document with their evidence. Entries are numbered D for developers.
|
|
|
|
|
|
### D1. Your users are a gate, not a fact
|
|
"The miners are your user base? Nine devnet identities today, a 1,000-miner testnet gate whose word 'independent' is still undefined (X5), and miners are the most mercenary users of all: they sell."
|
|
|
|
Status: Conceded, stated.
|
|
|
|
Answer: Correct on the count and on the definition. The claim in `docs/design/developer-adoption.md` section 2c is narrower than "users": miners are funded wallets that are present and have a continuing reason to transact (they are paid every block and pay power bills), which gives a specific set of apps (pools, payout contracts, hardware finance, hashrate forwards) a customer before any consumer app has one. Loyalty is not claimed. The number that makes the claim real is the testnet gate, with O-X.1's definition of independent.
|
|
|
|
Evidence: `docs/bench-log.md` 4 October 2026 (devnet v4, 9 identities); `site/journey.json` phase 5; ledger X5.
|
|
|
|
### D2. The app share pays nothing
|
|
"Run your own table. A 100,000-gas call at your devnet fees pays the app 20,000 gwei, four ten-millionths of a dollar at your base price. A million calls a day is $146 a year. 'Apps earn the gas they generate' is the Canto pitch, and Canto's chain has $1.4M of lending TVL."
|
|
|
|
Status: Conceded, 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"; Canto and Blast absent from the page (grep, tonight). Was: Conceded, not yet stated. Fix: the litepaper bullet "Apps earn the gas they generate ... Canto and Blast proved builders come for this" is replaced by the "Why build here" text proposed in `docs/design/developer-adoption.md` section 7, which states the number.
|
|
|
|
Answer: Correct. The app share is a property of the fee flow, not an income at launch: 20% of the priority fee, per call frame, and the priority fee on an uncongested chain is whatever wallets quote by default. At the three price inputs of `docs/analysis/security-budget.md` and a 1 gwei tip, a million calls a day pays $146, $730 or $7,300 a year (the last at a 10 gwei tip). What is new in it against Canto and Sonic is library attribution at the code address and factory inheritance, and the fact that it comes from the user's tip and never from emission. The 20% should not be raised: Sonic's 90% has distributed about $2M in a year across a whole chain, and a larger share comes out of the miners' and provers' side, which is the security budget. Blast announced its shutdown on 2 October 2026, so the sentence citing it must go now.
|
|
|
|
Evidence: `docs/design/developer-adoption.md` section 2a tables; `docs/evidence.md` row 22; `docs/bench-log.md` 3 October 2026 (execution layer devnet v3); MoneyCheck 3 October 2026 (Blast); DefiLlama via search 4 October 2026 (Canto).
|
|
|
|
### D3. Proof of work in 2027 is a perception cost you cannot measure
|
|
"My investors and the exchanges I need read 'GPU-mined' as 2021. Whatever your proofs do, the label costs me."
|
|
|
|
Status: Conceded, no experiment possible.
|
|
|
|
Answer: Correct that the cost exists and that nothing in the design measures it. The argument the litepaper makes ("Questions builders ask": the energy buys a proof of every block as well as its ordering; no stake to capture, no builder cartel, no foundation that can change the rules) is an argument and not a measurement. The only evidence that will exist is whether rows 1 and 2 of the adoption sequence (miner apps, verifiable-compute apps) sign despite the label.
|
|
|
|
Evidence: none possible; `site/litepaper.html` "Questions builders ask".
|
|
|
|
### D4. No dollar, no DeFi
|
|
"No stablecoin and no bridge at genesis. 'Native USDC is requested from Circle' is a request. There is no DeFi without a dollar, and your consumer apps cannot exist until phase two."
|
|
|
|
Status: Conceded by decision (ledger E7, spec 7.3), restated here for builders.
|
|
|
|
Answer: Correct, and the sequence in `docs/design/developer-adoption.md` section 4 puts consumer apps third for this reason: after mainnet, after a bridge run by a named operator, after a published record of the app share and the job market. The alternative, a multisig bridge the project labels official, was refused on 3 October 2026. The sentence naming Circle is a request about a third party and the round-3 review already asked for it to go.
|
|
|
|
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 (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, 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.
|
|
|
|
### 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: 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: 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/<token>` 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/<token>/api/<fn>` 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=<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/<token>/` (`ui.html`) and the calls that page makes (`/r/<token>/api/<fn>`, `/r/<token>/c/<fn>`, `/r/<token>/wake`), documented in `relay/README.md`. Print lines: `tools/relay.mjs` shows `/r/<token>` 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: 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: 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=<id>` 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=<id>` 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: 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: 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."
|
|
|
|
Status: Fixed (rolled out 5 October 2026, 0.3.5: fork 20139145 = `finality-fixes` 6aa69a45 + `fud-consensus` 977db931 + `m20-pruning` d35b00cf + the miner branches, cut 07:33 BST, `docs/plans/release-0.3.5.md` 1b and 4b; node line 2b6d23ef from 0.3.6 at 09:34 UTC carries the same consensus code; every reachable app machine on the line by 09:32 UTC and the hand nodes and the seed restarted on it for the proving activation at DAA 84,100 the same morning, `docs/plans/release-0.3.6.md` 8j, bench-log "live devnet: the first shards proven"). Was: Fix built, pending rollout (4 October 2026, night; node branch `fud-consensus`, local worktree `vendor/igneum-node-fud`, no remote; main repo branch `fud-consensus`). Was: Open (4 October 2026).
|
|
|
|
Sweep (5 October 2026, evening): measurement line: every node on the line prints `Consensus params digest: f10a4eab...` at start (node logs of PC 1, PC 2, the Mac, Sam's Mac and the US laptop, 5 October 2026, the digest with difficulty 33,000 and proving 84,100), and the environment variables have no reader left in the miner (`IGNEUM_POW_DAY_MS` moved into the template, M25 confirmed the day-mismatch rejection on 5 October). No mainnet node has been started; the mainnet refusal line is covered by the unit test `env_pow_schedule_is_devnet_and_simnet_only` only.
|
|
|
|
The fix: `PowSchedule::from_env()` is gone. `PowSchedule::from_env_for(network, base)` applies the three variables on devnet and simnet only and returns `None` elsewhere; the daemon calls `Params::apply_env_pow_schedule()` after the override file, prints "PoW schedule from the environment (...)" when applied and "Ignoring IGNEUM_POW_... on igneum-mainnet: the environment never sets a consensus parameter outside devnet and simnet" when not, then installs the network's schedule from `Params` on every network (`install_pow_schedule`), so `Params.pow_epoch_blocks` is what runs; the lazy fallback in `pow_schedule()` installs the devnet constants, never the environment. The miner takes all three schedule values from the template (`pow_epoch.day_ms` joined the two epoch fields in `PowEpochInfo`, the RPC model and the gRPC proto), so `IGNEUM_POW_DAY_MS` has no reader left in the miner (R4.1.9's day split is closed with it). The effective schedule is part of the params digest of X18, so a devnet node with the variable set cannot connect to one without it. Unit test `env_pow_schedule_is_devnet_and_simnet_only` (consensus-core, `config::params::tests`): the variable moves the devnet and simnet schedule and digest, leaves mainnet's and testnet's untouched, and the caller can tell "ignored" from "nothing set". Spec 2.8 and 8.7 state the rule.
|
|
|
|
Answer (as found): Correct. `daemon.rs:339-340` installs the file's schedule only when the file names one; otherwise `PowSchedule::from_env()` (`consensus/core/src/igneum.rs:137-145`) installs on first read; the difficulty manager takes the global (`services.rs:113`); `daemon.rs:316-319` gates the file only. Fix: delete the environment fallback and install `Params.pow_epoch_blocks` from the network params on every start. Review id R4.1.1.
|
|
|
|
Evidence: the files above. Experiment: start a node with `IGNEUM_POW_EPOCH_BLOCKS=60` and no file; its template's `epoch_blocks` must be the network's value.
|
|
|
|
### 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: 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=<main checkout>/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: 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 <value>` 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."
|
|
|
|
Status: Fixed (rolled out 5 October 2026, 0.3.5: fork 20139145 = `finality-fixes` 6aa69a45 + `fud-consensus` 977db931 + `m20-pruning` d35b00cf + the miner branches, cut 07:33 BST, `docs/plans/release-0.3.5.md` 1b and 4b; node line 2b6d23ef from 0.3.6 at 09:34 UTC carries the same consensus code; every reachable app machine on the line by 09:32 UTC and the hand nodes and the seed restarted on it for the proving activation at DAA 84,100 the same morning, `docs/plans/release-0.3.6.md` 8j, bench-log "live devnet: the first shards proven"). Was: Fix built, pending rollout (4 October 2026, night; node branch `fud-consensus`, main repo branch `fud-consensus`). Was: Open (4 October 2026).
|
|
|
|
Sweep (5 October 2026, evening): measurement line, live: the digest refused a real mismatch the morning it shipped. A hand node restarted early with another `proving_v0_activation_daa` was refused by every peer for 20 minutes (bench-log "live devnet: the first shards proven"); the node logs carry 115 `consensus params digest mismatch` lines on PC 1, 46 on PC 2 and 56 on the Mac between 08:15 and 08:35 BST on 5 October 2026 (`Refusing peer ...: consensus params digest mismatch, local f10a4eab... remote a6da35e8...`), none since. Still open from this entry: the digest-less allowance on devnet and simnet (to remove), `rollout-v2.sh` still writes the file as two fields (R4.1.12).
|
|
|
|
The fix: `Params::consensus_digest()` (BLAKE2b-256, domain `IgneumParamsDigest`, every consensus field in a fixed tagged order: genesis, difficulty, mass and lane limits, blockrate, crescendo, the ten finality fields, the PoW schedule, the three activation heights; not the dead `timestamp_deviation_tolerance`, not seeders or ports; spec 2.8 lists it). The version message carries it (`paramsDigest`, field 11); `initialize_connection` refuses a peer whose digest differs with `ProtocolError::ParamsDigestMismatch` and one WARN naming both digests before any flow is registered, so a finality-only mismatch, which used to connect and WARN "names N voters" after the fact, never connects. A peer with no digest (an older build) is refused on mainnet and testnet and let in with a WARN on devnet and simnet while the devnet rolls (an allowance to remove afterwards). The node prints its digest at start. Unit test `consensus_digest_covers_every_consensus_field_and_nothing_else`. Measured (`docs/bench-log.md`, "round-4 consensus items", digest run; `tools/finality-attacks/fud.mjs digest`, fast time, ports 29400+): a listener on the shared fast-time override and a dialler whose finality block differs by one DAA second of window: the dialler was refused at the handshake on both sides ("Refusing peer ...: consensus params digest mismatch, local 4bf7... remote 7a40..." on the listener, the reject message on the dialler), 0 peers after 25 s on both; a third node on the shared override connected in 1 s. Control on the finality-fixes build 6aa69a45: the mismatched dialler connected (1 peer, no line). `rollout-v2.sh` still rewrites the file as two fields and the app still rewrites the packaged file (R4.1.12): with the digest both now fail loudly at the handshake instead of forking; the merge fix for the script is not done tonight.
|
|
|
|
Answer (as found): Correct. `protocol/flows/src/flow_context.rs:833` compares `network`; the version message has no params digest and no genesis hash. `pre_pow_validation.rs:37` and `pow_guard.rs:25-42` fork and ban on PoW and difficulty fields; `processes/finality.rs:669-688` only warns on a finality mismatch; `infra/cloud-devnet/rollout-v2.sh:20,35` rewrites the file as two fields; `app/igneum-app/src/engine.rs:742-760` rewrites `override-params.json` each start. Fix: a digest of the effective consensus params plus the genesis hash in the version message, refused on mismatch; the finality WARN becomes a refusal with the reason; `rollout-v2.sh` merges rather than replaces. Review ids R4.1.2, R4.1.12.
|
|
|
|
Evidence: the files above. Experiment: two nodes on different files; the handshake must fail with the field named.
|
|
|
|
### F23. The equivocation ban is node-local, so honest nodes refuse each other's certificates
|
|
"Evidence detected from an RPC vote stamps the sink's DAA; evidence carried in a block stamps the carrier's DAA. Two honest nodes hold different `until` for the same key, their voter lists differ by one at every checkpoint between the two expiries, and `voter_count` refuses the other's certificate for good."
|
|
|
|
Status: Fixed (rolled out 5 October 2026, 0.3.5: fork 20139145 = `finality-fixes` 6aa69a45 + `fud-consensus` 977db931 + `m20-pruning` d35b00cf + the miner branches, cut 07:33 BST, `docs/plans/release-0.3.5.md` 1b and 4b; node line 2b6d23ef from 0.3.6 at 09:34 UTC carries the same consensus code; every reachable app machine on the line by 09:32 UTC and the hand nodes and the seed restarted on it for the proving activation at DAA 84,100 the same morning, `docs/plans/release-0.3.6.md` 8j, bench-log "live devnet: the first shards proven"). Was: Fix built, pending rollout (4 October 2026, night; node branch `fud-consensus`, main repo branch `fud-consensus`). Was: Open (4 October 2026); reproduced by the red team the same evening on the stock s1 scenario (n0 kept the ban until DAA 726 against 239 on n1 and n2, 9 and 3 to 4 certificates refused "names N voters").
|
|
|
|
Sweep (5 October 2026, evening): measurement line, live: the persisted finality state converted on the upgrade on every machine (`Finality: state blob of layout 1 read and converted (0 evidence records)` once on PC 1, PC 2, the Mac, Sam's Mac and the US laptop, 5 October 2026), no node lost its locks, and in the 10 hours to 15:45 UTC the node logs of the five app machines carry 0 certificates refused "names N voters", 0 CONFLICTING and 0 EQUIVOCATION lines against 5,243 LOCKED lines (intake query over every `nodelog-*` upload, split per line server-side). No equivocation has happened on the live devnet, so the ban path itself is exercised only by the fast-time run below (`fud.mjs ban`: voter lists agree on three nodes at every index, 0 refusals).
|
|
|
|
The fix: the node-local `stripped` map is gone. Evidence is kept as `EvidenceRecord` (the two votes, the carriers with their DAA scores) and the ban at a checkpoint C is a function of C's past (`bans_at`): the key is stripped at C when some carrier lies in C's past and `daa(C) < daa(lowest carrier in C's past) + ban`. Evidence detected over RPC or gossip strips nothing until a block carries it; the node puts it in its next templates. The weight table cache stays ban-free and `voters_at` applies the checkpoint's own bans, so a certificate built before the carrier existed verifies on a node that saw the evidence later, and a node that saw it over RPC counts the same voters as one that saw it in the block. Evidence records are bounded (4,096; dropped once the ban ended two windows below the sink or never carried within one ban of being seen; 16 carriers per record), the same for vote and certificate carriers. The persisted state is layout 2; a layout-1 blob is read and converted on start, so no devnet node loses its locks on the upgrade. Unit test `ban_is_decided_by_the_carrying_block_so_nodes_agree_on_every_voter_list` (three `TestConsensus` nodes on one chain: the voter list agrees on all three at every checkpoint, the key is a voter before the carrier and after the ban and nowhere in between, the third node verifies the first two's certificates at every locked index). Measured (`docs/bench-log.md`, "round-4 consensus items", ban run; `fud.mjs ban`, 480 s, six voters, one equivocation at index 9 by a voter on n0 over RPC, n2 cut off 45 s around it and healed, so it saw the evidence late from the carrier block): on the `fud-consensus` build every node names 5 voters at the same indices (10 to 12 in the final pass, 10 to 13 in the first), 0 certificates refused "names N voters", 0 conflicting certificates, 0 locked indices disagreeing, voter counts agree at every index with lines on two or more nodes, locks continue to index 14 or 15 on all three. Control on the finality-fixes build: n0 (the RPC detector) refused 2 certificates "names N voters, this node counts M", the rest agreed because each node built its own; the red team's stock s1 scenario the same evening gave 9 / 3 / 4 refusals. Spec 3.6 and the 3.10 row state the rule.
|
|
|
|
Answer (as found): Correct. `ingest_evidence` (`processes/finality.rs:600-612`); `ingest_certificate` (`:680-688`). Certificate validity is not a function of the DAG, the same defect R3.9 found in the execution veto. Fix: stamp every ban with the DAA of the block that carries the evidence; evidence seen by RPC is only acted on once carried. Review id R4.1.3.
|
|
|
|
Evidence: the files above. Experiment: `tools/finality-attacks` with one equivocation detected on node A by RPC and on node B from the carrying block 30 DAA later; count certificates refused with "names N voters" between the two expiries; after the fix, zero.
|
|
|
|
Red-team run, 4 October 2026 (evening, the 0.3.4 finality-fixes build with rule v3 on, `docs/review/redteam-2026-10-04.md` row 15): reproduced by the stock scenario 1 (two keys equivocating at every index, 4 honest voters, 3 nodes, fast time). The node that received the equivocators' votes by RPC re-detected at every index (46 detections) and held the ban until DAA 726; the two nodes that saw the evidence only in blocks detected it at indices 1 to 3 (8 detections, ban until 239) and let it expire. The first detection alone stamped `until` 174 and 176 on the RPC node against 176 on the others. From index 9 the voter lists differed by two keys and the nodes refused each other's certificates: 9 refusals "names 6 voters, this node counts 4" on the RPC node, 3 and 4 refusals "names 4 voters, this node counts 6" on the others. Every node still locked 15 of 15 only because each could aggregate its own certificate from the votes it held; with 8 named aggregators on a real network that fallback is `aggregator_fallback` later and a node whose certificate the rest refuse is one more aggregation round behind at every index. Rule v3 does not touch this path. Severity stays serious; the fix above stands.
|
|
|
|
### F24. A checkpoint determination is never revisited
|
|
"After a reorg deeper than `checkpoint_depth`, the node's record for that index names a block off its chain. Every certificate the network forms for that index is refused as conflicting, with no equivocation anywhere, and the node voted for a block that is not on its chain."
|
|
|
|
Status: Fixed (rolled out 5 October 2026, 0.3.5: fork 20139145 = `finality-fixes` 6aa69a45 + `fud-consensus` 977db931 + `m20-pruning` d35b00cf + the miner branches, cut 07:33 BST, `docs/plans/release-0.3.5.md` 1b and 4b; node line 2b6d23ef from 0.3.6 at 09:34 UTC carries the same consensus code; every reachable app machine on the line by 09:32 UTC and the hand nodes and the seed restarted on it for the proving activation at DAA 84,100 the same morning, `docs/plans/release-0.3.6.md` 8j, bench-log "live devnet: the first shards proven"). Was: Fix built, pending rollout (4 October 2026, night; node branch `fud-consensus`, main repo branch `fud-consensus`). Was: Open (4 October 2026); extends F7 and C4.
|
|
|
|
Sweep (5 October 2026, evening): measurement line, live: the re-determination fired on the real devnet and left no hole. Checkpoints 2970 and 2971 were re-determined at 10:56:44 to 10:56:45 BST on 5 October 2026 on PC 1, PC 2 and the Mac at once (`Finality: checkpoint 2971 re-determined: block bb4aa204...` on all three, 7 / 8 / 4 re-determined lines per machine over the day including the first-start ones at indices 704 to 722), with 0 CONFLICTING lines and 0 refusals anywhere in the 10 hours to 15:45 UTC, and the three nodes' later locks agree (the console's last lock #3646 at 15:46 UTC). Before this fix the same event would have logged CONFLICTING for every certificate at the moved index and left the index unlocked on the losing side.
|
|
|
|
The fix: after every virtual change, every unlocked checkpoint record whose block is no longer a chain ancestor of the sink is determined again on the new chain ("re-determined" log line); the certificate held over the old block is dropped, the fold clock restarts. A certificate over a block other than the node's determination at an unlocked index (or at an index not yet determined, up to 64 ahead) is no longer logged CONFLICTING and discarded: it is held pending (4 per index) and verified when a re-determination names its block; a block that cannot be the index's checkpoint on any chain (C1 as a function of the DAG: blue score under the target, or the selected parent's not) is refused outright. CONFLICTING now means what 3.11.4 says: a certificate against a LOCK. The certificate verification itself is unchanged; a locked index is never re-determined (fork choice keeps the chain through it). The node's own keys do not re-vote at a re-determined index (that would be equivocation); the lock there comes from the network's certificate, which is the point. Unit tests `reorg_past_an_unlocked_checkpoint_re_determines_it_and_verifies_the_pending_certificate` and `a_locked_checkpoint_pins_the_chain_and_a_certificate_against_it_conflicts`. Measured (`docs/bench-log.md`, "round-4 consensus items", reorg run; `fud.mjs reorg`, n0 with 30% of the weight cut off for 180 s while the 70% side kept locking, then healed): on the `fud-consensus` build n0 re-determined its own 1 to 2 split indices on the majority chain, verified the pending certificates at determination (2 in the final pass), logged 0 CONFLICTING and 0 refusals, and ended with every index the majority locked locked on the same block (0 disagreeing). Control on the finality-fixes build: n0 refused 3 certificates "is for X, this node's checkpoint is Y" and never locked indices 8 and 9 that the majority locked (the permanent hole of this entry), 0 disagreeing because the hole is not a lock. The final pass also found that a chain which becomes the sink at a lower blue score than the old one (more blue work per block after the split's difficulty drift) re-determined index 9 at a sink below its depth, to a block below the target: fixed the same night (an index the new chain has not reached is un-determined and determined again when it has; unit test `a_shallower_sink_un_determines_the_indices_it_cannot_reach`) and re-run (`reorg-final2`, fork 977db931): the majority locked nothing during the split this time (Poisson again), n0 re-determined its one split index, verified 1 pending certificate at determination, 0 CONFLICTING, 0 refused, 0 disagreeing, no record below its target, every index the majority locked locked on n0 too. The red team's own reproductions on the new build (`tools/finality-attacks/redteam/rtfin.mjs`, fin-attacks miner at 6 blocks/s): `f24c` (3/3 split, 16 s cut) PASS with 0 refusals, 0 CONFLICTING, 0 stuck indices, 0 disagreeing; `f24b` (4/2 split, 24 s cut) FAIL on both builds for a reason outside F24: at 6 blocks/s the DAA score advances 6 a second, so the 24-s cut is 144 DAA, longer than the 120-DAA weight window and the 60-DAA merge depth; the two chains cannot merge at the heal and each side's table holds only its own keys (n1's lone locks read "100.0% of total, 100.0% of the table frozen at lock 39"), which is the partition longer than a window that spec 3.7 item 9 states and F21 conceded, not a reorg. The scenario's "under merge depth" assumes 1 DAA a second. Spec 3.2 C1 and C4, and the 3.10 rows, state the rule.
|
|
|
|
Answer (as found): Correct. `on_virtual_changed` (`processes/finality.rs:404-440`) inserts once and advances `next_index`; `:661-666` refuses any certificate whose checkpoint is not the node's record. Fix: re-determine an unlocked index when the virtual's chain at that blue score changes; refuse only a certificate that conflicts with a lock. Review id R4.1.4.
|
|
|
|
Evidence: the files above. Experiment: a 30 s cut on a 3-node devnet at d = 20; the losing side must accept the network's certificate at that index with no CONFLICTING line.
|
|
|
|
Red-team run, 5 October 2026, 00:56 (the 0.3.4 finality-fixes build, rule v3 on, fast time, `docs/review/redteam-2026-10-04.md` row 23b): reproduced on a clean merge. Two nodes with three voting keys each, cut for 16 s (about 50 blue blocks a side, under the 60-DAA merge depth), healed: sinks equal, 64 locks each, no conflicting certificate. Checkpoint 33 was determined during the cut on each side's own chain (two different blocks); after the reorg neither node re-determined it, neither block ever got a certificate (votes split 3/3), and finality went on from 34. A permanent one-index hole on every node, with no equivocation anywhere. The round-4 shape, a false CONFLICTING line, needs the other side's certificate to arrive, which a 3/3 split cannot form; the two 4/2 attempts (rows 22 and 23) showed the stuck indices and the refusals "this node's checkpoint is ..." but overshot merge depth, so they are confounded with F21. Rule v3 does not touch this path. The fix above stands; the two-node test is `rtfin.mjs f24c` in the red-team scratchpad (cut 16 s, 3/3), which should end with index 33 locked on both nodes.
|
|
|
|
### F25. The fast-time harnesses cannot start a node, and the timestamp probe tests the old rule
|
|
"Both attack harnesses rebuild each node's override with `JSON.parse` and `JSON.stringify` of `infra/fast-time/override-60x.json`. That file now carries two `u64::MAX` sentinels (`difficulty_v2_activation_daa`, `proving_v0_activation_daa`); a JavaScript number cannot hold them, the round-trip writes `18446744073709552000`, and `igneumd` refuses the file as a floating point where a u64 is expected. Every `--fast-time` run of `tools/finality-attacks` and `tools/harness` fails at the first node. Scenario 2 of `tools/harness` still probes the 132 s future bound and reports FAIL against the 10 s rule the node has carried since the timestamp fix."
|
|
|
|
Status: Fixed (rolled out 5 October 2026, 0.3.5: both harness libraries reached master with the `fud-consensus` merge 7abce72 of the 0.3.5 cut; the sweep of 5 October ran `run.mjs s4` and `s5 --fast-time`, `fud.mjs` and tonight's `c4.mjs` through them, every node started). Was: Fixed in both harnesses (4 October 2026, night: `tools/finality-attacks/lib/net.mjs` kept the sentinels as BigInt through the merge since the v3 runner of the evening; `tools/harness/lib/net.mjs` got the same reviver on branch `fud-memory`, merged into `fud-consensus`); the stale timestamp criterion of scenario 2 is not touched. Was: Open (4 October 2026, red-team run). Tooling, low severity: no consensus effect, but every fast-time attack run is blind until it is fixed.
|
|
|
|
Answer: Correct, measured. The red-team run's first scenario errored on it (`docs/review/redteam-2026-10-04.md`, "Tooling defect"); `tools/proving-v0/run.mjs` already edits the file as text for this reason. Scenario 2 live probe: past floor pmt+1, future flip between +130.00 and +130.01 s of the probe's own offsets, every stamp from +10 s rejected; the node is right, the criterion is stale. Smallest fix: in `tools/finality-attacks/lib/net.mjs` and `tools/harness/lib/net.mjs` `overrideParams`, drop the two sentinel fields before `stringify` (absent means never) or splice the extra fields into the file text; in `tools/harness/scenarios/s2-timestamp.mjs`, probe `max(pmt + 1, parent - 10 s)` and the +10 s bound. Also stale: `tools/exec-attacks/scenario3_pgas.mjs` waits for an over-budget transaction to be included and skipped with `BlockProvingBudget`; since F-exec-B the mempool refuses it with the metered pgas, so the check should accept `ProvingGasAboveBlockLimit` from the pool (`docs/review/redteam-2026-10-04.md` row 28). And `tools/finality-attacks` scenario 5 compares the burster's share of the weight window with its share of the whole run, which only agree when the run is shorter than the window (row 17).
|
|
|
|
Evidence: the first run's `/tmp/igneum-redteam-fin/n0/node.log` parse line (kept in the session scratchpad `rt/logs/fa_s8/n0/node.log`), `rt/logs/ord_s2.log`.
|
|
|
|
### 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: 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: 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: 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."
|
|
|
|
Status: Fixed (rolled out 5 October 2026, 0.3.5: `miner-reliability` 945153ab merged into fork 20139145, `docs/plans/release-0.3.5.md` 1b; the guard tests in the 0.3.5 `igneum-miner` suite, 12 passed). Was: Fixed (4 October 2026, evening), fork commits `aea5ac6d`, `501363e0` and `945153ab` on `miner-reliability` (`igneum/miner/src/guard.rs`; the second fixes a fill loop that spun forever after a guard kill, found by the test network). Replaced: Open (4 October 2026).
|
|
|
|
Fix: `IntervalGuard` builds its baseline from the healthy intervals of the current worker process (a moving average, two intervals before it can trip) and forgets it when the worker restarts; the STATUS line is printed on a trip, with `faults=`; `RestartPolicy` restarts a guard-killed worker after 2 s, doubling per trip inside ten minutes, and the third trip ends the miner with exit 43 so the app shows a faulted card instead of a loop. The 60 s no-line timeout no longer skips the guards and the STATUS line. Measured against a fake worker on a private test network: `docs/bench-log.md`, "4 October 2026, miner fault guards and the app watchdog measured against a fake worker".
|
|
Sweep (5 October 2026, evening): measurement line, live, from the five app machines' miner logs over the 20 hours to 15:30 UTC: on the 0.3.5 to 0.3.8 miners every PC fault line is of one kind and rare (PC 1: 2 `WORKER FAULT` lines in the 07:00 hour and 4 in the 10:00 hour, PC 2: none after 03:00 UTC), the `no job completed ... killing the worker, it restarts` guard fired 43 times on PC 1 and 40 on PC 2 in the whole window, every time with a restart and a STATUS line afterwards, and the console shows 0 faults and 0 restarts on every card at 15:46 UTC. The loop this entry describes (a trip every interval for ever) does not appear on any machine since the 0.3.5 start. Earlier line, kept for the record: Fix built (4 October 2026, branch `miner-reliability` of the node, `aea5ac6d`), pending merge and a run on a PC. `IntervalGuard`: the baseline is a moving average of the worker process's healthy intervals, forgotten on a restart; the STATUS line is printed on a trip with `faults=`. `RestartPolicy`: 2 s, doubling inside ten minutes, the third trip exits 43 so a supervisor can mark the card. Unit tests in `guard.rs` replay the slow-first-interval case and the back-off. The GPU stress run (`--status-secs 10` with a stress tool for 15 s) needs a PC (hardware). Was: Open (4 October 2026).
|
|
|
|
Answer: Correct. `igneum/miner/src/main.rs:1404-1418` with the update at `:1452-1454` skipped by `continue`; the restart has no cap and no growing back-off (`:1213-1216`). A slow first interval (a game on the GPU, a foreground self-heal build on a slow card) is enough. Fix: update the baseline on a trip, or compare to the previous interval; cap restarts with a growing back-off. Review id R4.2.1.
|
|
|
|
Evidence: the file above. Experiment: `--status-secs 10` with a GPU stress tool for the first 15 s; one fault, one restart and a STATUS line afterwards.
|
|
|
|
### M27. A flapping node makes the worker rebuild once per template
|
|
"A prepare goes out whenever the wanted pair differs from the prepared one. No count, no interval, no once-per-epoch. Each one writes a pack on the CPU with the job loop stalled and costs the worker a full build; `prepare-failed` resends on the next fill."
|
|
|
|
Status: Fixed (rolled out 5 October 2026, 0.3.5, as M26). Was: Fixed (4 October 2026, evening), fork commit `aea5ac6d` on `miner-reliability` (`guard::PrepareLimiter`): one `prepare` per pair per epoch, one retry after `prepare-failed`, none within 30 s of the last; a held prepare is printed once (`PREPARE held ...`). Measured with a worker that refused every prepare across three epochs: `docs/bench-log.md`, the same entry as M26. Replaced: Open (4 October 2026).
|
|
Sweep (5 October 2026, evening): measurement line, live, the exact failure this entry predicts happened on the 0.3.4 miners and stopped with 0.3.5. Between 01:24 and 02:59 UTC on 5 October 2026 both PCs' NVIDIA workers refused the prepared pack for epoch 1130e9ea... (`prepare-failed ...: the epoch seed bytes do not give the pack's IGNEUM_SEEDW_INIT`) and the 0.3.4 miner re-sent the prepare every 0.7 s: 4,299 `prepare-failed` lines on PC 1 and 4,233 on PC 2 in two hours, with 3,609 and 3,494 `WORKER FAULT seed mismatch` lines, two boundaries (DAA 61,200 and 64,800) crossed by inline compile instead of a swap on both PCs. From the 0.3.5 start (07:15 UTC) to 15:30 UTC: 0 `prepare-failed` lines on any machine, 4 and 4 `WORKER FAULT` lines, and every boundary from DAA 68,400 to 111,600 swapped with no pause on both PCs (intake query over the `miner-*` uploads, `docs/bench-log.md`, "FUD ledger sweep round 6", M11). The flapping-node simnet was not run; the live storm stands in for it. Earlier line, kept for the record: Fix built (4 October 2026, branch `miner-reliability`, `aea5ac6d`), pending merge. `PrepareLimiter`: one prepare per pair per epoch, one retry after prepare-failed, none within 30 s of the last, a held prepare said once; a unit test replays a flapping node. The fast-time simnet with a flipping `next_epoch_seed` was not run (it needs a patched node and a GPU worker). Was: Open (4 October 2026).
|
|
|
|
Answer: Correct. `igneum/miner/src/main.rs:1113-1165, 1337-1339`; `worker.cpp:644-658`; `host.c:1208-1225`. Estimated loss 30 to 60 percent against a node that alternates seeds per template; a stale home node on a fork is the realistic trigger. Fix: at most one prepare per pair per epoch and none within 30 s of the last. Review id R4.2.2.
|
|
|
|
Evidence: the files above. Experiment: a fast-time simnet node patched to flip `next_epoch_seed` per template; the miner's `now=` rate within 5 percent of steady.
|
|
|
|
### 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: 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 <dir>` 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 <dir>` 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."
|
|
|
|
Status: Fixed (rolled out 5 October 2026, 0.3.5: the miner half with `miner-reliability` in fork 20139145, the app half with app commit f7d2af7 of the 0.3.5 branch, `docs/plans/release-0.3.5.md` 1a). Was: Fixed (4 October 2026, evening), fork commit `aea5ac6d` (`guard::MismatchGuard`: three consecutive CPU re-check mismatches kill the worker, `WORKER FAULT cpu re-check ...`) and app commit `f39e240` on `miner-reliability` (`app/igneum-app/src/watchdog.rs`: the app reads `mismatched=`, `faults=` and the `WORKER FAULT` lines, shows them on the card, and its own watchdog restarts a miner once for no status in 90 s or a zero rate for 60 s while synced, then marks the card faulted; a silent node is restarted in-process). Measured: `docs/bench-log.md`, the same entry as M26. Replaced: Open (4 October 2026).
|
|
Sweep (5 October 2026, evening): measurement line, live: every STATUS line of every card on the five machines carries `mismatched=0` and `faults=0` and the console reads the fields (Machines card at 15:46 UTC on 5 October 2026: `0 mismatched, 0 restarts` per card, `0 faults` per machine), so the path from the miner's counter to the card exists on the fleet; the edited-kernel test that would turn a card red was not run (it needs a hand-edited pack on a PC). Earlier line, kept for the record: Fix built (4 October 2026): `MismatchGuard` on branch `miner-reliability` (`aea5ac6d`) kills the worker after three consecutive CPU re-check mismatches (`WORKER FAULT cpu re-check`), and the app reads `mismatched=` and `WORKER FAULT` on branch `release-0.3.5` (`app/igneum-app/src/engine.rs`, 3 matches; 0 on master). Pending merge and release; the edited-kernel test needs a GPU worker (hardware). Was: Open (4 October 2026).
|
|
|
|
Answer: Correct. `igneum/miner/src/main.rs:1250-1261`; `app/igneum-app/src/engine.rs:~1762-1780` (zero matches for either string). The PowerShell launcher matches them (`igneum-common.ps1:843`), which is what README.txt and TEST.md describe. Fix: stop the worker after 3 consecutive mismatches and show it on the card; the app reads both fields. Review id R4.2.3.
|
|
|
|
Evidence: the files above. Experiment: one constant edited in `kernel_bound.cu` outside the vector warps; the card must go red within a minute.
|
|
|
|
### 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: 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-<card>` (`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<EpochSeeds>` 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: 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."
|
|
|
|
Status: Conceded, stated (5 October 2026, night): `site/index.html`, `site/miner.html` and `site/wallet.html`, a line beside every download control, "Devnet: coins have no value and the chain may be reset."; `site/index.html` Economics tiles, "of emission to miners and provers; the protocol carries no fee" and "0% anyone else in the protocol", with the E16 sentence under the bar. Not done: the same line on `site/live.html` (not in this round's file list). Was: Open (4 October 2026); extends E5.
|
|
|
|
Answer: Correct. `site/index.html:306, 382, 446-448`; `grep` for "no value", "reset", "wiped", "test coins" across `site/*.html` finds nothing; the only disclaimer is the app's welcome screen (`app/igneum-app/ui/index.html:45`). Fix: "devnet: coins have no value and the chain may be reset" beside the button and on the live page; the homepage tiles match the litepaper's dev-fee sentence. Review ids R4.7.3, R4.7.5.
|
|
|
|
Evidence: the files above.
|
|
|
|
### M29. The litepaper's app paragraph describes an app that does not exist
|
|
"'Press one button, and the card is mining and proving to a wallet the app made for you, with earnings shown in IGN and in your currency ... offers a hardware wallet for your earnings.' Version 0.3.3 shows a hash rate and block counts."
|
|
|
|
Status: Conceded, stated (5 October 2026, night): `site/litepaper.html`, For miners, "One click, for everyone else", rewritten to Ember 0.3.9 from `app/igneum-app/ui/index.html` (hash rate, blocks found, node, next program, finality votes, the proving tile, the devnet v4 label, the 80% power cap, the Settings switches); "It shows no earnings in IGN or in any currency, and it has no hardware-wallet path"; earnings, currency, game pause and the hardware wallet moved to "Roadmap, Designed and not in the app". Was: Open (4 October 2026).
|
|
|
|
Answer: Correct. `site/litepaper.html:424`; the app's sources have no earnings, currency or hardware-wallet path (`grep` of `src/*.rs` and `ui/app.js`); the prover service exists for the `proving` branch's chain. Fix: rewrite the paragraph to 0.3.3 (hash rate, blocks, devnet label, power cap, the prover setting where it applies) and move earnings, currency and the hardware wallet to a roadmap sentence. When an IGN figure is ever shown, derive it from accepted blocks over the last hour times the per-block subsidy, never from hash share, and label the network. Review id R4.7.4.
|
|
|
|
Evidence: the files above.
|
|
|
|
### M30. A block or transaction flood grows the 0.3.4 node by hundreds of megabytes in a minute
|
|
"On the 3 October ordering-layer node (no execution layer) the resource-exhaustion scenario grew RSS by 4, 11 and 14 MB and the 50x block flood by 30 MB. On the 0.3.4 build, same harness, same scenarios, same 60 s: template flood +6 MB, submit flood +269 MB, mempool flood +270 MB, block flood 302 to 1,082 MB on both nodes (567 MB at 10 s, 824 MB at 20 s). The harness calls it a pass because its bound is baseline + 512 MB; a peer that keeps going is not bounded by the harness."
|
|
|
|
Status: Fixed (rolled out 5 October 2026, 0.3.5: fork 20139145 = `finality-fixes` 6aa69a45 + `fud-consensus` 977db931 + `m20-pruning` d35b00cf + the miner branches, cut 07:33 BST, `docs/plans/release-0.3.5.md` 1b and 4b; node line 2b6d23ef from 0.3.6 at 09:34 UTC carries the same consensus code; every reachable app machine on the line by 09:32 UTC and the hand nodes and the seed restarted on it for the proving activation at DAA 84,100 the same morning, `docs/plans/release-0.3.6.md` 8j, bench-log "live devnet: the first shards proven"). Was: Fix built, pending rollout (4 October 2026, night; node branch `fud-memory`, merged into `fud-consensus`; main repo branch `fud-memory`, merged into `fud-consensus`). Was: Open (4 October 2026, red-team run).
|
|
|
|
Sweep (5 October 2026, evening): measurement line, live: cache builds now equal node restarts, not epoch rolls. In the 10 hours to 15:45 UTC on 5 October 2026 the node logs show 5 `PoW cache built` lines on PC 1, 5 on PC 2, 8 on the Mac and 1 on Sam's Mac, each at a node start (the 0.3.5, 0.3.6, 0.3.7 and 0.3.8 restarts and the proving-activation restart), and none at the hourly boundaries: the swaps at DAA 108,000 (14:29 UTC) and 111,600 (15:29 UTC) built no cache on any machine (the last build on PC 1 is the 0.3.8 restart at 13:42 UTC). The 0.3.4 engine built one 256 MiB cache per hourly roll (about 270 MB an hour of growth on the app node). The 30 MB per 1,000 blocks of non-cache growth and the unbounded `ExecState.records` stay as stated. Serious: a single peer at 50 blocks/s or 500 transactions/s is the devnet's own fast-miner event, and a node that grows 13 MB/s under it runs out of memory in minutes on the 2 to 4 GB cloud nodes.
|
|
|
|
The cause, measured (not the one guessed below): every RSS step in both floods is one `PoW cache built` line, 256 MiB each. The lottery engine (`consensus/pow/src/igneum.rs`, `IgneumEngine`) keyed its resident entries by `(epoch seed, day)` and built a full 256 MiB cache per entry, `KEEP = 4`, although the cache depends on the day seed alone (`igneum_pow::Epoch::from_seed_bytes`: cache from the day bytes, program from the epoch seed). The floods ran on the 60x profile, where an epoch rolls every 60 DAA, so the 50x block flood rolled it every 10 to 20 s and paid a cache each time; the 3 October run was on the devnet profile (3,600-DAA epochs, no roll in 60 s), which is what differed, not the execution layer. The s6 figures were cumulative from one starting RSS: the mempool flood's "+270 MB" was the submit flood's growth carried forward (its own cost is 1 MB), and 197 chain blocks cost under 1 MB in `ExecState.records`. On the live devnet the same engine costs 256 MiB per hourly epoch roll up to `KEEP`, which is the steady-state growth the coordinator saw on the 0.3.4 app node (1,081 MB at 27 min, 2,258 MB at 4 h 14 min, about 270 MB an hour). The fix: caches keyed by day, `KEEP_DAYS = 3` (3 x 256 MiB resident, plus at most 2 in-flight builds), programs keyed by `(epoch seed, day)` at a few KB each (`KEEP = 8`, LRU); an epoch roll on the same day builds no cache; node and miner compute the identical hash through `EpochRef` (unit test `epoch_rolls_share_the_day_cache`). No consensus rule changed. Measured (`docs/bench-log.md`, "ledger M30", two-node fast-time floods, before on the shipping finality-fixes build, after on `fud-memory` 796f758d): s6 submit flood +263 / +257 MB with 1 cache build each, after +3 / +2 MB and 0 builds; s7 50x block flood 302 to 1,085 MB with 3 builds, after 302 to 318 MB and 0 builds; template and mempool floods unchanged at +6 and +1 MB. Steady state, measured on two nodes at 1 block/s with no flood for 1,500 blocks on the 60x profile (`tools/harness/scenarios/s8-steady.mjs`, bench-log "ledger M30", steady-state paragraph): the shipping build reached 1,342 MB by block 514 after 9 cache builds (one per epoch roll; five 256 MiB chunks, the fifth an evicted one the allocator keeps) and 1,371 MB at 1,529 blocks; the fixed build held 319 MB at 510 blocks with 1 build and 603 MB at 1,526 blocks with 2 (the fast-time day rolled once), so on the devnet profile it is 256 MiB flat, 512 MiB around midnight UTC, 768 MiB worst case. Both builds then climb 30 MB per 1,000 blocks (30.7 before, 30.2 after), which is not the PoW cache (72 MB of non-cache footprint at 1,526 blocks against 23 MB at 0; the reading, not a measurement, is the consensus database's buffers and rusty-kaspa's entry-sized caches filling); the live node's 36 MB per 1,000 blocks between epoch rolls fits it. The app node's 2,258 MB at 4 h 14 min exceeds what this node build can reach (about 1.7 GB at 15,000 blocks) and includes its GPU worker, which needs its own `vmmap -summary`. Still growing by design and not bounded tonight: `ExecState.records` (1 to 2 KB per chain block, approximate, 100 to 170 MB a day at 1 block/s; a window must cover the proving sortition window and the by-number RPC history), `SNAPSHOT_RING = 64` state clones scaling with state size, the finality key registry (grows with distinct vote keys; votes, certificates, locks and evidence are trimmed). The harness now reports per-load RSS deltas and cache-build counts and takes `IGNEUM_HARNESS_BASE_PORT` and `IGNEUM_HARNESS_TMP`.
|
|
|
|
Answer: Measured, cause not yet isolated. What changed between the two builds is the execution layer, which this node links: `igneum/exec/src/service.rs` keeps every `ChainBlockRecord` in `ExecState.records` (`:304`, `:419`, pushed and never truncated) plus `tx_index` and `inclusions` maps per transaction, and the mempool flood's 14,998 rejected transactions cost 270 MB, so rejected transactions are retained somewhere too. Smallest fix: bound `ExecState.records` to the record window plus the pruning depth and drop `tx_index`/`inclusions` entries with them; discard a rejected transaction's bytes at rejection; then re-run `tools/harness` s6 and s7 and require growth under 50 MB, the 3 October figure.
|
|
|
|
Evidence: `/tmp/igneum-redteam-ord/results/s6-exhaustion.json` and `s7-flood.json` (samples carry `rss_a`, `rss_b` every 10 s), kept in the session scratchpad `rt/logs/ord_s6`, `rt/logs/ord_s7`; the 3 October numbers in `docs/bench-log.md`, "consensus attack harness" entry.
|
|
|
|
### M31. The 0.3.4 node cannot produce a block template on mainnet, testnet or simnet parameters
|
|
"`getBlockTemplate` on a `--simnet` node from the finality-fixes build answers every call with `Coinbase payload is above max length (204). Try to shorten the extra data.` and the network never makes a block. The coinbase of this build carries the vote-key reveal, the proof-record section and the finality section; only `DEVNET_PARAMS` was raised to `MAX_COINBASE_PAYLOAD_LEN_WITH_FINALITY` (16,384). `MAINNET_PARAMS`, `TESTNET_PARAMS` and `SIMNET_PARAMS` still carry Kaspa's 204 (`consensus/core/src/config/params.rs:705, 766, 828` against `:900`)."
|
|
|
|
Status: Fixed (rolled out 5 October 2026, 0.3.5: fork 20139145 = `finality-fixes` 6aa69a45 + `fud-consensus` 977db931 + `m20-pruning` d35b00cf + the miner branches, cut 07:33 BST, `docs/plans/release-0.3.5.md` 1b and 4b; node line 2b6d23ef from 0.3.6 at 09:34 UTC carries the same consensus code; every reachable app machine on the line by 09:32 UTC and the hand nodes and the seed restarted on it for the proving activation at DAA 84,100 the same morning, `docs/plans/release-0.3.6.md` 8j, bench-log "live devnet: the first shards proven"). Was: Fix built, pending rollout (4 October 2026, night; node branch `fud-consensus`). Was: Open (4 October 2026, red-team run). Serious for anything that is not the devnet: a mainnet or testnet genesis on these parameters cannot be mined by a voting miner at all; harmless on the live devnet, whose parameters carry the raise.
|
|
|
|
Sweep (5 October 2026, evening): measurement line: the unit test `largest_coinbase_fits_on_every_network` passed in every 0.3.5 suite run (`cargo test -p kaspa-consensus-core`, 101 passed on the 0.3.6 fork tip a11455e7 on 5 October 2026, `docs/plans/release-0.3.6.md` 3b) and the testnet identity `igneum-testnet-1` adopted the same morning carries the raised limit with every switch at 0, so the first testnet genesis is mineable by a voting miner; no simnet network has been started since the cut, so the template line on simnet is covered by the test, not a run.
|
|
|
|
The fix: `max_coinbase_payload_len` is `MAX_COINBASE_PAYLOAD_LEN_WITH_FINALITY` (16,384) on mainnet, testnet and simnet as on devnet, and the template builder fits the finality section into what the payload has left (`finality::encode_section_within`, certificates first, then evidence, then votes; the RPC computes the budget from the fixed part, the script, the node version, the miner's extra data and the record section), so a coinbase can never exceed the limit on any network whatever the voter count. The worst case did not fit even on devnet before: 8 certificates over 8,192 voters, 8 pieces of evidence and 48 votes come to about 30 KB, so the per-item bounds alone were not a bound. Unit test `largest_coinbase_fits_on_every_network` (consensus-core): the fixed part, the version, a key reveal, a full record section (8 records of 274 bytes) and the cut finality section fit under every network's limit, the cut keeps every certificate and every piece of evidence and at least 8 votes, the uncut section would not fit, and a budget under one certificate yields an empty section. The exec-attacks network (`tools/exec-attacks/net.sh`, `--simnet`) can drop its override once this build ships; not re-run tonight.
|
|
|
|
Answer: Measured on the execution-layer attack network (`tools/exec-attacks/net.sh` runs `--simnet` with no override): three nodes up, 0 blocks, every template refused with that line (`docs/review/redteam-2026-10-04.md` row 27). Smallest fix: set `max_coinbase_payload_len: MAX_COINBASE_PAYLOAD_LEN_WITH_FINALITY` on the three other networks, and add a unit test that builds a coinbase with a key reveal, the maximum record section and a full certificate and checks it under every network's limit. The red-team run worked around it with `{"max_coinbase_payload_len": 16384}` in an override file.
|
|
|
|
Evidence: session scratchpad `rt/logs/exec_b/miner_node1.log` (the template error, repeated once per second), `rt/logs/exec_b/n1/node.log` (28 lines, genesis executed, nothing after).
|
|
|
|
### 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: 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."
|
|
|
|
Status: Answered by design and with evidence (4 October 2026, evening; the project lead's decision of that evening, branch `dev-fee` in both repositories).
|
|
|
|
Answer: The fee exists and is disclosed; the rest is wrong in three places. (1) It is software-level, not protocol-level: no consensus rule, coinbase rule or emission rule knows of it. The chain pays whatever payout address a block template names, and the miner software names the dev address for one template in 100. A different client, or the same client with `--dev-fee 0` (a switch in the app's Settings, `DEV_FEE=0` on HiveOS), pays nothing and the chain treats its blocks exactly the same. That is the norm for GPU miners (lolMiner, T-Rex, approximate as to their percentages) and the litepaper says so beside the words "the protocol carries no fee". (2) It is auditable, not hidden: the choice is a template counter, not a random draw. Template n (from 0) is a fee template when floor((n + 1) p / 100) > floor(n p / 100), which at p = 1 is exactly the templates 99, 199, 299, ...; the source is one function (`fee_slot`, `igneum/miner/src/main.rs`, section "Software dev fee"), the miner prints `dev fee 1% (1 block in 100) to 0x<address>; --dev-fee 0 turns it off` at start, logs `dev-fee block <hash>` for each one and counts `fee=N` in its status line, and `igneum-miner payouts <node>` reads the chain back and lists blocks per payout address with the dev address tagged. (3) It takes nothing from anyone else's security: a fee block keeps the user's vote key, so the user's finality weight is unchanged; only the execution-layer payout of that block moves.
|
|
|
|
Evidence: `docs/design/miner-dev-fee.md`; the unit tests in `igneum/miner/src/main.rs` (`dev_fee_tests`: 100 fee templates in 10,000 at 1%, 0 at 0, exact at 2 to 100%); the test-network run in `docs/bench-log.md` ("the software dev fee measured") with the dev address's block count against the miners' own counters and the 1-in-100 expectation. Open: the release address is a placeholder (`DEV_FEE_ADDRESS`) until the project lead fills it before any public release; the devnet address is labelled as such.
|
|
|
|
### 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: 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."
|
|
|
|
Status: Fixed (4 October 2026): `ac89a37` and `6b644a6` (a scrubbed copy, the build fails on any private string), `2d8f09c` (none of the three in the public API), `621f5cc` (the menu). Review ids R4.6.1, R4.6.2, R4.6.8.
|
|
|
|
Answer: Correct at discovery; fixed before this document was written. The evidence page was brought up to the day's measurements in `86e5857` and `bf4d7ec` (rows 29 and 30, rows 10, 12 and 15 restated).
|
|
|
|
Evidence: the commits above. Experiment: `curl https://igneum.network/api/live` holds no address, no 64-hex key hash and no payout address.
|
|
|
|
### X31. The public testnet dated "August 2027" on the site
|
|
"The litepaper's For miners section said 'Pools and the public testnet are August 2027', the proving section said 'Live rows arrive with the public testnet, August 2027', the roadmap's phase 5 read 'Aug to Oct 2027' and the home page's journey carried the same row. igneum-testnet-1's genesis is final, three seed nodes and the public RPC are up, and the testnet opens when the go checklist (docs/plans/testnet-go.md) closes, which is weeks away."
|
|
|
|
Status: Fixed, stated (6 October 2026, night, the owner's decision): every mention of the month is gone from the site. The sentence everywhere is "The public testnet is weeks away: three seed nodes and the public RPC are up, and it opens when the go checklist closes." (`site/litepaper.html` For miners and the proving section, the roadmap row 5 reads "Weeks away: when the go checklist closes", `site/journey.json` phase 5 and the home page's inlined journey carry the same row). No calendar month is given for the testnet; the owner gives one if he wants one.
|
|
|
|
Answer: The date was the plan of 3 October 2026 and the chain overtook it: the testnet genesis was fixed on 5 October, the three seeds and rpc.testnet.igneum.network are up, and the remaining work is the go checklist. Rows that quoted the month (X3, O-X.2's blocker note, overclaim item 75's replacement text) read the new sentence by reference to this row.
|
|
|
|
Evidence: `docs/plans/testnet-go.md`; `docs/igneum-testnet` notes (genesis 87617621..., seeds seed1 to seed3.testnet.igneum.network, public RPC). Checked by `tools/ci/ledger-text-check.mjs` (the X3 and X31 rows).
|
|
|
|
### X32. The roadmap carried calendar months beside a testnet that is weeks away
|
|
"After X31 the roadmap read phase 4 'Apr to Jul 2027' and phase 6 'Nov 2027' with phase 5 'weeks away' between them, and phases 1 to 3 carried 'Oct to Nov 2026', 'Nov 2026 to Jan 2027' and '20 nodes by Mar 2027'. A reader spots the contradiction at once."
|
|
|
|
Status: Fixed, stated (6 October 2026, night, the owner's ruling): every calendar month is out of the roadmap. Each phase is worded by its gate in the shape phase 5 has: 1 "Under way; closes when the specification is out for external review", 2 "Under way; closes at its gate", 3 "Live since 3 October 2026; closes at its gate", 4 "Closes when the finality design passes external review and one rollup signs for the testnet", 5 "Weeks away: when the go checklist closes", 6 "After the testnet has passed its gate: 1,000 independent miners for 30 days and rollup proofs on time". The order is unchanged. The roadmap's lead reads "Six phases from specification to a fair launch, with four public gates and no calendar dates: each phase closes at its gate." (`site/litepaper.html` Roadmap, `site/journey.json`, the home page's inlined journey). The 3 October 2026 start of the devnet is a fact, not a target, and stays.
|
|
|
|
Answer: Dates were the plan of 3 October 2026; the gates are the plan. "Dates slip. Gates do not." was already the roadmap's own sentence, and the roadmap now says only the gates. The owner gives a month if he wants one.
|
|
|
|
Evidence: `site/litepaper.html` Roadmap; `site/journey.json`; X31.
|
|
|
|
### X33. The public benchmark dated "January 2027"
|
|
"After X31 and X32 the litepaper still said the public benchmark with a leaderboard 'is January 2027' (For miners) and 'ships in January 2027' (Questions miners ask), a calendar month beside a roadmap that names none."
|
|
|
|
Status: Fixed, stated (6 October 2026, night, the owner's ruling): both sentences read "The public benchmark with a leaderboard ships with the public testnet." (`site/litepaper.html`, For miners and Questions miners ask). The gate is one the reader already knows from the roadmap's phase 5. The 5 October answers in M1, X1 and the overclaims list that name January 2027 are the history of the plan and stay as written.
|
|
|
|
Answer: The month was the plan of 3 October 2026. The benchmark tool is part of the testnet's go checklist, so it ships with the testnet; no month is given for either.
|
|
|
|
Evidence: `site/litepaper.html`; `docs/plans/testnet-go.md`; X31, X32.
|
|
|
|
## Status updates, 4 October 2026 (round 4)
|
|
|
|
- **F21** (the long-partition fork). Extended: a side locks alone when its own share of its own table reaches two thirds, at `t = W (2/3 - s) / (1 - s)`: 50/50 at 2,400 DAA s on the devnet (about 40 minutes), 10 days on mainnet; the 60 side of 60/40 at 1,200 DAA s (20 minutes), 5 days; the ledger's measured `W/(3R)` = 200 s is this formula at s = 1/2. At HEAD a second certificate at an index is kept, logged and ignored (`processes/finality.rs:650-655, 661-666`) and `fork_choice_lock` (`:886-901`) pins the node. Public text: `site/litepaper.html:511` says a third of the blocks is needed to split finality in a partition; the partition alone does it. Replacement sentence in `docs/review/round-4-2026-10-04.md` section 1 (b). Review id R4.1.5.
|
|
- **M20** (pruning proofs under the stub). Extended: `validate_trusted_header` (`processor.rs:330-337`) skips `pre_pow_validation`, so trusted and pruning-proof headers are never checked for bits, DAA score or the v2 activation. Review id R4.1.11.
|
|
- **M13** (Macs mine too). Extended: the ratio is measured, 26.7 / 124, about a fifth, and the litepaper (`:420`) still carries no ratio; the app shows no projected earnings, which for a devnet is the right outcome. Review id R4.7.6.
|
|
- **E5** (the client dev fee). Still open on the homepage; see L9.
|
|
- **E5, L9** (the client dev fee), evening: the fee is built, switchable and audited (E18). The homepage's miner section now carries the litepaper's sentence (`site/index.html`, under the download buttons: "The protocol carries no fee. The Igneum Miner software takes an optional 1% dev fee, like other GPU miners, off with one flag"), and the litepaper's "What a miner's hour looks like" states the mechanism, the flag and the audit. The "no value" and "may be reset" devnet wording of L9 is still open.
|
|
- **D2** (the app share). The "Why build here" text is applied at `site/litepaper.html:355` and states the number; two gaps noted under E17.
|
|
|
|
## Status updates, 5 October 2026 (ledger sweep, night of 4 to 5 October)
|
|
|
|
`docs/review/ledger-sweep-2026-10-05.md` holds the runs, the commands and the running table. Every Open, Proposed, Unmeasured or pending entry was read against its experiment line; the status lines above carry the evidence inline, marked "Sweep (5 October 2026)" where a note was added and "Was:" where the status changed. Items owned by the other two night branches (F23, F24, G12, X18, the flood memory growth; the base-fee floor, testnet parameters, G13, G14, public text) were left to them.
|
|
|
|
- **Moved to Fixed or Rolled out, from evidence that already existed and had not reached the ledger:** M15 (cheap checks before the PoW engine, merged and live), M17 (hot swap, measured on the live devnet across three vendors), M19 (the census cells filled, 16 loads a Definition), M24 (rule v2 activated at DAA 33,000), P20 (the buffered save confirmed on the third run), X16 (the evidence page exists), G11 (the spec is public).
|
|
- **Moved to Answered with evidence:** F1 (the first-month gate implemented, measured on 4 October and re-confirmed tonight on the finality-fixes build: the burster locks nothing alone; the launch month is arithmetic now), F7 (reorg depth p50 1, p99 3, max 5 on a 12-node, 5-region network), F19 (bought keys are worth their blocks; scenario K at both floors), E12 (the simulation half), E15 (the security-budget model: the floor is crossed in year 7, 11 or never by price, and no fee level moves it).
|
|
- **Fix built on a branch, pending merge or rollout:** M26, M27, X21 (`miner-reliability` `aea5ac6d`, with the app half on `release-0.3.5`), F22 (rule v3, fast-time network), part of X22. Sweep (5 October 2026, evening): M26, M27, X21, F23, F24, G12, X18, M30, M31, F25 and M20 are now "Fixed (rolled out 5 October 2026, 0.3.5)" with their live measurement lines; F21 and F22 are shipped in every node since 0.3.4 and wait only for the switch N3 (decision owner the project lead).
|
|
- **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 |
|
|
|
|
## Status updates, 6 October 2026 (21:0x UTC, the 0.3.16 exec work)
|
|
|
|
### X31. The prover's segment exports filled the disk under the node
|
|
The fleet's provers (the kit's box-prover.py) exported the chain with `igneum_exportSegments [0, last]` for every segment, 50 to 500 MB a file, and nothing pruned them: between about 13:00Z and 20:44Z on 6 October 2026 the exports reached 42 GB on the hub (586 segment dirs on a 60 GB disk, 100 percent) and 3 to 46 GB on every standing box (p1-4090 and p2-4070-1 at 100 percent with 45 and 46 GB; p1-4070 97 percent, p2-3090-4 94 percent, p1-3080 87 percent, p1-a5000 81 percent, p2-4090-3 79 percent, p2-3090-3 75 percent, p1-5090 74 percent, p2-3090-2 55 percent, p2-3090-1 38 percent, p2-4090-1b 30 percent, the 8x rig 28 GB), 4 to 6 GB an hour a box. The hub's node died three times: 19:58:08Z and 20:01:55Z on the sync KeyNotFound (a peer's gap sync below retention, another class), 20:42:31Z on "No space left on device"; the supervisor restarted it at 19:59:11Z, 20:02:36Z and 20:44:38Z.
|
|
|
|
Status: Fixed (6 October 2026, 21:0x UTC). At the source: the 0.3.14 export is `[first-1, last]` with the account dump, a few hundred KB a segment, not 50 to 500 MB. In the kit: gpu-fleet f9ad70e (every standing box): a 20 GB and 168 h cap on the export dir enforced before every export, the export deleted the moment its record is accepted or paid, no export under 10 percent free disk (logged); the supervisor's 20-minute prune stays as the belt. In the app: exec-app-0314 4159818 and proving-v2 717148d (`app/igneum-app/src/provingdir.rs`): the same caps on `<app dir>/proving` (IGNEUM_PROVING_DIR_MAX_GB 20, IGNEUM_PROVING_DIR_MAX_DAYS 7, which leave 80 GB of a 100 GB box to the node and the system), a segment's directory deleted on submission, the free-disk floor before each export with the skip on the Prove page; the cap is a pure function with a unit test. Consequence per tier: a home miner's app never grows its proving dir past 20 GB or a week, and stops exporting (not mining) when the disk is under 10 percent free; a box or a rig the same through the kit.
|
|
|
|
## 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.
|
|
|