From 8e775bc8e2694db0a26240db120f1d775233b27d Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Sun, 4 Oct 2026 22:39:54 +0000 Subject: [PATCH 1/6] FUD ledger sweep, round 1: 63 entries reconciled with the day's evidence, the security-budget grid and the launch-month arithmetic Status lines updated from the bench-log, sim/results_v2.md, sim/difficulty/attacks and sim/economy where the evidence existed and the ledger still said Open (M15, M17, M19, M24 fixed and live; F1, F7, F19, E12, E15 answered with evidence; M26, M27, X21 fix built on miner-reliability; the rest annotated with what the experiment needs). New: sim/economy/security_budget.py (E15 fee grid, price paths, hashrate response), fud-fixes section 2.5 (rows 117 to 126), docs/review/ledger-sweep-2026-10-05.md (the running table). Co-Authored-By: Claude Fable 5.1 --- docs/fud-fixes.md | 17 +++++ docs/fud-ledger.md | 126 ++++++++++++++++----------------- sim/economy/security_budget.py | 112 +++++++++++++++++++++++++++++ 3 files changed, 192 insertions(+), 63 deletions(-) create mode 100644 sim/economy/security_budget.py diff --git a/docs/fud-fixes.md b/docs/fud-fixes.md index 45b2fb18e..cedd7e3fc 100644 --- a/docs/fud-fixes.md +++ b/docs/fud-fixes.md @@ -268,6 +268,23 @@ Added after `docs/review/round-4-2026-10-04.md`. Rows continue the numbering of | 115 | X19, X20, M25, M28, X22, X28, X29, E17 | The minors of round 4 (node knobs and silences, cold-sync cost, miner day length, kernel commitment, restart paths, relay hygiene, host and file modes, unlogged economics inputs) | As each ledger entry says; the stray token-named file and the 0644 modes today | consensus engineer, miner-community-lead, relay owner, Claude | when convenient | no | | 116 | X30 | Bench page private strings; /api/live addresses, key hashes, payout addresses; the mobile menu | Fixed 4 October 2026: `ac89a37`, `6b644a6`, `2d8f09c`, `621f5cc` | Claude | done | no | +### 2.5 Ledger sweep (night of 4 to 5 October 2026) + +Added by `docs/review/ledger-sweep-2026-10-05.md`, which holds what ran, what did not and why. Rows continue the numbering. Effort in hours. Items owned by the fud-consensus branch (F23, F24, G12, X18, the flood memory growth) and the testnet-prep branch (the base-fee floor, testnet parameters, G13, G14, public text) are not repeated here. + +| # | Ledger | Issue | Fix | Who | When | EXPOSES | +|---|---|---|---|---|---|---| +| 117 | M20 | Pruning-proof headers are still checked with the kHeavyHash stub on `devnet-v4` (`pruning_proof/validate.rs:192`, `apply.rs:74, 200`, `mod.rs:207`), and `validate_trusted_header` skips `pre_pow_validation` (round 4) | Derive the epoch and day of a proof header from the proof's own headers (fork map a4, O-2.5), replace the stub call, run the bits and DAA checks on trusted headers; test: a fresh node syncs a fast-time simnet past its pruning depth (6 h) | consensus engineer | before testnet | no | +| 118 | X20 | Cold sync walks the selected chain once per checkpoint index from index 1 (`processes/finality.rs:204`) | Start from the last certified index carried in headers and walk once; test on a 10^5-block fast-time simnet, time to first resolution (2 h) | consensus engineer | before testnet | no | +| 119 | P15 | The RPC block's `gasLimit` is one block's `B_e` beside a segment's summed `gasUsed` (`proving` branch, `igneum/exec/src/rpc.rs:355-356`) | Report `k x B_e` for a k-block segment, or document the invariant break for Blockscout (R10) (1 h) | execution engineer | before a public RPC | no | +| 120 | M28 | Nothing commits the seed to the kernel text the worker compiles; no kernel hash exists on any branch | 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 (3 h) | miner lead | before testnet | no | +| 121 | M21 | k = 18 is Kaspa's table value; `calculate_ghostdag_k` gives k 5 at the cloud devnet's measured p99 of 0.67 s and k 55 at a 20-s bound, and proof-bearing bodies are unmeasured | Run O-2.2 with bodies of the size design 5.4 implies, take the p99 propagation, re-derive k with the fork's function (the table is in the ledger entry) (3 h) | consensus engineer | before testnet | no | +| 122 | X29 | The live node's gRPC listens on every interface (`igneumd` on `*:26610`, read-only check 5 October); the file modes are fixed | `--rpclisten=127.0.0.1:26610`; PC 2 through a tunnel or its own node (0.5 h) | app owner, the project lead | now | no | +| 123 | M14, F14 | O-3.14 (the finality simulation with the DAA in the loop under both forms of W2) has no DAA model inside `finality_v2.py`; the chain-model result (no amplification under either controller) stands in for it | Add a lagging retarget to `finality_v2.py` (Kaspa's sampled window and rule v2), run the 50x pulse under both W2 forms, log the day the renter crosses a third (4 h) | cryptographer (sim) | before testnet | no | +| 124 | F1, O-3.1 | Spec 06 row O-3.1 still says "not yet in `sim/`" and the ledger's launch-month arithmetic was in prose only | Restate O-3.1, O-3.14, O-3.15, O-5.9 and O-5.11 in spec 06 with tonight's evidence (the min_daa rule is implemented and measured; K, I and the economy scenarios ran; the budget grid ran) (0.5 h) | Claude (spec) | now | no | +| 125 | X14 | Only hashing concentration can be computed from what the observer keeps; signing, proving and aggregation need certificate and proof-record extracts | The observer stores signer bitmaps per certificate and prover keys per proof record; a nightly top-1/3/10 table on the live page (3 h) | app owner (observer) | before testnet | no | +| 126 | E12 | The devnet half of O-5.9 (profit-only prover clients, `f_p` and `B_p` paths) | Phase 4 devnet run as the ledger entry states (4 h) | execution engineer | before testnet | no | + ## 4. What the 3 October decisions close or change Closed: diff --git a/docs/fud-ledger.md b/docs/fud-ledger.md index 3559540e3..e22cf06c9 100644 --- a/docs/fud-ledger.md +++ b/docs/fud-ledger.md @@ -94,7 +94,7 @@ Evidence: `proto-metal/TESTS.md` section 8, "Not demonstrated" item 1 and "next ### M8. Only two vendors, two programs, one day "'Any card, any vendor, bit-exact' rests on 192 vectors across two programs on one Apple chip and one NVIDIA card, all run on the same day. AMD is untested. Intel is unmentioned." -Status: Answered with evidence for what was measured; Open for AMD and Intel. +Status: Answered with evidence for what was measured; Open for AMD and Intel. Sweep (5 October 2026): Intel is now run. A Windows laptop with only an Intel UHD integrated GPU mined on the live devnet through the OpenCL worker at 1.46 MH/s, found one block that the network accepted, and its votes on checkpoints 1202 and 1203 were accepted (`docs/bench-log.md`, "first machine in the United States"). Discrete AMD is the remaining gap (hardware, O-1.15). 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. @@ -121,7 +121,7 @@ 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: Open, experiment scheduled. +Status: 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). 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. @@ -152,7 +152,7 @@ Evidence: `docs/bench-log.md`, two-card table. ### 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: Conceded, not yet stated in the litepaper. Experiment and rule change scheduled. +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. 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. @@ -170,7 +170,7 @@ Evidence: `sim/results.md` table E and "What the simulation cannot tell us"; des ### F3. Participation grinding through the bitmap "The aggregator picks which votes go in the certificate once quorum is reached. A block producer carries the certificate it likes. Drop a rival pool's votes from your bitmaps for two hours and its participation factor falls, your share rises." -Status: Closed by rule (3 October 2026), parameter open. Spec section 3.3 Q2 and 3.4.1: participation is computed from every vote seen in blocks over the presence window (votes are block payload), never from the certificates an aggregator chose; the per-block vote bound is O-3.3. Was: Open, experiment scheduled. +Status: Closed by rule (3 October 2026), parameter open. Spec section 3.3 Q2 and 3.4.1: participation is computed from every vote seen in blocks over the presence window (votes are block payload), never from the certificates an aggregator chose; the per-block vote bound is O-3.3. Was: Open, experiment scheduled. Sweep (5 October 2026): the block reading is exercised on the fork by harness s3 (block-carried votes give participation; 35 of 35 locked on each of 3 nodes) and s4 (a producer dropping the finality section from 40% of its blocks adds 0 ms to lock latency, 35 locks), bench-log "finality v2 attack harness"; the per-block vote bound and the hostile-aggregator simulation of O-3.3 are still owed. 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. @@ -206,7 +206,7 @@ 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: Open, experiment scheduled. +Status: Answered with evidence at 1 block/s (4 October 2026, cloud devnet: 12 `igneumd` in 5 locations; propagation p50 343 ms, p99 666 ms, max 2.3 s; reorg depth over 4 hours on every node, 37,113 chain removals: p50 1, p99 3, max 5 outside the two heals, 443 to 516 at the heals; `docs/bench-log.md`, "cloud devnet"). The devnet's d = 20 is 4x the observed maximum and mainnet's d = 60 is 12x; no vote split at one index was observed (0 conflicting locks). Other block rates stay open (O-3.2). 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. @@ -273,7 +273,7 @@ Evidence: design doc, "Proving speed on consumer GPUs" risk item and "Who needs" ### 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, not yet stated in the litepaper. +Status: 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. @@ -293,7 +293,7 @@ Evidence: design doc "Unit economics of a proof"; litepaper "What Igneum does no ### P3. A phone verifies in milliseconds is a SNARK-wrapper claim "Hash-based STARK proofs are hundreds of kilobytes and take real work to verify. Milliseconds on a phone means a Groth16 or Plonk wrapper, and wrapping SP1 proofs needs a big machine for minutes." -Status: Open, experiment scheduled. +Status: Open, experiment scheduled. Sweep (5 October 2026): hardware item (the wrapper on consumer hardware); not runnable here. 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". @@ -552,7 +552,7 @@ Evidence: none in repository; `vendor/rusty-kaspa` to be cloned and cited. Fix: ### 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: Open, experiment scheduled. +Status: 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. @@ -637,7 +637,7 @@ Evidence: CLAUDE.md rules (privacy rejected). Fix: overclaims list, item 68. ### L1. It is a security under Howey "A founder's company earns a dev fee, runs a pool and a proving business, seeds the DEX, pays 'launch grants', and the roadmap ends in 'exchange listings after'. Expectation of profit from the efforts of others, in writing." -Status: Open, counsel not yet engaged. +Status: Open, counsel not yet engaged. Sweep (5 October 2026): counsel; nothing runnable. 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. @@ -646,7 +646,7 @@ Evidence: design doc "Legal" paragraph. Fix: overclaims list, items 75 and 76. ### L2. Financial promotion rules "Several jurisdictions now treat a cryptoasset promotion to their consumers as regulated: the UK since October 2023 needs an authorised approver, the EU under MiCA has its own marketing rules, the US has the Howey test. 'The people who show up early get the most' on a domain you own is a promotion wherever the reader sits." -Status: Open, counsel not yet engaged. +Status: Open, counsel not yet engaged. Sweep (5 October 2026): counsel; nothing runnable. 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. @@ -655,7 +655,7 @@ Evidence: none. Fix: overclaims list, item 77. ### L3. GoDaddy domains are a seizure risk "Fifteen domains at a US registrar on US nameservers behind a US host. One court order and igneum.network is a parking page." -Status: Conceded, mitigation scheduled. +Status: Conceded, mitigation scheduled. Sweep (5 October 2026): a deSEC token now sits in `~/.config/igneum` (mode 600), so the nameserver move of fud-fixes row 44 has started; the registrar move waits for December. 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. @@ -664,7 +664,7 @@ 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. +Status: Open. Sweep (5 October 2026): counsel and entity; nothing runnable. 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. @@ -673,7 +673,7 @@ 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. +Status: Open. Sweep (5 October 2026): a person's search, recorded outside the repository; nothing runnable. 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. @@ -1064,7 +1064,7 @@ Evidence: `node1.log` of 3 October 2026 and `sim/difficulty/devnet-2026-10-03.cs ### 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: Open, fix named. +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. @@ -1073,7 +1073,7 @@ Evidence: the files and lines above. Fix: review's first of five. Review id R3.2 ### M16. The 256 MiB cache fits on a die, so the recompute attacker is compute bound "Your 4.8x-slower shortcut ran with the cache in DRAM behind a chip that cannot hold it. Put 256 MiB of SRAM on a die and the dataset is never needed: 128 items per hash at about 1,170 integer operations and 8 near-free reads each. That is 150,000 operations per hash, and integer operations per dollar is where silicon beats a GPU." -Status: Open, experiment scheduled. +Status: 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. 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). @@ -1082,7 +1082,7 @@ Evidence: spec 1.8, 1.16; `proto-metal/MEMHARD.md` 2.2 (Apple only). Experiment: ### 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: Open, fix named. +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. @@ -1100,7 +1100,7 @@ Evidence: spec 1.4.1. Fix: `site/litepaper.html` vs RandomX row, "Random program ### 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: Open, measurement in progress. +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. @@ -1109,7 +1109,7 @@ Evidence: `docs/analysis/weak-program-census-2026-10-03.md` sections 7 and 9. Re ### 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: Open, acknowledged, fix named. +Status: 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. 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. @@ -1118,7 +1118,7 @@ Evidence: the files above. Test: sync a fresh node from the 30-hour devnet. Revi ### M21. GHOSTDAG k is Kaspa's table value for Kaspa-sized bodies "k = 18 assumes a 5-second delay bound measured with Kaspa's blocks. Yours carry EVM transactions and recursive proof records." -Status: Open, extends O-2.2. +Status: 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. @@ -1127,7 +1127,7 @@ Evidence: spec 2.1; `docs/design/execution-layer.md` 5.4. Review id R3.4. ### F14. Weight in blocks over a window in blocks under a lagging retarget "Your day counts assume the block supply is capped at one a second. It is not during a retarget lag, and weight is counted in blocks." -Status: Rule written (3 October 2026): spec 3.1 W2 and 3.3 Q1 are denominated in past-median time, weight as a key's share of each 60-s bucket summed over 30 days; the simulated DAA-score form is kept beside it. O-3.14 (added the same evening) confirms or reverts it at gate 3. Was: Open, rule change proposed. +Status: Rule written (3 October 2026): spec 3.1 W2 and 3.3 Q1 are denominated in past-median time, weight as a key's share of each 60-s bucket summed over 30 days; the simulated DAA-score form is kept beside it. O-3.14 (added the same evening) confirms or reverts it at gate 3. Was: Open, rule change proposed. Sweep (5 October 2026): the simulated DAA-score form shows no amplification under either controller (`sim/difficulty/attacks` scenario 2: weight per hash 0.26 under Igneum, 0.98 under Kaspa; harness s5 on the fork: 0.999), so the median-time form is defence in depth whose own run, both forms with the DAA in the loop (O-3.14), is still owed. 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. @@ -1145,7 +1145,7 @@ Evidence: the files above. Review id R3.2. ### F16. A lock can become uncertified after a heal "Section 3.5: two certificates at one index, strike the equivocators, re-evaluate, and if neither or both still lock the index is uncertified. So the lock my node reported and I credited on is revocable." -Status: Open, decision at gate 3 (extends O-3.6). +Status: Open, decision at gate 3 (extends O-3.6). Sweep (5 October 2026): a decision item (O-3.17); nothing runnable. 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. @@ -1201,7 +1201,7 @@ 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: Open, decision named. +Status: 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. 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. @@ -1210,7 +1210,7 @@ Evidence: spec 5.1; `docs/design/execution-layer.md` 4.1, 4.3, 9.1. Review id R3 ### P15. RPC blocks are segments, so `gasUsed` can exceed `gasLimit` "A segment holds up to 180 blocks and your RPC block is the segment. Indexers assert `gasUsed <= gasLimit`." -Status: Open, minor, extends R10. +Status: Open, minor, extends R10. Sweep (5 October 2026): confirmed in code on the `proving` branch (`igneum/exec/src/rpc.rs:355-356`: `gasLimit` is the single-block `BLOCK_EXECUTION_GAS_LIMIT` while `gasUsed` is the segment record's total). Not exercised: a segment over the limit needs about 1,400 transfers inside 180 blocks. Fix row in section 2.5. 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). @@ -1264,7 +1264,7 @@ 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, wording fix. +Status: 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. @@ -1282,7 +1282,7 @@ Evidence: spec 8.2. Review id R3.21. ### G10. The signalling default on first run "8.3 says the default is the choice the user last made. On first run there is none." -Status: Open, minor. +Status: Open, minor. Sweep (5 October 2026): the app carries no signalling control today (`grep -i signal app/igneum-app/src`: none), so nothing is signalled on first run; the rule binds when the control is built. Answer: Correct. Fix: first run signals nothing until the user chooses, shown in the interface. @@ -1306,7 +1306,7 @@ Added by `docs/review/external-2026-10-03.md`, which holds the reviewer's text v ### M22. The ASIC challenge has no scoring rules, and 2x is not the economic line "Your bounty says 'beats a GPU by more than 2x'. Per what? Hashes per second, per joule, per dollar, on the average program or the worst hour? A chip at 1.6x with half the capital cost wins. And nobody has published eligible hardware, funding or a judge." -Status: Open, decision for the project lead (terms, judge and funding) and experiment scheduled (extends O-1.17). +Status: Open, decision for the project lead (terms, judge and funding) and experiment scheduled (extends O-1.17). Sweep (5 October 2026): nothing runnable; the terms, judge and funding are the project lead's decision. 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. @@ -1315,7 +1315,7 @@ Evidence: M1, O-1.17, spec 1.13 and 1.16, M16's arithmetic. Experiment: the scor ### 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: Open, experiment scheduled (O-3.15). +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. @@ -1324,7 +1324,7 @@ Evidence: spec 3.1 W5 and W6, 3.6; `sim/results_v2.md` (renter scenarios only). ### F20. During a finality pause the program must keep advancing, and nothing says which guarantees survive "Your epoch seed is a VDF of a certified checkpoint. When finality pauses for four days, your own 50% churn figure, which checkpoint seeds hour 50? And when the pause ends, what exactly was still guaranteed in between?" -Status: Open, decision scheduled at gate 3 (O-3.16, with O-4.3). +Status: Open, decision scheduled at gate 3 (O-3.16, with O-4.3). Sweep (5 October 2026): the seed half is decided (spec 4.3, from O-4.3: the seed checkpoint is the selected-chain block at the lead's blue score, certified or not, so mining never waits for a certificate) and spec 06 marks O-3.16's text closed; the devnet test through three epoch boundaries under a 45% silent set is still owed (devnet, person). 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. @@ -1333,7 +1333,7 @@ Evidence: spec 4.3 (O-4.3), 3.3.1, 3.5, 3.7 item 2, 3.9. Experiment: O-3.16. Rev ### 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: 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). +Status: 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): 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". @@ -1342,7 +1342,7 @@ Evidence: `infra/cloud-devnet/results/2026-10-04/partition-sin-20261004-140305/p ### P16. The proving gate can be passed by shrinking the shard "'A mid-range GPU proves a shard in under 20 s.' Your own R2 says: if missed, halve the shard and re-measure. That is the trap. Fix the workload first, measure the whole journey, and have strangers reproduce it." -Status: Open, experiment scheduled (O-7.1). The journey's phase 2 gate was rewritten the same night. +Status: Open, experiment scheduled (O-7.1). The journey's phase 2 gate was rewritten the same night. Sweep (5 October 2026): hardware item (the 12 GB card end to end); the standard is written. 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. @@ -1351,7 +1351,7 @@ Evidence: P1; execution-layer 9.1 R2 and R4; `docs/bench-log.md` (no shard has b ### P17. Interfaces must show four states, and the design shows three "Included, executed, proven, finalised are four different facts. Your status call returns executed, proven, locked and a list of blocks. A wallet that shows a balance at 'included' is lying by omission." -Status: Open, rule written (3 October 2026, night) in `docs/design/execution-layer.md` 2.4; experiment scheduled (O-7.2). +Status: Open, rule written (3 October 2026, night) in `docs/design/execution-layer.md` 2.4; experiment scheduled (O-7.2). Sweep (5 October 2026): the conformance set is devnet work; not run. 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). @@ -1360,7 +1360,7 @@ Evidence: execution-layer 2.3, 2.4, 8.2; phone-app 3 and 9; spec 3.9, 10.1. Expe ### 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: Open, simulation and testnet experiment scheduled (O-5.9). +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. @@ -1369,7 +1369,7 @@ Evidence: spec 5.1, 5.3, 7.2; execution-layer 4.3, 9.1 R8. Experiment: O-5.9. Re ### 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: Open, document scheduled (O-5.10). +Status: 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). @@ -1378,7 +1378,7 @@ Evidence: spec 2.5, 5.1 to 5.4; `docs/commercial/prover-customer-brief.md`; P10, ### E14. No funding table "Who pays for development, the independent review, the infrastructure and an incident response, from what, and what happens if revenue is late? You have no fund by design, which means you have no table either." -Status: Open, decision for the project lead. +Status: Open, with a placeholder table: `docs/plans/funding.md` (3 October 2026, marked PLACEHOLDER on 4 October) lists the sources (the founder's own means today, the 1% client fee, the team's own mining and proving, no protocol fee) and the cost lines; the project lead parked funding on 4 October 2026 and the decision stays his. Was: Open, decision for the project lead. 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. @@ -1387,7 +1387,7 @@ Evidence: E4, E5, G1, G5; fud-fixes rows 47, 50, 71. Decision: the project lead, ### 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: Open, simulation scheduled (O-5.11); extends E1 and E6. +Status: 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. @@ -1396,7 +1396,7 @@ Evidence: spec 2.5, 5.1 to 5.4; E1, E6. Experiment: O-5.11. Review: external, po ### 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: Open, decision for the project lead. +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. @@ -1405,7 +1405,7 @@ Evidence: X1; `docs/fud-fixes.md` section 5. Decision: the project lead. Review: ### X13. One paying customer for a stated reason "'One rollup signs for testnet' is a letter of intent with no money. A customer who pays once, pays again without a rebate, and then a second unrelated customer, is evidence. A signature is not." -Status: Open, experiment scheduled (the pilot itself), decision for the project lead on timing and terms; extends L4 and the customer brief. +Status: Open, experiment scheduled (the pilot itself), decision for the project lead on timing and terms; extends L4 and the customer brief. Sweep (5 October 2026): a decision and a customer; nothing runnable. 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. @@ -1414,7 +1414,7 @@ Evidence: `site/journey.json` phases 4 and 5; `docs/commercial/prover-customer-b ### X14. Concentration is unmeasured in four places "Define independent for the 1,000-miner gate, then report concentration in hashing, checkpoint signing, proving and aggregation, because a thousand miners behind two pools is two." -Status: Open, measurement scheduled (O-X.1); extends X5. +Status: Open, measurement scheduled (O-X.1); extends X5. Sweep (5 October 2026): hashing concentration computed from the devnet record (`sim/difficulty/records/live-2026-10-04.csv`, 8,090 blocks, 18 vote keys): top-1 12.8%, top-3 34.5%, top-9 98.0%, the nine being devnet v4's nine identities run by three machines (approximate), so by machine the devnet is three parties. Signing, proving and aggregation concentration need certificate and proof-record extracts the observer does not keep yet (O-X.1). 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. @@ -1423,7 +1423,7 @@ Evidence: X5, F10, P12, spec 9.4.2. Experiment: O-X.1. Review: external, point 6 ### X15. Remove the founders from a test network and show what continues "'The chain runs without its founders' is a sentence. Take the team's miners, provers, aggregators, seed nodes, observer and site off a running testnet and show what keeps producing blocks, proofs and locks." -Status: Open, experiment scheduled (O-X.2). +Status: 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). @@ -1432,7 +1432,7 @@ Evidence: `site/litepaper.html` Governance; spec 10.6, 4.5; G7, E2. Experiment: ### 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: Open, publication scheduled (O-X.3). +Status: Written (4 October 2026): `docs/evidence.md`, one row per public claim with five labels (tonight: designed 10, implemented 9, tested by the team 28, reproduced externally 4, reviewed independently 3). 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. @@ -1441,7 +1441,7 @@ Evidence: `docs/bench-log.md`; `docs/spec/README.md` labels; G2. Publication: O- ### X17. The miner app must show net earnings and keep jobs away from keys "Show me what a card earns after my electricity tariff, mining and proving separately, which jobs failed and why, which release I am on and whether I accepted it, and promise that a proving job can never read my wallet. Your spec covers the update and the seed, and nothing else on that list." -Status: Open, design and measurement scheduled (O-8.2, O-8.3); update control and the seed are answered by design (spec 8.2 item 4, 8.5). +Status: Open, design and measurement scheduled (O-8.2, O-8.3); update control and the seed are answered by design (spec 8.2 item 4, 8.5). Sweep (5 October 2026): design and devnet items (O-8.2, O-8.3); nothing runnable. 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). @@ -1472,7 +1472,7 @@ Evidence: `docs/bench-log.md`, 4 October 2026 "execution layer attack fixes" (be ### 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: (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. The only work there is saving the core proof, and SP1's `save` serialises straight into an unbuffered file: on WSL2 with the results folder under /mnt/c every 4-byte field element is one round trip across the Windows file bridge, and the 18.1 MB core proof of a full shard had not finished saving 25 minutes after the proof verified (the block-78 run's 10 minutes were the same save of a smaller proof). Fix: the host writes proofs through a 4 MB buffer and prints `saved in N s`, and `prove-shard.sh` writes results on the Linux side and copies them to the Windows folder once per stage. Confirmed by the stage timestamps of the second run (job run-20261004-173115): core proof verified 17:40:29 UTC, `STAGE compressed` 18:04:33 UTC, so the 18.1 MB core proof took 24 min 4 s to save; the 1.27 MB compressed proof took 1 min 42 s (18:04:44 to 18:06:26); the proving itself was 8.3 s and 10.9 s. The buffered save ships in the package rebuilt 18:10 UTC; the timed `saved` line on the next run closes this. Was: Fixed in the host, to be confirmed on the PC (4 October 2026, afternoon). (1) `igneum-prove-host` holds a Tokio runtime for the whole run (`main` enters it before anything else) and drops the proof system inside it, then shuts the runtime down with a 10-s grace, so `sp1-cuda`'s `tokio::spawn` in `Drop` finds a runtime. (2) Every stage prints a `STAGE ... start` line and a `RESULT` line with a UTC timestamp, and the setup line splits client creation from the two key setups (on the Mac CPU the client creation alone is 30 to 50 s of a 40 to 60 s setup; bench-log 4 October 2026, shards). The next PC run (PROVE-SHARD.bat) shows whether the gap sits before the first compressed stage and how long it is on the card. Was: Open, found by the team (4 October 2026, morning, first RTX 5090 run through WSL2, SP1 6.8.1). +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. @@ -1492,14 +1492,14 @@ Evidence: `docs/bench-log.md`, 4 October 2026 "difficulty rule: timestamp attack ### P21. The SP1 proof is not what consensus checks in proving v0 "Your proof records pay provers, and the node pays a record whose statement matches its own execution whether or not the SP1 proof behind it verifies. A prover can sign the native statement without proving anything." -Status: Open, stated in spec 7.7 item 4 (4 October 2026). Branch `proving` of the fork, `igneum/exec/src/proving.rs`. +Status: Open, stated in spec 7.7 item 4 (4 October 2026). Branch `proving` of the fork, `igneum/exec/src/proving.rs`. Sweep (5 October 2026): stated; the in-consensus verifier is a build item (execution engineer). 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. ### P22. The rewards and payouts are inputs to the shard proof, not outputs "The shard guest takes the segment's rewards and the prover payouts as data and commits the post-root after them. A host can feed any list and the proof still verifies." -Status: Open, stated in spec 7.7 item 6 (4 October 2026). +Status: 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. @@ -1521,7 +1521,7 @@ the project lead's decision of 4 October 2026: the total-weight floor of Q3 is 2 ### 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: Fix built, pending rollout (4 October 2026). Was: Open (10:46 UTC, 4 October 2026, the live finding). +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). @@ -1573,7 +1573,7 @@ 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. +Status: Conceded, scheduled. Sweep (5 October 2026): unchanged on the `proving` branch (no `debug_*`, `eth_subscribe` or `eth_getProof` in `igneum/exec/src/rpc.rs`); scheduled work, execution engineer. 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. @@ -1582,7 +1582,7 @@ Evidence: `docs/design/execution-layer.md` 10.1 (RPC table, "Missing"), 10.3; de ### D6. A forged job result reaches my contract and nobody vetoes it "Segments have the native-execution veto. Jobs do not: full nodes cannot re-run an arbitrary program, so for a precompile job the proof is the only check. A soundness bug in SP1 writes whatever the attacker wants into my callback." -Status: Conceded, contained by rule, review scheduled. +Status: 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. @@ -1595,7 +1595,7 @@ Review: `docs/review/round-4-2026-10-04.md`. Scope: devnet v4 through `a21ff239` ### X23. One shipped key is an administrator channel to the founder's PCs "Your relay accepts either the URL token or the `x-igneum-key` header for everything, including queuing PowerShell that the PC agent runs as administrator. The key is the log-intake key, a literal in six tracked files and inside every Windows and prover package you have handed out. And the zip with both relay secrets sits on the downloads host behind the dl token, which is in your git history and in every installed app. One token, four hops, no privilege boundary." -Status: Open, fatal as an operational fact (4 October 2026). The agent was live and elevated on PC 1 at 13:41 UTC (`GET machines`, read-only). +Status: Open, fatal as an operational fact (4 October 2026). The agent was live and elevated on PC 1 at 13:41 UTC (`GET machines`, read-only). Sweep (5 October 2026): the relay token was rotated on 4 October (`~/.config/igneum/relay-token.old-2026-10-04` sits beside the new one); `POST task` with `kind: run` still needs only the token (`relay/api/relay.mjs:114-119`, no per-machine secret or signature), so the operational half stands. The 401 test needs the deployed relay and PC 1 (relay owner; rotation is the project lead's). 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. @@ -1604,7 +1604,7 @@ Evidence: the files above; `docs/review/round-4-2026-10-04.md` sections 4 and 5. ### X24. The relay token rides in the URL on every request "Every poll of every agent and every page refresh puts the token in the path, so it is in Vercel's request logs, in browser history and in every terminal that ran `tools/relay.mjs`. You built an `x-relay-token` header and nobody uses it." -Status: Open (4 October 2026); the print lines fixed: `tools/relay.mjs` shows `/r/` in `list` and `watch` (only `url` prints the real one). +Status: Open (4 October 2026); the print lines fixed: `tools/relay.mjs` shows `/r/` in `list` and `watch` (only `url` prints the real one). Sweep (5 October 2026): `x-relay-token` is accepted (`relay/lib/relay.mjs:38`) but no client sends it (no match in `relay/clients`, `tools/relay.mjs` or `app/igneum-app/src`), so every request still carries the token in the path. The Vercel log check needs the deployment (relay owner). Answer: Correct. `relay/vercel.json:6` rewrites `/r//api/` to a query string; `igneum-agent.ps1:14`, `send.ps1:26`, `send.sh:11`, `agent.sh:10` and `tools/relay.mjs:24` all build the tokened URL, and `tools/relay.mjs:83,88,125` print it. `Referrer-Policy: no-referrer` and `X-Robots-Tag` are set (`vercel.json:12-13`); there is no HSTS. Fix: the header in every client, the URL token kept for the phone's page only, HSTS, and the print lines masked. Review id R4.4.3. @@ -1613,7 +1613,7 @@ Evidence: the files above. Experiment: the Vercel log view for `igneum-relay` af ### X25. The PC agent installs itself at every logon, at highest privilege, on every start "Double-click once and the agent writes a scheduled task with `/RL HIGHEST` and a RunOnce key. Your README says it only re-arms for a reboot. Closing the window does nothing." -Status: Open (4 October 2026). +Status: Open (4 October 2026). Sweep (5 October 2026): unchanged (`relay/clients/igneum-agent.ps1:72`, `schtasks /SC ONLOGON /RL HIGHEST`). The `schtasks /Query` check needs PC 1. 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. @@ -1622,7 +1622,7 @@ Evidence: `relay/clients/igneum-agent.ps1`. Experiment: `schtasks /Query /TN Ign ### X26. The feed is a permanent transcript, and it holds the dl token by design "One secret pages the whole history: every task body and every result transcript, usernames, hostnames, the folder that holds the secrets. And `tools/relay.mjs` writes the tokened download URL into task bodies before posting, so a relay leak is a dl-token leak." -Status: Open (4 October 2026). +Status: 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. @@ -1631,7 +1631,7 @@ Evidence: the files above. Experiment: `feed?limit=500&before=` after the ch ### X27. The relay has no clean rotation and no sender binding "Rotate the token and the key path stays open; rotate the key and every shipped package stops uploading logs. Any holder posts a `result` from any machine name, or registers a machine, and the Mac's watch prints it as truth." -Status: Open (4 October 2026). +Status: Open (4 October 2026). Sweep (5 October 2026): unchanged (`from` is a free field in `relay/api/relay.mjs`; nothing binds a `result` to the caller's machine). Relay owner. 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. @@ -1640,7 +1640,7 @@ Evidence: the files above. Experiment: a `result` posted with a `from` that does ### X28. Relay hygiene, minor "`===` on secrets, no HSTS, a GET that acks, a reboot on any output containing `RELAY-REBOOT`, orphaned blobs, no rate limit anywhere, a WSL user `igneum`/`igneum` with NOPASSWD sudo, the username and secret folder posted on register, and a file in `~/.config/igneum` whose name is a token." -Status: Open, minor (4 October 2026); two of the points fixed: secrets compared in constant time (`relay/lib/auth.mjs`, `sameSecret`, unit test in CI) and HSTS on the relay (`relay/vercel.json`). +Status: Open, minor (4 October 2026); two of the points fixed: secrets compared in constant time (`relay/lib/auth.mjs`, `sameSecret`, unit test in CI) and HSTS on the relay (`relay/vercel.json`). Sweep (5 October 2026): the remaining points unchanged; relay owner. 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. @@ -1703,7 +1703,7 @@ Evidence: the files above. Experiment: a 30 s cut on a 3-node devnet at d = 20; ### X19. Operational knobs and silences in the shipped node "A slow-clock node disconnects every peer on every relayed block and never says why; the handshake's `time_offset` is computed and unused; `IGNEUM_ATTACK_TS_OFFSET_MS` and `IGNEUM_POW_STRIKES` are compiled into the live binary; `timestamp_deviation_tolerance` is dead and still accepted." -Status: Open, minor (4 October 2026). +Status: Open, minor (4 October 2026). Sweep (5 October 2026): the app half is done (bench-log, "a node 60 s behind the clock is silently dead": the node card shows the skew with a Sync clock button, Start is blocked past 10 s, checked with `IGNEUM_APP_FAKE_SKEW=-60`); the node's one WARN line is filed in `docs/plans/node-changes.md` section 1 and not written; `faketime` is not installed on this Mac, so the node experiment was not run. 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. @@ -1712,7 +1712,7 @@ Evidence: the files above. Experiment: `igneumd` under `faketime -60s` logs one ### X20. Cold-sync checkpoint determination is indices times chain length "A fresh node starts `next_index` at 0 and walks the selected chain from the sink for every index. At mainnet length it never finishes its first resolution." -Status: Open, minor now (4 October 2026). +Status: Open, minor now (4 October 2026). Sweep (5 October 2026): unchanged on `finality-fixes` (`processes/finality.rs:204` starts `next_index` at 1 and walks the chain per index). A 10^6-block simnet is 11.6 days of chain at 1 block/s and was not built. Fix row in section 2.5. 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. @@ -1721,7 +1721,7 @@ Evidence: the file above. Experiment: a fresh node against a 10^6-block simnet c ### M25. The miner takes the day length from its environment, and the schedule global can tear "The template carries epoch and lead but not the day; the miner reads `IGNEUM_POW_DAY_MS` from its environment. And `install_pow_schedule` stores day, lead, epoch while `pow_schedule` loads epoch, lead, so a miner switched between schedules can wrap `pow_epoch_seed_score`." -Status: Open, minor (4 October 2026). +Status: Open, minor (4 October 2026). Sweep (5 October 2026): the schedule now rides in the override file as consensus params (`a5ef8b07`, in `devnet-v4`); whether the template carries the day and whether the global swap is atomic was not re-read, and the mismatch run (a miner at `IGNEUM_POW_DAY_MS=1440000` against a default node) was not run. 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. @@ -1730,7 +1730,7 @@ Evidence: the files above. Experiment: `igneum-miner` with `IGNEUM_POW_DAY_MS=14 ### 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: Open (4 October 2026). +Status: 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. @@ -1739,7 +1739,7 @@ Evidence: the file above. Experiment: `--status-secs 10` with a GPU stress tool ### 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: Open (4 October 2026). +Status: 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. @@ -1748,7 +1748,7 @@ Evidence: the files above. Experiment: a fast-time simnet node patched to flip ` ### M28. The kernel text is bound only to its own directory "The worker compiles whatever `kernel_bound.cu` it finds in a directory whose `seeds.txt` matches; the self-test checks the GPU against a `vectors.h` from the same directory. Nothing commits the text to what the generator would emit for the seed. 'Source check PASS' is a prefix equality." -Status: Open, minor (4 October 2026). The writer is the local miner and the directory is the user's own, so no privilege boundary is crossed. +Status: Open, minor (4 October 2026). The writer is the local miner and the directory is the user's own, so no privilege boundary is crossed. Sweep (5 October 2026): no kernel hash in `program.json` on any branch (`git grep -i 'kernel_hash|program_hash'` on `miner-reliability` finds nothing); the tampered-pack test needs a GPU worker. Fix row in section 2.5. 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. @@ -1757,7 +1757,7 @@ Evidence: the files above. Experiment: a tampered pack with matching vectors mus ### 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: Open (4 October 2026). +Status: 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. @@ -1766,7 +1766,7 @@ Evidence: the files above. Experiment: one constant edited in `kernel_bound.cu` ### X22. Worker restart paths, minor "Two miners truncate the same `packs\devnet` while workers read it; every restart begins on the stale first pack; the restart loop has no cap; the 60 s stall guard wraps the self-heal build; a node can crash the miner through an `expect`; a worker without prepare support loops on export during IBD." -Status: Open, minor (4 October 2026). +Status: Open, minor (4 October 2026). Sweep (5 October 2026): two of the six fixed on `miner-reliability` (`501363e0`: a dead worker's stdin no longer spins the fill loop; `945153ab`: a silent worker still runs the guards and STATUS); the shared `packs\devnet` truncation, the stale first pack, the `expect` crash and the IBD export loop remain; restart timing needs the PCs. 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. @@ -1775,7 +1775,7 @@ Evidence: the files above. Experiment: time from worker restart to first accepte ### E16. The 20% pool is burned on the live chain, and the text says it pays provers "Your coinbase sends the 20% to an OP_RETURN tagged `igneum-proving-pool-v0`. Your own comment says provably burned. Your cap test counts it as supply. Your litepaper says, present tense, that it pays a standing prover population." -Status: Open (4 October 2026). +Status: 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. @@ -1811,7 +1811,7 @@ Evidence: the files above. Experiment: the three draw lines. ### X29. Host and file hygiene, minor "The Mac's live node binds its gRPC to every interface. Four secrets or pointers in `~/.config/igneum` are world-readable, one token is a filename, and the intake key rides on `curl`'s command line. The manifest answers CORS `*` and the clock source is a cacheable page's Date header." -Status: Open, minor (4 October 2026). +Status: Open, minor (4 October 2026). Sweep (5 October 2026): read-only checks on this Mac: every secret under `~/.config/igneum` is now mode 600 (only `ota-signing-key.pub` is world-readable, as it should be), so that half is fixed; the live node still listens on every interface (`lsof`: `igneumd` on `*:26610`). The `curl` command line and the clock source were not re-checked. 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. diff --git a/sim/economy/security_budget.py b/sim/economy/security_budget.py new file mode 100644 index 000000000..b328fc738 --- /dev/null +++ b/sim/economy/security_budget.py @@ -0,0 +1,112 @@ +#!/usr/bin/env python3 +"""Security budget through the halvings (ledger E15, open item O-5.11). + +Arithmetic on the emission schedule of spec 2.5 against a fee grid, a price path and an electricity price, reporting +per year what reaches miners and provers apart from the burn, the fleet that income supports, and what a one-day 51% +rental and a 20-day two-thirds campaign cost against that fleet. Extends docs/analysis/security-budget.md (3 October +2026), which has the emission table and the USD 1,000,000 floor; this script adds the fee grid, the price paths and the +hashrate response the ledger asked for. Nothing here is a prediction: every price and fee is an input, labelled. + + python3 security_budget.py the full grid as markdown + python3 security_budget.py --elec 0.08 another electricity price, USD per kWh + python3 security_budget.py --card-w 300 --card-mh 124 + +Model. Emission: 1,000,000,000 IGN per 365.25-day year for years 1 and 2 (year 1 minus the 30-day ramp, about 37 +million IGN), halving every 63,115,200 DAA seconds (two years), 80% to the block producer and 20% to the proving pool +(spec 2.5). Fees: a priority-fee grid in IGN per block (low 0.01, medium 0.1, high 1.0), 80% of which reaches miners +and provers (spec 5.2; the burned base fee reaches nobody and is not counted); external proving demand in USD per year +(zero, or the economy simulator's launch assumption of USD 2,000 a day, `sim/economy/sim.py` ext_usd_day), 90% to +provers (spec 5.4). Price paths: flat at USD 0.005, 0.02 and 0.10 per IGN (the three inputs of the 3 October analysis), +and from the base input a falling path (-30% a year) and a rising path (+30% a year). Hashrate response: the fleet is +the number of cards whose electricity the miners' income pays for at the stated price, one card at `--card-w` watts and +`--card-mh` MH/s all year (an operator at break-even on power; capital, rent and margin are zero, so the fleet is an upper +bound). Rental cost: a 51% attacker for one day matches that fleet for 24 h at the same electricity price; the 20-day +figure is the finality headline (20 days of 100% of hashrate to hold two thirds of weight, spec 3). The floor is the +analysis's USD 1,000,000 a year to miners. +""" +import argparse + +YEAR_S = 365.25 * 86400 +HALVING_S = 63_115_200 +RAMP_LOSS = 37_000_000 # IGN never minted in the 30-day ramp, spec 2.5 (approximate, from the 3 October analysis) +BLOCKS_PER_YEAR = YEAR_S # one DAA second per block at 1 block/s; the fee grid is per block + + +def emission(year): + """IGN emitted in calendar year `year` (1-based).""" + halvings = (year - 1) // 2 + e = 1_000_000_000 / (2 ** halvings) + if year == 1: + e -= RAMP_LOSS + return e + + +def price_path(kind, year): + if kind == "flat-low": + return 0.005 + if kind == "flat-base": + return 0.02 + if kind == "flat-high": + return 0.10 + if kind == "falling": + return 0.02 * (0.7 ** (year - 1)) + if kind == "rising": + return 0.02 * (1.3 ** (year - 1)) + raise ValueError(kind) + + +def row(year, price, tip_per_block, ext_usd, elec, card_w, card_mh): + e = emission(year) + miners_ign = 0.8 * e + 0.8 * tip_per_block * BLOCKS_PER_YEAR * 0.5 # the 80% tip share split miners/provers, 50/50 assumed + provers_ign = 0.2 * e + 0.8 * tip_per_block * BLOCKS_PER_YEAR * 0.5 + miners_usd = miners_ign * price + provers_usd = provers_ign * price + 0.9 * ext_usd + burn_usd = 0.1 * ext_usd # the job burn only; the base fee is outside the grid and the unregistered app share is ignored + card_year_usd = card_w / 1000 * 8766 * elec + cards = miners_usd / card_year_usd + fleet_mh = cards * card_mh + rent_day = cards * card_w / 1000 * 24 * elec + return dict(year=year, price=price, miners=miners_usd, provers=provers_usd, burn=burn_usd, cards=cards, + fleet_mh=fleet_mh, rent_day=rent_day, rent_20d=20 * rent_day) + + +def fmt_usd(x): + return f"{x:,.0f}" + + +def main(): + ap = argparse.ArgumentParser() + ap.add_argument("--elec", type=float, default=0.12, help="USD per kWh") + ap.add_argument("--card-w", type=float, default=300.0) + ap.add_argument("--card-mh", type=float, default=124.0, help="MH/s per card (RTX 5090 on the devnet, 4 Oct 2026)") + ap.add_argument("--years", type=int, default=14) + ap.add_argument("--ext-usd", type=float, default=2000 * 365.25, help="external proving demand, USD per year, in the demand columns") + a = ap.parse_args() + + print(f"# Security budget through the halvings (E15 / O-5.11), electricity USD {a.elec}/kWh, card {a.card_w:.0f} W at {a.card_mh:.0f} MH/s\n") + print("Every price and fee is an input. Fleet = cards whose power the miners' income pays for (upper bound). " + "Rent 1 d = electricity for a fleet of equal size for 24 h (a 51% attacker at power cost); rent 20 d = the two-thirds campaign.\n") + + grids = [("no demand, no tips", 0.0, 0.0), ("low tips 0.01 IGN/block, no demand", 0.01, 0.0), + ("medium tips 0.1 IGN/block, launch demand", 0.1, a.ext_usd), ("high tips 1 IGN/block, launch demand", 1.0, a.ext_usd)] + paths = ["flat-low", "flat-base", "flat-high", "falling", "rising"] + + for label, tip, ext in grids: + print(f"## Fee grid: {label}\n") + for path in paths: + print(f"### Price path {path}\n") + print("| year | price USD | to miners USD | to provers USD | burned USD (job share) | fleet cards | fleet MH/s | rent 1 d USD | rent 20 d USD | below floor |") + print("|---|---|---|---|---|---|---|---|---|---|") + first_below = None + for y in range(1, a.years + 1): + r = row(y, price_path(path, y), tip, ext, a.elec, a.card_w, a.card_mh) + below = r["miners"] < 1_000_000 + if below and first_below is None: + first_below = y + print(f"| {y} | {r['price']:.4f} | {fmt_usd(r['miners'])} | {fmt_usd(r['provers'])} | {fmt_usd(r['burn'])} | {r['cards']:,.0f} | " + f"{r['fleet_mh']:,.0f} | {fmt_usd(r['rent_day'])} | {fmt_usd(r['rent_20d'])} | {'yes' if below else ''} |") + print(f"\nFirst year below the USD 1,000,000 miner floor: {first_below if first_below else 'none within ' + str(a.years) + ' years'}\n") + + +if __name__ == "__main__": + main() From 6c6ad45743de0e37a99fccd0927a30a0e5229f5e Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Sun, 4 Oct 2026 22:43:59 +0000 Subject: [PATCH 2/6] FUD ledger sweep, round 2: spec 06 rows restated, M20 exposure dated, the sweep's status-update section and the morning findings Spec 06 rows O-3.1, O-3.14, O-5.9 and O-5.11 carry the sweep's evidence (fix row 124 done). M20: the devnet's pruning point leaves genesis between DAA 108,000 and 151,200, about 14:00 UTC 5 October to 01:00 UTC 6 October, after which a fresh node rejects the honest pruning proof under the stub. The ledger ends with the sweep's status-update section; the review file carries draft counts and the three findings. Co-Authored-By: Claude Fable 5.1 --- docs/fud-fixes.md | 2 +- docs/fud-ledger.md | 17 ++++++++++++++--- docs/spec/06-open-items.md | 8 ++++---- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/docs/fud-fixes.md b/docs/fud-fixes.md index cedd7e3fc..de76fef58 100644 --- a/docs/fud-fixes.md +++ b/docs/fud-fixes.md @@ -281,7 +281,7 @@ Added by `docs/review/ledger-sweep-2026-10-05.md`, which holds what ran, what di | 121 | M21 | k = 18 is Kaspa's table value; `calculate_ghostdag_k` gives k 5 at the cloud devnet's measured p99 of 0.67 s and k 55 at a 20-s bound, and proof-bearing bodies are unmeasured | Run O-2.2 with bodies of the size design 5.4 implies, take the p99 propagation, re-derive k with the fork's function (the table is in the ledger entry) (3 h) | consensus engineer | before testnet | no | | 122 | X29 | The live node's gRPC listens on every interface (`igneumd` on `*:26610`, read-only check 5 October); the file modes are fixed | `--rpclisten=127.0.0.1:26610`; PC 2 through a tunnel or its own node (0.5 h) | app owner, the project lead | now | no | | 123 | M14, F14 | O-3.14 (the finality simulation with the DAA in the loop under both forms of W2) has no DAA model inside `finality_v2.py`; the chain-model result (no amplification under either controller) stands in for it | Add a lagging retarget to `finality_v2.py` (Kaspa's sampled window and rule v2), run the 50x pulse under both W2 forms, log the day the renter crosses a third (4 h) | cryptographer (sim) | before testnet | no | -| 124 | F1, O-3.1 | Spec 06 row O-3.1 still says "not yet in `sim/`" and the ledger's launch-month arithmetic was in prose only | Restate O-3.1, O-3.14, O-3.15, O-5.9 and O-5.11 in spec 06 with tonight's evidence (the min_daa rule is implemented and measured; K, I and the economy scenarios ran; the budget grid ran) (0.5 h) | Claude (spec) | now | no | +| 124 | F1, O-3.1 | Spec 06 row O-3.1 still said "not yet in `sim/`" and the ledger's launch-month arithmetic was in prose only | Done in the sweep (5 October 2026): rows O-3.1, O-3.14, O-5.9 and O-5.11 of spec 06 carry tonight's evidence (O-3.15 was already marked decided) | Claude (spec) | done | no | | 125 | X14 | Only hashing concentration can be computed from what the observer keeps; signing, proving and aggregation need certificate and proof-record extracts | The observer stores signer bitmaps per certificate and prover keys per proof record; a nightly top-1/3/10 table on the live page (3 h) | app owner (observer) | before testnet | no | | 126 | E12 | The devnet half of O-5.9 (profit-only prover clients, `f_p` and `B_p` paths) | Phase 4 devnet run as the ledger entry states (4 h) | execution engineer | before testnet | no | diff --git a/docs/fud-ledger.md b/docs/fud-ledger.md index e22cf06c9..da8e18d10 100644 --- a/docs/fud-ledger.md +++ b/docs/fud-ledger.md @@ -29,7 +29,7 @@ Evidence locations referenced below: `docs/bench-log.md`, `proto-metal/TESTS.md` ### M1. The program space is tiny "Eleven integer ops, 64 instructions, 8 iterations, a splitmix register init. That is not RandomX. RandomX leans on a superscalar out-of-order CPU with floating point and branches. Yours is a sea of 32-bit ALUs and a memory bus. A chip for that is a weekend." -Status: Open, experiment scheduled. +Status: 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. 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. @@ -347,7 +347,7 @@ Evidence: design doc "Proving speed on consumer GPUs" risk item and Finality v2 ### P9. Shard griefing "Claim a shard with a small bond and never prove it. Repeat. Finality waits on you." -Status: Answered by design, parameters open. +Status: 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). 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. @@ -1109,7 +1109,7 @@ Evidence: `docs/analysis/weak-program-census-2026-10-03.md` sections 7 and 9. Re ### 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: 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. Fix row in `docs/fud-fixes.md` section 2.5. +Status: 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. @@ -1833,3 +1833,14 @@ Evidence: the commits above. Experiment: `curl https://igneum.network/api/live` - **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. - **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 and measured; 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. +- **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), M14 and F14 (no amplification in the chain model; the finality-with-DAA run still owed). +- **Open, needs hardware, a person or the devnet:** M1, M11 (a rig), M16 (the 5090), M22, M25, 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. diff --git a/docs/spec/06-open-items.md b/docs/spec/06-open-items.md index 778682227..dc22f2328 100644 --- a/docs/spec/06-open-items.md +++ b/docs/spec/06-open-items.md @@ -49,7 +49,7 @@ An item closes when its measurement is in `docs/bench-log.md` or its decision is | Id | Item | What closes it | Gate | |---|---|---|---| -| O-3.1 | The first month: no weight exists; an attacker producing 75% of blocks from day 2 crosses 2/3 on day 9 (ledger F1). C5 says first hour; this specification proposes first 30 days | Launch-month simulation (not yet in `sim/`); decision; litepaper states the rule either way | 3 | +| O-3.1 | The first month: no weight exists; an attacker producing 75% of blocks from day 2 crosses 2/3 on day 9 (ledger F1). C5 says first hour; this specification proposes first 30 days | Launch-month simulation (not yet in `sim/`); decision; litepaper states the rule either way. Sweep 5 October 2026: the gate is implemented (`min_daa = weight_window`, fin-fixes, merged into devnet-v4) and measured on the fork (harness s5 before and after, `docs/bench-log.md` "finality fixes F17 and F1"); the launch month under the gate is arithmetic in `docs/review/ledger-sweep-2026-10-05.md` (no lock before day 30; on day 30 an attacker with share s of blocks from day k holds s (31 - k) / 30, so 75% from day 2 holds 72.5% and locks alone, 51% from day 1 cannot; the lock-alone threshold is 69% from day 2). What is left is the decision to keep the gate at the full window, which the ledger (F1) recommends | 3 | | O-3.2 | Checkpoint depth d = 60 is a placeholder (ledger F7) | Devnet with regional latency records the reorg-depth distribution at each block rate; set d so a vote split at one index is rare | 3 | | O-3.3 | Parameters of the block reading of participation (rule closed 3 October 2026, section 3.3 Q2 and 3.4.1; ledger F3): the per-block vote bound and the carriage window, and the simulation ran with the narrower cert reading | Add vote carriage in blocks and a hostile aggregator to `finality_v2.py`; re-run A, C, D and F1 under the block reading; set the per-block vote bound and confirm the carriage window of 240 indices | 3 | | O-3.4 | Certificate grace value; must be at least 3x the worst honest one-way delay (section 3.3, Q4) | Measure one-way delays on the devnet across regions; set grace | 3 | @@ -62,7 +62,7 @@ An item closes when its measurement is in `docs/bench-log.md` or its decision is | O-3.11 | Key succession (W5): replay protection and what happens if both keys mine after the message | Specify the message (old key, new key, DAA score, signature) and that blocks naming the old key after inclusion earn nothing | 3 | | O-3.12 | Vote message and certificate wire formats, aggregation rules, bitmap size at 10^4 keys | Specify with the P2P layer | 3 | | O-3.13 | `finality_active` flag semantics and exchange guidance (section 3.9) are Designed and untested | Devnet stall test; exchange guidance reviewed by an operator | 3, 4 | -| O-3.14 | Finality simulation with the DAA in the loop under a pulsed rental (ledger M14 and F14, round 3): every run of `sim/results_v2.md` assumed a perfect retarget, and the devnet of 3 October 2026 showed DAA time running 2.9x the wall clock for 17 minutes after a hashrate step | `finality_v2.py` with Kaspa's sampled DAA and the controller chosen at gate 2 (section 2.3) in the loop, a 50x renter pulsing two minutes in every hour, under both forms of W2 and Q1 (DAA-score blocks as simulated; median-time buckets as specified in section 3.1 and 3.3), reporting the day the renter crosses a third and the chain's block rate meanwhile; logged in `docs/bench-log.md`; confirms or reverts the median-time form | 3 | +| O-3.14 | Finality simulation with the DAA in the loop under a pulsed rental (ledger M14 and F14, round 3): every run of `sim/results_v2.md` assumed a perfect retarget, and the devnet of 3 October 2026 showed DAA time running 2.9x the wall clock for 17 minutes after a hashrate step | `finality_v2.py` with Kaspa's sampled DAA and the controller chosen at gate 2 (section 2.3) in the loop, a 50x renter pulsing two minutes in every hour, under both forms of W2 and Q1 (DAA-score blocks as simulated; median-time buckets as specified in section 3.1 and 3.3), reporting the day the renter crosses a third and the chain's block rate meanwhile; logged in `docs/bench-log.md`; confirms or reverts the median-time form. Sweep 5 October 2026: the chain model has run (`sim/difficulty/attacks` scenario 2: a 50x pulse earns 3.7% of the base's blocks per hash under the Igneum rule and 85% under Kaspa's, weight per hash 0.26 and 0.98, never above 1) and the fork agrees (harness s5, weight share over block share 0.999). The DAA inside `finality_v2.py` under both W2 forms is still not written (fud-fixes row 123) | 3 | | O-3.15 | Vote keys with history can be bought, borrowed or stolen; every scenario in `sim/results_v2.md` models a renter who must mine (ledger F19, external review 3 October 2026) | `finality_v2.py` scenario: k% of weight changes hands at day 0 against the same k% arriving as fresh hashrate, for k in 20, 34 and 40, plus a 40/40/20 partition row under the active-set rules and the floor; report time to a conflicting lock; decide whether W5 makes the successor re-earn and whether weight decays when a key's block profile breaks | 3 | | O-3.16 | What holds during a finality pause: the seed pipeline from uncertified checkpoint blocks (O-4.3, section 4.3), the survival of pre-pause locks (3.5) and `finality_active` false (3.9) are three texts and no statement (ledger F20) | Decide O-4.3 (this specification recommends uncertified-allowed); write the four pause guarantees into 3.7; devnet with a 45% silent set through 3 epoch boundaries: program advances on schedule, no seed fork, pre-pause locks survive the heal | 3 | @@ -92,9 +92,9 @@ An item closes when its measurement is in `docs/bench-log.md` or its decision is | O-5.6 | External job bond size and claim timeout (ledger P9); shards carry no bond since the sortition rule of section 7.2 | Set on the phase 4 devnet | 4 | | O-5.7 | The provers' proportion of the 80% tip share (section 5.2) | Defined by the chunked proving protocol | phase 2 | | O-5.8 | Developer registration format at deployment and the re-registration transaction (section 5.2) | Execution-layer specification | decision, execution engineer | -| O-5.9 | Mining against proving under shocks: external proving pays 10x, the IGN price falls, a large operator leaves, assignments go unfulfilled, clients maximise profit (ledger E12); design R8 covers the fee switch only and has not run | R8 simulation extended with the five shocks, then the phase 4 devnet with profit-only prover clients: backlog depth, time to clear, `f_p` and `B_p` paths, income per card | 4 | +| O-5.9 | Mining against proving under shocks: external proving pays 10x, the IGN price falls, a large operator leaves, assignments go unfulfilled, clients maximise profit (ledger E12); design R8 covers the fee switch only and has not run | R8 simulation extended with the five shocks, then the phase 4 devnet with profit-only prover clients: backlog depth, time to clear, `f_p` and `B_p` paths, income per card. Sweep 5 October 2026: the simulation half ran in `sim/economy` (scenarios b, d, e: external 10x with a 70% price fall, the 20% operator leaving, a 30% operator never fulfilling; no backlog, every block proven within 60 s, hash trough 82% and 75%); the devnet half with profit-only clients is fud-fixes row 126 | 4 | | O-5.10 | No single figure shows every payment route (emission, base fee, priority fee, external jobs at launch and after the bridge, the client dev fee) with currency, recipient, fee and burn (ledger E13) | Draw it, one route per row, in the litepaper Economics section and the customer brief; operator revenue never summed with protocol revenue | decision, execution engineer; before public repo | -| O-5.11 | Security budget through halvings with low fees and no external demand at a flat IGN price (ledger E15) | Model of emission per 2.5 through year 12 against a fee grid and an income-per-card hashrate response; payments to miners and provers reported apart from the burn; the failing year and price stated in the litepaper | before mainnet, simulation | +| O-5.11 | Security budget through halvings with low fees and no external demand at a flat IGN price (ledger E15) | Model of emission per 2.5 through year 12 against a fee grid and an income-per-card hashrate response; payments to miners and provers reported apart from the burn; the failing year and price stated in the litepaper. Sweep 5 October 2026: ran as `docs/analysis/security-budget.md` (3 October) plus `sim/economy/security_budget.py` (fee grid, falling and rising paths, hashrate response): the USD 1,000,000 miner floor is crossed in year 7 at USD 0.005, year 11 at USD 0.02, never within 14 years at USD 0.10; no fee level in the grid moves the year; at the year-7 crossing a 51% attacker matches the fleet the budget pays for at USD 1,369 of electricity a day. The litepaper sentence is public text | before mainnet, simulation | ## 6.6 Sections 7 and 8, execution and client security From a1deffd81ac0600138d012ace09050b3e093c05f Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Mon, 5 Oct 2026 00:14:12 +0000 Subject: [PATCH 3/6] FUD ledger sweep, round 3: the simulator batch (M14 under rule v2, E17 at 124 MH/s, F1 zero-history ramp) attacks.py scenario 2 under rule v2 and Kaspa's DAA: a pulse never earns more blocks per hash than steady mining (weight per hash 0.26 and 0.98); the economy simulator at the devnet's 124 MH/s; finality_sim scenario A (the window is full on day 35 to 41 from zero history). The first fast-time s5 attempt failed on an override field the integration build does not know; the re-run on the finality-fixes build is queued. Co-Authored-By: Claude Fable 5.1 --- docs/fud-ledger.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/fud-ledger.md b/docs/fud-ledger.md index da8e18d10..4092d636b 100644 --- a/docs/fud-ledger.md +++ b/docs/fud-ledger.md @@ -152,7 +152,7 @@ Evidence: `docs/bench-log.md`, two-card table. ### 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. +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. 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. @@ -1055,7 +1055,7 @@ Added by `docs/review/round-3-2026-10-03.md`, which holds the full argument for ### M14. A pulsed rental against the block-count DAA buys weight at a discount "Bring 50x the hashrate for two minutes once an hour. Kaspa's window keeps the 661 most recent samples, so you mine thousands of blocks at the old target before it moves, and when you leave the honest network crawls for hours at your difficulty. Weight is blocks over a window of blocks. You get a third of the window in a week for the price of a 1.6x average." -Status: Open, experiment scheduled as O-3.14 (3 October 2026). The weight half is written into the spec, see F14; the controller half is gate 2 (O-2.1). +Status: Answered with evidence for the controller half (5 October 2026 sweep); the finality run with the DAA inside `finality_v2.py` (O-3.14) is still owed (fud-fixes row 123). Chain model, `sim/difficulty/attacks/attacks.py --scenario pulse --rules 'igneum:ref_window=600+long_min=100000,kaspa' --seeds 3` (rule v2, the live rule since DAA 33,000, and Kaspa's DAA; 36 s, 5 October 2026): a 50x pulse for 10 min of every hour earns 3.7% of the always-on base's blocks per hash under rule v2 (weight per hash 0.262, worst seed 0.266) and 85.5% under Kaspa's rule (0.983); a single pulse earns 2.8% (0.130) and 56.8% (0.871). Under neither rule does a pulse earn more blocks per hash than steady mining, so the amplifier the critic describes is at most 1.0 in the chain model and the pulse is a loss; the cost it imposes on others is the crawl afterwards (rule v2: the base's blocks per hash down 36% in the hour after, worst gap 199 s, peak 185 blocks a minute; Kaspa's rule: peak 1,734 blocks a minute, 70 to 88% of blocks to the pulser for 81 to 89% of hashes). On the fork itself, `tools/finality-attacks` s5 (10x for 20 s of every 120 s under Kaspa's DAA, 4 October) measured weight share 35.3% against block share 35.3%, ratio 0.999. The hop profiles are in `sim/difficulty/results.md` (hop3, hop10, polluted). Was: Open, experiment scheduled as O-3.14 (3 October 2026). 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). @@ -1432,7 +1432,7 @@ Evidence: `site/litepaper.html` Governance; spec 10.6, 4.5; G7, E2. Experiment: ### 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: designed 10, implemented 9, tested by the team 28, reproduced externally 4, reviewed independently 3). Publication with the benchmark release is still O-X.3. Was: Open, publication scheduled (O-X.3). +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. @@ -1802,7 +1802,7 @@ Evidence: the files above. ### E17. Unlogged inputs behind the economics, minor "The cap's 110 MH/s and its draw are not in the bench-log; the Mac's draw is not logged; the economy sim's one measured input is a 229 MH/s card against today's 124; mining-versus-pool flips from 4.9x for mining on today's devnet to 930x for proving at 10,000 cards and no document says it depends on fleet size; the app-share text omits '100,000-gas calls' and the open base unit; emission ran at up to 2x schedule; shard-scale prover cost is unmeasured on any GPU; the iGPU default off is right." -Status: Open, minor (4 October 2026). +Status: 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. From 733f6c070ce2396ef8da90678c74633979c2c500 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Mon, 5 Oct 2026 01:09:07 +0000 Subject: [PATCH 4/6] FUD ledger sweep, round 4: M25 confirmed on a real-PoW test node (mismatched day length rejected with no reason named), fix row 127 Co-Authored-By: Claude Fable 5.1 --- docs/fud-fixes.md | 1 + docs/fud-ledger.md | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/fud-fixes.md b/docs/fud-fixes.md index de76fef58..2f40363a5 100644 --- a/docs/fud-fixes.md +++ b/docs/fud-fixes.md @@ -284,6 +284,7 @@ Added by `docs/review/ledger-sweep-2026-10-05.md`, which holds what ran, what di | 124 | F1, O-3.1 | Spec 06 row O-3.1 still said "not yet in `sim/`" and the ledger's launch-month arithmetic was in prose only | Done in the sweep (5 October 2026): rows O-3.1, O-3.14, O-5.9 and O-5.11 of spec 06 carry tonight's evidence (O-3.15 was already marked decided) | Claude (spec) | done | no | | 125 | X14 | Only hashing concentration can be computed from what the observer keeps; signing, proving and aggregation need certificate and proof-record extracts | The observer stores signer bitmaps per certificate and prover keys per proof record; a nightly top-1/3/10 table on the live page (3 h) | app owner (observer) | before testnet | no | | 126 | E12 | The devnet half of O-5.9 (profit-only prover clients, `f_p` and `B_p` paths) | Phase 4 devnet run as the ledger entry states (4 h) | execution engineer | before testnet | no | +| 127 | M25 | Confirmed 5 October 2026 (sweep batch 3): a miner started with a different `IGNEUM_POW_DAY_MS` builds its cache for another day and every block is rejected as `BlockInvalid` / `block has invalid proof-of-work`, with no line naming the day (0 of 4 accepted against 7 of 7 for the control) | The day length (or the day index) in the template beside `pow_epoch`, the miner takes it from there and ignores the environment; the node's PoW rejection names the engine's day and the header's day (1.5 h) | miner lead, consensus engineer | before testnet | no | ## 4. What the 3 October decisions close or change diff --git a/docs/fud-ledger.md b/docs/fud-ledger.md index 4092d636b..cb2c72582 100644 --- a/docs/fud-ledger.md +++ b/docs/fud-ledger.md @@ -1721,7 +1721,7 @@ Evidence: the file above. Experiment: a fresh node against a 10^6-block simnet c ### M25. The miner takes the day length from its environment, and the schedule global can tear "The template carries epoch and lead but not the day; the miner reads `IGNEUM_POW_DAY_MS` from its environment. And `install_pow_schedule` stores day, lead, epoch while `pow_schedule` loads epoch, lead, so a miner switched between schedules can wrap `pow_epoch_seed_score`." -Status: Open, minor (4 October 2026). Sweep (5 October 2026): the schedule now rides in the override file as consensus params (`a5ef8b07`, in `devnet-v4`); whether the template carries the day and whether the global swap is atomic was not re-read, and the mismatch run (a miner at `IGNEUM_POW_DAY_MS=1440000` against a default node) was not run. The environment fallback is G12, owned by the fud-consensus branch. +Status: Open, minor (4 October 2026). Sweep (5 October 2026): the schedule now rides in the override file as consensus params (`a5ef8b07`, in `devnet-v4`); the mismatch run was done (5 October 2026, 01:05 UTC, `scratchpad/runs/batch3.sh` under the run lock: one `finality-fixes` node with real PoW at genesis bits 2^16 on ports 29410 to 29412, `pow_day_ms` 86,400,000 in its override file; a control miner, then a miner started with `IGNEUM_POW_DAY_MS=1440000`, 2 CPU threads, 60 s each). Confirmed: the miner still takes the day from its environment (it built its cache for day 1,243,862 while the node and the control miner were on day 20,731); control 7 blocks accepted, 0 rejected; mismatched 0 accepted, 4 rejected, each as `Reject(BlockInvalid)` on the miner and `block has invalid proof-of-work` on the node, so the miner says that it is rejected and not why. Fix row 127: the day length in the template beside the epoch and lead, and a rejection reason that names the day. The environment fallback is G12, owned by the fud-consensus branch. 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. @@ -1841,6 +1841,6 @@ Evidence: the commits above. Experiment: `curl https://igneum.network/api/live` - **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 and measured; 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. -- **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), M14 and F14 (no amplification in the chain model; the finality-with-DAA run still owed). -- **Open, needs hardware, a person or the devnet:** M1, M11 (a rig), M16 (the 5090), M22, M25, 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. +- **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; 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. From 4967dae3b1d95c095025b006a8a4b0941ebcbc12 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Mon, 5 Oct 2026 01:17:45 +0000 Subject: [PATCH 5/6] FUD ledger sweep, round 5: s5 and s4 on the finality-fixes build (F1 burster locks nothing alone, F3 vote-dropping adds 0 ms), F2 floor note, final counts Co-Authored-By: Claude Fable 5.1 --- docs/fud-ledger.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/fud-ledger.md b/docs/fud-ledger.md index cb2c72582..d18744201 100644 --- a/docs/fud-ledger.md +++ b/docs/fud-ledger.md @@ -152,7 +152,7 @@ Evidence: `docs/bench-log.md`, two-card table. ### 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. +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. @@ -161,7 +161,7 @@ Evidence: arithmetic above (not yet in `sim/`); design doc, hostile review table ### 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. +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. @@ -170,7 +170,7 @@ Evidence: `sim/results.md` table E and "What the simulation cannot tell us"; des ### F3. Participation grinding through the bitmap "The aggregator picks which votes go in the certificate once quorum is reached. A block producer carries the certificate it likes. Drop a rival pool's votes from your bitmaps for two hours and its participation factor falls, your share rises." -Status: Closed by rule (3 October 2026), parameter open. Spec section 3.3 Q2 and 3.4.1: participation is computed from every vote seen in blocks over the presence window (votes are block payload), never from the certificates an aggregator chose; the per-block vote bound is O-3.3. Was: Open, experiment scheduled. Sweep (5 October 2026): the block reading is exercised on the fork by harness s3 (block-carried votes give participation; 35 of 35 locked on each of 3 nodes) and s4 (a producer dropping the finality section from 40% of its blocks adds 0 ms to lock latency, 35 locks), bench-log "finality v2 attack harness"; the per-block vote bound and the hostile-aggregator simulation of O-3.3 are still owed. +Status: Closed by rule (3 October 2026), parameter open. Spec section 3.3 Q2 and 3.4.1: participation is computed from every vote seen in blocks over the presence window (votes are block payload), never from the certificates an aggregator chose; the per-block vote bound is O-3.3. Was: Open, experiment scheduled. Sweep (5 October 2026): the block reading is exercised on the fork by harness s3 (block-carried votes give participation; 35 of 35 locked on each of 3 nodes) and s4 (a producer dropping the finality section from 40% of its blocks adds 0 ms to lock latency, 35 locks), bench-log "finality v2 attack harness"; the per-block vote bound and the hostile-aggregator simulation of O-3.3 are still owed. Re-run on the `finality-fixes` build under fast time (5 October 2026, 01:13 UTC, `run.mjs s4 --fast-time`, 2 nodes, 223 s): node B locked 14 checkpoints with a 40% vote-dropping producer, median lock latency 1,042 ms against 1,042 ms for the control, 0 ms added. PASS. 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. @@ -1127,7 +1127,7 @@ Evidence: spec 2.1; `docs/design/execution-layer.md` 5.4. Review id R3.4. ### F14. Weight in blocks over a window in blocks under a lagging retarget "Your day counts assume the block supply is capped at one a second. It is not during a retarget lag, and weight is counted in blocks." -Status: Rule written (3 October 2026): spec 3.1 W2 and 3.3 Q1 are denominated in past-median time, weight as a key's share of each 60-s bucket summed over 30 days; the simulated DAA-score form is kept beside it. O-3.14 (added the same evening) confirms or reverts it at gate 3. Was: Open, rule change proposed. Sweep (5 October 2026): the simulated DAA-score form shows no amplification under either controller (`sim/difficulty/attacks` scenario 2: weight per hash 0.26 under Igneum, 0.98 under Kaspa; harness s5 on the fork: 0.999), so the median-time form is defence in depth whose own run, both forms with the DAA in the loop (O-3.14), is still owed. +Status: Rule written (3 October 2026): spec 3.1 W2 and 3.3 Q1 are denominated in past-median time, weight as a key's share of each 60-s bucket summed over 30 days; the simulated DAA-score form is kept beside it. O-3.14 (added the same evening) confirms or reverts it at gate 3. Was: Open, rule change proposed. Sweep (5 October 2026): the simulated DAA-score form shows no amplification under either controller (`sim/difficulty/attacks` scenario 2: weight per hash 0.26 under Igneum, 0.98 under Kaspa; harness s5 on the fork: 0.999), so the median-time form is defence in depth whose own run, both forms with the DAA in the loop (O-3.14), is still owed. On the current node line (s5 under fast time, 5 October 2026): weight share over block share 0.864, below 1, so the window bought the pulse nothing. 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. @@ -1839,8 +1839,8 @@ Evidence: the commits above. Experiment: `curl https://igneum.network/api/live` `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 and measured; 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). +- **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. -- **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; the finality-with-DAA run still owed). +- **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. From 8f2cd23f045ef57aa5f060021bd3016ea6ba297e Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Mon, 5 Oct 2026 07:24:38 +0000 Subject: [PATCH 6/6] E15 decided: the 4 billion cap stays, no tail emission; spec 5.10 with the measured security-budget table and the review trigger, O-5.11 closed, litepaper and homepage state the cap and the years Co-Authored-By: Claude Fable 5.1 --- docs/fud-ledger.md | 2 +- docs/spec/05-fees-and-economics.md | 45 +++++++++++++++++++++++++++++- docs/spec/06-open-items.md | 4 +-- site/index.html | 2 +- site/litepaper.html | 10 +++++++ 5 files changed, 58 insertions(+), 5 deletions(-) diff --git a/docs/fud-ledger.md b/docs/fud-ledger.md index d18744201..e7fa9bc5a 100644 --- a/docs/fud-ledger.md +++ b/docs/fud-ledger.md @@ -1387,7 +1387,7 @@ Evidence: E4, E5, G1, G5; fud-fixes rows 47, 50, 71. Decision: the project lead, ### 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: 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. +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. diff --git a/docs/spec/05-fees-and-economics.md b/docs/spec/05-fees-and-economics.md index 70fede807..7fb61667e 100644 --- a/docs/spec/05-fees-and-economics.md +++ b/docs/spec/05-fees-and-economics.md @@ -1,6 +1,6 @@ # Igneum protocol specification, section 5: fees, splits, burns, signalling -Spec version 0.1, 3 October 2026. Status of this section: Designed (design document, "The token", "Finality rule, version 2: Fees", decisions table "What do I get for being early?"). Nothing here is implemented or measured. Emission itself is section 2.5. +Spec version 0.1, 3 October 2026. Status of this section: Designed (design document, "The token", "Finality rule, version 2: Fees", decisions table "What do I get for being early?"). Nothing here is implemented or measured, except section 5.10, which is Decided (5 October 2026) and carries a simulation. Emission itself is section 2.5. Two rules frame everything: there is no stake anywhere in consensus, and the protocol carries no fee to any team, foundation or fund. Not one unit of emission or of fees goes to a treasury, a fund, a founder or a stake. The development fund that earlier drafts carried (5% of tips and 5% of job fees under 60% signalling) was removed on 3 October 2026 (section 5.5). @@ -85,3 +85,46 @@ Designed, Open (O-5.3). Each block carries a bitfield; bit b set means "this blo | Proving-cost budget per block | from the phase 2 measurement | Target | | Emission to any treasury | 0 | Designed | | Protocol fee to any team, foundation or fund | 0 | Designed (3 October 2026) | +| Tail emission | 0; the 4,000,000,000 IGN cap of section 2.5 is absolute | Decided (5 October 2026, section 5.10) | +| Tail-reward review trigger | external proving revenue under 1/5 of the block subsidy over any 90-day window after year 5 puts the question to the miners' vote (5.7); the protocol never changes emission by itself | Decided (5 October 2026, section 5.10.3) | + +## 5.10 Security budget after the subsidy + +Decided 5 October 2026 by the owner: the 4,000,000,000 IGN hard cap of section 2.5 is 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 the provers who delivered, section 5.4) plus fees (the 80% producer-and-prover share of the priority fee, section 5.2). Ledger E15; open item O-5.11, decided. + +### 5.10.1 What the subsidy alone pays for + +Measured by `python3 sim/economy/security_budget.py` (5 October 2026, default arguments; the floor is from `docs/analysis/security-budget.md`, 3 October 2026, section 6). The assumptions, every one an input and none a prediction: + +| Input | Value | +|---|---| +| Emission | section 2.5: 1,000,000,000 IGN a year of 365.25 days in years 1 and 2, minus the 30-day ramp in year 1 (about 37,000,000 IGN never minted), halving every 63,115,200 DAA s; 80% to miners, 20% to the proving pool | +| Price | flat at USD 0.005, 0.02 and 0.10 per IGN for 14 years; and the base price USD 0.02 on a falling path (-30% a year) and a rising path (+30% a year) | +| Fees | a priority-fee grid of 0, 0.01, 0.1 and 1 IGN a block at 1 block/s, 80% to miners and provers split 50/50; external demand 0 or USD 2,000 a day, 90% to provers; the base-fee burn reaches nobody and is not counted | +| Card | 300 W at 124 MH/s (the RTX 5090 on the devnet, 4 October 2026); electricity USD 0.12 per kWh; USD 315.58 of power per card-year | +| Floor | USD 1,000,000 a year to miners: the power of 3,169 such cards ("about 3,000"; 393 GH/s), the fleet at which one 1,000-card operator holds a third of the 30-day vote weight | +| Fleet | the cards whose power the miners' subsidy pays at break-even; capital, rent and margin are zero, so the fleet is an upper bound | +| Attacker | a 51% attacker matches that fleet for 24 h at the same electricity price, a lower bound on the attack; the 20-day figure is the two-thirds campaign of section 3 (20 days of 100% of hashrate) | + +The years at which the subsidy alone, with no tips and no external demand, pays miners less than the floor: + +| Flat price, USD per IGN | First year under the floor | Subsidy to miners that year, USD | Cards that subsidy powers | 51% attacker's electricity, USD a day | 20-day campaign, USD | +|---|---|---|---|---|---| +| 0.005 | 7 | 500,000 | 1,584 | 1,369 | 27,379 | +| 0.02 | 11 | 500,000 | 1,584 | 1,369 | 27,379 | +| 0.10 | none within 14 years (the row shows year 14) | 1,250,000 | 3,961 | 3,422 | 68,446 | + +For scale, year 1 at USD 0.005: 3,852,000 to miners, 12,206 cards (1.51 TH/s), USD 10,546 of attacker electricity a day, USD 210,924 over 20 days. The crossing year is the same at every fee level in the grid: 1 IGN a block of tips is 12,623,040 IGN a year to miners, about a tenth of year-7 emission. The falling path crosses in year 5 at every fee level except the highest (1 IGN a block with launch demand), where it crosses in year 6; the rising path never within 14 years. Readers with another electricity price or card can re-run the script with `--elec`, `--card-w` and `--card-mh`; a 2x change in the floor moves the year by at most one halving. + +### 5.10.2 The decision and the reasoning + +The cap stays. Provers' income does not depend on emission: a prover is paid per job (90% of the job fee, 5.4) and per block from the tip share (5.2), and both scale with demand for proofs and for block space, not with the schedule. The 20% emission share is a launch subsidy for a standing prover population; when it fades, the proving market is what keeps the cards on, and a card that is on can hash. The subsidy to miners fades on the schedule every capped proof-of-work chain shares; here the years are measured and stated, and the same hardware has a second income that emission never paid. A tail reward is ruled out as a protocol default, not for ever: the trigger below says when the question is put to the miners, and only their vote can change the schedule. + +### 5.10.3 Review trigger + +REVIEW TRIGGER (rule). If external proving revenue is under one fifth of the block subsidy over any 90-day window (7,776,000 DAA s) after the end of year 5 (DAA score 157,788,000), the question of a tail reward goes to the miners' signalling vote. The protocol itself never changes emission without that vote. + +- External proving revenue: job fees settled in IGN under 5.4, counted at settlement over the window. Until jobs settle in IGN (O-5.2), it is what the payout contracts on customer chains received over the window, converted at the window's settlement rate and published with the reading. Block subsidy: `E(t)` of section 2.5 summed over the same window, in IGN. +- The reading is made by people from chain data and published. The chain computes nothing and changes nothing. +- The vote: a tail reward changes a consensus constant fixed at genesis, so it is an upgrade under 5.7 (90% of blue blocks over the window of O-5.3), not a 60% parameter. Anyone may register the proposal under 5.8 once the condition has held; a proposal that fails may be re-registered after the next qualifying window. +- Nothing in this rule obliges the vote to pass. The cap is the default; a tail reward is a change miners may adopt, and the protocol never adopts it by itself. diff --git a/docs/spec/06-open-items.md b/docs/spec/06-open-items.md index dc22f2328..860f1c562 100644 --- a/docs/spec/06-open-items.md +++ b/docs/spec/06-open-items.md @@ -94,7 +94,7 @@ An item closes when its measurement is in `docs/bench-log.md` or its decision is | O-5.8 | Developer registration format at deployment and the re-registration transaction (section 5.2) | Execution-layer specification | decision, execution engineer | | O-5.9 | Mining against proving under shocks: external proving pays 10x, the IGN price falls, a large operator leaves, assignments go unfulfilled, clients maximise profit (ledger E12); design R8 covers the fee switch only and has not run | R8 simulation extended with the five shocks, then the phase 4 devnet with profit-only prover clients: backlog depth, time to clear, `f_p` and `B_p` paths, income per card. Sweep 5 October 2026: the simulation half ran in `sim/economy` (scenarios b, d, e: external 10x with a 70% price fall, the 20% operator leaving, a 30% operator never fulfilling; no backlog, every block proven within 60 s, hash trough 82% and 75%); the devnet half with profit-only clients is fud-fixes row 126 | 4 | | O-5.10 | No single figure shows every payment route (emission, base fee, priority fee, external jobs at launch and after the bridge, the client dev fee) with currency, recipient, fee and burn (ledger E13) | Draw it, one route per row, in the litepaper Economics section and the customer brief; operator revenue never summed with protocol revenue | decision, execution engineer; before public repo | -| O-5.11 | Security budget through halvings with low fees and no external demand at a flat IGN price (ledger E15) | Model of emission per 2.5 through year 12 against a fee grid and an income-per-card hashrate response; payments to miners and provers reported apart from the burn; the failing year and price stated in the litepaper. Sweep 5 October 2026: ran as `docs/analysis/security-budget.md` (3 October) plus `sim/economy/security_budget.py` (fee grid, falling and rising paths, hashrate response): the USD 1,000,000 miner floor is crossed in year 7 at USD 0.005, year 11 at USD 0.02, never within 14 years at USD 0.10; no fee level in the grid moves the year; at the year-7 crossing a 51% attacker matches the fleet the budget pays for at USD 1,369 of electricity a day. The litepaper sentence is public text | before mainnet, simulation | +| O-5.11 (decided) | **Decided 5 October 2026 by the owner: the 4,000,000,000 IGN cap is absolute, no tail emission (section 5.10).** The question was the security budget through halvings with low fees and no external demand at a flat IGN price (ledger E15), and whether a tail reward answers it. Measured by `docs/analysis/security-budget.md` (3 October) plus `python3 sim/economy/security_budget.py` (5 October 2026: fee grid, falling and rising paths, hashrate response at USD 0.12/kWh, 300 W, 124 MH/s): 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; no fee level in the grid moves a flat-price year; 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. The security budget after the subsidy is the proving market plus fees; provers' income does not depend on emission | Closed. Section 5.10 states the table, the decision and the review trigger (5.10.3): 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 (5.7, 5.8; encoding O-5.3) and the protocol never changes emission without it. The litepaper Economics section and the homepage state the cap, the years and the trigger | decided; the trigger stands | ## 6.6 Sections 7 and 8, execution and client security @@ -126,7 +126,7 @@ Added 3 October 2026 (night) from the external review. These items belong to no | 2 | 9 (O-2.8 closed 3 October 2026 by section 7.1) | | 3 | 16 (O-3.3 and O-3.7 narrowed to parameters and confirmation on 3 October 2026; O-3.14 added the same evening, round 3; O-3.15 and O-3.16 added the same night, external review) | | 4 | 9 | -| 5 | 11 (O-5.1, O-5.2 and O-5.6 narrowed on 3 October 2026; O-5.9 to O-5.11 added the same night, external review) | +| 5 | 11 (O-5.1, O-5.2 and O-5.6 narrowed on 3 October 2026; O-5.9 to O-5.11 added the same night, external review; O-5.11 decided 5 October 2026, section 5.10) | | 7 | 2 (added 3 October 2026, night) | | 8 | 3 (O-8.2 and O-8.3 added the same night) | | X (6.8) | 3 | diff --git a/site/index.html b/site/index.html index 4b63076da..825a587fd 100644 --- a/site/index.html +++ b/site/index.html @@ -493,7 +493,7 @@ pre{margin:0;font-family:var(--f-mono);font-size:13px;line-height:1.6;color:var(

Every coin, mined

-

Hard cap of 4 billion IGN, halving every two years for ever.

+

Hard cap of 4 billion IGN, halving every two years for ever. The cap stays. After the subsidy, the proving market and fees pay for security. The litepaper has the measured years and the review rule.

diff --git a/site/litepaper.html b/site/litepaper.html index deca0c7ed..24afdf774 100644 --- a/site/litepaper.html +++ b/site/litepaper.html @@ -502,6 +502,16 @@ body.all .pager{display:none}

Where fees go

The base fee of every transaction is burned in full, Ethereum's rule, so a miner cannot fill blocks with its own transactions for free. The priority fee splits two ways: 80% to the miner and provers of that block, 20% to the apps whose code ran, by gas consumed inside each. External proving fees pay 90% to the provers who delivered and burn 10%. The hard cap fixes supply. Emission is untouched by any of this: every coin minted still goes to miners and provers.

+

Security after the subsidy

+

The cap stays at 4 billion. There is no tail emission. Long term, security is paid for by the proving market and by fees. Outside customers buy proofs as dollars-priced work settled in IGN, and 90% of every job goes to the provers who delivered it, so a prover's income does not depend on emission. The table shows the first year in which the block subsidy on its own pays miners less than the power of about 3,000 consumer cards, at three flat prices. The prices are inputs chosen to span two orders of magnitude. The model runs a 300 W card at 124 MH/s on electricity at USD 0.12 per kWh. One rule sits beside the cap. If external proving revenue is under one fifth of the block subsidy over any 90-day window after year 5, the question of a tail reward goes to the miners' signalling vote. The protocol never changes emission by itself.

+
+ + + + + + +
Price per IGNFirst year the subsidy alone pays under the power of 3,000 cardsSubsidy to miners that year
USD 0.005Year 7USD 500,000
USD 0.02Year 11USD 500,000
USD 0.10None in the first 14 yearsUSD 1,250,000 in year 14

No fund, no foundation, no fee to the team

There is no development fund. A switch that routes money to an address somebody controls is the first thing a critic points at, so Igneum has none. The protocol carries no fee to any team, foundation or fund. The team earns in the open: it runs provers in the job market and collects the app share on the contracts it deploys, like anyone else. If the community ever wants a grant mechanism, miners can add one by signalling.