From 679ad86fd786d311eb067d7518cb53de0aeab05e Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Sat, 3 Oct 2026 20:34:43 +0000 Subject: [PATCH] Review: hostile round 3 against the spec and the running fork, 27 ledger entries Seven reviewers (Kaspa core, RandomX author, Ethereum client, GPU farm, chip designer, exchange listing, regulator's analyst), three attacks each against docs/spec, the execution design, the fork code and tonight's devnet. 0 fatal, 18 serious, 8 minor. New ledger entries M14 to M21, F14 to F18, P11 to P15, E9 to E11, C13, L7, L8, G9, G10, X12; one cross-reference on P8. Co-Authored-By: Claude Fable 5.1 --- docs/fud-ledger.md | 251 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 250 insertions(+), 1 deletion(-) diff --git a/docs/fud-ledger.md b/docs/fud-ledger.md index d71b5026..8d113f8c 100644 --- a/docs/fud-ledger.md +++ b/docs/fud-ledger.md @@ -338,7 +338,7 @@ Status: Closed by rule (3 October 2026). Spec section 7.2: sortition keyed to th Answer: Fair, and the lottery/proving separation does not by itself fix it. If claims are first-come, latency wins. The candidate rule is sortition of shards: a VRF keyed to the block assigns each shard to a set of eligible provers, weighted by past proving or by a lottery, with fallback to open claiming after a timeout. This is a phase 1 specification item and a phase 4 devnet measurement. The 20% proving pool is paid per block as a fixed amount divided by consensus proving cost, so a prover's income is bounded by the shards it is assigned, not by how many it can grab. -Evidence: design doc "Proving speed on consumer GPUs" risk item and Finality v2 "Fees". Rule: not yet. +Evidence: design doc "Proving speed on consumer GPUs" risk item and Finality v2 "Fees". Rule: not yet. Cross-reference (round 3, 3 October 2026): F17 reopens the per-key draw of spec 7.2, which a key-splitter sweeps by count. ### P9. Shard griefing "Claim a shard with a small bond and never prove it. Repeat. Finality waits on you." @@ -1032,3 +1032,252 @@ Add one before sharing the litepaper, and point the FUD ledger's submission line 78. LP "What Igneum does not claim" Add three items: "A memory-hard prototype. Not yet: the current dataset can be shortcut 110x; the 256 MB cache replaces it." "Finality in the first month. Not until the 30-day window has history." "A cryptography team. Not yet; external reviewers are named before gate 3." + +--- + +## Round 3 entries (3 October 2026, evening): the specification and the running code + +Added by `docs/review/round-3-2026-10-03.md`, which holds the full argument for each, the reviewer who raised it, and the five to fix first. Entries are placed under their section letters below and numbered on from the last entry of each section. Existing entries are unchanged; where one is extended the new entry says so. Count after this block: 107 entries (80 plus 27). Of the 27: 0 fatal, 18 serious, 9 minor by the review's ranking (M18, M21, P13, P15, C13, L8, G10, X12 and the text half of E11 are the minor ones). + +### M14. A pulsed rental against the block-count DAA buys weight at a discount +"Bring 50x the hashrate for two minutes once an hour. Kaspa's window keeps the 661 most recent samples, so you mine thousands of blocks at the old target before it moves, and when you leave the honest network crawls for hours at your difficulty. Weight is blocks over a window of blocks. You get a third of the window in a week for the price of a 1.6x average." + +Status: Open, experiment scheduled. + +Answer: Correct in mechanism and unmeasured in size. `sim/results_v2.md` runs every scenario with a perfect retarget (its assumption table) and no finality run has a DAA model (O-3.9). Tonight's honest step on the devnet showed the lag: 5.67 blocks a second in a two-minute bucket after the first retarget, 2,248 blocks in eight minutes against 480 expected, and 1.5 blocks a second an hour later (`docs/review/round-3-2026-10-03.md`, "Tonight's devnet"). The review's estimate is that a pulse buys under two windows of blocks (about 5,000) and the chain crawls after each, so the amplifier over the formula is about 2x at the cost of a visible attack; the estimate is not a simulation. The same lag is the farm operator's hop profit (`sim/difficulty/sim.py` profiles `hop3`, `hop10`, `polluted`), for which no result is in the bench-log. Fix in two parts: the controller (gate 2, O-2.1, with the simulation results logged) and the weight rule (F14). + +Evidence: `node1.log` of 3 October 2026 and `sim/difficulty/devnet-2026-10-03.csv`; `sim/results_v2.md` assumptions. Experiment: `finality_v2.py` with the Kaspa DAA and the two-lane candidate in the loop against a 50x pulsed renter, reporting the day it crosses a third; `sim/difficulty/sim.py` results in the bench-log. Review id R3.1. + +### 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. + +Answer: Correct. `validate_header` (`consensus/src/pipeline/header_processor/processor.rs:293` to `301`) runs the isolation checks (timestamp against the future only, `pre_ghostdag_validation.rs:48`), GHOSTDAG, `check_pow_and_calc_block_level`, and only then `pre_pow_validation` with `check_difficulty_and_daa_score`. `epoch_seed` (`processor.rs:325`) reads `header.daa_score`; `day_index` reads `header.timestamp`; `IgneumEngine::KEEP` is 3. `docs/fork-divergence.md` flags the ordering as a GHOSTDAG cost; the cache thrash is the sharper form. Fix: run the DAA-score and past-median checks before the PoW check; derive the day from DAA score (spec 1.12) or from the selected parent's window; `KEEP` 4; a per-peer cap on cache builds. + +Evidence: the files and lines above. Fix: review's first of five. Review id R3.26. + +### M16. The 256 MiB cache fits on a die, so the recompute attacker is compute bound +"Your 4.8x-slower shortcut ran with the cache in DRAM behind a chip that cannot hold it. Put 256 MiB of SRAM on a die and the dataset is never needed: 128 items per hash at about 1,170 integer operations and 8 near-free reads each. That is 150,000 operations per hash, and integer operations per dollar is where silicon beats a GPU." + +Status: Open, experiment scheduled. + +Answer: Correct as arithmetic, unmeasured as a device. From spec 1.8.4 and 1.8.5 an item costs 9 mixer applications of about 130 operations and 8 cache reads; under the proposed 16-load rule a hash derives 128 items. A 5090-class integer budget (about 50 T operations a second, approximate) gives about 0.33 Ghash/s against the honest 141 Mhash/s projection, about 2.4x at equal silicon before any chip-versus-GPU efficiency, and a 256 MiB SRAM is about 250 to 300 mm^2 on a current node (approximate, from wafer-scale parts). The cache size was set to beat a GPU's L2 (spec 1.16), not a die. The lever is the cache size and the mixer cost, both prototype values at gate 1. Monero's precedent does not price this (C13). An FPGA does not reach it (review, chip designer, attack 3). + +Evidence: spec 1.8, 1.16; `proto-metal/MEMHARD.md` 2.2 (Apple only). Experiment: `--inline-dataset` on the RTX 5090 at a 64 MiB cache (inside its 96 MiB L2, the SRAM emulation) and at 256 MiB against the honest 1 GiB kernel; the O-1.6 time-memory curve; a CPU fill and verify time at a 1 GiB cache. Decision at gate 1: cache size "exceeds what one die can hold, and grows". Review ids R3.5 and the chip designer's pricing. + +### 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. + +Answer: Correct for the devnet client. Under the v0 seed rule (the last block of the previous epoch) nobody can compile early and the gap is structural; under the spec's VDF pipeline the seed is known 1,200 DAA seconds ahead (spec 4.3) and an honest client compiles ahead, so the gap is a client defect, not consensus. Fix: in-worker NVRTC and runtime OpenCL compilation (listed in `docs/fork-divergence.md` as open), measured on a mixed rig through 24 epoch changes (O-1.16). Extends M11. + +Evidence: `node1.log` 21:12:14 to 21:13:45; `proto-cuda/windows-miner/start-mining.ps1` (exit 42 handling); bench-log Metal compile figures. Review id R3.7. + +### M18. The per-hash random data path is a one-bit select +"Your `add` picks one of two immediates by a bit of `r0`. A chip computes both and muxes. Calling that a data-dependent path next to ProgPoW is marketing." + +Status: Conceded, wording fix. + +Answer: Correct. Spec 1.4.1: `sel` is `r0` at the top of each iteration and each `add` selects `imm` or `imm2` by one bit of it. It costs a chip nothing and defends nothing; the defence is the random reads. The litepaper's vs RandomX row should drop "random data path" or say what it is. + +Evidence: spec 1.4.1. Fix: `site/litepaper.html` vs RandomX row, "Random program" (review, RandomX author, sentence). Review id R3.8. + +### 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. + +Answer: Correct. The current-generator census is complete (100,000 programs, 94.8% with a redundant load, hash rate tracking distinct loads 56 to 152 per hash at the 1st to 99th percentile); the `fixed16-fresh2` run that fixes the proposed rule's own rejection rate and candidate count is not in the document, and section 1.4.2 of the spec still draws the load count freely. Fix: finish the run, fill the cells, adopt G1 + G2 + R into spec 1.4 with new vectors (spec 1.16 schedules the re-cut), and run ten programs on the 5090 under the new generator. Extends M5 and M6. + +Evidence: `docs/analysis/weak-program-census-2026-10-03.md` sections 7 and 9. Review id R3.6. + +### M20. Pruning proofs are checked with the kHeavyHash stub +"Wait thirty hours, start a fresh node, and watch it reject the honest pruning proof: `validate.rs:192` runs kHeavyHash on headers mined under the lottery, which pass with probability 2^-28. And if you loosen that, I forge levels with an ASIC that already exists." + +Status: Open, acknowledged, fix named. + +Answer: Correct. `consensus/src/processes/pruning_proof/validate.rs:192` calls `calc_block_level_check_pow`, which runs the stub, and `apply.rs` and `mod.rs` call `calc_block_level` the same way; `docs/fork-divergence.md` records that seeds must be threaded through pruning-proof validation before a pruning network. The devnet will pass its pruning depth (108,000 blocks, sooner after tonight's overshoot) and a fresh node will show it. Fix: derive the epoch and day for proof headers from the proof's own headers (fork map a4, O-2.5) and remove the stub from the proof path. + +Evidence: the files above. Test: sync a fresh node from the 30-hour devnet. Review id R3.3. + +### M21. GHOSTDAG k is Kaspa's table value for Kaspa-sized bodies +"k = 18 assumes a 5-second delay bound measured with Kaspa's blocks. Yours carry EVM transactions and recursive proof records." + +Status: Open, extends O-2.2. + +Answer: Correct. Spec 2.1 takes k, max parents and the mergeset limit from Kaspa's table at 1 BPS. O-2.2's two-miner devnet measures the parallel and red rate; it should run with proof-bearing bodies of the size section 5.4 of the execution design implies, and k should be re-derived from the measured delay. + +Evidence: spec 2.1; `docs/design/execution-layer.md` 5.4. Review id R3.4. + +### 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: Open, rule change proposed. + +Answer: Correct; this is the finality half of M14. Spec W2 counts blue blocks over a window of 2,592,000 DAA seconds, and DAA seconds are blocks, so a burst both inflates a key's count and ages the window. Proposed change: denominate the vote window (W2) and the presence window (Q1) in past-median time, and define weight as a key's share of the blue blocks in each 60-second median-time bucket summed over the trailing 30 days, so 50x the blocks in one minute is one minute of weight. The simulation of M14 decides. + +Evidence: spec 3.1 W2, 3.3 Q1; `sim/results_v2.md` assumptions. Experiment: the M14 run under both definitions. Review id R3.1. + +### F15. Merge depth is not the reorg bound; the finality depth is +"You tell exchanges that in month one the one-hour merge-depth bound limits a reorganisation. `check_bounded_merge_depth` only forbids merging an old red. The virtual switches to any heavier chain until the finality point, which you kept at 12 hours." + +Status: Open, text and rule fix named. + +Answer: Correct on reading the fork. `post_pow_validation.rs:79` bounds which reds a block may merge; the selected-chain switch is bounded by the finality point (`virtual_processor/processor.rs:1626`, `FINALITY_DURATION` 43,200 DAA seconds). So the month-one reorg bound is 12 hours of DAA time, not one hour, and spec 3.8, 3.9, litepaper "Finality" and "What Igneum does not claim" item 4 rest on the wrong constant. Fix: state the finality depth as the bound, in median time (M14 explains why not DAA time), or lower `FINALITY_DURATION` and accept Kaspa's finality-conflict handling at that depth; test with a heavier private chain forked 2, 6 and 13 hours back on simnet. + +Evidence: the files above. Review id R3.2. + +### F16. A lock can become uncertified after a heal +"Section 3.5: two certificates at one index, strike the equivocators, re-evaluate, and if neither or both still lock the index is uncertified. So the lock my node reported and I credited on is revocable." + +Status: Open, decision at gate 3 (extends O-3.6). + +Answer: Correct as the proposal stands. For an exchange "locked" must be irrevocable or it is a confirmation count. The alternative is Kaspa's: a verified certificate is never re-evaluated; two certificates at one index are a chain split that halts `finality_active` until an operator intervenes, and the node never reports a lock it may withdraw. Equivocation costing history and not coins (F6) means the attacker who caused the split keeps the deposit either way. Decision at gate 3; the devnet partition-and-heal test of O-3.6 measures whichever rule is chosen. + +Evidence: spec 3.5, 3.9. Review id R3.17. + +### F17. Keys are free and the official client mints eight per card +"Your launcher runs 8 identities per vendor, each with its own vote key. For the vote that is harmless by design. For shard sortition, which ranks every eligible key and takes 8, it is the whole game: 1% of hashrate holds 259 keys above dust. And a few thousand PCs cross your 8,192-voter switch, whose construction is open." + +Status: Open, rule change proposed. Reopens P8. + +Answer: Correct. Spec 7.2 step 2 ranks per key and eligibility is 100 blue blocks in 30 days (0.004% of hashrate at one block a second), so a miner with share s holds up to s x 2,592,000 / 100 keys and the draw of 8 is dominated by whoever splits most. `proto-cuda/windows-miner/start-mining.ps1` derives a key per identity (`MINERS` default 8). O-5.1's acceptance test (fastest prover under 25% of shards) does not catch a splitter, who wins by count. Fix: draw the 8 assignees by weight (8 blue blocks uniformly from the window, take their keys), so splitting changes nothing; the client defaults to one key per operator; specify S2 (O-3.5) and the bitmap size (O-3.12) before the count can cross 8,192. + +Evidence: spec 7.2, 3.4; the launcher. Cross-reference added to P8. Review id R3.14. + +### F18. "A silent minority cannot freeze finality" is false under the floor +"Your own simulation: 45% silent stalls finality for as long as they stay silent, 40% gives 138 stalls in three days, 50% churn stalls 4.1 days. The litepaper says a silent minority cannot freeze it and a lock never waits for miners who have left." + +Status: Conceded, not yet stated; text fix named. + +Answer: Correct. The sentence was true of the active-only rule and was not updated when the 56.7% floor was added (spec 3.3.1 states the liveness cost honestly: liveness ends between 40% and 45% silent). Fix: the replacement sentence in the review (exchange engineer, sentence), and a line in "What Igneum does not claim". + +Evidence: `sim/results_v2.md` C and D; spec 3.3.1; `site/litepaper.html` Finality. Review id R3.18. + +### P11. The native-execution veto makes block validity depend on the node's current selected chain +"Section 5.5: a block is invalid if a proof record names a segment not on the node's selected chain, or disagrees with the node's own execution. Two honest nodes with different tips disagree on the same block. You removed the hidden-block penalty for this exact reason." + +Status: Open, text fix named. + +Answer: Correct. `docs/design/execution-layer.md` 5.5 (D12) and spec 7.2 item 5 reference the node's selected chain, which is a property of its virtual, not of the block's past. Fix: a proof record is valid if the chain block it names is on the carrying block's own selected-parent chain and its `post_root` and receipts equal the execution of that segment along that chain, which every node computes from the block's past. Add a two-node reorg test to section 8.5. + +Evidence: the two sections. Review id R3.9. + +### P12. An aggregator can name itself as every prover +"`ProofRecord.provers` is who is paid and nothing in a shard proof's statement says who proved it. I aggregate eight gossiped shard proofs and write my key eight times." + +Status: Open, format fix named. + +Answer: Correct. Section 5.1's shard statement (pre-root, transactions, post-root, receipts) and the `ProofSystem` trait of 5.6 carry no prover identity; 4.4 credits the pool to the record's `provers`. Fix: each shard proof's public input includes the prover's payout key, aggregation carries the keys as public outputs, and a record whose list does not match them is invalid; acceptance test A5 checks the match, not only the credit. + +Evidence: `docs/design/execution-layer.md` 5.1, 5.4, 5.6, 9.2 A5. Review id R3.10. + +### P13. The litepaper still claims shards with a bond +"'Miners claim shards with a small bond.' Your spec 7.2 decided sortition with no bond the same day." + +Status: Conceded, fix now. + +Answer: Correct. Fix: "Shards are assigned by lot to eight provers for ten seconds, then open to anyone; there is no bond." (`site/litepaper.html`, Proving, "How a block gets proven".) + +Evidence: spec 7.2. Review id R3.13. + +### P14. Two definitions of the proving base fee, and a quote that cannot know the ratio +"Spec 5.1 adjusts `f_p` from the unproven backlog smoothed over the difficulty window; design 4.1 adjusts it EIP-1559 style toward `B_p / 2`. And `eth_gasPrice` has no calldata, so your fold returns an average and a modexp-heavy transaction reverts on the budget and pays for it." + +Status: Open, decision named. + +Answer: Correct on both. Fix: one controller definition in both files; `eth_gasPrice` documented as a network-average fold with `eth_estimateGas` (which has the calldata) returning the limit that covers both charges; and the R1 band measurement (pgas / gas inside 0.1 to 10 for 95% of ethereum/tests) as the evidence that the average is usually close. R8 and R11 remain the experiments. + +Evidence: spec 5.1; `docs/design/execution-layer.md` 4.1, 4.3, 9.1. Review id R3.11. + +### P15. RPC blocks are segments, so `gasUsed` can exceed `gasLimit` +"A segment holds up to 180 blocks and your RPC block is the segment. Indexers assert `gasUsed <= gasLimit`." + +Status: Open, minor, extends R10. + +Answer: Correct; spec 7.1 states that a segment's total can exceed `gaslimit`. Fix: report the segment's limit as `k x B_e` in the RPC block, or document the invariant break for Blockscout (R10). + +Evidence: spec 7.1; `docs/design/execution-layer.md` 8.2. Review id R3.12. + +### E9. The specification's year is 365 days; the code's is 365.25 +"Spec 2.5: 31,536,000 DAA seconds a year, halving every 63,072,000, about 31.7098 IGN a second. `igneum.rs`: 31,557,600, 63,115,200, 31.688 IGN. Which one is the money?" + +Status: Open, decision now. + +Answer: Correct. `consensus/core/src/igneum.rs` (`SECONDS_PER_YEAR = 31_557_600`, `HALVING_INTERVAL_SECONDS = 63_115_200`, `BASE_SUBSIDY_PER_SECOND_SOMPI = 3_168_808_781`) and spec 2.5 disagree; `docs/fork-divergence.md`'s per-second table follows the code. Fix: pick one (the code's values are tested and summed under the cap) and rewrite spec 2.5 and the litepaper's schedule to match, with a test that asserts the published numbers against the code. + +Evidence: the two files. Review id R3.19. + +### E10. Reds are paid in the code and "more blocks never means more coins" is false +"Spec 2.5: red blocks are unpaid, emission is keyed to DAA score so more blocks never means more coins. `coinbase.rs` pays a red's 80% to the merging miner and its 20% to the pool, and every blue block in the DAA window mints `E(daa)`. Tonight your chain minted 4.7x the schedule for eight minutes." + +Status: Conceded, text fix named. + +Answer: Correct. `consensus/src/processes/coinbase.rs:102` to `109` follows Kaspa's rule for reds; `block_subsidy` is paid per blue (and red) block in the DAA window, so coins are blocks times `E` and the controller's rate sets the short-run emission, as on every proof-of-work chain. Timestamps still cannot mint. Fix: spec 2.5 to say what the code does (reds paid to the merger, emission per block under the controller's rate, the cap unaffected), or the code to say what the spec does; the review recommends the code's rule. + +Evidence: the files; `docs/review/round-3-2026-10-03.md`, "Tonight's devnet". Review id R3.20. + +### E11. The homepage burns job fees at launch +"'Jobs through Igneum's own market are paid in IGN and 10% of each fee is burned', with a tile 'IGN burned from jobs, at launch'. Your spec 5.4 settles launch jobs on the customer's chain with no burn. You fixed the litepaper (P10) and left the homepage." + +Status: Conceded, fix now. + +Answer: Correct. Fix: `site/index.html`, "Proofs sold to other chains": "Jobs are paid on the customer's chain at launch; settlement in IGN with a 10% burn follows the proof bridge in phase two", and the tile's label to "phase two". Extends P10 and overclaim 52. + +Evidence: spec 5.4; `site/index.html`. Review id R3.24. + +### C13. Monero's seven years do not price a 256 MiB SRAM die +"RandomX's cache is 256 MiB too. Nobody built the die for Monero because the prize was small. That is not evidence about the die." + +Status: Conceded, label needed; extends C2. + +Answer: Correct. The precedent argument transfers the cache size and not the economics; see M16 for the pricing and the lever. + +Evidence: none beyond M16. Review id R3.16. + +### L7. "Where the price comes from" +"A heading in a document that says it is not an offer, followed by 'both reduce supply as they happen'. That is a value-accrual argument under a heading about price." + +Status: Open, counsel; text fix now. + +Answer: Correct as a reading. Fix: the heading becomes "Where fees go" and the sentence "Demand comes from use of the chain and from outsiders buying proofs, and both reduce supply as they happen" is deleted; counsel reviews the Economics section (L1, L2). + +Evidence: `site/litepaper.html`, Economics. Review id R3.23. + +### L8. Third-party names as implied outcomes +"'Native USDC is requested from Circle during public testnet.' 'Canto and Blast proved builders come for this.' Names of companies next to outcomes you do not control." + +Status: Conceded, wording fix. + +Answer: Correct. Fix: "The project will ask Circle for native USDC during public testnet; whether it is issued is Circle's decision" and the Canto and Blast sentence as overclaim 39 already rewrites it. + +Evidence: `site/litepaper.html`, Building, Questions builders ask. Review id R3.25. + +### G9. The release-key steward is one person, and a lost key cannot be revoked +"Spec 8.2: the key that signs the software every miner runs is held by 'the steward named in the published key policy', policy deferred to testnet. And item 5 says a lost key is revoked by its own last signed release, which a lost key cannot sign." + +Status: Open, policy and rule fix named; extends O-8.1. + +Answer: Correct on both. The steward is the control point a regulator writes down, and the revocation path as written freezes the update channel for ever on a lost key. Fix: a pre-signed revocation certificate held apart from the signing key, or a 2-of-3 key set with the policy published before the client ships rather than before testnet; and the entity and jurisdiction that employ the steward named with it (L1). + +Evidence: spec 8.2. Review id R3.21. + +### G10. The signalling default on first run +"8.3 says the default is the choice the user last made. On first run there is none." + +Status: Open, minor. + +Answer: Correct. Fix: first run signals nothing until the user chooses, shown in the interface. + +Evidence: spec 8.3 item 2. Review id R3.22. + +### X12. Tonight's numbers are quoted before they are logged, and the worker efficiency gap is unexplained +"The 50x step, the trough near 9 million, 5.5 blocks a second and two-thirds efficiency over eight processes are in the brief and not in the bench-log. And the chain saw 70 to 83 MH/s from a card that benches 229, which is a third, not two thirds." + +Status: Conceded, fix now. + +Answer: Correct. The bench-log is append-only and the project's rule is that a number exists when it is logged with its command. Tonight's run needs its entry: the step profile, the retarget trajectory from the CSV (134.2 M to 14.2 M expected hashes by DAA 812, further per the brief), the 2-minute block-rate buckets, the epoch-boundary gap, and the launcher's summed status against the block rate, with the gap explained (template age, sibling blocks dropped by the one-block-per-job rule, or queue stalls across eight processes). + +Evidence: `/tmp/igneum-devnet/node1.log`, `sim/difficulty/devnet-2026-10-03.csv`, the launcher log on the PC. Review id R3.15.