diff --git a/app/igneum-wallet/ui/app.js b/app/igneum-wallet/ui/app.js index 8712fca48..4fef2063a 100644 --- a/app/igneum-wallet/ui/app.js +++ b/app/igneum-wallet/ui/app.js @@ -144,6 +144,8 @@ var View = (function () { // section 9 of docs/spec/finality-guarantees.md: a block under a locked checkpoint is finalised even while the network's // finality is paused; the pause is the network's word, never a transaction's case 'finality not active': return { word: 'finalised', tone: 'ink', why: 'under a locked checkpoint, not yet verified here; finality is paused on the network above it' }; + // review B F04: a recovery lock is labelled "recovery", never plain "final" (the node lane's lockKind word) + case 'finalised by a recovery lock': return { word: 'finalised (recovery lock)', tone: 'ink', why: 'under a recovery lock: the surviving majority’s lock after a long pause, not a certified checkpoint; not yet verified here' }; case 'unknown': return { word: 'pending', tone: '', why: 'not in any block the node holds' }; } if (e.finality === 'in_block') return { word: 'included', tone: '', why: 'in ' + blk }; diff --git a/app/igneum-wallet/ui/view.test.mjs b/app/igneum-wallet/ui/view.test.mjs index f8d71f8d2..6e9d453bc 100644 --- a/app/igneum-wallet/ui/view.test.mjs +++ b/app/igneum-wallet/ui/view.test.mjs @@ -107,6 +107,10 @@ test('one state word per row: the wallet\'s verified final wins, failed from the // the network's finality is paused; the pause is the network's state word, never a transaction's. Known-failed first: the // node's "finality not active" word was shown on the row. assert.deepEqual(V.stateWord(e, 'finality not active'), { word: 'finalised', tone: 'ink', why: 'under a locked checkpoint, not yet verified here; finality is paused on the network above it' }); + // review B F04 (the founder, 8 October 2026): a recovery lock is labelled "recovery", never plain "final": the node's word + // for a transaction under one (the node lane's lockKind) reads on the row as finalised by a recovery lock. Known-failed + // first: the word fell through to the label. + assert.deepEqual(V.stateWord(e, 'finalised by a recovery lock'), { word: 'finalised (recovery lock)', tone: 'ink', why: 'under a recovery lock: the surviving majority’s lock after a long pause, not a certified checkpoint; not yet verified here' }); assert.equal(V.stateWord(e, 'unknown').word, 'pending'); // no node word yet (the public RPC, or not asked): the wallet's label assert.deepEqual(V.stateWord(e, ''), { word: 'included', tone: '', why: 'in block 140,262' }); @@ -117,8 +121,8 @@ test('one state word per row: the wallet\'s verified final wins, failed from the assert.deepEqual(V.stateWord(r, ''), { word: 'executed', tone: 'ink', why: 'in block 140,201' }); assert.equal(V.stateWord(entry({ hash: 'proving-1-0', kind: 'proving', finality: 'final', checkpoint: 9 }), '').word, 'finalised'); // never a stronger word than the chain's: the words the row can show are exactly the node's plus failed - const words = new Set(['pending', 'included', 'executed', 'proven', 'finalised', 'failed']); - for (const w of ['pending', 'included', 'executed', 'proven', 'finalised', 'finality not active', 'unknown', '']) assert.ok(words.has(V.stateWord(e, w).word), w); + const words = new Set(['pending', 'included', 'executed', 'proven', 'finalised', 'finalised (recovery lock)', 'failed']); + for (const w of ['pending', 'included', 'executed', 'proven', 'finalised', 'finality not active', 'finalised by a recovery lock', 'unknown', '']) assert.ok(words.has(V.stateWord(e, w).word), w); }); test('the row model: kind word, who, sign, amount, the rows that need the node\'s word', () => { diff --git a/docs/analysis/class-v6/amd-intel-energy.md b/docs/analysis/class-v6/amd-intel-energy.md new file mode 100644 index 000000000..431e2db5b --- /dev/null +++ b/docs/analysis/class-v6/amd-intel-energy.md @@ -0,0 +1,280 @@ +# AMD and Intel energy on class v6: why the measured cards pay 3x to 6x a Blackwell card per hash, and what a kernel can change + +8 October 2026, written 19:4x to 20:3x UK, the AMD-and-Intel energy lane. Register rows: GPU-03 (the 64-register +window's real cost) in its AMD and Intel cells; ECO-05's named cause (`docs/analysis/class-v6/eco-05-results.md` on +counter-asic-4: "the measured RX 9070 XT (7.9 microjoules at its knee), the RX 7600 (6.2 estimated, 8.1 measured at stock) +and the Arc B580 (10.4, watts estimated) cost 4x to 6x a Blackwell card per joule"); the P02 cohort's AMD and Intel cells. +The one acceptance rule is P03: a change must cost the honest card no more than 5 percent per accepted work against the +paired baseline (and no more than 2 percent of accepted throughput) and must not help the adversary. + +**Labels.** Every number carries one: **measured** (an instrument read it; the instrument is named), **modelled** +(arithmetic on labelled inputs, or an offline compiler's report standing in for the driver's), **estimated** (no +instrument behind it), **team-reported** (read by a person, not a job). Vendor and JEDEC figures are marked +approximate. No row here is a wall reading: neither PC has a wall meter, so every watt is the device's own telemetry +(ADLX `GPUPower` on AMD, `nvidia-smi power.draw` on NVIDIA, the Level Zero sysman energy counter on Intel, IOReport on +Apple), and none meets P02's calibrated 2 percent wall meter. **Efficiency kind** (review B's rule, main's order 8 October +2026): every efficiency row says which of two things it is, and the two are never mixed: **KT**, kernel throughput (the +worker's `--bench-pack` or `--memprobe`, device event time, no pool, no shares) against device-reported watts; **SV**, the +serving hash rate (the installed app's own `hash_now` for the card while it mines) against device-reported watts. No row +here is the third kind, **end-to-end accepted work per wall joule in serving mode**: that needs accepted shares and a wall +meter, and is owed (section 4.3). Nothing was built or run on the Mac: the offline compiles +ran on igneum-build-1 (LLVM 18.1.3), the jobs on PC 1 and PC 2 through the signed jobs queue. + +## 0. The answer in one paragraph + +On this hash every card runs at 87 to 100 percent of its own dependent random-read ceiling divided by 128 (the unit of +work is 128 dependent random 4-byte reads), so joules per hash = 128 x watts / random reads per second. Normalised per +32 bits of memory bus, the AMD and Intel cards burn about what the RTX 5090 burns (18 to 19 W per 32 bits at their +knees; the RX 7600 28 W at stock) but complete 0.21x to 0.47x its random reads per second (the 5090 1.08 G/s per 32 +bits; the 9070 XT 0.30; the 7600 0.44 to 0.51; the B580 0.23). That ratio is the whole gap: 3.4x for the 9070 XT, 3.1x +to 3.5x for the 7600, 4.4x for the B580 against the 5090's floor, and 3.8x to 6.1x against the 5080 and the 5070 Ti, +which is ECO-05's "4x to 6x". It sits in the memory system's random-access rate (GDDR7's four channels per device +against GDDR6's two, and a per-channel rate that varies 2.2x between the three GDDR6 cards), not in the kernel: the +ALU work is about 5 percent of an AMD card's joules, occupancy is 3x to 6x above what saturates the DRAM, the +64-register window costs the RX 7600 and the Arc B580 no rate per unit of work (0 and -0.3 percent, measured), and a 16-byte read costs what a 4-byte read costs on every +card measured. The kernel changes that keep every hash identical are worth 0 to about 10 percent on AMD, ranked in +section 3; none closes the gap, and the one hash change that does (64-byte reads) halves the 5090 and fails P03. +The levers that move ECO-05 tonight are the AMD operating point below the driver's floor (a baseline, not a candidate) +and the RX 7600's metered knee (a PC 1 job queued at landing; section 4), which ECO-05 says adds sustainable worlds +at 0.03 and 0.10 if it reads under 5 microjoules (modelled tonight at 5.0 to 5.4). + +## 1. The measured rows as they stand, with their instruments + +### 1.1 Rate and watts + +| Card | Class / point | MH/s (rate instrument) | Watts (watts instrument) | Microjoules per hash | Label | Kind | Source | +|---|---|---|---|---|---|---|---| +| RX 9070 XT (gfx1201, 16 GB GDDR6, 256-bit, PC 1 eGPU) | class v2, stock, app mining | 17.73 (the app's hash_now, mean of 24) | 198.9 (ADLX GPUPower, 12 samples, 193 to 212) | 11.2 | measured | SV | docs/bench-log.md, 5 Oct, job tele-measure-1 | +| RX 9070 XT | class v5, stock (grid point 0/0) | 18.9 (the app's hash_now, median over a 75 s hold) | 202 (ADLX GPUPower, mean after a 30 s settle) | 10.7 | measured | SV | the ADLX grid, 8 Oct 12:13, `relay/playbooks/ca3-pc1-amd-grid.ps1`; floor/denominator.md | +| RX 9070 XT | class v5, gmax -500 MHz, plimit -30 percent (the driver's floor; the grid's best of 24) | 18.9 to 19.0 (same) | 149.3 (same) | 7.9 | measured | KT | same | +| RX 7600 (gfx1102, 8 GB GDDR6, 128-bit, PC 1) | class v4 sub-version 3, stock | 13.88 (card-in job, worker bench) | 113 (ADLX, card-in job) | 8.14 | measured | KT | floor/denominator.md, 15:50 UK | +| RX 7600 | class v6 hl-v6-foldrw (the partner), stock, quiet | 15.79 (worker --bench-pack) | none | | measured rate only | KT | hash lane, 18:3x UK | +| RX 7600 | class v6 hl-v6-all (window + fold + rw; 256 loads per hash = two units of work), stock, quiet | 7.92 = **15.84 per unit of work** | none | | measured rate only | KT | hash lane, 18:3x UK | +| RX 7600 | class v6 sizes 1 / 2 / 4 / 5.5 GiB | 15.75 / 15.46 / 15.34 / 15.35 | none | | measured rate only | KT | reference-population.md section 6 | +| RX 7600 | class v6 at stock with the class v4 run's 113 W | 15.79 | 113 (a different class's reading) | **7.2** | modelled | KT (modelled) | this file | +| RX 7600 | knee | 13.9 | 86 (the 9070 XT's 24 percent applied) | 6.19 | estimated | KT (modelled) | reference-population.md | +| Arc B580 (12 GB GDDR6, 192-bit, PC 2 eGPU and a PC 1 slot) | class v4, stock | 10.6 to 11.0 (worker bench) | about 110 (the board's class) | 10.4 | measured rate, estimated watts | KT | floor/denominator.md; the Intel lane, 7 Oct | +| Arc B580 (PC 2, enclosure) | class v6 hl-v6-foldrw, stock, quiet (SIMD32, sub-group shuffle exchange) | 11.008 (worker --bench-pack, 60 dispatches of 2^24, device time) | not read: the Level Zero energy counter answered ZE_RESULT_ERROR_UNSUPPORTED_FEATURE (0x78000003) on all three power domains, unelevated, driver 32.0.101.6733 | | measured rate only | KT | job run-ae-pc2-b580-energy-20261008, 18:52Z | +| Arc B580 | class v6 hl-v6-all, stock, quiet (the compiler drops to SIMD16: sub-group 16, local-memory exchange with barriers) | 5.489 = **10.98 per unit of work** | not read (same) | | measured rate only | KT | same, 18:54Z | +| Arc B580 | class v6 at stock with the board-class watts | 11.0 | about 110 | 10.0 | measured rate, estimated watts | KT | this file | +| RTX 5090 (32 GB GDDR7, 512-bit, PC 1) | class v5, the 1,300 MHz lock | 134.8 (worker) | 314 (nvidia-smi; 2.33 x 134.8) | 2.33 | measured | KT | reference-population.md (PC 1, tiers file) | +| RTX 5080 (16 GB GDDR7, 256-bit) | class v5, 1,100 MHz | 71.2 | 146.6 | 2.06 | measured (rented) | KT | reference-population.md | +| RTX 5070 Ti (16 GB GDDR7, 256-bit) | class v5 knee | 77.0 | 131 | 1.70 | stock measured (rented), knee modelled | KT | reference-population.md | +| Apple M5 Max (36 GB LPDDR5X) | class v4 | 26.67 | 37.3 (IOReport GPU and DRAM channels) | 1.40 | measured | KT | floor/denominator.md | + +Tonight's jobs (section 4.1) added the B580's class v6 rows; its watts could not be read unelevated. The RX 7600's metered +class v6 rows (ADLX at stock and two knob points) are owed to a PC 1 job still queued at landing. + +### 1.2 The random-read ceiling (the instrument that explains the rows) + +`igneum-worker-opencl --memprobe` (proto-opencl/host.c): dependent random 4-byte loads over a buffer, device event +time, best over lanes in flight; `chase` is one dependent load per step per lane. + +| Card | Ceiling at 1024 MiB, G loads/s | Hash-implied (MH/s x 128) | Hash / ceiling | 64-byte read against 4-byte | Label | Source | +|---|---|---|---|---|---|---| +| RTX 5090 | 17.5 to 18.2 (card off in the app, CUDA) | 17.25 | 0.96 | 0.52x to 0.86x (two 32-byte sectors; bandwidth-bound at 584 GB/s) | measured | bench-log, read-width entry, 5 Oct | +| RX 9070 XT | 2.42 to 2.66 (4,096 lanes already saturate it; eight independent chains per lane give the same) | 2.42 | 0.87 to 0.95 | 1.0x (2.47 to 2.87: the line is fetched either way) | measured | bench-log, 5 Oct | +| RX 7600 | owed (the PC 1 job of section 4.1) | 2.02 (class v6) | | | hash-implied, modelled | | +| Arc B580 | 1.407 to 1.409 (4,096 lanes and up; eight independent chains per lane 1.41, the same); at 256 MiB 1.55 to 1.57 | 1.409 (class v6) | 1.00 | not probed | measured | job run-ae-pc2-b580-energy-20261008 (tonight); the Intel lane 7 Oct read 1.41 | +| Apple M5 Max | 3.50 | 3.47 | 1.0 | 1.0x | measured | bench-log, 5 Oct | + +## 2. The decomposition + +### 2.1 The identity + +The unit of work is 128 dependent random 4-byte dataset reads (program.json of both class v6 packs: +`loads_per_hash` 128, `load_width_counts_4_16_64` [16, 0, 0], `bytes_per_hash` 512; hl-v6-all does two units per hash). +Every card above runs at 0.87 to 1.0 of its probe ceiling / 128 (table 1.2), so: + +microjoules per unit = 128 x P / A, with P the card's watts at its operating point and A its random reads per second. + +Splitting both by the memory bus (32-bit units: the 5090 16, the 9070 XT 8, the 7600 4, the B580 6, the 5080 and 5070 Ti +8; vendor figures, approximate): + +| Card | A per 32 bits (G reads/s) | P per 32 bits (W) | Nanojoules per random read (P / A) | Microjoules per hash | Against the 5090: watts ratio x reads ratio = joules ratio | Label | +|---|---|---|---|---|---|---| +| RTX 5090 at the lock | 1.08 | 19.6 | 18.2 | 2.33 | 1 | A measured, P measured | +| RTX 5080 at 1,100 MHz | 1.14 | 18.3 | 16.1 | 2.06 | 0.94 x 0.95 = 0.88 | measured (rented) | +| RX 9070 XT at the floor point | 0.30 | 18.7 | 61.7 | 7.9 | 0.95 x 3.6 = 3.4 | measured | +| RX 9070 XT at stock | 0.30 | 25.3 | 84 | 10.7 | 1.29 x 3.6 = 4.6 | measured | +| RX 7600 at stock, class v4 run | 0.44 | 28.3 | 63.5 | 8.14 | 1.44 x 2.4 = 3.5 | measured | +| RX 7600 at stock, class v6 rate | 0.51 | 28.3 | 56 | 7.2 | 1.44 x 2.1 = 3.1 | modelled (watts from the v4 run) | +| Arc B580 at stock | 0.23 | 18.3 | 78 to 80 | 10.4 | 0.93 x 4.7 = 4.4 | A measured, P estimated | +| Apple M5 Max (for contrast) | 0.22 | 2.3 | 10.7 | 1.40 | 0.12 x 4.9 = 0.60 | measured | + +Reading: at their knees the AMD and Intel cards spend about the same watts per 32 bits of memory bus as the 5090 +(0.93x to 0.95x; the 7600 at stock and the 9070 XT at stock 1.3x to 1.4x because nothing has been taken off them), and +the whole 3x to 4.5x is the random-read rate per 32 bits. Against the 5080 and the 5070 Ti (1.70 to 2.06) the same rows +read 3.8x to 6.1x, which is the "4x to 6x" of ECO-05. The Mac shows the other way out: a memory system with a quarter of +the 5090's random-read rate per bus width wins on joules because it spends an eighth of the watts per bus width. + +### 2.2 The random-read rate per 32 bits: where the 3.6x lives + +| Factor | 5090 against the 9070 XT | Label | +|---|---|---| +| Channels per 32-bit device: GDDR7 four, GDDR6 two | 2x | JEDEC device organisation, approximate | +| Random reads per channel per second: 5090 about 270 M, 9070 XT about 150 M (the per-channel figure of floor/denominator.md) | 1.8x | modelled from the measured ceilings and the channel counts | +| Product | 3.6x | matches the measured 1.08 / 0.30 | + +Within GDDR6 the per-channel rate varies 2.2x on the same DRAM family: the RX 7600 about 220 to 250 M per channel per +second (8 channels; hash-implied, modelled), the 9070 XT about 150 M (16 channels; measured ceiling), the B580 about 115 +M (12 channels; measured ceiling). The 7600's rate says GDDR6 itself allows 1.5x to 2.2x more random reads per channel +than the 9070 XT and the B580 obtain, so part of their deficit sits above the DRAM, in the memory controller, the fabric, +the last-level cache path or address translation. That part is the only piece of the gap that software might reach +(section 3, candidate 2); the GDDR7 against GDDR6 part is hardware. Tonight's B580 probe bounds the translation share +on Xe2: its ceiling is 1.55 to 1.57 G/s at 256 MiB and 1.41 at 1024 MiB (measured), both far beyond its 18 MB L2, so +the footprint (page reach) costs it about 10 percent and the other 90 percent of its per-channel shortfall is the memory +controller and fabric's. + +Bandwidth is not the bound on the AMD and Intel cards: the 9070 XT moves 2.42 G x 64 bytes = 155 GB/s, 24 percent of its +640 GB/s rating, and a 64-byte read costs it exactly what a 4-byte read costs (measured); the bound is the rate of random +accesses, each opening a DRAM row. The 5090 at 64 bytes is the opposite case (it becomes bandwidth-bound and halves). + +### 2.3 The kernel's memory path on RDNA 3, RDNA 4 and Xe2 + +Instrument: the class v6 OpenCL texts (`kernel.cl` of hl-v6-all, id 0x9d40978601a7df2a, and hl-v6-foldrw, id +0x605d06cabc489f94, from build-1 `/srv/artefacts/packs/`) compiled offline with clang 18.1.3 for amdgcn-amd-amdhsa, +-O3, OpenCL C 1.2, `IGNEUM_EXCHANGE 0` (the local-memory path the driver takes on the 9070 XT), the work-item and +rotate built-ins shimmed to the target's own built-ins (no libclc on the box). The driver's compiler is AMD's own LLVM +(the PAL,LC stack) of a different version, so these are **modelled** stand-ins for the driver's binary; the driver's own +numbers come from the host's kernel line (private memory, local memory, sub-group) and, for the 9070 XT, the 5 October +measurement (wave32, private memory 0). + +| Quantity | hl-v6-all, gfx1102 | hl-v6-all, gfx1201 | hl-v6-foldrw, gfx1102 | hl-v6-foldrw, gfx1201 | Label | +|---|---|---|---|---|---| +| Wave size | 32 | 32 | 32 | 32 | modelled; the driver reports wave32 on gfx1201 (measured, 5 Oct) | +| VGPRs | 160 | 160 | 96 | 96 | modelled | +| Waves per SIMD (LLVM 18's model) | 6 | 6 (LLVM 18 models 1,024 VGPRs for gfx1201; its gfx1100 model gives 9 at 156) | 10 | 10 | modelled | +| Spills (scratch bytes) | 0 | 0 | 0 | 0 | modelled; the driver reports private memory 0 on the 9070 XT (measured, class v2) | +| LDS per work-group | 256 B (the exchange's two buffers) | 256 B | 256 B | 256 B | modelled | +| Barriers emitted | 0 (work-group = one wave32: elided) | 0 | 0 | 0 | modelled; matches WAVEFRONT.md's measured "barriers elided" | +| Global loads in the loop body | 32 x global_load_b32 | 32 | 16 x global_load_b32 | 16 | modelled | +| Loads with a full wait right after them | all 32 (51 vmcnt(0) waits) | all 32 | 13 of 16 (three overlap) | | modelled | +| Hash-kernel code size | 33.6 KB | 34.0 KB | 6.3 KB | 6.6 KB | modelled | +| Integer multiplies (mul_lo, mad, mul_hi) per body | 99 | 99 | 67 | 67 | modelled | + +The five questions the brief asks, answered on these numbers: + +1. **Wave size.** Wave32 on RDNA 3 and 4 (the compiler's choice and the driver's report); a work-group of 32 is one wave, + so the local-memory exchange compiles to LDS writes and reads with no barrier. The exchange path and the work-group + shape cost nothing on the 9070 XT (`--group-warps 1, 2, 4, 8` = 18.02 to 18.07 MH/s, measured 5 Oct). Xe2: the + kernel takes the khr or Intel sub-group shuffle only at a queried sub-group of exactly 32; the Arc's sub-group and + SIMD width under the 64-register window, measured tonight on the B580 (the host's kernel line, job + run-ae-pc2-b580-energy-20261008): the partner hl-v6-foldrw compiles at sub-group 32 and takes `sub_group_shuffle_xor`; + the window pack hl-v6-all drops to sub-group 16 (SIMD16, the Intel compiler's answer to 64 live registers), so the + host takes the local-memory exchange with barriers (256 bytes); private memory 0 in both (no spill). The cost of that + drop: none in rate (10.98 MH/s per unit of work against 11.01, -0.3 percent, measured), because the card is at 100 + percent of its random-read ceiling either way. +2. **The 16-byte read's coalescing.** Class v6 reads 4 bytes per load (program.json above); there is no 16-byte read in + the frozen object. The read-width experiment's 16-byte loads (w16) cost every card what 4 bytes cost (5090 139.8 + against 136.1 MH/s, 9070 XT 17.90 against 18.15, measured 5 Oct): a lane's random read fetches a whole line (64 bytes + on AMD and Apple, a 32-byte sector on NVIDIA) and the 32 lanes of a wave hit 32 different lines (a 1 GiB dataset has + 16.8 M 64-byte lines; two lanes of a wave share one with probability about 3 x 10^-5), so there is nothing to + coalesce. +3. **LDS use.** 256 bytes per wave, only the exchange: 8 exchanges per iteration in the body of hl-v6-all, 4 in + hl-v6-foldrw, plus 13 per shadow pass x 27 passes; about 2,840 LDS write-read pairs per unit of work. At a few + picojoules per lane-access that is a few nanojoules per hash against 7,900 (modelled, under 0.1 percent). +4. **The dependent-load chain's latency hiding.** Under the full chain every load's address mixes all 64 registers, + including the previous load's result, so each wave has one load in flight (all 32 loads wait vmcnt(0)). It does not + matter on these cards: 4,096 lanes in flight already saturate the 9070 XT's DRAM (2.64 G/s at 4,096 lanes, measured), + and occupancy 6 on 64 CUs holds 24,576 lanes (the 7600 at 32 CUs: 12,288). The latency is hidden by waves, not by + loads in flight within a wave, with 3x to 6x to spare. +5. **Occupancy under the 64-register window.** 160 VGPRs against 96: 6 waves per SIMD against 10 (modelled), no spill. + Measured consequence on the 7600: none in rate (15.84 per unit of work against 15.79). On NVIDIA the hash lane + measured the window at 96/88 registers (5090) and 104/87 (4090), occupancy 67 to 83 percent, within 5 percent per + load. **GPU-03's AMD cell, rate: 0 percent per unit of work on the RX 7600 (measured, quiet, rate only); energy: + section 4. GPU-03's Intel cell, rate: -0.3 percent per unit of work on the Arc B580 (measured, quiet, rate only), + with the class v6 fingerprints equal to the CUDA and Metal references on both packs (5a6ad122a71a888f and + 59e6708e46f1e87c, self-test PASS): the B580 computes class v6 bit-exact.** + +### 2.4 Where an AMD card's joules go (modelled split at the 9070 XT's floor point, 149.3 W, 18.9 MH/s) + +| Term | Watts | Basis | Label | +|---|---|---|---| +| ALU work | 6 to 12 | 55.3 k lane-ops per unit of work for the partner (8 iterations x (64 + 27 x 256 shadow ops)), 42 k for the window pack (its shadow covers two units); at 5 to 10 pJ per lane-op (the M5 Max's measured marginal 6.9 pJ per counted op as the scale); 17 percent of the card's measured 6.2 T int op/s chain throughput in use | modelled | +| DRAM array and I/O for 2.42 G random 64-byte reads per second | 10 to 20 | 4 to 8 nJ per activate-read-transfer of a 64-byte burst (public GDDR6 figures, approximate) | modelled | +| LDS exchange | under 0.2 | section 2.3 | modelled | +| The rest: the die and board kept awake at full memory data rate (clock trees, fabric and last-level cache, memory PHY, VRM losses, fans) | about 120 | the remainder | modelled | + +The kernel's own work (ALU, LDS, the loads it issues) is 15 to 30 W of 149; the remainder is the price of a whole +graphics card serving 8 or 16 GDDR6 channels' worth of random reads. That is why the knobs that take the core down +without touching memory (the 9070 XT's grid: 24 points, the rate flat at 18.9 MH/s, measured) are worth more than any +kernel text, and why they stop at the driver's floor (-500 MHz, -30 percent), not at the hash's. + +## 3. Candidate kernel changes that keep every hash identical, ranked + +Common to all: none changes the hash function, so none changes the adversary's cost (the adversary's chip computes the +function, not our kernel), and none can help the adversary; each moves only the GPU side. The equality proof for each: +(a) the pack's self-test on the changed kernel (cache head and FNV, dataset samples, 96 of 96 vector lanes), (b) the 2^24 +batch fingerprint at base nonce 0 equal to the unchanged kernel's and to the CUDA and Metal references on the same pack +(hl-v6-foldrw 5a6ad122a71a888f, hl-v6-all 59e6708e46f1e87c on the pre-review export; the re-export's pair when it lands), +on every platform the change ships to, (c) the P01 vector file (`igneum-pow hash-bound --count 1000000`, staged at +build-1 `/srv/artefacts/packs/p01-vectors/`) through the changed kernel. P03 is then a paired energy and rate run on +every mandatory cell the change touches (an OpenCL-only change touches no CUDA card). No candidate reduces the +specialist's advantage, so none is a G2 upgrade: they are efficiency work on the baseline. + +| Rank | Change | Where | Expected gain (all modelled) | The test that proves equality | Risk under P03 | Clock | +|---|---|---|---|---|---|---| +| 0 (a baseline, not a candidate) | The AMD operating point below the driver's floor: a lower absolute core clock or a voltage offset where ADLX exposes one (RDNA 3 and 4 Adrenalin carry a voltage offset; ADLX's manual tuning interface for it is unverified here) | the Ember tune's AMD path, not the kernel | the ALU needs about 17 percent of the 9070 XT's shader throughput and about 30 percent of the 7600's (muls at a quarter rate), so the core can lose half its clock before the rate moves: 149 W to 110 to 125 W on the 9070 XT, 7.9 to 5.8 to 6.6 microjoules; the 7600 similar in proportion | clocks never change outputs; the grid's own per-point self-test and fingerprint | none on correctness; P03 places clock savings in the baseline, so it lowers the AMD baseline (ECO-05's input) and scores nothing as a candidate | the update-return lane's AMD knob; a read of ADLX's absolute and voltage interfaces by 12:00 tomorrow | +| 1 | Occupancy throttle: launch only the lanes that saturate the DRAM (about 4,096 to 8,192 on the 9070 XT, measured) on a fraction of the CUs, so idle CUs clock-gate and the driver's power manager sees a partly idle die | host (a `--max-groups` cap on the dispatch, about 20 lines in host.c; the persistent-warp loop already exists for variant-5 packs) | 0 to 10 percent of the card's watts, unknown until measured; the ALU budget bounds the throttle at about a quarter of the 9070 XT's CUs and half the 7600's | per-nonce outputs do not depend on the launch shape (WAVEFRONT.md: work-groups of 32 to 256 bit-exact; the 2^24 fingerprint at every cap) | a cap below the ALU need loses rate; the sweep finds the knee | host flag and a sweep job: tomorrow 15:00 | +| 2 | Find the GDDR6 per-channel shortfall above the DRAM (the 9070 XT and the B580 at 0.45x to 0.65x the 7600's per-channel rate) and remove it if it is software's: page size and TLB reach of the 1 GiB dataset buffer, the buffer's placement, the driver's allocation flags | host allocation and driver flags | on the B580 at most about 10 percent (its probe falls 10 percent from 256 to 1024 MiB, measured tonight: that is the translation share); the 9070 XT unprobed at two sizes, the same bound expected (modelled) | allocation never changes outputs; the fingerprint | none on correctness; a different allocation could cost the NVIDIA path nothing because it would be vendor-gated | B580 read tonight (10 percent); the 9070 XT's two-size probe when it is back in the housing | +| 3 | Non-temporal dataset loads on AMD (`__builtin_nontemporal_load` in the OpenCL text, which AMD's LLVM lowers to the non-temporal bit on RDNA 3 and the TH_LOAD_NT hint on RDNA 4): no last-level-cache or L2 allocation for lines that are not reused | OpenCL text, AMD only | 0 to 3 percent of the watts (no 64-byte fill into the 32 or 64 MB cache per read); risk of losing the 3 to 6 percent of reads that hit that cache (0 to -3 percent rate) | the hint changes no value; the fingerprint and the vectors | the rate risk; paired run decides | an emitter flag and a PC 1 pair: tomorrow 15:00 | +| 4 | The window's address mix computed incrementally: m is linear over GF(2) in the 64 registers, so m(src) = A xor T_src xor P xor rotr(P, 1), with T_k = rotl(r_k, 63 - k), A the xor of all T_k kept up to date on each register write (two ops per write) and P the xor of T_k below src; the compiler today emits about 108 ops per load (52 rotates, 54 xors, 2 xor3) | emitter, all three dialects | removes about 20 to 25 percent of the window pack's ALU ops per unit of work, so 1 to 2 percent of an AMD card's joules and less on NVIDIA (its ALU share is smaller still) | the identity is exact; a property test in igneum-pow over random register files and every src, then the fingerprint and vectors | none expected; it must not move the 5090 or 4090 window rows by more than noise | an emitter change on the hash lane's line, after the post-review freeze: days two and three | +| 5 | The exchange through DPP or ds_swizzle instead of LDS (RDNA), sub-group shuffles on Intel | OpenCL text, vendor-gated | under 0.1 percent (section 2.3, item 3) | the fingerprint across the exchange paths (WAVEFRONT.md's emulator table already proves path equality) | none | not worth a slot; recorded to close the question | + +Not a candidate (changes the hash; recorded so it is not proposed again): reads of 64 bytes per load (w64) close the +5090 against 9070 XT gap from 7.5x to 4.1x in rate, entirely by halving the 5090 (measured, 5 Oct), so the honest NVIDIA +cells lose about 50 percent of accepted throughput against P03's 2 percent: out. W = 8 and W = 32 are standing rejected +knobs. The hot table and the scratch read-modify-write cost the 9070 XT 13 to 33 percent (measured): out. + +What this means for the vendor question: no kernel change that keeps the hash identical is worth more than about 10 +percent on AMD (candidate 1) plus whatever candidate 2 finds above the DRAM; the 3x to 4.5x is GDDR7 against GDDR6 and a +graphics card's fixed power over few channels. Closing it by changing the hash would cost the honest NVIDIA cards more +than P03 allows, which the standing rule forbids ("no ratio is bought with honest GPU energy"). + +## 4. Rows for the 21:00 economics landing and the P02 cohort, with clocks + +### 4.1 Tonight's two jobs + +| Job | Machine | What it reads | Instrument | Status and clock | +|---|---|---|---|---| +| run-ae-pc1-7600-energy-20261008 | PC 1 (ae432dc7), RX 7600 | memprobe at 1024 MiB; hl-v6-foldrw and hl-v6-all as the load at stock, plimit -30, gmax -500 with plimit -30; reset and read-back | the kit worker's bench (rate), ADLX through igneum-gpu-telemetry.exe every 5 s, samples after 20 s (watts) | published 19:41 UK behind the hash lane's ds2g and l8off; at 20:1x UK PC 1's runner was still held by the withdrawn overnight 7600 grid job (its last upload 19:06 UTC), so none of the three had started; the follow-up reset job run-ae-pc1-7600-reset-20261008 is queued behind it | +| fetch-ae-ze-power-20261008 + run-ae-pc2-b580-energy-20261008 | PC 2 (1ccfe586), Arc B580 | memprobe at 256 and 1024 MiB; both v6 packs at stock | the kit worker's bench (rate), ze-power.exe (Level Zero sysman energy counters, read only, built on build-1 with mingw, sha256 354abddde13a5341521eb298a5728e65675af7474823faf9b8d5613caf840d8f) | ran 19:50 to 19:54 UK (268 s, done): rates, probes and fingerprints read; the energy counter unsupported unelevated (rc 0x78000003 on all three domains, the device seen as `Intel(R) Graphics [0xe20b]`) | + + +### 4.2 The rows, each with its clock + +| # | Row | For | Value and label | Clock | +|---|---|---|---|---| +| 1 | The RX 7600's class v6 rate replaces the class v4 card-in rate in the reference population | the research lane's 21:00 landing | 15.79 MH/s (measured, quiet, rate only); the stock cell 7.2 microjoules (modelled on the v4 run's 113 W) until row 2 | now | +| 2 | The RX 7600 metered at stock and at two knob points on class v6 | the 21:00 landing; ECO-05's section 5 condition (a 7600 knee under 5 microjoules adds the worlds at 0.03 and 0.10) | OWED: the PC 1 runner had not reached the job at landing; until it reports, the cells stay 7.2 at stock (modelled on the class v4 run's 113 W) and 5.0 to 5.4 at the floor point (modelled: the 9070 XT's 24 percent, or a flat rate at -30 percent power) | when PC 1's runner reaches it, about 20 minutes after the hash lane's ds2g and l8off; the rows go to the research lane's ECO-05 batch 02 the minute they land | +| 3 | The Arc B580 on class v6 | the 21:00 landing; ECO-05's section 5 condition (a B580 under 8 adds worlds) | rate 11.01 MH/s (measured, KT); watts NOT READ: the Level Zero sysman energy counter answers unsupported (0x78000003) unelevated on driver 32.0.101.6733, so the cell stays about 110 W estimated, 10.0 microjoules (estimated); under 8 would need under 88 W | rate landed 19:54 UK; watts owed: an unelevated IGCL telemetry read (unverified) or a wall meter, tomorrow 15:00; an elevated read needs main's exception to the nothing-elevated rule | +| 4 | GPU-03's AMD cell: the window's cost per unit of work on the RX 7600 | the register (row 11 and GPU-03) | rate 0 percent (15.84 against 15.79, measured, KT); energy OWED with row 2 (the same job reads both packs at each point) | rate landed; energy with row 2 | +| 5 | GPU-03's Intel cell | the register | rate -0.3 percent per unit of work (measured, KT); SIMD16 under the window, no spill; fingerprints equal on both packs; energy not read | landed 19:54 UK | +| 6 | The named cause of ECO-05's two-vendor failure | the 21:00 landing's text and eco-05-results.md | section 0 and 2.1 of this file (per 32 bits of bus: the same watts, 0.21x to 0.47x the random reads) | landed with this file | +| 7 | The 9070 XT | the cohort | unchanged: 7.9 at the floor point (measured); no v6 row tonight (out of the housing since 14:2x) | when it is back on the bus | + +### 4.3 The P02 cohort, AMD and Intel cells + +| P02 requirement | State tonight | Owed | +|---|---|---| +| At least 3 AMD retail configurations | 2 measured (RX 9070 XT 16 GB, RX 7600 8 GB); the 9060 XT and 7600 XT are in the card-in queue, not on a PC | a third AMD card on PC 1; the hash lane's card-in job runs it as it arrives | +| An advertised 8 GB mining tier | the RX 7600 8 GB (measured; the 5.5 GiB dataset fits at 6,732 MiB of 8,176) | | +| Usable, not nominal, memory | the 7600's 8,176 MiB (measured) | the B580's and the 9070 XT's usable figure from the host's device line | +| Every advertised vendor in the competitive core | Intel: the Arc B580 only; its class v6 rate and fingerprints measured tonight, its watts not readable unelevated | a second Intel configuration if Intel stays advertised | +| Calibrated wall meter, at most 2 percent | none: every AMD and Intel watt is ADLX or Level Zero device telemetry | a wall meter on each PC (a purchase and a hand at the socket); until then every row reads "device-reported" | +| 5 paired 30-minute runs per primary cell after 15 minutes of warm-up | none: tonight's points are about 1 minute each after 20 s | the paired protocol on PC 1 and PC 2 once the 2.0 devnet mines there (GPU-02 and GPU-03 under the standard) | +| Three unaffiliated operators | none | the served kit (D1) | + +## 5. Unverified and owed + +- The offline compiles are LLVM 18 standing in for AMD's driver compiler; the driver's VGPR count and wave size on the + 7600 and the B580 come from tonight's host kernel lines. +- The channel counts per device and the GDDR6 and GDDR7 energy per access are JEDEC and public figures, approximate. +- The split of section 2.4 is modelled; only a per-rail reading (not available through ADLX) would measure it. +- The B580's watts: the Level Zero sysman energy counter is unsupported unelevated on driver 32.0.101.6733 (measured + tonight); the 110 W stays an estimate until an unelevated IGCL read, a wall meter, or main's exception for one + elevated read. +- The RX 7600's metered class v6 rows (job run-ae-pc1-7600-energy-20261008, queued on PC 1 behind a held runner). +- The ALU energy per op on RDNA is taken at the M5 Max's measured scale, not measured on AMD. +- Candidate 0's ADLX absolute-clock and voltage interfaces are unverified on the tool; candidates 1 to 4 are unmeasured. diff --git a/docs/analysis/class-v6/amd-intel-energy/offline-compile-prelude.h b/docs/analysis/class-v6/amd-intel-energy/offline-compile-prelude.h new file mode 100644 index 000000000..ae5258efb --- /dev/null +++ b/docs/analysis/class-v6/amd-intel-energy/offline-compile-prelude.h @@ -0,0 +1,10 @@ +// shims for an offline AMDGPU compile without libclc (analysis only; never a mining kernel) +#define get_global_id(d) ((size_t)(__builtin_amdgcn_workgroup_id_x() * 32u + __builtin_amdgcn_workitem_id_x())) +#define get_local_id(d) ((size_t)__builtin_amdgcn_workitem_id_x()) +#define get_global_size(d) ((size_t)(1u<<20)) +#define get_sub_group_size() 32u +#define rotate(x, n) __builtin_rotateleft32((x), (n)) +#define mul_hi(a, b) ((uint)(((ulong)(a) * (ulong)(b)) >> 32)) +#define barrier(f) do { __builtin_amdgcn_fence(__ATOMIC_RELEASE, "workgroup"); __builtin_amdgcn_s_barrier(); __builtin_amdgcn_fence(__ATOMIC_ACQUIRE, "workgroup"); } while (0) +#define vload4(o, p) (*(const __global uint4*)((p) + 4u*(o))) +#define vstore4(v, o, p) (*(__global uint4*)((p) + 4u*(o)) = (v)) diff --git a/docs/analysis/class-v6/amd-intel-energy/offline-isa-summary.txt b/docs/analysis/class-v6/amd-intel-energy/offline-isa-summary.txt new file mode 100644 index 000000000..26b42b197 --- /dev/null +++ b/docs/analysis/class-v6/amd-intel-energy/offline-isa-summary.txt @@ -0,0 +1,34 @@ +== hl-v6-all-gfx1102 (clang 18.1.3, -O3, OpenCL C 1.2, IGNEUM_EXCHANGE 0) +; codeLenInByte = 33576 +; NumSgprs: 18 +; NumVgprs: 160 +; ScratchSize: 0 +; LDSByteSize: 256 bytes/workgroup (compile time only) +; Occupancy: 6 +global_load_b32 32; s_barrier 0; full waits 51; VALU 4080; v_alignbit 1657; v_xor_b32 1724; v_xor3 72; int mul 99; ds_ 42; scratch 0 +== hl-v6-all-gfx1201 (clang 18.1.3, -O3, OpenCL C 1.2, IGNEUM_EXCHANGE 0) +; codeLenInByte = 34004 +; NumSgprs: 18 +; NumVgprs: 160 +; ScratchSize: 0 +; LDSByteSize: 256 bytes/workgroup (compile time only) +; Occupancy: 6 +global_load_b32 32; s_barrier 0; full waits 49; VALU 4077; v_alignbit 1657; v_xor_b32 1724; v_xor3 72; int mul 99; ds_ 42; scratch 0 +== hl-v6-foldrw-gfx1102 (clang 18.1.3, -O3, OpenCL C 1.2, IGNEUM_EXCHANGE 0) +; codeLenInByte = 6268 +; NumSgprs: 20 +; NumVgprs: 96 +; ScratchSize: 0 +; LDSByteSize: 256 bytes/workgroup (compile time only) +; Occupancy: 10 +global_load_b32 16; s_barrier 0; full waits 25; VALU 675; v_alignbit 84; v_xor_b32 104; v_xor3 20; int mul 67; ds_ 34; scratch 0 +== hl-v6-foldrw-gfx1201 (clang 18.1.3, -O3, OpenCL C 1.2, IGNEUM_EXCHANGE 0) +; codeLenInByte = 6584 +; NumSgprs: 20 +; NumVgprs: 96 +; ScratchSize: 0 +; LDSByteSize: 256 bytes/workgroup (compile time only) +; Occupancy: 10 +global_load_b32 16; s_barrier 0; full waits 23; VALU 675; v_alignbit 84; v_xor_b32 104; v_xor3 20; int mul 67; ds_ 34; scratch 0 +b3314b187c414925e52febb3683120cf7f8db2c8f4b802816b964d705c33c571 ../hl-v6-all/hl-v6-all/kernel.cl +b66c22e859244f86f164e05841858ed1d39b42f1ab6611504872c652fb02ee23 ../hl-v6-foldrw/hl-v6-foldrw/kernel.cl diff --git a/docs/analysis/class-v6/amd-intel-energy/run-ae-pc1-7600-energy-20261008.ps1 b/docs/analysis/class-v6/amd-intel-energy/run-ae-pc1-7600-energy-20261008.ps1 new file mode 100644 index 000000000..79cf1506e --- /dev/null +++ b/docs/analysis/class-v6/amd-intel-energy/run-ae-pc1-7600-energy-20261008.ps1 @@ -0,0 +1,107 @@ +# AMD-and-Intel energy lane (Igneum 2.0 register: GPU-03's AMD cells, ECO-05's owed RX 7600 knee), 8 October 2026. +# The three-card Windows rig's RX 7600 (OpenCL gfx1102), measure only, unelevated: the class v6 kit's own igneum-worker-opencl.exe is the load +# (--bench-pack, no app involvement: the app is never quit, paused or resumed, no api/cards, no app tune), the rebuilt +# igneum-gpu-telemetry.exe (ADLX GPUPower, else GPUTotalBoardPower) samples every 5 s beside it, at three knob points: +# stock, plimit -30, gmax -500 + plimit -30 (the 9070 XT's best). ADLX manual tuning is reset at the end and a read-back +# sample is printed. First: --memprobe at 1024 MiB (the card's dependent random-read ceiling, the 9070 XT's and B580's +# instrument). Every result line starts with RESULT; SUMMARY {json} ends it. The sampler is a child process whose pid is +# written to this job's folder and stopped by that pid only. +$ErrorActionPreference = 'Continue' +$jobName = 'pc1-7600-energy' +$started = Get-Date +function Stamp { (Get-Date).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ') } +function Summary([string] $status, [hashtable] $extra) { + $o = [ordered]@{ job = $jobName; status = $status; duration_s = [int]((Get-Date) - $started).TotalSeconds; finished_at = (Stamp) } + foreach ($k in $extra.Keys) { $o[$k] = $extra[$k] } + 'SUMMARY ' + ($o | ConvertTo-Json -Compress -Depth 5) +} +"RESULT start $(Stamp) job=$jobName machine=$env:COMPUTERNAME app_version=$env:IGNEUM_APP_VERSION" +$jobs = Split-Path $env:IGNEUM_JOB_DIR +$kitId = $env:IGNEUM_V6_KIT_ID; if (-not $kitId) { $kitId = 'fetch-class-v6-kit-20261008' } +$kit = Join-Path $jobs $kitId +$exe = Join-Path $kit 'bin\windows\igneum-worker-opencl.exe' +$packs = Join-Path $kit 'packs' +if (-not (Test-Path $exe)) { "RESULT error worker missing at $exe (fetch job $kitId first)"; Summary 'failed' @{ error = 'worker missing' }; exit 2 } +"RESULT worker $exe sha256 $((Get-FileHash -Algorithm SHA256 $exe).Hash.ToLower()) kit=$kitId" +# the telemetry tool: the newest job-folder copy that prints a tune line, else the installed one (the grid playbook's rule) +$install = Join-Path $env:LOCALAPPDATA 'Programs\Igneum Miner' +$tool = $null; $cands = @() +$jobsDir = Join-Path $env:LOCALAPPDATA 'igneum\app\jobs' +if (Test-Path -LiteralPath $jobsDir) { $cands += @(Get-ChildItem -LiteralPath $jobsDir -Recurse -Filter 'igneum-gpu-telemetry*.exe' -ErrorAction SilentlyContinue | Sort-Object LastWriteTime -Descending | ForEach-Object { $_.FullName }) } +$cands += Join-Path $install 'igneum-gpu-telemetry.exe' +foreach ($c in $cands) { if (-not (Test-Path -LiteralPath $c)) { continue }; $pr = @(& $c --tune 2>&1 | ForEach-Object { "$_" }) | Where-Object { $_ -match '^tune \d+ ' }; if ($pr) { $tool = $c; break } } +if (-not $tool) { "RESULT error no telemetry tool with a tune line"; Summary 'failed' @{ error = 'no tool' }; exit 2 } +"RESULT tool $tool sha256 $((Get-FileHash -LiteralPath $tool -Algorithm SHA256).Hash.ToLower())" +$tune = @(& $tool --tune 2>&1 | ForEach-Object { "$_" }) +$tune | ForEach-Object { "RESULT tune $_" } +$line = $tune | Where-Object { $_ -match '^tune (\d+) name "([^"]*7600[^"]*)" .* ok\s*$' } | Select-Object -First 1 +if (-not $line) { "RESULT error no RX 7600 tune line"; Summary 'failed' @{ error = 'no 7600 tune line' }; exit 2 } +$ord = [int]([regex]::Match($line, '^tune (\d+)').Groups[1].Value) +$gr = [regex]::Match($line, 'gmax_range (-?\d+) (-?\d+)'); $prr = [regex]::Match($line, 'plimit_range (-?\d+) (-?\d+)') +"RESULT card ordinal=$ord gmax_range=$($gr.Groups[1].Value)..$($gr.Groups[2].Value) plimit_range=$($prr.Groups[1].Value)..$($prr.Groups[2].Value)" +# the OpenCL device of the 7600 +$list = @(& $exe --list 2>&1 | ForEach-Object { "$_" }); $list | ForEach-Object { "RESULT list $_" } +$dev = $null; foreach ($l in $list) { if ($l -match '^\s*\[(\d+)\].*gfx1102' -and $l -notmatch 'dup') { $dev = [int]$Matches[1]; break } } +if ($null -eq $dev) { "RESULT error no gfx1102 in --list"; Summary 'failed' @{ error = 'no gfx1102' }; exit 2 } +$w = @(Get-CimInstance Win32_Process -Filter "Name = 'igneum-worker-opencl.exe'" -ErrorAction SilentlyContinue | ForEach-Object { "$($_.ProcessId):[$($_.CommandLine -replace '\s+', ' ')]" }) +$loaded = ($w | Where-Object { $_ -match "--device\s+$dev(\s|$)" }).Count -gt 0 +"RESULT device $dev gfx1102 card_state=$(if ($loaded) { 'loaded (another worker on the card: the rows are labelled loaded)' } else { 'quiet' }) workers=[$($w -join ' ')]" +function SampleLine() { @(& $tool 2>&1 | ForEach-Object { "$_" }) | Where-Object { $_ -match ('^amd ' + $ord + ' ') } | Select-Object -First 1 } +"RESULT idle_sample $(Stamp) $(SampleLine)" +# 1. the random-read ceiling at the dataset size +$mp = @(& $exe --memprobe --probe-mib 1024 --device $dev 2>&1 | ForEach-Object { "$_" }) +$mp | ForEach-Object { "RESULT memprobe $_" } +# 2. the three knob points x the two packs, the bench as the load, the sampler beside it +$sampler = Join-Path $env:IGNEUM_JOB_DIR 'sampler.ps1' +$pidFile = Join-Path $env:IGNEUM_JOB_DIR 'sampler.pid' +Set-Content -LiteralPath $sampler -Value @' +param([string] $tool, [int] $ord, [string] $out) +while ($true) { $l = @(& $tool 2>&1 | ForEach-Object { "$_" }) | Where-Object { $_ -match ('^amd ' + $ord + ' ') } | Select-Object -First 1; Add-Content -LiteralPath $out -Value ((Get-Date).ToUniversalTime().ToString('o') + ' ' + $l); Start-Sleep -Seconds 5 } +'@ +function SetPoint([int] $g, [int] $p) { + $a = @(& $tool --card $ord --set-gmax $g 2>&1 | ForEach-Object { "$_" }) | Where-Object { $_ -match '^tune ' } | Select-Object -First 1 + $b = @(& $tool --card $ord --set-plimit $p 2>&1 | ForEach-Object { "$_" }) | Where-Object { $_ -match '^tune ' } | Select-Object -First 1 + return @{ ok = (($a -match ' ok\s*$') -and ($b -match ' ok\s*$')); lines = ($a + ' | ' + $b) } +} +$rows = @() +$points = @(@(0, 0), @(0, -30), @(-500, -30)) +foreach ($pt in $points) { + $g = $pt[0]; $p = $pt[1] + if ($g -lt [int]$gr.Groups[1].Value -or $p -lt [int]$prr.Groups[1].Value) { "RESULT point gmax=$g plimit=$p skipped (outside the card's range)"; continue } + $set = SetPoint $g $p + "RESULT point gmax=$g plimit=$p set ok=$($set.ok) $($set.lines)" + if (-not $set.ok) { continue } + foreach ($pk in @('hl-v6-foldrw', 'hl-v6-all')) { + $d = Join-Path $packs $pk + $nb = if ($pk -eq 'hl-v6-all') { 40 } else { 80 } + $samp = Join-Path $env:IGNEUM_JOB_DIR ("samples-$pk-g$g-p$p.txt") + $sp = Start-Process -FilePath 'powershell.exe' -ArgumentList @('-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', $sampler, '-tool', $tool, '-ord', $ord, '-out', $samp) -WindowStyle Hidden -PassThru + Set-Content -LiteralPath $pidFile -Value $sp.Id + $t0 = Get-Date + $out = @(& $exe --bench-pack --pack $d --device $dev --batch-log2 24 --batches $nb 2>&1 | ForEach-Object { "$_" }) + $t1 = Get-Date + $spid = [int](Get-Content -LiteralPath $pidFile); Stop-Process -Id $spid -Force -ErrorAction SilentlyContinue; Remove-Item -LiteralPath $pidFile -ErrorAction SilentlyContinue + foreach ($l in $out) { if ($l -match '^(pack |class |RESULT |FAIL|error|warm-up|kernel|exchange)') { "RESULT bench $pk g=$g p=$p out $l" } } + $res = $out | Where-Object { $_ -match '^RESULT ' } | Select-Object -Last 1 + $fp = ''; $mhs = 0; $check = '' + if ($res -match 'fingerprint=([0-9a-f]{16})') { $fp = $Matches[1] } + if ($res -match 'mhs=([0-9.]+)') { $mhs = [double]$Matches[1] } + if ($res -match 'check=(\w+)') { $check = $Matches[1] } + # the watts: samples from 20 s after the bench started (the dataset build and warm-up excluded) to its end + $ws = @(); $gc = @(); $raw = @() + if (Test-Path -LiteralPath $samp) { foreach ($s in Get-Content -LiteralPath $samp) { $raw += $s; $ts = [datetime]::Parse(($s -split ' ')[0]).ToUniversalTime(); if ($ts -ge $t0.ToUniversalTime().AddSeconds(20) -and $ts -le $t1.ToUniversalTime()) { $m = [regex]::Match($s, ' watts (-?[\d.]+)'); if ($m.Success -and [double]$m.Groups[1].Value -gt 0) { $ws += [double]$m.Groups[1].Value }; $c = [regex]::Match($s, ' gclk_mhz (-?[\d.]+)'); if ($c.Success) { $gc += [double]$c.Groups[1].Value } } } } + $raw | Select-Object -First 3 | ForEach-Object { "RESULT sample $pk g=$g p=$p $_" } + $wm = if ($ws.Count) { [math]::Round((($ws | Measure-Object -Average).Average), 1) } else { 0 } + $gm = if ($gc.Count) { [math]::Round((($gc | Measure-Object -Average).Average), 0) } else { 0 } + $uj = if ($mhs -gt 0 -and $wm -gt 0) { [math]::Round($wm / $mhs, 3) } else { 0 } + "RESULT ROW card=RX7600 pack=$pk gmax_off=$g plimit=$p mhs=$mhs watts=$wm uj_per_hash=$uj gclk=$gm samples=$($ws.Count) seconds=$([int]($t1 - $t0).TotalSeconds) fingerprint=$fp check=$check $(Stamp)" + $rows += [ordered]@{ pack = $pk; g = $g; p = $p; mhs = $mhs; watts = $wm; uj = $uj; gclk = $gm; samples = $ws.Count; fingerprint = $fp; check = $check } + } +} +$r = @(& $tool --card $ord --reset 2>&1 | ForEach-Object { "$_" }) | Where-Object { $_ -match '^tune ' } | Select-Object -First 1 +"RESULT reset $r" +Start-Sleep -Seconds 3 +"RESULT after_reset_sample $(Stamp) $(SampleLine)" +"RESULT after_reset_tune $((@(& $tool --tune 2>&1 | ForEach-Object { "$_" }) | Where-Object { $_ -match ('^tune ' + $ord + ' ') } | Select-Object -First 1))" +Summary $(if ($rows.Count) { 'done' } else { 'failed' }) @{ rows = $rows; device = $dev; ordinal = $ord; kit = $kitId } +exit $(if ($rows.Count) { 0 } else { 1 }) diff --git a/docs/analysis/class-v6/amd-intel-energy/run-ae-pc1-7600-reset-20261008.ps1 b/docs/analysis/class-v6/amd-intel-energy/run-ae-pc1-7600-reset-20261008.ps1 new file mode 100644 index 000000000..432b6aa60 --- /dev/null +++ b/docs/analysis/class-v6/amd-intel-energy/run-ae-pc1-7600-reset-20261008.ps1 @@ -0,0 +1,23 @@ +# AMD-and-Intel energy lane, 8 October 2026: the guaranteed ADLX reset of the RX 7600 after run-ae-pc1-7600-energy-20261008 +# (a timeout, a killed job tree or a lost relay must never leave the card capped). Unelevated; the card's ordinal from the +# tool's own tune line (the integrated Radeon's all-dash line is not a card); --reset, then a tune-line read-back. +$ErrorActionPreference = 'Continue' +$install = Join-Path $env:LOCALAPPDATA 'Programs\Igneum Miner' +$tool = $null; $cands = @() +$jobsDir = Join-Path $env:LOCALAPPDATA 'igneum\app\jobs' +if (Test-Path -LiteralPath $jobsDir) { $cands += @(Get-ChildItem -LiteralPath $jobsDir -Recurse -Filter 'igneum-gpu-telemetry*.exe' -ErrorAction SilentlyContinue | Sort-Object LastWriteTime -Descending | ForEach-Object { $_.FullName }) } +$cands += Join-Path $install 'igneum-gpu-telemetry.exe' +foreach ($c in $cands) { if (-not (Test-Path -LiteralPath $c)) { continue }; $pr = @(& $c --tune 2>&1 | ForEach-Object { "$_" }) | Where-Object { $_ -match '^tune \d+ ' }; if ($pr) { $tool = $c; break } } +if (-not $tool) { 'RESULT error no telemetry tool with a tune line'; 'SUMMARY {"job":"pc1-7600-reset","status":"failed"}'; exit 2 } +$line = @(& $tool --tune 2>&1 | ForEach-Object { "$_" }) | Where-Object { $_ -match '^tune (\d+) name "([^"]*7600[^"]*)" .* ok\s*$' } | Select-Object -First 1 +if (-not $line) { 'RESULT error no RX 7600 tune line'; 'SUMMARY {"job":"pc1-7600-reset","status":"failed"}'; exit 2 } +$ord = [int]([regex]::Match($line, '^tune (\d+)').Groups[1].Value) +"RESULT before $line" +$r = @(& $tool --card $ord --reset 2>&1 | ForEach-Object { "$_" }) | Where-Object { $_ -match '^tune ' } | Select-Object -First 1 +"RESULT reset $r" +Start-Sleep -Seconds 2 +$after = @(& $tool --tune 2>&1 | ForEach-Object { "$_" }) | Where-Object { $_ -match ('^tune ' + $ord + ' ') } | Select-Object -First 1 +"RESULT after $after" +$ok = ($after -match ' gmax 0 ') -and ($after -match ' plimit 0 ') +"SUMMARY {""job"":""pc1-7600-reset"",""status"":""$(if ($ok) { 'done' } else { 'check' })"",""ordinal"":$ord}" +exit 0 diff --git a/docs/analysis/class-v6/amd-intel-energy/run-ae-pc2-b580-energy-20261008.ps1 b/docs/analysis/class-v6/amd-intel-energy/run-ae-pc2-b580-energy-20261008.ps1 new file mode 100644 index 000000000..1e1c416e3 --- /dev/null +++ b/docs/analysis/class-v6/amd-intel-energy/run-ae-pc2-b580-energy-20261008.ps1 @@ -0,0 +1,70 @@ +# AMD-and-Intel energy lane (Igneum 2.0 register: GPU-03's Intel cell, ECO-05's owed B580 watts), 8 October 2026. +# The second Windows rig's Intel Arc B580, measure only, unelevated, no knob written (Intel has none in our tools): the class v6 kit's own +# igneum-worker-opencl.exe is the load (--bench-pack; the app is never quit, paused or resumed, no api/cards), and +# ze-power.exe (fetch job fetch-ae-ze-power-20261008, sha256 354abddd...; Level Zero sysman energy counters through the +# driver's ze_loader.dll, read only) samples every 5 s beside it. First: --memprobe at 256 and 1024 MiB (the dependent +# random-read ceiling; two sizes to see whether the rate falls with the footprint beyond the caches, a TLB-reach sign). +# The sampler is a child process whose pid is written to this job's folder and stopped by that pid only. +$ErrorActionPreference = 'Continue' +$env:IGNEUM_V6_KIT_ID = 'fetch-class-v6-kit-20261008' +$jobName = 'pc2-b580-energy' +$started = Get-Date +function Stamp { (Get-Date).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ') } +function Summary([string] $status, [hashtable] $extra) { + $o = [ordered]@{ job = $jobName; status = $status; duration_s = [int]((Get-Date) - $started).TotalSeconds; finished_at = (Stamp) } + foreach ($k in $extra.Keys) { $o[$k] = $extra[$k] } + 'SUMMARY ' + ($o | ConvertTo-Json -Compress -Depth 5) +} +"RESULT start $(Stamp) job=$jobName machine=$env:COMPUTERNAME app_version=$env:IGNEUM_APP_VERSION" +$jobs = Split-Path $env:IGNEUM_JOB_DIR +$ze = Join-Path (Join-Path $jobs 'fetch-ae-ze-power-20261008') 'ze-power.exe' +if (-not (Test-Path $ze)) { $ze = @(Get-ChildItem -LiteralPath $jobs -Recurse -Filter 'ze-power.exe' -ErrorAction SilentlyContinue | Select-Object -First 1 | ForEach-Object { $_.FullName }) | Select-Object -First 1 } +if (-not $ze -or -not (Test-Path $ze)) { "RESULT error ze-power.exe missing (fetch job fetch-ae-ze-power-20261008 first)"; Summary 'failed' @{ error = 'no sampler' }; exit 2 } +"RESULT sampler $ze sha256 $((Get-FileHash -Algorithm SHA256 $ze).Hash.ToLower())" +@(& $ze 2>&1 | ForEach-Object { "$_" }) | ForEach-Object { "RESULT ze_idle $_" } +# the kit: IGNEUM_V6_KIT_ID, else the newest job folder holding the worker and packs\hl-v6-foldrw +$kit = $null +if ($env:IGNEUM_V6_KIT_ID) { $kit = Join-Path $jobs $env:IGNEUM_V6_KIT_ID } +if (-not $kit -or -not (Test-Path $kit)) { $kit = @(Get-ChildItem -LiteralPath $jobs -Directory -ErrorAction SilentlyContinue | Where-Object { (Test-Path (Join-Path $_.FullName 'packs\hl-v6-foldrw\kernel_bound.cl')) -and (Test-Path (Join-Path $_.FullName 'bin\windows\igneum-worker-opencl.exe')) } | Sort-Object LastWriteTime -Descending | ForEach-Object { $_.FullName }) | Select-Object -First 1 } +if (-not $kit) { "RESULT error no class v6 kit on this PC"; Summary 'failed' @{ error = 'no kit' }; exit 2 } +$exe = Join-Path $kit 'bin\windows\igneum-worker-opencl.exe'; $packs = Join-Path $kit 'packs' +"RESULT worker $exe sha256 $((Get-FileHash -Algorithm SHA256 $exe).Hash.ToLower()) kit=$(Split-Path $kit -Leaf)" +$list = @(& $exe --list 2>&1 | ForEach-Object { "$_" }); $list | ForEach-Object { "RESULT list $_" } +$dev = $null; foreach ($l in $list) { if ($l -match '^\s*\[(\d+)\].*(B580|Arc|Battlemage)' -and $l -notmatch 'dup') { $dev = [int]$Matches[1]; break } } +if ($null -eq $dev) { "RESULT error no Arc B580 in --list"; Summary 'failed' @{ error = 'no B580' }; exit 2 } +$w = @(Get-CimInstance Win32_Process -Filter "Name = 'igneum-worker-opencl.exe'" -ErrorAction SilentlyContinue | ForEach-Object { "$($_.ProcessId):[$($_.CommandLine -replace '\s+', ' ')]" }) +$loaded = ($w | Where-Object { $_ -match "--device\s+$dev(\s|$)" }).Count -gt 0 +"RESULT device $dev card_state=$(if ($loaded) { 'loaded' } else { 'quiet' }) workers=[$($w -join ' ')]" +foreach ($mib in @(256, 1024)) { @(& $exe --memprobe --probe-mib $mib --device $dev 2>&1 | ForEach-Object { "$_" }) | ForEach-Object { "RESULT memprobe $mib $_" } } +$pidFile = Join-Path $env:IGNEUM_JOB_DIR 'ze.pid' +$rows = @() +foreach ($pk in @('hl-v6-foldrw', 'hl-v6-all')) { + $d = Join-Path $packs $pk + if (-not (Test-Path (Join-Path $d 'kernel_bound.cl'))) { "RESULT error pack $pk missing"; continue } + $nb = if ($pk -eq 'hl-v6-all') { 30 } else { 60 } + $samp = Join-Path $env:IGNEUM_JOB_DIR ("ze-$pk.txt") + $sp = Start-Process -FilePath $ze -ArgumentList @('-l', '5') -RedirectStandardOutput $samp -WindowStyle Hidden -PassThru + Set-Content -LiteralPath $pidFile -Value $sp.Id + $t0 = Get-Date + $out = @(& $exe --bench-pack --pack $d --device $dev --batch-log2 24 --batches $nb 2>&1 | ForEach-Object { "$_" }) + $t1 = Get-Date + $zpid = [int](Get-Content -LiteralPath $pidFile); Stop-Process -Id $zpid -Force -ErrorAction SilentlyContinue; Remove-Item -LiteralPath $pidFile -ErrorAction SilentlyContinue + foreach ($l in $out) { if ($l -match '^(pack |class |RESULT |FAIL|error|warm-up|kernel|exchange)') { "RESULT bench $pk out $l" } } + $res = $out | Where-Object { $_ -match '^RESULT ' } | Select-Object -Last 1 + $fp = ''; $mhs = 0; $check = '' + if ($res -match 'fingerprint=([0-9a-f]{16})') { $fp = $Matches[1] } + if ($res -match 'mhs=([0-9.]+)') { $mhs = [double]$Matches[1] } + if ($res -match 'check=(\w+)') { $check = $Matches[1] } + # ze lines arrive every 5 s; the lines after the first 20 s of the bench (warm-up and dataset build excluded): the sampler + # started with the bench, so the first four sample rounds are dropped + $lines = @(); if (Test-Path -LiteralPath $samp) { $lines = @(Get-Content -LiteralPath $samp) } + $lines | Select-Object -First 6 | ForEach-Object { "RESULT ze $pk $_" } + $dom = @{} + $round = @{} + foreach ($l in $lines) { if ($l -match '^intel (\d+) dom (\d+) card (\d) watts ([\d.]+)') { $k = "$($Matches[1])/$($Matches[2])/card$($Matches[3])"; if (-not $round.ContainsKey($k)) { $round[$k] = 0 }; $round[$k]++; if ($round[$k] -gt 4) { if (-not $dom.ContainsKey($k)) { $dom[$k] = @() }; $dom[$k] += [double]$Matches[4] } } } + $dm = [ordered]@{} + foreach ($k in $dom.Keys) { $dm[$k] = [math]::Round((($dom[$k] | Measure-Object -Average).Average), 1); "RESULT ROW card=ArcB580 pack=$pk domain=$k mhs=$mhs watts=$($dm[$k]) uj_per_hash=$(if ($mhs -gt 0) { [math]::Round($dm[$k] / $mhs, 3) } else { 0 }) samples=$($dom[$k].Count) seconds=$([int]($t1 - $t0).TotalSeconds) fingerprint=$fp check=$check $(Stamp)" } + $rows += [ordered]@{ pack = $pk; mhs = $mhs; watts = $dm; fingerprint = $fp; check = $check } +} +Summary $(if ($rows.Count) { 'done' } else { 'failed' }) @{ rows = $rows; device = $dev } +exit $(if ($rows.Count) { 0 } else { 1 }) diff --git a/docs/analysis/class-v6/amd-intel-energy/ze-power.c b/docs/analysis/class-v6/amd-intel-energy/ze-power.c new file mode 100644 index 000000000..1a7f99c8b --- /dev/null +++ b/docs/analysis/class-v6/amd-intel-energy/ze-power.c @@ -0,0 +1,98 @@ +/* ze-power: Intel GPU power from the Level Zero sysman energy counters (AMD-and-Intel energy lane, 8 October 2026). + * Windows: loads ze_loader.dll (installed by the Intel graphics driver) at run time; no SDK, no headers. + * ze-power.exe one reading: two energy-counter reads 1 s apart per power domain + * ze-power.exe -l N a line every N seconds until killed + * Line: intel dom card <0|1> watts energy_uj ts_us name "" + * The counter is the device's own (package or card domain, as the driver exposes it), not the wall. Read only: + * no set call exists in this program. */ +#include +#include +#include +#include +#include +typedef int32_t zr; +typedef void *H; +typedef struct { uint64_t energy; uint64_t timestamp; } ecnt; +typedef zr (__cdecl *f_init)(uint32_t); +typedef zr (__cdecl *f_get)(uint32_t *, H *); +typedef zr (__cdecl *f_get2)(H, uint32_t *, H *); +typedef zr (__cdecl *f_card)(H, H *); +typedef zr (__cdecl *f_cnt)(H, ecnt *); +typedef zr (__cdecl *f_props)(H, void *); +#define MAXD 8 +#define MAXP 8 +static void names(H dev, f_props gp, char *out, size_t cap) { + out[0] = 0; + if (!gp) return; + static unsigned char buf[8192]; + memset(buf, 0, sizeof buf); + *(uint32_t *)(buf + 0) = 0x1; /* ZES_STRUCTURE_TYPE_DEVICE_PROPERTIES */ + *(uint32_t *)(buf + 16) = 0x3; /* core: ZE_STRUCTURE_TYPE_DEVICE_PROPERTIES */ + if (gp(dev, buf) != 0) return; + size_t o = 0; int run = 0; size_t start = 0; + for (size_t i = 0; i < sizeof buf && o + 2 < cap; i++) { + unsigned char c = buf[i]; + if (c >= 32 && c < 127) { if (!run) { start = i; run = 1; } } + else { if (run && i - start >= 4) { size_t n = i - start; if (o + n + 2 >= cap) break; if (o) out[o++] = '|'; memcpy(out + o, buf + start, n); o += n; } run = 0; } + } + out[o] = 0; +} +int main(int argc, char **argv) { + int loop = 0; + if (argc >= 3 && strcmp(argv[1], "-l") == 0) loop = atoi(argv[2]); + HMODULE m = LoadLibraryA("ze_loader.dll"); + if (!m) { printf("error no ze_loader.dll (%lu)\n", GetLastError()); return 2; } + f_init zesInit = (f_init)GetProcAddress(m, "zesInit"); + f_get zesDriverGet = (f_get)GetProcAddress(m, "zesDriverGet"); + f_get2 zesDeviceGet = (f_get2)GetProcAddress(m, "zesDeviceGet"); + f_get2 enumPwr = (f_get2)GetProcAddress(m, "zesDeviceEnumPowerDomains"); + f_card cardPwr = (f_card)GetProcAddress(m, "zesDeviceGetCardPowerDomain"); + f_cnt getE = (f_cnt)GetProcAddress(m, "zesPowerGetEnergyCounter"); + f_props gp = (f_props)GetProcAddress(m, "zesDeviceGetProperties"); + f_init zeInit = (f_init)GetProcAddress(m, "zeInit"); + f_get zeDriverGet = (f_get)GetProcAddress(m, "zeDriverGet"); + f_get2 zeDeviceGet = (f_get2)GetProcAddress(m, "zeDeviceGet"); + if (!enumPwr || !getE) { printf("error the loader has no sysman power entry points\n"); return 2; } + H drv[MAXD], dev[MAXD * 4]; uint32_t nd = 0, ndev = 0; const char *path = "zesInit"; + zr r = zesInit ? zesInit(0) : -1; + if (r == 0 && zesDriverGet && zesDeviceGet) { + uint32_t c = MAXD; if (zesDriverGet(&c, drv) == 0) nd = c; + for (uint32_t i = 0; i < nd; i++) { uint32_t k = MAXD; if (zesDeviceGet(drv[i], &k, dev + ndev) == 0) ndev += k; } + } + if (ndev == 0 && zeInit && zeDriverGet && zeDeviceGet) { + path = "zeInit+ZES_ENABLE_SYSMAN"; SetEnvironmentVariableA("ZES_ENABLE_SYSMAN", "1"); + r = zeInit(0); + uint32_t c = MAXD; if (r == 0 && zeDriverGet(&c, drv) == 0) nd = c; + for (uint32_t i = 0; i < nd; i++) { uint32_t k = MAXD; if (zeDeviceGet(drv[i], &k, dev + ndev) == 0) ndev += k; } + } + printf("info path %s init %d drivers %u devices %u\n", path, (int)r, nd, ndev); + if (ndev == 0) { printf("error no sysman device\n"); return 3; } + H pw[MAXD * 4][MAXP + 1]; uint32_t np[MAXD * 4]; int iscard[MAXD * 4][MAXP + 1]; char nm[MAXD * 4][256]; + for (uint32_t d = 0; d < ndev; d++) { + names(dev[d], gp, nm[d], sizeof nm[d]); + uint32_t k = MAXP; np[d] = 0; + if (enumPwr(dev[d], &k, pw[d]) == 0) np[d] = k; + for (uint32_t j = 0; j < np[d]; j++) iscard[d][j] = 0; + H c = 0; + if (cardPwr && cardPwr(dev[d], &c) == 0 && c) { pw[d][np[d]] = c; iscard[d][np[d]] = 1; np[d]++; } + printf("info dev %u domains %u name \"%s\"\n", d, np[d], nm[d]); + } + ecnt prev[MAXD * 4][MAXP + 1]; + for (uint32_t d = 0; d < ndev; d++) for (uint32_t j = 0; j < np[d]; j++) { memset(&prev[d][j], 0, sizeof(ecnt)); getE(pw[d][j], &prev[d][j]); } + int every = loop > 0 ? loop : 1; + for (;;) { + Sleep(every * 1000); + for (uint32_t d = 0; d < ndev; d++) for (uint32_t j = 0; j < np[d]; j++) { + ecnt e; memset(&e, 0, sizeof e); + zr q = getE(pw[d][j], &e); + double dt = (double)(e.timestamp - prev[d][j].timestamp) * 1e-6, de = (double)(e.energy - prev[d][j].energy) * 1e-6; + double w = dt > 0 ? de / dt : 0; + printf("intel %u dom %u card %d watts %.2f energy_uj %llu ts_us %llu rc %d name \"%s\"\n", d, j, iscard[d][j], w, + (unsigned long long)e.energy, (unsigned long long)e.timestamp, (int)q, nm[d]); + prev[d][j] = e; + } + fflush(stdout); + if (loop <= 0) break; + } + return 0; +} diff --git a/docs/analysis/proving-outcome-ledger.md b/docs/analysis/proving-outcome-ledger.md new file mode 100644 index 000000000..fb81227aa --- /dev/null +++ b/docs/analysis/proving-outcome-ledger.md @@ -0,0 +1,40 @@ +# The proving outcome ledger (review B F08) + +8 October 2026, the enforced proving lane. Review B, finding F08: the proving pipeline reported waste and deadline censoring, never sustained capacity; "add an outcome ledger for every eligible job: completed, active, expired or explicitly cancelled, then report paid completions, missed deadlines and wasted work by cause". + +## What an eligible job is + +A segment a prover claimed (`RESULT claim` in `tools/fleet/box-prover.py`): every block of the segment present in its worklist, every shard open, unpaid and absent from its pool, the deadline (last block's DAA plus the unproven window) at least the margin past the tip. A segment nobody claimed is not a job; the chain's own view of those (pending, unproven, paid per segment) is `igneum_getProvingStatus` and stays as it was. + +## The one outcome per job + +| Outcome | When | Cause field | +|---|---|---| +| active | claimed and not yet closed: in export, cut or chain; submitted and waiting for a carrier; held for a retry | none | +| paid | a carrying block paid the segment record (`RESULT paid`) | none | +| expired | the deadline passed with no paid record | `unpaid` (submitted, never carried in time), `held_expired` (a held record past its deadline), `never_submitted` (log reconstruction only: the log ran 50 DAA past the deadline with no submit) | +| cancelled | this prover gave the job up | `disk`, `export`, `cut`, `chain`, `timeout`, `shards`, `statement`, `sign`, `refused` | + +A job closes once; a second close is ignored. Each segment row in `prover-state.json` carries `outcome`, `cause`, `deadline`, `margin_daa` (at the claim), `spent_s` (export, cut and chain seconds), `wasted_s` (the same unless paid), `miss_daa` (an expiry's distance past the deadline at the close), `closed_at`. The state carries `outcomes` (paid, active, expired, cancelled), `wasted_s` by cause and `deadline_misses`. Every close is a `RESULT outcome` line and the run ends with a `RESULT ledger` line naming the still-active segments. + +## The report + +`tools/fleet/prover-outcomes.py --state ... --log ... [--json]` merges the fleet's state files (a state row wins over the same segment in a log) and reconstructs the ledger for a prover from before this change from its RESULT lines (claim, chain, shards, statement, sign, segment_refused, held, submitted, paid, unpaid, held_expired). It prints: + +- Outcome ledger: jobs by outcome. +- Paid completions: segments, shards, IGN, median end to end, median time from submit to pay, median margin at the claim. +- Missed deadlines: count by cause, median miss in DAA (never negative; none when the log's last tip is stale), median margin at the claim, the seconds spent on them. +- Wasted work by cause: jobs and seconds per cause, against the seconds spent in all. +- Throughput over the covered span: segments paid per hour, shards paid per hour, the paid share of the seconds spent. +- Active: the open jobs, with whether each is submitted. + +`--self-test` runs a synthetic log (six jobs: paid, timeout, unpaid, shards, held_expired, active) and four old-shape state rows to known numbers; the gate runs it (`tools/ci/pre-push.sh`). `tools/fleet/night.py` sums the fleet's counters into its hourly row (`outcomes`, `deadline_misses`, `wasted_s`), which `page.py` publishes. + +## Reading it + +The question the finding asks is answered by three ratios the report prints: paid jobs over claimed jobs, the paid share of the seconds spent, and the median margin at the claim for paid against expired jobs. A pipeline whose expired jobs claimed with a margin close to the floor (240 DAA) and whose paid jobs claimed wider is sizing its jobs too close to the deadline; the fix is the margin, never a longer exclusive window (the finding's warning: a longer window is tested against slow or malicious claimants before it moves). A pipeline whose waste sits under `chain` or `timeout` has a prover problem, under `unpaid` a carrier problem (records accepted and never carried in time), under `refused` a chaining problem (fresh records refused while the previous segment waits). + +## Not in this change + +- The chain-side ledger (every segment the chain planned, claimed or not, with its pending, unproven and paid state per claimant) stays on the node's RPC as it is; a per-segment outcome feed from the observer is the next step if the fleet's view and the chain's view disagree. +- Job sizing, resumable verified work, early cancellation and bounded assignment protection (the finding's second paragraph) are design items for the pool and prover lanes; this ledger is the instrument they read. diff --git a/docs/bridge/light-client-bridge.md b/docs/bridge/light-client-bridge.md index f165c57b7..a90cae0e9 100644 --- a/docs/bridge/light-client-bridge.md +++ b/docs/bridge/light-client-bridge.md @@ -48,6 +48,12 @@ Measured on the test EVM: a 29-voter table costs about 5.3 million gas to instal verifies in about 3.9 million gas (the pairing and the two map-to-curve calls dominate; a G1 addition per signer is 375 gas). On Sepolia at a 1 gwei tip that is under 0.01 ETH per certificate. +Recovery locks (finality rule v4's majority-continuity recovery after an empty window, review B item F04) are not a +kind the contract knows: the certificate bytes carry no lock label, so the verifier reads only weight against the +installed table and accepts the final rule alone. A certificate signed by over half but under two thirds of the +table returns `ok = false` and `submitCertificate` reverts: a recovery lock is never recorded as final, and a +consumer that needs recovery locks must carry its own state, since nothing here tells them apart. + ## What the account proof proves `verifyAccount(stateRoot, account, proof)` walks an Ethereum account proof (the `eth_getProof` shape: RLP nodes from diff --git a/docs/plans/counter-asic-3-status.md b/docs/plans/counter-asic-3-status.md index 437af07b9..1f7b3643a 100644 --- a/docs/plans/counter-asic-3-status.md +++ b/docs/plans/counter-asic-3-status.md @@ -499,6 +499,12 @@ THE ADVERSARY LANE's F05 PRICING (20:00 BST, section 17 at 319e79c6a, ahead of 2 THE SIXTIETH LANDING, THE LOCK AND THE FINAL TREE (20:0x to 20:1x BST). The sixtieth landing on master at 36d9ccc7. THE FIRST LOCK AFTER THE OUTAGE: checkpoint 270 at 19:51:37 on build-1's seed and hand together (block 63d82e57, blue score 7,949, 63.6 percent of total weight signing; 269 the same second; 264 backfilled at 19:56); the seed active with latestLocked 270 and next index 285 at 20:06; the kind "final" (rule v4 never on devnet-4, no recovery lock on this chain). 7cfa422a: the steward's six cells green at 19:55, the miner suite 31 green on build-2, the pair placed on both boxes (igneumd 23ee1b71), the live canary on build-1's seed parsing every template (49 in 60 s at DAA 8,565, no refusal, no NODE SLOW; the 2.0.0 miner on the same seed refusing every template of this epoch); the roll per main's correction. LANE D's SECOND CHAIN-PATH FAULT (20:0x): accept::is_class_v4_shape also compared `mix`, and a width-4 class carries mix one-hot on 4 words (LoadClass::era setting it from the drawn width), so with W = 4 pinned at genesis the chain's acceptance would never run (a'), (c'), (c'') or (c''') and the cap would be 32; under the crate's own predicate the width-4 class ran the class v2 parts only ((a') 0 of 1,581 candidates, r = 0.05, the accepted draw's minimum ratio p1 0.9832 under the floor, the bit read over 300 sigma in 36 percent of eras); every width-4 row of the day ran the full rule because the harness's predicate overrides mix; fixed in b24dfc162 (mix set aside in the predicate and the source rule, the test that the shape holds at every width; the genesis draw unchanged). Lane D's 6.11 read on 04442d9ca COMPLETE (on build-4 before the move): the full class string mx8+sh256x27+state+reg64c+nowin+fold+rw under the harness's predicate, width 4, 3,000 eras: r = 0.154, mean attempt 0.18, max 4, 0 exhausted, (c'') 0 and (c''') 0.23 percent of reaching candidates; width 1, 1,500 eras: r = 0.134, (c''') 0.07 percent; the bit-R read over 6 sigma in 22 percent of eras (6.10 without the fold 44), over 300 sigma 3.8 (19.9): the fold halves the class and does not remove it; attack-f8 on the mirror-valid subset at 2^20 on 64 seeds: 0 hot sets, 0 over 1.2x, worst 1.02x; PASS on the acceptance; build-4 cleared at 20:0x (the holders were the predicate bisect's census binaries at 4 to 8 threads and one reg64-alone probe exhausting 256 attempts per era; no cargo job). THE FINAL TREE: class-v6 ac86d791094610710de4531b051fdb906d84520f = b24dfc162 (5a095e64a A06's kernel hashes in identity.json, a thirteenth pack file, the pinned twelve byte for byte; 4b888682d F03 ProgramClass::V6 in the canonical enum, GENERATOR_VERSION_V6 = 6, V6_CLASS = mx8+sh256x27+state+reg64c+fold+rw with layer 8 off as the fifth flag, every v6 class drawing as generator 6 under an era, the packs reading program_class "v6"; F05 the reg64 full-chain address source in closed form r[s] ^ ror(P_s, 1) ^ (S ^ P_s ^ a[s]) with a[k] = rotl(r[k], (63 - k) mod 32), proven equal to the reference fold on every source register over 256 drawn register states and a real update sequence, the one-rotation-off form disagreeing, known-failed first, the verifier keeping the fold as the definition; the mix fix) plus the F05 measurement text as an exporter switch (igneum-pow export --reg64-prefix) and one lib test fix (program_classes counting class v6); the suite on build-7 green about 20:35; the generator-6 packs with ids and sha256s from build-5 by 20:40 to the node lane, the census hand and lane D; the prefix pack hl-v6-all-prefix.tgz for the fleet's F05 rows (a 5090 and a 4090 at stock by 23:30). The node lane's candidates: (c) re-cut on b24dfc162 as e0e3789b (the kaspa-pow arm mapping the chain's V6 to the crate's V6; core 184, consensus 143 green on build-1), re-cut again on ac86d7910 when mirrored; (a) and (b) on build-9 (core 184, consensus 143 green so far) with the 2.0.2 candidate e58d3270; the pin on master at 20:45. The adversary lane's F05 pricing (section 17, 319e79c6a): the cheapest form at the shipped shape the literal fold, at most 56 nJ per hash, the complete-machine bracket 1.42x to 1.49x same node, 1.7x to 1.8x a node ahead, the coupling buying the honest side at most 0.08x; the shipped class folds one register per load, untouched. Review B on master at dc7d6c60 (20:04; the landing lost three pushes to the one-a-minute batch landings, the merge tool now retrying a lost compare-and-swap twelve times without re-running the hook); the REV suite from tools/ci/review-suite.mjs (one case per regression, REV-F01-1 onward, the line verbatim, NOT RUN, the owner from the dispatch; --check in the gate refusing drift) with the founder's two rulings as dated notes through the recorder's --note mode and in F0's register as resolved, on master by 20:30; F02's tools/ci/proof-rule-bypass-check.sh in the node matrix, RED on 7cfa422a as the code stands until the fix rides 2.0.2; F03's one manifest and the build-from-manifest in CI by 23:00. F01 and F02's fix verdict-cache-fix-node 3f672661 green on build-7 at 20:07 (consensus-core 175, consensus 141, igneum-exec 79, p2p-flows 38): the verifier answers a fact record or a typed refusal, only InvalidBytes cached, a context refusal re-answered per carrier, the cache bounded 4096 with 8 in flight, the harness skip behind the harness-unsafe feature, a not-ready verifier retrying the block unmarked; F01 reproduced live on the pre-fix node by the redesigned succession run (20:01, build-2, both pairs embedded, phases at DAA 117, 256 and 374): below H right; at the window H1 refused the next-pair proof with the below-H text verbatim ("block 103" inside a block-241 refusal), a context refusal cached by proof hash; after the window the prior-pair proof refused on its cached statement text; the before-evidence, the rerun on the fixed node by 20:45; two harness facts fixed on key-succession 77072e110; the enforced lane's cell and batch on master at 7ade25b00. FIN-02 the night's first PASS under the procedure (the finality lane's own cell harness:finality-sim-fin02, master 0218d6bf1, batch fin-boundary-20261008-02; FIN-08 RUNNING under the model cell; the real-node half the node lane's). GOV-03's first row (20:01): the shipped 2.0.1 seed pair rebuilt from a clean clone on build-8 with the same recipe: igneum-miner bit for bit (sha256 f922b216a726b01d); igneumd NOT (013986fecb2e77f4 against 6d03d0968c03e6a4, 57,040,848 B both, 60,022 differing bytes, string tables identical: a build id, symbol or section order, or a timestamp in a non-string section); PARTIAL, the build-id and sorted-link try on build-8 tonight; the 2.0.1 hive done (a16add6a, 20:02, six seeds, no packs), the Windows payload abb46d01 staged, the Setup on PC 2. The site: the home page at the edge since 19:58 (master 97951e6c: the one-click line, the four headings, the mission table, /docs, the finality row, the whole-machine sentence with the reconciled per-tier line; captures at 390 and 1440 px in both themes); the deploy's Vercel upload slow (6 min 30 s), not stalled; the workers page republished 20:08 with nine box rows (build-5 to 9 reading down for want of /srv/workers/sources; the mini without a relay id); the publish's 8.1 GB peak resident a class for the build-server lane's script. MAIN'S TWO QUESTIONS ON THE 20:1x LINE, ANSWERED (20:1x BST): "layer 8 off as the fifth flag" in ac86d7910 is the flag's existence in the generator (CLASS_V6_FLAG_NOWIN = 1 << 4), not a decision; the frozen object's served class string keeps layer 8 ON (class_v6_family_flags 0xf) until the knee rows read; PC 1 cannot run them tonight, so main's wording is taken early in the register (row 18) and the freeze note: "layer 8 off at stock PASS (the honest side within one run's noise, the chip side minus 4 to 11 percent, the acceptance 6.10 PASS); the knee rows owed; the layer re-entered by a new class if they fail, left out by a new class if they pass". Checkpoint 270's "63.6 percent" is against TOTAL weight (every key in the window, the unpeered and refusing nodes included); the rule is two thirds of the anchored table and of the sliding table and a lock prints only when both pass; the exact fractions asked of the node lane by 20:40 and carried beside the 63.6 so no reader takes a lock as formed under two thirds. The workers page: https://dl.igneum.network/fleet-22adafa34bc2/workers.html, workers.json generated 20:03 UK with nine box rows (build-5 to 9 "no facts from this box yet" for want of /srv/workers/sources), client-rendered with max-age 0; the mini joins on its relay id. +LOCK 270's EXACT FRACTIONS (the node lane, 20:2x BST, from the seed's log). The lock formed on the CERTIFICATE received at 19:51:37.391 ("certificate at index 270 received: 21 of 38 voters, weight 4979 of 7076"): the node re-tests a received certificate's signers against the current table and the anchored one (finality.rs evaluate, the certificate arm: lock_test(s, active, total) && frozen_test(&keys)); 4,979 of 7,076 is 70.4 percent of the sliding table's total weight (the inclusive two-thirds floor 4,717), the active test trivially (active weight 1,264, the presence window 20 blocks of a stalled chain), the anchored test on those 21 keys against the table frozen at lock 249 (total 7,146 minus the leaves) at or above two thirds, or the arm does not lock. The LOCKED line's "signed 4498 = 355.8% of active, 63.6% of total, 61.2% of the table frozen at lock 249 (4372 of 7146)" is the seed's OWN local vote sum (19 votes seen, votesSeen 19) printed whichever arm locked; the hand printed 4,617 (65.2 percent) for the same reason. No reader takes 270 as formed under two thirds: it formed on 70.4 percent of the sliding total and at least two thirds of the anchored table by the certificate's signers; "total weight" (7,076) is every key with 30-day window weight at the checkpoint, the unpeered and refusing nodes' keys included; the lock kind final. A 2.0.2 log item: the LOCKED line prints the fractions of the signer set the lock passed on and the RPC's signedWeight follows the same set. Layer 8's wording taken verbatim into the D1 record and the freeze note (the frozen object keeps layer 8 on, class_v6_family_flags 0xf, CLASS_V6_FLAG_NOWIN defined and off). + +THE 20:2x LINES (BST). The sixty-first landing on master at fc11a091. The AMD and Intel energy lane is main's own (ab6a7c716e8c61a2e), not the hash lane's: its branch amd-intel-energy at 84e08df5c (one commit on master 4ce5f36b, documents only: docs/analysis/class-v6/amd-intel-energy.md and its directory with three job scripts, ze-power.c, an offline-compile prelude and an ISA summary; pre-push on build-1 81 of 83, the two reds environment-only) ready at 20:2x ahead of 21:15, handed to the landing hand; its content: GPU-03's AMD and Intel cells (the window's rate cost 0 percent on the RX 7600, minus 0.3 percent on the Arc B580, measured), ECO-05's named cause decomposed (per 32 bits of bus the same watts, 0.21x to 0.47x the random reads), hash-identical kernel candidates ranked (0 to about 10 percent), every efficiency row labelled kernel throughput or serving per review B. The research lane's PC 1 dependency: the runner held by the withdrawn grid job (fetched before its 19:34 withdrawal, running to its 600-minute cap while it waits for the card to mine); the paired 2 GiB read takes its default (the morning's +4 percent at 2 GiB served as that run); the AMD lane's RX 7600 metered ADLX knee waits on it (the one measurement ECO-05's batch 02 turns on: a 7600 knee at or under about 5.4 microjoules adds one sustainable world and no more); batch 02 lands on the modelled 7.2 / 5.4 cells labelled modelled. The genesis dataset: no founder figure by 20:00, the default applied as his word (4 GiB, decided), told to the research lane for the 21:00 landing at 20:2x. ADV-07 (20:15): the 32-lane genesis comparator placed and routed on adv-g (717,268 cells; 4.80 pJ per lane-op at ASAP7, 4.17 to 6.28; 3.36 at N5, 2.42 at N3; k 0.33 same node, 0.24 a node ahead), a floor (routed at a 30 ns constraint, the unpipelined crossbar path 27 ns, the resizer downsizing every cell, 9 percent under its synthesis row where the 8-lane cores at 12 ns sat 32 to 42 percent over); the honest 32-lane band 3.36 to 5.7 pJ at N5, k 0.33 to 0.55; the complete machine at the 32-lane floor: the GDDR7 board 2.1x same node (1.7 to 2.4), 2.4x a node ahead (2.0 to 2.7); the SRAM die 4.2x / 5.7x; the same-node honest bracket across the adversary's choices 1.5x (the placed 8-lane 18-family core) to 2.1x (the placed 32-lane floor) on the DRAM board, 1.9x to 2.6x with the stored-half hybrid; P04 FAIL at both ends; document 1d443dda7. Floor lane 2's third joint row: the served line "1.5x to 2.1x for the complete machine, 2.0x to 2.9x for the board alone, same node, placed, both lanes" (a node ahead 1.8x to 2.4x and 2.45x to 3.3x), the 2.9x end the resizer-downsized floor until its placed core32 (flops, 1.5 ns clock; synthesised 5.55 pJ ASAP7, expected placed about 7.8, 5.4 at N5, 2.4x) lands by 21:00; the reasons: the convention 0.6 of the gap, the core 0.4, now lane count and the clock the core is sized to. The hash lane's suite on ac86d7910: the lib, the fuzz, the review tests and v6fold pass; five tests in tests/packs.rs fail on F03's generator 6 (the pinned reg64 and era packs exported at generator 5), a test-only fix (the comparisons reading the pinned pack's generator, a04's check reading the pinned program's own verdict) by 20:40 with the suite by 21:05; the prefix pack hl-v6-all-prefix.tgz on build-1 (id 0x4de7b836cc40a4ea, the same program at generator 6). The node lane's candidates: (c) 1a21d1ec six suites green on build-1 (core 184, consensus 143, exec 74, miner 30, p2p 38, pow 19 on the generator-6 tree), its pair reading the freeze line (fingerprint f9030d60fe850875 = ac86d7910's tree, class-v6-review), rule 19 pairing, the artefact and canaries following; (b) 83bb8ea6 on build-9 p2p-flows 38 and kaspa-pow 19 green, its pair built; the 2.0.2 chain on build-9. build-5 to build-9 on the workers page: /srv/workers/sources existed on none and no collector was installed (provision.sh does not install it); the build-server lane put the collector, lib and the igneum-workers unit (15 s timer) on all five by 20:13; the mini reports through the relay agent or the app's worker report (the founder's LAN machine, unreachable from any box). GOV-03: a same-box second build on build-8 reproduced igneumd byte for byte (6d03d096 twice), so the build-1 against build-8 difference is cross-box only (a build-path or host-id class, not nondeterminism); the --build-id=none try at 22:00. The update-return lane: the F14 relay-and-publisher half green (lab-signing-20 362633c5, full gate 83: the publishers sign by channel with the lab root or the OTA key and refuse a cross; the agent refuses tasks beside a public engine; release rule 16 written); the UX-01 batch refused twice by rule 26 and re-gating; the MINING-ON lines for 2.0.1 on the 20:55 entry. Lane D on INT-18: family-gate.md carries no economics and will not (a typed band would be the F09 fault); the row's owners the research and adversary lanes, lane D's file the acceptance evidence; the 6.11 landing refused twice by rule 26 on the harness-map page (the regenerated page dropping 25 hand-added lines), re-sent with master's copy verbatim; 6.12 on ac86d7910 on build-6 by 22:00. + +THE FOUNDER'S STOP (20:21 UK, through main): "STOP all these mess ups." Four tonight: a fix that did not compile announced as cut (777214af); a native AVX-512 gate build rolled as a fleet binary (79 hosts would crash); the workers page never published while he watched; fifteen Mac processes killed by a grep (the fourth kill-by-name breach today). From now, by construction, not by rule: (1) pkill and killall refuse on the Mac (a shim first in PATH, exit 97) and on every box by 20:45 (the build-server lane); (2) a fleet binary comes only from the shipper's cross-build kit at the x86-64-v3 baseline; a gate check scans kits for AVX-512 (the steward, 21:30); a sha is "cut" only when its binary exists on build-1 with its commit string read back; (3) nothing is published from the Mac except the site lane's one deploy script, which records its own pid before it starts; the workers page is the build-server lane's from build-1; (4) a slip is reported once with its cause and the new clock, never re-announced; no lane says "done" for anything it has not read back. Broadcast to every lane in those words at 20:2x; the standing text in CLAUDE.md with this landing. + A SHARED-DEVNET FACT FROM THE FLEET (not this lane's, with the shipper and the infra lane): the Hetzner live seed 188.245.5.161:26611 is still on the old override object (digest eada4bda) 1 h 40 min after the 0.3.20 sweep (the fleet never touches Hetzner nodes, so it was outside the sweep); the 0.3.21 wipe canary c22-1 took five digest-mismatch rejects from it; an app with the packaged peers is refused at the seed and syncs through node1 and the hub only, a fresh joiner with only the seed cannot join, the 14 voters and the hub are unaffected; the owner puts the floor file ov16-floor-900000.json (sha 294f1f80) and the c4459193 pin on it. 0.3.21's STAGING (the node lane): the order dry-merges onto 55768f88 with nothing moving to 0.3.22; the late-join fix is 52e96c94 (70e4601e rebased onto 55768f88, exec suite 33 green with both new tests); f067f7c1, b0444f51 and 437f0438 merge clean in order; 2e32d5f6's one conflict (DST_ADDRESS beside pool-finish's DST_BINDING in consensus/core/src/finality.rs) kept both; the live-file digest eada4bda after each (every switch at never); the staging waits on the shipper's sweep-end word; the re-pin held. PC 2 DOWN AGAIN (main, 16:5x UK): the founder takes PC 2 down for cable work (PC 1 back but his desk); both PCs out of the sweep's waves, each updates on its poller on return; no PC job to PC 1; the Windows G1 completed before the outage, nothing reruns. 0.3.21's SECOND GATE LINE on 55768f88 (sha256 279b1b690e854fc9): the ten-minute mixed-version gate beside the 5899f603 pair, 13:37:40Z to 13:47:52Z, SUMMARY PASS (one digest b0afb2ee on five nodes; 223 new and 381 old blocks accepted by the old hub, 0 rejected; counts equal at 319, 486 and 604 through both clean joins and the restart step at 13:45:22Z; no panic); the node lane's two lines on 0.3.21's first candidate complete, in plan 6.9 on ca3-v4-node; the fleet's set on it (the bare-child 12 GB line, the wipe, the kept read, the cases) is the fleet's. 0.3.21's FIRST GATE LINE on 55768f88 (sha256 279b1b690e854fc9, the string read back; pairing igneum-pow 8c728ca3 at byte 5): the digest gate 13:35:41Z to 13:37:19Z SUMMARY PASS (a89be8a7 on both binaries with the peers; db9a85f9 refused, no peer; the live file's eada4bda unmoved); the ten-minute mixed-version gate from 13:37:40Z, line about 13:50Z. The 0.3.21 order as the shipper sent it: 55768f88; f067f7c1 and 70e4601e; b0444f51; 6eb21fc9; db28d331; then the re-pin from 8bdcbdd8 on the coordinator's word; suites between, the digest read after every one; the mirror's release-0.3.20-node back at the pin c4459193, release-0.3.21-node open at 55768f88. THE LATE-JOIN COMMIT (N9's second half, the node lane): 70e4601e on the box mirror as branch proof-hold-fix, from c4459193, two files (igneum/exec/src/proving.rs, protocol/flows/src/v10/proving.rs); the gap was the fetch side on the joiner (the served record ran the native check against the joiner's trailing exec state before anything was stored, the check refused it, the proof was never held, the body rule read "not held" for 20 s and failed the IBD); the fix holds the proof by hash before the checks (the pool entry still needs them) and the serve side says when it holds fewer than asked; the exec suite 32 passed at 13:26Z with the known-failed shape first, the flows check green 13:28Z, igneumd on build-1 at the 0321 worktree path built 13:32Z, sha256 17649eeb2f7d1290, string read back; with the testnet lane (the resume form, B alone); it joins the 0.3.21 staging as its own commit. THE WIPE CANARY ON c19-1, c4459193 (sha 45be9b02d1b002f5, string read back): FORM END rc 0 at 13:50:53Z. Wipe synced 13:35:50Z (57 minutes, inside the 98-minute class); mining 13:36:00Z to 13:47:07Z, 66 mined, 66 accepted, 0 rejected, isSynced true at the tip throughout; the hub holds 41 of its blocks in its last 700 with 0 rejects (13:47:09Z); the restart on its kept datadir at 13:47:15Z: the old process stopped at once (the new process's first lock line seven seconds after the marker; the watchdog held nothing, the b7cc37e7 fault closed), synced again at 13:48:39Z after 84 s, 109 templates read with max 3,432 ms and 0 timeouts; the kept read on pool-1's 0.3.17 copy on the same pod passed at 13:38Z (the rewrite line once, a clean second start). The pin's set on c4459193: the digest gate PASS, the mixed-version gate PASS, the wipe canary PASS, the kept read PASS, the restart PASS, the 12 GB line proves and verifies (paid is a race, not a gate); CASES END from c20-1 (about 14:50Z) is the last pin line. THE INTEROP FACT stands from the void run: the 5899f603 hub accepted 235 object-byte-5 blocks from the 8097d600 node with 0 rejected, one digest on all five nodes on the live sixteen-field file. The gates: the digest test and the kaspa-pow vector test (the amended devnet epoch-0 id 1a4230699a6b9c60 must equal, c120d7963abdcd96 must differ, the v3 control unchanged) on the box; the mixed-version Devnet 2 gate (the amended 0.3.20 node beside a 5899f603 node for ten minutes on the live file without the v4 fields) after the Mac build; the fresh-join canary the 0.3.20 cut's | | Main's rulings (7 October, morning) | no generator change to v4 on the live devnet; the record's null is the window model with numbers, sent by the hash lane to the attack-pass lane so AP-F8-1 re-gates against it; a fault beyond the model (a low-entropy source at site 15) stops at the coordinator with the two options priced (a 0.3.19 class amendment before the flip, or the flip held at the floor), nothing shipping without the founder's word; the tighter tail, an acceptance bound on the hot-set share, is a CLASS V5 item (sent to the v5 lane a6410f3b8abefb762 with the 64-seed census as its gate; the bound's number follows from the model) | diff --git a/docs/plans/igneum-2.0-master/README.md b/docs/plans/igneum-2.0-master/README.md new file mode 100644 index 000000000..42aa8561b --- /dev/null +++ b/docs/plans/igneum-2.0-master/README.md @@ -0,0 +1,9 @@ +# IGNEUM 2.0, Complete Master Edition (8 October 2026) + +THE reference from 20:13 UK on 8 October 2026. It consolidates, in one 292-page document, the strategy text, the 37-page plan, the Test and Acceptance Standard (128 cases, 17 profiles), the additional closure requirements (18 INT integration gates and 44 R2 closure requirements, which overlap the 128 cases and are not 190 independent tests), and all three external reviews: R0 (the historical algorithm review), R1 (the full-system review, findings I01 to I10 and V6-01 to V6-11) and R2 (the updated-stack review, F01 to F14). Where the master and the earlier plan PDF or RTF differ, the master governs; it preserves them and preserves differing interpretations (REC-01, finality healing) without choosing. + +Reading order (page numbers of the PDF): master introduction 1 to 18; strategy 19 to 55; test standard 56 to 128; closure requirements 129 to 139; R2 140 to 198; R1 199 to 270; R0 271 to 288; evidence inventory 289 to 292. + +Files: igneum-2.0-complete-master.pdf (the light edition; the obsidian edition has the same substance), igneum-2.0-complete-master.txt (text extraction), traceability.json (the master traceability register: the original registry, the INT gates, the R2 closure requirements, the crosswalk, the unresolved interpretations, the claim), evidence/ (the companion's manifest, README, the R1 review with its results and harness, the R0 evidence). The six reviewed source archives are our own code snapshots of 8 October and are not duplicated here; their SHA-256 values are in evidence/MANIFEST.json. + +The claim the master makes: "A complete, independently substantiated technical/economic/operational/commercial pass supports a credible leadership-contender assessment, not a numerical rank certificate." Status: compilation only; no new technical tests were run for this edition. Missing or unrun evidence is not PASS; a defect reproduced by a probe is not a passed gate. diff --git a/docs/plans/igneum-2.0-master/evidence/04_full_system/IGNEUM_V6_Full_System_Review.md b/docs/plans/igneum-2.0-master/evidence/04_full_system/IGNEUM_V6_Full_System_Review.md new file mode 100644 index 000000000..ac15e641c --- /dev/null +++ b/docs/plans/igneum-2.0-master/evidence/04_full_system/IGNEUM_V6_Full_System_Review.md @@ -0,0 +1,2683 @@ +# IGNEUM 2.0 - Updated v6 full-system source review + +**Basis:** five supplied source archives dated 8 October 2026: v6 freeze tree, proving, Ember, node/DAG, and mining workers including the desktop driving engine and pool. + +**Assessment:** substantial implementation and a credible research programme, with specific opportunities to improve competitiveness. The highest-value next work is consistency of the release, proof/consensus correctness, reliable payouts, and accepted-and-paid GPU work. This review does not establish a numerical market ranking, a measured ASIC advantage, or mainnet readiness. + +## Read this first + +This is a scoped source review, not a completed security audit. I inspected the relevant generator, verifier, hosts, node admission/finality paths, pool and application scheduler. I did not independently audit every inherited GHOSTDAG component. No production network, funds or GPU settings were touched. Source presence is not proof of deployment or activation. + +The environment contains Python, Node.js and a C compiler, but not Rust/Cargo, CUDA/SP1 runtime or physical GPUs. **Native Rust tests, full-node experiments, SP1 verification and GPU timing were not run.** Tiny Python transcriptions reproduce the indicated decisions; they are not substitutes for native integration tests. + +The node and worker ZIPs were recovered from the user's Library after they did not appear in the current chat attachment list. This edition supersedes the interim three-package scope. It does not carry forward the claims that node enforcement, hosts or engine callers are absent. + +### Evidence classes + +- **Executed:** supplied JavaScript and C unit tests, checksums, source guards and explicitly identified Python models. +- **Static:** source/control-flow finding; possible consequences require the described native reproduction. +- **Team-reported:** supplied hardware measurements, incident records and adversarial cost models; not reproduced on hardware here. +- **Research:** an alternative architecture or optimisation that still needs measurement and adversarial evaluation. +- **Blocked:** missing dependencies, compiler, runtime, hardware or fixture prevents a result. Blocked is not PASS. + +### What actually ran + +| Check | Actual result | Boundary | +|---|---|---| +| Supplied C99 packfile test | 45 assertions passed, exit 0 | Synthetic metadata/seed/class/geometry/leaf fixtures; optional checked-in pack arguments were not supplied; no GPU | +| Supplied class-v5 JavaScript tier tests | 10 tests passed | Table/schema/selection tests, not v6 hardware performance | +| UI test attempt in the standalone Ember slice | Blocked by missing ui/app.js | Packaging coverage gap, not a demonstrated UI behaviour defect; expanded app remains a source subset | +| Supplied ELF/VK manifest integrity | Four SHA256 values matched | Not a rebuild, source equivalence, or proof verification | +| Frozen acceptance predicate | Reg64 shapes exclude the strengthened comparison | Python transcription guarded against the reviewed source | +| Ember choose/confirm logic | Three counterexamples retain rate-ineligible priors; controls exercised | Python transcription, not card measurements | +| Full-chain address identity | 16,384 static and 16,384 post-update equalities, zero mismatch | Exact subexpression alternative, not a complete hash or ASIC speedup | +| Proof verdict cache model | Warm/cold wrong-statement decisions disagree | Toy proof oracle modelling source branching; real proof/block test still needed | +| Finality anchor predicate | Pause-only rejects even 100% signatures after window | Native source inspected; Python predicate executed; current spec names a later fix | +| Pool crash ordering | A synthetic 100-unit debt can yield two distinct broadcasts | No signing, RPC or real funds; models the source's persistence ordering | +| Shard retry state | Transient failure leaves shard excluded for that session | Shard path only; segment retry exists | +| Memory geometry | Metal log2-only sizing is 1.5 GiB short for ds55 | Arithmetic and source inspection, not an observed GPU memory error | + +The full machine-readable outputs and exact source hashes accompany this document. + +## Executive priorities + +| Priority | Finding | Why it comes before headline hashrate | +|---|---|---| +| P0 candidate | I01 proof cache context | Consensus decisions must not depend on a node's cache history | +| P0 candidate | I02 pool payment durability | A crash or ambiguous RPC response must not duplicate or erase miner liabilities | +| P0 before finality activation | I03 anchor pause/recovery contract | A healed network must resume as specified; weaker recovery must not masquerade as the ordinary guarantee | +| Release gate | I04 release/class consistency; V6-01/02 | A research pack, census and live node must implement the same work definition | +| Operator gate | I05/I06 device memory and Metal geometry | Small cards must survive transitions and workloads, not only a benchmark | +| Security/product gate | I07/I08 Ember identity, privileges and pool sessions | Protect users' machine settings, keys and network-facing services | +| Economic gate | V6-11 strongest adversary | The team's own hybrid/SRAM cases still fail the broad coexistence claim | + +P0 candidate means I would block a value-bearing release until native reproduction and closure, not that I have executed an attack on a deployed network. + +## What is resolved or materially improved + +**V6 research is present.** The freeze includes reg64/reg64c, fold/rw, scheduling, tests and hardware records. The earlier V2-V4-only conclusion does not apply to this archive. + +**The earlier shadow omission is addressed.** Acceptance now includes the V4 shadow. Its new 64-register execution coverage is a different issue, not the old finding repeated. + +**The supplied node has actual proof enforcement.** The earlier absence of consensus verification source is no longer true. It has a concrete cache-context problem to close, rather than no implementation. + +**Nonce alignment is guarded by all three worker hosts.** CUDA worker.cpp:1208, Metal main.swift:3303 and OpenCL host.c:1783 reject misaligned jobs; CUDA also splits low-word rollover. This closes the missing-host uncertainty from the older review. + +**Proving-payment source changes exist on both sides.** Native/guest accounting changes are present. Rebuilt guest artifacts, verifier identities and activation remain distinct gates. + +**Negative experiments are published.** The team records failed coexistence and specialist cost cases. Those are useful engineering evidence and must not be replaced with the most favourable isolated result. + +## New findings from the node, hosts, application engine and pool + +### I01 - Proof-verdict cache omits application context + +**Class:** static source + source-guarded Python counterexample. **Priority:** P0 candidate. **Sources:** node/igneum/exec/src/proving.rs:1048-1081 and 1336-1379; node/igneum/exec/src/nativeverify.rs:163-176; node/consensus/src/pipeline/body_processor/body_validation_in_context.rs:20-79. + +`verdict_for` looks up `inner.verdicts[c.proof_hash]` before checking the held proof kind and before comparing its public values to `c.statement`. Cached success stores a program id, not all the context of the successful validation. The cold path does check the statement through `verify_kind`. The relay also seeds the verdict cache. + +A minimal source-branch model shows: + +| Record/context | Warm node | Cold node | +|---|---|---| +| Proof H was previously verified for statement A; current record uses H with statement B under the same accepted program id | VERIFIED from cache | INVALID on statement binding | + +Negative cached results can also suppress a later valid record for the same proof bytes. Kind mismatch is a further context dimension; distinct accepted ids may independently reject a cross-kind variant, so it is not required for the wrong-statement finding. + +**Limit:** this review has not constructed a signed carried record, generated a real proof or run the block through two nodes. Record admission, canonical statement checks and signatures still matter to exploitability. The cached/cold discrepancy is nevertheless unacceptable in a consensus verifier and needs a native test immediately. + +**Fix:** cache intrinsic proof validity together with the actual proof kind, verified public-value commitment and verifier identity. Check the current record's statement, kind, accepted verifier set and activation context on EVERY access. Alternatively use a complete context key. Do not context-poison the negative cache. Pin the verifier implementation/security version as needed. + +**Acceptance:** native positive proof fixture; warm/cold/restart/relay-order/concurrent queries produce identical verdicts, block acceptance and payouts for valid, wrong-statement, wrong-kind and wrong-activation records. One valid proof must not authenticate a different statement. + +### I02 - Pool broadcasts before durable accounting + +**Class:** static source + synthetic crash-order model. **Priority:** P0 before real funds. **Sources:** pool/src/payout.rs:164-259, 265 onward; pool/src/state.rs:133-158; pool/src/main.rs:123-150. + +The pool signs and calls `eth_sendRawTransaction`, then reduces the in-memory balance and marks state dirty. Persistence occurs separately. A crash after broadcast but before the next saved snapshot can restore the old debt. The next round reads a fresh pending nonce and can issue another transaction for that debt. An accepted RPC request whose response times out has the same ambiguity. This requires available funds; it is not a claim that money was actually duplicated. + +The model owes 100 units, broadcasts nonce 0, loses memory before persistence, restarts from the old debt and broadcasts nonce 1: 200 units sent for one 100-unit obligation. No actual chain calls occur. + +`State::load` additionally starts empty after malformed JSON or any read error, rather than distinguishing first run from corruption. Rename-based snapshots are useful but not a write-ahead transaction protocol. Receipt handling also needs explicit canonical/finality and reorg semantics, not just a one-time success receipt. + +**Fix:** transactional ledger and durable outbox. Reserve the exact debt, nonce, signed bytes and transaction hash durably BEFORE broadcasting. Retry the same signed transaction after an ambiguous response; reconcile nonce/receipt/canonical state on restart. Finalise liabilities only under the declared confirmation rule. Detect corrupt existing state and stop safely, restoring from verified backups rather than silently forgetting debts. + +**Acceptance:** fault injection before/after every persistence and RPC boundary, accepted-but-timeout, replaced transaction, reorg, corrupted snapshot, disk-full and process kill. No duplicate debit/credit/payment and no lost miner obligation. + +### I03 - Finality source, specification and recovery assurance must be reconciled + +**Class:** static source + predicate model; simulation figures are team-reported. **Priority:** before activating the new finality rule. **Sources:** node/consensus/src/processes/finality.rs:1090-1129, 3862-3899; spec/docs/spec/finality-guarantees.md:64-76, 89-115. + +**Part A: a specific stale-code mismatch.** With v4 active, recovery disabled and the anchor window elapsed, `anchored_test` returns false even for 100/100 anchored signatures. The supplied unit test explicitly expects a 99/100 case to fail. It is not simply a pause that ends when enough signatures return. + +Importantly, the updated specification ALREADY acknowledges this exact older fault and names `acd9d067` as fixing it: the two-thirds anchored path is to remain available at any time and recovery is an additional path. That fix is not the function present in this node ZIP. Do not interpret this as evidence the team has not worked on the fix; it is evidence the supplied code/spec pair is not one coherent freeze. + +**Part B: majority recovery has a genuinely weaker safety bound.** After the window, the recovery predicate allows strictly more than half of anchored weight (alongside current sliding-table requirements). For an illustrative 45% honest / 10% equivocating / 45% honest partition, both sides can assemble 55% of the old table if the equivocator remains eligible on both sides. The documentation explicitly reports recovery conflicts in corresponding long-partition simulations and acknowledges the weaker guarantee. This is not an undisclosed new attack or a full-network reproduction here. + +**Fix:** land the documented anchored-test correction in the actual release; reproduce healing beyond the window. Decide explicitly whether ordinary finality always preserves the stronger anchored quorum or whether a weaker recovery state is offered. Recovery labels, wallet treatment, inter-chain verification and voting rules must preserve that distinction. Slashing after reconnection does not retroactively make two conflicting irreversible labels consistent. + +**Acceptance:** real implementation, >window partition and healed >2/3 quorum, disabled/enabled recovery, equivocation on one/both branches, authority succession/strip, restart, contradictory certificate arrival order, and seed boundaries. Publish the fault assumptions; do not count a accelerated simulation as years of operation. Source flags alone do not prove activation on a live object. + +### I04 - Research v6 is not yet one end-to-end chain object in this package set + +**Class:** static source/version reconciliation. **Priority:** release blocker for a claim of integrated v6 readiness. **Sources:** node/consensus/core/src/igneum.rs:442-495; node/consensus/pow/src/igneum.rs:519-545; pow/src/accept.rs:487-492; docs/analysis/class-v6/census-packs.md. + +The research crate supports composable v6 flags. The supplied node's wire class enum and `pow_class_of` map only V2-V5. Its shown generation path applies the shadow setting but not the new reg64/fold/rw composition. Do not confuse the existence of v6 generated benchmark packs with an activated and agreed v6 consensus object. + +The census also uses a separate family-gate patch not present in the frozen acceptance predicate (V6-01). In the pool, the shown `EpochSeeds` initializer omits `shadow_reps` required by the supplied node type; the pool references its own absent vendored workspace, so this is a pairing inconsistency rather than an observed compilation failure. + +**Fix:** pin one release manifest covering node/worker/pool/app commits, class semantics, generation/acceptance schedule, exact dataset words, runtime capabilities, verifier/guest identities, fee/finality activation and tuner profiles. Freeze program and dataset semantics rather than infer them from coarse names. + +**Acceptance:** the same header, nonce and pack yield identical work across the native CPU verifier, every supported GPU backend and the pool; changing any binding field either gives the specified new result or is rejected. Test before/at/after every activation. No unshipped harness patches or private symlinks. + +### I05 - Small-memory workers need an explicit cold epoch transition + +**Class:** static allocation path + arithmetic. **Priority:** operator availability. **Sources:** workers/proto-cuda/nvrtc/worker.cpp:872-879, 1180-1235, 1295; node/igneum/miner/src/main.rs worker timeout path. + +The CUDA worker builds a new cache/dataset pair while retaining the current pair. When background preparation fails, the shown foreground `buildPair` fallback still retains the current allocation. For ds55, two datasets alone need 11 GiB, before caches, buffers and runtime. This cannot fit an 8 GiB card. Assuming 256 MiB caches, the pair total is at least 11.5 GiB, making a 12 GiB device a tight, implementation-dependent case rather than guaranteed coexistence. + +The miner supervisor has timeout/restart recovery, so this is not claimed to be permanently unrecoverable. But relying on timeouts and process restarts for routine epochs sacrifices availability and makes tuning/proving coordination harder. + +**Fix:** select warm preparation only when the reserved memory budget permits it. Otherwise stop/drain work, release the old allocation and build the new pair deliberately. Separate reusable cache lifetime from dataset lifetime when semantics permit. Confirm actual device free memory before admitting work; pausing a kernel does not release its buffers. + +**Acceptance:** real 8/12/16 GiB cards, full memory pressure and display use, repeated hourly/family/dataset transitions, foreground recovery, overlapping proof request, cancelled prepare and crash. Every nonce must use the correct epoch; no stale work passed as current. Record accepted-work downtime and rebuild energy. + +### I06 - Metal host uses log2 allocation where ds55 requires an exact word count + +**Class:** static source + exact arithmetic. **Priority:** cross-vendor correctness. **Sources:** workers/proto-metal/main.swift:3133-3205; workers/proto-cuda/nvrtc/emu/packfile-test.c; workers/proto-opencl/host.c:238-244. + +The Metal host sets `words = 1 << datasetLog2`, allocates `words * 4` and dispatches the corresponding item count. It does not use `IGNEUM_DATASET_WORDS` on that path. A ds55 header has 1,476,395,008 words but a floor log2 of 30: the path allocates 4 GiB rather than 5.5 GiB, a 1.5 GiB difference. + +CUDA's supplied C pack loader explicitly supports the exact word count; its ds55 fixture passed here. OpenCL also has an explicit word-count path. This is a backend difference, not a blanket claim that every host is broken. A preceding class/capability rejection or pack self-test may stop execution; no Metal out-of-bounds access was executed in this review. + +**Fix:** one normative pack-geometry parser or shared conformance vectors; allocate/build/hash from exact counts, use sufficiently wide integer arithmetic, and reject unsupported pack semantics before GPU launch. Require head/tail and random reference checks on every backend. + +**Acceptance:** ds55/ds85/ds115, power-of-two legacy sizes, wrong count/log2, malicious sizes/overflow, missing leaves, and checked-in generated packs. Passing CUDA metadata tests does not certify Metal execution. + +### I07 - Ember needs eligibility-first decisions, workload-aware priors and privileged-state ownership + +**Class:** static source + existing Python counterexamples. **Priority:** operator trust/security. **Sources:** app/src/ember.rs:549-608; app/src/engine.rs:1883-1902, 3937-3957; app/src/powertask.rs:113-142, 184-267. + +A 1%-tolerance confirmation can retain a 98 MH/s prior although a 100 MH/s neighbour makes the admissible floor 99. `choose` correctly selects the eligible row; `confirm_verdict` keeps the old row unless efficiency also improves. The difference is a rule bug, not a GPU speedup claim (V6-04). + +The actual driving engine confirms the coarse `loads/wide` workload label used for fleet priors (V6-05). Reg64, dataset size, prover mode and compiler changes can alter the right operating point without changing that label. + +The helper launches elevated work from paths requiring an actual Windows ACL/signature review. The engine's `restore_power_limits` prepares command text but only logs that limits remain until reboot. The full source therefore resolves the earlier missing-engine uncertainty: this path does not restore settings on quit. No Windows exploit or physical device failure was executed. + +**Fix:** rate eligibility before efficiency; stable semantic/mode fingerprints; isolated per-device tuning and leases; minimal protected helper with authenticated commands; restore only settings owned by the lease on off/exit/heartbeat failure; do not overwrite an independent user change. The main GUI should remain unprivileged. + +**Acceptance:** native counterexamples, sensor loss, noisy rows, driver changes, GPU hot removal/reordering, competing control software, abrupt GUI/helper kill, malicious stale command, real ACL checks, thermal abort and multiple devices. An explicit user preference to retain limits is different from misleading automatic restoration. + +### I08 - Pool session identity and network resource bounds are unfinished + +**Class:** static source, no live network abuse. **Priority:** before a public value-bearing pool. **Sources:** pool/src/protocol.rs:42-53; pool/src/server.rs:53-151. + +The authorization message has a `binding` field, but v0 documents it as unused; the server pattern drops it. It verifies the BLS proof of possession, not a fresh session-bound proof over the server challenge, chain and payout address. A static PoP is not evidence of current possession for this specific session. This does not itself prove theft of previous balances or free mining work. + +The server also uses an unbounded outbound channel and only checks maximum line length after `lines().next_line()` has accumulated a complete line. The buffer's initial capacity is not the maximum frame size. A TLS terminator may add transport protection, but its unprovided limits cannot be assumed to close application framing or identity gaps. + +**Fix:** authenticate a fresh challenge bound to this session/server, network, key, payout and expiry (with TLS/exporter binding where specified). Bound frame growth while reading, per-connection queues, connection count and expensive validation jobs. Reject repeated/invalid authorization safely, provide backpressure and preserve operator vote/template control. + +**Acceptance:** replay a public PoP into a different session/payout and reject it without a fresh authorization; wrong-server/chain; slow partial lines, oversized frames, stalled reader, connection storm and expensive invalid shares under controlled load. No pool outage or memory growth beyond approved budgets. + +### I09 - Fail-closed proof activation and real proof-fixture coverage + +**Class:** static source. **Priority:** security/coverage gate. **Sources:** node/consensus/src/pipeline/body_processor/body_validation_in_context.rs:27-50; node/igneum/exec/src/nativeverify.rs real-proof test paths. + +The activated body path returns success when no proof oracle is installed and retains an environment-controlled skip intended for tests. These are not attacker-controlled network fields; no remote bypass is asserted. They should nevertheless not silently disable an advertised guarantee in a production build or misconfigured startup. + +Some real-proof unit tests return early when external fixture files are missing. A green unit runner can therefore mean the positive proof case was not exercised. The current environment cannot run them anyway. + +**Fix:** production startup must require the configured oracle and pinned keys whenever the network object activates the rule. Compile deliberate bypasses only into explicit test harnesses. Missing mandatory fixtures should produce a blocked/failing gate rather than a silent successful return. Exercise valid current proofs and every invalid binding cold and warm, with minimum-node CPU/memory budgets. + +### I10 - Shard failures are remembered as completed attempts, not recoverable work + +**Class:** static source + Python state-transition model; supplied fleet outcomes are team-reported. **Priority:** realised operator earnings. **Sources:** app/src/prover.rs:79-90, 362-375, 625-721; V6-07/V6-08. + +The shard branch marks `(block, shard)` attempted before input export/proving. A transient error leaves that marker in place, and subsequent `choose` calls exclude the shard for the session. This is not a claim that all retries are absent: segment handling has separate held-work retry logic and receipt checks. + +The shown proving launch also starts a separate host without a demonstrated mining-allocation-release acknowledgement in that path. Package documents record why that matters on 8/12 GiB cards. Environment and a server may select the device; neither establishes a coordinated memory reservation by this scheduler. + +**Fix:** persistent job states for discovered/reserved/exported/proving/verified/submitted/accepted/paid, with failed-transient, expired, cancelled and lost-race states distinct. Reconcile node/pool status before retry; reuse identical proof bytes where safe; bound retries/backoff by deadline and expected return. Admit the job only after a per-device memory lease is acknowledged. Cancel or stop acquiring work during obsolete-parent/finality/queue conditions as the protocol permits. + +**Acceptance:** export timeout, accepted-but-lost-response, server restart, expired assignment, parent change, competing winner, app restart and device OOM. No duplicate payout claim, no permanently skipped recoverable shard, and all consumed GPU time accounted for. + +## Important v6 / proving findings retained and corrected + +The following twelve detailed findings originated in the initial three-package review. They are retained with the node/host/engine scope corrected above, not asserted as still missing code. The combined priorities are the table at the start of this edition. + + +### V6-01 - The census and frozen acceptance rules do not match + +**Evidence:** static source plus a Python predicate transcription. **Priority:** release-blocking evidence/consensus-version reconciliation, not a demonstrated live attack. + +`accept.rs:487-492` clears era, shadow, state, fold and rw before comparing with the V4 shape. It does not clear reg64/reg64_chain. Therefore the reg64 and reg64c classes do not enter that shape. The same omission occurs in the generator's load-source rule at `generator.rs:1654-1655`. + +Consequences of that exact predicate include: +- `check_fresh_sources_v4` returns without running its stronger rule. +- The saturated-source / distinct-index / hot-item checks behind the shape predicate are not selected. +- The attempt cap becomes 32 rather than 256. +- The shape-gated last-resort path is not selected. + +This does NOT mean all acceptance checks disappear, or that an exhausting epoch / profitable attack was observed. + +The census document expressly uses `harness-family-gate-v5-3dc3117c.diff` and `IGNEUM_FAMILY_GATE`, which clear additional flags. That patch is not in the supplied freeze implementation. Its PASS rows cannot be promoted into certification of a different rule. + +**Closure:** decide one versioned v6 generation/acceptance contract; merge/review the necessary implementation; regenerate every program ID/vector and rerun the census using exactly the shipping crate without an unshipped gate patch. Version changes rather than silently altering historical validation. Add native regression tests for all flag combinations, rejection reasons, caps and deterministic last-resort paths. + +### V6-02 - New execution is 64-register; the acceptance model and generic counters are not + +**Evidence:** static source, schedule arithmetic. **Priority:** release-blocking coverage and measurement integrity. + +The updated acceptance interpreter does include shadows, but allocates eight registers and walks `p.instrs`, not `p.scheduled()`. The actual verifier allocates `program.registers()`, runs the interleaved schedule and uses full-chain address mixing. `check_window_liveness` exists but is not called by the ordinary `check` path. The base-only acceptance model is documented in some research comments; it must not be mistaken for a direct measurement of the whole new hash. + +For a 16-load reg64 base, `loads_per_hash()` reports 128 while the executed schedule contains 256 loads over eight iterations. `bytes_per_hash()` likewise reads the unscheduled base. The emitter's nested reg64 metadata separately uses the correct schedule, so this is inconsistent reporting, not proof that every published model uses the wrong count. Dataset byte demand also differs from physical memory transactions/cache misses. + +**Closure:** share the instrumented semantics or explicitly separate base-program guards from mandatory real-v6 validation. Make every metric name its exact schedule and memory model. Assert top-level/nested counters agree. Test the actual dataset geometry and state-keyed access distribution, not only a closed-form proxy. Finish the live-dataset window-pack F8 run identified as owed in the census. + +### V6-03 - All-register dependence is not a hardware-cost lower bound + +**Evidence:** algebraic identity with 32,768 executed equality checks. **Priority:** adversarial hardware experiment, not an exploit. + +The full-chain address source is `r[a] XOR m`, where m rotate-XOR folds all registers except a in increasing order. Define, for 64 registers: + +``` +u[k] = ROTL32(r[k], 63-k) +P(a) = XOR of u[k] for k < a +T = XOR of every u[k] +address(a) = r[a] XOR ROTR32(P(a),1) XOR T XOR P(a) XOR u[a] +``` + +Why the identity holds: registers before the omitted position have exponent `62-k`; registers after it have exponent `63-k`. The first group is a one-bit right rotation of its u-prefix. The source's direct term is added separately. + +A maintained XOR prefix structure can compute that address without scanning all 63 other values on every load. The supplied harness uses a Fenwick tree and updates it after arbitrary register writes. It still retains state and adds metadata, update work, ports and routing; maintaining it through the many shadow writes may make it worse. No ASIC area/energy advantage or GPU speedup is claimed. + +**Closure:** price this exact alternative, compiled common-subexpression reuse and other state representations against the direct fold. Require proof of actual cost, not just that flipping each register can influence a load. Keep the separately rejected `cs64s27x16` experiment separate from this algebraic comparison of the existing reg64c operation. + +### V6-04 - Ember can keep a prior that violates its requested rate floor + +**Evidence:** static code plus five Python-transcribed scenarios. **Priority:** fix before automated v6 tuning rollout. + +`choose` restricts eligible points to the selected throughput tolerance. `confirm_verdict` only requests a full tune when the chosen alternative also improves efficiency by over one percent. + +Example at a one-percent rate tolerance: + +| Point | MH/s | W | MH/W | +|---|---:|---:|---:| +| Existing prior | 98 | 100 | 0.9800 | +| Neighbour | 100 | 103 | 0.9709 | + +`choose` selects the neighbour because the prior misses the 99 MH/s floor. `confirm_verdict` returns Keep(prior), since the neighbour is less efficient. A deliberately larger 50-versus-100 MH/s example and a MaxRate example also expose the rule. + +**Closure:** separate rate eligibility from efficiency improvement. An ineligible prior triggers retuning regardless of efficiency gain. Decide a safe temporary compliant point; do not leave the invalid prior indefinitely. Preserve the distinction between a conscious Efficiency goal and Balanced/MaxRate. Add native regression assertions and realistic noisy-measurement tests. + +### V6-05 - Tuning identity does not identify the workload finely enough + +**Evidence:** static helpers AND the supplied app-engine caller. **Priority:** before reusing fleet priors across v6/proving. + +`program_class(loads, wide)` returns only `l{loads}w{wide}`. `prior_key` adds model and driver-major. That is not enough by itself to distinguish dataset size, reg64/fold/rw semantics, prover mode, kernel/compiler version, or memory concurrency. The package's shipped tier table is expressly class v5. The additional engine confirms the call: app/src/engine.rs:3937-3957 assigns program_class from only loads and wide. This is no longer a missing-caller question. + +**Closure:** use a versioned workload fingerprint covering consensus class and dataset geometry, stable kernel/compiler/prover configuration, GPU UUID/capabilities and driver compatibility. Do not force a full retune on every harmless hourly seed if a validated compatibility family suffices. Invalidate on material resource changes. Store separate modes for mining, proving, aggregation and supported concurrency. + +### V6-06 - Privileged helper path and recovery require a security gate + +**Evidence:** static source; Windows execution/ACLs not tested. **Priority:** security release gate, not a demonstrated compromise. + +The task uses the highest run level and executes the application binary. The preferred candidate is under LOCALAPPDATA/Programs. The reregister path writes a PowerShell file into the user-profile sweep directory and executes it elevated. Digit-only command arguments prevent one injection class but do not establish integrity of a replaceable executable or elevated script. The package lacks installer ACL/signature and platform resolution evidence needed to close this. + +The helper exits on quit, remove or 20-minute idle without restoring device settings in this function. The supplied engine now resolves the earlier uncertainty: app/src/engine.rs:1883-1902 builds restoration commands but only logs that limits are left in place until reboot. It does not execute those commands on this path. Forced process termination, task time limits, stale commands and app crashes still need tests. Bare quit/remove bypass the sequence guard; stale-control-file handling must be tested against actual callers. + +**Closure:** a minimal privileged helper in an administrator-protected location; restricted authenticated IPC, protected executable/script loading, update signature checks, per-device command ownership and a crash-safe lease. On lease loss restore the settings the lease owns, including memory and core clocks and power, without clobbering independent user controls. Validate ACLs and kill/restart behaviour on Windows. Never execute an elevated script from a writable staging location. + +### V6-07 - The actual memory floor requires a mode scheduler, not a coexistence slogan + +**Evidence:** team-reported physical-card rows; patch source inspected. **Priority:** operator product and measurement gate. + +The new coexistence document reports: +- RTX 3060 12 GB: miner 6,129 MiB + compressed prover 7,525 MiB; together the prover fails allocation. Proving alone verifies in 13.2 seconds. +- RTX 4060 8 GB: miner 6,116 MiB + compressed prover 7,532 MiB; together fails allocation. Proving alone verifies in 8.2 seconds. Power on this host was unavailable. + +Those are two source-reported workload points, not universal proving times. The earlier 37.5-second simultaneous result used a much smaller mining dataset. Larger-card coexistence requires its own measured row. + +The floor patch picks default limits from total device capacity, not a reservation of currently free memory. Its small-card default element threshold is 2^27; the cited successful compressed rows explicitly set 2^26. That difference does not prove the default always fails, but a test made with one configuration does not certify the other. The recursion-allocation budget function currently returns the same constant in both branches. + +**Closure:** atomic VRAM reservations covering the full shard+aggregation path, explicit release/offload of the mining dataset before proving on constrained cards, headroom for display/driver/runtime, a pinned memory profile per workload and measured transition costs. A stopped kernel can still hold allocations; prove the memory is actually available. Do not rely solely on total VRAM or a shell override absent from the normal job path. + +### V6-08 - Proof-to-payment reliability is the biggest realised-performance opportunity + +**Evidence:** supplied incident/measurement log, not rerun here. **Priority:** main commercial and small-operator validation gate. + +The documented window is disrupted Devnet 3, not a clean final-v6 performance run. It reports 93 paid segments, a 336-second median and 720-second p95 claim-to-paid time, and no paid transaction from the declared 150 tx/s hold. The 3060 tier has 313 claims and zero paid segments; its 34 submitted segments were after the stall. The source reports approximately 70 card-hours on unpaid work and 4.1 on paid work, dominated by partition/stall losses, with pre-stall waste around three-to-one. Do not extrapolate that full-window ratio as steady-state energy efficiency. + +The report separately records package-link failures (subsequently fixed), proof-string-size failures, moved parent chains, missed deadlines, competing winners, and no retry lines. Each needs a separate metric and remedy. + +**Closure:** capability- and deadline-aware assignment; smaller verifiable paid tasks for constrained hardware where economical; optional separation of shard production and aggregation without granting aggregation finality authority; restart-safe task state and bounded retries for transient faults; idempotent submission; a chain-health/backpressure gate; bounded binary/chunked proof transport; preflight package integrity and dependency checks. Any protected reservation must resist claim-and-abandon griefing and restore open recovery when the lease expires. + +**Important measurement correction:** the report says the worklist is bounded near 600 because jobs expire, proved or not. Queue size alone cannot certify throughput. Use flow conservation: + +``` +closing backlog = opening backlog + arrivals - verified completions - expiries - cancellations +``` + +Report each departure category, lost-work energy/time, all-job deadline success and paid work separately. Do not report success latency only for winners without the loss rate beside it. + +### V6-09 - Proof verification improved; minimum-node and activation evidence still needed + +**Evidence:** host AND node source, checksums, team-reported node tests. **Priority:** mainnet/security gate. + +The host's shard and segment verify paths use pinned keys, real `LightProver` verification, public-value commitments and program checks. The enforcement spec describes both block admission and payment locks and reports a real-proof activation-boundary test. This supersedes the blanket earlier interpretation that no enforcement closure work exists. + +The later node archive includes real body-admission and payout enforcement code. That closes the earlier missing-source limitation, but introduces the cache-context finding I01 and configuration gate I09 below. The supplied subset still does not permit an independent full native build here. The full positive case (valid proof of the harness chain is accepted and paid exactly once) must accompany negative forged-proof rejection across each intended key/fee transition. + +The spec reports a cold compressed verify around 0.668-0.710 seconds on one loaded server core, and discusses up to ten cold proofs in a block. It explicitly notes that smaller validators can fall behind. Relay caching is not a worst-case capacity guarantee when proofs first arrive with a block. + +**Closure:** test worst-case valid and expensive-invalid proof payloads on the minimum supported validator, without a warm relay cache; consensus-safe limits and memory budgets; limits before deserialising external bytes; deadline/backpressure behaviour; appropriate amortisation/aggregation only after soundness review. Pin and check the full network object, then run before/at/after activation on unmodified validators. + +### V6-10 - Proving fee changes are in source, but source/ELF/wire format must be pinned together + +**Evidence:** static source, tests present but not run, manifest dates/hashes. **Priority:** activation/build gate. + +The document says the guest fee mirror is owed. The actual executor contains `proving_payment_split` and pool credits in both normal and over-budget branches, with a host regression test for the new flag. Therefore the correct status is source implementation present, not no implementation. + +The supplied ELF manifest remains pinned_at 2026-10-05. Its four hashes match. The normal host build intentionally does not rebuild guests. The newly added FixtureEnv flag is part of a bincode input read by the guest. None of those facts alone demonstrates the packaged ELF matches the current source and input layout. + +**Closure:** deterministic rebuild and repin; versioned guest input format; genuine compressed proofs with the new host on old and new fee modes; equality with the node's native state/receipt outputs; fee rounding, aborts, duplicate payments and succession-window cases. Do not activate from a passing native test alone. Conversely, do not infer an observed binary mismatch solely from the manifest timestamp. + +### V6-11 - The latest hardware report does not yet support the broad coexistence statement + +**Evidence:** team-reported model, not physical silicon. **Priority:** central research/economic acceptance gate. + +The late placed-core table (design section 10.0r) reports the full GDDR7 machine at about 1.6x against the 5090 at the same node and 1.9x a node ahead, with stated ranges and wider advantages against the cohort card. It separately concludes that the success conditions fail for an already-funded SRAM die and for the stored-half hybrid on dollar conditions. It is incorrect to promote the pure DRAM comparison into a result against every plausible specialist. + +The same record credits no automatic retirement from the published family bank. That is an important improvement in modelling honesty. + +**Closure:** independently challenge the feasibility and cost of the strongest surviving design: memory density/yield, die area, interconnect, packaging, ports, realistic activity, unit volumes, board/host overhead and matching GPU acquisition/resale assumptions. If the adversary survives, redesign the cheapest dominant advantage or narrow the supported competitiveness conditions. Do not reinstate high development cost or fictional expiry to hide it. + +The already-rejected larger instruction-memory, FP and connected-state variants should remain controls. The archive's baseline shadow block is not automatically identical to the separate longer-program proposal that was killed. + +### V6-12 - A single release evidence manifest is now essential + +**Evidence:** package scope, independent fingerprints, stale prose, missing dependencies. **Priority:** before calling the system frozen or independently reproducible. + +Make one signed, versioned release manifest bind: source and lockfile hashes, generated class/parameters, dataset identity/geometry, acceptance version, kernel and host binaries, supported devices/driver assumptions, prover server patch/version, memory thresholds, guest ELF/VK IDs, node proof/fee activation floors, and tuner compatibility identity. + +Test the complete accepted-and-paid path from a clean install on independent machines with no unpublished files, symlinks or shell overrides. Preserve old experiment logs but do not let their status label the new object. + +Additional carried-forward closures: the custom FNV-derived input seeding and 64-bit output fold still require a scoped cryptographic/binding review; this review does not exhibit a cryptographic break. The subsequently supplied CUDA, Metal and OpenCL job hosts DO enforce 32-aligned starts/counts; the earlier missing-caller concern is closed at those entry points. Preserve native rollover and tail tests. Generated low-level wrappers can still document or enforce their own contract defensively; do not claim the production hosts lack it. Add end-to-end artifact authentication rather than equating metadata coherence with executable correctness. + + +## Recommended engineering sequence + +### 1. Establish one executable release contract + +Pin the node, generator/acceptance crate, worker hosts, pool, app, proof server, guest ELF/VKs and network object. Resolve the census patch, full scheduled metrics, v6 wire semantics, finality correction and geometry discrepancy. These source subsets are not a build/activation certificate. + +### 2. Close correctness and money-handling gates before tuning for publicity + +Fix and natively reproduce I01, I02, I03, I08 and I09. Minimum deliverables are cache-invariant proof decisions, durable exactly-once debt accounting, documented long-partition behaviour, authentic pool sessions and bounded inputs. Apply test changes on an isolated devnet, not a live fork experiment. + +### 3. Make the GPU a managed resource shared by mining and proving + +One device owner admits kernels, old/new datasets, proving and aggregation against measured memory headroom. It handles warm versus cold transitions, per-mode tuning, safe cancellation, leases and power restoration. Scheduling should maximise legitimate expected net earnings within user constraints, not kernel utilisation alone. + +### 4. Optimise accepted-and-paid work, not a displayed peak + +The shown CUDA serve path copies every 64-bit result to the host and filters there (worker.cpp:1254-1291). Evaluate target filtering and bounded candidate compaction on-device, while keeping reference/diagnostic paths and overflow handling. Cache compiler outputs with exact semantic keys and verify them; amortise reusable allocations; profile register pressure/occupancy on the final workload. These are candidates, not promised speedups. + +At 100 million hashes per second, returning eight bytes per hash is 800 MB/s of result data before overhead. This arithmetic does not establish the bottleneck; measure wall time and accepted-work improvement. A small fast benchmark is not proof of better paid-work economics. + +### 5. Attack the best remaining hardware alternative + +The team's latest pure-DRAM estimate is more favourable, but its own SRAM/hybrid models still fail central cost conditions. Independently test feasibility and pricing rather than treat either the best or worst model as established silicon. Price alternative register-fold implementations and memory access concentrations on the exact shipping work. Keep failed FP/long-program experiments out unless a new falsifiable reason justifies them. + +### 6. Earn the leadership comparison + +Run the 2.0 acceptance programme on the corrected release with contemporary peer comparisons, independently operated machines, repeat non-subsidised customers, and sustained telemetry. This scoped review supplies additional gates; it does not mark the existing 128-test standard complete or certify a rank. Commodity access, security, operator margins and demand are separate requirements. + +## Additional regression gates for the 2.0 registry + +All entries below are **PROPOSED / NOT RUN as full-system tests**. The small models already executed are described separately. + +| ID | Required closure | +|---|---| +| INT-01 | Real proof H cannot authenticate a different statement under a warm cache. | +| INT-02 | Warm/cold/relay/restart/concurrent cache order does not change block or payout decisions; negative cache isolated. | +| INT-03 | Durable payout outbox survives every crash/RPC boundary without duplicate or lost liabilities. | +| INT-04 | Corrupt existing pool state, disk-full and reorg cause safe recovery, not silent empty balances. | +| INT-05 | The supplied finality implementation matches the approved anchor rule after >window healing. | +| INT-06 | Recovery tests state and preserve their weaker fault bound; interfaces never label it as a stronger guarantee. | +| INT-07 | One v6 object agrees in node, pool, CPU verifier and each supported GPU host across activation. | +| INT-08 | Census, production acceptance, schedule counters and live-dataset tests use the identical frozen contract. | +| INT-09 | Eight- and twelve-GiB epoch transitions recover deliberately without relying on repeated OOM/watchdog cycles. | +| INT-10 | Metal/CUDA/OpenCL exact dataset geometry agrees; unsupported packs reject before launch. | +| INT-11 | Only a memory-reserved proving job launches; mining buffers really release when required. | +| INT-12 | Transient shard errors can retry safely; expiration, loss and paid work remain distinct durable outcomes. | +| INT-13 | Ember cannot retain a rate-ineligible prior; material workload changes invalidate incompatible profiles. | +| INT-14 | Protected helper and per-device leases restore owned settings on normal/abnormal exit; real ACL/security tests. | +| INT-15 | Public PoP replay is not session authorization; payout/server/network binding enforced. | +| INT-16 | Pool parsing/queues/connection and crypto budgets remain bounded under controlled adversarial traffic. | +| INT-17 | Missing oracle/keys/mandatory real-proof fixture blocks the applicable production acceptance gate. | +| INT-18 | Whole-system economics pass the strongest feasible adversary, including sunk development and multi-epoch survival. | + +## Source roots and provenance + +Abbreviations used in source references: + +- `pow/` = `igneum-v6-freeze-tree/igneum-pow/` +- `docs/` = `igneum-v6-freeze-tree/docs/` +- `proof/` = `igneum-proving/proving/igneum-prove/` +- `node/` = `igneum-node-dag/node/` +- `spec/` = `igneum-node-dag/spec/` +- `workers/` = `igneum-mining-workers/` +- `app/` = `igneum-mining-workers/app/igneum-app/` +- `pool/` = `igneum-mining-workers/pool/` + +The original standalone Ember source and the later app's ember.rs match. Duplicate uploads of the original three archives match byte-for-byte. + +- `igneum-ember-2026-10-08(1).zip`: `c219211b49fccda65b151df230b10ded5971ac2a8c7d1e5847c0a68bffe4cf4a` (78,946 bytes) +- `igneum-mining-workers-2026-10-08.zip`: `808abcecf157a3716d1c72fa6e76c540bf5808af1c0e4dd0fd888576d546cade` (6,090,014 bytes) +- `igneum-node-dag-2026-10-08.zip`: `ead2cf94092b7e27aab2e44d653b2d969cb2a52878ef12abf6e5d7a9e7421cff` (1,519,903 bytes) +- `igneum-proving-2026-10-08(1).zip`: `9ccf4112e274f586392e8e4a4f98ece2e82b4990fe5f1ee89ae0ee0a151ce01e` (1,612,294 bytes) +- `igneum-v6-freeze-tree-2026-10-08(1).zip`: `f448981b2ceeab2e59e8bbd137a1a13ea1c730ecd9db72b9a89bd2bbf5d85acb` (696,492 bytes) + +## New integration source excerpts + +### I01 proof cache + +`node/igneum/exec/src/proving.rs:1046-1081` + +```text +1046: /// The consensus body rule's question (0.3.16): the cached verdict, else the in-process verify of the held +1047: /// proof bytes under the pinned key for the record's kind, else Missing. The verify runs outside the pool lock. +1048: pub fn verdict_for(&self, c: &kaspa_consensus_core::proving::CarriedProof, keys: &crate::nativeverify::Keys) -> kaspa_consensus_core::proving::ProofVerdict { +1049: use kaspa_consensus_core::proving::{ProofKind, ProofVerdict}; +1050: let accepted = self.cfg.accepted_ids(c.kind, c.carrier_daa); +1051: let held = { +1052: let inner = self.inner.lock(); +1053: if let Some(v) = inner.verdicts.get(&c.proof_hash) { +1054: return match v { +1055: Ok(id) if accepted.is_empty() || *id == B256::ZERO || accepted.contains(id) => ProofVerdict::Verified, +1056: Ok(id) => ProofVerdict::Invalid(format!("{}: verified under program id {id}, which the carrier's epoch at DAA {} does not accept (accepted: {})", c.label, c.carrier_daa, accepted.iter().map(|i| i.to_string()).collect::>().join(", "))), +1057: Err(e) => ProofVerdict::Invalid(e.clone()), +1058: }; +1059: } +1060: inner.proofs.get(&c.proof_hash).map(|(k, b)| (*k, b.clone())) +1061: }; +1062: let Some((kind, bytes)) = held else { return ProofVerdict::Missing }; +1063: if kind != c.kind { +1064: return ProofVerdict::Invalid(format!("the proof is held as a {kind:?} proof and the record carries it as a {:?} record", c.kind)); +1065: } +1066: let started = std::time::Instant::now(); +1067: // in-process on Unix; through the installed host on Windows (sp1-jit does not build there) +1068: let r = if crate::nativeverify::IN_PROCESS { +1069: crate::nativeverify::verify_kind(keys, c.kind, &bytes, &c.statement, &c.label, &accepted) +1070: } else if let VerifyMode::Command(host) = &self.cfg.verify { +1071: // the host pins one pair, the one it names at start (`cfg.shard_program_id` / `aggregator_id`, zero when unnamed) +1072: crate::nativeverify::verify_via_host(host, c.kind, &bytes, &c.statement, &c.label).map(|()| self.host_pair_id(c.kind)) +1073: } else { +1074: Err(format!("{}: this build has no in-process verifier and no verifier host is configured", c.label)) +1075: }; +1076: info!("[igneum-exec] consensus verify of {}: {} in {:.3} s", c.label, if r.is_ok() { "VERIFIED" } else { "REFUSED" }, started.elapsed().as_secs_f64()); +1077: self.inner.lock().verdicts.insert(c.proof_hash, r.clone()); +1078: match r { +1079: Ok(_) => ProofVerdict::Verified, +1080: Err(e) => ProofVerdict::Invalid(e), +1081: } +``` + +### I01 cold statement verification + +`node/igneum/exec/src/nativeverify.rs:145-180` + +```text +145: Some(vk_bytes(&words)) +146: } +147: +148: /// The pool's entry: verify under the embedded pair the proof claims, when that pair is accepted at the carrier +149: /// (`accepted`: the ids the epoch allows; empty = any embedded pair, the shape of a network with no pinned ids and no +150: /// succession). Returns the id the proof verified under. +151: pub fn verify_kind(keys: &Keys, kind: ProofKind, bytes: &[u8], statement: &[u8; 32], what: &str, accepted: &[B256]) -> Result { +152: let proof: SP1ProofWithPublicValues = bincode::deserialize(bytes).map_err(|e| format!("{what}: the proof bytes are not a bincode SP1 proof: {e}"))?; +153: let Some(claimed) = claimed_program_id(&proof) else { return Err(format!("{what}: the proof is not a compressed SP1 proof")) }; +154: if !accepted.is_empty() && !accepted.contains(&claimed) { +155: return Err(format!("{what}: the proof claims program id {claimed}, which the carrier's epoch does not accept (accepted: {})", accepted.iter().map(|i| i.to_string()).collect::>().join(", "))); +156: } +157: let Some((id, vk)) = keys.pairs(kind).into_iter().find(|(id, _)| *id == claimed) else { +158: return Err(format!("{what}: the proof claims program id {claimed}, which this node does not embed (embedded: {})", keys.ids(kind).iter().map(|i| i.to_string()).collect::>().join(", "))); +159: }; +160: verify(bytes, statement, vk, id, what).map(|()| id) +161: } +162: +163: /// The verifier itself: the proof bytes (bincode `SP1ProofWithPublicValues`) must claim the pinned id, carry +164: /// public values whose keccak-256 is `statement`, and verify under `vk`. +165: pub fn verify(bytes: &[u8], statement: &[u8; 32], vk: &SP1VerifyingKey, pinned_id: B256, what: &str) -> Result<(), String> { +166: let proof: SP1ProofWithPublicValues = bincode::deserialize(bytes).map_err(|e| format!("{what}: the proof bytes are not a bincode SP1 proof: {e}"))?; +167: let got = alloy_primitives::keccak256(proof.public_values.as_slice()); +168: if got.as_slice() != statement { +169: return Err(format!("{what}: the proof's public values hash to {got}, the record's statement is 0x{}", hex::encode(statement))); +170: } +171: match claimed_program_id(&proof) { +172: Some(id) if id == pinned_id => {} +173: Some(id) => return Err(format!("{what}: the proof claims program id {id}, the pinned id is {pinned_id}")), +174: None => return Err(format!("{what}: the proof is not a compressed SP1 proof")), +175: } +176: let verifier = LightProver::new(); +177: verifier.verify(&proof, vk, None).map_err(|e| format!("{what}: the SP1 verifier refuses the proof: {e}")) +178: } +179: +180: #[cfg(test)] +``` + +### I01/I09 node admission + +`node/consensus/src/pipeline/body_processor/body_validation_in_context.rs:27-79` + +```text +27: /// Igneum 0.3.16 (ledger P21), enforced proving 8 October 2026 (`docs/spec/proving-enforcement.md`): from +28: /// `Params::proof_rule_active_from()` (block zero under the named switch `verifier_in_consensus`, else the DAA floor +29: /// `proving_consensus_verify_daa`), every proof record the coinbase carries +30: /// must come with a proof the node holds and that verifies for the record's statement under the pinned program +31: /// id. A failing proof makes the block invalid (a producer paid for fake proofs in its own blocks was the one +32: /// attack line where a majority earned more than it spent); a proof not held yet is `IgneumProofMissing`, which +33: /// is retried, not marked, since the relay delivers proof bytes beside their records a moment before or after +34: /// the carrying block. The verifier is the execution layer's (`set_proof_oracle`); the verdicts are cached by +35: /// proof hash, so a proof verified at relay time costs nothing here. No oracle (unit tests) = the rule is off. +36: fn check_carried_proofs(self: &Arc, block: &Block) -> BlockProcessResult<()> { +37: if block.header.daa_score < self.proof_rule_active_from { +38: return Ok(()); +39: } +40: // the attacker's shape for the harness only: a node with the rule switched off carries fake proofs; every +41: // honest peer refuses its blocks (IGNEUM_TEST_SKIP_PROOF_RULE=1, never set on a live node) +42: static SKIP: std::sync::OnceLock = std::sync::OnceLock::new(); +43: if *SKIP.get_or_init(|| std::env::var("IGNEUM_TEST_SKIP_PROOF_RULE").map(|v| v == "1").unwrap_or(false)) { +44: return Ok(()); +45: } +46: let Some(oracle) = kaspa_consensus_core::proving::proof_oracle() else { return Ok(()) }; +47: // the rule applies from the floor only (never on the live Devnet 3 object): below it a carried +48: // record is what the record flows and the pool make of it, as on 0.3.17 +49: if !kaspa_consensus_core::proving::proof_rule_applies(block.header.daa_score, oracle.active_from()) { +50: return Ok(()); +51: } +52: let Some(coinbase) = block.transactions.first() else { return Ok(()) }; +53: let carried = kaspa_consensus_core::proving::carried_proofs(&coinbase.payload, block.header.daa_score); +54: if carried.is_empty() { +55: return Ok(()); +56: } +57: // every proof in parallel: a cold verify is 0.26 to 0.53 s a proof on one core (M5 Max to a 2019 Zen 2) +58: let verdicts: Vec<_> = self.thread_pool.install(|| { +59: use rayon::prelude::*; +60: carried.par_iter().map(|c| (c, oracle.verdict(c))).collect() +61: }); +62: let mut missing = Vec::new(); +63: let mut missing_hashes = Vec::new(); +64: for (c, v) in verdicts { +65: match v { +66: kaspa_consensus_core::proving::ProofVerdict::Verified => {} +67: kaspa_consensus_core::proving::ProofVerdict::Invalid(why) => { +68: return Err(RuleError::IgneumInvalidProofRecord(format!("{} (proof {}): {why}", c.label, faster_hex::hex_string(&c.proof_hash[..8])))); +69: } +70: kaspa_consensus_core::proving::ProofVerdict::Missing => { +71: missing.push(format!("{} (proof {})", c.label, faster_hex::hex_string(&c.proof_hash[..8]))); +72: missing_hashes.push(Hash::from_bytes(c.proof_hash)); +73: } +74: } +75: } +76: if !missing.is_empty() { +77: return Err(RuleError::IgneumProofMissing(missing_hashes, missing.join("; "))); +78: } +79: Ok(()) +``` + +### I02 payout send-before-account + +`pool/src/payout.rs:179-259` + +```text +179: let tx = TxEip1559 { +180: chain_id: self.chain_id, +181: nonce, +182: gas_limit: gas, +183: max_fee_per_gas: base_fee * 2 + tip, +184: max_priority_fee_per_gas: tip, +185: to: TxKind::Call(to_addr), +186: value: U256::from(amount_wei), +187: access_list: Default::default(), +188: input: Bytes::new(), +189: }; +190: let sig: Signature = alloy_signer::SignerSync::sign_hash_sync(&self.signer, &tx.signature_hash()).map_err(|e| e.to_string())?; +191: let env: TxEnvelope = tx.into_signed(sig).into(); +192: let raw = format!("0x{}", hex::encode(env.encoded_2718())); +193: let h = self.rpc.call("eth_sendRawTransaction", json!([raw])).await?; +194: h.as_str().map(|s| s.to_string()).ok_or_else(|| "eth_sendRawTransaction: no hash".into()) +195: } +196: +197: /// One payout round over the ledger: every balance at or above the minimum, at most 16 transfers. +198: pub async fn round(&self, state: &Mutex) -> Vec { +199: let mut lines = Vec::new(); +200: let due: Vec<(String, u128)> = { +201: let s = state.lock().unwrap(); +202: let mut v: Vec<(String, u128)> = s.balances.iter().filter(|(_, w)| **w >= self.min_payout_wei).map(|(a, w)| (a.clone(), *w)).collect(); +203: v.sort(); +204: v.truncate(16); +205: v +206: }; +207: if due.is_empty() { +208: return lines; +209: } +210: if self.dry_run { +211: let mut s = state.lock().unwrap(); +212: for (a, wei) in due { +213: s.payments.push(PaymentRec { +214: at_ms: crate::state::unix_ms(), +215: address: a.clone(), +216: amount_wei: wei, +217: tx_hash: None, +218: status: "dry-run".into(), +219: dry_run: true, +220: nonce: None, +221: note: "computed, not sent (--dry-run); the balance stays".into(), +222: }); +223: lines.push(format!("DRY RUN payout {} IGN to {a}", wei as f64 / WEI_PER_IGN as f64)); +224: } +225: s.dirty = true; +226: return lines; +227: } +228: let from = self.address_hex(); +229: let nonce0 = match self.rpc.call("eth_getTransactionCount", json!([from, "pending"])).await.and_then(|v| hex_u128(&v).ok_or("nonce".into())) { +230: Ok(n) => n as u64, +231: Err(e) => { +232: lines.push(format!("payout: nonce unavailable: {e}")); +233: return lines; +234: } +235: }; +236: let pool_balance = self.balance_of(&from).await.unwrap_or(0); +237: let mut nonce = nonce0; +238: let mut spent = 0u128; +239: for (a, wei) in due { +240: if spent + wei + 100_000_000_000_000 > pool_balance { +241: lines.push(format!("payout: pool balance {} IGN cannot cover {} IGN to {a}; waiting", pool_balance as f64 / WEI_PER_IGN as f64, wei as f64 / WEI_PER_IGN as f64)); +242: break; +243: } +244: match self.send(&a, wei, nonce).await { +245: Ok(tx) => { +246: let mut s = state.lock().unwrap(); +247: let left = s.balances.get(&a).copied().unwrap_or(0).saturating_sub(wei); +248: s.balances.insert(a.clone(), left); +249: *s.paid.entry(a.clone()).or_insert(0) += wei; +250: s.payments.push(PaymentRec { at_ms: crate::state::unix_ms(), address: a.clone(), amount_wei: wei, tx_hash: Some(tx.clone()), status: "sent".into(), dry_run: false, nonce: Some(nonce), note: String::new() }); +251: s.dirty = true; +252: lines.push(format!("PAYOUT {} IGN to {a} tx {tx} nonce {nonce}", wei as f64 / WEI_PER_IGN as f64)); +253: nonce += 1; +254: spent += wei; +255: } +256: Err(e) => { +257: lines.push(format!("payout to {a} failed: {e}")); +258: break; +259: } +``` + +### I02 state load/save + +`pool/src/state.rs:133-158` + +```text +133: pub fn load(path: &Path, window_blocks: f64) -> Self { +134: match std::fs::read(path) { +135: Ok(bytes) => match serde_json::from_slice::(&bytes) { +136: Ok(mut s) => { +137: s.pplns.window_blocks = window_blocks; +138: s.dirty = false; +139: eprintln!("state: loaded {} ({} blocks, {} payments, {} miners)", path.display(), s.blocks.len(), s.payments.len(), s.miners.len()); +140: s +141: } +142: Err(e) => { +143: eprintln!("state: {} unreadable ({e}); starting empty", path.display()); +144: State::new(window_blocks) +145: } +146: }, +147: Err(_) => State::new(window_blocks), +148: } +149: } +150: +151: pub fn save(&mut self, path: &Path) -> std::io::Result<()> { +152: if let Some(dir) = path.parent() { +153: std::fs::create_dir_all(dir)?; +154: } +155: let tmp = path.with_extension("json.tmp"); +156: std::fs::write(&tmp, serde_json::to_vec(self)?)?; +157: std::fs::rename(tmp, path)?; +158: self.dirty = false; +``` + +### I03 anchor predicate + +`node/consensus/src/processes/finality.rs:1088-1129` + +```text +1088: self.frozen_table_with_daa(state, index, checkpoint, checkpoint_daa).map(|(j, _, t)| (j, t)) +1089: } +1090: +1091: /// `frozen_table` with the DAA score of the lock the table is frozen at (rule v4's window test reads it). +1092: fn frozen_table_with_daa(&self, state: &FinalityState, index: u64, checkpoint: Hash, checkpoint_daa: u64) -> Option<(u64, u64, Arc)> { +1093: for (&j, &h) in state.locks.range(..index).rev() { +1094: if !self.reachability_service.is_dag_ancestor_of(h, checkpoint) { +1095: continue; +1096: } +1097: let daa_j = self.headers_store.get_daa_score(h).unwrap_or(0); +1098: // rule v4, item 1: the anchored table never expires by time; under v3 (Q5) it expires one window after +1099: // the lock and the sliding table alone decides +1100: if !self.v4_active(checkpoint_daa) && checkpoint_daa >= daa_j.saturating_add(self.params.weight_window) { +1101: return None; +1102: } +1103: // W5: a succession carried between the lock and C_i folds the frozen table too (the key that handed over +1104: // signs nothing, and its weight is the successor's), the shape of a leave in `frozen_floor` +1105: let later = self.successions_at(state, checkpoint, checkpoint_daa); +1106: return Some((j, daa_j, self.voters_at_with(h, state, (!later.is_empty()).then_some(&later)))); +1107: } +1108: None +1109: } +1110: +1111: /// The anchored test of a certificate's signers against the table frozen at lock `C_f` (docs/spec/finality- +1112: /// guarantees.md 6.2): inside one weight window of the lock, two thirds of `T_f` (rule v3's Q5 and rule v4's +1113: /// item 1); past the window, under rule v4 with the recovery, strictly more than half of `T_f` (item 2, the +1114: /// majority-continuity recovery: `2 x signed_f > total_f`); under rule v4 without the recovery (6.5, the pause), +1115: /// nothing passes past the window; under rule v3 the table has expired by then (`frozen_table` returns None) and +1116: /// the sliding table alone decides. Pure: (passes, signed_f, total_f, past_the_window). +1117: pub fn anchored_test(v4: bool, recovery: bool, lock_daa: u64, checkpoint_daa: u64, window: u64, signed_f: u64, total_f: u64) -> (bool, bool) { +1118: let past = checkpoint_daa >= lock_daa.saturating_add(window); +1119: if total_f == 0 { +1120: return (false, past); +1121: } +1122: if !past { +1123: return (FinalityParams::floor_met(signed_f, total_f), past); +1124: } +1125: if v4 && recovery { +1126: return ((signed_f as u128) * 2 > total_f as u128, past); +1127: } +1128: (false, past) +1129: } +``` + +### I03 predicate tests + +`node/consensus/src/processes/finality.rs:3862-3899` + +```text +3862: // dust, and has no position in the voter list at that block, so no certificate can name it +3863: assert!(honest_voters.binary_search(&b.key_hash()).is_ok(), "inside one window of B's last block B is still a voter"); +3864: for i in 150 + (w as u64) + 26..=150 + 2 * (w as u64) + 60 { +3865: mine(&tc, &mut prev, i, &a).await; +3866: } +3867: let later_voters = fm.weights_at(prev).voters.clone(); +3868: assert!(later_voters.binary_search(&b.key_hash()).is_err(), "B, under dust a window later, has no position in the bitmap at that block"); +3869: assert!(later_voters.binary_search(&a.key_hash()).is_ok()); +3870: tc.shutdown(handles); +3871: } +3872: +3873: /// Rule v4, item 2 (6.2; the lane's test 2): the same shape with the recovery. Inside the window A alone (60 +3874: /// percent of T_f) does not lock; at the first checkpoint one window past the anchored lock A's certificate +3875: /// locks (2 x 60 > 100 and Q3 on the sliding table, all A's by then), the status reads "recovered", and the +3876: /// table re-anchors there. The even case on the pure test: exactly half of T_f is refused, 51 of 100 passes. +3877: #[tokio::test] +3878: async fn rule_v4_the_majority_continuity_recovery_locks_after_a_full_window_and_re_anchors() { +3879: let w = TEST_PARAMS.weight_window; +3880: // the pure test, known-failed first: inside the window a majority is not enough (two thirds), past it under +3881: // v3 the table has expired (not reached here), under v4 pause nothing, under v4 recovery strictly more than half +3882: assert!(!super::FinalityManager::anchored_test(true, true, 1_000, 1_000 + w - 1, w, 60, 100).0, "inside the window 60 of 100 is under two thirds"); +3883: assert!(super::FinalityManager::anchored_test(true, true, 1_000, 1_000 + w - 1, w, 67, 100).0, "inside the window 67 of 100 passes"); +3884: assert!(!super::FinalityManager::anchored_test(true, false, 1_000, 1_000 + w, w, 99, 100).0, "v4 pause: nothing passes past the window"); +3885: assert!(!super::FinalityManager::anchored_test(true, true, 1_000, 1_000 + w, w, 50, 100).0, "the even case: exactly half is refused"); +3886: assert!(super::FinalityManager::anchored_test(true, true, 1_000, 1_000 + w, w, 51, 100).0, "51 of 100 passes"); +3887: assert!(!super::FinalityManager::anchored_test(true, true, 1_000, 1_000 + w, w, 0, 0).0, "an empty table passes nothing"); +3888: assert!(super::FinalityManager::anchored_test(true, true, 1_000, 1_000 + w, w, 51, 100).1, "past the window reads past"); +3889: // the chain: A alone locks at the first checkpoint one window past the anchored lock, and the status says recovered +3890: let (last, alone, reason) = first_lock_alone_v4(0, u64::MAX, false, Some(true)).await; +3891: let alone = alone.expect("v4 recovery: A locks alone one window past the anchored lock"); +3892: assert!(alone >= last + w && alone < last + w + 20, "v4 recovery: A locked alone at {alone} against the lock at {last} (window {w})"); +3893: assert!(reason.starts_with("recovered:") || reason == "active", "{reason}"); +3894: } +3895: +3896: /// The fresh-join cost (the 0.3.17 canary, 7 October 2026: a joiner fell to 3.7 blocks a second on one core +3897: /// replaying 5,005 checkpoints and 2,529 locks). A chain of `IGNEUM_JOIN_BENCH` checkpoints (default 200) at +3898: /// the devnet's finality numbers (interval 30, depth 20, window 7,200, presence 20, 30 keys mining round-robin +3899: /// and all signing, every block carrying the builder's finality section), then a FRESH node takes every block +``` + +### I03 specification names fix and weaker recovery + +`spec/docs/spec/finality-guarantees.md:89-115` + +```text +89: ### 6.2 The rule (designed) +90: +91: Rule v4 replaces Q5's expiry with the following, active for checkpoints at or above `finality_v4_activation_daa`: +92: +93: 1. **The anchored table never expires by time.** `T_f` is the sliding table at `C_f`, the highest certified checkpoint on the selected chain of `C_i`, with the strips and successions known at `C_i` applied. It stands until a certificate that passes it replaces it. A certificate for `i` locks if its signers hold at least two thirds of `T_f` at `T_f`'s weights, in addition to Q3, **at any time**: the two-thirds anchored test never lapses, under either variant (the node line's acd9d067 of 8 October 2026 reads it so; an earlier reading that refused everything past one window under the pause-only variant was a fault, found by the harness: the heal could not resume). Item 2 adds a second way to pass once a window has elapsed; it replaces nothing. And +94: 2. **The majority-continuity recovery.** Once `daa(C_i) >= daa(C_f) + 2,592,000` with no certificate formed between `C_f` and `C_i` on this chain, a certificate for `i` locks when its signers hold at least two thirds of the sliding table `T(i)` (Q3, both tests) AND **strictly more than half** of `T_f` at `T_f`'s weights (`2 x signed_f > total_f`), AND +95: 3. `C_f` is an ancestor of `C_i` on the selected chain (the certificate names a chain through the last certified history; a certificate for a chain that misses any lock the node holds is a conflict under 3.11.4, as before). +96: 4. A lock under item 2 is a **recovery lock**: it re-anchors `T_f` at `C_i` (so the next certificate needs two thirds again), it is carried, verified and followed exactly like any other certificate (C3, C4, F1, the certificate-driven reorg of 3.5), and the node reports `finality_reason` `recovered` with the index and the signed share of the old `T_f` for one window after it, then `active`. +97: 5. Before the first certificate of the chain there is no anchored table and Q3 alone decides (3.8's first-month rule applies). +98: +99: In one sentence: the last certified table is the authority until a new certificate carries the consent of two thirds of it, or, after a full window of silence, of more than half of it; nothing else, and no clock, can replace it. +100: +101: ### 6.3 Why a pause, and why this recovery and not a timeout +102: +103: A node inside a partition sees exactly what a node after a departure sees: the same chain, the same missing votes, the same elapsed window. No local rule can tell the two apart, which is the review's point, and any rule that resumes on elapsed time alone resumes on both sides of a partition and forks (6.1). The anchored table is therefore the default: when enough weight is missing, finality pauses and stays paused. The chain does not stop (5). +104: +105: The recovery relaxes the anchored test only; Q3 (two thirds of the sliding table) always stands, so a set that keeps mining and withholds its votes pauses finality for as long as it does so under every rule (N3), and the recovery reaches only weight that has stopped producing blocks on this chain: departed, partitioned away, or the decayed purchase of N4. The majority test is the one resumption that is safe without knowing which case it is in, because it is **asymmetric by construction**: two certificates at one index each carrying more than half of `T_f` need more than `T_f` in total, so some key signed both (derived). Under a partition with no equivocator, at most one side can hold more than half of the last certified table, whatever each side mined since; the 50/50 split holds exactly half on each side and stays paused until the heal (N1, measured: never in 31 days). After a departure, the survivors recover exactly when they are the majority of the table the chain last agreed on (N6: 35 percent gone, day 30; 50 percent gone, never). Bought or stolen keys that withhold lose their veto at day 30 to the honest majority (N4), where the pause-only variant hands one purchase a permanent veto. +106: +107: ### 6.4 The continuity proof, and who can verify it +108: +109: A recovery certificate is verifiable by anyone holding the chain, with no operator, no committee and no out-of-band input: (i) `T_f` from `C_f`'s past (W2 at `C_f`, bans and successions as the chain carries them at `C_i`), (ii) `T(i)` from `C_i`'s past, (iii) `C_f` an ancestor of `C_i` (reachability), (iv) `daa(C_i) - daa(C_f) >= 2,592,000` and no certificate between (the node's own locks on this chain), (v) the bitmap over the canonical voter list at `C_i` and the aggregate signature. A light client that holds `C_f`'s certificate and the header chain checks the same five facts (section 10's receipt already carries the voter table with weights). This is the "disclosed, verifiable continuity rule" of the acceptance line: the new authority set, the signers of `T(i)`, cannot certify anything unless a majority of the old authority set, `T_f`, signed with them, and never on a chain that misses `C_f`. +110: +111: ### 6.5 The cost, stated, and the one-line alternative +112: +113: The recovery certificate's safety bound is weaker than one third. Two conflicting recovery locks need a partition that has lasted a full window with no certificate on either side AND equivocating keys that (i) hold a share of `T_f` exceeding the split's imbalance and (ii) are still in BOTH sides' canonical voter lists at the recovery index, which means they mined at least dust (100 blue blocks in the window, W3) on each side: a certificate's bitmap is over the voter list at `C_i` (C3), so a key that mined on one side only is, after a full window, not a voter on the other side whatever its anchored weight. Each side of a 50/50 split with an equivocator at `a` that mines on both holds `(1 - a) / 2 + a` of `T_f`, more than half for any `a > 0`; in a 60/40 split the 40 side needs `a > 0.2`. Measured (N1b, N2b, five rows each over two seeds): an equivocator mining on one side only never produces a recovery conflict (one side recovers at day 30.00, the other never, 0 conflicts, at 10 and 20 percent across 50/50 and in the 40/40 case); one mining on both sides makes both sides recover at day 30.00 and the heal shows 2,800 to 2,889 conflicting locks under `v4 recovery` and 0 under `v4 pause`; at 34 percent both sides lock from minute 0 under every rule (the one-third bound). Every pre-heal lock kept and the heal locks at 0 minutes in every row. In every such case the equivocator is stripped at the heal (3.6), the history through `C_f` is untouched (item 3), and the pair is handled as 3.11.4 says. The one-third bound of section 4 is intact for every certificate formed within a window of the last one, which is every certificate of a connected network. +114: +115: The alternative the founder can choose by deleting item 2 is the **indefinite pause** (`v4 pause` in the simulator, `P.recovery = False`; in the node, the recovery test left out). Its guarantees are strictly stronger: no certificate ever forms with less than two thirds of the last certified table, so the one-third bound holds for every certificate for ever. Its costs, measured: one purchase of keys worth a third of a window is a permanent veto on finality (N4: never in 31 days, against day 30 with the recovery), a sudden honest loss of a third of weight (a pool folding with its keys) pauses finality permanently absent succession or an operator's trusted certificate (N6: never, against day 30), and a 60/40 partition that outlasts a window pauses the 60 side until the heal instead of recovering at day 30 (N1). +``` + +### I04 node classes + +`node/consensus/core/src/igneum.rs:442-490` + +```text +442: /// The program class of an epoch: which generator the lottery hash draws the epoch's program from. V2 is the +443: /// lottery hash as adopted on 4 October 2026; V3 is generator version 3 (`igneum_pow::ProgramClass`); V4 is generator +444: /// version 4 (Counter ASIC 3.0, 6 October 2026: class v3 plus the latency-shadow block, `igneum_pow::V4_CLASS`). One +445: /// epoch has one program (spec 01 section 1.12), so the height switches `Params::program_class_v3_activation_daa` +446: /// (N4) and `Params::program_class_v4_activation_daa` (N5) key on the epoch: epoch `e` is v3 when +447: /// `epoch_blocks * e >= N4` and v4 when `epoch_blocks * e >= N5`, each activation rounded up to an epoch boundary, +448: /// and a block's class is a function of its DAA score alone. +449: #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default, Serialize, Deserialize)] +450: #[serde(rename_all = "lowercase")] +451: pub enum ProgramClass { +452: #[default] +453: V2, +454: V3, +455: V4, +456: /// Class v5, proof of stored state and of following (`docs/design/class-v5-stored-state.md`, 7 October 2026, behind +457: /// `program_class_v5_activation_daa`): class v4's program over a dataset whose every item is keyed by the execution +458: /// state after the epoch's seed block (the window's reference block), generator 5. +459: V5, +460: } +461: +462: impl ProgramClass { +463: /// The generator version of the class (2, 3, 4 or 5), what the packs and the wire carry. +464: pub fn generator_version(&self) -> u32 { +465: match self { +466: ProgramClass::V2 => 2, +467: ProgramClass::V3 => 3, +468: ProgramClass::V4 => 4, +469: ProgramClass::V5 => 5, +470: } +471: } +472: +473: pub fn from_generator(v: u32) -> Option { +474: match v { +475: 2 => Some(ProgramClass::V2), +476: 3 => Some(ProgramClass::V3), +477: 4 => Some(ProgramClass::V4), +478: 5 => Some(ProgramClass::V5), +479: _ => None, +480: } +481: } +482: +483: /// "v2", "v3", "v4" or "v5": the log and job-line form. +484: pub fn name(&self) -> &'static str { +485: match self { +486: ProgramClass::V2 => "v2", +487: ProgramClass::V3 => "v3", +488: ProgramClass::V4 => "v4", +489: ProgramClass::V5 => "v5", +490: } +``` + +### I04 node generator mapping + +`node/consensus/pow/src/igneum.rs:519-545` + +```text +519: /// The `igneum-pow` class of these seeds. +520: pub fn pow_class(seeds: &EpochSeeds) -> igneum_pow::ProgramClass { +521: Self::pow_class_of(seeds.class) +522: } +523: +524: /// The `igneum-pow` class of a chain class (the two enums are kept apart so the node's wire form never +525: /// depends on the crate's). +526: pub fn pow_class_of(class: super::ProgramClass) -> igneum_pow::ProgramClass { +527: match class { +528: super::ProgramClass::V2 => igneum_pow::ProgramClass::V2, +529: super::ProgramClass::V3 => igneum_pow::ProgramClass::V3, +530: super::ProgramClass::V4 => igneum_pow::ProgramClass::V4, +531: super::ProgramClass::V5 => igneum_pow::ProgramClass::V5, +532: } +533: } +534: +535: /// The pack label of these seeds (recorded in emitted packs, not part of the hash). +536: fn label(seeds: &EpochSeeds) -> String { +537: format!("igneum-epoch/{}/day/{}", Hash::from_bytes(seeds.epoch.as_bytes()), seeds.day) +538: } +539: +540: /// The program of these seeds: the class's generator on the 32-byte epoch seed (and, for class v3, the era +541: /// seed), through `igneum_pow::Epoch::chain_program`, the same entry `standalone_epoch` builds through. +542: fn generate_program(seeds: &EpochSeeds) -> igneum_pow::Program { +543: let (epoch_bytes, _) = Self::seed_bytes(seeds); +544: let era = Self::era_bytes(seeds); +545: igneum_pow::Epoch::chain_program_shadow(&epoch_bytes, era.as_ref().map(|b| &b[..]), Self::pow_class(seeds), seeds.shadow_reps, &Self::label(seeds)) +``` + +### I05 pair allocation + +`workers/proto-cuda/nvrtc/worker.cpp:872-884` + +```text +872: // Cache +873: double t0 = wallMs(); +874: size_t cacheBytes = (size_t)p->cacheWords * 4u, dsBytes = (size_t)p->words * 4u; +875: { +876: size_t freeB = 0, totalB = 0; +877: if (c.drv.memGetInfo(&freeB, &totalB) == CUDA_SUCCESS && freeB < cacheBytes + dsBytes + scratchBytes + hotBytes + leavesBytes + (64u << 20)) { +878: err = fmt("%llu MiB free on the device, this pack needs %llu MiB (cache %llu + dataset %llu + scratch %llu + hot %llu + leaves %llu)", (unsigned long long)(freeB >> 20), (unsigned long long)((cacheBytes + dsBytes + scratchBytes + hotBytes + leavesBytes) >> 20), (unsigned long long)(cacheBytes >> 20), (unsigned long long)(dsBytes >> 20), (unsigned long long)(scratchBytes >> 20), (unsigned long long)(hotBytes >> 20), (unsigned long long)(leavesBytes >> 20)); +879: std::free(hLeaves); releasePair(c, p); return nullptr; +880: } +881: } +882: if (p->persistent) { +883: CUresult r = c.drv.memAlloc(&p->scratch, scratchBytes); +884: if (r != CUDA_SUCCESS) { err = "cuMemAlloc scratch: " + c.err(r); p->scratch = 0; std::free(hLeaves); releasePair(c, p); return nullptr; } +``` + +### I05 preparation/self-heal + +`workers/proto-cuda/nvrtc/worker.cpp:1180-1239` + +```text +1180: takeClassTokens(f, wantClass, wantEra); +1181: if (f[0] == "prepare") { +1182: if (f.size() < 4) { emit(fmt("prepare-failed %s %s a pack directory is needed as the third field (igneum-miner --prepare-packs )", f.size() > 1 ? f[1].c_str() : "0", f.size() > 2 ? f[2].c_str() : "0")); continue; } +1183: if (f[1].size() != 64) { emit(fmt("prepare-failed %s %s bad field (epoch_seed 64 hex, day_seed hex)", f[1].c_str(), f[2].c_str())); continue; } +1184: if (task) { emit(fmt("prepare-failed %s %s a prepare is still running", f[1].c_str(), f[2].c_str())); continue; } +1185: if (prepared && prepared->epochHex == f[1] && prepared->dayHex == f[2]) { emit(fmt("prepared %s %s 0 (already resident)", f[1].c_str(), f[2].c_str())); continue; } +1186: if (cur->epochHex == f[1] && cur->dayHex == f[2]) { emit(fmt("prepared %s %s 0 (already the current pair)", f[1].c_str(), f[2].c_str())); continue; } +1187: std::string dir = f[3]; +1188: for (size_t i = 4; i < f.size(); ++i) dir += " " + f[i]; // a directory with spaces arrives as several fields +1189: prepareRoot = parentDir(dir); +1190: task = new PrepareTask(); +1191: task->epochHex = f[1]; task->dayHex = f[2]; task->dir = dir; task->t0 = wallMs(); +1192: task->wantClass = wantClass; task->wantEra = wantEra; +1193: task->thread = std::thread(prepareRun, &c, task); +1194: info(fmt("prepare started for epoch %.16s day %s from %s (NVRTC %s in the background)", f[1].c_str(), f[2].c_str(), dir.c_str(), c.archOpt.c_str())); +1195: continue; +1196: } +1197: if (f[0] != "job") { info("ignored: " + line); continue; } +1198: std::string jobId = f.size() > 1 ? f[1] : "0"; +1199: if (f.size() < 8) { emit("error " + jobId + " malformed job line (need 7 fields after job)"); continue; } +1200: uint8_t prehash[32], epochSeed[32], daySeed[256]; +1201: size_t pl = 0, el = 0, dl = 0; +1202: unsigned long long target = 0, nonceStart = 0, nonceCount = 0; +1203: if (!pf_unhex(f[2].c_str(), prehash, 32, &pl) || pl != 32 || std::sscanf(f[3].c_str(), "%llx", &target) != 1 || +1204: std::sscanf(f[4].c_str(), "%llu", &nonceStart) != 1 || std::sscanf(f[5].c_str(), "%llu", &nonceCount) != 1 || +1205: !pf_unhex(f[6].c_str(), epochSeed, 32, &el) || el != 32 || !pf_unhex(f[7].c_str(), daySeed, sizeof(daySeed), &dl)) { +1206: emit("error " + jobId + " bad field (prehash 64 hex, target 16 hex, nonce_start u64, nonce_count u64, epoch_seed 64 hex, day_seed hex)"); continue; +1207: } +1208: if (nonceCount == 0 || nonceCount % 32 != 0 || (nonceStart & 31) != 0) { emit("error " + jobId + " nonce_start must be 32-aligned and nonce_count a non-zero multiple of 32"); continue; } +1209: uint32_t sw[8], kw[8]; +1210: pf_seed_words_from_bytes(epochSeed, 32, sw); +1211: pf_seed_words_from_bytes(daySeed, dl, kw); +1212: double t0 = wallMs(); +1213: bool switched = false; +1214: if (!pairIsClass(cur, f[6], f[7], wantClass, wantEra) && !task && !pairIsClass(prepared, f[6], f[7], wantClass, wantEra)) { +1215: // Self-heal: a job on seeds this worker has no pair for and no prepare in flight (a prepare failed, or +1216: // the miner never sent one). The miner writes a pack per pair under its --prepare-packs root; find it by +1217: // seeds.txt and build it now, in the foreground. The miner only re-sends prepare for the pair after this one. +1218: std::string dir = findPackFor(prepareRoot, f[6], f[7]); +1219: if (dir.empty()) dir = findPackFor(parentDir(o.pack) + "/prepare", f[6], f[7]); +1220: if (dir.empty()) dir = findPackFor(parentDir(o.pack), f[6], f[7]); +1221: if (!dir.empty()) { +1222: info(fmt("job %s is for epoch %.16s day %s, which is not resident; building its pack %s now (foreground)", jobId.c_str(), f[6].c_str(), f[7].c_str(), dir.c_str())); +1223: std::string berr; +1224: Pair* p = buildPair(c, dir, nullptr, berr, true); +1225: if (p && (p->epochHex != f[6] || p->dayHex != f[7])) { berr = "the pack in " + dir + " is for other seeds"; releasePair(c, p); p = nullptr; } +1226: if (p) { if (prepared) releasePair(c, prepared); prepared = p; info(fmt("built %s: %s", dir.c_str(), pairSummary(p).c_str())); if (!p->raceLine.empty()) emit(p->raceLine); } +1227: else emit("error " + jobId + " could not build " + dir + ": " + berr); +1228: } +1229: } +1230: if (!pairIsClass(cur, f[6], f[7], wantClass, wantEra)) { +1231: char why[256]; +1232: if (pairIsClass(prepared, f[6], f[7], wantClass, wantEra)) { +1233: if (old) releasePair(c, old); +1234: old = cur; cur = prepared; prepared = nullptr; switched = true; +1235: info(fmt("switched to the prepared pair epoch %.16s day %s (class %s) in %.2f ms", cur->epochHex.c_str(), cur->dayHex.c_str(), cur->programClass.c_str(), wallMs() - t0)); +1236: } else if (pairIs(cur, f[6], f[7]) && !pf_pack_class_ok(cur->programClass.c_str(), cur->eraHex.c_str(), wantClass.c_str(), wantEra.c_str(), why, sizeof(why))) { +1237: // Counter ASIC 2.0: right seeds, wrong class or era. The miner prepares the pair again from a pack of +1238: // the class the chain is on (the `need` line), and the pack of the other class is never mined. +1239: emit(fmt("need %s %s", f[6].c_str(), f[7].c_str())); +``` + +### I06 Metal geometry + +`workers/proto-metal/main.swift:3133-3209` + +```text +3133: func servePackDataset(_ gpu: GPU, _ store: ServeStore, dayHex: String, dir: String, wantClass: String, wantEra: String) throws -> (ServeDataset, Double) { +3134: if let d = store.dataset(dayHex, cls: wantClass, era: wantEra) { return (d, 0) } +3135: let t0 = nowNs() +3136: func refuse(_ why: String) -> NSError { NSError(domain: "pack", code: 3, userInfo: [NSLocalizedDescriptionKey: "pack \(dir): \(why)"]) } +3137: guard let programH = try? String(contentsOfFile: dir + "/program.h", encoding: .utf8) else { throw refuse("cannot read program.h") } +3138: func defineU32(_ name: String) -> UInt32? { +3139: guard let re = try? NSRegularExpression(pattern: "#define \(name) ([0-9a-fA-Fx]+)"), let m = re.firstMatch(in: programH, range: NSRange(programH.startIndex..., in: programH)) else { return nil } +3140: let v = String(programH[Range(m.range(at: 1), in: programH)!]).replacingOccurrences(of: "u", with: "") +3141: return v.hasPrefix("0x") ? UInt32(v.dropFirst(2), radix: 16) : UInt32(v) +3142: } +3143: func defineStr(_ name: String) -> String? { +3144: guard let re = try? NSRegularExpression(pattern: "#define \(name) \"([^\"]*)\""), let m = re.firstMatch(in: programH, range: NSRange(programH.startIndex..., in: programH)) else { return nil } +3145: return String(programH[Range(m.range(at: 1), in: programH)!]) +3146: } +3147: let generator = defineU32("IGNEUM_GENERATOR") ?? 1 +3148: let packClass = packClassOf(generator: generator) +3149: let eraHex = defineStr("IGNEUM_ERA_SEED_HEX") ?? "" +3150: if let packDay = defineStr("IGNEUM_DAY_BYTES_HEX"), packDay.lowercased() != dayHex.lowercased() { throw refuse("the pack's day is \(packDay), not \(dayHex)") } +3151: if wantClass != "" && wantClass != packClass { throw refuse("program class mismatch: this pack is class \(packClass), the line names class \(wantClass)") } +3152: if wantEra != "" && isPackClass(packClass) && wantEra.lowercased() != eraHex.lowercased() { throw refuse("era seed mismatch: the pack's era is \(eraHex.prefix(16)), the line names \(wantEra.prefix(16))") } +3153: if (defineU32("IGNEUM_HOT_MB") ?? 0) > 0 { throw refuse("a hot-table pack (IGNEUM_HOT_MB) is not served by this worker") } +3154: guard (defineU32("IGNEUM_DATASET_MODE") ?? 0) == 1 else { throw refuse("not a memory-hard pack (IGNEUM_DATASET_MODE 1)") } +3155: let datasetLog2 = Int(defineU32("IGNEUM_DATASET_LOG2") ?? 28) +3156: let cacheLog2 = Int(defineU32("IGNEUM_CACHE_LOG2_WORDS") ?? 26) +3157: let cacheSegments = Int(defineU32("IGNEUM_CACHE_SEGMENTS") ?? 65536) +3158: guard datasetLog2 >= 20 && datasetLog2 <= 31 && cacheLog2 >= 16 && cacheLog2 <= 30 && cacheSegments % 256 == 0 && cacheSegments > 0 else { throw refuse("program.h sizes out of range") } +3159: guard let mhSrc = try? String(contentsOfFile: dir + "/memhard.metal", encoding: .utf8) else { throw refuse("cannot read memhard.metal") } +3160: let lib: MTLLibrary +3161: do { lib = try gpu.device.makeLibrary(source: mhSrc, options: MTLCompileOptions()) } catch { throw refuse("Metal compile of memhard.metal: \(error)") } +3162: guard let fillFn = lib.makeFunction(name: "igneum_cache_fill"), let buildFn = lib.makeFunction(name: "igneum_build") else { throw refuse("memhard.metal lacks igneum_cache_fill or igneum_build") } +3163: let fillPipe = try gpu.device.makeComputePipelineState(function: fillFn) +3164: let buildPipe = try gpu.device.makeComputePipelineState(function: buildFn) +3165: let words = 1 << datasetLog2 +3166: // Class v5 (docs/design/class-v5-stored-state.md, 7 October 2026): the window's state leaves, leaves.bin beside program.h +3167: // (IGNEUM_STATE_LEAVES leaves of 16 little-endian words), checked against the pack's count and FNV-1a 64 +3168: // (IGNEUM_STATE_LEAVES_FNV64) and bound as buffer 2 of igneum_build with the count in buffer 3 (packbench.swift's shape, +3169: // the kernel text the Rust emitter wrote). A v5 pack without its leaves builds nothing (the known-failed case); the buffer +3170: // is dropped after the build, so device memory while hashing is the class v4 worker's. +3171: func defineU64(_ name: String) -> UInt64? { +3172: guard let re = try? NSRegularExpression(pattern: "#define \(name) 0x([0-9a-fA-F]+)ull"), let m = re.firstMatch(in: programH, range: NSRange(programH.startIndex..., in: programH)) else { return nil } +3173: return UInt64(programH[Range(m.range(at: 1), in: programH)!], radix: 16) +3174: } +3175: let stateLeaves = defineU32("IGNEUM_STATE_LEAVES") ?? 0 +3176: if (packClass == "v5") != (stateLeaves > 0) { throw refuse(packClass == "v5" ? "class v5 pack without IGNEUM_STATE_LEAVES" : "a class \(packClass) pack carries IGNEUM_STATE_LEAVES \(stateLeaves): state leaves belong to class v5") } +3177: var leavesBuf: MTLBuffer? = nil +3178: var nLeaves: UInt32 = 0 +3179: if stateLeaves > 0 { +3180: let file = defineStr("IGNEUM_STATE_LEAVES_FILE") ?? "leaves.bin" +3181: guard let data = FileManager.default.contents(atPath: dir + "/" + file) else { throw refuse("class v5 pack without its leaves file \(file) (the state leaves key every item: nothing can be built without them)") } +3182: if data.count != Int(stateLeaves) * 64 { throw refuse("\(file) is \(data.count) bytes, the pack says \(stateLeaves) leaves of 64") } +3183: guard let want = defineU64("IGNEUM_STATE_LEAVES_FNV64") else { throw refuse("class v5 pack without IGNEUM_STATE_LEAVES_FNV64: the leaves cannot be checked") } +3184: let got = fnv1a64Bytes([UInt8](data)) +3185: if got != want { throw refuse("\(file) FNV-1a 64 \(h64(got)) is not the pack's IGNEUM_STATE_LEAVES_FNV64 \(h64(want)) (the leaves are of another state root; export the pack again)") } +3186: guard let b = gpu.device.makeBuffer(bytes: (data as NSData).bytes, length: data.count, options: .storageModeShared) else { throw refuse("cannot allocate the \(data.count) byte leaf buffer") } +3187: leavesBuf = b; nLeaves = stateLeaves +3188: } +3189: guard let cache = gpu.device.makeBuffer(length: (1 << cacheLog2) * 4, options: .storageModePrivate) else { throw refuse("cannot allocate the 2^\(cacheLog2) word cache") } +3190: guard let dataset = gpu.device.makeBuffer(length: words * 4, options: .storageModePrivate) else { throw refuse("cannot allocate the 2^\(datasetLog2) word dataset") } +3191: func run(_ body: (MTLComputeCommandEncoder) -> Void) throws -> Double { +3192: let cb = gpu.queue.makeCommandBuffer()! +3193: let enc = cb.makeComputeCommandEncoder()! +3194: body(enc); enc.endEncoding(); cb.commit(); cb.waitUntilCompleted() +3195: if let e = cb.error { throw refuse("command buffer: \(e)") } +3196: return (cb.gpuEndTime - cb.gpuStartTime) * 1000 +3197: } +3198: let fillMs = try run { enc in +3199: enc.setComputePipelineState(fillPipe); enc.setBuffer(cache, offset: 0, index: 0) +3200: enc.dispatchThreadgroups(MTLSize(width: cacheSegments / 256, height: 1, depth: 1), threadsPerThreadgroup: MTLSize(width: 256, height: 1, depth: 1)) +3201: } +3202: let buildMs = try run { enc in +3203: enc.setComputePipelineState(buildPipe); enc.setBuffer(cache, offset: 0, index: 0); enc.setBuffer(dataset, offset: 0, index: 1) +3204: if let lb = leavesBuf { enc.setBuffer(lb, offset: 0, index: 2); var n = nLeaves; enc.setBytes(&n, length: 4, index: 3) } +3205: enc.dispatchThreadgroups(MTLSize(width: words / 16 / 256, height: 1, depth: 1), threadsPerThreadgroup: MTLSize(width: 256, height: 1, depth: 1)) +3206: } +3207: leavesBuf = nil +3208: // The build's self-test when the pack carries vectors.json (igneum-pow export writes it): the dataset's head 16 words and +3209: // its last word against the CPU reference, as the one-click workers' pf_selftest does; a mismatch refuses the day (the +``` + +### I07 engine workload class + +`app/src/engine.rs:3937-3957` + +```text +3937: /// A worker's race line (one per hourly prepare, docs/design/miner-tuning.md): +3938: /// `race device driver arch loads wide variants =/r/w ... +3939: /// winner base gain % compile bench total ms [| : ]`. +3940: /// Becomes the fleet record: one `TUNING {json}` line in the app log (uploaded to the intake, aggregated by +3941: /// tools/tuning.mjs) with the card's power figures, plus the card state and one event. +3942: fn race_line(&mut self, card: usize, card_name: &str, text: &str) { +3943: let Some(body) = text.split(" worker: race ").nth(1) else { return }; +3944: let Some(r) = parse_race(body) else { return }; +3945: let (vendor, worker, power_limit_w, power_w, power_pct) = { +3946: let mut st = self.st(); +3947: match st.mining.cards.get_mut(card) { +3948: Some(c) => { +3949: c.variant = r.winner.clone(); +3950: c.race_mhs = r.mhs; +3951: c.race_gain_pct = r.gain_pct; +3952: c.race_variants = r.variants.len() as u32; +3953: if !r.driver.is_empty() && c.driver.is_empty() { +3954: c.driver = r.driver.clone(); +3955: } +3956: c.program_class = crate::ember::program_class(r.loads as u32, r.wide as u32); +3957: (c.vendor.clone(), c.worker.clone(), c.power_limit_w, c.power_w, c.power_pct) +``` + +### I07 engine restore path + +`app/src/engine.rs:1883-1903` + +```text +1883: /// On quit: the limits the cards had before the app (one more prompt; nvidia-smi limits do not survive a reboot anyway). +1884: fn restore_power_limits(&mut self) { +1885: if !self.power_restore_pending { +1886: return; +1887: } +1888: let st = self.st(); +1889: let cmds: Vec = st +1890: .mining +1891: .cards +1892: .iter() +1893: .filter(|c| c.vendor == "nvidia" && c.present() && c.power_applied && c.power_before_w > 0.0) +1894: .map(|c| format!("\"{}\" -i {} -pl {}", crate::platform::tool("nvidia-smi").display(), c.device, c.power_before_w.round() as u64)) +1895: .collect(); +1896: drop(st); +1897: if cmds.is_empty() { +1898: return; +1899: } +1900: // no administrator prompt on quit (5 October 2026: the app never asks on its own); the limits reset at the +1901: // next reboot, and the next start with Power control on sets them again +1902: self.shared.log(&format!("GPU power limits left as set (they reset at the next reboot; no prompt on quit): {}", cmds.join(" & "))); +1903: } +``` + +### I08 auth wire + +`pool/src/protocol.rs:42-54` + +```text +42: Authorize { +43: /// 48 bytes hex, the member's BLS vote key +44: pubkey: String, +45: /// 96 bytes hex, the proof of possession (spec 3.10 KeyReveal) +46: pop: String, +47: /// Worker name shown on the dashboards +48: label: String, +49: /// EVM payout address, 0x + 40 hex (v0 addition) +50: payout: String, +51: /// `binding` of spec 9.3 (a signature over the TLS exporter) is absent in v0: no TLS yet +52: #[serde(default)] +53: binding: String, +54: }, +``` + +### I08 pool reading and authorization + +`pool/src/server.rs:53-151` + +```text +53: share_scheme: ShareScheme { scheme: "pplns".into(), fee_percent: pool.cfg.fee_percent, pplns_window_blocks: pool.cfg.pplns_window_blocks, min_payout_ign: pool.cfg.min_payout_ign }, +54: min_shift: pool.cfg.min_shift, +55: max_shift: pool.cfg.max_shift, +56: share_interval_s: pool.cfg.share_interval_s, +57: stale_grace_ms: pool.cfg.stale_grace_ms, +58: pool_name: pool.cfg.name.clone(), +59: } +60: } +61: +62: async fn connection(pool: Arc, sock: TcpStream, remote: String) { +63: let (rd, mut wr) = sock.into_split(); +64: let (tx, mut rx) = tokio::sync::mpsc::unbounded_channel::(); +65: let writer = tokio::spawn(async move { +66: while let Some(line) = rx.recv().await { +67: if wr.write_all(line.as_bytes()).await.is_err() { +68: break; +69: } +70: } +71: }); +72: let mut lines = BufReader::with_capacity(64 << 10, rd).lines(); +73: let mut member: Option> = None; +74: let mut said_hello = false; +75: let mut buf_guard = 0usize; +76: loop { +77: let l = match tokio::time::timeout(Duration::from_secs(300), lines.next_line()).await { +78: Ok(Ok(Some(l))) => l, +79: Ok(Ok(None)) => break, +80: Ok(Err(e)) => { +81: eprintln!("{} {remote}: read error: {e}", now()); +82: break; +83: } +84: Err(_) => { +85: let _ = tx.send(Msg::Bye { reason: "idle for 300 s".into() }.line()); +86: break; +87: } +88: }; +89: buf_guard += l.len(); +90: if l.len() > MAX_LINE { +91: let _ = tx.send(Msg::Bye { reason: "line over 4 MiB".into() }.line()); +92: break; +93: } +94: let msg = match Msg::parse(&l) { +95: Ok(m) => m, +96: Err(e) => { +97: let _ = tx.send(Msg::Error { code: "parse".into(), detail: e }.line()); +98: continue; +99: } +100: }; +101: match msg { +102: Msg::Hello { versions, chain_id, client, .. } => { +103: if !versions.iter().any(|v| v == VERSION) { +104: let _ = tx.send(Msg::Bye { reason: format!("protocol {VERSION} only") }.line()); +105: break; +106: } +107: if chain_id != pool.cfg.chain_id() { +108: let _ = tx.send(Msg::Bye { reason: format!("chain id {} here, you said {chain_id}", pool.cfg.chain_id()) }.line()); +109: break; +110: } +111: said_hello = true; +112: println!("{} {remote}: hello from {client}", now()); +113: let _ = tx.send(welcome(&pool).line()); +114: } +115: Msg::Authorize { pubkey, pop, label, payout, .. } => { +116: if !said_hello { +117: let _ = tx.send(Msg::Error { code: "order".into(), detail: "hello first".into() }.line()); +118: continue; +119: } +120: let (Some(pk), Some(pp)) = (parse_hex_array::<48>(&pubkey), parse_hex_array::<96>(&pop)) else { +121: let _ = tx.send(Msg::Bye { reason: "pubkey is 48 bytes hex and pop 96".into() }.line()); +122: break; +123: }; +124: if !verify_pop(&pk, &pp) { +125: let _ = tx.send(Msg::Bye { reason: "proof of possession does not verify".into() }.line()); +126: break; +127: } +128: let Some(addr) = parse_hex_array::<20>(&payout) else { +129: let _ = tx.send(Msg::Bye { reason: "payout is 0x followed by 40 hex".into() }.line()); +130: break; +131: }; +132: let reveal = KeyReveal { pubkey: pk, pop: pp }; +133: let key_hash = reveal.key_hash(); +134: let worker: String = label.chars().filter(|c| c.is_ascii_alphanumeric() || *c == '-' || *c == '_' || *c == '.').take(32).collect(); +135: let worker = if worker.is_empty() { "worker".to_string() } else { worker }; +136: let id = pool.next_member_id.fetch_add(1, Ordering::Relaxed) + 1; +137: let m = Arc::new(Member { +138: id, +139: address: format!("0x{}", hex::encode(addr)), +140: worker: worker.clone(), +141: key_hash, +142: reveal, +143: remote: remote.clone(), +144: connected_at: Instant::now(), +145: tx: tx.clone(), +146: inner: Mutex::new(MemberInner { +147: vardiff: Vardiff::new(pool.cfg.min_shift, pool.cfg.min_shift, pool.cfg.max_shift, pool.cfg.share_interval_s as f64, pool.now_s()), +148: jobs: VecDeque::new(), +149: last_parents: None, +150: last_seeds: None, +151: accepted: 0, +``` + +### I10 attempted-work selection + +`app/src/prover.rs:79-90` + +```text +79: /// The shard to prove next: assigned to one of our keys, unpaid, not already in the pool from us, not attempted +80: /// in this session; the newest first (its exclusive window is the one still open), the smallest among equals. +81: /// With nothing assigned, an open shard (spec 7.2 item 4: past its exclusive window, unpaid, anyone may prove it), +82: /// so a machine with no weight in the window still earns on what the assignees left. +83: pub fn choose(work: &[Work], attempted: &HashSet<(String, u32)>) -> Option { +84: let pick = |want_assigned: bool| { +85: let mut c: Vec<&Work> = work.iter().filter(|w| (if want_assigned { w.assigned } else { w.open }) && !w.paid && !w.in_pool && !attempted.contains(&(w.hash.clone(), w.shard))).collect(); +86: c.sort_by(|a, b| b.number.cmp(&a.number).then(a.pgas.cmp(&b.pgas))); +87: c.first().map(|w| (*w).clone()) +88: }; +89: pick(true).or_else(|| pick(false)) +90: } +``` + +### I10 mark attempt and launch + +`app/src/prover.rs:625-678` + +```text +625: let boundary = exec_boundary(&shared); +626: let work: Vec = work.into_iter().filter(|w| w.number >= boundary).collect(); +627: let Some(w) = choose(&work, &attempted) else { +628: set(&shared, |p| { +629: p.status = if submitted.is_empty() { "idle".into() } else { "submitted".into() }; +630: p.message = if assigned == 0 { format!("no shard assigned to this machine and none open in the last {} blocks", crate::segments::WORK_LOOKBACK) } else { "every assigned and open shard is proven or paid".into() }; +631: }); +632: continue; +633: }; +634: attempted.insert((w.hash.clone(), w.shard)); +635: let label = keys.iter().find(|(_, h)| *h == w.key_hash).map(|(l, _)| l.clone()).unwrap_or_else(|| keys[0].0.clone()); +636: let payout = shared.settings.lock().unwrap().address.clone(); +637: if payout.len() != 42 { +638: set(&shared, |p| { +639: p.status = "waiting".into(); +640: p.message = "no rewards address".into(); +641: }); +642: continue; +643: } +644: let started = Instant::now(); +645: set(&shared, |p| { +646: p.status = "proving".into(); +647: p.current = format!("block {} shard {} ({} txs, {} pgas{})", w.number, w.shard, w.tx_count, w.pgas, if w.assigned { "" } else { ", open" }); +648: p.started_at = crate::platform::unix_now_f(); +649: p.message = "exporting the chain and cutting the shard".into(); +650: }); +651: shared.log(&format!("prover: block {} shard {} assigned to {label}: export, cut, prove ({}), sign, submit", w.number, w.shard, if t.cuda { "CUDA" } else { "CPU" })); +652: // 2. export and cut +653: let dir = shared.runtime.app_dir.join("proving"); +654: let _ = std::fs::create_dir_all(&dir); +655: let seq = dir.join("seq.json"); +656: let fixture = dir.join(format!("block-{}.json", w.number)); +657: let results = dir.join(format!("results-{}-{}.json", w.number, w.shard)); +658: let outcome: Result<(), String> = (|| { +659: // the export from one block below (0.3.14): the node's account dump after block n-1 seeds the exporter; +660: // never from 0 (on a restarted node the records below the restart carry zero roots and the exporter +661: // refused every cut, the fleet 16:02Z) +662: let from = w.number.saturating_sub(1); +663: let export = evm_rpc(&shared, "igneum_exportSegments", json!([format!("{from:#x}"), format!("{:#x}", w.number)]), Duration::from_secs(120))?; +664: std::fs::write(&seq, export.to_string()).map_err(|e| e.to_string())?; +665: let (seq_p, fix_p, res_p) = if t.wsl { (wsl_path(&seq), wsl_path(&fixture), wsl_path(&results)) } else { (seq.display().to_string(), fixture.display().to_string(), results.display().to_string()) }; +666: let (ok, out) = run_tool(&shared, t, &t.export, &[seq_p, w.number.to_string(), fix_p.clone()], &[], Duration::from_secs(600), &dir.join(format!("export-{}.log", w.number))); +667: if !ok || !fixture.exists() { +668: return Err(format!("exporter: {}", out.lines().rev().find(|l| !l.trim().is_empty()).unwrap_or("failed"))); +669: } +670: set(&shared, |p| p.message = if t.cuda { "proving on the GPU".into() } else { "CPU prover: about five minutes a shard, 30 GB of RAM, paid only when no card proves first".into() }); +671: let prover_env = if t.cuda { "cuda" } else { "cpu" }; +672: let (ok, out) = run_tool(&shared, t, &t.host, &[fix_p, "--mode".into(), "compressed".into(), "--shard".into(), w.shard.to_string(), "--prover".into(), payout.clone(), "--out".into(), res_p], &[("SP1_PROVER", prover_env), ("RUST_LOG", "off")], Duration::from_secs(3 * 3600), &dir.join(format!("prove-{}-{}.log", w.number, w.shard))); +673: if !ok || !results.exists() { +674: let last = out.lines().rev().find(|l| l.contains("RESULT") || l.contains("rror")).unwrap_or("failed").to_string(); +675: // the root-socket class (5 October 2026, PC 2 at 20:00Z and 21:25Z): a job that ran the host as root +676: // inside WSL2 left /tmp/sp1-cuda-0.sock owned by root, and this user's client cannot open it +677: let hint = if last.contains("PermissionDenied") { " (a GPU-server socket /tmp/sp1-cuda-*.sock owned by another user, left by a job that ran the prover as root: remove it as that user, or run the socket-fix job)" } else { "" }; +678: return Err(format!("prover: {last}{hint}")); +``` + +### I10 failure + +`app/src/prover.rs:701-724` + +```text +701: })(); +702: match outcome { +703: Ok(()) => { +704: shared.event("proving", &format!("block {} shard {} proven and submitted in {:.0} s", w.number, w.shard, started.elapsed().as_secs_f64())); +705: submitted.push((w.number, w.hash.clone(), w.shard, w.shard_wei)); +706: set(&shared, |p| { +707: p.proved += 1; +708: p.submitted += 1; +709: p.status = "submitted".into(); +710: p.message = format!("block {} shard {} submitted; paid when a block carries it", w.number, w.shard); +711: p.current = String::new(); +712: }); +713: } +714: Err(e) => { +715: shared.log(&format!("prover: block {} shard {}: {e}", w.number, w.shard)); +716: set(&shared, |p| { +717: p.failed += 1; +718: p.status = "idle".into(); +719: p.message = e; +720: p.current = String::new(); +721: }); +722: } +723: } +724: } +``` + +## Earlier v6/proving source excerpts + + +Paths below are relative to each archive's top-level directory. Line numbering is from the supplied text, not web pagination. Excerpts preserve the source; historical comments may not equal the current implementation. Unquoted context should be inspected before patching. + +### F01 / predicate + +`igneum-v6-freeze-tree/igneum-pow/src/accept.rs:485-558` + +```text +485: /// Whether `class` is the class v4 shape (the 256-instruction shadow block over the class v3 base, the pass count and +486: /// the era set aside): the shape the sub-version 2 rules (a') and (c') apply to, on every draw path. +487: pub fn is_class_v4_shape(class: &LoadClass) -> bool { +488: matches!(class.shadow, Some(ShadowClass { instrs: V4_SHADOW_INSTRS, .. })) +489: // class v5 (docs/design/class-v5-stored-state.md) is judged under the same rules: its state flag is set aside; +490: // class v6 lane 1's index fold and re-weight table are set aside too (the address path and the op table are +491: // not the shape) +492: && LoadClass { era: None, shadow: None, state: false, fold: false, rw: 0, ..*class } == LoadClass { shadow: None, ..V4_CLASS } +493: } +494: +495: /// One pass of the dataflow freshness over the base program then the shadow block (the order of one iteration), +496: /// from `fresh`; `check` reports the first load that reads a register that is not fresh. The rule (AP-F8-1, +497: /// `docs/analysis/ca3-v4-uniform.md`): a load leaves its destination fresh only if its source was (a saturated +498: /// source reads one fixed word); add, sub, xor, mad and shfl if either operand was; rotl and rotr if the operand +499: /// was (a rotate maps all-ones and zero to themselves); or, mul and mulhi never. +500: fn freshness_pass(p: &Program, fresh: &mut [bool; 8], pair_op: &mut [Option<(Op, usize)>; 8], check: bool) -> Result<(), Reject> { +501: for (k, i) in p.instrs.iter().chain(p.shadow.iter()).enumerate() { +502: let (d, a) = (i.dst as usize, i.src as usize); +503: if check && i.op.is_load() && !fresh[a] { +504: return Err(Reject::UnfreshLoadSource { instr: k as u8, reg: i.src }); +505: } +506: // the shared-operand idiom (sub-version 3): or-then-xor or or-then-sub on one operand is `d & ~s`, xor-then-or +507: // is `d | s`: lossy, though the second op would inject on its own (F8's p23: `or r6 |= r4; xor r6 ^= r4`) +508: let masked = matches!((pair_op[d], i.op), (Some((Op::Or, s)), Op::Xor) | (Some((Op::Or, s)), Op::Sub) | (Some((Op::Xor, s)), Op::Or) if s == a); +509: fresh[d] = !masked +510: && match i.op { +511: Op::Load | Op::WLoad | Op::Scratch | Op::Hot => fresh[a], +512: Op::Add | Op::Sub | Op::Xor | Op::Mad | Op::Shfl => fresh[d] || fresh[a], +513: Op::Rotl | Op::Rotr => fresh[d], +514: Op::Or | Op::Mul | Op::MulHi => false, +515: }; +516: pair_op[d] = if matches!(i.op, Op::Or | Op::Xor) && !masked { Some((i.op, a)) } else { None }; +517: for r in 0..8 { +518: if r != d { +519: if let Some((_, s)) = pair_op[r] { +520: if s == d { +521: pair_op[r] = None; +522: } +523: } +524: } +525: } +526: } +527: Ok(()) +528: } +529: +530: /// Part (a'), class v4 sub-version 2: every load's source is fresh by dataflow in the loop's steady state. The draw +531: /// of `candidate_from_words_class` keeps in-pass sources fresh; this closes the iteration boundary (a source last +532: /// written late in the previous iteration or in the shadow block, which the draw's no-eligible fallback can pick: +533: /// F8's p11, an `or` at 63 feeding a load at 1). The state starts all fresh (the init words are a per-lane hash of +534: /// the nonce) and is run to its fixpoint (it only ever falls, so at most 8 passes change it), then one checking pass. +535: pub fn check_fresh_sources_v4(p: &Program) -> Result<(), Reject> { +536: if !is_class_v4_shape(&p.class) { +537: return Ok(()); +538: } +539: let mut fresh = [true; 8]; +540: let mut pair_op: [Option<(Op, usize)>; 8] = [None; 8]; +541: for _ in 0..9 { +542: let before = (fresh, pair_op); +543: freshness_pass(p, &mut fresh, &mut pair_op, false)?; +544: if (fresh, pair_op) == before { +545: break; +546: } +547: } +548: freshness_pass(p, &mut fresh, &mut pair_op, true) +549: } +550: +551: /// Parts (a), (b) and, for class v4 sub-version 2, (a'). +552: pub fn check_static(p: &Program) -> Result<(), Reject> { +553: if p.instrs.len() != INSTR_COUNT { +554: panic!("acceptance needs a {INSTR_COUNT}-instruction program"); +555: } +556: check_stale_loads(&p.instrs)?; +557: check_injecting_writes(&p.instrs)?; +558: check_fresh_sources_v4(p) +``` + +### F01 / gated dynamic checks + +`igneum-v6-freeze-tree/igneum-pow/src/accept.rs:808-871` + +```text +808: pub fn check_dynamic(p: &Program) -> Result { +809: let loads = p.loads_per_hash(); +810: let v4 = is_class_v4_shape(&p.class); +811: let sites = loads / ITERATIONS; +812: let mut acc = Acc { +813: sources: None, +814: indices: None, +815: sat_source: vec![0; sites], +816: and_acc: [u32::MAX; 8], +817: or_acc: [0; 8], +818: saturated: 0, +819: bit_ones: [0; 64], +820: distinct_sum: 0, +821: }; +822: let mut lane_addrs = vec![0u32; LANES * loads]; +823: for (unit, &base) in accept_base_nonces(&p.seed).iter().enumerate() { +824: run_unit(p, unit, base, &mut acc, &mut lane_addrs)?; +825: } +826: for reg in 0..8 { +827: let bits = (acc.and_acc[reg] | !acc.or_acc[reg]).count_ones(); +828: if bits != 0 { +829: return Err(Reject::ConstantBit { reg: reg as u8, bits: bits as u8 }); +830: } +831: } +832: if acc.saturated >= MAX_SATURATED { +833: return Err(Reject::Saturated { count: acc.saturated }); +834: } +835: // (c'), class v4 sub-version 2 (AP-F8-1, 7 October 2026): a load whose source is saturated reads one fixed word, +836: // whatever delivered the saturation (an or-written value, a rotate of one, a load after a saturated load); the +837: // source rule of the draw removes the writers it can see and this count catches every delivery. Keyed on the +838: // class v4 shape as the draw's rule is, so v2 and v3 verdicts do not move. +839: if v4 { +840: if let Some((site, &count)) = acc.sat_source.iter().enumerate().find(|(_, &c)| c >= MAX_SATURATED) { +841: return Err(Reject::SaturatedSource { site: site as u8, count }); +842: } +843: // (c''), the ratio on the candidate that passed everything else (the draw's last and dearest test); class v5 +844: // reads (c''') the hot-item rule on the same run (`docs/design/class-v5-stored-state.md` section 14), keyed +845: // on the state flag so no class v4 verdict moves +846: if p.class.state { +847: check_indices_v5(p)?; +848: } else { +849: check_distinct_indices_v4(p)?; +850: } +851: } +852: let half = (ACCEPT_HASHES / 2) as u32; +853: let mut bias_max = 0u32; +854: for (bit, &ones) in acc.bit_ones.iter().enumerate() { +855: let d = ones.abs_diff(half); +856: if d > BIAS_TOLERANCE { +857: return Err(Reject::OutputBias { bit: bit as u8, ones }); +858: } +859: bias_max = bias_max.max(d); +860: } +861: if acc.distinct_sum <= min_distinct_sum(loads - p.scratch_ops_per_hash()) { +862: return Err(Reject::DistinctAddresses { sum: acc.distinct_sum }); +863: } +864: Ok(AcceptReport { distinct_sum: acc.distinct_sum, saturated: acc.saturated, bias_max }) +865: } +866: +867: /// The whole rule: (a), (b), then (c). +868: pub fn check(p: &Program) -> Result { +869: check_static(p)?; +870: check_dynamic(p) +871: } +``` + +### F01 / generation and exhaustion + +`igneum-v6-freeze-tree/igneum-pow/src/generator.rs:1640-1657` + +```text +1640: // Class v4's load-source rule (AP-F8-1, 7 October 2026, `docs/analysis/ca3-v4-uniform.md`; sub-version 2): +1641: // a load's source is drawn only from registers that are FRESH by dataflow. Fresh at the program start (the init +1642: // words are a per-lane hash of the nonce); after an op, the destination is fresh when: a load's source was fresh +1643: // (a saturated source reads one fixed word and leaves a constant); add, sub, xor, mad or shfl had a fresh operand +1644: // (dst or src); rotl or rotr rotated a fresh value (a rotate maps all-ones to all-ones); never after or, mul or +1645: // mulhi (an or-written value is all-ones with probability (3/4)^32 per read, the 153x item of the finding; mul +1646: // zeroes low bits; mulhi is dense near zero). Sub-version 1 looked one writer back and counted every load and +1647: // rotate as fresh, which let an or-saturated value through a rotate or a load-after-load chain (F8's p6, p31). +1648: // Keyed on the class v4 shape (the 256-instruction shadow block over the class v3 base, the pass count and the +1649: // era set aside) on EVERY draw path, era or not, so a census through candidate_class reads the same stream as +1650: // the chain; v2, v3 and every other class take no part. The draw order and the stream are otherwise the same. +1651: // class v5 (docs/design/class-v5-stored-state.md) draws under the same rule: its state flag is set aside here too +1652: // class v6 lane 1: the index fold and the re-weight table are set aside too (the address path and the table are not +1653: // the shape; a +fold or +rw program draws its sources under the same rule) +1654: let source_rule_v4 = matches!(class.shadow, Some(ShadowClass { instrs: V4_SHADOW_INSTRS, .. })) +1655: && LoadClass { era: None, shadow: None, state: false, fold: false, rw: 0, ..class } == LoadClass { shadow: None, ..V4_CLASS }; +1656: // the op table and the roll's range: the plain table at 75 for every class without the re-weight flag +1657: let (weights, weights_sum) = class.nonload_weights(); +``` + +### F01 / attempt policy + +`igneum-v6-freeze-tree/igneum-pow/src/generator.rs:54-68` + +```text +54: /// Attempts before an implementation may treat the seed as a consensus fault (spec 01 section 1.4.6). At the +55: /// measured 5.14 percent rejection rate the chance of 32 consecutive rejections is below 2^-136. +56: pub const MAX_ATTEMPTS: u32 = 32; +57: +58: /// The attempt cap of class v4 sub-version 2 (AP-F8-2, 7 October 2026): rules (a') and (c') reject about two thirds of +59: /// candidates, so 32 attempts exhaust with probability about (2/3)^32, 2e-6 per epoch seed, one epoch no node could +60: /// draw every few decades at one epoch an hour (seen at chain-shaped seed igneum-f9/331672). At 256 attempts the +61: /// exhaustion probability is (2/3)^256, under 1e-45; the cost of a rejected attempt is one draw and the 64-unit check, +62: /// about 2 ms on one core, so the worst case is half a second. Keyed on the class v4 shape, so v2 and v3 keep 32. +63: pub const MAX_ATTEMPTS_V4: u32 = 256; +64: +65: /// The attempt cap of a class: [`MAX_ATTEMPTS_V4`] for the class v4 shape, [`MAX_ATTEMPTS`] otherwise. +66: pub fn max_attempts_for(class: &LoadClass) -> u32 { +67: if crate::accept::is_class_v4_shape(class) { MAX_ATTEMPTS_V4 } else { MAX_ATTEMPTS } +68: } +``` + +### F01 / fallback branch + +`igneum-v6-freeze-tree/igneum-pow/src/generator.rs:1848-1876` + +```text +1848: /// This is what the chain calls (`Epoch::from_seed_bytes`) with the 32-byte epoch seed, and what the packs call +1849: /// with the UTF-8 of a seed string. +1850: pub fn try_generate_from_seed_bytes(seed_string: &str, seed_bytes: &[u8]) -> Result { +1851: try_generate_class(seed_string, seed_bytes, LoadClass::V2) +1852: } +1853: +1854: /// [`try_generate_from_seed_bytes`] for a load class. +1855: pub fn try_generate_class(seed_string: &str, seed_bytes: &[u8], class: LoadClass) -> Result { +1856: let mut last = None; +1857: let cap = max_attempts_for(&class); +1858: for attempt in 0..cap { +1859: let p = candidate_class(seed_string, seed_bytes, attempt, class); +1860: match check(&p) { +1861: Ok(_) => return Ok(p), +1862: Err(r) => last = Some(r), +1863: } +1864: } +1865: if crate::accept::is_class_v4_shape(&class) { +1866: // AP-F8-2 (7 October 2026, main's ruling: the draw is total and no consensus path panics): a class v4 seed that +1867: // exhausts its attempts takes the last-resort program, deterministic. Sub-version 3's is accepted as drawn +1868: // (unreachable at 4.6e-44 per epoch and unverified against the rule: adv-accept-3's finding, 223 of 2,500 +1869: // rewritten candidates fail it, 209 by part (a)); class v5's is the verified one. +1870: if class.state { +1871: return Ok(last_resort_v5(seed_string, seed_bytes, cap, class)); +1872: } +1873: return Ok(last_resort_v4(candidate_class(seed_string, seed_bytes, cap, class))); +1874: } +1875: Err(Exhausted { seed_string: seed_string.to_string(), attempts: cap, last: last.unwrap() }) +1876: } +``` + +### F01 / separate census harness + +`igneum-v6-freeze-tree/docs/analysis/class-v6/census-packs.md:7-22` + +```text +7: | Pack | Program id (reproduced from the pack's seeds before any row) | Crate | Harness (branch, commit) | (A) the rule with (c''') on the pack's program | (B) attempts census, 256 chain-shaped seeds under the pack's era and state | (C) F8 on the live state-keyed dataset | Verdict | +8: |---|---|---|---|---|---|---|---| +9: | hl-v6-fold (the index fold alone, W = 4, base mix) | 482dc0dad937135b, attempt 1 | class-v6-fold 7880bc96 | class-v6-census-fold 5b3486f0 | accepted; min site ratio 0.99986; bucket +5.25 sigma; worst free bit 2.84 sigma; no site over 6 sigma (class v5's own program on the same state: -448 sigma at one site) | 256 of 256, 0 exhausted, r 0.701, mean attempt 2.34, max 14, (c''') 0.35 percent | 16 seeds p18 to p33 at 2^22: 16 PASS, at most 1.0455x of the window model (the class v5 control on the same seeds: 5 of 16 flagged on the 6-sigma bucket); the known-failed set at 2^24: p4 1.0057x (from 1.2163x), p8 1.1663x (+6.6 sigma bucket; from 1.3787x), p10 1.1868x (from 1.5052x), p15 PASS, p212 1.0411x (+27 sigma; from 1.1917x), p225 1.2414x BEYOND (from 1.2457x: the value-level class, unmoved), p34 1.0486x with a +11.9 sigma bucket (from +5.06: the one regression) | **PASS** | +10: | hl-v6-rw (the k lane's table rw1: 16,14,4,12,4,11,10,2,10,0 in draw order, sum 83, `or` never drawn) | 30628f8adcf6035e, attempt 0 | class-v6-fold 7880bc96 | the same | accepted; min ratio 0.99990; bucket +5.5; worst bit 2.89; no site over 6 sigma | 256 of 256, 0 exhausted, r 0.117, mean attempt 0.13, max 2, (c''') 0.34 percent | 16 seeds: ratio at most 1.1526x (within), 4 of 16 flagged on the 6-sigma bucket (the control's own rate is 5 of 16); known-failed under this table's draw: p4, p34, p225 PASS, p8 +22 sigma, p10 +14, p15 +8.8, p212 +37 sigma buckets at ratios 1.00 to 1.15x | **PASS** | +11: | hl-v6-foldrw (fold and rw1) | 605d06cabc489f94, attempt 0 | class-v6-fold 7880bc96 | the same | accepted; min ratio 0.99993; bucket +5.75; worst bit 3.49; no site over 6 sigma | 256 of 256, 0 exhausted, r 0.117, mean 0.13, max 2, (c''') 0.34 percent | 16 seeds: 15 PASS, 1 flagged (p18), at most 1.0932x; known-failed: every ratio within (p4 1.0002x, p8 1.0138x, p10 1.0100x, p15 1.0088x, p34 1.0121x, p212 1.1111x, p225 1.0000x), buckets flagged on p15 (+9.3) and p212 (+24.5) | **PASS** | +12: | hl-v6-rw2 (the census lane's table 13,11,6,10,8,8,7,2,6,4, sum 75) | 09e91b0dcd458c77, attempt 1 | class-v6-fold 7880bc96 | the same | accepted; min ratio 0.99990; two sites with the stride bit at -64 sigma (no fold) | 256 of 256, 0 exhausted, r 0.410, mean 0.70, max 8, (c''') 1.15 percent | 16 seeds: seed p30 1.3111x over the window model (the control 1.0004x; hl-v6-rw's worst 1.1526x), BEYOND the 1.2x gate; known-failed under its draw: p8 1.2507x (+42.8), p10 1.5044x (+100.9), p225 1.4049x beyond, p34 +70.7 and p15 +13.2 sigma buckets, p4 and p212 PASS | **FAIL** on the F8 line | +13: | hl-v6-win (the 64-register full-chain window alone, `+reg64c`) | f42d4a743ce7d4fa, attempt 0 (the v5-dn3-epoch0 seeds and state) | reg64-v5 198d171d | class-v6-census-reg64 b29e690d2 | accepted (with the liveness probe); min ratio 0.99923; bucket +5.5; the base program's stride-bit site at -448 sigma (no fold) | 256 of 256, 0 exhausted, r 0.716, mean 2.52, max 15, (c''') 1.66 percent (the window does not enter the draw: class v5's rows) | the window's own address stream through the interpreter's tracing probe, 32 sites of the interleaved schedule, 16 seeds at 2^22, the era laid over, closed form: per-site distinct ratio 1.0026 to 1.0027 on every site (the (c'') form; the control 0.9946 to 1.0027); the item histogram's top-0.1-percent share 1.0645 to 1.5624x of a flat control against the control's 1.0738 to 1.5074x, paired by seed 0.968 to 1.036x of the control. The attack-f8 mirror and the known-failed set do not apply (eight registers) | **PASS** (the live-dataset point owed) | +14: | hl-v6-all (window, fold and rw1) | 9d40978601a7df2a, attempt 0 | class-v6 3f25a8305 (the texts at c245d50b9, the verifier unchanged) | class-v6-census-all 2d54a4633 | accepted; min ratio 0.99993; bucket +5.75; worst bit 3.49; no site over 6 sigma | 256 of 256, 0 exhausted, r 0.117, mean 0.13, max 2, (c''') 0.34 percent | the trace on 32 sites: per-site distinct ratio 1.0026 to 1.0027; item share 1.0443 to 1.5132x flat against the foldrw control's 1.0398 to 1.4616x, paired 1.004 to 1.035x | **PASS** (the live-dataset point owed) | +15: +16: The controls: the freeze's class v5 pack v5-dn3-epoch0 (e5a4ac5978462156) through the whole harness at 15:53 UK (the dry run: the known-failed set reproduces the record to three places, p4 1.2163x, p8 1.3787x, p10 1.5052x, p212 1.1917x, p225 1.2457x) and class v5 on the node1 state over the same 16 seeds at 2^22 (16 of 16 within 1.2x, worst 1.0698x; 5 of 16 flagged on the 6-sigma windowed bucket: the statistic's own rate on the family at 2^22, so a pack's 4 or 5 flags is the control's and a pack's 0 of 16 is a gain). +17: +18: What the sheet means. The index fold does what it was drawn for: the stride-bit bias is gone from every program it ships, the F8 tails of 1.22 to 1.50x come inside the gate (1.01 to 1.19x) and the bucket concentration at narrow-window sites falls from the control's 5 of 16 seeds to 0 of 16; p225's value-level class is untouched and p34 gains one bucket statistic. The k lane's table (rw1, `or` never drawn, `mul` at 4) reads clean and gives the lowest rejection rate measured on the family (0.117); the census lane's table (rw2, `or` 4, `mul` 6) keeps the lossy writers the tails come from and fails the F8 line, so the re-weight is sound in the rw1 form only. The window changes nothing the rule or the F8 form sees at 2^22 on the closed form and carries the fold's and the table's rows unchanged; its value is the chip-side cost the adversary lane prices. +19: +20: ## 1. The harness +21: +22: The class v5 crate of each pack's branch plus lane D's family-gate harness diff (`docs/analysis/class-v6/logs/harness-family-gate-v5-3dc3117c.diff`: `IGNEUM_FAMILY_GATE` widens the class v4 rules to the family's shapes, with every new class flag set aside in `is_family_shape`: state, fold, rw, wide8, reg64, reg64_chain), plus: a `sitestats` command (the whole rule with (c'''), then per site over 2^20 evaluations the distinct ratio against the window model, the largest 256-item bucket in sigma, the largest index-bit excess in sigma over the free bits); the `accept` walk at the class's own cap under the flag; the attack-pass lane's `attack-f8` with `--load-class ` (the program drawn from a class string with the spec's era laid over it) and `--dataset-words N` (the ds55 geometry through `load_index_geom`; not exercised: a state class refuses the non-power-of-two count); the uniform trace tool `tools/attack/v6-census/uniform` on `verify::Probe { trace_loads }` (every load's index per lane through the interpreter itself). Binaries pinned per crate under `/srv/builds/v6-census/bin//` with sha256: fold-5b3486f0 (igneum-pow 50903d30, attack-f8 9ba2210b), reg64-1b676975 (v6census-uniform b2214265 after the fixes), all-d7d441be (igneum-pow 5a221e56, v6census-uniform 2ebd92c1). +``` + +### F02 / base acceptance execution + +`igneum-v6-freeze-tree/igneum-pow/src/accept.rs:601-634` + +```text +601: /// One unit of the dynamic test: the interpreter of `verify.rs` with the closed-form dataset, instrumented. +602: /// Returns the first lane-constant load site, if any. +603: fn run_unit(p: &Program, unit: usize, base: u32, acc: &mut Acc, lane_addrs: &mut [u32]) -> Result<(), Reject> { +604: let seed = &p.seed; +605: let mask: u32 = (1u32 << ACCEPT_DATASET_LOG2) - 1; +606: let (d0, d1) = (seed[0], seed[1]); +607: let (h0, h1) = (seed[2], seed[3]); +608: let hot_words = p.hot_words(); +609: let loads = p.loads_per_hash(); +610: let mut r = [[0u32; LANES]; 8]; +611: for lane in 0..LANES { +612: let nonce = base.wrapping_add(lane as u32); +613: for i in 0..8 { +614: let mut x = nonce ^ seed[i]; +615: x = x.wrapping_add(0x9e3779b9u32.wrapping_mul(i as u32 + 1)); +616: x = splitmix32(x); +617: r[i][lane] = x ^ seed[(i + 1) & 7]; +618: } +619: } +620: let mut idx = [0u32; LANES]; +621: let mut nload = 0usize; +622: let mut scratch = if p.has_scratch() { Some(ScratchModel::new(p.class.scratch_slots_per_lane())) } else { None }; +623: let slot_mask = p.class.scratch_slot_mask(); +624: let era = p.class.era; +625: // Class v4 sub-version 3 (AP-F8-3, 7 October 2026): the acceptance interpreter runs the latency-shadow block +626: // after instruction 63 of every iteration, `reps` times with the iteration's `sel`, exactly as the hash does +627: // (verify.rs). Until this commit it ran the 64 base instructions only, so every dynamic test (c) judged a class v4 +628: // program the chain never hashes. The shadow block holds no load, so its instructions take the same arms. +629: let shadow_reps = p.shadow_reps(); +630: for it in 0..ITERATIONS { +631: let sel = r[0]; +632: let shadow_pass = (0..shadow_reps).flat_map(|_| p.shadow.iter().enumerate().map(|(k, i)| (INSTR_COUNT + k, i))); +633: for (k, ins) in p.instrs.iter().enumerate().chain(shadow_pass) { +634: let d = ins.dst as usize; +``` + +### F02 / actual schedule and counters + +`igneum-v6-freeze-tree/igneum-pow/src/generator.rs:1153-1209` + +```text +1153: /// The reg64 full-chain fold in the program id: 1 = the load's own source out of the rotate-xor chain. +1154: pub const REG64_CHAIN_FOLD: u8 = 1; +1155: +1156: impl Program { +1157: /// Registers per lane (8, or 64 under `class.reg64`). +1158: pub fn registers(&self) -> usize { +1159: if self.class.reg64 { REG64_REGISTERS } else { 8 } +1160: } +1161: /// Whether every load's address consumes all 64 registers (the reg64 full-chain variant). +1162: pub fn address_mix(&self) -> bool { +1163: self.class.reg64 && self.class.reg64_chain +1164: } +1165: /// The pack's liveness statement (the reg64 variants): which reads keep every register necessary. +1166: pub fn reg64_liveness(&self) -> String { +1167: if !self.class.reg64 { +1168: return String::new(); +1169: } +1170: let loads = self.scheduled().iter().filter(|i| i.op == Op::Load).count(); +1171: if self.address_mix() { +1172: format!("every one of the 64 registers is read by the address of each of the {loads} loads per iteration (the load's source directly, the 63 others through the rotate-xor chain) and by the end fold; 64 independently necessary values for the length of the dependent chain; xoring any register with either of two seed-derived probe words at the start of an iteration moves the first load address and the final hash") +1173: } else { +1174: "every one of the 64 registers is read by the end fold (r[k] ^= r[k + 8] ^ ... ^ r[k + 56]); a load's address reads its own window's register only, so the chain needs 8 live values at a time and the other 56 are live across it as state (window, arithmetic-only)".to_string() +1175: } +1176: } +1177: /// The instructions one iteration executes, in order, with their register fields as the kernels name them. +1178: /// Without the reg64 flag this is the drawn program as it stands. Under the flag, instruction i of the drawn +1179: /// program runs on window 0 with every register field widened by `8 * (i % 4)` (so the 64 instructions touch all +1180: /// 32 registers of the window), then the same instruction runs on window 1 (the widened field + 32): 128 +1181: /// statements per iteration over registers 0..63. The CPU verifier and every emitter read this list, so the +1182: /// vectors and the kernel text agree by construction. +1183: pub fn scheduled(&self) -> Vec { +1184: if !self.class.reg64 { +1185: return self.instrs.clone(); +1186: } +1187: let mut out = Vec::with_capacity(self.instrs.len() * 2); +1188: for (i, ins) in self.instrs.iter().enumerate() { +1189: let off = (8 * (i % 4)) as u8; +1190: let a = Instr { dst: ins.dst + off, src: ins.src + off, src2: ins.src2 + off, ..*ins }; +1191: let b = Instr { dst: a.dst + 32, src: a.src + 32, src2: a.src2 + 32, ..a }; +1192: out.push(a); +1193: out.push(b); +1194: } +1195: out +1196: } +1197: pub fn loads_per_hash(&self) -> usize { +1198: self.instrs.iter().filter(|i| i.op.is_load()).count() * ITERATIONS +1199: } +1200: pub fn wide_loads_per_hash(&self) -> usize { +1201: self.instrs.iter().filter(|i| i.op == Op::WLoad).count() * ITERATIONS +1202: } +1203: pub fn has_wide(&self) -> bool { +1204: self.instrs.iter().any(|i| i.op == Op::WLoad) +1205: } +1206: /// Dataset bytes read per hash: 4 per one-word load, 16 and 64 for the wider loads of the experiment. +1207: pub fn bytes_per_hash(&self) -> usize { +1208: self.instrs.iter().filter(|i| i.op == Op::Load).map(|i| i.width as usize * 4).sum::() * ITERATIONS +1209: } +``` + +### F02 / live-dataset work owed + +`igneum-v6-freeze-tree/docs/analysis/class-v6/census-packs.md:40-49` + +```text +40: ## 4. Faults found and fixed on the way (the record, so no one repeats them) +41: +42: - The uniform tool's distinct sets as HashSet took 16 GB a thread at 2^22 nonces and were killed by the lease's memory cap; bit vectors over the dataset's words now. +43: - The reg64 interleaved schedule runs 32 load rows per iteration (instruction k on window 0 then window 1); the first read mapped them onto 16 sites (doubling N, ratios 1.35 to 1.80), the second mapped site s to load s mod 16 (the wrong window's expectation, ratios 0.84); site s is load instruction s / 2. +44: - The all pack's attack-f8 chain died at start on the fold-base tool (`+reg64c` unparsed); the class-v6 tool parses it but its mirror interprets eight registers, so the mirror is not the window's instrument. +45: - The lease pool is a race, not a queue; `env VAR="a b"` through it splits on spaces. +46: +47: ## 5. Owed +48: +49: The live-dataset F8 point at 2^24 for the two window packs (the mirror would need the two-window interpreter: four to six hours); the 64 x 2^24 point per pack (45 to 100 core-hours each); hl-v6-rw's files (on build-3, unreachable); the exact `or = 0` attempts rows are lane D's. +``` + +### F03 / full chain definition + +`igneum-v6-freeze-tree/igneum-pow/src/verify.rs:674-691` + +```text +674: // reg64 full chain: a load's address source is src ^ m, m the rotate-xor chain over the 63 other registers in +675: // index order (m = first; m = rotl(m, 1) ^ next). The source itself stays out of the chain: with it inside, a +676: // register whose term lands at rotation 0 mod 32 (r31, r63) cancels its own direct term, a dead register the +677: // liveness rule found on the pinned draw (first load src r31, 8 October 2026, 15:5x UK). +678: let addr_src = |r: &[[u32; LANES]], lane: usize| -> u32 { +679: if !address_mix { +680: return r[a][lane]; +681: } +682: let mut m = 0u32; +683: let mut started = false; +684: for k in 0..r.len() { +685: if k == a { +686: continue; +687: } +688: m = if started { m.rotate_left(1) ^ r[k][lane] } else { r[k][lane] }; +689: started = true; +690: } +691: r[a][lane] ^ m +``` + +### F04 / choice and confirmation + +`igneum-ember/app/igneum-app/src/ember.rs:549-619` + +```text +549: /// The choice: among the usable rows within `tolerance_pct` of the fastest row's rate, the best MH per watt; within +550: /// 1% on efficiency the higher rate wins; within 1% on both, the lower draw. A card never gives up more than the +551: /// tolerance in blocks for the saving. Marked rows never win. +552: pub fn choose(rows: &[Row], tolerance_pct: f64) -> Option { +553: let top = rows.iter().filter(|r| r.usable()).map(|r| r.mhs).fold(0.0, f64::max); +554: if top <= 0.0 { +555: return None; +556: } +557: let floor = top * (1.0 - tolerance_pct.max(0.0) / 100.0); +558: let mut best: Option<&Row> = None; +559: for r in rows.iter().filter(|r| r.usable() && r.mhs >= floor) { +560: best = Some(match best { +561: None => r, +562: Some(b) => { +563: let eff_tie = (r.eff - b.eff).abs() <= 0.01 * b.eff.max(r.eff); +564: if !eff_tie { +565: if r.eff > b.eff { r } else { b } +566: } else { +567: let mhs_tie = (r.mhs - b.mhs).abs() <= 0.01 * b.mhs.max(r.mhs); +568: if !mhs_tie { +569: if r.mhs > b.mhs { r } else { b } +570: } else if r.watts < b.watts { +571: r +572: } else { +573: b +574: } +575: } +576: } +577: }); +578: } +579: best.cloned() +580: } +581: +582: /// A confirm check's verdict: the prior stands, or the neighbour beat it by over CONFIRM_GAIN_PCT (the full plan is +583: /// due), or nothing could be read. +584: #[derive(Clone, Debug, PartialEq)] +585: pub enum Verdict { +586: Keep(Row), +587: FullDue { prior: Row, better: Row }, +588: NoReadings, +589: } +590: +591: pub fn confirm_verdict(rows: &[Row], tolerance_pct: f64) -> Verdict { +592: let Some(prior) = rows.first().filter(|r| r.usable()).cloned() else { +593: return match choose(rows, tolerance_pct) { +594: Some(r) => Verdict::FullDue { prior: Row::default(), better: r }, +595: None => Verdict::NoReadings, +596: }; +597: }; +598: match choose(rows, tolerance_pct) { +599: Some(best) if best.point != prior.point && best.eff > prior.eff * (1.0 + CONFIRM_GAIN_PCT / 100.0) => Verdict::FullDue { prior, better: best }, +600: _ => Verdict::Keep(prior), +601: } +602: } +603: +604: // ---- the fleet prior ------------------------------------------------------------------------------------------ +605: +606: /// The key a prior is filed under: card model (spaces as underscores), driver major, program class. +607: pub fn prior_key(card: &str, driver: &str, class: &str) -> String { +608: format!("{}|{}|{}", card.trim().replace(' ', "_"), driver_major(driver), if class.is_empty() { "v2" } else { class }) +609: } +610: +611: /// "581.57" -> "581", "32.0.15801" -> "32", "" -> "0". +612: pub fn driver_major(driver: &str) -> String { +613: let d: String = driver.trim().chars().take_while(|c| c.is_ascii_digit()).collect(); +614: if d.is_empty() { "0".into() } else { d } +615: } +616: +617: /// The program class from a race line's features (loads and wide loads per hash); the generator fixes both today. +618: pub fn program_class(loads: u32, wide: u32) -> String { +619: if loads == 0 { "v2".into() } else { format!("l{loads}w{wide}") } +``` + +### F04 / final confirmation behaviour + +`igneum-ember/app/igneum-app/src/ember.rs:948-973` + +```text +948: /// What the plan concludes: the full plan's choice; the confirm plan keeps its prior unless the neighbour beat +949: /// it (then the prior still holds the card and the engine schedules the full plan); the baseline is itself. +950: fn decide(&self) -> Option { +951: match self.plan.kind { +952: PlanKind::Baseline => self.rows.first().cloned().filter(|r| r.usable()), +953: PlanKind::Confirm => match confirm_verdict(&self.rows, self.plan.tolerance_pct) { +954: Verdict::Keep(r) => Some(r), +955: Verdict::FullDue { prior, .. } if prior.usable() => Some(prior), +956: Verdict::FullDue { better, .. } => Some(better), +957: Verdict::NoReadings => None, +958: }, +959: PlanKind::Full => choose(&self.rows, self.plan.tolerance_pct), +960: PlanKind::Climb => { +961: if self.plan.climb.as_ref().map(|c| c.goal) == Some(Goal::MaxRate) { +962: self.rows.iter().filter(|r| r.usable()).max_by(|a, b| a.mhs.partial_cmp(&b.mhs).unwrap_or(std::cmp::Ordering::Equal)).cloned() +963: } else { +964: choose(&self.rows, self.plan.tolerance_pct) +965: } +966: } +967: } +968: } +969: +970: /// After a confirm plan: did the neighbour beat the prior (the full plan is due)? +971: pub fn full_due(&self) -> bool { +972: self.plan.kind == PlanKind::Confirm && matches!(confirm_verdict(&self.rows, self.plan.tolerance_pct), Verdict::FullDue { .. }) +973: } +``` + +### F06 / helper candidates and task + +`igneum-ember/app/igneum-app/src/powertask.rs:113-142` + +```text +113: /// Where the installed exe lives: the per-user install, then the old administrator install. +114: pub fn install_candidates() -> Vec { +115: [ +116: std::env::var_os("LOCALAPPDATA").map(|l| PathBuf::from(l).join("Programs").join("Igneum Miner").join("igneum-app.exe")), +117: std::env::var_os("ProgramFiles").map(|p| PathBuf::from(p).join("Igneum Miner").join("igneum-app.exe")), +118: ] +119: .into_iter() +120: .flatten() +121: .collect() +122: } +123: +124: /// The PowerShell that prints the task's action (what `reregister` is proven by). +125: pub fn readback_command() -> String { +126: format!("$t = Get-ScheduledTask -TaskName '{TASK_NAME}' -ErrorAction SilentlyContinue; if ($t) {{ Write-Output ($t.Actions[0].Execute + ' ' + $t.Actions[0].Arguments) }}; exit 0") +127: } +128: +129: /// The PowerShell that registers the task (run inside the ONE elevated step, with the caps). `exe` is this +130: /// executable's path in the install folder. Principal: the signed-in user, interactive logon, highest run level; no +131: /// trigger; may start on battery; one hour limit per run; multiple starts are ignored while one runs. +132: pub fn register_script(exe: &Path) -> String { +133: let exe = exe.display().to_string().replace('\'', "''"); +134: format!( +135: "$a = New-ScheduledTaskAction -Execute '{exe}' -Argument '--power-helper' -WorkingDirectory '{dir}'\r\n\ +136: $p = New-ScheduledTaskPrincipal -UserId ([System.Security.Principal.WindowsIdentity]::GetCurrent().Name) -LogonType Interactive -RunLevel Highest\r\n\ +137: $s = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -ExecutionTimeLimit (New-TimeSpan -Hours 1) -MultipleInstances IgnoreNew -Hidden\r\n\ +138: Register-ScheduledTask -TaskName '{name}' -Action $a -Principal $p -Settings $s -Force | Out-Null\r\n\ +139: exit 0\r\n", +140: dir = exe.rfind(['\\', '/']).map(|i| exe[..i].to_string()).unwrap_or_default(), +141: name = TASK_NAME +142: ) +``` + +### F06 / helper elevated path and exits + +`igneum-ember/app/igneum-app/src/powertask.rs:184-267` + +```text +184: /// The helper process (`igneum-app --power-helper`): polls `/cmd.txt` twice a second, runs the parsed commands +185: /// through nvidia-smi, logs what it ran to `/helper.log`, ends on `quit`, on `remove` (after unregistering the +186: /// task) or after 20 idle minutes. `dir` is `/app/sweep`. +187: pub fn run_helper(dir: &Path) -> i32 { +188: let _ = std::fs::create_dir_all(dir); +189: let cmd_file = dir.join("cmd.txt"); +190: let log_file = dir.join("helper.log"); +191: let log = |line: &str| { +192: use std::io::Write; +193: if let Ok(mut f) = std::fs::OpenOptions::new().append(true).create(true).open(&log_file) { +194: let _ = writeln!(f, "{} {line}", crate::platform::unix_now()); +195: } +196: }; +197: log("helper started (scheduled task, elevated)"); +198: // a stale file from an earlier run is not a command: only lines after the start count +199: let mut last_seq: u64 = std::fs::read_to_string(&cmd_file).ok().and_then(|t| t.lines().filter_map(parse_line).map(|(s, _)| s).max()).unwrap_or(0); +200: let mut last_text = String::new(); +201: let mut dev = "0".to_string(); +202: let mut idle = Instant::now(); +203: let smi = crate::platform::tool("nvidia-smi"); +204: loop { +205: let text = std::fs::read_to_string(&cmd_file).unwrap_or_default(); +206: if text != last_text { +207: last_text = text.clone(); +208: for (seq, c) in text.lines().filter_map(parse_line) { +209: match c { +210: HelperCmd::Quit => { +211: log("quit"); +212: return 0; +213: } +214: HelperCmd::Remove => { +215: let mut p = std::process::Command::new(crate::platform::tool("powershell")); +216: p.args(["-NoProfile", "-ExecutionPolicy", "Bypass", "-Command", &remove_command()]); +217: crate::platform::quiet(&mut p); +218: let ok = p.status().map(|s| s.success()).unwrap_or(false); +219: log(&format!("remove: the task is {}", if ok { "unregistered" } else { "still registered (Unregister-ScheduledTask failed)" })); +220: return if ok { 0 } else { 1 }; +221: } +222: _ if seq <= last_seq => continue, +223: HelperCmd::Reregister => { +224: last_seq = seq; +225: idle = Instant::now(); +226: let Some(target) = install_candidates().into_iter().find(|p| p.is_file()) else { +227: log(&format!("{seq} reregister: no installed exe found")); +228: continue; +229: }; +230: let script = dir.join("register-power-task.ps1"); +231: let ok = std::fs::write(&script, [b"\xEF\xBB\xBF".as_slice(), register_script(&target).as_bytes()].concat()).is_ok() && { +232: let mut p = std::process::Command::new(crate::platform::tool("powershell")); +233: p.args(["-NoProfile", "-ExecutionPolicy", "Bypass", "-File", &script.display().to_string()]); +234: crate::platform::quiet(&mut p); +235: p.status().map(|s| s.success()).unwrap_or(false) +236: }; +237: let mut q = std::process::Command::new(crate::platform::tool("powershell")); +238: q.args(["-NoProfile", "-ExecutionPolicy", "Bypass", "-Command", &readback_command()]); +239: crate::platform::quiet(&mut q); +240: let now = q.output().map(|o| String::from_utf8_lossy(&o.stdout).trim().to_string()).unwrap_or_default(); +241: log(&format!("{seq} reregister {}: the task now runs {now}", if ok { "ok" } else { "failed" })); +242: } +243: HelperCmd::Dev(d) => { +244: last_seq = seq; +245: idle = Instant::now(); +246: dev = d; +247: log(&format!("{seq} dev {dev}")); +248: } +249: other => { +250: last_seq = seq; +251: idle = Instant::now(); +252: let args = smi_args(&dev, &other).unwrap_or_default(); +253: let mut p = std::process::Command::new(&smi); +254: p.args(&args); +255: crate::platform::quiet(&mut p); +256: let out = p.output().map(|o| format!("{}{}", String::from_utf8_lossy(&o.stdout), String::from_utf8_lossy(&o.stderr))).unwrap_or_else(|e| e.to_string()); +257: log(&format!("{seq} nvidia-smi {} : {}", args.join(" "), out.replace('\n', " ").trim())); +258: } +259: } +260: } +261: } +262: if idle.elapsed() >= Duration::from_secs(IDLE_S) { +263: log("idle 20 min: exit (the engine starts the task again when it needs it)"); +264: return 0; +265: } +266: std::thread::sleep(Duration::from_millis(500)); +267: } +``` + +### F07 / physical coexistence rows + +`igneum-v6-freeze-tree/docs/analysis/class-v6/coexist-rows.md:75-86` + +```text +75: ## The table +76: +77: | Card | Miner alone (ds55) | Proof alone (compressed 2^26) | Together | Register windows (v5 kit worker) | +78: |---|---|---|---|---| +79: | RTX 3060 12 GB | 26.82 MH/s at 117.4 W, 6,129 MiB resident, fingerprint 23ced07a4d28b465, PASS | 13.2 s, VERIFIED, peak 7,525 MiB, 122 W | 6,129 + 7,525 = 13,654 MiB against 12,288: TIME-SHARING NEEDED. Live attempt: the card filled to 11,893 MiB and the prover died in a device allocation (raw_buffer.rs:271) after 34 s; the miner held 26.51 MH/s through it (1.2 percent under alone). Proof with the miner paused = the proof-alone row | hl-reg64c 13.47 MH/s, 87 regs, 16 of 24 blocks per SM, fingerprint 4e7cc25967eba280 MATCH, 120.8 W; hl-reg64 13.48 MH/s, 104 regs, 16 of 24, 70e786af1a457653 MATCH, 119.3 W | +80: | RTX 4060 8 GB | 18.84 MH/s, 6,116 MiB resident, fingerprint 23ced07a4d28b465, PASS (no watts: host sensor N/A) | 8.2 s, VERIFIED, peak 7,532 MiB | 6,116 + 7,532 = 13,648 MiB against 8,188: TIME-SHARING NEEDED. Live attempt: the server died in a tensor allocation (inner.rs:51) at 7,811 MiB after 5 s; the miner held 18.83 MH/s | hl-reg64c 9.51 MH/s, 87 regs, 20 of 24 blocks per SM, fingerprint MATCH; hl-reg64 9.57 MH/s, 104 regs, 16 of 24, MATCH | +81: +82: Not measured and why: a core-only proof beside the miner (igneum-prove-host-0317 has no `--mode core`: "Error: unknown mode core"; its modes are native, execute, shard, compressed, block, all); watts on the 4060 (the host's power sensor reads N/A). +83: +84: ## Reconciliation with the served row +85: +86: The served sentence (litepaper, "Proving", from `docs/analysis/prover-tiers-real-cards.md`, 6 October 2026) says an RTX 3060 (12 GB) "mines at 23.78 MH/s and proves the v1 shard beside its miner at an 8.9 GB peak in 37.5 s". Today's row on the same card tier reads a 7.5 GiB compressed peak that kills the prover beside a 6.1 GiB miner. The two are not in conflict; they measured different things. The 6 October row is the matrix's `miner-comp-26-v1` point (`tools/fleet/box-matrix.sh` section 7): the patched server at threshold 2^26 in compressed mode, driven by the matrix host (the segment host build at `/opt/igneum-segal/.../igneum-prove-host`, which also carries `--mode core`; the matrix's core rows come from it), beside `igneum-miner mine` on the 1 GiB class v3 pack, whose resident set was 1.4 GB: 1.4 + 7.5 = 8.9 GB, inside 12 GB, proof in 37.5 s with the miner running. Today's row is igneum-prove-host-0317 in compressed mode at the same threshold 2^26 (the same 7.5 GiB own footprint, 7,525 to 7,532 MiB peak alone), beside the ds55 miner on the 5.5 GiB dataset of the genesis floor, whose resident set is 6.1 GB: 6.1 + 7.5 = 13.6 GB, outside 12 GB and 8 GB alike, so the prover's allocation fails while the miner keeps mining. What changed between the rows is the miner's dataset (1 GiB then, 5.5 GiB now), not the prover. The rule that follows: at the 5.5 GiB floor a compressed shard proof beside a running miner needs a 16 GB card (13.6 GB together; the 16 GB tier's own peak is 18 GB on the stock sizes and 7.8 GB patched, so 16 GB holds both with about 2 GB spare); 8 GB and 12 GB cards time-share, proving with the miner paused (13.2 s on the 3060, 8.2 s on the 4060) and mining otherwise. The 6 October beside rows stand only for the 1 GiB dataset; the 6 October core-only beside rows (5.6 GB own on the 3060, 27.2 s) stand only for core mode on the segment host, which the 0317 host does not expose, and are not a coexistence claim at the floor. The served sentence is read as a 1 GiB-dataset row until the site lane rewrites it against this record. +``` + +### F07 / default memory profile patch + +`igneum-proving/proving/prover-floor/sp1-gpu-6.8.1-floor.patch:111-190` + +```text +111: +/// Igneum prover-floor patch (5 October 2026). Upstream sizes every device buffer for a 24 GB card or larger +112: +/// and panics below that, whatever the shard. Here the card's memory (or `SP1_GPU_MEMORY_BUDGET_GB`) picks a +113: +/// tier, and `SP1_GPU_ELEMENT_THRESHOLD` / `SP1_GPU_RECURSION_TRACE_ALLOCATION` set the two buffers directly. +114: +/// The proof format, the verifier and the program ids do not change: the element threshold only decides where +115: +/// the executor splits shards, as upstream's own 24 GB tier already does. +116: +fn env_usize(name: &str) -> Option { +117: + std::env::var(name).ok().and_then(|s| s.parse::().ok()) +118: +} +119: + +120: +fn env_f64(name: &str) -> Option { +121: + std::env::var(name).ok().and_then(|s| s.parse::().ok()) +122: +} +123: + +124: +/// The core element threshold for a memory budget in GB (upstream's own figure for the budget, +4, as it +125: +/// computed it: a 32 GB card is 36, a 24 GB card 28, a 16 GB card 20, a 12 GB card 16). +126: +pub fn element_threshold_for_budget(gpu_memory_gb: usize, full_size_shards: bool) -> u64 { +127: + if gpu_memory_gb > 30 || (full_size_shards && gpu_memory_gb >= 24) { +128: + ELEMENT_THRESHOLD +129: + } else if gpu_memory_gb >= 24 { +130: + ELEMENT_THRESHOLD - (1 << 26) - (1 << 25) - (1 << 24) +131: + } else if gpu_memory_gb >= 18 { +132: + (1 << 27) + (1 << 26) +133: + } else { +134: + 1 << 27 +135: + } +136: +} +137: + +138: +/// The recursion trace allocation (elements) for a memory budget. +139: +pub fn recursion_trace_allocation_for_budget(gpu_memory_gb: usize) -> usize { +140: + if gpu_memory_gb >= 24 { +141: + RECURSION_TRACE_ALLOCATION +142: + } else { +143: + RECURSION_TRACE_ALLOCATION +144: + } +145: +} +146: + +147: +pub fn gpu_memory_gb() -> usize { +148: + let gb = 1024.0 * 1024.0 * 1024.0; +149: + match env_f64("SP1_GPU_MEMORY_BUDGET_GB") { +150: + Some(b) => (b.ceil() as usize) + 4, +151: + None => (((cuda_memory_info().unwrap().1 as f64) / gb).ceil() as usize) + 4, +152: + } +153: +} +154: + +155: +pub fn recursion_trace_allocation() -> usize { +156: + env_usize("SP1_GPU_RECURSION_TRACE_ALLOCATION") +157: + .unwrap_or_else(|| recursion_trace_allocation_for_budget(gpu_memory_gb())) +158: +} +159: + +160: pub fn local_gpu_opts() -> SP1CoreOpts { +161: let mut opts = SP1CoreOpts::default(); +162: +163: let log2_shard_size = 24; +164: opts.shard_size = 1 << log2_shard_size; +165: +166: - let gb = 1024.0 * 1024.0 * 1024.0; +167: - +168: - // Get the amount of memory on the GPU. +169: - let gpu_memory_gb: usize = (((cuda_memory_info().unwrap().1 as f64) / gb).ceil() as usize) + 4; +170: - +171: - if gpu_memory_gb < 24 { +172: - panic!("Unsupported GPU memory: {gpu_memory_gb}, must be at least 24GB"); +173: - } +174: + // The card's memory plus 4, as upstream computed it (a 32 GB card reads 36), or the budget given. +175: + let gpu_memory_gb = gpu_memory_gb(); +176: +177: - let shard_threshold = if !opts.full_size_shards && gpu_memory_gb <= 30 { +178: - ELEMENT_THRESHOLD - (1 << 26) - (1 << 25) - (1 << 24) +179: - } else { +180: - ELEMENT_THRESHOLD +181: + let shard_threshold = match env_usize("SP1_GPU_ELEMENT_THRESHOLD") { +182: + Some(t) => t as u64, +183: + None => element_threshold_for_budget(gpu_memory_gb, opts.full_size_shards), +184: }; +185: + let height_threshold = opts.sharding_threshold.height_threshold; +186: +187: - tracing::debug!("Shard threshold: {shard_threshold}"); +188: + eprintln!( +189: + "FLOOR opts gpu_memory_gb={gpu_memory_gb} element_threshold={shard_threshold} height_threshold={height_threshold} recursion_trace_allocation={} full_size_shards={}", +190: + recursion_trace_allocation(), +``` + +### F08 / pipeline scope and distributions + +`igneum-proving/docs/analysis/proving-pipeline-2026-10-08.md:7-50` + +```text +7: ## The window and its limit +8: +9: The measurement window is the whole of 8 October's proving on the rented fleet, 07:00:26Z (first claim) to 14:27:15Z (last claim), read +10: from every prover box's own log after Devnet 3 was turned off at 15:34Z. Paid work exists only between 07:46:55Z and 10:43:10Z: 93 paid +11: segments, 172.88 IGN. From 11:45Z the chain stalled at the class v5 crossing and then partitioned (every solo branch carried old-object +12: blocks, the network restarted from the stall sink at 15:27Z and was turned off at 15:34Z), so every segment claimed after 11:45Z was +13: submitted into a chain that never paid it. The hold's declared workload (150 tx/s) ran 11:42Z to 12:23Z with inclusion, then without, so +14: no paid shard carries a hold transaction: the stage columns below are the fleet's proving of the chain's own blocks, under the pre-stall +15: load (the DEX and faucet lanes, the hold's earlier steps), on the 0.3.24 node (5b673577). The window asked for, two hours under the hold, +16: does not exist in the record; this is the honest substitute, and the instrument is in place for the next chain. +17: +18: ## The instrument +19: +20: Collector `tools/fleet/pipeline-collect.py` (hub-1's Devnet 3 node, `igneum_getProvingStatus` every 30 s; every prover's RESULT lines +21: every 5 min) and the per-box logs `/root/fleet/out/prover.log` written by `tools/fleet/box-prover.py`, pulled whole after the stop. Each +22: column names its lines. +23: +24: | column | source lines in prover.log | how the number is read | +25: |---|---|---| +26: | assignment wait | `RESULT claim segment A..B (n shards, fresh) margin=M tip=T` | not separable from the logs: a segment becomes claimable when its last block settles and the box claims on its next pass (passes every 15 s). The proxy recorded is the margin at claim, the DAA left before the deadline (600 DAA window): median 467, p5 (slowest) 557 is not a wait but an early claim. Block timestamps would give the wait exactly; Devnet 3 is off, so they are not read. | +27: | inputs | claim stamp to the chain's start (the `RESULT seg N chain` stamp minus its `wall`) | the export of the segment's records from the node, the pair check and the cuts | +28: | proving | `RESULT seg N chain k shard records, chain_len c, proof b bytes, shards P s, aggregation A s, wall W s, peak MiB` field P | the shard proofs on the card (SP1 floor server) | +29: | aggregation | the same line's A | the segment chain over the shard proofs | +30: | verification | chain stamp to `RESULT seg N shards accepted k of n` | the node's verification of each shard record at submission; it answers inside the second, so verification and submission are one column | +31: | inclusion and payment | `RESULT submitted ... end to end E s` to `RESULT paid ... after S s` | S is the prover's own clock from the record's acceptance to the payment read on its node | +32: | failure, retry | `RESULT seg N ... FAILED`, `RESULT segment_refused`, `RESULT unpaid`, `RESULT paid_other`, `record accepted on retry` | counted per kind | +33: | queue depth | `RESULT pass n no whole segment inside the margin (worklist N entries, tip T)` | N is the node's assigned-shard worklist as the prover reads it on each idle pass | +34: +35: ## Stage columns, seconds, every segment that reached the stage +36: +37: | stage | n | median | slowest 5 % | slowest 1 % | max | +38: |---|---|---|---|---|---| +39: | inputs (claim to export and cuts done) | 2,447 | 2.4 | 7.5 | 10.1 | 14.7 | +40: | proving (shard proofs) | 2,453 | 26.8 | 216.1 | 364.7 | 1,104.7 | +41: | aggregation (segment chain) | 2,453 | 22.8 | 44.2 | 96.4 | 156.6 | +42: | verification and shard-record submission | 2,453 | 0.0 | 2.0 | 2.0 | 10.0 | +43: | segment-record submission | 1,909 | 0.0 | 1.0 | 1.0 | 1.0 | +44: | claim to submitted (end to end) | 1,909 | 75.1 | 230.3 | 301.6 | 497.4 | +45: | inclusion and payment (submitted to paid) | 93 | 171.0 | 543.0 | 31,397 | 31,470 | +46: | claim to paid | 91 | 336.0 | 720.0 | 1,098 | 1,240 | +47: | peak GPU memory during the chain, MiB | 2,453 | 11,948 | 21,174 | 25,788 | 26,210 | +48: +49: The two 31,000-second payments are segments submitted before the 02:4xZ pause and paid when the chain resumed; without them the +50: inclusion-and-payment p99 is 902 s. The assignment wait is not in the table (see the instrument row). +``` + +### F08 / paid outcomes and expiry + +`igneum-proving/docs/analysis/proving-pipeline-2026-10-08.md:66-121` + +```text +66: ## Outcomes per tier and wasted work +67: +68: | tier | claimed | paid | stolen | refused | submitted, never paid | claimed, never submitted | work s paid | work s wasted | +69: |---|---|---|---|---|---|---|---|---| +70: | RTX 4090 | 2,515 | 48 | 98 | 93 | 1,322 | 959 | 7,025 | 183,524 | +71: | RTX 3060 12 GB | 313 | 0 | 0 | 0 | 34 | 280 | 0 | 6,765 | +72: | L40S | 273 | 10 | 25 | 28 | 147 | 63 | 1,196 | 26,026 | +73: | RTX 3090 | 263 | 34 | 8 | 30 | 152 | 41 | 6,484 | 34,855 | +74: | RTX 6000 Ada | 45 | 1 | 6 | 0 | 26 | 12 | 57 | 3,055 | +75: +76: - "submitted, never paid" (1,681 segments) is the partition: records accepted into a chain that never settled them after 11:45Z. It is +77: the day's largest waste and is not a pipeline fault; it is the fault of the afternoon (the fleet record). +78: - "claimed, never submitted" (1,355): the chain step failed or the claim was abandoned. The failures are counted below. +79: - The 3060 tier completed no paid segment in 313 claims: at 12 GB the chain runs out of margin (its proving median on completed chains +80: is above the 4090's by the card's ratio, and a 4090 claimant finishes the same segment first), so the 12 GB tier is a miner, not a +81: prover, on this segment size. The 3060's 34 submitted segments were all after 11:45Z (never paid for the partition's reason). +82: - Wasted work is the end-to-end seconds of every claimed segment that was not paid; the fleet spent 254,000 card-seconds (70 card-hours) +83: on segments that did not pay against 14,800 (4.1 card-hours) that did. Before the stall the ratio was about 3 to 1 (the steals and +84: refusals below); after it, everything was waste. +85: +86: ## Failures and retries +87: +88: - `RESULT seg N chain FAILED`: 900, median wall 2.7 s. 629 "NotFound: No such file or directory": the sm_89 floor tarball's +89: `igneum-prove-host` was a dangling link until the real host was served at 10:50Z (08:00 to 10:59Z, the fleet record's floor fault); +90: 264 "invalid string length" (the host's proof-bytes string on the 48 GB cards' larger segments); 4 OutOfMemory (12 GB cards). After +91: 10:50Z the NotFound class ended; the string-length class remains open for the node lane. +92: - `RESULT segment_refused`: 153. 62 "does not chain to segment N..N" (the previous segment's record moved under the claim), 54 "unproven: +93: the record is carried after the segment's deadline" (the chain step finished too late), 35 "segment already paid" (a faster claimant). +94: - Retries: 0 lines "record accepted on retry". The prover does not retry a failed chain; it drops the export and claims afresh. +95: - Failure rate on claims: 900 chain failures plus 153 refusals over 3,421 claims is 30.8 percent; without the floor-link class (fixed) it +96: is 12.5 percent. +97: +98: ## Steals: a faster claimant takes an assigned prover's reward +99: +100: `RESULT paid_other`: 137 segments this box had claimed were paid to another key, 4.0 percent of claims (98 on 4090s, 25 on L40S, 8 on +101: 3090s, 6 on the 6000 Ada). The time from this box's claim to the other key's payment read: median 306 s, p95 9,757 s (the long tail is the +102: same pause-and-resume as the payment column). The exclusive window (10 DAA seconds) does not hold a slow claimant's segment for it: a +103: second box that finishes its chain first is paid. The 3060 tier was never the winner and never the victim (it never finished). +104: +105: ## Queue depth over time +106: +107: The worklist as the provers read it on idle passes, median entries per hour (tip in the line): 02Z 596, 05Z 596, 08Z 596, 11Z 713, 14Z +108: 594. Bounded at about 600 entries (the 600 DAA unproven window times one entry a DAA) for the whole day; it did not grow, because a +109: segment leaves the list at its deadline whether proved or not. Growth would show the window itself lengthening; it did not. +110: +111: ## What this means +112: +113: - With the floor link fixed, the pipeline's own stages are fast: inputs 2 s, verification and submission under 2 s, aggregation 23 s +114: (75 s on a 3090); the proving stage sets the pace, 27 s median and 216 s at the slowest 5 percent, and payment lands 171 s after +115: submission (543 s at the slowest 5 percent) when the chain settles. +116: - The waste is structural, not incidental: 70 card-hours wasted against 4 paid, dominated by the partition, then by the floor fault, +117: then by steals and late chains (13 percent of claims). Two changes would cut the pre-stall waste: a claim that is honoured for the +118: window it was granted (the steal rate goes to zero) and a 12 GB tier that claims only segments it can finish (the 3060's 313 claims +119: earned nothing). +120: - The next chain (igneum-devnet-4) starts this instrument from block zero; the two-hour window under the hold's declared workload is +121: the first measurement to run on it, with block timestamps read so the assignment wait becomes a real column. +``` + +### F09 / host verification + +`igneum-proving/proving/igneum-prove/host/src/main.rs:477-509` + +```text +477: fn run_verify(pinned: &pinned::Pinned, proof_path: &str, statement: &str) -> Result<()> { +478: use sp1_sdk::blocking::{LightProver, Prover}; +479: let bytes = std::fs::read(proof_path).with_context(|| format!("read {proof_path}"))?; +480: let want: B256 = statement.parse().context("statement is not 32 bytes of hex")?; +481: stage("setup"); +482: let t = Instant::now(); +483: let verifier = LightProver::new(); +484: println!("RESULT setup: {:.3} s (light verifier, pinned key), shard program id {} at {}", t.elapsed().as_secs_f64(), pinned.shard_id, now()); +485: stage("verify"); +486: let t = Instant::now(); +487: let proof: sp1_sdk::SP1ProofWithPublicValues = bincode::deserialize(&bytes).context("the file is not a bincode SP1 proof")?; +488: let got = alloy_primitives::keccak256(proof.public_values.as_slice()); +489: let output = ShardOutput::from_bytes(proof.public_values.as_slice()); +490: let claimed = pinned::claimed_program_id(&proof); +491: let same_program = claimed == Some(pinned.shard_id); +492: let crypto_ok = same_program && verifier.verify(&proof, &pinned.shard_vk, None).is_ok(); +493: let ok = crypto_ok && got == want && output.is_some(); +494: let dt = t.elapsed().as_secs_f64(); +495: let program = match claimed { +496: Some(c) if same_program => format!("program id {c} (ours)"), +497: Some(c) => format!("program id {c} IS NOT OURS {} (the prover runs another guest build)", pinned.shard_id), +498: None => "not a compressed proof".to_string(), +499: }; +500: match &output { +501: Some(o) => println!("RESULT verify: {} in {dt:.3} s; block {} shard {} prover {} statement {got} (want {want}) {program} proof {} bytes at {}", if ok { "VERIFIED" } else { "NOT VERIFIED" }, o.number, o.shard_index, o.prover, bytes.len(), now()), +502: None => println!("RESULT verify: NOT VERIFIED in {dt:.3} s; public values are not a shard statement; {program} at {}", now()), +503: } +504: if ok { +505: Ok(()) +506: } else { +507: std::process::exit(3) +508: } +509: } +``` + +### F09 / aggregation verification + +`igneum-proving/proving/igneum-prove/host/src/main.rs:869-911` + +```text +869: fn run_verify_segment(pinned: &pinned::Pinned, proof_path: &str, statement: &str) -> Result<()> { +870: use sp1_sdk::blocking::{LightProver, Prover}; +871: let bytes = std::fs::read(proof_path).with_context(|| format!("read {proof_path}"))?; +872: let want: B256 = statement.parse().context("statement is not 32 bytes of hex")?; +873: stage("setup"); +874: let t = Instant::now(); +875: let verifier = LightProver::new(); +876: println!("RESULT setup: {:.3} s (light verifier, pinned aggregator key), aggregator id {} shard program id {} at {}", t.elapsed().as_secs_f64(), pinned.agg_id, pinned.shard_id, now()); +877: stage("verify-segment"); +878: let t = Instant::now(); +879: let proof: sp1_sdk::SP1ProofWithPublicValues = bincode::deserialize(&bytes).context("the file is not a bincode SP1 proof")?; +880: let got = alloy_primitives::keccak256(proof.public_values.as_slice()); +881: let output = BlockOutput::from_bytes(proof.public_values.as_slice()); +882: let claimed = pinned::claimed_program_id(&proof); +883: let same_program = claimed == Some(pinned.agg_id); +884: let crypto_ok = same_program && verifier.verify(&proof, &pinned.agg_vk, None).is_ok(); +885: let ids_ok = output.as_ref().map(|o| o.shard_vk == pinned.shard_id && (o.agg_vk == pinned.agg_id || (o.chain_len == 1 && o.agg_vk == B256::ZERO))).unwrap_or(false); +886: let ok = crypto_ok && ids_ok && got == want; +887: let dt = t.elapsed().as_secs_f64(); +888: let program = match claimed { +889: Some(c) if same_program => format!("aggregator id {c} (ours)"), +890: Some(c) => format!("aggregator id {c} IS NOT OURS {} (the aggregator runs another guest build)", pinned.agg_id), +891: None => "not a compressed proof".to_string(), +892: }; +893: match &output { +894: Some(o) => println!( +895: "RESULT verify-segment: {} in {dt:.3} s; block {} ({}) chain_len {} shards {} statement {got} (want {want}) {program}; inner ids {}; proof {} bytes at {}", +896: if ok { "VERIFIED" } else { "NOT VERIFIED" }, +897: o.number, +898: o.block_hash, +899: o.chain_len, +900: o.shard_count, +901: if ids_ok { "ours".to_string() } else { format!("NOT OURS (shard {} agg {} chain_len {})", o.shard_vk, o.agg_vk, o.chain_len) }, +902: bytes.len(), +903: now() +904: ), +905: None => println!("RESULT verify-segment: NOT VERIFIED in {dt:.3} s; public values are not a block statement; {program} at {}", now()), +906: } +907: if ok { +908: Ok(()) +909: } else { +910: std::process::exit(3) +911: } +``` + +### F09 / recorded enforcement and cold verification + +`igneum-proving/docs/spec/proving-enforcement.md:72-117` + +```text +72: | (6) incorrect rewards or consensus inputs: derivation authenticated, not only execution over supplied inputs | `enforced_a_statement_over_altered_rewards_or_payouts_is_vetoed_native_derivation_is_the_check` (a statement whose post-root came from execution over other rewards or payouts is not the native statement and pays nothing: the native veto, every node's own derivation) | executor, branch proving-payment of the fork at 421bb852 (on release-2.0.0-node's c04674fe), igneum-exec 67 passed on build-2 at 17:10 UK | team-tested for what the test holds (the derivation authenticated by every node's own execution: a statement over other rewards or payouts pays nothing); PENDING for the proof side, the register row "Negative test six, proof side: derivation inside the aggregator guest (P22 stage 3)", clock 18:00 UK on 9 October 2026, when its served label moves from PENDING to team-tested on its own test (section 7, stages 1 to 3) | +73: +74: The boundary sentence of the plan, carried in every served text that names the rule: a proof of execution is not a proof of authenticated consensus inputs, canonical history or data availability. What the rule proves today is that the carried record's statement is the native statement of this node's own execution and that an SP1 proof of that statement verifies; what consensus inputs the execution used, which history is canonical and whether the data is available are each the node's own reading, not the proof's. +75: +76: ## 4. The cost +77: +78: The verifier's time per record on the node, measured on build-2 under the lease tool (section 6 carries the RESULT lines). The budget per block: at most 8 shard records and 2 segment records per block (`MAX_RECORDS_PER_BLOCK`, `MAX_SEGMENT_RECORDS_PER_BLOCK`), verified in parallel on the body processor's thread pool, each verdict cached by proof hash, so a proof verified at relay time costs the block nothing. Measured (section 6, build-2, one EPYC 9454P core at nice 19 under the lease tool, the box loaded): 0.668 to 0.710 s per record and about 30 MB per concurrent verify. What the switch costs a block, from those figures: nothing for a block that carries no records; nothing for a proof the relay verified before its block (the cached verdict); the worst case is a block whose ten proofs all arrive cold with it, about 0.7 s wall on ten cores of the body processor's pool (7 s of CPU) and about 300 MB peak. At the hold's rate of one block a second, a producer that fills every block with cold proofs costs a validator 0.7 s of wall per block on ten cores, which the pool absorbs; a validator with fewer cores serialises the ten verifies (7 s a block) and falls behind, which is why the relay-time verify is the design's budget and the block-time verify its backstop. Per tier: every node class holds the 300 MB (8 GB rig, 12 and 16 GB card nodes, pool nodes); a Windows node verifies through `igneum-prove-host` and the daemon refuses to start with the rule set and no host. The 10 ms gate of the overview is the hash's per-warp CPU-verify gate, not this check's: an SP1 compressed proof verify is 70x it, a different class of check, and the cache above is what keeps it off the block's critical path. +79: +80: ## 5. Activation +81: +82: 1. The live Devnet 3 object does not move: the switch is false, the floor never, the digest unchanged, and the tests say so. +83: 2. igneum-testnet-1 already runs the body rule from block zero under its two pinned ids; this rollout adds the payment rule on the same floor (0), which changes nothing a testnet node pays (every carried record on the testnet has passed the body rule), and is the first live network under the full condition. +84: 3. The class v6 object (`docs/design/class-v6-rotating-family.md`, no consensus code yet) carries `verifier_in_consensus: true`: on from its block zero. Until that object exists, a network that wants the rule before class v6 sets its own floor through `proving_consensus_verify_daa` in the override file, the way the 0.3.16 rule was designed to land, one weight window above the rollout so every node runs the binary first. +85: 4. Every node must run a binary whose embedded keys are the object's pinned ids before the floor; the daemon refuses to start otherwise. +86: 5. Shipping: consensus code on the release line the shipper names (release-0.3.26 is the hotfix pair; the next node line opens as release-0.3.27); the main-repository branch lands on the box mirror master through the gate on the coordinator's word. +87: +88: ## 6. Results and measurements +89: +90: Filled from the box runs as they land; each line names the box, the command class and the time. +91: +92: | Time (UK) | Box | What | Result | +93: |---|---|---|---| +94: | 16:08 | build-2, suite class, 12 threads, nice 10 (the bounded pool held 13 free cores; the 24-thread ask waited) | `cargo test --release -p igneum-exec --lib enforced_` | 7 passed, 0 failed (the seven executor tests of section 3), 229 s wall with the compile | +95: | 16:11 | build-2, same class | `cargo test --release -p kaspa-consensus-core --lib the_verifier_switch` | 1 passed (the switch is off on every compiled object; Devnet 3 at never; the testnet floor 0; the digest moves once set; a file that omits it changes nothing) | +96: | 16:15 | build-2, suite class, 12 threads | `cargo test --release -p kaspa-consensus-core -p igneum-exec -p kaspa-consensus --lib` (the full lib suites on the branch; the first consensus build stopped on a missing `ConsensusApi` import at 16:11, fixed at 16:12) | igneum-exec 64 passed 0 failed; kaspa-consensus 138 passed 0 failed, 3 ignored (the six `proving_enforcement_tests::enforced_*` among them); kaspa-consensus-core 171 passed 0 failed, 4 ignored; 172 s wall with the compile | +97: | 17:22 | build-2, `tools/fast-time-remote.sh` (normal class), three local nodes, one CPU mining thread each | `infra/fast-time/proving-enforcement.mjs --floor 240 --before 90 --after 150 --real-proof ` (the fifth attempt; the first four were the harness's own faults: a bare boolean in the override file, the block tag's hex form, the forged block inside the exclusive window, a dead ssh leaving three nodes on the box) | RESULT PASS. Below the floor (A at DAA 118, block 101): A's trusting pool took shapes a, b, c, d and g and its templates carried them; A's own unmodified pool refused e (bad signature) and f (the native-execution veto), the same checks every honest node runs; H1 paid the first carried record, shape c (the real proof of another chain under A's statement), 0x8cc611991c3c400 wei to A's payout: ledger P21's finding, observed; the three records after it read "shard already paid" (shape g's duplicate among them). At the floor (A at DAA 247, block 229): the same five shapes carried by A; H1 paid nothing, carried nothing of A's (its blocks never entered H1's DAG), and H1 and H2 each logged four new REFUSED verdicts (3 to 7), one per carried record, in 0.000 to 0.003 s each (the cached verdict from the relay-time verify, the measured cold path above being the first verify). Result file on build-2: `/home/build/enforced-fixtures/floor-240-expect-refuse.json` | +98: | 16:34 | build-2 (AMD EPYC 9454P, 96 threads, 125 GB), `lease pool 1 --nice 19`, one core, the box at load 85 to 95 | the verify cost per record: `nativeverify::tests::a_real_proof_verifies_and_a_wrong_statement_is_refused` on a real compressed shard proof of the testnet join pass (build-1 `/srv/builds/tn-join-pass/prover/block-763-shard-0-compressed.bin`, 1,272,897 bytes), seven runs; `/usr/bin/time -v` for the memory | measured: 0.710, 0.683, 0.701, 0.671, 0.700, 0.687, 0.668 s one core (0.668 to 0.710 s, a loaded-box figure); peak resident 34.6 MB with the verify against 4.6 MB for the same binary without it, so about 30 MB per concurrent verify | +99: +100: ## 7. The staging statement for P22 +101: +102: P22: the rewards and the prover payouts are inputs to the shard proof, not outputs. The shard guest takes the segment's rewards and payouts as data and commits the post-root after them; a host can feed any list and the proof still verifies. Today the node's own derivation is the check: the statement must equal the node's native statement for that shard and payout, which used the rewards and payouts consensus derived, so a proof over another list matches no node's statement and pays nothing. +103: +104: The closure is staged. Each stage is a claim about one input and the check that holds it; no stage claims a self-contained proof of the whole state. +105: +106: | Stage | What becomes an output of a proof | What checks it until then | Status | +107: |---|---|---|---| +108: | 0 (today) | nothing: rewards and payouts are data in the shard statement (`BlockFixture.rewards`, `payouts`) | every node's native execution derives both and vetoes a statement that differs; enforced proving (this document) adds that the record's proof must verify for that statement | implemented | +109: | 1 | the shard proof's rewards list is checked against a commitment the aggregator carries in its public values (the mergeset's blue blocks and their subsidies, hashed) | the aggregator's commitment is itself data; every node recomputes it from the mergeset it holds and vetoes a segment statement whose commitment differs (spec 7.8 item 5, the native block statement) | next: the consensus-proof work of design 7, phase 2 | +110: | 2 | the payouts list is derived inside the aggregator guest from the carried records it verifies (the first valid record per shard, the pool credit split) | the node's `carried_payouts` is the native check of the same derivation; a segment statement whose payouts differ is vetoed | phase 2, after stage 1 | +111: | 3 | the rewards are derived inside the aggregator guest from consensus data it verifies (headers, blue sets) | the node's own derivation vetoes; this is the consensus proof proper, and only here do rewards stop being an input anywhere | phase 2, the last step | +112: +113: Until stage 3 lands, every stage's output is checked natively by every node, and the statement "the rewards and payouts are proven" is not made in any served text. The ledger entry P22 carries this table. +114: +115: ## 8. The fast-time harness case +116: +117: `infra/fast-time/proving-enforcement.mjs` (ran, PASS at 17:22 UK, section 6): three nodes on one fast-time network, two honest under the floor set a few epochs ahead (`proving_consensus_verify_daa` in the override, the boundary), one attacker with the body rule off and the verifier in trust mode. The attacker reads each shard's native statement for its own payout address from its node (`igneum_getShardPlan(block, payout)`), signs it (`igneum-miner sign-record`) and submits it with proof bytes of the seven shapes through `igneum_submitProofRecord`; its templates carry the records. Below the boundary the honest nodes accept the attacker's blocks and the v0 rule pays (the finding, observed); from the boundary every honest node refuses the carrying block (`IgneumInvalidProofRecord` or the 20-s drop) and `igneum_getProofRecords` shows no paid entry for any of the seven. The honest-pays-once case needs a real shard proof of the harness's own chain, which a CPU prover makes in minutes; the unit tests hold it meanwhile and the testnet holds it live. +``` + +### F10 / fee split in source + +`igneum-proving/proving/igneum-prove/core/src/executor.rs:194-213` + +```text +194: /// Igneum 2.0 D4: how a transaction's proving charge divides, exactly as the node (`igneum_exec::executor::proving_payment_split`). +195: /// Off: the whole charge burns. On: 90 percent is the provers' payment (to the pool escrow), 10 percent burns, the +196: /// rounding wei to the burn. +197: pub fn proving_payment_split(charge: u128, to_pool: bool) -> (u128, u128) { +198: if !to_pool { +199: return (0, charge); +200: } +201: let payment = charge / 100 * 90 + (charge % 100) * 90 / 100; +202: (payment, charge - payment) +203: } +204: +205: pub fn execute_range(db: &mut IgneumDb, chain_id: u64, env: &FixtureEnv, schedule: &FeeSchedule, rewards: Option<(&[(Address, U256)], U256, &[(Address, U256)])>, txs: &[ShardTx], carry_in: Carry, roots: bool) -> RangeOutcome { +206: // The fee set that meters this chain block: the schedule read at the block's own DAA score, so the guest +207: // replays the height switch as the node does. The base fees carried in are raised to this set's floors here +208: // (the node does the same; the record, and so the fixture, already carry the raised values). +209: let fees = schedule.at(env.daa_score); +210: let env = &FixtureEnv { base_fee_exec: env.base_fee_exec.max(fees.floor_exec_u64()), base_fee_proving: env.base_fee_proving.max(fees.floor_proving_u64()), ..env.clone() }; +211: let intrinsic_pgas = fees.pgas.intrinsic_pgas_per_tx; +212: let block_proving_limit = fees.block_proving_gas_limit; +213: let base_fee_exec = env.base_fee_exec as u128; +``` + +### F10 / execution fee credits + +`igneum-proving/proving/igneum-prove/core/src/executor.rs:297-337` + +```text +297: // Fee flows (design 4.1 and 4.4, spec 7.5 item 2), exactly as the node applies them. +298: let (status, gas_used, logs) = if insp.over_budget { +299: let gas_used = tx.gas_limit(); +300: let burned_exec = (gas_used as u128) * base_fee_exec; +301: let proving_charge = ((pgas_used as u128) * base_fee_proving).min(budget.saturating_sub(burned_exec)); +302: let tip_total = budget.saturating_sub(burned_exec + proving_charge); +303: db.bump_nonce(tx.sender); +304: db.sub_balance(tx.sender, U256::from(budget)); +305: let (proving_payment, _burned_proving) = proving_payment_split(proving_charge, env.proving_payment_to_pool); +306: if proving_payment > 0 { +307: db.add_balance(PROVING_POOL_ADDRESS, U256::from(proving_payment)); +308: } +309: let shares = developer_shares(tip_total, &insp.attributions, |code| registered_payee(db, code)); +310: let dev_total: u128 = shares.iter().map(|(_, w)| *w).sum(); +311: db.add_balance(t.miner, U256::from(tip_total - dev_total)); +312: for (payee, wei) in &shares { +313: if let Some(p) = payee { +314: db.add_balance(*p, U256::from(*wei)); +315: } +316: } +317: (false, gas_used, Vec::new()) +318: } else { +319: db.commit(state); +320: let (status, gas_used, logs) = if insp.pgas_aborted { +321: // Spec 7.5 item 2: charged like an out-of-gas transaction for what it consumed up to the abort; +322: // the gas beyond the abort point goes back to the sender and its tip part comes back from the +323: // miner. State changes reverted, nonce advanced (committed above), status 0, no logs. +324: let consumed = insp.gas_at_abort.unwrap_or(gas_used).clamp(tx.intrinsic_gas, gas_used); +325: let unconsumed = (gas_used - consumed) as u128; +326: db.add_balance(tx.sender, U256::from(unconsumed * price)); +327: db.sub_balance(t.miner, U256::from(unconsumed * (price - base_fee_exec))); +328: (false, consumed, Vec::new()) +329: } else { +330: (status, gas_used, logs) +331: }; +332: // The proving charge never takes the sender past the signed budget (design 4.1). +333: let proving_charge = ((pgas_used as u128) * base_fee_proving).min(budget.saturating_sub((gas_used as u128) * price)); +334: db.sub_balance(tx.sender, U256::from(proving_charge)); +335: let (proving_payment, _burned_proving) = proving_payment_split(proving_charge, env.proving_payment_to_pool); +336: if proving_payment > 0 { +337: db.add_balance(PROVING_POOL_ADDRESS, U256::from(proving_payment)); +``` + +### F10 / guest input + +`igneum-proving/proving/igneum-prove/core/src/fixture.rs:11-34` + +```text +11: /// The chain block's environment (design section 3), as the node computed it. +12: #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] +13: pub struct FixtureEnv { +14: pub number: u64, +15: pub hash: B256, +16: pub parent_hash: B256, +17: pub timestamp: u64, +18: pub miner: Address, +19: pub prevrandao: B256, +20: /// Base fees in wei per unit, both dimensions (fit in u64 on the devnet; the executor widens to u128). As the +21: /// node recorded them: already raised to the floors of the set that meters this block. +22: pub base_fee_exec: u64, +23: pub base_fee_proving: u64, +24: /// The chain block's DAA score: what the fee schedule is read at (`fees_v1_activation_daa`, 5 October 2026). +25: /// A fixture written before the switch existed has none, and 0 keeps it on the schedule's base set. +26: #[serde(default)] +27: pub daa_score: u64, +28: /// Igneum 2.0 D4 (`docs/design/proving-payment.md`): the node's `proving_payment_activation_daa` reached at this +29: /// chain block, so a transaction's proving charge (pgas used x f_p) is the provers' payment: 90 percent credited to +30: /// the proving pool escrow, 10 percent burned; false (every fixture written before the field) burns the whole +31: /// charge, as spec 5.1 stood. Exactly what the node does (`igneum_exec::executor::proving_payment_split`). +32: #[serde(default)] +33: pub proving_payment_to_pool: bool, +34: } +``` + +### F10 / guest deserialisation + +`igneum-proving/proving/igneum-prove/program/src/main.rs:1-16` + +```text +1: //! The shard guest. Input: bincode of `ShardInput` (environment, the shard's transactions, the carried-in +2: //! position, the prover's payout address, the witness). Output (public values): `ShardOutput` in its fixed byte +3: //! layout. Everything between is `igneum_prove_core::shard::shard_statement`, the same code the host runs +4: //! natively first. +5: +6: #![no_main] +7: sp1_zkvm::entrypoint!(main); +8: +9: use igneum_prove_core::shard::{shard_statement, ShardInput}; +10: +11: pub fn main() { +12: let input = sp1_zkvm::io::read_vec(); +13: let input: ShardInput = bincode::deserialize(&input).expect("ShardInput decodes"); +14: let out = shard_statement(&input); +15: sp1_zkvm::io::commit_slice(&out.to_bytes()); +16: } +``` + +### F10 / pinned build behaviour + +`igneum-proving/proving/igneum-prove/host/build.rs:1-39` + +```text +1: //! Stamps the host with a hash of the native sources it was built from (`IGNEUM_PROVE_SOURCES`, printed in the +2: //! host's first line; the stale-build class of 5 October 2026): `cat $(ls core/src/*.rs host/src/*.rs | sort) | +3: //! shasum -a 256 | cut -c1-16` in proving/igneum-prove. Same recipe as export/build.rs. +4: //! +5: //! The guests are pinned build artefacts (host/src/pinned.rs, elf/manifest.json), so a normal host build compiles +6: //! nothing for the zkVM and needs no Succinct toolchain. `IGNEUM_BUILD_GUESTS=1` builds both guests with sp1-build +7: //! (into target/elf-compilation/...), for `igneum-prove-pin` to turn into the next pinned set; see +8: //! proving/igneum-prove/pin-guests.sh. Building the guest on every machine is what gave the Mac and PC 2 different +9: //! program ids on 5 October 2026. +10: +11: use sha2::{Digest, Sha256}; +12: use std::path::Path; +13: +14: fn main() { +15: println!("cargo:rerun-if-env-changed=IGNEUM_BUILD_GUESTS"); +16: if std::env::var("IGNEUM_BUILD_GUESTS").map(|v| v == "1").unwrap_or(false) { +17: sp1_build::build_program("../program"); +18: sp1_build::build_program("../aggregator"); +19: } +20: +21: let root = Path::new(env!("CARGO_MANIFEST_DIR")).join(".."); +22: let mut files: Vec = Vec::new(); +23: for dir in ["core/src", "host/src"] { +24: for entry in std::fs::read_dir(root.join(dir)).expect("source dir") { +25: let name = entry.expect("entry").file_name().to_string_lossy().into_owned(); +26: if name.ends_with(".rs") { +27: files.push(format!("{dir}/{name}")); +28: } +29: } +30: } +31: files.sort(); +32: let mut h = Sha256::new(); +33: for f in &files { +34: let path = root.join(f); +35: println!("cargo:rerun-if-changed={}", path.display()); +36: h.update(std::fs::read(&path).expect("read source")); +37: } +38: println!("cargo:rerun-if-changed=build.rs"); +39: println!("cargo:rustc-env=IGNEUM_PROVE_SOURCES={}", &hex::encode(h.finalize())[..16]); +``` + +### F10 / new fee regression present + +`igneum-proving/proving/igneum-prove/host/src/main.rs:985-1018` + +```text +985: /// charges (pgas used x f_p over the executed transactions) sit in PROVING_POOL_ADDRESS, the post-root differs from +986: /// the recorded one (another statement, which is why the floor stays at never until this guest is pinned), and the +987: /// split's arithmetic is the node's. +988: #[test] +989: fn the_proving_payment_flag_moves_90_percent_of_the_charge_to_the_pool() { +990: use igneum_prove_core::config::PROVING_POOL_ADDRESS; +991: use igneum_prove_core::executor::{execute_block, load_pre_state, proving_payment_split}; +992: let f = load("fees-v1-shards2.json"); +993: assert!(f.expected.pgas_used > 0); +994: // off: the recorded roots, the pool holds the subsidy credit alone +995: let mut db = load_pre_state(&f.block); +996: let before = db.balance(PROVING_POOL_ADDRESS); +997: let off = execute_block(&mut db, &f.block); +998: assert_eq!(off.state_root, f.expected.post_state_root); +999: let pool_off = db.balance(PROVING_POOL_ADDRESS) - before; +1000: assert_eq!(pool_off, f.block.proving_pool_credit, "off: the 20 percent credit alone reaches the escrow"); +1001: // on: 90 percent of every executed transaction's proving charge joins it +1002: let mut block = f.block.clone(); +1003: block.env.proving_payment_to_pool = true; +1004: let mut db = load_pre_state(&block); +1005: let before = db.balance(PROVING_POOL_ADDRESS); +1006: let on = execute_block(&mut db, &block); +1007: let pool_on = db.balance(PROVING_POOL_ADDRESS) - before; +1008: let charges: u128 = on.executed.iter().map(|t| t.pgas_used as u128 * block.env.base_fee_proving as u128).sum(); +1009: let payment: u128 = on.executed.iter().map(|t| proving_payment_split(t.pgas_used as u128 * block.env.base_fee_proving as u128, true).0).sum(); +1010: assert!(charges > 0, "the fixture carries proving charges"); +1011: assert_eq!(pool_on - pool_off, alloy_primitives::U256::from(payment), "90 percent of the charges reach the escrow"); +1012: assert!(payment >= charges / 100 * 90 && payment <= charges / 100 * 90 + on.executed.len() as u128); +1013: assert_ne!(on.state_root, off.state_root, "another post-root: another statement"); +1014: assert_eq!(on.pgas_used, off.pgas_used, "the proving work is unchanged"); +1015: assert_eq!(proving_payment_split(100, true), (90, 10)); +1016: assert_eq!(proving_payment_split(7, true), (6, 1)); +1017: assert_eq!(proving_payment_split(7, false), (0, 7)); +1018: } +``` + +### F11 / late hardware model + +`igneum-v6-freeze-tree/docs/design/class-v6-rotating-family.md:572-584` + +```text +572: #### 10.0r The placed energies, and the three chips scored at them (the adversary lane's placed row, 17:5x UK: the 8-lane genesis core placed and routed on ASAP7 with its SRAM macros, SPEF, a gate-level VCD; the full core's routed run 38 of 58 tags in; the SRAM term modelled; node factors claimed; the coordinator's order 18:0x UK: these are the energies the served form uses) +573: +574: Placement and the clock tree add 32 percent to the class v4 draw (7.78 pJ per lane-op routed against 5.91 synthesised at ASAP7; 5.44 against 4.13 at N5), inside the k lane's +20 to +40 expectation; node-for-node k 0.53 at the 5090's lock for the genesis core (0.38 a node ahead), the full 18-family core scaled 0.59 and 0.42 until its routed row lands; the 32-lane genesis core (synthesis) 3.70 pJ at N5, k 0.36, 10 percent under the 8-lane core. **Placement takes a tenth off every per-joule ratio and nothing off the per-dollar ones.** The served convention at the placed energy, the 5090 at its 1,300 MHz lock over the complete machine (controller, host share, PSU, VRM, cooling in): +575: +576: | Chip, as a complete machine | Per joule, node-for-node | Per joule, a node ahead | USD per MH/s (per dollar against the card's about 16) | Label | +577: |---|---|---|---|---| +578: | The GDDR7 board (the chip anyone can build) | **1.6x** (1.4x to 1.8x); 1.4x the 5080; 2.5x the cohort card | 1.9x (1.5x to 2.1x); 1.7x the 5080; 2.9x the cohort | 4.84 (3.3x) | placed core, modelled memory and machine, measured card | +579: | The stored-half hybrid board (1 GiB of SRAM beside the DRAM; 10.0q) | about 2.4x | about 2.9x | 1.88 (8.5x); the 5.5 GiB floor raises its SRAM ticket to USD 690 a board | modelled on the placed core | +580: | The N2 SRAM die | 2.4x | 3.3x | 0.8 (about 20x) | modelled on the placed core | +581: +582: Scored on lane 3's seven conditions at these energies (a first reading on lane 3's rows, approximate; its own scoring with the sunk-development case replaces it by 21:00): the board's verdicts stand (its per-joule ratio falls a tenth, its dollars do not move; it passes all seven at a one to three year life); the hybrid's stand (it fails (b) and (c), the dollar conditions, which placement does not touch; on (e) it sits on the 3x line a node ahead and under it node-for-node); the die's stand on (a), (b), (c) and (f) (its dollars are the die's) and on (e) it now holds node-for-node (2.4x) and fails a node ahead (3.3x). **So the success statement holds for the pure DRAM board, fails for the SRAM die once sunk, and fails for the hybrid on the dollar conditions; the placed energies change no verdict and tighten every per-joule figure by a tenth.** The served energy sentence (10.0h) reads from this table. +583: +584: The proving-payment pin is in the code (the node-side hand, 17:03 UK): branch proving-payment of the fork at eaddbf83 on release-2.0.0-node's c04674fe, the suites green on build-2 (igneum-exec 66 passed, kaspa-consensus-core 174 passed): behind `Params::proving_payment_activation_daa` (u64::MAX on every object; the height is main's word) a transaction's proving charge (pgas used x f_p) is 90 percent credited to `PROVING_POOL_ADDRESS` and the block's `proving_pool_credit` (so 5.3's per-shard payout carries it) and 10 percent burned, the rounding wei to the burn; below the height the whole charge burns as 5.1 stood; the receipt's new field `proving_payment` shows the provers' part beside `burned_proving`. One fact before any height is named: the shard guest (`proving/igneum-prove/core/src/executor.rs` lines 290 and 318) still burns the whole charge, so the floor stays at never until the guest carries the same split behind the same switch and the object pins the new shard program id; set before that, no shard proof verifies past the floor. The economics row reads: "designed, in the code behind the constant; the guest's mirror owed before any height". +``` + +### F12 / launch boundary + +`igneum-v6-freeze-tree/igneum-pow/src/emit.rs:1553-1573` + +```text +1553: if p.has_scratch() { +1554: s.push_str("// Variant 5: the wrapper launches `warps` persistent warps over `nonces / 32` units (host.cu does not use it).\n"); +1555: s.push_str("cudaError_t igneum_launch_hash_bound(const uint32_t* ds, uint64_t* out, uint32_t baseNonce, uint32_t mask,\n"); +1556: s.push_str(&format!(" IgneumInitWords iw,{hot_decl} uint32_t nonces, uint32_t blockWarps, uint32_t* scratch, uint32_t warps, uint32_t salt) {{\n")); +1557: s.push_str(" if (blockWarps == 0u || blockWarps > 32u || warps == 0u || (warps % blockWarps) != 0u) return cudaErrorInvalidValue;\n"); +1558: s.push_str(" uint32_t block = 32u * blockWarps;\n"); +1559: s.push_str(" if (nonces == 0u || (nonces % (32u * warps)) != 0u) return cudaErrorInvalidValue;\n"); +1560: s.push_str(&format!(" igneum_hash_bound<<>>(ds, out, baseNonce, mask, iw{hot_pass}, scratch, nonces / 32u, salt);\n")); +1561: s.push_str(" return cudaGetLastError();\n"); +1562: s.push_str("}\n"); +1563: } else { +1564: s.push_str( +1565: "cudaError_t igneum_launch_hash_bound(const uint32_t* ds, uint64_t* out, uint32_t baseNonce, uint32_t mask,\n", +1566: ); +1567: s.push_str(&format!(" IgneumInitWords iw,{hot_decl} uint32_t nonces, uint32_t blockWarps) {{\n")); +1568: s.push_str(" if (blockWarps == 0u || blockWarps > 32u) return cudaErrorInvalidValue;\n"); +1569: s.push_str(" uint32_t block = 32u * blockWarps;\n"); +1570: s.push_str(" if (nonces == 0u || (nonces % block) != 0u) return cudaErrorInvalidValue;\n"); +1571: s.push_str(&format!(" igneum_hash_bound<<>>(ds, out, baseNonce, mask, iw{hot_pass});\n")); +1572: s.push_str(" return cudaGetLastError();\n"); +1573: s.push_str("}\n"); +``` + + +## Supplementary primary references + +These provide external implementation context, not validation of Igneum's results. Accessed 8 October 2026. + +- NVIDIA CUDA C++ Best Practices: https://docs.nvidia.com/cuda/cuda-c-best-practices-guide/index.html - profiling, transfer minimisation, register occupancy and allocation trade-offs. +- NVIDIA System Management Interface: https://docs.nvidia.com/deploy/nvidia-smi/index.html - supported power and clock controls and device identification. +- Succinct SP1 proof types: https://docs.succinct.xyz/docs/sp1/generating-proofs/proof-types - distinguish core/compressed proof costs and stages. +- Microsoft AppLocker path conditions: https://learn.microsoft.com/en-us/windows/security/application-security/application-control/app-control-for-business/applocker/understanding-the-path-rule-condition-in-applocker - path trust depends on who can change files. This is general security context, not an ACL audit of the user's installation. + +## Reproduction package + +Run `reproduce.py` for the original three-package checks and `integration_reproduce.py` for the added source-guarded models and supplied C99 unit test. See the ZIP README for root layout and commands. No network, GPU setting changes or fund transfers occur. + +The proposed native Rust assertions are included but NOT RUN. The model results intentionally expose discrepancies; they are not a declaration that these application behaviours are acceptable. Hardware rows and cost models remain team-reported. Unreviewed source or future changes require a new review. diff --git a/docs/plans/igneum-2.0-master/evidence/04_full_system/IGNEUM_V6_Full_System_Review_Harness.zip b/docs/plans/igneum-2.0-master/evidence/04_full_system/IGNEUM_V6_Full_System_Review_Harness.zip new file mode 100644 index 000000000..ab6ded00b Binary files /dev/null and b/docs/plans/igneum-2.0-master/evidence/04_full_system/IGNEUM_V6_Full_System_Review_Harness.zip differ diff --git a/docs/plans/igneum-2.0-master/evidence/04_full_system/IGNEUM_V6_Full_System_Review_Results.json b/docs/plans/igneum-2.0-master/evidence/04_full_system/IGNEUM_V6_Full_System_Review_Results.json new file mode 100644 index 000000000..f40489455 --- /dev/null +++ b/docs/plans/igneum-2.0-master/evidence/04_full_system/IGNEUM_V6_Full_System_Review_Results.json @@ -0,0 +1,345 @@ +{ + "review": "Igneum v6 five-package source and integration review", + "date": "2026-10-08", + "native_rust_gpu_sp1_or_fullnode_executed": false, + "baseline_checks": { + "scope": "2026-10-08 uploaded archives; no native Rust/GPU/node execution", + "source_guards": { + "accept_shape_flag_omission": true, + "eight_register_acceptance": true, + "unscheduled_acceptance": true, + "counter_uses_unscheduled_instructions": true, + "confirm_requires_efficiency_gain": true, + "address_chain_excludes_source": true + }, + "source_sha256": { + "pow/src/accept.rs": "a4baf9286508e73406dd05b9f89bc6660baf017f107c650ce09bda504cfc92f9", + "pow/src/generator.rs": "751f39aeedb2987856343e2a67c7aeca7daa47ddafe5192c50a19b1d425e3a8a", + "pow/src/verify.rs": "033ae9f2ccd32e1170e7ff4f259b206b26e78ddc9ebf68d7b26933794aa1f345", + "ember/src/ember.rs": "e1e9d83e37b3acb47e89027994dba1638d7c4c547a0d1f587b95455cbe3c4873", + "ember/src/powertask.rs": "ab7cefacdc0758cbf0d192cc464449a7b51ec6a6d0a614e43c1844538108ccd6", + "proof/core/src/executor.rs": "1db37a599b24d8f1a1ba3bae05b915fbcd1fa3134eb7a5a825c1e3aeb43cf62d", + "proof/elf/manifest.json": "dfbf66a2c8426e27b27fd8915325619e21f3d44478a7ed2e8d2d04ca9359df7c" + }, + "manifest_integrity": [ + { + "role": "shard", + "kind": "elf", + "file": "igneum-prove-program.elf", + "bytes": 2832504, + "sha256": "150f4c05a2951fc56174a87089707a030b18df8fbe7e053a66459edb83053083", + "manifest_match": true, + "declared_size_match": true + }, + { + "role": "shard", + "kind": "vk", + "file": "igneum-prove-program.vk", + "bytes": 104, + "sha256": "8b4da5bff86d963f4210a78e5d800a1cd00ab41b158f6962f4ac009edc249d4c", + "manifest_match": true, + "declared_size_match": null + }, + { + "role": "aggregator", + "kind": "elf", + "file": "igneum-prove-aggregator.elf", + "bytes": 319744, + "sha256": "143d9c243dd12e87e90be71f6b8cd42353e513bf8ce78903ef6f972f1bc9aa7b", + "manifest_match": true, + "declared_size_match": true + }, + { + "role": "aggregator", + "kind": "vk", + "file": "igneum-prove-aggregator.vk", + "bytes": 104, + "sha256": "ad17bc1ae5be816554dbb13cb5b4d242678adfb8e1a4f7247ceb8b5ba9001b9f", + "manifest_match": true, + "declared_size_match": null + } + ], + "shape_predicate_transcription": [ + { + "class": "v5", + "strengthened_shape": true, + "attempt_cap": 256, + "shape_gated_freshness_and_hot_index_checks": true, + "shape_gated_last_resort": true + }, + { + "class": "v5_fold_rw", + "strengthened_shape": true, + "attempt_cap": 256, + "shape_gated_freshness_and_hot_index_checks": true, + "shape_gated_last_resort": true + }, + { + "class": "v6_window", + "strengthened_shape": false, + "attempt_cap": 32, + "shape_gated_freshness_and_hot_index_checks": false, + "shape_gated_last_resort": false + }, + { + "class": "v6_full_chain_fold_rw", + "strengthened_shape": false, + "attempt_cap": 32, + "shape_gated_freshness_and_hot_index_checks": false, + "shape_gated_last_resort": false + } + ], + "load_counter_arithmetic": { + "base_loads_per_iteration": 16, + "iterations": 8, + "reported_loads_per_hash": 128, + "scheduled_reg64_loads_per_hash": 256, + "note": "Derived from generic counters versus scheduled() for a 16-load reg64 class, not measured memory transactions. The nested reg64 metadata separately reports the schedule correctly." + }, + "ember_confirm_transcription": [ + { + "name": "large_rate_deficit", + "tolerance_pct": 1.0, + "prior": { + "point": 1300, + "mhs": 50, + "watts": 80, + "ok": true + }, + "neighbour": { + "point": 1500, + "mhs": 100, + "watts": 180, + "ok": true + }, + "chosen_point": 1500, + "confirm_verdict": "Keep", + "prior_within_rate_floor": false, + "policy_violation": true + }, + { + "name": "modest_rate_deficit", + "tolerance_pct": 1.0, + "prior": { + "point": 1300, + "mhs": 98, + "watts": 100, + "ok": true + }, + "neighbour": { + "point": 1500, + "mhs": 100, + "watts": 103, + "ok": true + }, + "chosen_point": 1500, + "confirm_verdict": "Keep", + "prior_within_rate_floor": false, + "policy_violation": true + }, + { + "name": "legitimate_efficiency_gain", + "tolerance_pct": 1.0, + "prior": { + "point": 1300, + "mhs": 100, + "watts": 180, + "ok": true + }, + "neighbour": { + "point": 1500, + "mhs": 100, + "watts": 160, + "ok": true + }, + "chosen_point": 1500, + "confirm_verdict": "FullDue", + "prior_within_rate_floor": true, + "policy_violation": false + }, + { + "name": "prior_within_policy", + "tolerance_pct": 1.0, + "prior": { + "point": 1300, + "mhs": 99.5, + "watts": 90, + "ok": true + }, + "neighbour": { + "point": 1500, + "mhs": 100, + "watts": 103, + "ok": true + }, + "chosen_point": 1300, + "confirm_verdict": "Keep", + "prior_within_rate_floor": true, + "policy_violation": false + }, + { + "name": "max_rate_goal", + "tolerance_pct": 0.0, + "prior": { + "point": 1300, + "mhs": 99, + "watts": 90, + "ok": true + }, + "neighbour": { + "point": 1500, + "mhs": 100, + "watts": 103, + "ok": true + }, + "chosen_point": 1500, + "confirm_verdict": "Keep", + "prior_within_rate_floor": false, + "policy_violation": true + } + ], + "address_fold_algebra": { + "static_queries": 16384, + "queries_after_state_updates": 16384, + "mismatches": 0, + "seed": "0x1a6e0026", + "scope": "Exact subexpression equivalence only. Not a whole-hash run, GPU benchmark, exploit, reduction in state information, or ASIC cost result.", + "identity": "u[k]=ROTL32(r[k],63-k); P=prefix_xor(u,a); T=xor(u); address(a)=r[a]^ROTR32(P,1)^T^P^u[a]" + }, + "supplied_js_tier_tests": { + "returncode": 0, + "tests": "10", + "pass": "10", + "output": "TAP version 13\n# Subtest: the shipped table validates with no faults\nok 1 - the shipped table validates with no faults\n ---\n duration_ms: 3.341691\n type: 'test'\n ...\n# Subtest: the measured rows are the record's (the 5090 at its 1,300 MHz knee, the 5080 at 1,100, the 4070 at its tune, the 9070 XT grid, the M5 Max meter)\nok 2 - the measured rows are the record's (the 5090 at its 1,300 MHz knee, the 5080 at 1,100, the 4070 at its tune, the 9070 XT grid, the M5 Max meter)\n ---\n duration_ms: 0.701674\n type: 'test'\n ...\n# Subtest: every entry carries the three tiers where the card has a lever, and only max where it has none\nok 3 - every entry carries the three tiers where the card has a lever, and only max where it has none\n ---\n duration_ms: 1.564993\n type: 'test'\n ...\n# Subtest: the match rule takes the longer name: a 5070 Ti is not a 5070, a 4060 Ti is not a 4060, a 9060 XT is not a 9070 XT\nok 4 - the match rule takes the longer name: a 5070 Ti is not a 5070, a 4060 Ti is not a 4060, a 9060 XT is not a 9070 XT\n ---\n duration_ms: 0.615752\n type: 'test'\n ...\n# Subtest: a class flip reads stale exactly as src/ember.rs tiers_stale does\nok 5 - a class flip reads stale exactly as src/ember.rs tiers_stale does\n ---\n duration_ms: 0.454489\n type: 'test'\n ...\n# Subtest: known-failed: a power rung under 50 is refused\nok 6 - known-failed: a power rung under 50 is refused\n ---\n duration_ms: 0.861034\n type: 'test'\n ...\n# Subtest: known-failed: a row missing a field tier_from_json reads is refused\nok 7 - known-failed: a row missing a field tier_from_json reads is refused\n ---\n duration_ms: 1.304932\n type: 'test'\n ...\n# Subtest: known-failed: a tuned row dearer per hash than stock is refused, and a max tier that is not stock\nok 8 - known-failed: a tuned row dearer per hash than stock is refused, and a max tier that is not stock\n ---\n duration_ms: 1.611869\n type: 'test'\n ...\n# Subtest: known-failed: a card class of the brief left out is refused, and a stale uj (not w over mhs) is refused\nok 9 - known-failed: a card class of the brief left out is refused, and a stale uj (not w over mhs) is refused\n ---\n duration_ms: 2.807709\n type: 'test'\n ...\n# Subtest: known-failed: a table under another class is refused\nok 10 - known-failed: a table under another class is refused\n ---\n duration_ms: 1.569598\n type: 'test'\n ...\n1..10\n# tests 10\n# suites 0\n# pass 10\n# fail 0\n# cancelled 0\n# skipped 0\n# todo 0\n# duration_ms 86.25061\n" + }, + "supplied_ui_test_attempt": { + "returncode": 1, + "status": "BLOCKED_MISSING_SOURCE", + "missing": "ember/ui/app.js", + "output": "TAP version 13\n# node:fs:442\n# return binding.readFileUtf8(path, stringToFlags(options.flag));\n# ^\n# Error: ENOENT: no such file or directory, open '/mnt/data/igneum_v6_review/igneum-ember-2026-10-08/igneum-ember/app/igneum-app/ui/app.js'\n# at readFileSync (node:fs:442:20)\n# at file:///mnt/data/igneum_v6_review/igneum-ember-2026-10-08/igneum-ember/app/igneum-app/ui/tune-line.test.mjs:9:13\n# at ModuleJob.run (node:internal/modules/esm/module_job:274:25)\n# at async onImport.tracePromise.__proto__ (node:internal/modules/esm/loader:644:26)\n# at async asyncRunEntryPointWithESMLoader (node:internal/modules/run_main:117:5) {\n# errno: -2,\n# code: 'ENOENT',\n# syscall: 'open',\n# path: '/mnt/data/igneum_v6_review/igneum-ember-2026-10-08/igneum-ember/app/igneum-app/ui/app.js'\n# }\n# Node.js v22.16.0\n# Subtest: /mnt/data/igneum_v6_review/ember/ui/tune-line.test.mjs\nnot ok 1 - /mnt/data/igneum_v6_review/ember/ui/tune-line.test.mjs\n ---\n duration_ms: 51.870567\n type: 'test'\n location: '/mnt/data/igneum_v6_review/ember/ui/tune-line.test.mjs:1:1'\n failureType: 'testCodeFailure'\n exitCode: 1\n signal: ~\n error: 'test failed'\n code: 'ERR_TEST_FAILURE'\n ...\n1..1\n# tests 1\n# suites 0\n# pass 0\n# fail 1\n# cancelled 0\n# skipped 0\n# todo 0\n# duration_ms 63.240523\n" + }, + "not_executed": [ + "Native Rust test suites", + "CUDA / Metal / OpenCL kernels", + "SP1 proof creation or cryptographic verification", + "Full-node integration", + "Physical hardware or ASIC measurement" + ] + }, + "integration_checks": { + "scope": "Source-guarded transcriptions and supplied C test; NOT native Rust, GPU, SP1 or node execution", + "source_guards": [ + { + "path": "node/igneum/exec/src/proving.rs", + "sha256": "92302ee089fca720f2ee6ac0756c0054a01c995db4c997d358683a2a08f3401b" + }, + { + "path": "node/consensus/src/processes/finality.rs", + "sha256": "6194a96a80e5ec5a4daeb63afa8fda55a8c7a2f959d5becab60ea733790f5bf4" + }, + { + "path": "pool/src/payout.rs", + "sha256": "839619378b7e9b0b7eda22ce900aa2ada6410aa90e3d7f1f000a02f0b8449c1f" + }, + { + "path": "pool/src/state.rs", + "sha256": "54835bcf498328fdfb111f9a8911378d622c7ff57a87ca5ec5b58f41fe6e019d" + }, + { + "path": "app/src/prover.rs", + "sha256": "8dfd507d475ed2bd4a36385603c743d722009f092bda9113241f29b3c5e2d64c" + }, + { + "path": "workers/proto-metal/main.swift", + "sha256": "0f909ca4d20345635765e03442b06c79f34bc8a2ec8bdac22a3e87f6d7e209b5" + }, + { + "path": "workers/proto-cuda/nvrtc/worker.cpp", + "sha256": "faf4782ff0fbfdea594e4635200a75db9084f96c663053d7c074df8e5bebf92f" + } + ], + "proof_cache_model": { + "initial_valid": "VERIFIED", + "warm_wrong_statement": "VERIFIED", + "cold_wrong_statement": "INVALID", + "warm_wrong_kind_same_accepted_id": "VERIFIED", + "cold_wrong_kind_same_accepted_id": "INVALID", + "after_negative_cache_valid_record": "INVALID", + "fresh_valid_record": "VERIFIED", + "limitation": "Toy valid-proof oracle, no cryptography or block/record construction. A native two-node proof fixture is required." + }, + "anchored_finality_model": { + "before_window_100_percent": true, + "after_window_pause_mode_100_percent": false, + "after_window_recovery_mode_100_percent": true, + "recovery_50_percent": false, + "recovery_55_percent_left": true, + "recovery_55_percent_right": true, + "limitation": "Pure anchor predicate only. Both-55 example needs 10 percent equivocation; not a full GHOSTDAG simulation." + }, + "pool_crash_order_model": { + "owed": 100, + "broadcast_transactions": [ + { + "nonce": 0, + "amount": 100 + }, + { + "nonce": 1, + "amount": 100 + } + ], + "broadcast_total": 200, + "limitation": "Synthetic crash/RPC ledger schedule with ample pool funds; no real money, RPC, signature, or network used." + }, + "shard_retry_model": { + "initially_eligible": true, + "eligible_after_transient_failure_same_session": false, + "limitation": "Shard branch only. Segment retry logic is separate and exists." + }, + "memory_geometry_arithmetic": { + "declared_words": 1476395008, + "metal_log2_allocated_words": 1073741824, + "declared_bytes": 5905580032, + "metal_bytes": 4294967296, + "shortfall_bytes": 1610612736, + "two_dataset_bytes": 11811160064, + "two_pair_bytes_assuming_256_MiB_cache_each": 12348030976, + "limitation": "Arithmetic plus allocation-path inspection; not a GPU allocation or an observed out-of-bounds access." + }, + "native_c_packfile_test": { + "status": "EXECUTED", + "assertions_passed": 45, + "exit_code": 0, + "optional_real_pack_arguments": false, + "scope": "supplied C99 pack metadata/seed/geometry/leaf unit tests; no GPU" + } + }, + "archive_provenance": [ + { + "filename": "igneum-ember-2026-10-08(1).zip", + "sha256": "c219211b49fccda65b151df230b10ded5971ac2a8c7d1e5847c0a68bffe4cf4a", + "size": 78946 + }, + { + "filename": "igneum-mining-workers-2026-10-08.zip", + "sha256": "808abcecf157a3716d1c72fa6e76c540bf5808af1c0e4dd0fd888576d546cade", + "size": 6090014 + }, + { + "filename": "igneum-node-dag-2026-10-08.zip", + "sha256": "ead2cf94092b7e27aab2e44d653b2d969cb2a52878ef12abf6e5d7a9e7421cff", + "size": 1519903 + }, + { + "filename": "igneum-proving-2026-10-08(1).zip", + "sha256": "9ccf4112e274f586392e8e4a4f98ece2e82b4990fe5f1ee89ae0ee0a151ce01e", + "size": 1612294 + }, + { + "filename": "igneum-v6-freeze-tree-2026-10-08(1).zip", + "sha256": "f448981b2ceeab2e59e8bbd137a1a13ea1c730ecd9db72b9a89bd2bbf5d85acb", + "size": 696492 + } + ] +} diff --git a/docs/plans/igneum-2.0-master/evidence/IGNEUM_Algorithm_Review_Evidence.md b/docs/plans/igneum-2.0-master/evidence/IGNEUM_Algorithm_Review_Evidence.md new file mode 100644 index 000000000..9e2e720f7 --- /dev/null +++ b/docs/plans/igneum-2.0-master/evidence/IGNEUM_Algorithm_Review_Evidence.md @@ -0,0 +1,752 @@ +# IGNEUM - Mining algorithm source review and reproducible evidence + +**Date:** 8 October 2026 +**Basis:** `igneum-mining-algorithm-2026-10-08.zip` +**Archive SHA-256:** `94edb290005ecb8379cc599da90c877c7e25562f727cc4291069b4fbc149c7c1` + +## Executive assessment + +There is concrete room to improve this snapshot, especially program-resource guarantees, acceptance coverage, cryptographic boundaries, artifact identity and launch safety. This review does not establish that Igneum has the best GPU algorithm, reaches a 1.5x specialised-hardware ceiling, or contains a profitable live-network exploit. + +The supplied snapshot contains V2/V3/V4 paths, not the 64-register v6 described in the strategy discussion. Its actual production activation status is unknown from these files. Do not transfer old benchmark ratios to a modified candidate. + +## Scope and execution boundary + +The archive contains 13 source/document files (527,803 uncompressed bytes), including 11 Rust files, the algorithm specification and a README. It does not include Cargo.toml/Cargo.lock, the pack fixtures referenced by tests, the complete mining worker host, the node integration, raw GPU measurements, or adversarial RTL/physical-design reports. + +Rust, Cargo and CUDA were unavailable in the review environment. No original Rust test binary was built; no GPU kernel, live-node test or ASIC benchmark was run. The executable work is an independent C/Python transcription of the selected source paths. It is a diagnostic model, not a replacement implementation. + +The transcription matches the supplied genesis program id/op mix, two closed-form hashes, three rejection/attempt vectors, and all eight published header-bound memory-hard hash vectors. Those anchors increase confidence in the probes but do not prove complete equivalence for untested classes or hardware. + +The model supports V2 and the V3 era draw/base instructions, the fixed V2 cache/mixer, and optional ALU shadows. It excludes the experimental scratch, hot-table and derive-class variants. It does not certify all of the approximately 9,769 source/document lines. + +## Reproduced observations + +| Probe | Observation | Limit | +|---|---|---| +| V2 lane communication | 909/1,000 accepted programs lack all five shuffle dimensions | Structural bound, no ASIC speedup measured | +| V3 lane communication | 887/1,000 accepted programs lack all five dimensions | One fixed era; not V4 with its shadow | +| Memory concentration | 312/2,048 hashes hit 0x0fffffff at one site, with zero-header binding | One accepted V2 program and site; not overall traffic | +| Shadow coverage | A deliberately mutated zeroing shadow is invisible to the acceptance report | Not a canonically generated program or chain exploit | +| Identity | Two eras share program id ef42100d5403c90d but compute different hashes | Separate expected-era checking can mitigate | +| Dispatch grouping | Starting a batch at 1 changes the modelled result for nonce 2 | Host code is absent; no physical GPU run | +| Naive rejection patch | 32/1,000 seeds exhaust 32 attempts | Hypothetical bad patch, not current behaviour | + +All counts, seeds, vectors and detailed qualifications are in the accompanying JSON and runnable harness. CPU elapsed times in diagnostic logs are not mining-performance benchmarks. + +## Findings and exact source locations + +### A01 - The supplied snapshot is not the planned v6 + +The public class enum exposes V2, V3 and V4. Mutable per-lane state is eight 32-bit logical registers. V3 fixes reads to one 32-bit word (4 bytes); V4 adds a 256-instruction block repeated 27 times per iteration. These facts do not establish what is deployed or implemented elsewhere. + +**Original source:** `igneum-pow-src/generator.rs:780-819`; `igneum-pow-src/generator.rs:850-858`; `igneum-pow-src/verify.rs:335-354`. + +### A02 - Accepted short programs need not connect all 32 lanes + +For XOR-shuffle masks drawn from 1,2,4,8,16, k distinct dimensions allow components of at most 2^k lanes. An independent census of 1,000 accepted V2 and 1,000 accepted V3 programs found full mask span in only 91 and 113 respectively. Missing dimensions establish a connectivity bound, not a measured ASIC speedup. Full span is necessary, not sufficient, for all-lane influence. The V3 run uses one fixed era; these are not V4-shadow results. + +**Original source:** `igneum-pow-src/generator.rs:1230-1298`; `igneum-pow-src/accept.rs:276-304`; `igneum-pow-src/accept.rs:368-404`. + +### A03 - Per-hash address diversity can conceal per-site concentration + +An accepted V2 example, seed SHA256("igneum-review/139"), passes the transcribed acceptance checks. At iteration 5, instruction 51 (zero indexed), 312 of 2,048 sampled header-bound hashes read address 0x0fffffff when the exact V2 memory-hard dataset construction is used. Two additional initialisation contexts give 318 and 325 hits. This is one load site, not that fraction of all mining traffic, and it is not a demonstrated profitable caching attack. Proposed remedies are entropy-preserving state transitions and measured per-site/address-cache analysis. + +**Original source:** `igneum-pow-src/accept.rs:289-317`; `igneum-pow-src/accept.rs:347-397`; `igneum-pow-src/generator.rs:124-147`. + +### A04 - The acceptance interpreter omits the shadow that runtime executes + +accept.rs runs only p.instrs; verify.rs also runs program.shadow. A deliberately mutated Program with a valid-operand, zeroing 256-instruction shadow still passes the base-only acceptance check in the model and produces 32 zero outputs. The fixture is NOT generated by the canonical generator and does NOT show that the network accepts attacker-supplied programs. It demonstrates that the acceptance report does not cover full shadow semantics. Either retire the excluded long-program path in the new class or test its complete execution. + +**Original source:** `igneum-pow-src/accept.rs:178-207`; `igneum-pow-src/accept.rs:327-350`; `igneum-pow-src/verify.rs:370-395`. + +### A05 - Header binding and final digest deserve independent cryptographic review + +The seed/binding layer uses four salted FNV-1a runs with a final mixing step. The final result is a rotated-XOR fold into 64 bits, inserted into the top 64 bits of a 256-bit value. The target comparison is internally consistent: lane <= floor(T/2^192). This is not a demonstrated comparison bug, but it is not a 256-bit cryptographic final digest. Recommend reviewing a domain-separated cryptographic input/output envelope, including nonce and template binding, while keeping cheap inner operations where justified. Such a change needs new consensus versioning and benchmarks. + +**Original source:** `igneum-pow-src/seed.rs:34-49`; `igneum-pow-src/bind.rs:47-83`; `igneum-pow-src/verify.rs:390-395`. + +### A06 - Different V3 eras can have the same program_id + +The V3 and base-rung V4 identity path excludes the era parameters. The independent model produces two V3 programs with id ef42100d5403c90d and different era-dependent hashes. This is structural aliasing, not a brute-force collision. packcheck can compare a separately supplied expected era, which mitigates that path when used. Its directory check reads metadata, not kernel content. Use distinct, full semantic program, dataset and work identities; validate or regenerate executable artifacts against trusted inputs. + +**Original source:** `igneum-pow-src/generator.rs:1049-1065`; `igneum-pow-src/packcheck.rs:166-185`; `igneum-pow-src/packcheck.rs:215-229`; `igneum-pow-src/packcheck.rs:263-272`. + +### A07 - CUDA dispatch needs explicit canonical-group constraints + +The bound CUDA wrapper validates block shape but not 32-aligned baseNonce. The canonical verifier aligns nonce groups to a 32 boundary. CPU emulation of the kernel grouping gives nonce 2 = e5f5f4b14e9c87ae for a batch starting at 1, versus canonical 7342f96cbedb41d1. No GPU was run, and the omitted host may already prevent this. Add wrapper/host guards and tests for alignment, nonce-low rollover and refresh of nonce-high init words. + +**Original source:** `igneum-pow-src/emit.rs:1219-1243`; `igneum-pow-src/emit.rs:1260-1270`; `igneum-pow-src/bind.rs:99-119`. + +### A08 - An operation described as bijective is not always bijective + +Mad permits src2 == dst. For src == 1, dst += src*dst is 2*dst modulo 2^32. Distinct old destinations 0 and 2^31 both map to 0. This contradicts the unconditional bijective-in-dst description of injects(), but is not alone a lottery exploit. Restrict aliases or revise the invariant; separately examine destructive operations and address-state entropy. + +**Original source:** `igneum-pow-src/generator.rs:124-147`; `igneum-pow-src/generator.rs:1266-1282`; `igneum-pow-src/verify.rs:403-475`. + +### A09 - A naive stronger rejection test can exhaust all candidates + +In a hypothetical patch requiring all five XOR-shuffle dimensions while retaining the existing draw distribution and 32-attempt limit, 32 of 1,000 test seeds exhaust all attempts. This is NOT a failure observed under the unmodified acceptance rule. Construct essential invariants into the generator rather than naively adding a high-rejection check or using an unbounded consensus loop. + +**Original source:** `igneum-pow-src/generator.rs:1377-1404`. + +## Proposed next candidate - not a production patch + +1. Freeze the actual intended source and activation manifest; establish what is v6 and what has been retired. +2. Construct live state and lane-connectivity properties by design; do not rely only on a random instruction count or statistical rejection. +3. Analyse per-site addresses across nonces and headers, whole-dataset working sets and caching/recomputation alternatives. A permutation cannot restore entropy already collapsed to one value. +4. Use a common instruction semantics core for acceptance, reference execution and instrumentation. Keep CPU verification costs bounded. +5. Review a domain-separated cryptographic envelope and full-width final result. Bind expensive work to the job/nonce before finalisation; a cheap final hash alone must not allow intermediate-work reuse. +6. Introduce explicit semantic identities and trusted artifact validation. Keep work identity distinct from reusable program/dataset identity. +7. Fix dispatch preconditions and test all backends for canonical results. Target filtering, compilation caching and asynchronous staging are candidate byte-preserving miner optimisations, subject to inspecting the missing host implementation. +8. Compare every candidate with tuned commodity GPUs and a redesigned multi-epoch adversary at complete-board cost. No speedup or resistance multiplier is forecast by this review. + +Changes to program generation, binding, digest, operation semantics or dataset layout change the consensus function. They require a versioned transition, new vectors and compatibility tests. Host guards and byte-exact implementation optimisation should not silently change accepted hashes. + +## Native follow-up acceptance tests + +- Reproduce the exact corpus counts and vectors in the original Rust crate and independently check their source semantics. +- Add generated-program dependency/communication analysis and adversarial algebraic simplification, not just mask coverage. +- Census per-site address distributions over independent holdout seeds, multiple headers/nonces, actual memory-hard datasets and every proposed size; measure effective cache and bandwidth cost. +- Mutation-test the acceptance checker against all activated execution components. Keep canonical-generator tests separate from hostile fixtures. +- Check every semantic identity component for accidental omission and every pack input for substitution, stale state and mismatched compiled artifacts. +- Compare CUDA/Metal/OpenCL/CPU results at aligned/unaligned starts, tails, epoch transitions and 32-bit nonce rollover; preserve active-lane shuffle semantics. +- Reassess GPU register spills, occupancy, wall energy, CPU-verifier latency and sustained mining/proving coexistence on the final configuration. +- Rerun the 2.0 multi-epoch hardware and economic gates with no assumed chip retirement. An algorithm review cannot establish customer demand, network security, retention or category rank. + +## External primary-source context + +These references support the general engineering context, not the numerical observations about Igneum. + +- RFC 9923, FNV Non-Cryptographic Hash Algorithm, section 1.2: https://www.rfc-editor.org/rfc/rfc9923.html#section-1.2 +- ProgPoW reference design, program generation and cryptographic encapsulation: https://github.com/ifdefelse/ProgPOW +- NVIDIA CUDA Best Practices Guide, register/occupancy and memory optimisation: https://docs.nvidia.com/cuda/cuda-c-best-practices-guide/index.html +- RandomX design, device binding and easy-program selection: https://github.com/tevador/RandomX/blob/master/doc/design.md + +## Source excerpts + +Line numbers below refer to the unmodified files inside the supplied archive. These excerpts are included so the findings are auditable without assuming this report's interpretation. The source manifest records every file's SHA-256. + +### `igneum-pow-src/generator.rs:780-819` + +```text + 780 | pub const GENERATOR_VERSION_V3: u32 = 3; + 781 | + 782 | /// Generator version of a class v4 program (Counter ASIC 3.0, 6 October 2026, PROPOSED: `program_id(4, seed, attempt)`). + 783 | pub const GENERATOR_VERSION_V4: u32 = 4; + 784 | + 785 | /// The program class of an epoch (Counter ASIC 2.0, 5 October 2026, `docs/plans/counter-asic-2-rollout.md`): one + 786 | /// height switch in the node, `program_class_v3_activation_daa`, rounded up to an epoch boundary, decides which + 787 | /// class an epoch's program is drawn from. V2 is the lottery hash as adopted on 4 October 2026, byte for byte. + 788 | /// V3 is generator version 3: its program id carries `generator = 3` and its load class is [`V3_CLASS`]. + 789 | /// V4 (Counter ASIC 3.0, 6 October 2026, the candidate `mx8+sh256x27` behind `program_class_v4_activation_daa`) is + 790 | /// generator version 4: its program id carries `generator = 4` and its load class is [`V4_CLASS`]. + 791 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)] + 792 | pub enum ProgramClass { + 793 | #[default] + 794 | V2, + 795 | V3, + 796 | V4, + 797 | } + 798 | + 799 | /// The load class of program class v3, decided 5 October 2026 (Counter ASIC 2.0, `docs/plans/counter-asic-2-status.md` + 800 | /// "22:00 decided", `docs/plans/mixer-x4.md`): [`LoadClass::MX4`], version 2 loads (the width stays 4 bytes, the + 801 | /// per-load mix and the scratch share are out), the mixer applied 4 times per round and the cache growth rule. The + 802 | /// placeholder of the seam (w16) is replaced here; nothing else in the seam names the class. + 803 | /// Composed on 5 October 2026 (branch ca2-era): the era layout of `docs/plans/era-layout.md` is drawn inside this class by + 804 | /// [`generate_from_seed_bytes_program_class`] (`LoadClass::era(V3_CLASS, era, &V3_ALLOWED)`); here `era` is `None`. + 805 | pub const V3_CLASS: LoadClass = LoadClass { era: None, hot: None, ..LoadClass::MX8 }; + 806 | + 807 | /// The load class of program class v4 (Counter ASIC 3.0 item 8, `docs/analysis/latency-shadow-2026-10-06.md`, the + 808 | /// candidate of 6 October 2026, gated by `docs/plans/counter-asic-3-node.md`): class v3 plus the latency-shadow block + 809 | /// of 256 ALU instructions run 27 times per iteration ("mx8+sh256x27", 55,296 shadow instructions per hash). The + 810 | /// base program, the 16 loads, the item construction, the cache growth rule and the era draw are class v3's, draw + 811 | /// for draw, so a v4 epoch's day cache and dataset are the v3 day's. Composed with the era exactly as V3 is. + 812 | pub const V4_CLASS: LoadClass = LoadClass { shadow: Some(ShadowClass { instrs: V4_SHADOW_INSTRS, reps: V4_SHADOW_REPS }), ..V3_CLASS }; + 813 | + 814 | /// The shadow block size of class v4 at every rung of the latency ladder (`docs/design/latency-ladder.md`): 256 + 815 | /// instructions. The ladder moves the pass count alone. + 816 | pub const V4_SHADOW_INSTRS: u16 = 256; + 817 | + 818 | /// The shadow passes of class v4 at rung 0 of the latency ladder: 27 (`mx8+sh256x27`, about 102,100 counted ops). + 819 | pub const V4_SHADOW_REPS: u16 = 27; +``` + +### `igneum-pow-src/generator.rs:850-858` + +```text + 850 | /// The width set class v3's era draw chooses from: 4 bytes only (the read-width decision of 5 October 2026; the + 851 | /// draw is consumed, so widening the set at genesis keeps the derivation). + 852 | pub const V3_ALLOWED: [u8; 1] = [1]; + 853 | + 854 | /// The program of an era class (generator version 3): `base` with the era parameters drawn from `era_bytes` + 855 | /// over the width set `allowed`, generator 3 stamped and the era bytes recorded (`docs/plans/era-layout.md`). + 856 | /// The chain's path is this with `base = V3_CLASS` and `allowed = V3_ALLOWED`. + 857 | pub fn generate_era(seed_string: &str, seed_bytes: &[u8], base: LoadClass, era_bytes: &[u8], allowed: &[u8]) -> Program { + 858 | generate_era_generator(seed_string, seed_bytes, base, era_bytes, allowed, era_generator_of(&base)) +``` + +### `igneum-pow-src/generator.rs:124-147` + +```text + 124 | /// An injecting op: bijective in `dst` and bringing another register (or the dataset) in. The acceptance + 125 | /// rule's part (b) requires one such write per register. + 126 | pub fn injects(self) -> bool { + 127 | matches!(self, Op::Add | Op::Sub | Op::Xor | Op::Mad | Op::Shfl | Op::Load | Op::WLoad | Op::Scratch | Op::Hot) + 128 | } + 129 | + 130 | /// A memory operation: the fresh-source rule, the acceptance tests and the load count treat the scratch + 131 | /// read-modify-write and the hot-table load as loads (each is one of the program's 128 memory operations). + 132 | pub fn is_load(self) -> bool { + 133 | matches!(self, Op::Load | Op::WLoad | Op::Scratch | Op::Hot) + 134 | } + 135 | } + 136 | + 137 | /// One instruction. Every field is drawn for every instruction whether the op uses it or not, so the + 138 | /// draw stream is identical for every op. + 139 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] + 140 | pub struct Instr { + 141 | pub op: Op, + 142 | /// Destination register 0..7. + 143 | pub dst: u8, + 144 | /// Source register 0..7, never equal to `dst`. + 145 | pub src: u8, + 146 | /// Second source (mad only). + 147 | pub src2: u8, +``` + +### `igneum-pow-src/generator.rs:1049-1065` + +```text +1049 | /// The program id: FNV-1a 64 over `"igneum-program/" || generator_le32 || seed words as little-endian bytes +1050 | /// || attempt_le32`. Written into every pack so a version 1 program, or another attempt of the same seed, +1051 | /// can never be mistaken for this one. +1052 | pub fn program_id(&self) -> u64 { +1053 | // Latency ladder (docs/design/latency-ladder.md section 7): a class v4 program above rung 0 carries its shadow +1054 | // size in the id (`program_id_class`, the "shadow/" bytes), so two rungs of one seed never share an id and a +1055 | // pack of another rung is refused as a pack of another class is. Rung 0 keeps `program_id(4, seed, attempt)` +1056 | // byte for byte, so every v4 id written before the ladder stands. +1057 | let v4_rung_0 = self.generator == GENERATOR_VERSION_V4 && LoadClass { era: None, ..self.class } == V4_CLASS; +1058 | if self.class.is_v2() || self.generator == GENERATOR_VERSION_V3 || v4_rung_0 { +1059 | // Spec 01 section 1.4.6: a class v3 program's id is `program_id(3, seed, attempt)`, a class v4 program's +1060 | // `program_id(4, seed, attempt)` (Counter ASIC 3.0); the generator version in the preimage separates +1061 | // them from every version 2 program of the same seed +1062 | program_id(self.generator, &self.seed, self.attempt) +1063 | } else { +1064 | program_id_class(self.generator, &self.seed, self.attempt, &self.class) +1065 | } +``` + +### `igneum-pow-src/generator.rs:1266-1310` + +```text +1266 | eligible[rng.below(n as u64) as usize] +1267 | } +1268 | } else { +1269 | let a = rng.below(7); +1270 | if a >= dst { +1271 | a + 1 +1272 | } else { +1273 | a +1274 | } +1275 | }; +1276 | let b = rng.below(8); +1277 | let imm = rng.next() as u32; +1278 | let imm2 = rng.next() as u32; +1279 | let rot = 1 + rng.below(31) as u32; +1280 | let bit = rng.below(32); +1281 | let mask = 1u8 << rng.below(5); +1282 | // Version 2 loads take no width roll, so a mixer class with version 2 loads draws the version 2 program +1283 | let width = if class.takes_width_roll() { class.width_for_roll(rng.below(100)) } else { 1 }; +1284 | let width = if op == Op::Load { width } else { 1 }; +1285 | // Era layout, layer 8: two window draws per instruction (drawn on every slot, used on a load slot). +1286 | let (win, off) = if class.era.is_some() { +1287 | let k = rng.below(3) as u8; +1288 | let o = (rng.next() as u32 & ((1u32 << k) - 1)) as u8; +1289 | if op == Op::Load { +1290 | (k, o) +1291 | } else { +1292 | (0, 0) +1293 | } +1294 | } else { +1295 | (0, 0) +1296 | }; +1297 | if op.is_load() { +1298 | fresh[src as usize] = false; +1299 | } +1300 | fresh[dst as usize] = true; +1301 | instrs.push(Instr { op, dst: dst as u8, src: src as u8, src2: b as u8, imm, imm2, rot, bit: bit as u8, mask, width, win, off }); +1302 | } +1303 | // (3) The latency-shadow block (Counter ASIC 3.0 item 8): drawn after the base program from the same stream, so +1304 | // the 64 instructions above are the class's without the shadow, draw for draw. Every slot is an ALU slot: the +1305 | // op from the non-load table, the source as on an ALU slot, the same per-instruction draws (the width roll and +1306 | // the era windows included when the class takes them, drawn and ignored) so the stream shape is the program's. +1307 | let mut shadow = Vec::new(); +1308 | if let Some(sh) = class.shadow { +1309 | for _ in 0..sh.instrs { +1310 | let mut roll = rng.below(75); +``` + +### `igneum-pow-src/generator.rs:1377-1404` + +```text +1377 | /// The program of a seed: the first accepted candidate over attempts `0, 1, 2, ...`, at most [`MAX_ATTEMPTS`]. +1378 | /// This is what the chain calls (`Epoch::from_seed_bytes`) with the 32-byte epoch seed, and what the packs call +1379 | /// with the UTF-8 of a seed string. +1380 | pub fn try_generate_from_seed_bytes(seed_string: &str, seed_bytes: &[u8]) -> Result { +1381 | try_generate_class(seed_string, seed_bytes, LoadClass::V2) +1382 | } +1383 | +1384 | /// [`try_generate_from_seed_bytes`] for a load class. +1385 | pub fn try_generate_class(seed_string: &str, seed_bytes: &[u8], class: LoadClass) -> Result { +1386 | let mut last = None; +1387 | for attempt in 0..MAX_ATTEMPTS { +1388 | let p = candidate_class(seed_string, seed_bytes, attempt, class); +1389 | match check(&p) { +1390 | Ok(_) => return Ok(p), +1391 | Err(r) => last = Some(r), +1392 | } +1393 | } +1394 | Err(Exhausted { seed_string: seed_string.to_string(), attempts: MAX_ATTEMPTS, last: last.unwrap() }) +1395 | } +1396 | +1397 | /// [`try_generate_from_seed_bytes`], treating exhaustion as the consensus fault it is. +1398 | pub fn generate_from_seed_bytes(seed_string: &str, seed_bytes: &[u8]) -> Program { +1399 | try_generate_from_seed_bytes(seed_string, seed_bytes).unwrap_or_else(|e| panic!("{e}")) +1400 | } +1401 | +1402 | /// [`generate_from_seed_bytes`] for a load class. +1403 | pub fn generate_from_seed_bytes_class(seed_string: &str, seed_bytes: &[u8], class: LoadClass) -> Program { +1404 | try_generate_class(seed_string, seed_bytes, class).unwrap_or_else(|e| panic!("{e}")) +``` + +### `igneum-pow-src/accept.rs:178-205` + +```text + 178 | /// Returns the first lane-constant load site, if any. + 179 | fn run_unit(p: &Program, unit: usize, base: u32, acc: &mut Acc, lane_addrs: &mut [u32]) -> Result<(), Reject> { + 180 | let seed = &p.seed; + 181 | let mask: u32 = (1u32 << ACCEPT_DATASET_LOG2) - 1; + 182 | let (d0, d1) = (seed[0], seed[1]); + 183 | let (h0, h1) = (seed[2], seed[3]); + 184 | let hot_words = p.hot_words(); + 185 | let loads = p.loads_per_hash(); + 186 | let mut r = [[0u32; LANES]; 8]; + 187 | for lane in 0..LANES { + 188 | let nonce = base.wrapping_add(lane as u32); + 189 | for i in 0..8 { + 190 | let mut x = nonce ^ seed[i]; + 191 | x = x.wrapping_add(0x9e3779b9u32.wrapping_mul(i as u32 + 1)); + 192 | x = splitmix32(x); + 193 | r[i][lane] = x ^ seed[(i + 1) & 7]; + 194 | } + 195 | } + 196 | let mut idx = [0u32; LANES]; + 197 | let mut nload = 0usize; + 198 | let mut scratch = if p.has_scratch() { Some(ScratchModel::new(p.class.scratch_slots_per_lane())) } else { None }; + 199 | let slot_mask = p.class.scratch_slot_mask(); + 200 | let era = p.class.era; + 201 | for it in 0..ITERATIONS { + 202 | let sel = r[0]; + 203 | for (k, ins) in p.instrs.iter().enumerate() { + 204 | let d = ins.dst as usize; + 205 | let a = ins.src as usize; +``` + +### `igneum-pow-src/accept.rs:276-317` + +```text + 276 | for lane in 0..LANES { + 277 | r[d][lane] = src[lane].wrapping_mul(src2[lane]).wrapping_add(r[d][lane]); + 278 | } + 279 | } + 280 | Op::Shfl => { + 281 | let src = r[a]; + 282 | let m = ins.mask as usize; + 283 | for lane in 0..LANES { + 284 | r[d][lane] ^= src[lane ^ m]; + 285 | } + 286 | } + 287 | Op::Load => { + 288 | // Read-width experiment: a load of `width` words reads from the aligned address and folds every + 289 | // word (verify::fold_words); width 1 is the lottery hash's xor of one word. + 290 | let width = ins.width as usize; + 291 | let align = !(ins.width as u32 - 1); + 292 | for lane in 0..LANES { + 293 | idx[lane] = load_index(era.as_ref(), ins, r[a][lane], mask, ACCEPT_DATASET_LOG2) & align; + 294 | } + 295 | if idx.iter().all(|&x| x == idx[0]) { + 296 | return Err(Reject::LaneConstantSite { iteration: it as u8, instr: k as u8, unit: unit as u8 }); + 297 | } + 298 | for lane in 0..LANES { + 299 | if width == 1 { + 300 | r[d][lane] ^= dataset_elem(idx[lane], d0, d1); + 301 | } else { + 302 | let mut w = [0u32; 16]; + 303 | for j in 0..width { + 304 | w[j] = dataset_elem(idx[lane] + j as u32, d0, d1); + 305 | } + 306 | r[d][lane] = fold_words(r[d][lane], &w[..width]); + 307 | } + 308 | lane_addrs[lane * loads + nload] = idx[lane]; + 309 | } + 310 | nload += 1; + 311 | } + 312 | Op::Hot => { + 313 | // Hot table: the stand-in is dataset_elem keyed by seed words 2 and 3; the address is tagged with + 314 | // bit 30 so a hot word and a dataset word at one index count as two addresses. + 315 | for lane in 0..LANES { + 316 | idx[lane] = hot_index(r[a][lane], hot_words); + 317 | } +``` + +### `igneum-pow-src/accept.rs:327-404` + +```text + 327 | Op::WLoad => { + 328 | let b = (r[a][0] & mask) & !31; + 329 | for lane in 0..LANES { + 330 | idx[lane] = b + lane as u32; + 331 | r[d][lane] ^= dataset_elem(idx[lane], d0, d1); + 332 | lane_addrs[lane * loads + nload] = idx[lane]; + 333 | } + 334 | nload += 1; + 335 | } + 336 | } + 337 | } + 338 | } + 339 | for i in 0..8 { + 340 | for lane in 0..LANES { + 341 | let v = r[i][lane]; + 342 | acc.and_acc[i] &= v; + 343 | acc.or_acc[i] |= v; + 344 | acc.saturated += (v == 0 || v == u32::MAX) as u32; + 345 | } + 346 | } + 347 | for lane in 0..LANES { + 348 | let lo = r[0][lane] ^ r[1][lane].rotate_left(7) ^ r[2][lane].rotate_left(14) ^ r[3][lane].rotate_left(21); + 349 | let hi = r[4][lane] ^ r[5][lane].rotate_left(9) ^ r[6][lane].rotate_left(18) ^ r[7][lane].rotate_left(27); + 350 | let h = ((hi as u64) << 32) | lo as u64; + 351 | for j in 0..64 { + 352 | acc.bit_ones[j] += ((h >> j) & 1) as u32; + 353 | } + 354 | let sl = &mut lane_addrs[lane * loads..(lane + 1) * loads]; + 355 | sl.sort_unstable(); + 356 | let mut distinct = 0u64; + 357 | for k in 0..loads { + 358 | // scratch slots carry bit 31 (variant 5) and are not dataset addresses + 359 | if sl[k] & 0x8000_0000 == 0 && (k == 0 || sl[k] != sl[k - 1]) { + 360 | distinct += 1; + 361 | } + 362 | } + 363 | acc.distinct_sum += distinct; + 364 | } + 365 | Ok(()) + 366 | } + 367 | + 368 | /// Part (c). + 369 | pub fn check_dynamic(p: &Program) -> Result { + 370 | let loads = p.loads_per_hash(); + 371 | let mut acc = Acc { and_acc: [u32::MAX; 8], or_acc: [0; 8], saturated: 0, bit_ones: [0; 64], distinct_sum: 0 }; + 372 | let mut lane_addrs = vec![0u32; LANES * loads]; + 373 | for (unit, &base) in accept_base_nonces(&p.seed).iter().enumerate() { + 374 | run_unit(p, unit, base, &mut acc, &mut lane_addrs)?; + 375 | } + 376 | for reg in 0..8 { + 377 | let bits = (acc.and_acc[reg] | !acc.or_acc[reg]).count_ones(); + 378 | if bits != 0 { + 379 | return Err(Reject::ConstantBit { reg: reg as u8, bits: bits as u8 }); + 380 | } + 381 | } + 382 | if acc.saturated >= MAX_SATURATED { + 383 | return Err(Reject::Saturated { count: acc.saturated }); + 384 | } + 385 | let half = (ACCEPT_HASHES / 2) as u32; + 386 | let mut bias_max = 0u32; + 387 | for (bit, &ones) in acc.bit_ones.iter().enumerate() { + 388 | let d = ones.abs_diff(half); + 389 | if d > BIAS_TOLERANCE { + 390 | return Err(Reject::OutputBias { bit: bit as u8, ones }); + 391 | } + 392 | bias_max = bias_max.max(d); + 393 | } + 394 | if acc.distinct_sum <= min_distinct_sum(loads - p.scratch_ops_per_hash()) { + 395 | return Err(Reject::DistinctAddresses { sum: acc.distinct_sum }); + 396 | } + 397 | Ok(AcceptReport { distinct_sum: acc.distinct_sum, saturated: acc.saturated, bias_max }) + 398 | } + 399 | + 400 | /// The whole rule: (a), (b), then (c). + 401 | pub fn check(p: &Program) -> Result { + 402 | check_static(p)?; + 403 | check_dynamic(p) + 404 | } +``` + +### `igneum-pow-src/verify.rs:335-398` + +```text + 335 | pub fn interpret_warp_scratch( + 336 | program: &Program, + 337 | seed: &[u32; 8], + 338 | base_nonce: u32, + 339 | ds: &DatasetSource, + 340 | trace: bool, + 341 | ) -> (WarpResult, Vec) { + 342 | let mask = ds.mask; + 343 | let log2 = ds.log2_words; + 344 | let era = program.class.era; + 345 | let layout = program.class.layout(); + 346 | let mut r = [[0u32; LANES]; 8]; + 347 | for lane in 0..LANES { + 348 | let nonce = base_nonce.wrapping_add(lane as u32); + 349 | for i in 0..8 { + 350 | let mut x = nonce ^ seed[i]; + 351 | x = x.wrapping_add(0x9e3779b9u32.wrapping_mul(i as u32 + 1)); + 352 | x = splitmix32(x); + 353 | r[i][lane] = x ^ seed[(i + 1) & 7]; + 354 | } + 355 | } + 356 | let mut items_derived = 0usize; + 357 | let mut idx = [0u32; LANES]; + 358 | let mut val = [0u32; LANES]; + 359 | let mut scratch = if program.has_scratch() { Some(ScratchModel::new(program.class.scratch_slots_per_lane())) } else { None }; + 360 | if trace { + 361 | if let Some(m) = scratch.as_mut() { + 362 | m.trace = Some(Vec::new()); + 363 | } + 364 | } + 365 | let slot_mask = program.class.scratch_slot_mask(); + 366 | if program.has_hot() { + 367 | let h = ds.hot.as_ref().expect("a hot-table program needs the epoch's hot table on the dataset source"); + 368 | assert_eq!(h.n_words(), program.hot_words(), "the hot table's size is the class's"); + 369 | } + 370 | for _ in 0..ITERATIONS { + 371 | let sel = r[0]; + 372 | for ins in &program.instrs { + 373 | step(ins, &mut r, &sel, mask, log2, era.as_ref(), layout, ds, &mut idx, &mut val, &mut items_derived); + 374 | if ins.op == Op::Scratch { + 375 | let m = scratch.as_mut().expect("a scratch op needs a scratch class"); + 376 | let (d, a) = (ins.dst as usize, ins.src as usize); + 377 | for lane in 0..LANES { + 378 | let slot = r[a][lane] & slot_mask; + 379 | r[d][lane] = m.rmw(&program.seed, base_nonce, lane, slot, r[d][lane]); + 380 | } + 381 | } + 382 | } + 383 | // Latency-shadow block (Counter ASIC 3.0 item 8): the block runs `reps` times after instruction 63 with the + 384 | // iteration's `sel`; it is empty on every class without a shadow, so version 2 and class v3 run nothing here. + 385 | for _ in 0..program.shadow_reps() { + 386 | for ins in &program.shadow { + 387 | step(ins, &mut r, &sel, mask, log2, era.as_ref(), layout, ds, &mut idx, &mut val, &mut items_derived); + 388 | } + 389 | } + 390 | } + 391 | let mut hashes = [0u64; LANES]; + 392 | for lane in 0..LANES { + 393 | let lo = r[0][lane] ^ r[1][lane].rotate_left(7) ^ r[2][lane].rotate_left(14) ^ r[3][lane].rotate_left(21); + 394 | let hi = r[4][lane] ^ r[5][lane].rotate_left(9) ^ r[6][lane].rotate_left(18) ^ r[7][lane].rotate_left(27); + 395 | hashes[lane] = ((hi as u64) << 32) | lo as u64; + 396 | } + 397 | let events = scratch.and_then(|m| m.trace).unwrap_or_default(); + 398 | (WarpResult { hashes, items_derived }, events) +``` + +### `igneum-pow-src/seed.rs:34-49` + +```text + 34 | + 35 | /// The 32-byte seed (8 x u32) from arbitrary bytes: FNV-1a 64 with four salts, each finalised with the + 36 | /// murmur-style mix `h ^= h >> 33; h *= 0xff51afd7ed558ccd; h ^= h >> 33`; low word then high word. + 37 | pub fn seed_words_from_bytes(bytes: &[u8]) -> [u32; 8] { + 38 | let mut words = [0u32; 8]; + 39 | for salt in 0..4u64 { + 40 | let basis = 0xcbf29ce484222325u64 ^ salt.wrapping_mul(0x9E3779B97F4A7C15); + 41 | let mut h = fnv1a64_with_basis(basis, bytes); + 42 | h ^= h >> 33; + 43 | h = h.wrapping_mul(0xff51afd7ed558ccd); + 44 | h ^= h >> 33; + 45 | words[2 * salt as usize] = h as u32; + 46 | words[2 * salt as usize + 1] = (h >> 32) as u32; + 47 | } + 48 | words + 49 | } +``` + +### `igneum-pow-src/bind.rs:47-83` + +```text + 47 | /// `"igneum-block/" || H || nonce_hi_le32`, the bytes the init words are derived from. + 48 | pub fn block_init_bytes(header_prehash: &[u8; 32], nonce: u64) -> [u8; 49] { + 49 | let mut b = [0u8; 49]; + 50 | b[..13].copy_from_slice(BLOCK_TAG); + 51 | b[13..45].copy_from_slice(header_prehash); + 52 | b[45..49].copy_from_slice(&nonce_hi(nonce).to_le_bytes()); + 53 | b + 54 | } + 55 | + 56 | /// The init words `I` for a header and a 64-bit nonce (only the high 32 bits of the nonce matter). + 57 | pub fn block_init_words(header_prehash: &[u8; 32], nonce: u64) -> [u32; 8] { + 58 | seed_words_from_bytes(&block_init_bytes(header_prehash, nonce)) + 59 | } + 60 | + 61 | /// Interim day seed bytes: `"igneum-day/" || day_le64`. + 62 | pub fn day_bytes(day_index: u64) -> [u8; 19] { + 63 | let mut b = [0u8; 19]; + 64 | b[..11].copy_from_slice(DAY_TAG); + 65 | b[11..19].copy_from_slice(&day_index.to_le_bytes()); + 66 | b + 67 | } + 68 | + 69 | /// Day index of a header timestamp in milliseconds. + 70 | #[inline] + 71 | pub fn day_index(timestamp_ms: u64) -> u64 { + 72 | timestamp_ms / DAY_MS + 73 | } + 74 | + 75 | /// The 256-bit pow value as little-endian bytes: the lane hash in bytes 24..32, zero elsewhere. + 76 | pub fn pow256_from_lane(lane: u64) -> [u8; 32] { + 77 | let mut b = [0u8; 32]; + 78 | b[24..32].copy_from_slice(&lane.to_le_bytes()); + 79 | b + 80 | } + 81 | + 82 | /// The 64-bit target from a little-endian 256-bit target: its top 64 bits. + 83 | pub fn target64_from_le256(target: &[u8; 32]) -> u64 { +``` + +### `igneum-pow-src/bind.rs:99-119` + +```text + 99 | + 100 | impl Epoch { + 101 | /// The 32 bound hashes of the aligned warp that contains `nonce`: lane `l` is the hash of + 102 | /// `(nonce_hi << 32) | ((lane_nonce & !31) + l)`. + 103 | pub fn hash_warp_bound(&self, header_prehash: &[u8; 32], nonce: u64) -> [u64; LANES] { + 104 | self.interpret_warp_bound(header_prehash, nonce).hashes + 105 | } + 106 | + 107 | pub fn interpret_warp_bound(&self, header_prehash: &[u8; 32], nonce: u64) -> WarpResult { + 108 | let init = block_init_words(header_prehash, nonce); + 109 | interpret_warp_init(&self.program, &init, lane_nonce(nonce) & !31, &self.dataset) + 110 | } + 111 | + 112 | /// The 32 bound hashes for already-derived init words (what a GPU worker computes per dispatch). + 113 | pub fn hash_warp_init(&self, init: &[u32; 8], base_lane_nonce: u32) -> [u64; LANES] { + 114 | interpret_warp_init(&self.program, init, base_lane_nonce, &self.dataset).hashes + 115 | } + 116 | + 117 | /// The bound 64-bit lane hash of one header nonce. + 118 | pub fn hash_bound(&self, header_prehash: &[u8; 32], nonce: u64) -> u64 { + 119 | self.hash_warp_bound(header_prehash, nonce)[(lane_nonce(nonce) & 31) as usize] +``` + +### `igneum-pow-src/emit.rs:1219-1243` + +```text +1219 | s.push_str(&format!("__global__ void igneum_hash_bound(const uint32_t* ds, uint64_t* out, uint32_t baseNonce, uint32_t mask, IgneumInitWords iw{hot_args}{scratch_args}) {{\n")); +1220 | if p.has_scratch() { +1221 | s.push_str(&persistent_prologue(CoreDialect::Cuda, p.class.scratch_words_per_lane())); +1222 | } else { +1223 | s.push_str(" uint32_t gid = blockIdx.x * blockDim.x + threadIdx.x;\n"); +1224 | } +1225 | s.push_str(" uint32_t nonce = baseNonce + gid;\n"); +1226 | s.push_str(" uint32_t r0, r1, r2, r3, r4, r5, r6, r7;\n"); +1227 | if p.has_wide() { +1228 | s.push_str(" uint32_t lane = threadIdx.x & 31u;\n uint32_t wmask = mask & ~31u;\n"); +1229 | } +1230 | for i in 0..8 { +1231 | s.push_str(&format!( +1232 | " {{ uint32_t x = nonce ^ iw.w[{i}]; x += 0x9e3779b9u * {}u; x = splitmix32(x); r{i} = x ^ iw.w[{}]; }}\n", +1233 | i + 1, +1234 | (i + 1) & 7 +1235 | )); +1236 | } +1237 | s.push_str(&format!("\n for (uint32_t it = 0u; it < {ITERATIONS}u; ++it) {{\n uint32_t sel = r0;\n")); +1238 | s.push_str(&cuda_instr_lines(p, dataset_log2)); +1239 | s.push_str(&shadow_block(p, CoreDialect::Cuda)); +1240 | s.push_str(" }\n"); +1241 | s.push_str(" uint32_t lo = r0 ^ rotl_imm(r1, 7u) ^ rotl_imm(r2, 14u) ^ rotl_imm(r3, 21u);\n"); +1242 | s.push_str(" uint32_t hi = r4 ^ rotl_imm(r5, 9u) ^ rotl_imm(r6, 18u) ^ rotl_imm(r7, 27u);\n"); +1243 | s.push_str(" out[gid] = ((uint64_t)hi << 32) | (uint64_t)lo;\n"); +``` + +### `igneum-pow-src/emit.rs:1260-1270` + +```text +1260 | } else { +1261 | s.push_str( +1262 | "cudaError_t igneum_launch_hash_bound(const uint32_t* ds, uint64_t* out, uint32_t baseNonce, uint32_t mask,\n", +1263 | ); +1264 | s.push_str(&format!(" IgneumInitWords iw,{hot_decl} uint32_t nonces, uint32_t blockWarps) {{\n")); +1265 | s.push_str(" if (blockWarps == 0u || blockWarps > 32u) return cudaErrorInvalidValue;\n"); +1266 | s.push_str(" uint32_t block = 32u * blockWarps;\n"); +1267 | s.push_str(" if (nonces == 0u || (nonces % block) != 0u) return cudaErrorInvalidValue;\n"); +1268 | s.push_str(&format!(" igneum_hash_bound<<>>(ds, out, baseNonce, mask, iw{hot_pass});\n")); +1269 | s.push_str(" return cudaGetLastError();\n"); +1270 | s.push_str("}\n"); +``` + +### `igneum-pow-src/packcheck.rs:166-185` + +```text + 166 | + 167 | /// [`verify_pack_texts`] that also demands a program class and, for class v3 and v4, the era seed the chain is on + 168 | /// (Counter ASIC 2.0, 5 October 2026; class v4 Counter ASIC 3.0, 6 October 2026). `want_class` `None` accepts any + 169 | /// class; `want_era` `None` skips the era. A pack whose `IGNEUM_GENERATOR` is not 2, 3 or 4 is refused whatever is wanted. + 170 | pub fn verify_pack_texts_chain( + 171 | program_h: &str, + 172 | seeds_txt: Option<&str>, + 173 | want_epoch: &[u8], + 174 | want_day: &[u8], + 175 | want_class: Option, + 176 | want_era: Option<&[u8]>, + 177 | ) -> Result { + 178 | let generator = define_u32(program_h, "IGNEUM_GENERATOR").unwrap_or(1); + 179 | let Some(class) = ProgramClass::from_generator(generator) else { + 180 | return Err(PackFault::WrongClass(format!("IGNEUM_GENERATOR {generator} is not a generator version this software runs (2, 3 or 4)"))); + 181 | }; + 182 | // IGNEUM_PROGRAM_CLASS, when present, must name the class the generator version names + 183 | if let Some(named) = define_str(program_h, "IGNEUM_PROGRAM_CLASS") { + 184 | if ProgramClass::parse(&named) != Some(class) { + 185 | return Err(PackFault::Disagree(format!("IGNEUM_PROGRAM_CLASS {named:?} does not match IGNEUM_GENERATOR {generator}"))); +``` + +### `igneum-pow-src/packcheck.rs:208-225` + +```text + 208 | if let (Some(want), true) = (want_era, class.has_era()) { + 209 | let want_hex = hex(want); + 210 | match &era_hex { + 211 | Some(h) if *h == want_hex => {} + 212 | Some(h) => return Err(PackFault::WrongClass(format!("the pack's era seed {} is not the era seed {} the job names", short(h), short(&want_hex)))), + 213 | None => return Err(PackFault::WrongClass(format!("a class {} pack without IGNEUM_ERA_SEED_HEX; the job names an era seed", class.name()))), + 214 | } + 215 | } + 216 | let seedw = define_words(program_h, "IGNEUM_SEEDW_INIT").ok_or_else(|| PackFault::Unreadable("program.h has no IGNEUM_SEEDW_INIT with 8 words".into()))?; + 217 | let keyw = define_words(program_h, "IGNEUM_KEY_INIT").ok_or_else(|| PackFault::Unreadable("program.h has no IGNEUM_KEY_INIT with 8 words".into()))?; + 218 | let attempt = define_u32(program_h, "IGNEUM_PROGRAM_ATTEMPT").unwrap_or(0); + 219 | let mut epoch_hex = define_str(program_h, "IGNEUM_SEED_BYTES_HEX").unwrap_or_default(); + 220 | let mut day_hex = define_str(program_h, "IGNEUM_DAY_BYTES_HEX").unwrap_or_default(); + 221 | if let Some(s) = seeds_txt { + 222 | let e = seeds_line(s, "epoch_seed_hex").ok_or_else(|| PackFault::Unreadable("seeds.txt has no epoch_seed_hex line".into()))?; + 223 | let d = seeds_line(s, "day_seed_hex").ok_or_else(|| PackFault::Unreadable("seeds.txt has no day_seed_hex line".into()))?; + 224 | if !epoch_hex.is_empty() && !epoch_hex.eq_ignore_ascii_case(&e) { + 225 | return Err(PackFault::Disagree(format!("seeds.txt names epoch {} but program.h was generated for epoch {} (a pack half rewritten?)", short(&e), short(&epoch_hex)))); +``` + +### `igneum-pow-src/packcheck.rs:263-272` + +```text + 263 | pub fn verify_pack_dir(dir: &Path, want_epoch: &[u8], want_day: &[u8]) -> Result { + 264 | verify_pack_dir_chain(dir, want_epoch, want_day, None, None) + 265 | } + 266 | + 267 | /// [`verify_pack_texts_chain`] over a pack directory. + 268 | pub fn verify_pack_dir_chain(dir: &Path, want_epoch: &[u8], want_day: &[u8], want_class: Option, want_era: Option<&[u8]>) -> Result { + 269 | let program_h = std::fs::read_to_string(dir.join("program.h")).map_err(|e| PackFault::Unreadable(format!("cannot read {}/program.h: {e}", dir.display())))?; + 270 | let seeds = std::fs::read_to_string(dir.join("seeds.txt")).ok(); + 271 | verify_pack_texts_chain(&program_h, seeds.as_deref(), want_epoch, want_day, want_class, want_era) + 272 | } +``` + diff --git a/docs/plans/igneum-2.0-master/evidence/MANIFEST.json b/docs/plans/igneum-2.0-master/evidence/MANIFEST.json new file mode 100644 index 000000000..ce3d99cf7 --- /dev/null +++ b/docs/plans/igneum-2.0-master/evidence/MANIFEST.json @@ -0,0 +1,181 @@ +{ + "edition": "Igneum 2.0 master / 2026-10-08", + "assets": [ + { + "bundle_path": "01_strategy_source/IGNEUM 2.0.rtf", + "filename": "IGNEUM 2.0.rtf", + "bytes": 28017, + "sha256": "00ca1ec477aef0e967eadd6652a35355e17a1346d42396afec202fc99abb4475", + "description": "Original supplied strategy text" + }, + { + "bundle_path": "02_tests/IGNEUM_2.0_Test_Registry.json", + "filename": "IGNEUM_2.0_Test_Registry.json", + "bytes": 204778, + "sha256": "573e0df9b4449d877eaf420279a53eef4497d3d9c67e12e62da7bd5e253a0417", + "description": "128 original cases and 17 proposed profiles" + }, + { + "bundle_path": "03_legacy_review/IGNEUM_Algorithm_Review_Evidence.md", + "filename": "IGNEUM_Algorithm_Review_Evidence.md", + "bytes": 45434, + "sha256": "fe6f4c9242574cadbd88e769d4e2c17bbc81c027e8a5fca9599dbf452078d77d", + "description": "Exact R0 source" + }, + { + "bundle_path": "03_legacy_review/IGNEUM_Algorithm_Review_Results.json", + "filename": "IGNEUM_Algorithm_Review_Results.json", + "bytes": 82485, + "sha256": "6a529f0ec8488669cfb3a8a5f702da73a092a1947a9280e7ec31d582b041d206", + "description": "Exact original observations and manifest" + }, + { + "bundle_path": "03_legacy_review/IGNEUM_Algorithm_Review_Harness.zip", + "filename": "IGNEUM_Algorithm_Review_Harness.zip", + "bytes": 42759, + "sha256": "566d12f1bb67c99cda2c47a7c6eb4616479da80d320925979ff0052c5784cab5", + "description": "Original runnable diagnostic harness" + }, + { + "bundle_path": "04_full_system/IGNEUM_V6_Full_System_Review.md", + "filename": "IGNEUM_V6_Full_System_Review.md", + "bytes": 210161, + "sha256": "1e62d89f743c3c3d4525f6321c53c05025e628080face878d82ff2f93ceb0213", + "description": "Exact R1 source" + }, + { + "bundle_path": "04_full_system/IGNEUM_V6_Full_System_Review_Results.json", + "filename": "IGNEUM_V6_Full_System_Review_Results.json", + "bytes": 15353, + "sha256": "44c4931c657aac530f95f1a6d183943f817fd6f022afab2495555b4a1ece8c03", + "description": "Exact R1 recorded outputs" + }, + { + "bundle_path": "04_full_system/IGNEUM_V6_Full_System_Review_Harness.zip", + "filename": "IGNEUM_V6_Full_System_Review_Harness.zip", + "bytes": 95385, + "sha256": "13fb83611921df0b1d3d7ed9f25bea4d2af404d6aa3f55fbf578e4bc5fad9261", + "description": "R1 original harness and source guards" + }, + { + "bundle_path": "05_updated_stack/IGNEUM_Updated_Stack_Review.md", + "filename": "IGNEUM_Updated_Stack_Review.md", + "bytes": 163364, + "sha256": "3734c1d09075421976e5872baee7c00abe00d1e0a062ad56dded4a05df002a87", + "description": "Exact R2 source" + }, + { + "bundle_path": "05_updated_stack/IGNEUM_Updated_Stack_Findings.json", + "filename": "IGNEUM_Updated_Stack_Findings.json", + "bytes": 43073, + "sha256": "9809e8284cdf841e051c6db4494af7e24159c96aa25e6c71635b411f9fac3b3e", + "description": "All 14 R2 findings, 44 closure requirements and outputs" + }, + { + "bundle_path": "05_updated_stack/IGNEUM_Updated_Stack_Reproductions.zip", + "filename": "IGNEUM_Updated_Stack_Reproductions.zip", + "bytes": 16657, + "sha256": "21f8bbf15a12aa4836f16464fa0af7fab1e789d4bbacc331234c6f634dfdca9a", + "description": "R2 original reproduction pack" + }, + { + "bundle_path": "06_master/IGNEUM_2.0_Master_Traceability.json", + "filename": "IGNEUM_2.0_Master_Traceability.json", + "bytes": 271435, + "sha256": "7ebf8d60cf0e4e3889ab5472b5b4f807d791739ef62f91ffaa74236792a4810e", + "description": "Original registry plus namespaced add-ons and mapping" + }, + { + "bundle_path": "07_reviewed_sources/igneum-mining-algorithm-2026-10-08.zip", + "filename": "igneum-mining-algorithm-2026-10-08.zip", + "bytes": 148136, + "sha256": "94edb290005ecb8379cc599da90c877c7e25562f727cc4291069b4fbc149c7c1", + "description": "R0 reviewed source archive" + }, + { + "bundle_path": "07_reviewed_sources/igneum-v6-freeze-tree-2026-10-08(1).zip", + "filename": "igneum-v6-freeze-tree-2026-10-08(1).zip", + "bytes": 696492, + "sha256": "f448981b2ceeab2e59e8bbd137a1a13ea1c730ecd9db72b9a89bd2bbf5d85acb", + "description": "Reviewed v6 freeze archive; one byte-identical copy" + }, + { + "bundle_path": "07_reviewed_sources/igneum-proving-2026-10-08(1).zip", + "filename": "igneum-proving-2026-10-08(1).zip", + "bytes": 1612294, + "sha256": "9ccf4112e274f586392e8e4a4f98ece2e82b4990fe5f1ee89ae0ee0a151ce01e", + "description": "Reviewed proving archive; one byte-identical copy" + }, + { + "bundle_path": "07_reviewed_sources/igneum-ember-2026-10-08(1).zip", + "filename": "igneum-ember-2026-10-08(1).zip", + "bytes": 78946, + "sha256": "c219211b49fccda65b151df230b10ded5971ac2a8c7d1e5847c0a68bffe4cf4a", + "description": "Reviewed Ember archive; one byte-identical copy" + }, + { + "bundle_path": "07_reviewed_sources/igneum-node-dag-2026-10-08.zip", + "filename": "igneum-node-dag-2026-10-08.zip", + "bytes": 1519903, + "sha256": "ead2cf94092b7e27aab2e44d653b2d969cb2a52878ef12abf6e5d7a9e7421cff", + "description": "Reviewed node and DAG source" + }, + { + "bundle_path": "07_reviewed_sources/igneum-mining-workers-2026-10-08.zip", + "filename": "igneum-mining-workers-2026-10-08.zip", + "bytes": 6090014, + "sha256": "808abcecf157a3716d1c72fa6e76c540bf5808af1c0e4dd0fd888576d546cade", + "description": "Reviewed workers, engine and pool source" + } + ], + "source_pdf_pages": { + "strategy": 37, + "test_standard": 73 + }, + "sections": { + "A": { + "start": 19, + "pages": 37 + }, + "B": { + "start": 56, + "pages": 73 + }, + "C": { + "start": 129, + "pages": 11 + }, + "R2": { + "start": 140, + "pages": 59 + }, + "R1": { + "start": 199, + "pages": 72 + }, + "R0": { + "start": 271, + "pages": 18 + }, + "E": { + "start": 289, + "pages": 4 + } + }, + "total_pages": 292, + "editorial_note": "Source PDF pages preserved; source reports reflowed without substantive omissions; no new technical audit performed.", + "companion_original_documents": [ + { + "bundle_path": "00_original_documents/IGNEUM_2.0_Plan.pdf", + "bytes": 257288, + "sha256": "418b3b9f68f96a413872fecb16f8508a40063891c70054c65e92e6e5f5fb70b6" + }, + { + "bundle_path": "00_original_documents/IGNEUM_2.0_Test_and_Acceptance_Standard.pdf", + "bytes": 391678, + "sha256": "3b0767a1f2ed3312ad4b6ff277285754ee1f4dc64fa0a3a37dc07c42eaf23a8b" + } + ], + "master_pdf_sha256": "c878ee4f80adf1da58fcc78fb91a8008de2e9fc44060bec143d020a780c5093e", + "master_light_pdf_sha256": "f54f12117fd10ebcd1cad83b41342cf2a21ba7e0cf0abfa100d48b101b02b18b" +} \ No newline at end of file diff --git a/docs/plans/igneum-2.0-master/evidence/README.txt b/docs/plans/igneum-2.0-master/evidence/README.txt new file mode 100644 index 000000000..41e37410e --- /dev/null +++ b/docs/plans/igneum-2.0-master/evidence/README.txt @@ -0,0 +1,48 @@ +IGNEUM 2.0 - Complete Master Edition: evidence companion +08 October 2026 + +The two 292-page master PDFs contain the same substantive material in +obsidian and light editions. This bundle provides the raw evidence for +viewers that do not expose PDF attachments. + +CONTENTS +- Original supplied strategy RTF. +- Original 128-case test registry and 17 proposed acceptance profiles. +- All three complete review reports, original results/findings and + reproduction packages. +- Master traceability JSON preserving the original registry and adding + 18 INT integration gates and 44 namespaced R2 closure requirements. +- Six distinct reviewed source archives (legacy algorithm plus five updated + source bundles). Byte-identical repeated uploads are represented once. +- Original strategy and test-standard PDFs for provenance. +- MANIFEST.json with SHA-256 hashes and page mapping. + +READING ORDER +Master introduction: pages 1-18. +Original strategy: pages 19-55. +Original test standard: pages 56-128. +Additional closure requirements: pages 129-139. +R2 updated stack review: pages 140-198. +R1 full-system review: pages 199-270. +R0 historical algorithm review: pages 271-288. +Evidence inventory: pages 289-292. + +STATUS AND LIMITS +This is a consolidation, not a new code audit or execution report. No +native node, SP1, GPU, production network or physical ASIC test was run for +this edition. Original probe results are preserved with their limitations. +A defect reproduced by a probe is not a passed acceptance gate. + +Overlapping findings are not independent defects. The 128 cases, 18 INT +gates and 44 closure requirements overlap; do not count their sum as 190 +independent tests. Numerical acceptance profiles remain proposed unless +separately approved. Missing or unrun evidence is not PASS. + +The master explicitly preserves differing interpretations, particularly +around finality healing. It does not silently decide which account is +correct. Closure requires version-pinned source and native evidence. + +Reproduction archives are source artifacts, not signed production releases. +Inspect their README, dependencies and commands before running them in an +isolated environment. Never run fault or payment tests against live funds. +No original font files are distributed in this bundle. diff --git a/docs/plans/igneum-2.0-master/igneum-2.0-complete-master.pdf b/docs/plans/igneum-2.0-master/igneum-2.0-complete-master.pdf new file mode 100644 index 000000000..5566c19c4 Binary files /dev/null and b/docs/plans/igneum-2.0-master/igneum-2.0-complete-master.pdf differ diff --git a/docs/plans/igneum-2.0-master/igneum-2.0-complete-master.txt b/docs/plans/igneum-2.0-master/igneum-2.0-complete-master.txt new file mode 100644 index 000000000..1df23ff8e --- /dev/null +++ b/docs/plans/igneum-2.0-master/igneum-2.0-complete-master.txt @@ -0,0 +1,19001 @@ +THE COMPLETE STRATEGY + VERIFICATION DOSSIER + + + + +2.0 +A durable home +for GPU owners. +The plan. The tests. Every review. +One evidence-led implementation programme. + + +MASTER EDITION / 08 OCTOBER 2026 + + + +COMPETITIVE VERIFIABLE INDEPENDENT +HARDWARE COMPUTATION OPERATORS + + + + +Build the contender. Earn the claim. + +Original strategy and test standard preserved in full. Updated-stack, full-system and historical algorithm reviews included with +their limitations, source excerpts and reproducibility assets. + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 1 + +MASTER 001 / 292 + MASTER / INTEGRATION + + + + +MASTER / DOCUMENT MAP + + + + +One complete reference. +This master edition contains 292 pages. The first 18 pages integrate the decisions; the source documents +that follow retain their detail and original claims. + + +A Original 2.0 strategy 19 + + Complete 37-page plan, including original source appendices. + + + +B Test & acceptance standard 56 + + Complete 73-page standard: 128 cases across 16 suites. + + + +C Additional closure register 129 + + 18 integration gates and 44 namespaced closure requirements. + + + +R2 Updated-stack review 140 + + All 14 findings, results, manifests and exact source excerpts. + + + +R1 V6 full-system review 199 + + All I/V6 findings, integration gates, evidence and excerpts. + + + +R0 Historical algorithm review 271 + + Original nine findings and evidence; version limits retained. + + + +E Evidence inventory & attachments 289 + + Exact source files, registries, results, harnesses and source archives. + + + +Use the PDF bookmarks for source headings, findings and the original test cases. Source PDFs retain their original printed page +numbers; the bottom master footer and this map give the continuous master page. Machine assets are also in the companion +evidence ZIP. + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 2 + +MASTER 002 / 292 + MASTER / INTEGRATION + + + + +MASTER / 01 + + + + +The statement to earn. + GOVERNING OBJECTIVE + + + Someone can build one, but ordinary GPU owners remain competitive, the supplier + cannot obtain a lasting overwhelming advantage, and the network does not depend on + emergency intervention to survive. + + + +This remains the design objective of Igneum 2.0. The credible claim is competitive coexistence, not proof +that nobody can build dedicated hardware. + +Successful execution means the technical, economic and operating outcomes survive their approved +tests. A completed implementation task, a favourable model or an isolated benchmark is not sufficient. + + + OUTCOME WHAT MUST SUBSTANTIATE IT + + + + Complete-system costs, accepted work and new-entrant viability + Ordinary GPUs remain competitive + across the declared hardware and economic conditions. + + + No lasting overwhelming Independent scrutiny of programmable, multi-epoch SRAM, DRAM, + specialisation advantage recomputation and hybrid opponents, including sunk development. + + + No-new-rules evaluation plus actual no-founder operation under the + No emergency anti-chip dependence + specified fault and recovery model. + + + +The word cannot is a demanding internal objective, not an unconditional promise about every future +device or market. Published claims must name the evaluated release, evidence and boundary conditions. + +Basis: original plan pp. 3, 8, 11-13 and 27; R1 V6-11; R2 F09. + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 3 + +MASTER 003 / 292 + MASTER / INTEGRATION + + + + +MASTER / 02 + + + + +What leadership would mean. +Yes: a complete, independently substantiated pass would support a serious case that Igneum is in +contention for leadership among GPU-first networks. It would not award a numerical rank. + +The strongest proposition is the combination of competitive commodity mining, Ethereum-compatible +applications, verifiable proofs, a reliable native miner and retained operator control. The plan treats these +as connected but separately evidenced obligations. + + + MILESTONE EVIDENCE, NOT A SLOGAN + + + + Reproducible builds; exact consensus agreement; bounded specialist + Engineering credibility + advantage; sound proof enforcement; reviewed finality. + + + Safe tuning; memory-aware work scheduling; reliable payment; accessible + Operator credibility + hardware; retained keys and control. + + + Repeat unaffiliated buyers; useful delivered proofs; measured operator and + Commercial credibility + service margins; no disguised reimbursements. + + + Fair contemporary peer comparisons, sustained reliability, customer and + Leadership credibility + miner retention, independent operation. + + + + + CURRENT BOUNDARY + + + The source reviews do not report these gates complete. They retain release-critical + findings, unfinished full-v6 testing and a failed modelled specialist case. Fixing software + bugs does not, by itself, solve the hardware economics. + + + +Basis: original plan pp. 4 and 27, original test suite LEAD, R2 conclusion. This is a conditional judgement, not a new market ranking. + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 4 + +MASTER 004 / 292 + MASTER / INTEGRATION + + + + +MASTER / 03 + + + + +What is preserved. + SOURCE SCOPE IN THIS VOLUME + + + + All 37 pages: objectives, architecture, economics, operations, delivery and + A / Original plan + source appendices. + + + All 73 pages: 128 test cases, 16 suites, 17 proposed profiles and original + B / Acceptance standard + governance. + + + A01-A09; the earlier V2/V3/V4 archive, exact observations, qualifications + R0 / Algorithm review + and excerpts. + + + R1 / Full-system review I01-I10; V6-01-V6-12; INT-01-INT-18; all evidence and source excerpts. + + + F01-F14; 44 required regressions; probe outputs, integrity checks, + R2 / Updated-stack review + provenance and excerpts. + + + Original JSON files and Markdown, all three reproduction archives, the + E / Exact machine assets + reviewed source ZIPs and master traceability. + + + +There are 45 named finding records across the three reports, but many overlap. They are not 45 +independently discovered defects. Likewise, 128 base cases plus 18 INT gates plus 44 R2 requirements +is not a count of 190 independent tests. + +Identifiers are namespaced by source. In R1, some historical excerpt captions still use local F labels; they +are not the same identifiers as R2:F01-F14. + +Editorial treatment: layout, wrapping and source navigation are normalised. Original statements and evidence status are not +silently rewritten. Source PDF bodies are retained. Raw files are embedded and included in the companion ZIP. + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 5 + +MASTER 005 / 292 + MASTER / INTEGRATION + + + + +MASTER / 04 + + + + +Read the evidence correctly. + EVIDENCE WHAT THE REVIEWS ACTUALLY SUPPORT + + + + C/Python transcription matched the listed original vectors; short-program census, + R0 diagnostic model address concentration, identity and launch observations. Not native Rust or GPU + validation. + + + 45 C assertions; 10 JavaScript tests; four artifact hashes; 32,768 address- + R1 checks + equivalence checks; source-guarded models. No native Rust/SP1/GPU network run. + + + 13 isolated probes; 33,024 expression comparisons with 4,096 updates; 10 + R2 checks JavaScript tests; four artifact hashes. Not an acceptance pass or measured chip + result. + + + Consumer proving times, coexistence allocation failures, disrupted pipeline results + Team measurements + and hardware models are carried forward as team-reported. + + + Document assembly, source preservation, cross-references and PDF validation only. + This edition + No new technical test execution, deployment check or hardware audit. + + + + + A PASSING PROBE CAN EXPOSE A FAILING SYSTEM + + + A test script that reproduces a warm-cache error can exit successfully because it + detected the expected error. Do not translate that success into PASS for the requirement + that all validators agree. + + + +Different counts in R1 and R2 describe separate recorded probe runs. They are not accumulated into a +larger security guarantee. Checksums prove byte identity with a manifest, not source equivalence, +soundness or activation. + +Basis: R0 scope; R1 evidence table; R2 snapshot, results and artifact checks. + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 6 + +MASTER 006 / 292 + MASTER / INTEGRATION + + + + +MASTER / 05 + + + + +Close correctness first. + RELEASE OBLIGATION REQUIRED IMPLEMENTATION AND EVIDENCE + + + + Cache verified kind, identity and public-values commitment; check current + Proof-cache context statement and activation on every lookup. Native nodes with different relay/cache + histories must agree. [R1 I01; R2 F01] + + + A release build must not silently accept because an oracle or mandatory key is + Fail-closed proof + absent. Keep unsafe harness bypasses out of production. Missing real-proof fixtures + activation + block the gate. [R1 I09; R2 F02] + + + Pin generator, acceptance, node, pool, hosts, app, guest ELF/VKs, fee rules, dataset + One integrated release geometry and activation. Resolve the supplied EpochSeeds/shadow_reps seam + natively. [R1 I04; R2 F03] + + + Review the approved anchored and recovery rules, prove authority continuity and + Finality semantics exercise native long-partition healing. Do not label a weaker recovery quorum as + ordinary irreversible finality. [R1 I03; R2 F04] + + + + + NOT A LIVE EXPLOIT REPORT + + + The reports identify source-level and model-level risks. They do not demonstrate + arbitrary state forgery, actual stolen funds or an SP1 forgery. Native positive and negative + fixtures must establish exact impact and closure. + + + +Source interpretations about pause-only healing are preserved separately in the reconciliation register. No deployed status is +inferred. + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 7 + +MASTER 007 / 292 + MASTER / INTEGRATION + + + + +MASTER / 06 + + + + +Make every device dependable. +The operator product needs a common per-device resource owner spanning mining, proving, aggregation, +benchmark runs and next-epoch preparation. An idle kernel can still hold the buffers that prevent another +job from fitting. + + + WORKSTREAM INTEGRATED ACTION + + + + Reserve the complete workload and runtime headroom before launch. Provide + Memory admission + tested concurrent, time-shared and mining-only modes. [R2 F07] + + + Warm-prepare only when old and new allocations fit. Otherwise drain, release and + Cold epoch transitions + rebuild deliberately; do not rely on repeated OOM/timeouts. [R1 I05] + + + Validate exact dataset word counts rather than floor-log2 sizing alone. Reject + Metal geometry unsupported semantics before dispatch; run common vectors on every backend. + [R1 I06] + + + Preserve the host alignment and rollover improvements reported by both new + Nonce / work identity reviews. Test canonical grouping, tails, transitions and stale jobs on the native + backends. [R0 A07; R1 V6-12] + + + Port the existing OpenCL hit-selection pattern to CUDA with sentinels and overflow + Output and compilation + handling. Cache compiler output by a complete identity. Measure serving-mode + cost + accepted work and wall energy. [R2 F10] + + +The 12 GB / 8 GB standalone proofs do not establish simultaneous proving beside the larger miner. R1 reports the epoch allocation +and Metal-path findings; R2 does not close them by omission. + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 8 + +MASTER 008 / 292 + MASTER / INTEGRATION + + + + +MASTER / 07 + + + + +Make Ember safe and useful. + OBLIGATION WHAT CHANGES + + + + Do not retain a prior that misses the chosen rate floor merely because a + Eligibility before efficiency compliant neighbour is not more efficient. Reproduce the 98/100 MH/s + counterexample natively. [R1 I07, V6-04] + + + Maximum-rate mode must be able to explore permissible higher core/power + Objective-aware exploration settings rather than inherit an efficiency prior it cannot escape. Full sweeps and + short climbs have different scope. [R2 F11] + + + Separate hints from certified device measurements. Bind profiles to material + Workload-aware profiles dataset, register, compiler, driver and execution-mode changes; avoid + unnecessary retunes for harmless seeds. [R1 V6-05; R2 F11] + + + Minimal protected helper, authenticated commands, per-device leases, real ACL + Privileged-state ownership tests and explicit restoration of owned settings without clobbering user changes. + [R1 V6-06] + + + Separate signed developer-fleet control from public defaults. An urgent update + Public client independence + label must not silently override the operator installation choice. [R2 F14] + + + + + DO NOT OVERCLAIM THE EXISTING MACHINERY + + + The reviews recognise thermal/fault controls, fleet priors, signed jobs and visible + switches. The remaining work is to finish the safety and consent contract, not to describe + the current tools as an unauthenticated hidden backdoor. + + + +All gains remain measurement candidates. The 10 JavaScript tests do not certify physical tuning safety or a global optimum. + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 9 + +MASTER 009 / 292 + MASTER / INTEGRATION + + + + +MASTER / 08 + + + + +Turn work into reliable payment. +Proving speed matters only as one part of the request-to-payment path. Preserve the evidence that small +cards generate valid proofs, but test the full paid job under the final memory, scheduling and consensus +configuration. + + + PATH REQUIRED IMPROVEMENT + + + + Persist discovered, reserved, proving, verified, submitted, accepted and paid states. + Prover jobs Separate transient failure, expiry, cancellation and a lost race. Reconcile before retry. + [R1 I10; R2 F08] + + + Report arrivals, verified completions, active work, expiry and cancellation. A worklist + Flow accounting held near 600 by expiry is not proof of sufficient capacity. Include unsuccessful jobs + in latency and energy reporting. [R1 V6-08; R2 F08] + + + Persist exact debt reservation, signed transaction, nonce and hash before broadcast. + Pool money Reconcile ambiguous replies and restart. Treat mined, finalised, replaced and + reorged states separately. [R1 I02; R2 F12] + + + Distinguish first run from damaged state. Authenticate fresh sessions; bound frames + Pool integrity while reading, write queues, membership, deduplication and expensive verification. + Preserve miner vote keys. [R1 I08; R2 F13] + + + + + CUSTOMER AND OPERATOR TESTS STAY SEPARATE + + + Development-network payouts demonstrate a mechanism. Repeat outside purchases + demonstrate demand. Correct debt accounting, useful proof delivery and sustainable + margins are all required; none substitutes for another. + + + +The supplied disrupted pipeline period is not a clean v6 performance benchmark. Both reports retain this limitation. + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 10 + +MASTER 010 / 292 + MASTER / INTEGRATION + + + + +MASTER / 09 + + + + +Attack the strongest opponent. +The pure-DRAM comparison is not the whole competitive result. The reviews preserve modelled SRAM +and hybrid cases that fail important coexistence conditions after development is sunk. Neither their +manufacturability nor their defeat is established by this compilation. + + + RESEARCH OBLIGATION EVIDENCE REQUIRED + + + + Use the exact activated schedule, live dataset, complete geometry and + Full-window acceptance production predicate. A patched census or base-only counter cannot certify a + different release. [R1 V6-01/02; R2 F06] + + + Price the exact prefix-XOR alternative, including cached state, update work, ports + Incremental reg64 fold and routing. Equality checks do not establish a whole-hash speedup or a lower + hardware bound. [R1 V6-03; R2 F05] + + + Allow shared/reduced storage, recomputation, data-local and hybrid designs + Alternative memory across the known family bank. Include setup amortisation and selective + participation. [Plan pp. 10-13] + + + Generate decisions from the declared inputs and inequalities. Resolve the + Reproducible economics displayed $18M versus $40-80M inconsistency. Allow a specialised operator to + own companion GPUs or purchase proofs. [R2 F09] + + + Multi-epoch compatibility and sunk development remain mandatory stress cases. + No artificial expiry High development cost is not proof that an already-built machine cannot + dominate. [R1 V6-11; R2 F09] + + +No resistance multiplier, chip-arrival probability or speedup is newly asserted. A modelled failing case must be challenged and +resolved, not averaged out by a favourable one. + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 11 + +MASTER 011 / 292 + MASTER / INTEGRATION + + + + +MASTER / 10 + + + + +Finish the rest of the contract. +The new stack reviews supplement the 2.0 plan; they do not replace the non-mining gates. The following +obligations remain in the master test programme even when an individual source review does not mention +them. + + + AREA REQUIRED FOLLOW-THROUGH + + + + Review custom seed/header derivation, the 64-bit final fold, job/nonce binding and + Cryptographic binding reusable expensive work. No demonstrated break was asserted. Version any + consensus-semantic change. [R0 A05/A06/A08; R1 V6-12] + + + Rebuild, repin and test native/guest state and receipt agreement under old/new fee + Proof guests and fees modes. Hash matching alone does not prove current source-to-ELF equivalence. + [R1 V6-09/10] + + + Pin the supported semantics, block context, fees and limits. Test wallets, RPC, + EVM compatibility indexers and representative applications rather than bytecode execution alone. + [Plan p. 15; EVM suite] + + + Authenticate authority and state roots, successful payments and available + Wallets / data / oracle reconstruction data. Preserve the actual finality/trust labels. [Plan pp. 19-20; FIN + and VER suites] + + + Test release/key failure, founder withdrawal, bootstrap, replacement providers, + Independent operation + crashes and maintenance funding. [Plan pp. 21, 26; OPS suite] + + + Commercial and peer Repeat unaffiliated paid demand, operator margins, retention and fair current + evidence comparisons. No invented rank or unsupported probability. [COM and LEAD suites] + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 12 + +MASTER 012 / 292 + MASTER / INTEGRATION + + + + +MASTER / 11 + + + + +Reconcile; do not erase. + ITEM WHAT DIFFERS / WHAT MUST HAPPEN + + + + R1 I03 describes stale pause-only code and a documented later fix. R2 F04 says + the predicate alone cannot establish permanent liveness failure because historical + REC-01 / Finality healing + backfill may matter. Preserve both; pin the exact mode/spec/commit and run native + post-window healing with and without historical data. + + + R0 contains only V2/V3/V4. Both later reports identify genuine v6 research and + REC-02 / Version scope alignment/shadow improvements, while retaining integrated-release gaps. Do not + repeat R0 as the status of v6; do not infer deployment from source. + + + R1 records 32,768 expression checks; R2 records 33,024 with 4,096 updates. + REC-03 / Evidence counts These are separate runs, not contradictory totals or stronger security probabilities. + Keep each result with its harness. + + + R1 discusses a late placed-core table; R2 discusses the coexistence-model + REC-04 / Model variants conditions. DRAM, SRAM, hybrid, node and GPU-cohort assumptions differ. + Reconcile through raw inputs; do not select the most flattering ratio. + + + Metal geometry, cold transitions, eligibility-first tuning, helper restoration, session + REC-05 / Findings omitted + binding, shard retry and guest-build details remain carried forward from R1. + later + Absence from R2 is not closure. + + + R1 historical excerpt captions include local F labels. Master references always use + REC-06 / Local IDs + R0, R1 or R2 prefixes so they cannot be confused with R2 findings. + + +This is an editorial discrepancy register, not a fresh audit or an assertion that either review is definitively correct. Closure requires +source and execution evidence on the intended release. + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 13 + +MASTER 013 / 292 + MASTER / INTEGRATION + + + + +MASTER / 12 + + + + +One sequence. Clear exits. + STAGE DELIVERABLE EXIT EVIDENCE + + + + One pinned release, complete fixtures, Clean independent build and common work + 01 / Contract + approved claims and thresholds. identity across all components. + + + Native positive/negative, order, crash, replay + Cache, enforcement, payment durability, + 02 / Correctness and long-partition tests close the relevant + session boundaries and finality decision. + findings. + + + 03 / Productive Memory owner, cold transitions, exact Declared consumer tiers finish suitable jobs; + devices geometry, retry lifecycle, tuning safety. no hidden expiry, memory or payment losses. + + + CUDA selection, valid compile caching, Byte agreement and serving-mode + 04 / Competitive + objective-aware tuning and v6 improvements within the approved cost + execution + acceptance. limits. + + + Strongest feasible programmable SRAM/ Independent cost review and approved + 05 / Specialist + DRAM/hybrid design and model coexistence scenarios pass without + economics + reconciliation. emergency retirement assumptions. + + + Repeat customers, operator retention, no- + 06 / Contender Independent assessment based on sustained + founder operation and fair peer + evidence technical, economic and commercial results. + comparison. + + + +Owners, budgets and delivery dates require project approval; none is invented here. Research can finish +with a negative result. That result changes the design or narrows the claim rather than automatically +producing a green release status. + +Sequence consolidates R1 and R2 recommendations. Safety and money-handling gates cannot be offset by aggregate throughput +or a weighted score. + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 14 + +MASTER 014 / 292 + MASTER / INTEGRATION + + + + +MASTER / TRACEABILITY + + + + +F01 to F07 / test coverage +Editorial crosswalk. The complete source wording and evidence are retained in the corresponding review. +Proposed tests remain NOT RUN. + + + R2 FINDING RELATED R1 RECORD ORIGINAL TESTS + INT GATES + + + + ZKP-02, ZKP-03, ZKP-04, ZKP-08 INT-01, + F01 / Proof-cache context I01 + INT-02 + + + F02 / Mandatory proof + I09 / V6-09 GOV-05, ZKP-01, ZKP-07, ZKP-08 INT-17 + enforcement + + + GOV-01, GOV-03, POW-01, ROT-02 INT-07, + F03 / One executable release I04 / V6-01, V6-12 + INT-08 + + + FIN-02, FIN-03, FIN-07, FIN-08, VER-08 + F04 / Finality / recovery contract I03 + INT-05, INT-06 + + + F05 / Incremental register fold V6-03 POW-03, POW-04, ADV-03, ADV-05 INT-18 + + + F06 / Complete v6 acceptance V6-01, V6-02 GOV-05, POW-01, POW-02, POW-06 INT-08 + + + GPU-05, CAP-02, CAP-05, UX-02 INT-09, + F07 / One device memory owner I05 / V6-07 + INT-11 + + +Part C contains all 44 R2 closure requirements. Original case definitions and numerical profiles remain in Part B. Mappings do not +imply unique defects or executed tests. + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 15 + +MASTER 015 / 292 + MASTER / INTEGRATION + + + + +MASTER / TRACEABILITY + + + + +F08 to F14 / test coverage +Editorial crosswalk. The complete source wording and evidence are retained in the corresponding review. +Proposed tests remain NOT RUN. + + + R2 FINDING RELATED R1 RECORD ORIGINAL TESTS + INT GATES + + + + F08 / All-job proving outcomes I10 / V6-08 CAP-03, CAP-04, CAP-06, CAP-07 INT-12 + + + ADV-05, ADV-08, ECO-03, ECO-08, LEAD-03 + F09 / Strongest feasible specialist V6-11 + INT-18 + + + Implementation + F10 / Production worker efficiency GPU-06, GPU-08, POW-01, UX-08 INT-07 + opportunity + + + F11 / Ember search and identity I07 / V6-04, V6-05 GPU-02, GPU-04, UX-02, UX-03 INT-13, INT-14 + + + F12 / Durable pool obligations I02 ZKP-05, UX-04, OPS-04 INT-03, INT-04 + + + F13 / Bounded pool service I08 OPS-06, UX-04, UX-05, UX-06 INT-15, INT-16 + + + V6-06 is related, not + F14 / Public operator control OPS-03, OPS-05, UX-02, UX-07 INT-14 + identical + + +Part C contains all 44 R2 closure requirements. Original case definitions and numerical profiles remain in Part B. Mappings do not +imply unique defects or executed tests. + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 16 + +MASTER 016 / 292 + MASTER / INTEGRATION + + + + +MASTER / CARRIED-FORWARD COVERAGE + + + + +Nothing disappears by omission. + SOURCE RECORD RETAINED OBLIGATION BASE COVERAGE + + + + Historical version scope; v6 progress recorded by R1/ + R0 A01 GOV-01; GOV-08 + R2. + + + Lane dependencies, per-site memory concentration, + operation invariants and safe deterministic POW-02/03/04/06; + R0 A02, A03, A08, A09 + generation. Re-test current candidate; old counts ADV-02/04 + remain historical. + + + Historical shadow omission; later reports say + R0 A04 addressed. Preserve mutation regression and full-v6 GOV-05; POW-01/02 + coverage distinction. + + + Cryptographic binding and semantic identity review; + R0 A05, A06 POW-05; GOV-01; ZKP-03 + no demonstrated break claimed. + + + Host alignment now guarded per later reports; + R0 A07 POW-01; ROT-01 + preserve actual GPU rollover/tail tests. + + + Cold allocation, exact Metal geometry, Ember + R1 I05/I06; I07; I08; I10 eligibility/restoration, fresh session auth and safe INT-09/10/12/13/14/15 + shard retry remain in INT gates. + + + Minimum-validator cold capacity, actual proof + ZKP-01/02/07; + R1 V6-09/V6-10 fixtures, source/ELF/VK/input-format and fee + EVM-03/08; INC-01 + activation. + + +R1 contains 10 I findings and 12 V6 findings; R2 contains 14 F findings. Full reports preserve every source location and +qualification. + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 17 + +MASTER 017 / 292 + MASTER / INTEGRATION + + + + +MASTER / RELEASE DECISION + + + + +Pass the outcome, not the task. +Approval has four layers: scope approved; implementation complete; evidence reproduced; claim +authorised. None can be inferred from the next or previous label. + +Before confirmatory tests, lock the supported GPU population, economic envelope, security/fault +assumptions, workloads, performance limits, evidence standards and external-review scope. The original +numerical profiles are proposals, not already approved protocol rules. + + + DECISION REQUIRED CONDITION + + + + One reproducible manifest; required fixtures present; thresholds + Proceed to confirmatory testing + approved; all blocking scope ambiguities resolved. + + + Applicable safety, validity, payment, recovery, access and operational + Release / operation sign-off + tests pass on the real release. No waiver disguises a core failure. + + + In addition, economic specialist tests, independent comparison, sustained + Leadership-contender assessment + operating evidence and repeat paid demand support the declared claim. + + + Retest affected gates after relevant changes; retain negative evidence and + Ongoing claim maintenance + unresolved limitations; update public statements when conditions change. + + + + + THE ANSWER TO THE AMBITION + + + Executing and independently passing this complete programme would support a credible + case that Igneum is in the running for the leading GPU-first network position. It would + not guarantee adoption, perpetual GPU profitability, defeat of all future chips or a + numerical number-one ranking. + + + +No tests, code fixes, deployment status or specialist-model failures were newly closed while assembling this volume. + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 18 + +MASTER 018 / 292 + STRATEGY EDITION + 08 OCTOBER 2026 + PLAN / 2.0 + + + + + THE GPU-FIRST EXECUTION PLAN + + + + + 2.0 + A durable home + for GPU owners. + Competitive hardware. Verifiable computation. + Independent operators. + + + + + GPU EVM + ZKVM INDEPENDENT + COMPETITIVENESS ARCHITECTURE VERIFICATION + + + + The complete strategy, research programme and delivery gates. + Includes the full supplied leadership and architecture source. + + + +MASTER 019 / 292 + STRATEGY / 2.0 + + + +DOCUMENT MAP + + + +The complete 2.0 plan. +Direction, hardware research, application architecture, security, economics and execution. The supplied +document is retained in full at the end. + + +DIRECTION APPLICATION AND OPERATORS + +The governing objective 3 Proofs and paid demand 17 + +The leadership case 4 Mining / proving coexistence 18 + +Evidence and status 5 + SECURITY AND INDEPENDENCE + +MINING FOUNDATION Finality and recovery 19 + +Hardware baseline 6 Wallets, receipts and state 20 + +Keep progress. Remove noise 7 Operational independence 21 + +Define competitiveness 8 + EXECUTION PROGRAMME + +The resource-coupling experiment 9 + Past and future reference points 22 + +Memory and shortcut attacks 10 + Delivery gates 1-3 23 + +Rotation without rescue 11 + Delivery gates 4-5 24 + +The programmable opponent 12 + Acceptance scorecard 25 + +Coexistence economics 13 + Risk and ownership 26 + +APPLICATION AND OPERATORS Leadership and claims 27 + +Ember and operator control 14 + SOURCE AND ARCHIVE + +EVM and zkVM architecture 15 + Completeness map 28 + +Consensus proof enforcement 16 + Source register 29 + + Research references 30 + + + FULL SOURCE APPENDIX + + A / Leadership assessment 31 + + B / EVM and proving strategy 34 + + + + +How to read this plan. Team-reported results and modelled estimates remain labelled. Proposed work is not marked complete. +Role labels are suggestions, not appointments. This is the 8 October 2026 source snapshot, not a fresh technical audit. + + + + +IGNEUM 2.0 / 08 OCT 2026 2 / 37 +MASTER 020 / 292 + STRATEGY / 2.0 + + + +01 / THE OBJECTIVE + + +Built to remain competitive. +The system we are trying to earn. Not a claim that the work is already complete. + + + THE GOVERNING STATEMENT + + + Someone can build one, but ordinary GPU owners remain + competitive, the supplier cannot obtain a lasting overwhelming + advantage, and the network does not depend on emergency + intervention to survive. + + +Igneum 2.0 is the consolidated plan for a GPU-secured network with Ethereum-compatible applications, +verifiable execution and a proving service that can serve customers beyond the chain. The success +condition is durable participation by ordinary operators, even when specialised hardware exists. + + W HAT YOU DELIVER W HY IT MATTERS + + + GPUs remain economically competitive against Miners can invest without depending on emergency + realistic specialised hardware algorithm changes to protect them. + + + A straightforward, efficient miner with reliable Ordinary owners can participate successfully, not just + payouts and retained operator control sophisticated mining businesses. + + + Useful proofs that outside customers repeatedly You establish demand for a service, rather than relying + purchase exclusively on enthusiasm for the coin. + + + Secure execution, finality and independently Developers and customers have a reason to trust the + operated infrastructure network with meaningful activity. + + +Deliver all four. The result would be a serious leadership candidate, not merely another GPU-minable coin. +Shipping features is not the same as demonstrating that these outcomes hold. + +S1: supplied 2.0 document. S2: supplied leadership screenshot. C2: consolidated research discussion. + + + + +IGNEUM 2.0 / 08 OCT 2026 3 / 37 +MASTER 021 / 292 + STRATEGY / 2.0 + + + +02 / STRATEGIC POSITION + + +A credible route to leadership. +The ceiling is category leadership. Adoption, sustained demand and trust still have to be earned. + + A REA T HE PROPOSED END-STATE + + + A potential leadership position once independent hardware analysis confirms + GPU competitiveness + the result against programmable, multi-epoch competitors. + + + Reproducible measurements and realistic adversarial designs. Economics that + Resistance evidence + do not assume chips automatically expire. + + + Straightforward installation, effective tuning, transparent earnings, reliable + Miner experience + payouts and retained control. + + + The same accessible hardware can potentially earn from genuinely purchased + Useful hardware + proving work as well as securing the chain. + + + A credible contender after independent review and failure testing. A feature + Security and decentralisation + list does not establish security. + + + Profitability and market Demand, competition, liquidity and operating costs determine the outcome. + position Protocol design alone cannot guarantee them. + + + + MINER PROPOSITION CUSTOMER PROPOSITION + + Useful hardware. Retained control. Correct results. Reliable delivery. + My hardware remains useful and competitive. I I receive a correct result at a competitive price + can earn from more than the mining subsidy and reliable delivery time, without needing to + without surrendering control. choose which independent operator produced it. + + +Leadership requires miners who stay through difficult conditions, customers who repeatedly pay for output +and a network that works without the founding team holding it together. The complete package is the +advantage, not one supposedly unbeatable hash. + +S1: leadership assessment, proposed end-state and miner/customer propositions. S2: leadership requirements. + + + + +IGNEUM 2.0 / 08 OCT 2026 4 / 37 +MASTER 022 / 292 + STRATEGY / 2.0 + + + +03 / EVIDENCE AND BASELINE + + +What the evidence shows. +This edition preserves the source snapshot. It does not certify a deployment, an audit or a +completed benchmark. + + E VIDENCE CLASS M EANING IN THIS PLAN + + + A result supplied by the team or recorded in the earlier discussion. Not + TEAM-REPORTED + independently reproduced for this PDF. + + + An estimate conditional on hardware, implementation, cost and lifetime + MODELLED + assumptions. Not a measured manufactured product. + + + An architectural recommendation or research hypothesis. It needs an acceptance + PROPOSED + test before adoption. + + + Evidence or implementation was outstanding at the source snapshot. No later + PENDING + completion is assumed. + + + A rejected approach retained in the record. It is not silently returned to the + EXCLUDED + roadmap. + + +The current foundation +The discussion records consumer-GPU proof generation, development-network mining, execution +consistency and proving payouts. These support a technical proof of concept. They do not yet establish a +fully enforced, independently validated or commercially proven network. + +The next boundary +Consensus-enforced proof verification, finality under long disruptions, sustained end-to-end proving +capacity, independent operation and repeat external demand are separate gates. A successful test in one +category does not satisfy another. + + + STATUS DISCIPLINE + + Designed, implemented, activated, team-tested, independently reproduced and independently + reviewed are different states. Every release should make the difference visible. + + +The full source text is retained in the appendix. References to current conditions in that text describe the source snapshot, not a fresh +status check performed during typesetting. + + +S1: implementation caveats. C1: team update. C3: earlier litepaper review and evidence discussion. + + + + +IGNEUM 2.0 / 08 OCT 2026 5 / 37 +MASTER 023 / 292 + STRATEGY / 2.0 + + + +04 / HARDWARE SNAPSHOT + + +The honest hardware baseline. +Latest team update in the conversation. Figures remain conditional on the declared comparison +and outstanding measurements. + + R EPORTED SPECIALISED + C OMPARISON AT THE KNEE + A DVANTAGE + + + + GPU and chip on the same process node 2.0× per joule + + Chip one process node ahead 2.4× per joule + + Chip two process nodes ahead 2.8× per joule + + Apple comparison tier 1.2× per joule + + L EVER OR ASSUMPTION S OURCE SNAPSHOT + + + Reported reduction of 34-41% in Blackwell/Ada power draw for under 2% + Ember core-clock lock + loss of rate. This saving is already in the tuned baseline. + + + Reported k change from 0.56 to 0.78 against a chip one node ahead; parity + 64-register window + on the GPU's own node. GPU-side cost was still being measured. + + + 5.5 / 8.5 / 11.5 GiB proposed. The update says the 8 GB tier would be retired + Dataset schedule + at year two. This is a policy cost, not automatically a success. + + + The update reports thirty-odd measurement rows across rented 5090, 4090, + Evaluation coverage + H100, 3090 and PC 1 cards. + + + Register-window GPU cost; PC 1 memory-clock ladder; placed chip core; 5.5 + Still owed in the update + GiB rows on the 8 GB card. + + +The same-DRAM assumption must be tested against the adversary's best feasible memory configuration. A +larger register file on the GPU is not proof that using it has zero marginal cost. Synthesis and physical- +design estimates must be kept separate. + + + DO NOT PROMOTE THE MODEL INTO A GUARANTEE + + The earlier $23M and $340M annual-revenue thresholds, $20-75M development-cost range + and chip-arrival probabilities are source assumptions or claims, not validated safety boundaries. + Chip lifetime must be tested, not assigned. + + + +C1: latest team chip-status update. C2: interpretation, outstanding tests and modelling limits. + + + +IGNEUM 2.0 / 08 OCT 2026 6 / 37 +MASTER 024 / 292 + STRATEGY / 2.0 + + + +05 / DECISION REGISTER + + +Keep progress. Remove noise. +The 2.0 baseline starts with measured work and a short list of falsifiable experiments. + + E LEMENT D IRECTION R EASON + + + Reduce honest operating cost without adding + Ember tuning Keep + consensus complexity. + + Measure unavoidable live-state cost and the + 64-register window Keep and test + complete GPU penalty. + + Preserve measured settings and address-quality + 16-byte reads / index fold Retain baseline + fixes. Reopen only with a new hypothesis. + + Re-optimise the adversarial architecture after every + Operation mix Conditional + change. + + Price the ASIC burden against excluded cards and + Dataset progression Reconsider + proving-memory pressure. + + Require measured versatility benefits and acceptable + Hourly program Conditional keep + compilation cost. + + Each boundary must earn its implementation and + Weekly / family layers Simplify if redundant + testing cost. + + Useful for genuine vulnerabilities; not the basis of + Bring-forward mechanism Govern carefully + normal competitiveness. + + Not a committed fix. Require deterministic, cross- + Mixed integer/FP32 Research branch + vendor results. + + The apparent advantage did not survive realistic + Long programs / select trees Exclude + implementation. + + SM gating, wider reads, sealed classes, random + Other rejected knobs Exclude epoch lengths, per-tier scoring and VRF draws + remain out. + + A programmable adversary can implement known + Automatic chip expiry Remove assumption + changes in firmware. + + +Retain rejected variants as controls. A sound evaluation should continue rejecting the long-program result +when instruction memory is implemented as shared SRAM rather than flip-flops. + + ONE ACCEPTANCE RULE + + A change passes only when the best adversarial implementation becomes worse relative to the + best practical GPU implementation, within pre-agreed cost and verification limits. + + +C1: chosen and rejected levers. C2: consolidated keep/change/remove recommendations. + + + + +IGNEUM 2.0 / 08 OCT 2026 7 / 37 +MASTER 025 / 292 + STRATEGY / 2.0 + + + +06 / DEFINE THE TARGET + + +Measure real competitiveness. +A single joules-per-hash ratio cannot establish durable access to mining. + + + EXISTING OWNER NEW ENTRANT + + Does running the card make sense? Can accessible hardware be purchased? + Include electricity, wear, fees, failure risk and Include purchase price, financing or annualised + alternative uses. Existing hardware does not cost, operation and realistic resale value. A + need to recover its historical purchase cost in the healthy installed fleet can hide poor replacement + same way as a new investment. economics. + + + + CORE MEASURE + + Cost per accepted unit of work = annualised hardware cost, power, hosting, failures and + fees divided by annual accepted work. + + +Use accepted work rather than kernel hashrate. Include rejected submissions, downtime, epoch +preparation, compilation, host power and network delays. Publish the reference population before +optimising against it: several generations, vendors and memory capacities, including realistic used +hardware. + + E NERGY TARGET W HAT THE ARITHMETIC ACTUALLY SAYS + + + About 33.3% less electricity per hash. This can still be commercially + 1.5× specialist efficiency + meaningful. + + + With the ASIC unchanged, the GPU would need a further 37.5% + 2.4× down to 1.5× energy reduction. The existing clock-lock saving cannot be counted + twice. + + + Under the earlier assumed 1.2× node multiplier, reaching 1.5× one + Same-node research gate node ahead implies about 1.25× at the same node. Recalculate for + each design. + + +Separate specialisation advantage from electricity and scale advantages. No hash can guarantee that every +domestic tariff is competitive with every industrial tariff. The target is a bounded additional barrier from +hardware specialisation, not equal profitability everywhere. +Figures above are calculations from assumptions already discussed. They are targets and illustrations, not achieved results. + + +C2: competitiveness definition, energy-ratio calculations and comparison boundaries. + + + + +IGNEUM 2.0 / 08 OCT 2026 8 / 37 +MASTER 026 / 292 + STRATEGY / 2.0 + + + +07 / ARCHITECTURAL EXPERIMENT + + +Make simplification expensive. +Investigate a compact execution core that connects live state, dependent reads, arithmetic and +communication. + + + CANDIDATE EVALUATION PATH + + Live state → memory address → returned data → arithmetic and lane interaction → + updated live state → next address. + + +Start by reorganising, not expanding +Hold approximate instruction count, read count and dataset size constant for the first experiment. Change +dependency structure so the adversary cannot cheaply isolate storage, arithmetic and scheduling into +independent small engines. Make the final result depend on the necessary intermediate work. + +Prove the state is necessary +The useful question is not whether the reference program declares 64 registers. It is how much +independent information must remain available across memory waits, how often it is accessed and what +the cheapest implementation pays to service it. Permit banking, SRAM, time-multiplexing, compression +where possible and selective recomputation. + + E XPERIMENT P ASS EVIDENCE + + + Lower whole-system specialist advantage after the adversary is + Connected existing resources + redesigned, without an unacceptable honest-card cost. + + + Reducing, reconstructing or moving the state creates a quantified + Persistent live state + performance, energy or area penalty. + + + A separate integer/FP32 prototype improves the result after exact + Broader resource mix semantics, compiler behaviour and adversarial simplification are + included. + + +The mixed-resource prototype is optional. Avoid approximate operations and architecture-dependent +results. A restricted floating-point domain may be much cheaper for a specialist than a general floating- +point unit, so the hardware reviewer must be allowed to exploit it. + + + RESEARCH STATUS + + These are hypotheses, not an established recipe for 1.5×. A negative result is useful evidence + and must remain publishable. + + + +C2: resource-matching programme and research qualifications. R5-R8: carried-forward research context. + + + + +IGNEUM 2.0 / 08 OCT 2026 9 / 37 +MASTER 027 / 292 + STRATEGY / 2.0 + + + +08 / MEMORY AND ATTACK SURFACE + + +Price the cheapest alternative. +Large memory capacity alone is not a complete energy-resistance argument. + + A DVERSARIAL PATH W HAT TO TEST + + + Several engines amortise dataset storage, construction and updates. + Shared dataset + Analyse many concurrent hashes, not only one. + + + Store selected data, recompute the rest and choose the best time-memory + Reduced memory + trade-off. + + + Distribute data across processors and move computation or intermediate + Data-local computation + state towards the next read. + + + Mine only favourable programs or families. Include idle periods, fallback + Selective participation + execution and difficulty response. + + + Try to reuse an expensive intermediate state across many cheap winning + Reusable expensive work + attempts. Review nonce, template and output binding. + + + Allow different devices, channels, banking, caches, packaging and + Alternative memory system + operating points rather than fixing the GPU's layout. + + +The register window has a specific job +Price the cheapest combination of moving state, moving data, recomputing values and adding local +resources. A larger necessary state may make distributed execution less attractive, but it can also penalise +the GPU. The complete comparison decides. + +Every accepted program must carry the intended cost +Study both the average advantage and its distribution. A family bank with occasional weak periods can +support a profitable intermittent specialist. Require an unavoidable resource floor and examine whether +each lottery attempt really pays for it. + + + ANALYSIS DELIVERABLE + + Map the actual Igneum evaluation process into an explicit memory-capacity, bandwidth, energy + and amortisation model. State which results are bounded formally and which depend on + physical-design estimates. + + + +C2: memory sharing, selective participation, data-local execution and shortcut review. R6-R10: context retained from the research +discussion. + + + + +IGNEUM 2.0 / 08 OCT 2026 10 / 37 +MASTER 028 / 292 + STRATEGY / 2.0 + + + +09 / ROTATION AND MEMORY POLICY + + +Competitive without rescue. +Known scheduled changes are part of the adversary's design brief. Future emergency changes +are not a profitability assumption. + + L AYER IN THE TEAM PLAN 2 .0 ACCEPTANCE REQUIREMENT + + + Show the anti-specialisation benefit after compilation, setup and easy- + Hourly program + program selection costs. + + + Demonstrate a distinct cost to the adversary. Remove redundant + Weekly parameters + complexity. + + + Evaluate one programmable opponent supporting the entire published + 180-day family / 18-family bank + bank. Crossing the boundary is not proof of chip retirement. + + + Specify activation, coalition behaviour, partition handling and old-client + Miner-voted bring-forward + behaviour. "No veto" requires a mechanism, not a label. + + + Measure adversary burden against commodity exclusion, upgrade costs + Dataset schedule + and mining/proving coexistence. + + + Protect the intended seed-selection property and define behaviour + Seed/VDF pipeline + when finality is unavailable. + + +The no-rescue test +Evaluate several years with no newly invented instruction families or emergency anti-chip upgrades. +Published program changes and scheduled transitions can continue, but the hardware designer knows +them all. The system must remain competitive against a design that survives them. + +A conservative memory support horizon +Prefer a bounded, epoch-defined dataset and a declared hardware-support horizon. Grow memory only +where the extra adversary cost justifies the burden on ordinary operators. Treat retirement of the 8 GB tier +as a cost to evaluate, not an achievement. + +Do not credit live chain-state coupling as an ASIC exclusion mechanism merely because stale state gives +wrong answers. Price update bandwidth, synchronisation, recovery and adversarial state growth. Keep it +only where the measured benefit survives those costs. + +C1: four-layer plan and dataset sizes. C2: no-rescue evaluation and dataset-policy recommendations. + + + + +IGNEUM 2.0 / 08 OCT 2026 11 / 37 +MASTER 029 / 292 + STRATEGY / 2.0 + + + +10 / INDEPENDENT HARDWARE BRIEF + + +Build the strongest opponent. +Commission an independent, programmable, multi-epoch design. Do not force it to imitate a +graphics card. + +The reviewer should minimise total cost and energy while remaining compatible with the published +program space. Permit changes in clock, lane count, execution width, pipelines, state storage, instruction +sharing, memory configuration and supporting hardware. + + A DAPTATION R EQUIRED RESULT + + + Firmware update Throughput, energy and cost before and after each family transition. + + + Measured or modelled penalty for missing native operations. Slower + Emulation + does not automatically mean unprofitable. + + + Board cost, bandwidth, power and survival through the dataset + Memory expansion or overprovisioning + schedule. + + + Companion CPU, GPU or FPGA Complete-system economics, including hybrid mining and proving. + + + Favourable-period mining Revenue after idle periods, re-entry and difficulty response. + + + Incremental revision cost, reusable design work and realistic + Silicon revision + development delay. + + +Evidence standard +Use realistic SRAM macros, port requirements, wiring, memory interfaces, switching activity and complete- +board overhead. Logic synthesis is one input, not a manufactured-chip measurement. Keep same-node +and advanced-node results separate and publish uncertainty ranges. + + + THE LIFETIME RULE + + Assume a capable programmable design can survive several epochs. Award a retirement benefit + only when the cheapest adaptation loses economic competitiveness. Compatibility, efficiency + and investment return are separate outcomes. + + +Public challenge incentives should reward a better adversary and a reproduced shortcut, not only +confirmatory results. Independent reproduction and independent security review answer different +questions. + +C2: adversarial brief, transition matrix and physical-design requirements. + + + + +IGNEUM 2.0 / 08 OCT 2026 12 / 37 +MASTER 030 / 292 + STRATEGY / 2.0 + + + +11 / COEXISTENCE ECONOMICS + + +Economics after chips arrive. +A failed development investment can still leave an efficient installed fleet. The model must +include that world. + + + NORMAL INVESTMENT CASE ALREADY-FUNDED CASE + + Price the full project. Treat development as sunk. + Include development, initial fleet, later Assume research has already been paid for or + purchases, power, operations, financing reused elsewhere. The opponent still pays + assumptions and residual value. Test private manufacturing, deployment and operation. Can + mining and hardware sales. accessible GPUs compete? + + +Let operators react +Model entry and exit, used-card prices, replacement cycles, changing difficulty and alternative workloads. +Do not hold everyone's revenue share constant while comparing margins. A GPU upgrade is not free, and a +chip revision need not repeat the entire original development bill. + + S CENARIO AXIS R EQUIRED RANGE OF BEHAVIOUR + + + Small, growing and successful high-revenue networks; falling token + Network revenue + revenue as well as expansion. + + + Multi-year programmable survival plus demonstrated transition + Hardware lifetime + penalties. + + + Different electricity tariffs, hosting, failure rates, purchase prices and + Operator costs + resale values. + + + Declining issuance, fee income, internal proving demand and external + Reward structure + jobs. + + + Private supply, public hardware sales, multiple suppliers and + Market structure + concentration. + + +The earlier $340M and $23M annual-revenue thresholds belong in a sensitivity workbook with their +assumptions. They are not general safety boundaries. The revised goal is not to make every specialised +investment lose money; it is to prevent a lasting overwhelming barrier to accessible mining. + + + SUCCESS CONDITION + + A specialised supplier may earn a normal return. Ordinary GPUs remain sufficiently close in total + cost, widely obtainable and useful outside mining that new operators can still compete. + + + +C1: source thresholds and development-cost assumptions. C2: five-year coexistence model and sunk-cost stress case. + + + + +IGNEUM 2.0 / 08 OCT 2026 13 / 37 +MASTER 031 / 292 + STRATEGY / 2.0 + + + +12 / MINER AND OPERATOR EXPERIENCE + + +Make good operation ordinary. +Desktop-first on Windows and macOS. A mining-console experience, not a web app disguised as +a desktop product. + + P RODUCT REQUIREMENT W HAT THE OPERATOR SHOULD RECEIVE + + + Straightforward install, hardware detection, compatibility explanation and + Easy entry + safe default tuning. + + + Separate mining, internal proving and external proving income. Show net + Honest economics + estimates using the operator's entered electricity tariff. + + + Clear power limits, pause/stop controls, job selection and explicit + Control + software-update acceptance. + + + Rejected work, failed proofs, queue delays, memory pressure and missed + Failure visibility + payments are visible and actionable. + + + Reliable, noncustodial payment paths that do not make small operators + Accessible payouts + impractical. + + + Isolate proving workloads from wallet secrets and signing authority. + Safe execution + Publish the security assumptions. + + +Pool payment variance without surrendering authority +Investigate a verifiable binding between performed work and the miner's retained voting key. Pooling +payments should not silently hand transaction selection, governance or finality control to the pool. Test key +substitution and actual template selection rather than relying on a protocol label. + +Make the best implementation accessible +Publish optimisations, compiler settings and safe tuning logic. Measure home-connection performance +against datacentre performance using accepted work. Evaluate decentralised pooling and job declaration +where they fit Igneum's own protocol. + + + DO NOT ADD + + Hardware whitelists, trusted-device attestation, self-reported GPU bonuses or per-address + reward quotas do not establish economic equality. Keep hardware profiling in the client, not + self-attested consensus privilege. + + + +C2: operator-control programme, pooling and software requirements. Earlier project context: native desktop miner and wallet. + + + + +IGNEUM 2.0 / 08 OCT 2026 14 / 37 +MASTER 032 / 292 + STRATEGY / 2.0 + + + +13 / APPLICATION ARCHITECTURE + + +EVM is the right front door. +A sovereign GPU-mined L1 with a flexible, carefully versioned proving layer. Not simply another +zkEVM label. + + D ECISION 2 .0 DIRECTION P URPOSE + + + Reuse familiar contracts, languages, + Developer interface EVM-compatible execution + wallets and tooling. + + + General-purpose zkVM; initially the Prove the EVM implementation without + Execution proof + SP1-based implementation creating a bespoke proof system. + + + Keep responsibility for consensus, data + Security and finality Igneum's sovereign GPU-mined L1 + availability and recovery explicit. + + + Supported customer proving Serve other networks without requiring + External service + workloads application migration to Igneum. + + +The supplied plan identifies revm for EVM execution and SP1 behind a versioned proving interface. A zkVM +can prove a program that implements EVM execution; zkVM and zkEVM are not competing choices in this +composition. + +Compatibility is a test suite +Document differences in block context, timestamps, randomness and two-dimensional fees. Test +representative contracts, wallet fee estimation, indexing, reverted transactions, receipts and application- +level economic assumptions. Bytecode execution is not proof that every application behaves unchanged. + +Sovereignty is deliberate +Do not move to an Ethereum L2 merely for the category label. An L2 may be appropriate for Ethereum- +settlement objectives, but the supplied strategy is an independent home for GPU operators. Igneum +therefore keeps its own consensus, availability and cross-chain verification obligations. + + + POSITIONING + + A GPU-secured network for Ethereum-compatible applications and verifiable computation. + + + +S1: architectural choices, EVM compatibility and sovereign-L1 recommendation. + + + + +IGNEUM 2.0 / 08 OCT 2026 15 / 37 +MASTER 033 / 292 + STRATEGY / 2.0 + + + +14 / PROVING CORRECTNESS + + +Enforce every proof. +Official producers doing the right thing is not the same as ordinary validators enforcing it. + +The supplied source describes proving v0 as checking the statement against native execution without +requiring the carried SP1 proof to verify in consensus. Under that source snapshot, a modified producer +could obtain a proving payout without doing the corresponding valid proof work. This plan does not assume +the issue remains open or has been fixed; it requires version-specific closure evidence. + + N EGATIVE TEST R EQUIRED VALIDATOR BEHAVIOUR + + + Correct statement, invalid proof Reject the proof record and pay no proving reward. + + + Wrong program or verifier identity Reject under the pinned release configuration. + + + Wrong chain, epoch or statement binding Reject replayed or misbound work. + + + Changed payout identity Reject unauthorised payout changes. + + + Duplicate proof reward Enforce exactly the permitted payment outcome. + + + Authenticate their derivation, not just execution over supplied + Incorrect rewards or consensus inputs + inputs. + + +One well-tested backend first +Pin permitted program identities, verifier versions and security parameters. Preserve a controlled +replacement interface without treating several immature proof systems as interchangeable. Include +soundness analysis, security margins and the cost of verification in the acceptance process. + +Keep authority separate +Producing a proof should not make a provider the authority over ordering or finality. Test whether a +concentrated provider can stall useful operation by withholding service. Replacement operators need +usable inputs, reassignment and explicit behaviour during delays. + + + BOUNDARY + + A proof of execution is not automatically a proof of authenticated consensus inputs, canonical + history or data availability. + + + +S1: four conditions for the proving architecture. C3: P21/P22 review and proposed negative tests. + + + + +IGNEUM 2.0 / 08 OCT 2026 16 / 37 +MASTER 034 / 292 + STRATEGY / 2.0 + + + +15 / USEFUL WORK + + +Turn proofs into paid demand. +Start with one complete workload. Add breadth only where the operator fleet has demonstrated +an advantage. + + + COMPLETE PIPELINE + + Request → input availability → assignment → execution → shard proving → aggregation → + verification → inclusion or delivery → payment. + + + + S TAGE R EQUIRED EVIDENCE + + + Sustained proofs for a fixed, meaningful workload. Correct acceptance and + Igneum execution + payment. + + + An agreed proof format, deadline, price, failure policy and customer reason + First external pilot + for choosing the service. + + + Repeat purchases Genuine repeat paid jobs without the project reimbursing the customer. + + + Each service has validated inputs, program identity, verification rules and + Broader workloads + measured delivery economics. + + +Publish the complete benchmark +Report workload size, input transfer, memory, energy, waiting time, proving time, aggregation, verification, +failed attempts and payment delay. Publish typical and tail latency. A small shard that finishes quickly is +not a commercial result if total queues keep growing. + +Keep revenue categories separate +Mining subsidy, internal proving rewards and external customer revenue are different streams. +Development-network payouts prove an accounting path; they do not prove willingness to pay. Operator +revenue is also not automatically protocol revenue or demand for IGN. + + + INITIAL COMMERCIAL GATE + + One repeat customer purchasing useful proofs at a price that supports reliable delivery and + operator margin. Igneum does not first need to win the largest application ecosystem. + + + +S1: external proving sequence and commercial qualification. C2/C3: complete-pipeline benchmark and pilot gates. + + + + +IGNEUM 2.0 / 08 OCT 2026 17 / 37 +MASTER 035 / 292 + STRATEGY / 2.0 + + + +16 / COMBINED WORKLOAD + + +Mining and proving, together. +Do not combine isolated benchmark wins into a final configuration that has never been tested. + +The earlier review recorded the following team results for a fixed 4,717,439-cycle shard on a patched SP1 +implementation. These are historical discussion figures, not independently reproduced measurements for +this edition. + + C ONSUMER HARDWARE P ROVING ALONE A LONGSIDE MINING + + + RTX 3060 / 12 GB 14.4 s 37.5 s + + + Not reported for full compressed-proof + RTX 4060 / 8 GB 18.4 s + coexistence + + + RTX 4070 / 12 GB 12.1 s 27.3 s + + +The earlier coexistence configuration had a reported miner resident set around 1.4 GB. A 5.5 GiB mining +dataset changes the memory budget. Re-test the final dataset, register allocation, clocks and prover +together. Time-sharing or eviction may work, but their delay and opportunity cost belong in the result. + +Let operators maximise their own returns +Allow mining, internal proving, external proving and switching off. Test external-demand spikes, token- +price declines, a large operator disappearing and specialisation entering either market. The protocol +should not rely on the official scheduler choosing a less-profitable task. + +Pay for internal capacity +Clarify the recurring compensation for internal proof generation as issuance falls. Resolve any discrepancy +between the published fee table and prose before modelling security income. Burning a fee is not an +operator payment; external jobs do not automatically finance internal chain work. + + + ASSIGNMENT FAIRNESS + + Calibrate exclusive proving windows against real completion distributions. The earlier + provisional 10-DAA-second window must be tested against actual consumer-card latency, + failures and wasted work, not merely fair assignment counts. + + + +C3: historical proving results and assignment review. C1: new dataset plan. C2: joint incentive and fee tests. + + + + +IGNEUM 2.0 / 08 OCT 2026 18 / 37 +MASTER 036 / 292 + STRATEGY / 2.0 + + + +17 / CONSENSUS AND FAILURE BEHAVIOUR + + +Preserve the meaning of final. +Safety and liveness need explicit assumptions, authenticated authority and deterministic +recovery rules. + +The earlier review distinguished a corrected two-thirds total-weight rule from a later authority-set +problem. It recorded a frozen-table simulation in which conflicting locks appeared around expiry during a +prolonged partition. This is a version-specific source finding, not a fresh assertion about the deployed +node. + + F AILURE SCENARIO A CCEPTANCE EVIDENCE + + + No conflicting final histories within the stated fault assumptions. Any + Prolonged partition + loss of liveness is explicit. + + + Verifiable continuity from the last certified history. A timeout alone is + Authority-set transition + not evidence that missing voters no longer exist. + + + Defined checkpoint, weight and recovery behaviour without + Signing stops, mining continues + contradictory certificates. + + + Old voting keys compromised A distinct analysis from newly arriving hashrate. + + + Finality unavailable at a seed A documented seed and mining path that does not accidentally depend + boundary on an unavailable certificate. + + + Deterministic recovery. No quiet reversal of a guarantee previously + Partitions reconnect + labelled irreversible. + + +Test the real integration +The implementation and network tests must exercise ordering, finality, proof queues, voter tables and seed +transitions together. Passing simplified simulations is useful but does not replace testing the actual fork- +choice and recovery rules. + + + USER-FACING RULE + + Included, executed, proven and finalised are distinct states. A safe pause must be visible as a + pause, not presented as an unchanged guarantee. + + + +C3: finality, authority-table and seed-pipeline review. C2: independent failure-testing programme. + + + + +IGNEUM 2.0 / 08 OCT 2026 19 / 37 +MASTER 037 / 292 + STRATEGY / 2.0 + + + +18 / USER VERIFICATION + + +Verify what the label promises. +Light clients, receipts and cross-chain demos are valuable only within their actual verification +boundaries. + + S URFACE F INISH THE GUARANTEE + + + Authenticate the starting point, voter weights and subsequent authority + Light wallet changes. Signatures from supplied keys are not proof those keys were entitled + to certify the history. + + + Verify the permitted proof and authenticate its inputs. Do not substitute a + Execution proof + trusted aggregator statement for a stronger claim. + + + Prove a successful transfer with the asset, recipient and amount. Transaction + Payment receipt + inclusion alone does not establish successful execution. + + + Verify authority changes and the required execution statement. Remove or + Cross-chain oracle + disclose deployer-installed trust anchors and unchecked signatures. + + + Explain how the necessary state can be obtained and reconstructed. Valid + Data availability + execution does not by itself make the data available. + + +Preserve useful demos, narrow the labels +The earlier review treated browser verification, receipts and the Sepolia oracle as meaningful integration +work with unfinished trust assumptions. Keep those demonstrations, but name the actual verified property. +"Transaction-inclusion receipt" is more accurate than "successful payment proof" where execution status +is still node-reported. + + + BOUNDARY 01 BOUNDARY 02 + + EVM is not Ethereum security. ZK does not imply privacy. + An Ethereum-compatible application on Igneum Public transaction and state data remain public + depends on Igneum's security and availability unless a separate privacy design changes that. + model. + + +These surfaces are not prerequisites for proving mining competitiveness. They become trust products only +when their verification paths match their claims. + +S1: positioning boundaries. C3: light-wallet, receipt, oracle and availability review. + + + + +IGNEUM 2.0 / 08 OCT 2026 20 / 37 +MASTER 038 / 292 + STRATEGY / 2.0 + + + +19 / OPERATIONAL INDEPENDENCE + + +Operate without founder rescue. +A permissionless specification needs an operational counterpart. + +Distribution is not consensus authority +The earlier review noted development-network activation and state changes distributed through a signed +update manifest. Mainnet readiness requires separation between software delivery, operator acceptance +and consensus activation. A fleet that automatically accepts a release key can remain operationally +centralised. + + C ONTROL OR DEPENDENCY R EQUIRED OUTCOME + + + Reproducible builds, pinned source and binaries, explicit operator + Software release + acceptance and a signing-key incident procedure. + + + Independent discovery, node operation, proof inputs and payment paths + Public infrastructure + continue without the founder's services. + + + Replacement operators can take over without unpublished files, + Mining / proving / aggregation + privileged coordination or hidden configuration. + + + Secrets are isolated from untrusted workloads. Recovery and updates do + Wallet and worker execution + not quietly change signing authority. + + + Network identity and rules One authoritative release manifest states exactly what a node enforces. + + +Publish a machine-readable release manifest +Include network identity, source commits, mining class, dataset parameters, finality rule, program/verifier +identities, activation state and fee schedule. Generate current-status pages from it and label historical +records clearly. The earlier chain-ID and threshold discrepancies illustrate why this matters. + + + THE NO-FOUNDER EXERCISE + + Remove founder mining, proving, aggregation and public infrastructure from a test network. + Cross boundaries and inject failures. Show what continues to work, what pauses and how + independent participants recover. + + + +C3: release-manifest and update-control review. C2: no-founder network exercise. + + + + +IGNEUM 2.0 / 08 OCT 2026 21 / 37 +MASTER 039 / 292 + STRATEGY / 2.0 + + + +20 / REFERENCE LANDSCAPE + + +Learn from the mechanism. +Historical and future-hardware context retained from the research discussion. No new market +ranking is asserted here. + + R EFERENCE POINT L ESSON CARRIED INTO 2.0 + + + Specialised hardware existing and GPUs remaining viable are not mutually + Ethash + exclusive. Coexistence is the relevant target. + + + Bind work to useful general-purpose resources. Treat frequent emergency + RandomX + tweaks as a weaker foundation than a sound baseline. + + + The goal of keeping GPUs competitive without repeated algorithm forks + KAWPOW / Ravencoin + already has a serious precedent. + + + Benchmark an operating GPU-oriented system, including pooling, emissions + Ergo + and difficulty behaviour, not just a whitepaper. + + + Open, competitive reference mining software is part of accessibility. Treat + Firo + reported performance as source-reported. + + + + F UTURE OPPONENT TO ALLOW W HY IT CHANGES THE TEST + + + Programmable compute without Supports the whole family bank while removing unrelated + graphics graphics functions. + + + Reuses design work and changes components without funding an + Chiplets and modular revisions + entirely new project. + + + Survives known dataset growth without automatically replacing + Denser or excess memory + the compute core. + + + Chooses the cheapest balance of memory, movement, + Data-local and hybrid systems + recomputation and companion processors. + + + Specialises proving separately from the mining lottery. Useful + Proof accelerators + proving is not permanently GPU-exclusive. + + +These are stress-test opponents, not predictions of shipment dates or evidence that an Igneum chip exists. Credit future improvement +to commodity hardware and specialised hardware consistently. + + +S1: Ravencoin, Ergo and Firo context. C2: historical research and future-hardware stress cases. R1-R14. + + + + +IGNEUM 2.0 / 08 OCT 2026 22 / 37 +MASTER 040 / 292 + STRATEGY / 2.0 + + + +21 / DELIVERY PROGRAMME + + +The hardware delivery gates. +Proposed work packages. Owners, dates, budgets and numerical acceptance tolerances still +require approval. + + +G1 / FROZEN BASELINE + +Reproduce the real system. +Publish the exact v6 generator, verifier, dataset policy, compiler configuration and measurement harness. +Close the pending register, memory-clock, placed-core and 8 GB-card measurements. Test final mining +and proving together. + +Pass: independent operators reproduce the baseline within declared tolerances. Report wall power, device +telemetry, accepted/rejected work, compilation, memory and sustained thermal behaviour. +Lead role: GPU engineering. Evidence review: independent operators. + + + + +G2 / TWO ARCHITECTURAL EXPERIMENTS + +Test resource coupling and memory alternatives. +Reorganise existing work to increase unavoidable live-state and execution costs. Attack the candidate and +v6 with sharing, recomputation and data-local execution. Keep mixed-resource FP32 work separate and +optional. + +Pass: the candidate improves against re-optimised adversaries across the reference GPU population, +within a pre-agreed honest-card and verifier cost budget. +Lead roles: GPU engineering and cryptography. Reviewer: independent hardware team. + + + + +G3 / PROGRAMMABLE ADVERSARY + +Let the opponent survive. +Build a realistic multi-family, multi-epoch design with physical memory and complete-board costs. Permit +firmware updates, emulation, overprovisioning and hybrid devices. Separate process-node advantage from +architectural advantage. + +Pass: the strongest supported whole-system advantage remains inside the approved competitiveness +envelope. Publish uncertainty, unsuccessful designs and any shortcuts found. +Lead role: independent hardware reviewer. Decision: protocol and GPU leads. + + + +C2: five-deliverable research programme. Role labels are planning placeholders, not staff assignments. + + + + +IGNEUM 2.0 / 08 OCT 2026 23 / 37 +MASTER 041 / 292 + STRATEGY / 2.0 + + + +22 / DELIVERY PROGRAMME + + +The durability delivery gates. +Commercial validation runs alongside the network programme. None of these gates is marked +complete in this edition. + + +G4 / FIVE-YEAR COEXISTENCE MODEL + +Model the network after specialisation arrives. +Use measured and modelled hardware results rather than an assumed expiry date. Include rising and +falling revenue, lower issuance, different power costs, already-funded development, GPU resale/ +replacement and changes in proving demand. + +Pass: identify credible conditions for sustained accessible participation and state the failure regions. A +result that requires a small network, token appreciation or guaranteed chip death has not met the +objective. +Lead role: economic modelling. Inputs: independent hardware and operator data. + + + + +G5 / NO-RESCUE NETWORK EXERCISE + +Operate without founder intervention. +Use independent builds and operators. Remove founder infrastructure, cross program and family +boundaries, interrupt signing, partition the network, withdraw major providers and submit hostile proof +records. + +Pass: ordinary validators reject invalid work and the network exhibits documented safety, availability and +recovery behaviour without an emergency anti-chip rule or privileged intervention. +Lead roles: protocol engineering and independent security review. + + + + COMMERCIAL TRACK / IN PARALLEL + + Secure one genuine paid proof pilot. Progress to repeat purchases without reimbursing the + customer. Document the workload, service guarantee, total cost and customer's reason for + choosing Igneum. + + +Before mainnet, the intended release also needs complete proof enforcement, a resolved finality/recovery +model, operator-control tests, a compatible application test suite and an adequately funded maintenance +plan. A compressed exercise cannot substitute for years of operational evidence. + +C2: coexistence and no-rescue deliverables. S1/C3: commercial and mainnet-readiness conditions. + + + + +IGNEUM 2.0 / 08 OCT 2026 24 / 37 +MASTER 042 / 292 + STRATEGY / 2.0 + + + +23 / ACCEPTANCE SCORECARD + + +Evidence for every gate. +This is an acceptance checklist, not a completion dashboard. + + G ATE E VIDENCE REQUIRED D O NOT SUBSTITUTE + + + Pinned code and independently reproduced system- A favourable isolated + Hardware baseline + power results. benchmark. + + Best realistic multi-epoch adversary, complete cost One reference ASIC or a + Specialist competition + boundaries and uncertainty. synthesis artefact. + + Current owners and new entrants across the + Commodity access The newest flagship alone. + reference cohort. + + Unmodified validators reject invalid, replayed and Official producers behaving + Proof enforcement + misbound proofs. correctly. + + Declared workload, bounded backlog and tail- Fast shards with unbounded + Sustained proving + latency distribution. queues. + + Consistent authority changes and documented + Finality and recovery A timeout labelled irreversible. + partition behaviour. + + Authenticated roots, execution outcomes and trust Signatures over + User verification + anchors. unauthenticated authority. + + Pooled payments without hidden transfer of + Operator control A pool protocol name. + governance/finality control. + + Independent operation No-founder exercise on the real implementation. A centrally supported demo. + + Repeat paid external jobs and workable operator Devnet payouts or subsidised + Commercial demand + margins. volume. + + Internal proving/security payments and maintenance Burn accounting or assumed + Long-term funding + runway. appreciation. + + Comparative results, adoption, retention and A roadmap or unsupported + Leadership + reliability over time. rank. + + + + RELEASE EVIDENCE PACKET + + A source commit, exact parameters, test procedure, raw result, independent-reproduction + status, review scope and unresolved limitations should accompany every material claim. + + + +S1/S2: leadership outcomes. C2/C3: consolidated technical, economic and commercial acceptance tests. + + + + +IGNEUM 2.0 / 08 OCT 2026 25 / 37 +MASTER 043 / 292 + STRATEGY / 2.0 + + + +24 / RISK AND OWNERSHIP + + +Keep the hard risks in view. +Suggested lead roles. This document does not appoint individuals or invent delivery dates. + + R ISK P RIORITY RESPONSE L EAD ROLE + + + Residual specialist cost Run physical, programmable multi-epoch GPU + independent + advantage evaluation. Do not promise chip expiry. hardware + + Set GPU-cost and memory-accessibility limits + Defence harms honest cards GPU + product + before experiments. + + Make valid proof verification mandatory in ordinary + False proving reward Protocol + proving + validators. + + Resolve authority transitions and long-partition + Conflicting final histories Consensus + security + recovery. + + Preserve miner keys and transaction control Protocol + pool + Concentrated authority + through pooling. integration + + Provider withdrawal stalls Reassignment, usable inputs, replacement + Proving + operations + chain aggregation and failure tests. + + Model lower issuance and explicit recurring + Reward economics decay Economics + protocol + capacity payments. + + One paid workload, repeat customers, costs and + No external demand Commercial + proving + service guarantees. + + Explicit updates, reproducible builds and an + Release-key dependence Release engineering + incident/recovery process. + + Single release manifest and source-versioned + Status and claim drift Release + documentation + evidence pages. + + +Spend in the right order +Complete consensus proof enforcement and resolve finality boundaries while closing the v6 evidence +packet. Run hardware research and a narrow customer pilot in parallel. Delay broad ecosystem expansion +until the core path is secure, reproducible and useful. + +Publish a maintenance plan covering engineering, audits, infrastructure and incident response. Distinguish +committed funding from income that depends on future adoption. Preserve the fair-launch principle +without treating it as a funding strategy. + +C2/C3: prioritisation and risk themes. S1: adoption and proof-enforcement conditions. Owner roles are editorial planning labels. + + + + +IGNEUM 2.0 / 08 OCT 2026 26 / 37 +MASTER 044 / 292 + STRATEGY / 2.0 + + + +25 / LEADERSHIP AND PUBLIC CLAIMS + + +Leadership through outcomes. +Verified engineering earns consideration. Competitive economics and real demand earn +adoption. Sustained operation earns leadership. + +The commercial and adoption tests +Track whether miners remain active through weak market conditions, whether customers repurchase +without subsidies and whether independent developers can deploy useful applications. Reliability, +operator margin, liquidity and support all affect the outcome. None can be guaranteed by an algorithm. + + P UBLIC WORDING W HAT MUST SUPPORT IT + + + Designed for GPU competitiveness A clear objective and design rationale. Not a measured guarantee. + + + Team-tested Published procedure, version and team result. + + + An unaffiliated operator reproduces the stated result and + Independently reproduced + boundaries. + + + Independently reviewed A scoped review of the relevant release and its unresolved findings. + + + Comparative engineering evidence plus a credible operating and + Top-tier contender + customer proposition. + + + Sustained adoption, demand, reliability and retention. No + Category leader + unsupported numerical ranking. + + + + THE CLAIM TO EARN + + Igneum remains competitive on accessible commodity GPUs even when specialised mining + hardware is assumed to exist, remain compatible and seek profit. Its security does not rely on + identifying that hardware or retiring it through emergency changes. + + +Claims to leave out +Do not publish guaranteed chip death, a universal ASIC-efficiency ceiling, precise chip-arrival probabilities +without a calibrated model, guaranteed profits, Ethereum security by compatibility or automatic +transaction privacy from using ZK technology. + +The strongest proposition combines competitive commodity mining, application execution, verifiable +proving, an accessible operator application and meaningful miner control. Execute the evidence gates first. +Let the ranking follow the results. + +S1: leadership assessment and architecture boundaries. S2: adoption risks. C2: final competitiveness claim. + + + + +IGNEUM 2.0 / 08 OCT 2026 27 / 37 +MASTER 045 / 292 + STRATEGY / 2.0 + + + +26 / COMPLETENESS MAP + + +Everything has a home. +The operational plan is consolidated here. The supplied document is preserved in full in the +appendix. + + S OURCE THEME W HERE IT APPEARS + + + Four leadership requirements and screenshot + The objective (p. 3); leadership and claims (p. 27). + context + + Complete supplied leadership assessment Strategic position (p. 4); full source appendix A (p. 31). + + Application architecture (p. 15); full source appendix B (p. + Complete supplied EVM / zkVM strategy + 34). + + + Latest team chip figures and outstanding work Hardware snapshot (p. 6); decision register (p. 7). + + Architectural experiment (p. 9) through independent + GPU-first architecture, dataset and rotation + hardware brief (p. 12). + + Past, present and future threat model Reference landscape (p. 22); reference register (p. 29). + + Economic survival, ASIC coexistence and proof Coexistence economics (p. 13); useful work (p. 17); + demand combined workload (p. 18). + + Miner experience, pools and retained authority Ember and operator control (p. 14). + + Evidence baseline (p. 5); proof enforcement (p. 16) + Proof-of-concept limits and security gaps + through operational independence (p. 21). + + Delivery programme (p. 23) through risk and ownership (p. + Delivery, acceptance and risk + 26). + + + +Editorial boundaries +The first part converts the discussion into a usable plan without marking proposed work as completed. The +appendix retains the supplied document's organisation, argument, qualifications and level of detail. +Typography, punctuation and table structure are normalised for readability. The source title's spelling is +recorded rather than silently treated as the official brand spelling. + +No delivery dates, staff assignments, budgets or new performance claims have been invented. Historical +source statements have not been silently updated to a later status. + +S1/S2 and C1-C3: source coverage and editorial method. + + + + +IGNEUM 2.0 / 08 OCT 2026 28 / 37 +MASTER 046 / 292 + STRATEGY / 2.0 + + + +27 / PROVENANCE + + +Source register. +This is a designed compilation, not a new research or verification pass. + +S1 and S2 are the materials supplied with this request. C1-C3 are the preceding conversation. B1 is the +original brand kit recovered from the file library. References R1-R18 are reading links carried forward from +the discussion; they have not been independently rechecked for this formatting edition. + +S1 IGNEUM 2.0.rtf + Supplied document. Complete substantive text retained in appendices A and B. + +S2 Screenshot 2026-10-08 at 16.30.15.png + Supplied four-outcome table and leadership context. Re-typeset on the mission page. + +C1 Team chip-status updates in this conversation + Reported hardware figures, chosen class-v6 changes, four-layer rotation, rejected levers and pending measurements. + +C2 GPU competitiveness research discussion + Consolidated research recommendations, economic stress cases, future opponents and five delivery gates. + +C3 Earlier litepaper and proof-of-concept review + Historical reported proving results and version-specific security, finality, wallet and operations findings. + +B1 Igneum brand kit, 7 October 2026 + Original mark and lockups; Unbounded, IBM Plex Sans and IBM Plex Mono; obsidian, ember, graphite, bone and + molten palette. + +R1 Igneum litepaper, ledger, evidence and economics + Project references carried forward from the supplied material and discussion. + +R2 Ethereum: Ethash + Historical GPU/ASIC coexistence context. + +R3 Monero: a note on scheduled protocol upgrades + Earlier anti-ASIC changes and the transition to RandomX. + +R4 Ravencoin, Ergo and Firo reference landscape + Comparative project descriptions in the supplied source. See also Ergo Autolykos and Firo miner-release material in + the discussion. + +R5 RandomX design and design v2 + Device binding, program selection and tightly connected resource use. + +R6 ProgPoW design and independent audit + Resource matching, state movement and alternative implementations. + +The source text includes date-sensitive descriptions of project status and competitors. Those are retained as source statements. Their +presence in a polished document does not convert them into independently verified findings. + + +Source register. Reading links are retained for traceability, not represented as a fresh source audit. + + + + +IGNEUM 2.0 / 08 OCT 2026 29 / 37 +MASTER 047 / 292 + STRATEGY / 2.0 + + + +28 / READING LINKS + + +Research references. +Use the linked primary material when reproducing experiments, reviewing claims or updating +the plan. + +R7 HashCore + Processor-resource-matching research direction. + +R8 NVIDIA CUDA best practices + Registers, occupancy, memory behaviour and reproducible numerical execution. + +R9 Memory-hardness research discussed earlier + Distinguishes memory-capacity cost from bandwidth/energy properties. + +R10 EIP-1057 and related evaluation discussion + Proof-of-work structure and questions about reusable expensive work. + +R11 Vortex GPU architecture + Programmable compute as a future-adversary category. + +R12 UCIe specifications + Modular interconnect and packaging as future-adversary context. + +R13 Samsung 24 Gb GDDR7 announcement + Memory-density evolution; not a claim that arbitrary boards are upgradeable. + +R14 PipeZK + Proof-specific accelerator research, not a measured Igneum advantage. + +R15 SP1 documentation and RSP + General-purpose zkVM execution and EVM proving composition. + +R16 Ethereum: ZK-rollups and zkEVM programme + Execution proofs, settlement, availability and privacy boundaries. + +R17 Stratum V2 and Monero P2Pool + Job declaration, payout variance and retained operator control. + +R18 Ethereum receipt and account-proof interfaces + Inclusion, execution status and state-root authentication are distinct properties. + + + + UPDATING THIS DOCUMENT + + Update the evidence against a pinned release before changing a status label. Preserve + superseded results as historical records and distinguish new research from the supplied source. + + + +Carried-forward research references. Full supplied document begins on the following pages. + + + + +IGNEUM 2.0 / 08 OCT 2026 30 / 37 +MASTER 048 / 292 + STRATEGY / 2.0 + + + +APPENDIX A / SUPPLIED DOCUMENT + + + +Leadership assessment. +Complete source text. The original source title is INGEUM 2.0. + +Retained from IGNEUM 2.0.rtf. Formatting and punctuation normalised. Source statements are not newly +verified. + + + + +Yes - if the programme delivers the independently verified results we defined, my judgement is that Igneum +would belong in the top tier of GPU-first mining projects, with a credible case for technical leadership. +That is different from automatically becoming the largest, most profitable or most trusted GPU network. You +can engineer a leading system; adoption and sustained demand still have to follow. +The distinction is between shipping the proposed changes and demonstrating that they achieve the +objective. The latter is what would earn that position. + + +Where successful execution would put you + + A REA M Y ASSESSMENT OF THE PROPOSED END-STATE + + + A potential leadership position, provided independent hardware + Keeping ordinary GPUs competitive analysis confirms the result against programmable, multi-epoch + competitors. + + + A major strength if you publish reproducible measurements, realistic + Quality of the resistance evidence adversarial designs and economics that do not assume chips + automatically expire. + + + Potentially top-tier: straightforward installation, effective tuning, + Miner experience + transparent earnings, reliable payouts and retained control. + + + A compelling proposition if the same accessible hardware can earn + Usefulness of the hardware + from genuinely purchased proving work as well as securing the chain. + + + A credible contender after independent review and failure testing - not + Security and decentralisation + something a feature list establishes. + + + Miner profitability and market Still dependent on demand, competition, liquidity and operating costs. + leadership These cannot be guaranteed by protocol design. + + +The strongest potential advantage is the complete package - not one supposedly unbeatable hash. + + +You would be competing with serious projects +The space is not empty, and I would not claim Igneum had surpassed these projects merely because its +design is newer. +Ravencoin already expresses a closely related objective. Its KAWPOW approach is intended to keep +consumer GPUs competitive, explicitly allows for future ASIC development, and does not envisage further +algorithm forks as the normal defence. Igneum would need to demonstrate a stronger result or a more +valuable overall offering - not just restate that goal. + + +IGNEUM 2.0 / 08 OCT 2026 31 / 37 +MASTER 049 / 292 + STRATEGY / 2.0 + + + +Ergo already has a GPU-oriented, memory-hard mining design, with implemented changes to pooling, +emissions and difficulty adjustment. That gives you an operating system to benchmark against, rather than +merely a competing whitepaper. +Firo is actively improving commodity mining accessibility. Its September 2026 reference-miner release +supports NVIDIA and AMD, charges no developer fee, and reports performance within roughly 1% of +popular closed-source alternatives. That performance figure is Firo’s own report, but it illustrates the +practical standard Ember would need to meet. +Those are useful reference points, not an exhaustive league table. They also show why “GPU-friendly” is the +entry requirement, not sufficient differentiation. + + +What could make Igneum stand out +Your proposed combination is more interesting: +Competitive commodity mining + application execution + verifiable proving + an accessible operator +application + meaningful miner control. +The litepaper already frames mining, proving and Ethereum-compatible execution as separate but +connected parts of the system. The opportunity is to make that combination work reliably and economically +- not simply to have more features than another chain. +For a miner, the strongest proposition would be: + + “My hardware remains useful and competitive, I can earn from more than the mining subsidy, and + I do not have to surrender control to participate.” + +For a customer buying proofs: + + “I receive a correct result at a competitive price and reliable delivery time, without needing to care + which independent operator produced it.” + +Deliver both, and Igneum would have a strong reason to exist beyond attracting miners from another coin. +However, the proving-income distinction matters enormously. The current economics page describes +internal proving payouts on a valueless devnet and says the external proving market is not yet built. Internal +reward distribution demonstrates the mechanism; repeat purchases by outside customers would +demonstrate demand. + + +What separates “top-tier technology” from “the leading +network”? +I would look for three outcomes. +Miners stay through difficult conditions. Not because the launch is temporarily lucrative, but because +hardware compatibility, operating costs, payouts and control remain attractive. +Customers repeatedly pay for the output. Not subsidised pilots or partnership announcements: useful work +purchased at prices that support reliable service and operator margins. +The network works without the founding team holding it together. Independent operators build the +software, enforce the rules, survive failures and continue operating without emergency intervention. +Those would be my tests for leadership. A small specialist-hardware advantage alone would not establish +any of them. + + + + +IGNEUM 2.0 / 08 OCT 2026 32 / 37 +MASTER 050 / 292 + STRATEGY / 2.0 + + + + +My direct answer +The ceiling is category leadership. Successful, independently validated execution would put Igneum in +serious contention for the top of the GPU-mining space on engineering and operator proposition. +But I would not give it an unsupported “number one” ranking before comparative results and real-world +adoption exist. +The progression I would expect is: +Demonstrated technical advantage → credible top-tier project → repeat customer demand and miner +retention → potential category leader. +You have a plausible route to the top. The decisive move is now to prove that ordinary operators can +succeed on the system - not to make the design sound more ambitious. + + + + +IGNEUM 2.0 / 08 OCT 2026 33 / 37 +MASTER 051 / 292 + STRATEGY / 2.0 + + + +APPENDIX B / SUPPLIED DOCUMENT + + + +EVM and proving architecture. +Complete second section of the supplied document, in its original order. + +Retained from IGNEUM 2.0.rtf. Proposed architecture and source-snapshot qualifications are preserved. + + + + +Yes - EVM-compatible applications with ZK-proven execution are the right default for Igneum. But I would +position and build it as a GPU-secured L1 with a flexible proving layer, not simply “another zkEVM chain.” +The architecture I would choose is: + + EVM for developers. A general-purpose zkVM for proving. Igneum’s own consensus for security. + External customers for additional proving demand. + +Those choices fit together, but they are not the same decision. + +1. Separate the three architectural choices + + M Y RECOMMENDATION FOR + D ECISION W HY + I GNEUM + + + Let builders use familiar contracts, + What developers build + EVM-compatible execution languages and tools rather than requiring + against + them to learn a new application platform. + + + Prove the EVM implementation without + An established general-purpose + developing an entirely new proof system + How execution is proved zkVM, initially your SP1-based + yourselves. Preserve a carefully versioned + implementation + replacement path. + + + This preserves your actual objective: an + Where the network Your sovereign GPU-mined L1, independent network secured by + obtains consensus and subject to the security gates we accessible hardware, rather than a proving + finality discussed service attached to someone else’s + settlement system. + + +Your litepaper already points broadly in this direction: it identifies revm for EVM execution and SP1 behind a +versioned proving interface. I would refine that architecture rather than restart it. +A zkVM and a zkEVM are not competing choices here. SP1 proves programs compiled for RISC-V; one such +program can implement EVM execution. Succinct’s RSP project demonstrates this composition using Reth +and SP1, although that repository explicitly warns that it is not audited or production-ready. + +2. Why EVM is a sensible application layer +I would not make attracting developers harder while you are already solving difficult mining, consensus and +proving problems. +EVM compatibility lets developers reuse familiar languages and infrastructure. Ethereum’s documentation +identifies precisely that benefit: applications can use established tooling while gaining proof-based +verification. + + + +IGNEUM 2.0 / 08 OCT 2026 34 / 37 +MASTER 052 / 292 + STRATEGY / 2.0 + + + +For Igneum, my preferred developer experience would be: + + “Deploy familiar contracts, understand a small, clearly documented set of differences, and obtain + verifiable execution.” + +That is a stronger starting point than asking developers to adopt a new language, wallet model, execution +environment and security model simultaneously. +However, compatibility needs to be demonstrated, not described as “everything runs unchanged.” Your +ledger already acknowledges differences in block context, randomness and two-dimensional fees. Those can +matter to application behaviour even where the bytecode executes successfully. +I would therefore make compatibility testing a product deliverable: representative contracts, wallet fee +estimation, indexing, failed transactions, receipts and application-specific assumptions. + +3. ZK-proven execution is also aligned with where the technology +is going +This is not a case of choosing an architecture whose only purpose is Ethereum rollups. +The Ethereum Foundation’s current zkEVM programme is working towards proof-based verification of +Ethereum’s own L1 execution, beginning with optional execution proofs and aiming later for mandatory +proofs. Its approach explicitly involves general-purpose zkVMs. +That supports your architectural direction: +Keep a familiar application environment, while changing how execution is verified. +It does not establish that Igneum’s implementation is secure or that customers will choose it. It does mean +you can build on a substantial shared engineering direction rather than invent every component. +My recommendation is to benefit from that work while concentrating your own effort on what is distinctive: +accessible operators, distributed proving, reliable payments and the GPU-mined base layer. + +4. I would not turn Igneum into an Ethereum L2 by default +Using EVM execution and ZK proofs does not require moving Igneum “onto Ethereum.” +A conventional Ethereum ZK-rollup uses Ethereum to enforce state updates and make the necessary state- +reconstruction data available. That is a different security and settlement arrangement from operating a +sovereign L1. +An L2 could be the better choice for a project whose primary objective was Ethereum settlement and an +Ethereum-facing application. But it would not automatically be a better implementation of your objective: an +independent, durable home for GPU operators. +There is a real cost to choosing sovereignty: you must establish your own consensus security, data +availability and credible cross-chain verification. Adding execution proofs does not make those +responsibilities disappear. +My preferred commercial relationship is: + + Serve Ethereum and other networks without requiring Igneum to become subordinate to one of + them. + +Customers should be able to purchase supported proofs for their existing systems. Requiring every customer +to migrate its application to Igneum would unnecessarily narrow the business. + + + + +IGNEUM 2.0 / 08 OCT 2026 35 / 37 +MASTER 053 / 292 + STRATEGY / 2.0 + + + + +5. The proving business should be broader than your own zkEVM +This is the most important strategic refinement. +Make EVM the main application interface, but do not make EVM execution the only useful work your proving +infrastructure can eventually support. +A general-purpose zkVM gives you a potential route to additional verifiable workloads. It does not make +every proof format interchangeable: each supported service still needs its own validated program, inputs, +verification rules, performance measurements and delivery requirements. SP1’s general-purpose execution +model supports that broader direction. +I would start narrowly: +First: reliably prove Igneum’s own execution. +Next: support one external customer’s exact workload, with repeat paid jobs. +Then: add further workloads where the existing operator fleet has a demonstrated advantage. +Your economics page still describes the external proving market as unbuilt. That is an opportunity to shape +correctly - not established demand that should already be included in revenue assumptions. +Igneum should not need to win a contest for the largest application ecosystem before its operators can sell +useful computation. + +6. The conditions that make this the right choice +I would keep this architecture only while enforcing four requirements. + +Proofs must become a protocol guarantee +Your ledger currently states that proof verification occurs outside the consensus path in proving v0; a +modified producer can include a matching statement without the valid proof and cause an undeserved +payout. +Closing that gap is essential. Otherwise, the network is demonstrating proving activity rather than enforcing a +permissionless proving economy. + +The hardware requirements must match the miner promise +The litepaper currently distinguishes NVIDIA proving from AMD and Apple mining support. That is an +important limitation to preserve in the product language. +I would judge the proving stack on the complete pipeline: inputs, proving, aggregation, verification, payment, +memory footprint and mining income forgone. +A fast shard result is not sufficient when aggregation or memory pressure makes ordinary operators +uncompetitive. + +Proof-system flexibility must not become arbitrary acceptance +Keep the implementation replaceable, but pin the permitted program identities, verifier versions and security +parameters in the protocol. +My recommendation is one well-tested backend first, a clean replacement interface, and independent +implementations where justified later - not several immature backends accepted interchangeably. +The Ethereum Foundation’s security work emphasises that proving speed is insufficient without soundness +analysis and appropriate security margins. That is directly relevant to deciding which optimisations and +versions Igneum can safely adopt. + +Proving must not become the authority to control the chain +I would preserve your separation between winning the mining lottery and producing proofs. + + +IGNEUM 2.0 / 08 OCT 2026 36 / 37 +MASTER 054 / 292 + STRATEGY / 2.0 + + + +But also test whether a concentrated proving provider could stall useful operation by withholding service. +The design needs replacement operators, usable inputs, reassignment and explicit behaviour during proof +delays. +Separate responsibilities on paper are not enough; they must remain separable during a failure. + +7. What “zkEVM” should - and should not - mean in your +positioning +I would not lead with: +“We are another zkEVM.” +I would lead with: + + “A GPU-secured network for Ethereum-compatible applications and verifiable computation.” + +Then explain the proof architecture underneath it. +Also keep three boundaries explicit: +Proven execution is not automatically finality. +EVM compatibility is not Ethereum security. +ZK technology does not automatically make transactions private. Ethereum’s rollup documentation explicitly +notes that published state-reconstruction data is public; privacy requires additional application or protocol +design. +And none of these choices, by itself, solves specialised-hardware competition. Your mining-resistance +programme remains a separate obligation. + +My judgement +Yes: stay with EVM-compatible, ZK-provable execution. I would not switch to a new application VM, develop +a bespoke proof system, or convert Igneum into an Ethereum rollup just to follow a category label. +The strongest architecture for your stated purpose is: + + A sovereign GPU-mined L1, familiar EVM applications, an established and versioned zkVM proving + engine, and a proving service capable of serving customers beyond Igneum. + +EVM is the right front door. Verifiable computation is the broader opportunity. Keeping ordinary operators +competitive is the differentiator you still have to prove. + + +END OF SUPPLIED SOURCE + +The original document is preserved in full across appendices A and B. + + + + +IGNEUM 2.0 / 08 OCT 2026 37 / 37 +MASTER 055 / 292 + 08 OCTOBER 2026 + + ASSURANCE EDITION / 1.0 + + + + +THE 2.0 VALIDATION PROGRAMME + + + + +2.0 +Test & acceptance +standard. +The evidence required to become a credible +contender for GPU-network leadership. + + + + +128 16 G1-G5 +TEST CASES TEST SUITES DELIVERY GATES + + + + + STATUS / PROPOSED. NOT EXECUTED. + + + Independent hardware, security, economic, customer and comparative evidence. No guaranteed + rank. No assumed chip death. No emergency anti-chip rescue in the baseline case. + + + + +IGNEUM + MASTER 2.0 + 056 // PROPOSED + 292 / NOT EXECUTED 1 / 73 + TEST STANDARD / 1.0 + + + + +DOCUMENT MAP + + + +The complete test programme. +A navigable specification for engineering teams, independent reviewers and the release decision. +READ FIRST THE TEST CATALOGUE + + +Assurance contract 3 GOV / Release identity and evidence 18 + +Execution rules 4 GPU / Whole-system GPU measurements 21 + +Source traceability 5 POW / Proof-of-work correctness and coupling 24 + +Gate dependencies 6 ADV / Programmable specialist adversaries 27 + +Approval register 7 ROT / Epochs, seeds and memory transitions 30 + +Shared fixtures 8 ECO / Five-year coexistence economics 33 + +Hardware thresholds 9 EVM / Execution and developer compatibility 36 + +Correctness and support 10 ZKP / Consensus-enforced proof validity 39 + +Capacity and independence 11 CAP / Sustained proving and delivery 42 + +Security and Ember 12 INC / Rewards, incentives and selfish operators 45 + +Economics and funding 13 FIN / Consensus safety and recovery 48 + +Commercial and field evidence 14 VER / Wallets, receipts and data availability 51 + +Execution sequence 15 OPS / Independent operation and release security 54 + +Measurement controls 16 UX / Ember, payouts and operator control 57 + +Suite ownership map 17 COM / Paid demand and sustainable delivery 60 +APPENDICES + LEAD / Comparative leadership evidence 63 + +Evidence record template 66 + +Defects and retesting 67 + +Gate sign-off sheet 68 + +Sources and public wording 69 + +Full test index 70 + + + + +Read the numbers as proposals. P00-P16 require approval. Source-page references preserve the original 2.0 plan. Case and +index links open the exact procedure. + + + + +IGNEUM + MASTER 2.0 + 057 // PROPOSED + 292 / NOT EXECUTED 2 / 73 + TEST STANDARD / 1.0 + + + + +01 / ASSURANCE CONTRACT + + + +What a full pass earns. +The objective is a defensible leadership-contender case. A green checklist is not a universal ranking +certificate. + + + THE GOVERNING OBJECTIVE + + + Someone can build one, but ordinary GPU owners remain competitive, the supplier cannot obtain a + lasting overwhelming advantage, and the network does not depend on emergency intervention to + survive. + + + +This manual turns the supplied 37-page plan into 128 test cases across 16 suites, with procedures, pass +criteria, evidence, owners, review roles and source traceability. It is a test specification, not a completed +audit, deployed change or runnable test harness. + + DECISION EVIDENCE REQUIRED + + + All applicable baseline, correctness, security, capacity and operator-control tests + Engineering-ready + pass on the pinned release. + + G1-G4 and the frozen-rule test pass, including an adaptable specialist with + Coexistence-supported + already-funded development. + + Engineering and coexistence gates plus real paid demand, independent peer + Leadership contender + comparisons and the 90-day observation all pass. + + Not established by this manual. Ranking requires a defined external metric, + Number one + current competitors and sustained market evidence. + + +The interpretation of all pass +Every mandatory and claimed-option test must pass with evidence and independent review. Optional +excluded capabilities receive EXCLUDED, never PASS or a performance credit. Core requirements cannot be +removed to create a green dashboard. Finite tests support only the stated hardware, economic, threat-model +and observation scope. + + INITIAL STATUS + + + All 128 tests are NOT RUN. All new numerical thresholds are PROPOSED and require pre-run + approval. No new claim of implementation, current deployment or independent verification is made. + + + + +Basis: 2.0 plan pp. 3-5, 23-27 and 31-33. New test design is explicitly proposed. + +IGNEUM + MASTER 2.0 + 058 // PROPOSED + 292 / NOT EXECUTED 3 / 73 + TEST STANDARD / 1.0 + + + + +02 / EXECUTION RULES + + + +No greenwashing the result. +Separate experimental outcomes from implementation status, economic claims and ranking judgements. + + + STATE EXACT MEANING + + + No valid execution packet exists for the candidate release. This is the initial state of every + NOT RUN + case. + + A required input, approved threshold, adapter, environment or independent reviewer is + BLOCKED + missing. + + An invariant, threshold or required outcome is violated. Retrying does not erase this + FAIL + result. + + All pre-registered conditions pass and the prescribed reviewer accepts the complete + PASS + evidence. + + Uncertainty, conflicting observations or inadequate coverage prevent a supported + INCONCLUSIVE + decision. + + A predeclared optional capability is absent and unclaimed. It is not a pass and cannot hide + EXCLUDED + a failed core feature. + + +Stop rules +Immediately stop and isolate any test that reveals unauthorised signing, accepted invalid proofs, conflicting +finality within assumptions, unsafe hardware settings or real-data leakage. Preserve evidence; do not +continue merely to improve the pass percentage. + +No averaging away security +A severe safety failure is a blocker even if every performance test passes. A hardware energy ratio does not +substitute for total-cost competitiveness. Paid testnet rewards do not substitute for external revenue. A +modelled ASIC is not a manufactured-chip measurement. + +An experiment can finish and still fail +G2 requires an improved production candidate under the approved cost limits. Negative research is useful +but does not satisfy that outcome. Replacing an unsuccessful hypothesis is legitimate; changing the target +after observing results requires a new frozen protocol and reassessment. + + DO NOT TEST UNSUSPECTING USERS + + + Fault injection, hostile records, key-compromise drills and overload runs belong on authorised + isolated infrastructure with test funds and keys. Customer trials require explicit agreement and + data-handling controls. + + + + +Basis: 2.0 plan pp. 5, 23-27. Assurance rules and workflow are proposed here. + +IGNEUM + MASTER 2.0 + 059 // PROPOSED + 292 / NOT EXECUTED 4 / 73 + TEST STANDARD / 1.0 + + + + +03 / REQUIREMENT TRACEABILITY + + + +Every plan theme has a test. +S-page references below refer to the supplied IGNEUM_2.0_Plan.pdf, not to this manual. + + + SOURCE REQUIREMENT S-PAGES TEST SUITES + + + Objective, evidence and defensible claims 3-5, 27 GOV; LEAD + + Reported v6 baseline and pending measurements 6 GPU + + Keep/change/remove decision register 7 POW; ROT; GOV + + Accepted-work cost and commodity access 8 GPU; ECO; UX + + Resource coupling and optional FP32 9 POW; ADV + + Memory sharing, shortcuts and program selection 10 POW; ADV + + Rotation, seed pipeline and dataset policy 11 ROT; GPU; FIN + + Programmable and physically credible opponent 12 ADV + + Five-year and sunk-development economics 13 ECO; INC + + Ember, pooling, keys and accessible payouts 14 UX; OPS; FIN + + EVM, zkVM and sovereign architecture 15, 34-37 EVM; ZKP; VER + + Consensus proof enforcement and rewards 16 ZKP; INC + + Full proving pipeline and paying customers 17 CAP; COM + + Mining/proving coexistence and incentives 18 GPU; CAP; INC; ECO + + Finality, authority, expiry and recovery 19 FIN; ROT + + Wallets, receipts, oracles and availability 20 VER + + Independent operation and release controls 21 GOV; OPS + + Future hardware and fair peer comparisons 22 ADV; LEAD + + G1-G5, acceptance, risks and ownership 23-26 All suites; gate sign-off + + Leadership/adoption assessment in full source 31-33 COM; LEAD + + Architecture conditions in full source 34-37 EVM; ZKP; CAP; VER + + +S-pages 1-2 and 28-30 are title/navigation/provenance/reference material. They are preserved through this source map and +the source hash, not represented as additional protocol requirements. + + + +Source: full 2.0 plan, pp. 3-37. Test allocation is a proposed extension. + +IGNEUM + MASTER 2.0 + 060 // PROPOSED + 292 / NOT EXECUTED 5 / 73 + TEST STANDARD / 1.0 + + + + +04 / GATE DEPENDENCIES + + + +Pass outcomes, not features. +G1-G5 retain the source plan names. G0, technical readiness and the contender decision are proposed +execution controls. + + + GATE PRIMARY EVIDENCE RELEASE CONSEQUENCE + + + No formal run or public pass before + G0 / Freeze GOV; approved P-profiles; F0; test adapters + approval. + + No validated hardware claim without + G1 / Baseline GPU; build reproducibility; exact correctness + reproduction. + + No improvement claim from a + G2 / Experiments POW; candidate GPU costs; redesigned ADV + negative hypothesis. + + No broad resistance claim from one + G3 / Adversary ADV; physical/whole-system envelope + weak design. + + No durability claim based on assumed + G4 / Coexistence ECO; INC; adaptation and sunk costs + chip expiry. + + No no-rescue claim from a + G5 / No rescue ROT; FIN; OPS; independent real nodes + founder-supported demo. + + No mainnet-ready claim with missing + Technical readiness EVM; ZKP; CAP; VER; UX; critical OPS + enforcement or safety. + + Commercial evidence COM; actual external verification/payment Devnet activity is insufficient. + + Supports a scoped contention + Contender decision All preceding gates plus LEAD + assessment, not guaranteed rank. + + +Independent approval paths +Hardware/economics reviewers approve G1-G4. Cryptography/consensus/operations reviewers approve +technical readiness and G5. Customer/operator/comparative reviewers approve commercial and LEAD +evidence. The implementation author cannot be the sole approver of their own result. + + NO COMPENSATING SCORE + + + Do not weight the gates into a single average. A strong UI cannot compensate for invalid-proof + acceptance; customer revenue cannot compensate for broken finality; a good model cannot replace + independent operation. + + + + +Basis: 2.0 plan pp. 23-27. No gate is complete in this edition. + +IGNEUM + MASTER 2.0 + 061 // PROPOSED + 292 / NOT EXECUTED 6 / 73 + TEST STANDARD / 1.0 + + + + +05 / P00 APPROVAL REGISTER + + + +Freeze what the plan leaves open. +The source plan deliberately left numerical tolerances and implementation details for approval. Do not +invent them during a test. + + + FIELD TO APPROVE REQUIRED VALUE OR RECORD + + + Source and binary hashes, genesis/chain identity, protocol versions, exact + Candidate identity + dependency locks. + + Work/order rule, quorum/fault bounds, authority transitions, liveness + Consensus specification + assumptions, expiry and recovery. + + Generator/semantics, families, seed/VDF mechanism, activation and dataset + Mining and seeds + schedule. + + EVM fork and deviations; permitted program, verifier and parameter hashes; + Execution and proof identity + authenticated reward inputs. + + Supply, fee allocation, burns, payouts, assignment windows, duplicate policies and + Economic rules + derived security budget. + + Supported device/OS/role cells; light-client anchors; claimed receipt/oracle + Product and trust scope + guarantees; excluded features. + + Hardware cohort, workload W and contract deadlines, scenario reference R, + Test inputs + validator budgets, link profiles. + + Actual build/test commands, submission interfaces, metric names and assertion + Implementation adapters + hooks. Bind to source; do not invent endpoint names. + + Independence and Owners, reviewers, conflicts, resources, authorisations, evidence storage and + operations incident responsibilities. + + Approved P00-P16 version, required economic worlds, peers, exclusions, public + Claims and thresholds + claim envelope. + + + + APPROVAL RULE + + + A blank or contradictory field blocks dependent tests. This manual does not silently choose a new + consensus threshold, verifier security level, final dataset size or customer contract. + + + +The supplied plan remains the source of requirements. New measurements, sample sizes and commercial thresholds below +are this manual's proposed acceptance design. Their presence in a branded PDF does not make them approved or achieved. + + + + +Basis: 2.0 plan pp. 21, 23-25. This register and default thresholds are proposed. + +IGNEUM + MASTER 2.0 + 062 // PROPOSED + 292 / NOT EXECUTED 7 / 73 + TEST STANDARD / 1.0 + + + + +06 / SHARED FIXTURES + + + +Prepare the test environments. +Every case inherits the relevant fixture controls and the signed release manifest. No production secrets +are needed. + + + ID / FIXTURE REQUIRED CONTENT + + + Exact commits, binaries, genesis/network ID, mining class, dataset schedule, + F0 / Release and assurance + EVM fork/deviations, program/verifier IDs, fees, supply, quorum/fault rules, + manifest + trust anchors, activation and supported roles. + + Pinned toolchains, dependency locks, clean OS images and documented + F1 / Clean build environments + signing/notarisation boundaries. No production secrets or private founder files. + + F2 / Hardware and Approved physical GPU cohort, calibrated wall meters, stable thermal + measurement lab conditions, driver/OS images and realistic home/datacentre link conditions. + + F3 / Workload and oracle Fixed full-hash and EVM/proving jobs, independent reference implementations, + catalogue real customer-sized payloads, held-out seeds and complete expected results. + + Independent nodes/operators; controllable latency, loss, clocks, partitions, + F4 / Authorised fault network storage faults and role withdrawals. Actual consensus paths plus separately + labelled simulators. + + F5 / Negative and regression Malformed transactions/proofs, wrong roots/IDs, duplicate payments, bad + corpus authority tables, historical failures and deliberately faulty code mutants. + + Functionally checked architectures, RTL/physical estimates where feasible, + F6 / Specialist implementation + memory and board assumptions, cost inputs, adaptation paths and uncertainty + pack + ranges. + + F7 / Economic and incentive Independently reproducible costs, entry/exit/difficulty policies, scenario grid, + models operator opportunity costs and money-flow conservation fixtures. + + F8 / User/customer/peer Consenting unaffiliated users, contracted meaningful workloads, private + studies ownership checks, dated competitor methods and independent analysis. + + Immutable run IDs, raw logs, hashes, analysis code, exclusions, defects, + F9 / Evidence and status vault + reviewers, signatures, privacy controls and public redacted summaries. + + + + BUILD THE HARNESS AGAINST REAL CODE + + + The catalogue specifies procedures and assertions. Implement command/API adapters against the + actual repository in GOV-01. No endpoint, executable command or fabricated test output in this PDF + should be mistaken for a working harness. + + + + +Fixture design is proposed from the requirements in 2.0 plan pp. 5-26. + +IGNEUM + MASTER 2.0 + 063 // PROPOSED + 292 / NOT EXECUTED 8 / 73 + TEST STANDARD / 1.0 + + + + +07 / NUMERICAL PROFILES + + + +The proposed hardware bar. +P02-P04 are deliberate research targets. They are not reported achievements or universal ASIC bounds. + +P02 / Hardware coverage and reproducibility +At least 12 physical retail configurations: at least 3 NVIDIA, 3 AMD and 2 Apple configurations, at least two +discrete-GPU generations, an advertised 8 GB mining tier and 12 GB proving tiers where claimed. Record usable, not +nominal, memory. +Declare a competitive core of at least 6 configurations spanning every advertised vendor and at least two discrete +generations before optimisation. The wider cohort remains mandatory for access and economic tests; it cannot be +silently dropped. +Use 5 paired 30-minute steady-state runs per primary cell after at least 15 minutes of warm-up and a stable +temperature trend. Calibrated wall meter uncertainty must be at most 2%. Run a 7-day soak on representative +low/mid/high tiers. +Three unaffiliated operators participate; every competitive-core cell is reproduced by at least two. Identical-SKU +energy/accepted-work results must agree within 5% after declared environment corrections; unexplained variance +blocks the headline. + + +P03 / Candidate improvement and honest-card budget +For production candidate changes, per mandatory GPU cell: no more than 5% increase in joules per accepted work +and no more than 2% decrease in accepted throughput versus the paired tuned baseline. Absolute safety limits +always apply. +G2 requires at least a 10% reduction in the strongest evaluated specialist advantage after redesign, outside the +declared measurement/model uncertainty, while meeting those budgets. A failed experiment is not a successful +upgrade. +Existing clock-lock savings belong in the baseline. Long programs cannot pass by adding enough equally costly work +to both devices to improve a ratio while materially worsening honest operation. + + +P04 / Scoped specialist-competition target +Define R_E as GPU wall joules per accepted work divided by the lowest credible complete-system specialist joules +for that same work. The proposed target is R_E at most 1.5 for every competitive-core cell at the same node and one +node ahead. +Evaluate at least three materially distinct specialist architectures, with one programmable multi-family design, and a +second independent reviewer. Include shared/reduced memory, hybrid execution, selective participation and +realistic power/host costs. +Publish two-node-ahead and modular/reused-IP stress cases; they must satisfy the predeclared P12 economic +envelope. No universal ceiling for unknown future hardware is claimed. Report model bounds separately from +statistical confidence. +A lower-bound specialist estimate, not a convenient average or a deliberately constrained reference architecture, +drives the conservative comparison. Undefined or unbounded decision-critical assumptions make the result +BLOCKED. + + + + +Source requirements: 2.0 plan pp. 6-12 and 23. All limits below are proposed. + +IGNEUM + MASTER 2.0 + 064 // PROPOSED + 292 / NOT EXECUTED 9 / 73 + TEST STANDARD / 1.0 + + + + +08 / NUMERICAL PROFILES + + + +Correctness before confidence. +P01, P05 and P06 prevent favourable sampling, hidden uncertainty and unsupported hardware claims. + +P01 / Correctness and negative-test depth +Zero observed invalid acceptance, unauthorised signature, conflicting finality within assumptions, duplicated reward +or unexplained cross-backend state/hash disagreement. +Minimum proposed campaign: 1,000,000 full-hash vectors per supported backend across all families, plus at least +10,000 malformed/boundary cases per relevant parser or binding class. Include exhaustive small-domain cases and +historical regressions. +All prescribed critical mutants must be detected. This sampling target is not a bound on cryptographic failure +probability and does not replace independent reasoning about soundness or safety. + + +P05 / Measurement and inference protocol +Pre-register primary metrics, cohorts, holdout seeds, run order, exclusions and analysis before confirmation. Keep +tuning/training runs separate from holdout runs. +Use independent runs/operators as measurement units. Report point estimates, two-sided 95% measurement +intervals and absolute sample counts; handle time-series dependence with a declared block or run-level method. +Apply conservative uncertainty to pass decisions. A confidence interval around measured GPU energy does not +capture unknown ASIC architectures; model parameter ranges and expert judgement must be reported as such. +Never compare raw hashes per second across different algorithms. Do not transform a five-year scenario sweep into +a probability of chip arrival or a guarantee of future profitability. + + +P06 / Memory and support policy +All advertised role/configuration combinations must finish without OOM, corruption or unsafe fallback. Publish a +component memory budget, including display/OS, driver, miner, prover, aggregation and epoch construction. +Proposed support horizon: at least 24 months of known schedule compatibility for the advertised entry tier, unless a +narrower horizon is prominently approved before sale or launch. Removal changes the claim and must pass ECO-07. +Treat 5.5 / 8.5 / 11.5 GiB as source candidates, not imposed final rules. Simultaneous operation, eviction and +time-sharing are distinct advertised modes with separately measured cost. + + + + +Source requirements: 2.0 plan pp. 5-12 and 25. All new numeric limits are proposed. + +IGNEUM + MASTER 2.0 + 065 // PROPOSED + 292 / NOT EXECUTED 10 / 73 + TEST STANDARD / 1.0 + + + + +09 / NUMERICAL PROFILES + + + +Capacity, faults and +independence. +Keep the proof-delivery promise separate from finality, payment eligibility and periods when liveness +assumptions fail. + +P07 / Proof service capacity and fairness +Freeze W as a meaningful workload mix, input sizes, proof format, fleet and requests/hour. Primary proposed target: +72 hours at W, plus 24 hours at 1.2W; at least 99.5% accepted jobs delivered valid within the contracted deadline. +Default delivery targets for the declared internal reference workload: p95 at most 60 seconds and p99 at most 120 +seconds from input-ready assignment through verified delivery. Also publish request-to-delivery including input wait; +no claim may omit that delay. +Request-to-delivery p99 must meet the separately approved customer deadline. Payment p99 must be at most 10 +minutes after verified payable eligibility, with chain finality time reported separately. These defaults do not override a +stricter contract. +No statistically supported positive backlog drift at steady load, no silent drops; after 2W for 15 minutes, drain excess +backlog within 30 minutes of return to W. Report rejected demand and accepted-job success separately. +Proposed advertised-tier fairness: at least 90% timely valid assigned completions are paid under the approved rules; +avoidable duplicate/retry work is at most 10% of total work. Reassignment policy must bound abandonment without +promising every assignment a reward. + + +P08 / Fault assumptions and recovery +F0 must state the exact safety threshold, quorum and authority-transition rule; the synchrony/participation +assumptions for liveness; trusted inputs; and clock/expiry semantics. This manual supplies no substitute consensus +rule. +Exercise threshold-minus/at/plus cases, the 40/40/20 partition fixture, signing outages and 31/35/60/90 logical-day +expiry cases. Preserve safety when liveness assumptions fail; do not demand finality from an unavailable quorum. +After assumptions and input availability are restored: service replacement within 10 minutes and deterministic +network convergence within 30 minutes on the reference topology. Different certified bounds must be approved +beforehand. +Accelerated-time simulation and real elapsed operation are separate evidence classes. Recovery may not reverse a +guarantee previously represented as final. + + +P11 / No-founder exercise and independence +At least 10 verified unaffiliated operators, three independently administered network/hosting domains and sufficient +honest weight/capacity to satisfy F0 and W after founders are removed. +Run at least 30 real elapsed days without founder mining, proving, aggregation, bootstrap, required RPC, private files +or privileged interventions. Cross all known logical transitions separately without calling accelerated time real history. +Document control by role and common dependencies; uncertain identities are not counted as independent. +Within-assumption withdrawals must satisfy P08; losing more than the assumed quorum may cause a visible safe +pause. + + + + +Source requirements: 2.0 plan pp. 17-21 and 24-25. All new numeric limits are proposed. + +IGNEUM + MASTER 2.0 + 066 // PROPOSED + 292 / NOT EXECUTED 11 / 73 + TEST STANDARD / 1.0 + + + + +10 / NUMERICAL PROFILES + + + +Safe and practical operation. +A supported operator should not need privileged help, opaque software or unsafe tuning to participate. + +P09 / Security and bounded resource requirements +Zero unresolved critical or high-severity security findings on the claimed release. Independent scopes must cover +consensus, proof soundness/parameters, implementation bypasses, wallet/isolation and relevant operational +controls. +Review the intended proof-system security level and assumptions explicitly; do not infer a security-bit claim from +random rejection tests. Version every verifier, program and parameter set. +Freeze maximum valid/invalid verification time, memory, disk and admission rates for ordinary validator hardware. At +rated valid load plus the approved hostile load, no unbounded growth, invalid acceptance or unrecoverable process +failure. +For supported wallet fee-estimation cases, proposed absolute error at most 5% versus the specified charge when +inputs are unchanged; deterministic fee-cap handling and explicit uncertainty otherwise. Customer contracts remain +separately binding. + + +P10 / Ordinary-operator product targets +At least 30 unaffiliated first-time study participants across supported Windows/macOS combinations. At least 90% +install, configure safely and submit accepted work without staff help; p90 active setup at most 15 minutes. Publish +complete download/dataset time separately. +Pause/stop acknowledgement within 2 seconds, safe worker stop within 5 seconds where no documented atomic +operation prevents it, and reliable restoration of original tuning settings. No hidden custody or silent update. +Net-energy/fee displays reconcile within 5% under the declared measurement boundary. Incremental rejected-work +loss on the normal home-link profile is at most 2 percentage points over the matched datacentre profile. +Open miner efficiency is within 5% of the best independently tuned permitted implementation on identical work. For +the declared single-card payout case, p95 payable-to-payment at most 24 hours and total payout friction at most 2% +of earned value. +Critical alerts are emitted within 60 seconds of detectable evidence. At least 90% of study users can identify the +injected failure and follow the published safe action. No control target excuses a security failure. + + + REQUIRED SOFTWARE EVIDENCE + + + Manual and automated security review, correct negative-test oracles, secret-isolation tests and + reproducible release inputs are separate obligations. A large pass count does not replace them. + + + + +Source requirements: 2.0 plan pp. 14-16 and 20-26. All new numeric limits are proposed. + +IGNEUM + MASTER 2.0 + 067 // PROPOSED + 292 / NOT EXECUTED 12 / 73 + TEST STANDARD / 1.0 + + + + +11 / NUMERICAL PROFILES + + + +Test the world after chips arrive. +The economics must survive a funded programmable competitor. They must also disclose where +commodity participation fails. + +P12 / Five-year coexistence envelope +Freeze a sourced revenue reference R and mandatory worlds before results. Sweep 0.25R, R, 4R and 10R; electricity +at $0.03/$0.10/$0.25/$0.40 per kWh; 1/3/5-year productive life; zero/$20M/$75M development; private mining and +hardware sales; no/normal/spiking external demand. +Those values are proposed stress inputs, not current prices or forecasts. Declare which worlds have enough funded +demand for rational ongoing service before running; retain collapse worlds as explicit safety/exit tests, not profitable +successes. +Proposed matched-tariff new-entry target in every mandatory sustainable world: median GPU/specialist total cost +per accepted work at most 1.5, 90th percentile at most 1.75, and no advertised competitive-core cell above 2.0. +Publish every cell, including heterogeneous tariffs. +At least three purchasable GPU configurations across at least two advertised vendors must have positive modelled +new-entry economics; at least 75% of the entry cohort must have positive marginal operating economics in those +worlds. Report model uncertainty and failure regions. +Do not impose GPU market share, specialist production limits, token appreciation, full research-cost recovery or +automatic chip death to force the result. Any such condition must become an explicit limitation rather than a hidden +assumption. + + +P13 / Maintenance continuity +Before a readiness claim, document at least 12 months of committed maintenance resources at the approved +operating scope. Include engineering, security review, infrastructure, support and incident response. +Use independently reviewable commitments and downside budgets. Uncommitted future sales, rising token prices, +burned fees or assumed fundraising are not available resources. +This is a proposed governance test, not a directive to change the supply cap, issuance allocation or fair-launch +design. + + + WHAT THIS DOES NOT PROMISE + + + No hash guarantees profit at every tariff or with zero demand. The mandatory sustainable worlds and + collapse cases must be chosen before results. A failure cannot be moved outside scope afterwards to + rescue the headline. + + + + +Source requirements: 2.0 plan pp. 8, 13, 18 and 24-26. Stress inputs and limits are proposed. + +IGNEUM + MASTER 2.0 + 068 // PROPOSED + 292 / NOT EXECUTED 13 / 73 + TEST STANDARD / 1.0 + + + + +12 / NUMERICAL PROFILES + + + +The bar beyond engineering. +Passing a private technical test set alone is insufficient for the leadership-contender assessment. + +P14 / Genuine commercial and developer proof +At least three unrelated paying buyer organisations, each making at least three separate purchase decisions across at +least 30 days; at least 1,000 meaningful verified external jobs in aggregate. Split invoices do not create independent +demand. +No project reimbursement, circular funding or undisclosed related party counts. Report customer concentration and +churn; proposed maximum largest-buyer share is 70% of qualifying revenue. +At least 20% aggregate contribution margin after directly attributable delivery costs, retries, refunds and support; +publish fully loaded economics separately. At least 75% of sampled eligible operators have positive realised +contribution on the declared workload. +At least five unaffiliated developers complete a useful supported application or proof-service integration using public +documentation. Customer confirmation and raw commercial evidence may remain confidential to the reviewer. + + +P15 / Comparative contention threshold +Pre-register at least three relevant operating GPU-first peers, plus a real proving alternative for customer +comparisons. Verify current versions at execution time. The source reference set is a starting point, not a claim about +current rankings. +Require at least three meaningful comparable dimensions with no material inferiority beyond a pre-agreed 10% +margin against the best valid comparator, and at least two independently evidenced advantages against at least two +peers. +Advantages must be either a greater-than-10% measured improvement outside uncertainty or a directly tested +control/capability difference with demonstrated user value. Non-comparable or missing data is not a win. +A panel with hardware/economics, security/operations and customer/operator expertise must support the scoped +contender conclusion. Passing these judgement-based thresholds does not certify a universal number-one ranking. + + +P16 / Observed durability and claim freshness +At least 90 real elapsed days on the final compatible release family, at least 30 independently verified operators, and +transparent eligibility/churn denominators. Material uncomparable changes reset affected observations. +Proposed outcomes: at least 60% day-90 operator retention and at least 75% of eligible observed operators with +positive measured marginal operation over the period. Report incentives and electricity assumptions; do not claim a +downturn was observed if it was not. +At least 99.9% availability for the declared customer service during eligible operating conditions, with all-in +availability also reported; zero accepted invalid proofs or conflicting finality within F0 assumptions. Do not remove +real incidents as maintenance to force a pass. +Run fault injection on isolated infrastructure, not unsuspecting customers. Publish planned test windows separately. +Reassess claims at least quarterly and immediately after material hardware, protocol, economics or security +changes. + + + + +Source requirements: 2.0 plan pp. 4, 17, 24-27 and 31-33. New thresholds are proposed judgements. + +IGNEUM + MASTER 2.0 + 069 // PROPOSED + 292 / NOT EXECUTED 14 / 73 + TEST STANDARD / 1.0 + + + + +13 / EXECUTION SEQUENCE + + + +Run in the right order. +Observation periods are minimum test durations, not delivery promises. Staffing and budgets still need +approval. + + + PHASE DO THE WORK EXIT + + + GOV and all + Approve F0/P00-P16; build adapters, clean images, + A / Freeze preconditions + independent oracles and mutation controls. + accepted. + + No blocking safety + Close proof enforcement, authenticated authority, + B / Safety first failure; safe to run + replay/payout correctness and wallet isolation. + broader trials. + + G1-G4 with scoped + Reproduce v6; evaluate coupling and memory attacks; uncertainty and + C / Hardware research + independent programmable design and economics. rejected designs + retained. + + D / Integrated Run sustained W, overload, concurrency, actual node Technical readiness + operation partitions and no-founder exercise. and G5. + + COM and P16 evidence; + Run consenting user/developer studies, genuine paid jobs and + E / Field evidence no simulated customer + 90-day operation/retention. + demand. + + Dated contender + assessment or a + F / Compare and Complete current peer/customer comparisons and + documented + decide independent gate review. + failed/blocked + decision. + + +Cadence by risk +Every code change runs affected deterministic and negative regressions. Nightly campaigns extend fuzzing +and soak coverage. Every release candidate reruns relevant integration and hardware cases. Protocol, +verifier, fee or dataset changes invalidate all dependent model and field evidence. Commercial/peer claims +refresh at least quarterly. + +Real time cannot be compressed away +The 30-day independent exercise can be a properly scoped part of the 90-day field period. Long-expiry +simulations remain separate. Hardware design/review and customer acquisition may take longer than any +test run; this manual makes no staffing or elapsed-delivery guarantee. + + + + +Basis: 2.0 plan pp. 23-26. Sequencing is this manual's proposed implementation approach. + +IGNEUM + MASTER 2.0 + 070 // PROPOSED + 292 / NOT EXECUTED 15 / 73 + TEST STANDARD / 1.0 + + + + +14 / MEASUREMENT CONTROLS + + + +Make the evidence difficult to +game. +Apply P05 globally, not only to hardware charts. Every exclusion and missing result remains visible. + +Define the denominator +Accepted-work energy = complete measured energy divided by accepted work. Delivery success = correct, +on-time jobs divided by all accepted jobs. Publish admission rejection separately. Retention uses the original +eligible cohort, including departures. Revenue excludes refunds, reimbursements and circular funding. + +Separate four kinds of evidence + + CLASS CAN SUPPORT CANNOT SUBSTITUTE FOR + + + Actual device, job or operating result with Unknown architectures or years not + Measured + uncertainty. observed. + + A result conditional on explicit cost, Manufactured-silicon performance or + Modelled + hardware and behaviour assumptions. observed profits. + + A property under a stated model and Correct implementation and complete + Formally analysed + bounded or proven assumptions. environmental assumptions. + + Independently A scoped qualified assessment and A guarantee that no future flaw or + reviewed reproduced evidence. competitor exists. + + +Use adversarial controls +Publish positive controls, historical failures, deliberate mutants and holdout seeds. Compare different +algorithms only through meaningful common tasks or normalised overhead. Do not award a win when peer +data is absent or incomparable. + + GENERAL PASS RULE + + + PASS requires the pre-registered condition, full raw evidence, no unresolved contradictory result and + the assigned review. Missing data, borderline uncertainty or a changed workload means BLOCKED, + INCONCLUSIVE or FAIL. It is not rounded into success. + + + + +Basis: 2.0 plan pp. 5, 8, 12, 17, 23-25. Experimental methods are proposed. + +IGNEUM + MASTER 2.0 + 071 // PROPOSED + 292 / NOT EXECUTED 16 / 73 + TEST STANDARD / 1.0 + + + + +15 / TEST EXECUTION MAP + + + +The 16-suite catalogue. +Every test starts NOT RUN. BLOCKER and GATE identify the consequence of failure, not a waiver option. + + + SUITE ACCOUNTABLE LEAD CASES + + + GOV / Release identity and evidence Release lead + independent assurance 8 + + GPU / Whole-system GPU measurements GPU lead + three independent operators 8 + + POW / Proof-of-work correctness and coupling Cryptography + GPU lead 8 + + ADV / Programmable specialist adversaries Independent hardware team 8 + + ROT / Epochs, seeds and memory transitions Consensus + GPU leads 8 + + ECO / Five-year coexistence economics Economics lead + independent reviewer 8 + + EVM / Execution and developer compatibility Execution lead + independent implementer 8 + + Proving + protocol leads; independent + ZKP / Consensus-enforced proof validity 8 + cryptography review + + CAP / Sustained proving and delivery Proving lead + independent operators 8 + + INC / Rewards, incentives and selfish operators Protocol economics + proving leads 8 + + Consensus lead + independent formal/security + FIN / Consensus safety and recovery 8 + review + + Wallet + light-client lead; independent security + VER / Wallets, receipts and data availability 8 + review + + Operations + release leads; independent + OPS / Independent operation and release security 8 + operators + + Desktop product + pool leads; independent + UX / Ember, payouts and operator control 8 + usability study + + Commercial lead + independent + COM / Paid demand and sustainable delivery 8 + financial/customer reviewer + + Independent assessment panel + + LEAD / Comparative leadership evidence 8 + product/economics reviewers + + +Inherited preconditions: approved F0/P-profile versions, controlled test keys/data, positive and negative controls, +calibrated collection and the stated independent reviewer. Retest: every release candidate and any relevant source, +parameter, hardware, economic or scope change. + + + + +Source requirements: 2.0 plan pp. 3-27. Full traceability is on the source map and each suite page. + +IGNEUM + MASTER 2.0 + 072 // PROPOSED + 292 / NOT EXECUTED 17 / 73 + TEST STANDARD / 1.0 + + + + +GOV / GOV-01 TO GOV-03 + + + +Release identity and evidence +Prevent a favourable result from being attached to the wrong code, assumptions or public claim. + +Lead: Release lead + independent assurance +Fixtures: F0 manifest; F1 source/build archives; F9 evidence vault +GOV-01 BLOCKER / P00 / NOT RUN + + +Freeze the release and its claims +Setup. Candidate source, binaries, public documentation and the 2.0 plan are available; no run is yet +accepted. +1. Record exact commits, binary hashes, dependencies, genesis/network identity, mining class, datasets, +execution fork, verifier IDs and fee rules in F0. 2. Map every promised capability and plan requirement to a +test ID; distinguish supported mining, proving and wallet combinations. 3. Sign the manifest with protocol, +product and independent review owners before confirmatory runs. +Pass. Every material rule and claim has an unambiguous version and test. Conflicts or unknown activation +rules produce BLOCKED, not an inferred default. Changes create a new manifest and invalidate affected +results. +Evidence. Signed F0; source-to-test map; claim inventory; unresolved-field register. + +GOV-02 BLOCKER / P00 / NOT RUN + +Approve thresholds before results +Setup. This manual supplies proposed test thresholds, not source-approved protocol parameters. +1. Approve or replace every P-profile before confirmatory testing; give each change a rationale and +independent approver. 2. Register hardware cohorts, mandatory economic worlds, customer workloads, +peer dimensions and exclusion rules. 3. Lock the profile hash and hold out seeds/workloads from the +developers doing optimisation. +Pass. No decision-critical field is TBD. Numeric limits are frozen, commercially meaningful and not chosen +from observed results. A weakened limit after failure requires a new protocol, full affected rerun and explicit +claim downgrade review. +Evidence. Approved profile register; timestamped holdout commitments; change log. + +GOV-03 BLOCKER / P00; P02 / NOT RUN + +Reproduce builds outside the founding team +Setup. Provide public source and documented build instructions to three unaffiliated operators. +1. Build on clean declared environments without private files, tokens or founder assistance. 2. Compare +reproducible payload hashes; isolate signatures, notarisation and permitted non-deterministic wrappers. 3. +Run reference vectors and restart a node using only documented artifacts. +Pass. All independent builds reproduce the same consensus payload or an independently explained, +pre-approved wrapper difference; reference outputs match exactly. Missing private prerequisites block +release. +Evidence. Build logs; dependency lockfiles; binary comparison; operator attestations. + + + + +Source: 2.0 plan pp. 5, 21, 23, 25, 26, 27. Procedures and P-profile thresholds are proposed. + +IGNEUM + MASTER 2.0 + 073 // PROPOSED + 292 / NOT EXECUTED 18 / 73 + TEST STANDARD / 1.0 + + + + +GOV / GOV-04 TO GOV-06 + + + +Release identity and evidence +Prevent a favourable result from being attached to the wrong code, assumptions or public claim. + +Lead: Release lead + independent assurance +Fixtures: F0 manifest; F1 source/build archives; F9 evidence vault +GOV-04 BLOCKER / P00 / NOT RUN + + +Preserve raw and negative evidence +Setup. Enable append-only storage for run outputs and a separate analysis workspace. +1. Capture failed, aborted and successful runs with timestamps, seeds and environment hashes. 2. +Recompute one published figure from raw records on a clean machine. 3. Modify a retained artifact +deliberately and test integrity verification. +Pass. Every headline can be regenerated; tampering is detected; exclusions have pre-registered reasons. +Failed or missing runs remain visible and are never replaced silently by a successful retry. +Evidence. Artifact manifest; hashes; reproduction script; exclusion ledger; negative-run archive. + +GOV-05 BLOCKER / P01 / NOT RUN + +Prove the test oracle detects broken behaviour +Setup. Create controlled defective variants on an isolated network only. +1. Disable proof verification, change one reward, accept an expired authority set and alter one hash output +in separate mutants. 2. Run the corresponding ZKP, INC, FIN and POW tests without telling the runner which +mutant is active. 3. Confirm the baseline still accepts authorised valid cases. +Pass. Every deliberately introduced fault is caught by its mapped test; valid controls pass. Any undetected +critical mutant blocks acceptance of that test family until the oracle is repaired. +Evidence. Mutation catalogue; blinded run results; baseline controls; oracle review. + +GOV-06 BLOCKER / P00 / NOT RUN + + +Enforce scope and optional-feature discipline +Setup. Inventory FP32 experiments, receipts/oracles and all retained or excluded mining levers. +1. Mark each capability CORE, CLAIMED-OPTIONAL or EXCLUDED before release testing. 2. For excluded +code, check binaries, protocol activation and product copy for accidental enablement or implied availability. +3. For each claimed option, require the complete associated test set rather than a demonstration. +Pass. Every core and claimed-option obligation passes. Excluded items are shown as EXCLUDED, never +PASS and never counted as achievements. Removing a failed core requirement prevents an all-2.0-pass +claim. +Evidence. Scope manifest; activation scan; product-copy comparison; exclusions register. + + + + +Source: 2.0 plan pp. 5, 21, 23, 25, 26, 27. Procedures and P-profile thresholds are proposed. + +IGNEUM + MASTER 2.0 + 074 // PROPOSED + 292 / NOT EXECUTED 19 / 73 + TEST STANDARD / 1.0 + + + + +GOV / GOV-07 TO GOV-08 + + + +Release identity and evidence +Prevent a favourable result from being attached to the wrong code, assumptions or public claim. + +Lead: Release lead + independent assurance +Fixtures: F0 manifest; F1 source/build archives; F9 evidence vault +GOV-07 BLOCKER / P09 / NOT RUN + + +Independent review and finding closure +Setup. Nominate reviewers with declared conflicts and scopes covering cryptography, consensus and +hardware. +1. Provide pinned code, raw data, adversarial models and prior failures, including negative results. 2. Track +each finding to remediation and an independent retest; do not use the author as sole approver. 3. Have +reviewers state unreviewed surfaces and model limitations in their signed conclusions. +Pass. No unresolved critical or high-severity finding affects the claimed release. A finite review is described +by scope, not as proof of universal security. Independent reproduction and review are both evidenced. +Evidence. Signed scoped reports; conflict declarations; finding/retest ledger. + +GOV-08 BLOCKER / P00 / NOT RUN + +Invalidate stale evidence and control public status +Setup. Create a simulated post-test change to a verifier, mining class, dataset and fee rule. +1. Calculate affected test dependencies and invalidate their former PASS statuses. 2. Regenerate public +status pages from F0 and the evidence register. 3. Attempt to publish a rank-one, guaranteed-profit or +automatic-chip-death claim without the required evidence. +Pass. Affected gates return to NOT RUN or BLOCKED. Public claims retain version, limits and date; +unsupported claims are withheld. No stale result remains attached to a different release. +Evidence. Dependency impact report; regenerated status page; rejected claim examples. + + + + SUITE CLOSE / GOV + + + Confirm the frozen release and P-profiles, all positive/negative controls, complete raw artifacts and + independent review. A missing result is not a pass. Re-run affected cases after relevant changes. + + + +Execution owner: ____________________ Review: ____________________ +Evidence root: _______________________ Decision: NOT RUN + + + + +Source: 2.0 plan pp. 5, 21, 23, 25, 26, 27. Procedures and P-profile thresholds are proposed. + +IGNEUM + MASTER 2.0 + 075 // PROPOSED + 292 / NOT EXECUTED 20 / 73 + TEST STANDARD / 1.0 + + + + +GPU / GPU-01 TO GPU-03 + + + +Whole-system GPU measurements +Close the pending measurements and evaluate the actual configuration, including costs hidden by +kernel-only results. + +Lead: GPU lead + three independent operators +Fixtures: F2 retail-hardware cohort; F3 paired benchmark workloads; F9 calibrated evidence +GPU-01 GATE / P02 / NOT RUN + + +Cover the declared commodity population +Setup. Freeze the P02 cohort, supported role matrix and the final v6 configuration. +1. Inventory physical SKU, usable memory, driver, operating system, firmware, cooling and acquisition +channel. 2. Run mining on every supported cohort cell and proving on every separately advertised prover +cell. 3. Include lower-memory, used-generation and all advertised vendor cases; retain unsupported results +separately. +Pass. All declared cells are tested, with no after-the-fact removal of weak cards. At least the P02 minimum +coverage is met. Mining-only support is never reported as proof-generation support. +Evidence. Cohort manifest; compatibility matrix; raw results by SKU and role. + +GPU-02 GATE / P02; P03 / NOT RUN + +Reproduce Ember clock-lock savings +Setup. Use paired stock and tuned runs on the same board, host, workload and ambient conditions. +1. Warm to stability; randomise stock/tuned order and run P02 repeated sessions. 2. Measure accepted +work, calibrated wall energy, device telemetry and rejected work. 3. Calculate paired energy and rate +changes with run-level uncertainty, retaining failed tuning attempts. +Pass. Tuning preserves correctness and meets approved P03 operating limits. The historical 34-41% saving +and under-2% rate-loss statement is reproduced only for qualifying configurations; otherwise that claim is +corrected. Existing savings are not counted twice. +Evidence. Raw power/time series; paired analysis; tuning settings; claim-by-SKU table. + +GPU-03 GATE / P02; P03 / NOT RUN + +Measure the real 64-register GPU cost +Setup. Build the baseline and window variant with identical dataset, reads and semantic workload. +1. Inspect compiled register allocation, spills, occupancy and memory traffic on each supported backend. 2. +Measure paired complete-system energy and accepted throughput, including host work. 3. Repeat during +proving coexistence and expose any memory or scheduling cliff. +Pass. Any production window meets P03 budgets for every mandatory SKU; no hidden spills or correctness +changes. Zero GPU cost is claimed only where measurement supports it within uncertainty. Results feed the +redesigned adversary, not an old core estimate. +Evidence. Compiler reports; allocation traces; paired energy/rate data; coexistence runs. + + + + +Source: 2.0 plan pp. 6, 7, 8, 14, 18, 23. Procedures and P-profile thresholds are proposed. + +IGNEUM + MASTER 2.0 + 076 // PROPOSED + 292 / NOT EXECUTED 21 / 73 + TEST STANDARD / 1.0 + + + + +GPU / GPU-04 TO GPU-06 + + + +Whole-system GPU measurements +Close the pending measurements and evaluate the actual configuration, including costs hidden by +kernel-only results. + +Lead: GPU lead + three independent operators +Fixtures: F2 retail-hardware cohort; F3 paired benchmark workloads; F9 calibrated evidence +GPU-04 BLOCKER / P01; P02 / NOT RUN + + +Find the memory-clock operating ladder +Setup. Use safe vendor-supported settings only; record operator permission and original settings. +1. Sweep approved core and memory operating points while holding workload constant. 2. Measure error +rate, accepted throughput, wall energy and thermal equilibrium. 3. Repeat the selected knee after reboot +and restore defaults after a failed or interrupted tuning session. +Pass. Selected profiles are stable, reproducible and not dependent on unsafe clocks. Every accepted hash +remains correct; saved settings restore predictably. Tuning failure leaves a working safe configuration. +Evidence. Clock ladder; safe bounds; thermal/error logs; reboot and rollback record. + +GPU-05 BLOCKER / P01; P02; P06 / NOT RUN + +Test dataset fit and support-horizon costs +Setup. Test 5.5, 8.5 and 11.5 GiB only as source-proposed candidates; F0 determines activated sizes. +1. Measure allocation plus driver, display, prover and OS headroom on the 8 GB and other cohort tiers. 2. +Run near-full-memory, fragmentation, restart and next-epoch construction scenarios. 3. Compare +time-sharing/eviction with concurrent mining/proving, including reload cost. +Pass. Every advertised combination completes without OOM or silent corruption. Unsupported future sizes +are identified before activation. GPU exclusions and lost proving capacity appear in ECO evaluation; +retirement of a tier is not a success metric. +Evidence. Memory budget per SKU; OOM traces; support horizon; concurrency cost table. + +GPU-06 GATE / P02; P10 / NOT RUN + +Measure accepted work under ordinary connectivity +Setup. Use the same hardware against clean, delayed, lossy and intermittent links in F4. +1. Measure kernel rate and accepted work separately under home and datacentre link profiles. 2. Include +reconnects, template changes, expired submissions and pool failover. 3. Attribute loss to network, local +software, validation and protocol causes. +Pass. Results use accepted work, never kernel rate alone. Ordinary-link incremental rejection stays within +P10; all losses remain priced in ECO. Unreachable links may pause but must not claim paid work. +Evidence. Per-submission ledger; network trace; rejection reasons; accepted-work comparison. + + + + +Source: 2.0 plan pp. 6, 7, 8, 14, 18, 23. Procedures and P-profile thresholds are proposed. + +IGNEUM + MASTER 2.0 + 077 // PROPOSED + 292 / NOT EXECUTED 22 / 73 + TEST STANDARD / 1.0 + + + + +GPU / GPU-07 TO GPU-08 + + + +Whole-system GPU measurements +Close the pending measurements and evaluate the actual configuration, including costs hidden by +kernel-only results. + +Lead: GPU lead + three independent operators +Fixtures: F2 retail-hardware cohort; F3 paired benchmark workloads; F9 calibrated evidence +GPU-07 BLOCKER / P01; P02; P10 / NOT RUN + + +Survive sustained thermal and power operation +Setup. Run the selected profile on actual reference machines for the P02 soak period. +1. Track wall power, temperatures, clocks, memory and accepted work continuously. 2. Inject safe power +interruptions, process restarts and normal competing desktop load. 3. Check restored settings and compare +late-run efficiency with the first stable period. +Pass. No invalid work or unsafe persistent settings; P02/P10 stability limits hold. Thermal throttling, +crashes and recovery time remain in throughput and energy denominators. A crash-free short benchmark +cannot substitute for the soak. +Evidence. Seven-day time series; crash reports; settings-restoration checks; drift analysis. + +GPU-08 GATE / P02 / NOT RUN + +Reproduce the full baseline independently +Setup. Three unaffiliated operators receive F0, F2 and F3, including the final miner/prover build. +1. Repeat identical-SKU paired runs with documented meter calibration and environment differences. 2. +Recompute joules and total cost per accepted work from the shared raw schema. 3. Investigate divergence +before accepting a pooled headline or uncertainty band. +Pass. Reproductions meet P02 tolerance and exact correctness. No unexplained divergence or selectively +missing low-end cell remains. Report manufactured GPU measurements separately from modelled +specialist estimates. +Evidence. Three signed reproduction packs; reconciliation report; final baseline table. + + + + SUITE CLOSE / GPU + + + Confirm the frozen release and P-profiles, all positive/negative controls, complete raw artifacts and + independent review. A missing result is not a pass. Re-run affected cases after relevant changes. + + + +Execution owner: ____________________ Review: ____________________ +Evidence root: _______________________ Decision: NOT RUN + + + + +Source: 2.0 plan pp. 6, 7, 8, 14, 18, 23. Procedures and P-profile thresholds are proposed. + +IGNEUM + MASTER 2.0 + 078 // PROPOSED + 292 / NOT EXECUTED 23 / 73 + TEST STANDARD / 1.0 + + + + +POW / POW-01 TO POW-03 + + + +Proof-of-work correctness and +coupling +Find semantic disagreements and structural shortcuts before treating a harder-looking program as a +stronger defence. + +Lead: Cryptography + GPU lead +Fixtures: F0 rule set; F3 independent CPU/GPU oracles; F5 mutation corpus +POW-01 BLOCKER / P01 / NOT RUN + + +Match independent execution across every backend +Setup. Implement an independently written reference evaluator, not a wrapper around the production GPU +path. +1. Execute the P01 corpus across every family, boundary seed and supported backend. 2. Exercise zero, +maximum, sign, shift, rotate, overflow and unaligned-address cases allowed by the spec. 3. Minimise every +mismatch and rerun it on clean builds. +Pass. Bit-for-bit agreement for all valid cases and identical rejection for invalid cases. One unexplained +mismatch is a blocker. Large sample counts are evidence of testing, not proof that unseen disagreements +cannot exist. +Evidence. Reference implementation review; seeds/vectors; backend matrix; mismatch archive. + +POW-02 BLOCKER / P01 / NOT RUN + +Validate generated programs and index folding +Setup. Use the frozen grammar, opcode semantics and index-fold rule; include boundary and malformed +programs. +1. Enumerate small constrained programs and fuzz the full generator at P01 depth. 2. Check bounds, valid +dependencies, address distribution and forbidden encodings. 3. Compare source-level operations with +optimised compiled code for removed or altered work. +Pass. No accepted program violates semantics, termination or memory bounds. Distribution claims have +predeclared tests and effect-size limits; passing randomness checks is not treated as a cryptographic proof. +Evidence. Generator/fuzzer logs; reduced counterexamples; disassembly comparison; index tests. + +POW-03 GATE / P03; P04 / NOT RUN + +Test whether live state is unavoidable +Setup. Take the 64-register candidate and the cheapest independently proposed storage organisations. +1. Trace value liveness across dependent reads and final output, distinguishing distinct information from +duplicated values. 2. Try banking, compression, recomputation, fewer ports and time-multiplexed contexts. +3. Quantify the best complete-system cost/throughput trade-off rather than the reference register count. +Pass. Production selection is supported by measured or physically modelled penalties after these +alternatives. G2 requires the P03 improvement; an attractive source-level register count alone does not +pass. +Evidence. Liveness traces; alternative implementations; Pareto table; reviewer analysis. + + + + +Source: 2.0 plan pp. 7, 9, 10, 23. Procedures and P-profile thresholds are proposed. + +IGNEUM + MASTER 2.0 + 079 // PROPOSED + 292 / NOT EXECUTED 24 / 73 + TEST STANDARD / 1.0 + + + + +POW / POW-04 TO POW-06 + + + +Proof-of-work correctness and +coupling +Find semantic disagreements and structural shortcuts before treating a harder-looking program as a +stronger defence. + +Lead: Cryptography + GPU lead +Fixtures: F0 rule set; F3 independent CPU/GPU oracles; F5 mutation corpus +POW-04 GATE / P03; P04 / NOT RUN + + +Evaluate connected-resource restructuring +Setup. Use a candidate initially matched to baseline instruction count, read count and dataset size. +1. Connect state, addresses, arithmetic and lane communication according to the written hypothesis. 2. +Measure GPU cost and allow the specialist reviewer to redesign the entire core. 3. Repeat on held-out +program seeds and compare the worst supported adversary, not only the original design. +Pass. The selected upgrade meets P03 and improves the adversarial result outside declared uncertainty. A +negative experiment remains a negative outcome; adopting a different design requires a new frozen +comparison. +Evidence. Matched workloads; GPU runs; redesigned core estimates; held-out results. + +POW-05 BLOCKER / P01; P04 / NOT RUN + +Prevent amortised cheap winning attempts +Setup. Prepare valid templates, nonces, intermediate-state captures and independent acceptance checks. +1. Vary nonce, payout identity, transactions, roots and other committed fields after expensive work. 2. Try +replay, precomputation, shared prefixes, partial evaluation and many cheap suffix candidates. 3. Price any +valid strategy against fresh evaluation; independently review all bindings. +Pass. Invalid modifications are rejected. Any valid cost-saving strategy is incorporated into ADV and must +still meet P04/ECO gates. No unresolved shortcut is hidden behind passing reference vectors. +Evidence. Attack implementations; valid/invalid controls; work-cost analysis; binding review. + +POW-06 BLOCKER / P01; P09 / NOT RUN + +Bound verifier work and malformed-input cost +Setup. Use ordinary CPU validators with a manifest-defined resource budget and untrusted submissions. +1. Submit shortest/longest programs, malformed encodings and adversarial memory references. 2. Measure +verification time, peak memory and work amplification across valid and invalid inputs. 3. Sustain the +approved hostile request rate while ordinary valid traffic continues. +Pass. All semantics remain correct and P09 resource budgets hold. Invalid traffic cannot cause unbounded +allocation, crashes or disproportionate free work. Rate limits must not replace consensus validation. +Evidence. CPU profiles; adversarial corpus; allocation traces; valid-traffic latency. + + + + +Source: 2.0 plan pp. 7, 9, 10, 23. Procedures and P-profile thresholds are proposed. + +IGNEUM + MASTER 2.0 + 080 // PROPOSED + 292 / NOT EXECUTED 25 / 73 + TEST STANDARD / 1.0 + + + + +POW / POW-07 TO POW-08 + + + +Proof-of-work correctness and +coupling +Find semantic disagreements and structural shortcuts before treating a harder-looking program as a +stronger defence. + +Lead: Cryptography + GPU lead +Fixtures: F0 rule set; F3 independent CPU/GPU oracles; F5 mutation corpus +POW-07 BLOCKER / P00; P01; P03 / NOT RUN + + +Constrain any mixed-resource or FP32 branch +Setup. If this branch is excluded, verify that it is unreachable and not claimed; if included, use a separate +frozen candidate. +1. Specify exact rounding, fusion, special values and backend behaviour before compiling. 2. Differentially +test all supported architectures and allow numerical-domain simplification in the specialist model. 3. +Include verifier cost and candidate energy in P03/P04, not just arithmetic-unit area. +Pass. Included branches achieve exact agreed semantics and all hardware budgets. An excluded branch +earns no performance credit. No approximate operation or unspecified compiler choice enters consensus. +Evidence. Scope decision; semantic specification; vectors; simplified datapath model. + +POW-08 GATE / P00; P03 / NOT RUN + +Keep rejected mechanisms out of the shipped claim +Setup. Inventory long programs, select trees, SM gating, wider reads, sealed classes, random epoch +lengths, per-tier scoring and VRF draws. +1. Retain their historic negative tests and realistic SRAM instruction-memory control. 2. Inspect the release +for reintroduction through renamed settings or hidden paths. 3. Require a new written hypothesis and +complete adversarial retest for any proposed return. +Pass. Excluded levers remain excluded unless separately approved and retested. Flip-flop +instruction-memory area is never presented as the cost of a realistic SRAM implementation. +Evidence. Decision register; binary/config scan; negative-control results. + + + + SUITE CLOSE / POW + + + Confirm the frozen release and P-profiles, all positive/negative controls, complete raw artifacts and + independent review. A missing result is not a pass. Re-run affected cases after relevant changes. + + + +Execution owner: ____________________ Review: ____________________ +Evidence root: _______________________ Decision: NOT RUN + + + + +Source: 2.0 plan pp. 7, 9, 10, 23. Procedures and P-profile thresholds are proposed. + +IGNEUM + MASTER 2.0 + 081 // PROPOSED + 292 / NOT EXECUTED 26 / 73 + TEST STANDARD / 1.0 + + + + +ADV / ADV-01 TO ADV-03 + + + +Programmable specialist +adversaries +Give the opponent permission to adapt, share resources and remain operational; test cost rather than +imagined chip death. + +Lead: Independent hardware team +Fixtures: F2 reference GPUs; F6 RTL/physical models; all published families +ADV-01 GATE / P01; P04 / NOT RUN + + +Build a multi-family programmable opponent +Setup. Provide the complete published family bank and future known parameter schedule to the reviewer. +1. Design one programmable architecture that supports all retained families, including firmware and +emulation paths. 2. Optimise clocks, lanes, ports and pipelines without requiring a graphics-card layout. 3. +Verify its outputs against POW vectors before measuring any advantage. +Pass. At least the P04 design diversity is evaluated; every estimated competitive design is functionally +validated. Inability of one narrow design to adapt is not evidence that all chips expire. +Evidence. Architecture reports; functional simulations; adaptation matrix; reviewer signature. + +ADV-02 GATE / P04 / NOT RUN + +Price shared, reduced and reconstructed memory +Setup. Allow multiple engines to share a dataset and to store selected fractions rather than a complete +per-engine copy. +1. Sweep sharing factors, memory fractions, caches and recomputation depth across many simultaneous +hashes. 2. Include construction/update amortisation, bandwidth contention and retained state. 3. Take the +most favourable feasible point for the specialist into the complete-board model. +Pass. No omitted feasible trade-off materially lowers the accepted cost estimate. Any winning alternative is +included in P04 and ECO; capacity alone is not accepted as an energy bound. +Evidence. Sweep definitions; energy/bandwidth data; best-feasible envelope; excluded-design reasons. + +ADV-03 GATE / P04 / NOT RUN + +Attack with data-local and hybrid execution +Setup. Permit distributed memories, state migration and companion CPU/GPU/FPGA components. +1. Compare moving computation, intermediate state or fetched data to each read location. 2. Test +specialised mining alongside outsourced proof generation rather than assuming one physical GPU does +both. 3. Include interconnect, host, synchronisation, idle and conversion costs. +Pass. The cheapest feasible combined system is included in the adversarial envelope and economic model. +A worker identity or account is never treated as proof of a single physical device. +Evidence. Hybrid architecture diagrams; traffic traces; system cost and energy ledger. + + + + +Source: 2.0 plan pp. 8, 10, 12, 22, 23. Procedures and P-profile thresholds are proposed. + +IGNEUM + MASTER 2.0 + 082 // PROPOSED + 292 / NOT EXECUTED 27 / 73 + TEST STANDARD / 1.0 + + + + +ADV / ADV-04 TO ADV-06 + + + +Programmable specialist +adversaries +Give the opponent permission to adapt, share resources and remain operational; test cost rather than +imagined chip death. + +Lead: Independent hardware team +Fixtures: F2 reference GPUs; F6 RTL/physical models; all published families +ADV-04 GATE / P04; P12 / NOT RUN + + +Measure profitable selective participation +Setup. Use all declared families plus held-out generated programs and the protocol difficulty rule. +1. Identify favourable execution paths and add cheap fallbacks for other periods. 2. Simulate entry/exit +around profitable periods, including idle time, compilation and re-entry costs. 3. Evaluate revenue and costs +across the full schedule, not just average program energy. +Pass. Intermittent specialists meet P04/ECO limits when evaluated on full-period economics. A weak tail +cannot be concealed by a favourable mean; known valid shortcuts must be priced. +Evidence. Per-program advantage distribution; policy simulator; full-period returns. + +ADV-05 GATE / P04 / NOT RUN + +Validate physical and complete-board costs +Setup. Use feasible process/library assumptions and documented component boundaries; no fabricated +foundry access. +1. Model SRAM macros, ports, wiring, clocking, memory PHYs, external memory, host and power +conversion. 2. Run place-and-route where available; mark unmodelled items as uncertainty rather than +zero. 3. Compare against a calibrated existing hardware block or equivalent validation case. +Pass. No decision-critical cost is omitted. Physically unvalidated or proprietary estimates are labelled and +independently bounded; synthesis alone cannot earn a manufactured-chip claim. +Evidence. Netlist/physical reports; macro assumptions; bill of materials; model calibration. + +ADV-06 GATE / P04; P12 / NOT RUN + +Separate process advantage from specialisation +Setup. Evaluate same-node, one-node-ahead and two-node-ahead scenarios with explicit technology +definitions. +1. Use independently justified process factors, voltages, memory and packaging assumptions for each +design. 2. Allow reusable IP and modular revisions; credit GPU improvement consistently. 3. Evaluate +measurement confidence and model-parameter sensitivity separately. +Pass. P04 primary limits hold for all competitive-reference cells; two-node futures are reported and pass +the predeclared economic stress envelope. A model range is never labelled a statistical confidence interval +without justification. +Evidence. Node-specific reports; factor provenance; uncertainty and sensitivity tables. + + + + +Source: 2.0 plan pp. 8, 10, 12, 22, 23. Procedures and P-profile thresholds are proposed. + +IGNEUM + MASTER 2.0 + 083 // PROPOSED + 292 / NOT EXECUTED 28 / 73 + TEST STANDARD / 1.0 + + + + +ADV / ADV-07 TO ADV-08 + + + +Programmable specialist +adversaries +Give the opponent permission to adapt, share resources and remain operational; test cost rather than +imagined chip death. + +Lead: Independent hardware team +Fixtures: F2 reference GPUs; F6 RTL/physical models; all published families +ADV-07 GATE / P04; P12 / NOT RUN + + +Evaluate lifetime without forced obsolescence +Setup. Assume multi-year productive survival and known schedule support before testing optional +retirement penalties. +1. Price firmware, emulation, memory expansion, companion hardware and incremental redesign. 2. Include +1-, 3- and 5-year productive lifetimes plus idle/resale possibilities. 3. Grant a retirement credit only if all +feasible cheaper adaptations lose competitiveness. +Pass. The primary case does not require chip death or a fresh full development bill per family. Every +retirement credit has a documented adaptation comparison; incompatible and unprofitable are reported +separately. +Evidence. Lifetime/adaptation ledger; revision costs; feasible-alternative analysis. + +ADV-08 GATE / P04 / NOT RUN + +Independently challenge the best-cost envelope +Setup. Publish the non-sensitive model and negative results; commission an unaffiliated second hardware +reviewer. +1. Reward cheaper valid designs and reproduced shortcuts, not confirmation of the preferred number. 2. +Re-run P04 with the strongest submitted feasible design, including a low-cost funded-development case. 3. +Record unresolved modelling disagreements and future technology exclusions. +Pass. Both reviews accept the scoped envelope or all material disagreements are resolved transparently. +Passing supports only evaluated designs and conditions, never a universal bound on all future silicon. +Evidence. Two review reports; challenge log; final envelope; unresolved-limit statement. + + + + SUITE CLOSE / ADV + + + Confirm the frozen release and P-profiles, all positive/negative controls, complete raw artifacts and + independent review. A missing result is not a pass. Re-run affected cases after relevant changes. + + + +Execution owner: ____________________ Review: ____________________ +Evidence root: _______________________ Decision: NOT RUN + + + + +Source: 2.0 plan pp. 8, 10, 12, 22, 23. Procedures and P-profile thresholds are proposed. + +IGNEUM + MASTER 2.0 + 084 // PROPOSED + 292 / NOT EXECUTED 29 / 73 + TEST STANDARD / 1.0 + + + + +ROT / ROT-01 TO ROT-03 + + + +Epochs, seeds and memory +transitions +Transitions must agree across nodes and remain usable during failures; crossing a boundary is not a +chip-retirement test. + +Lead: Consensus + GPU leads +Fixtures: F0 activation rules; F4 fault network; F5 historical and boundary vectors +ROT-01 BLOCKER / P01; P08 / NOT RUN + + +Agree across every hourly boundary +Setup. Use real nodes, CPU/GPU miners and independent clocks around successive program boundaries. +1. Submit valid work immediately before, at and after the activation boundary under clock skew and delayed +delivery. 2. Restart nodes from both sides and replay the same headers. 3. Compare selected seed, +program, validity, rewards and local wall-clock dependence. +Pass. All honest nodes derive identical consensus outcomes from the frozen rule. Late work is handled +exactly as specified; no wall-clock ambiguity or cross-backend split occurs. +Evidence. Boundary vectors; node/miner traces; acceptance and reward matrix. + +ROT-02 BLOCKER / P01; P03; P08 / NOT RUN + +Cross weekly and family boundaries together +Setup. Use the retained schedule in F0, including coincident program, parameter and family changes. +1. Run every known family transition and all coincident-boundary combinations on production code. 2. +Interrupt downloads, compilation and restart during activation; include mixed old/new clients. 3. Repeat +selected cases under real elapsed time and the remainder under disclosed accelerated time. +Pass. Deterministic activation, documented old-client behaviour and no unsafe fallback. Compilation/setup +costs satisfy P03; accelerated runs are not reported as years of operating history. +Evidence. Transition matrix; code-path evidence; compile timing; old-client logs. + +ROT-03 BLOCKER / P00; P01; P08 / NOT RUN + +Test miner-voted bring-forward governance +Setup. Freeze eligibility, threshold, windows and activation semantics before testing; do not invent a +no-veto rule. +1. Attempt threshold-minus-one, threshold, conflicting proposals, duplicate votes and coalition withholding. +2. Partition voters, restore them and test vote-key substitution through pools. 3. Verify adoption and refusal +behaviour of already running nodes. +Pass. The actual mechanism enforces F0, with authenticated voting and no conflicting activation. Any +coalition capable of blocking or manipulating changes is disclosed; labels such as no veto do not override +arithmetic. +Evidence. Executable governance model; signed-vote corpus; coalition/partition results. + + + + +Source: 2.0 plan pp. 7, 11, 19, 21. Procedures and P-profile thresholds are proposed. + +IGNEUM + MASTER 2.0 + 085 // PROPOSED + 292 / NOT EXECUTED 30 / 73 + TEST STANDARD / 1.0 + + + + +ROT / ROT-04 TO ROT-06 + + + +Epochs, seeds and memory +transitions +Transitions must agree across nodes and remain usable during failures; crossing a boundary is not a +chip-retirement test. + +Lead: Consensus + GPU leads +Fixtures: F0 activation rules; F4 fault network; F5 historical and boundary vectors +ROT-04 BLOCKER / P00; P01; P08 / NOT RUN + + +Resist seed selection and faster evaluators +Setup. Provide the specified seed pipeline and delay proof implementation plus independently +parameterised fast-adversary models. +1. Try withholding candidate seeds, grinding alternatives, replaying delay proofs and biased checkpoint +selection. 2. Vary adversarial speed advantage and outage duration; trace influence on program choice. 3. +Validate inputs, parameters and proofs against independent vectors. +Pass. No invalid seed or proof is accepted; selection advantage stays within the approved threat-model +bound. Missing bounds block this gate. A delay mechanism is not credited as generic ASIC resistance. +Evidence. Seed/grinding simulations; speed sensitivity; proof vectors; threat-model signoff. + +ROT-05 BLOCKER / P01; P08 / NOT RUN + +Continue or pause correctly when finality stops +Setup. Stop checkpoint signing while mining continues, then cross seed and family boundaries. +1. Remove the required signing weight and observe the documented fallback or safe pause. 2. Prevent +access to any founder seed service; restart from persisted state. 3. Restore the stated fault assumptions +and verify deterministic recovery. +Pass. Mining/seed behaviour matches F0 without manufacturing certificates or reinterpreting finality. Safety +holds during the outage; liveness is required only after its stated assumptions return. +Evidence. Fault timeline; seed/certificate history; node-state comparison; recovery log. + +ROT-06 BLOCKER / P01; P06 / NOT RUN + +Activate datasets without hidden exclusions +Setup. Freeze memory sizes, support horizon and sync/update procedure; test all advertised roles. +1. Construct the next dataset while current work remains active; test slow disks, low free memory and +interruption. 2. Try stale-state/dataset submissions and maliciously expensive state growth where coupling +exists. 3. Measure data transfer, restart and excluded-card costs before approving progression. +Pass. No invalid stale work is accepted, no supported card silently fails, and P06 is met. Hardware +retirement and sync burden are included in the economic decision, not treated as automatic chip protection. +Evidence. Dataset hashes; memory/update traces; stale-work tests; exclusion decision. + + + + +Source: 2.0 plan pp. 7, 11, 19, 21. Procedures and P-profile thresholds are proposed. + +IGNEUM + MASTER 2.0 + 086 // PROPOSED + 292 / NOT EXECUTED 31 / 73 + TEST STANDARD / 1.0 + + + + +ROT / ROT-07 TO ROT-08 + + + +Epochs, seeds and memory +transitions +Transitions must agree across nodes and remain usable during failures; crossing a boundary is not a +chip-retirement test. + +Lead: Consensus + GPU leads +Fixtures: F0 activation rules; F4 fault network; F5 historical and boundary vectors +ROT-07 GATE / P03; P04 / NOT RUN + + +Ablate redundant rotation layers +Setup. Use matched baseline and ablated variants in the lab; do not change a running public network. +1. Remove each weekly/family component independently and measure adversarial cost, GPU setup and +verifier complexity. 2. Include favourable-period specialists and all retained known families. 3. Keep a layer +only with a distinct, independently supported benefit or a documented non-resistance purpose. +Pass. Every retained layer has explicit justification and full boundary coverage. Redundant complexity is +removed or its rationale recorded; the security model does not double-count the same versatility cost. +Evidence. Ablation report; decision log; complexity/cost comparison. + +ROT-08 GATE / P04; P12 / NOT RUN + +Pass the no-new-rules counterfactual +Setup. Freeze the complete published rule bank and known schedule for the five-year evaluation. +1. Allow a programmable adversary to know and survive all planned changes. 2. Remove assumed future +emergency instructions and manual retirement actions from the model. 3. Run the required ECO scenarios +and link them to independent network-transition tests. +Pass. Competitiveness survives the approved envelope without future rescue assumptions. Any result that +needs unannounced changes fails this claim; ordinary bug maintenance is distinguished from anti-chip +intervention. +Evidence. Frozen-rule model; scenario results; excluded-rescue audit; G5 evidence. + + + + SUITE CLOSE / ROT + + + Confirm the frozen release and P-profiles, all positive/negative controls, complete raw artifacts and + independent review. A missing result is not a pass. Re-run affected cases after relevant changes. + + + +Execution owner: ____________________ Review: ____________________ +Evidence root: _______________________ Decision: NOT RUN + + + + +Source: 2.0 plan pp. 7, 11, 19, 21. Procedures and P-profile thresholds are proposed. + +IGNEUM + MASTER 2.0 + 087 // PROPOSED + 292 / NOT EXECUTED 32 / 73 + TEST STANDARD / 1.0 + + + + +ECO / ECO-01 TO ECO-03 + + + +Five-year coexistence economics +Test the world after specialised hardware exists, including new entrants and an already-funded +competitor. + +Lead: Economics lead + independent reviewer +Fixtures: F6 adversarial costs; F7 scenario model; F2 operator costs +ECO-01 GATE / P12 / NOT RUN + + +Reconcile complete cost per accepted work +Setup. Use benchmark outputs, current-source cost inputs recorded at execution time and separate +reference scenarios. +1. Calculate hardware annualisation, electricity, host, cooling/hosting, failures, fees, downtime and residual +value. 2. Use actual accepted work and independently verify units and period conversions. 3. Cross-check +formulas using hand-worked fixtures, edge cases and a second implementation. +Pass. All material costs and rejected-work effects appear once; model totals reconcile to raw inputs. No +GPU upgrade is free, development cost is not double-counted, and burn is not mislabelled operator income. +Evidence. Versioned model; unit fixtures; independent reconciliation; input sources. + +ECO-02 GATE / P12 / NOT RUN + +Separate existing-owner and new-entrant viability +Setup. Use both installed hardware and purchasable replacement hardware in every mandatory cohort. +1. Evaluate marginal operation separately from recovery of a new purchase. 2. Stress resale at zero, +hardware failures, financing and replacement cycles. 3. Report break-even power price and total cost +relative to the strongest feasible specialist. +Pass. P12 competitiveness conditions hold for the predeclared cohorts in required sustainable worlds. +Existing-owner profitability cannot substitute for viable new entry; cards outside the envelope remain +visible. +Evidence. Owner/entrant curves; price-date records; break-even tables; cohort outcomes. + +ECO-03 GATE / P12 / NOT RUN + +Let the specialist keep its sunk development +Setup. Use three development cases: fully funded elsewhere, source-range low and source-range high. +1. Evaluate private mining, public hardware sales and a hybrid business model. 2. Allow shared IP, +incremental revisions, multi-year survival and resale where justified. 3. Re-evaluate GPU entry after the +specialist fleet is already installed. +Pass. The coexistence claim does not depend on recovering the original chip research bill. Required P12 +cases meet the approved envelope even at zero incremental development cost; failures cannot be hidden by +the $23M/$340M source thresholds. +Evidence. Business-model variants; sunk-cost case; full cash-flow and adaptation records. + + + + +Source: 2.0 plan pp. 8, 13, 18, 24, 26. Procedures and P-profile thresholds are proposed. + +IGNEUM + MASTER 2.0 + 088 // PROPOSED + 292 / NOT EXECUTED 33 / 73 + TEST STANDARD / 1.0 + + + + +ECO / ECO-04 TO ECO-06 + + + +Five-year coexistence economics +Test the world after specialised hardware exists, including new entrants and an already-funded +competitor. + +Lead: Economics lead + independent reviewer +Fixtures: F6 adversarial costs; F7 scenario model; F2 operator costs +ECO-04 GATE / P12 / NOT RUN + + +Model entry, exit and difficulty response +Setup. Use independently reviewed dynamic operator policies, not fixed market shares. +1. Let agents buy, sell, switch off, re-enter and choose tasks based on declared costs and expected income. +2. Apply the actual difficulty/reward rules and test optimistic and adversarial liquidity/capital availability. 3. +Compare equilibrium and transient outcomes across independent starting conditions. +Pass. Mandatory worlds satisfy P12 without an imposed GPU share or artificial specialist capacity limit. +Concentration, oscillations and excluded regions are reported; model behaviour matches unit and +conservation checks. +Evidence. Agent policies; sensitivity seeds; market-share paths; independent model review. + +ECO-05 GATE / P12 / NOT RUN + +Stress success, contraction and cheap electricity +Setup. Freeze mandatory scenarios before results: revenue bands, tariff range, lifetimes and demand states. +1. Run the P12 factorial grid plus adversarial combinations selected by the independent reviewer. 2. Test a +large successful network as well as weak-revenue and heterogeneous-tariff cases. 3. Distinguish feasible +sustained-entry worlds from collapse scenarios with no rational profitable operator. +Pass. No small-network or token-appreciation assumption props up the primary claim. Required viable +worlds pass the envelope; collapse worlds show honest contraction and safety, not fabricated profits. +Failure regions are explicit. +Evidence. Scenario register; full result cube; boundary plots; failed-world explanations. + +ECO-06 GATE / P12 / NOT RUN + +Fund security and proving as issuance falls +Setup. Use the frozen supply, halving, fee, burn and reward rules rather than source prose assumptions. +1. Reconcile revenue reaching miners, internal provers, developers and burns over the full horizon. 2. Test +flat/declining fees and no external proving income; separately introduce external demand. 3. Calculate +capacity and security-provider coverage after each reward transition. +Pass. Recurring compensation is explicit and internally consistent; mandatory sustainable scenarios meet +P12. Burned amounts are never counted as payments, and external operator income is not assumed to fund +internal work automatically. +Evidence. Issuance/fee ledger; scenario cash flows; funding-shortfall report. + + + + +Source: 2.0 plan pp. 8, 13, 18, 24, 26. Procedures and P-profile thresholds are proposed. + +IGNEUM + MASTER 2.0 + 089 // PROPOSED + 292 / NOT EXECUTED 34 / 73 + TEST STANDARD / 1.0 + + + + +ECO / ECO-07 TO ECO-08 + + + +Five-year coexistence economics +Test the world after specialised hardware exists, including new entrants and an already-funded +competitor. + +Lead: Economics lead + independent reviewer +Fixtures: F6 adversarial costs; F7 scenario model; F2 operator costs +ECO-07 GATE / P06; P12 / NOT RUN + + +Price memory growth and honest-card displacement +Setup. Use GPU-05 and ROT-06 costs with the cheapest specialist adaptation. +1. For each dataset increment, compare specialist cost increases with excluded cards and lost proving +capacity. 2. Include ordinary-owner replacement, resale and reloading expenses. 3. Run alternate bounded +schedules without assigning automatic chip death. +Pass. The retained schedule meets P06/P12 and has an evidence-backed net competitiveness benefit. A +schedule that mainly harms accessible GPUs fails; excluded tiers and mitigations are documented before +activation. +Evidence. Per-step cost/retention table; alternative schedules; approval record. + +ECO-08 GATE / P12 / NOT RUN + +Reproduce and adversarially audit the model +Setup. Give an independent economist or qualified analyst the code, inputs and frozen success criteria. +1. Recalculate required worlds and perturb favourable assumptions against the team. 2. Check dependence +on discounts, utilisation, capital limits, artificial prices and future upgrades. 3. Publish the sensitivity range +and state which conclusions are conditional. +Pass. Material results reproduce, required scenarios pass and no unacknowledged assumption dominates +the claim. The model supports a bounded coexistence conclusion, not a percentage probability that no chip +will appear. +Evidence. Independent report; rerun outputs; model limitations; approved claim envelope. + + + + SUITE CLOSE / ECO + + + Confirm the frozen release and P-profiles, all positive/negative controls, complete raw artifacts and + independent review. A missing result is not a pass. Re-run affected cases after relevant changes. + + + +Execution owner: ____________________ Review: ____________________ +Evidence root: _______________________ Decision: NOT RUN + + + + +Source: 2.0 plan pp. 8, 13, 18, 24, 26. Procedures and P-profile thresholds are proposed. + +IGNEUM + MASTER 2.0 + 090 // PROPOSED + 292 / NOT EXECUTED 35 / 73 + TEST STANDARD / 1.0 + + + + +EVM / EVM-01 TO EVM-03 + + + +Execution and developer +compatibility +Keep familiar applications while making every difference and metering rule explicit and reproducible. + +Lead: Execution lead + independent implementer +Fixtures: F0 execution-fork semantics; F5 transactions/contracts; F4 multi-node network +EVM-01 BLOCKER / P01; P09 / NOT RUN + + +Match the selected EVM semantics +Setup. Pin the intended execution fork, revm version and all Igneum deviations in F0. +1. Run the applicable upstream execution/state fixtures plus independently written deviation tests. 2. +Execute identical blocks on multiple nodes and compare roots, receipts, logs, gas and failure outcomes. 3. +Minimise mismatches and distinguish intended differences from implementation defects. +Pass. All applicable vectors match; every deviation has a documented test and developer consequence. No +claim of universal Ethereum equivalence or Ethereum settlement security is inferred. +Evidence. Fixture/version inventory; root/receipt diffs; deviation matrix. + +EVM-02 BLOCKER / P01 / NOT RUN + +Preserve transaction binding and replay protection +Setup. Use signed transfers, contract calls and deployment transactions with boundary field values. +1. Alter chain identity, nonce, signature, fee caps and recipient after signing. 2. Replay across nodes, forks +and distinct test networks; resubmit around reorganisation. 3. Check mempool admission and final +consensus execution independently. +Pass. Unauthorised, wrong-network or duplicate spends are rejected according to F0. Valid replacements +follow the declared rule; mempool filtering alone is not evidence of consensus enforcement. +Evidence. Signed corpus; admission/execution outcomes; account-state reconciliation. + +EVM-03 BLOCKER / P01; P09 / NOT RUN + +Test two-dimensional fees and proving limits +Setup. Freeze fee dimensions, estimator rules, abort behaviour and refund policy. +1. Run workloads near and beyond execution and proving budgets, including state-heavy pathological cases. +2. Compare estimated fees with charged fees and validate rollback/receipt status on abort. 3. Mutate a +block producer to omit or undercharge expensive work. +Pass. Deterministic metering, charged amounts and aborted state agree across nodes and proofs. Resource +bounds hold; fee estimates meet P09 for accepted supported cases. Undercharged invalid blocks cannot +bypass consensus. +Evidence. Metering traces; fee fixtures; estimator errors; invalid-block rejection. + + + + +Source: 2.0 plan pp. 15, 25, 34, 35, 36, 37. Procedures and P-profile thresholds are proposed. + +IGNEUM + MASTER 2.0 + 091 // PROPOSED + 292 / NOT EXECUTED 36 / 73 + TEST STANDARD / 1.0 + + + + +EVM / EVM-04 TO EVM-06 + + + +Execution and developer +compatibility +Keep familiar applications while making every difference and metering rule explicit and reproducible. + +Lead: Execution lead + independent implementer +Fixtures: F0 execution-fork semantics; F5 transactions/contracts; F4 multi-node network +EVM-04 BLOCKER / P01; P09 / NOT RUN + + +Exercise block context and randomness assumptions +Setup. Use contracts sensitive to timestamp, height/context, randomness and ordering. +1. Compare the declared Igneum semantics with developers' documented expectations. 2. Test boundary +transitions, miner-influenced inputs and adversarial ordering in the isolated network. 3. Run dependency +reviews for applications using these values for economic decisions. +Pass. Semantics match F0 and differences are surfaced in compatibility documentation. No source of miner +influence is marketed as unbiased randomness; incompatible applications are not included in the +compatibility claim. +Evidence. Context-contract results; threat notes; compatibility exclusions. + +EVM-05 BLOCKER / P01; P09 / NOT RUN + +Run representative contract integration journeys +Setup. Use versioned transfer/token, NFT, multisignature, exchange and upgrade-pattern fixtures where +supported. +1. Deploy, initialise, transact, revert and upgrade each contract using ordinary tooling. 2. Exercise events, +logs, balances, storage and call traces across node restart/reorganisation. 3. Compare expected application +invariants with native execution and proved results. +Pass. Supported journeys preserve their stated invariants; all deviations are documented. Example +deployment success alone cannot stand in for application-level correctness or financial audit. +Evidence. Contract fixture hashes; transaction journeys; invariant and state comparisons. + +EVM-06 BLOCKER / P01; P09 / NOT RUN + +Validate wallets, RPC and indexers +Setup. Pin supported RPC methods and response semantics; use normal developer clients and an +independent indexer. +1. Test fee estimation, pending/final states, subscriptions, pagination and reconnects. 2. Reindex from +genesis or the documented trust anchor after pruning and restart. 3. Compare logs, receipts and balances +with independently validated chain state. +Pass. No missing/duplicate canonical records; unsupported methods are explicit. UI states distinguish +included, executed, proven and finalised. Malformed RPC input cannot crash validators or leak secrets. +Evidence. RPC conformance report; reindex comparison; reconnect/edge-case logs. + + + + +Source: 2.0 plan pp. 15, 25, 34, 35, 36, 37. Procedures and P-profile thresholds are proposed. + +IGNEUM + MASTER 2.0 + 092 // PROPOSED + 292 / NOT EXECUTED 37 / 73 + TEST STANDARD / 1.0 + + + + +EVM / EVM-07 TO EVM-08 + + + +Execution and developer +compatibility +Keep familiar applications while making every difference and metering rule explicit and reproducible. + +Lead: Execution lead + independent implementer +Fixtures: F0 execution-fork semantics; F5 transactions/contracts; F4 multi-node network +EVM-07 BLOCKER / P01; P09 / NOT RUN + + +Handle execution denial-of-service workloads +Setup. Create bounded pathological bytecode, calls, state growth, storage and precompile inputs. +1. Measure CPU, memory, disk and proving cost against charged budgets. 2. Saturate admission with +invalid/expensive requests while valid workloads continue. 3. Restart mid-execution and verify atomic state +recovery. +Pass. P09 limits hold with no unbounded free work or divergent rollback. State remains consistent after +crash; availability under overload follows the declared admission policy, not silent dropping of accepted +transactions. +Evidence. Resource profiles; adversarial corpus; state recovery comparisons. + +EVM-08 BLOCKER / P01; P08; P09 / NOT RUN + +Verify controlled execution and verifier upgrades +Setup. Prepare two authorised versions and malicious, stale or unknown versions. +1. Cross activation with mixed clients, queued transactions and proofs from both versions. 2. Bind each +accepted proof to the correct execution semantics and program identity. 3. Exercise a failed software +distribution without altering consensus activation. +Pass. No unknown or wrong-version execution is accepted. Pre/post-boundary handling is deterministic and +documented; software delivery cannot silently redefine transaction semantics or proof acceptance. +Evidence. Upgrade vectors; mixed-version traces; manifest/version bindings. + + + + SUITE CLOSE / EVM + + + Confirm the frozen release and P-profiles, all positive/negative controls, complete raw artifacts and + independent review. A missing result is not a pass. Re-run affected cases after relevant changes. + + + +Execution owner: ____________________ Review: ____________________ +Evidence root: _______________________ Decision: NOT RUN + + + + +Source: 2.0 plan pp. 15, 25, 34, 35, 36, 37. Procedures and P-profile thresholds are proposed. + +IGNEUM + MASTER 2.0 + 093 // PROPOSED + 292 / NOT EXECUTED 38 / 73 + TEST STANDARD / 1.0 + + + + +ZKP / ZKP-01 TO ZKP-03 + + + +Consensus-enforced proof validity +The validator, not merely the official producer, must reject unauthorised or invalid proof records and +rewards. + +Lead: Proving + protocol leads; independent cryptography review +Fixtures: F0 pinned programs/verifiers; F5 valid and hostile proof corpus; unmodified validators +ZKP-01 BLOCKER / P01; P09 / NOT RUN + + +Reject missing and invalid proofs +Setup. Start from a native-correct statement and an independently verified valid proof. +1. Submit the statement with no proof, truncated bytes, random bytes and targeted proof mutations using a +modified producer. 2. Submit the genuine proof as a positive control through ordinary network paths. 3. +Inspect block acceptance and resulting reward/state on unmodified validators. +Pass. Every invalid proof record is rejected and earns no reward; valid controls succeed. A producer-side +filter is not sufficient. Record rejection semantics exactly as defined by F0. +Evidence. Hostile record corpus; validator decisions; before/after balances; positive controls. + +ZKP-02 BLOCKER / P01; P09 / NOT RUN + +Bind program, verifier and security parameters +Setup. Use valid proofs from authorised and unauthorised programs and parameter sets. +1. Swap program digest, verifier version, security settings and verification key where applicable. 2. Attempt +downgrade through configuration, serialized metadata or an old node path. 3. Test authorised boundary +transitions and unsupported future identities. +Pass. Only explicitly authorised combinations are accepted in the correct epoch. No implicit trust in +producer-supplied metadata or lower-security fallback; all accepted settings have scoped soundness +review. +Evidence. Identity/parameter matrix; rejection traces; cryptographic review. + +ZKP-03 BLOCKER / P01 / NOT RUN + +Bind network, epoch, job and state roots +Setup. Prepare valid proofs for distinct chains, epochs, jobs and initial/final states. +1. Replay each proof under another network, job, epoch, shard range or state commitment. 2. Alter public +inputs while retaining the proof and test valid-but-wrong-context statements. 3. Check duplicated and +reordered records across forks and replayed sync data. +Pass. Every misbound proof is rejected; valid authorised replays follow only explicitly allowed semantics +and never create extra rewards. Native reexecution cannot conceal missing proof-context binding. +Evidence. Binding matrix; public-input hashes; replay traces; reward reconciliation. + + + + +Source: 2.0 plan pp. 16, 20, 24, 25, 36, 37. Procedures and P-profile thresholds are proposed. + +IGNEUM + MASTER 2.0 + 094 // PROPOSED + 292 / NOT EXECUTED 39 / 73 + TEST STANDARD / 1.0 + + + + +ZKP / ZKP-04 TO ZKP-06 + + + +Consensus-enforced proof validity +The validator, not merely the official producer, must reject unauthorised or invalid proof records and +rewards. + +Lead: Proving + protocol leads; independent cryptography review +Fixtures: F0 pinned programs/verifiers; F5 valid and hostile proof corpus; unmodified validators +ZKP-04 BLOCKER / P01 / NOT RUN + + +Prevent reward and payout substitution +Setup. Use proofs that commit to authorisation and all reward-relevant fields required by F0. +1. Alter payout key, amount, beneficiary, source work or fee allocation independently. 2. Supply correct +execution over malicious producer-provided consensus/reward inputs. 3. Compare consensus-derived +rewards with the proved/publicly authenticated derivation. +Pass. Unauthorised payout changes and incorrect consensus inputs are rejected; no statement accepted +merely because execution over supplied inputs is internally correct. Legitimate authorisations are +preserved. +Evidence. Mutation cases; reward derivation trace; signature/proof binding review. + +ZKP-05 BLOCKER / P01 / NOT RUN + +Make proof payment idempotent across races +Setup. Use competing provers submitting valid results for the same work and simulate +retries/reorganisations. +1. Submit simultaneous duplicates, reordered receipts and repeated messages after disconnects. 2. Crash +validators between validation and reward application, then recover. 3. Reconcile canonical payouts against +the exact F0 duplicate policy. +Pass. Only the authorised total payment is made; no double payout, lost accepted entitlement or +fork-retained balance. Transactions and payout records recover atomically. +Evidence. Concurrency schedule; canonical payment ledger; crash/recovery evidence. + +ZKP-06 BLOCKER / P01; P09 / NOT RUN + +Verify aggregation coverage and completeness +Setup. Build valid multi-shard workloads plus omitted, duplicated, overlapping and misordered shard sets. +1. Attempt an aggregate with a correct outer proof but wrong coverage/public-input construction. 2. Alter +shard ranges, roots and aggregation-program identity. 3. Verify native execution, aggregate validity and +coverage commitments independently. +Pass. Only complete, correctly ordered authorised coverage is accepted. No valid proof of the wrong +computation becomes an accepted chain result; aggregation failures do not fabricate successful delivery. +Evidence. Coverage corpus; aggregate/public-input verification; rejection ledger. + + + + +Source: 2.0 plan pp. 16, 20, 24, 25, 36, 37. Procedures and P-profile thresholds are proposed. + +IGNEUM + MASTER 2.0 + 095 // PROPOSED + 292 / NOT EXECUTED 40 / 73 + TEST STANDARD / 1.0 + + + + +ZKP / ZKP-07 TO ZKP-08 + + + +Consensus-enforced proof validity +The validator, not merely the official producer, must reject unauthorised or invalid proof records and +rewards. + +Lead: Proving + protocol leads; independent cryptography review +Fixtures: F0 pinned programs/verifiers; F5 valid and hostile proof corpus; unmodified validators +ZKP-07 BLOCKER / P01; P09 / NOT RUN + + +Review soundness and verifier resource limits +Setup. Provide proof-system code, parameters, patches and the pinned verification path to an independent +specialist. +1. Review soundness assumptions, parameter margins and consequences of performance patches. 2. Fuzz +deserialization and adversarial proofs; measure verification CPU and memory under load. 3. Cross-check an +independent verifier or reference path and test crash containment. +Pass. P09 review and resource requirements pass with no unresolved critical/high finding. Random proof +rejection counts are not described as evidence of a particular cryptographic security level. +Evidence. Scoped soundness review; parameter sheet; fuzzer corpus; verifier profiles. + +ZKP-08 BLOCKER / P01; P07; P08 / NOT RUN + +Preserve authority and audit all acceptance paths +Setup. Inspect block import, sync, RPC, light verification, database restoration and fast paths. +1. Try bypassing validation via each path with a proof rejected by the normal path. 2. Remove the dominant +prover/aggregator and have independent replacements process available inputs. 3. Attempt to use +proof-production status as ordering, voting or finality authority. +Pass. No bypass accepts invalid work; proofs alone confer no unauthorised consensus control. Replacement +and pause behaviour meet F0/P07/P08 without privileged keys or a trusted aggregator shortcut. +Evidence. Path coverage report; bypass corpus; replacement run; authority checks. + + + + SUITE CLOSE / ZKP + + + Confirm the frozen release and P-profiles, all positive/negative controls, complete raw artifacts and + independent review. A missing result is not a pass. Re-run affected cases after relevant changes. + + + +Execution owner: ____________________ Review: ____________________ +Evidence root: _______________________ Decision: NOT RUN + + + + +Source: 2.0 plan pp. 16, 20, 24, 25, 36, 37. Procedures and P-profile thresholds are proposed. + +IGNEUM + MASTER 2.0 + 096 // PROPOSED + 292 / NOT EXECUTED 41 / 73 + TEST STANDARD / 1.0 + + + + +CAP / CAP-01 TO CAP-03 + + + +Sustained proving and delivery +A correct fast shard is only one stage; capacity, latency, payment and retries must work together. + +Lead: Proving lead + independent operators +Fixtures: F3 meaningful workload catalogue; F4 network; F8 external job harness +CAP-01 GATE / P02; P07 / NOT RUN + + +Reproduce the historical consumer-shard result +Setup. Recover the exact source-era workload/build if available; keep it separate from the +release-candidate workload. +1. Attempt independent reproduction of the 4,717,439-cycle workload and reported 3060/4060/4070 +results. 2. Record proof format, memory, energy, host and whether aggregation/compression are included. +3. Repeat on the final release and label all configuration changes. +Pass. Historical figures are either reproduced within P02 tolerance or corrected/labelled non-reproduced. +Release acceptance uses the current complete workload, never an unmatched historical time or a smaller +substituted shard. +Evidence. Historical/current manifests; proof verification; timing and memory records. + +CAP-02 BLOCKER / P01; P06; P07 / NOT RUN + +Prove on the actual mining configuration +Setup. Use final dataset sizes, registers, clocks, drivers and proof pipeline on every advertised proving tier. +1. Run mining alone, proving alone, concurrent execution and supported time-sharing. 2. Measure wall +energy, memory headroom, reloads, proof latency and forgone accepted mining work. 3. Induce memory +pressure and GPU task failure without losing wallet control. +Pass. Every advertised mode completes correctly and meets P06/P07. Net output includes opportunity +cost; unsupported concurrency is not claimed. Mining-only vendor support remains separately labelled. +Evidence. Four-mode results; OOM/failure logs; memory and opportunity-cost ledger. + +CAP-03 GATE / P07 / NOT RUN + +Measure the entire request-to-payment path +Setup. Assign a unique job ID and immutable timestamps to every stage of F3/F8 jobs. +1. Record request, input availability, assignment, execution, shard proof, aggregation, verification, delivery +and payment. 2. Compare monotonic elapsed time with any protocol/DAA clock and document their +relationship. 3. Reconcile failed, censored, retried and abandoned jobs with the original request +denominator. +Pass. No hidden stage or missing job; latency distributions and cost cover the complete path. Delivery, +finality and payment are reported separately; protocol seconds are not silently relabelled wall-clock +seconds. +Evidence. Stage event ledger; clock calibration; end-to-end latency/cost report. + + + + +Source: 2.0 plan pp. 17, 18, 24, 25. Procedures and P-profile thresholds are proposed. + +IGNEUM + MASTER 2.0 + 097 // PROPOSED + 292 / NOT EXECUTED 42 / 73 + TEST STANDARD / 1.0 + + + + +CAP / CAP-04 TO CAP-06 + + + +Sustained proving and delivery +A correct fast shard is only one stage; capacity, latency, payment and retries must work together. + +Lead: Proving lead + independent operators +Fixtures: F3 meaningful workload catalogue; F4 network; F8 external job harness +CAP-04 GATE / P07 / NOT RUN + + +Sustain meaningful load without queue growth +Setup. Freeze W: payload mix, input sizes, execution work and per-hour demand; prohibit tiny-workload +substitution. +1. Run 72 hours at W and a separate 24 hours at 1.2W on the declared fleet. 2. Measure arrival/completion +counts, backlog trend, oldest-job age, deadlines and all retries. 3. Use held-out workloads and an +independent observer to detect discarded or delayed requests. +Pass. P07 completion, tail-latency and bounded-backlog criteria hold. Capacity is stated for the tested +W/fleet, not as universal TPS. A queue that grows indefinitely or shrinks through silent loss fails. +Evidence. Request/completion reconciliation; backlog series; held-out results; observer report. + +CAP-05 BLOCKER / P01; P07 / NOT RUN + +Overload and recover without false acceptance +Setup. Start at W and inject 2W for 15 minutes with valid and invalid jobs, then return to W. +1. Observe admission, explicit backpressure, reservations and deadline estimates. 2. Track accepted jobs to +valid completion or the pre-agreed failure/refund outcome. 3. Measure recovery time and ensure ordinary +users are not silently starved. +Pass. P07 overload policy and recovery limits hold; no accepted job vanishes or earns an invalid reward. +Rejected demand is reported separately from delivery success, preventing denominator manipulation. +Evidence. Overload timeline; admission/refund logs; backlog-drain proof. + +CAP-06 GATE / P07; P12 / NOT RUN + +Calibrate assignment windows to paid completion +Setup. Use a heterogeneous proving fleet, including the slowest advertised consumer tier. +1. Measure actual completion distributions with network delay, competing load and failed attempts. 2. Test +the chosen exclusive window, open claiming and faster challengers after expiry. 3. Compare assignment +frequency, paid completions and wasted work by tier. +Pass. P07 fairness and wasted-work limits hold for advertised tiers. A provisional 10-DAA-second window is +not treated as approved. Fair assignment counts alone cannot pass; payment outcomes and operator +margins matter. +Evidence. Window sweep; paid-completion distribution; wasted-work and margin report. + + + + +Source: 2.0 plan pp. 17, 18, 24, 25. Procedures and P-profile thresholds are proposed. + +IGNEUM + MASTER 2.0 + 098 // PROPOSED + 292 / NOT EXECUTED 43 / 73 + TEST STANDARD / 1.0 + + + + +CAP / CAP-07 TO CAP-08 + + + +Sustained proving and delivery +A correct fast shard is only one stage; capacity, latency, payment and retries must work together. + +Lead: Proving lead + independent operators +Fixtures: F3 meaningful workload catalogue; F4 network; F8 external job harness +CAP-07 BLOCKER / P01; P07; P08 / NOT RUN + + +Reassign work when inputs or providers disappear +Setup. Remove input providers, assigned provers and the dominant aggregator independently and together. +1. Have replacement operators retrieve authenticated inputs without founder files. 2. Retry expired +assignments while preserving idempotent reward and customer outcomes. 3. Restore providers and test +late submissions racing with replacements. +Pass. P07/P08 replacement deadlines hold when availability assumptions permit. Otherwise a truthful +bounded pause/refund occurs; no fake proof, double payment or hidden privileged input source is used. +Evidence. Failure schedule; input hashes; reassignment and payout ledger; recovery trace. + +CAP-08 BLOCKER / P01; P07; P14 / NOT RUN + +Deliver customer-verifiable output at scale +Setup. Run the external workload using a customer-controlled verifier and independently operated workers. +1. Verify every delivered proof against the contracted program and input commitment. 2. Reject +wrong-format, stale and partial deliveries; test customer retry and delivery failure. 3. Reconcile delivery, +acceptance, payment and refund records without exposing private inputs publicly. +Pass. P07 delivery performance and exact validity hold. Payment depends on the contracted correct result; +a valid proof for the wrong job is not a successful delivery. +Evidence. Customer verification log; proof-format contract; settlement reconciliation. + + + + SUITE CLOSE / CAP + + + Confirm the frozen release and P-profiles, all positive/negative controls, complete raw artifacts and + independent review. A missing result is not a pass. Re-run affected cases after relevant changes. + + + +Execution owner: ____________________ Review: ____________________ +Evidence root: _______________________ Decision: NOT RUN + + + + +Source: 2.0 plan pp. 17, 18, 24, 25. Procedures and P-profile thresholds are proposed. + +IGNEUM + MASTER 2.0 + 099 // PROPOSED + 292 / NOT EXECUTED 44 / 73 + TEST STANDARD / 1.0 + + + + +INC / INC-01 TO INC-03 + + + +Rewards, incentives and selfish +operators +Assume operators optimise their own returns. Do not depend on the official client choosing a less +profitable task. + +Lead: Protocol economics + proving leads +Fixtures: F0 fee/reward rules; F4 adversarial operators; F7 incentive models +INC-01 BLOCKER / P01; P12 / NOT RUN + + +Reconcile issuance, fees, burns and recipients +Setup. Use a deterministic short chain containing all reward types, fee paths and rounding cases. +1. Calculate balances, total supply changes, burns and distributions independently. 2. Execute identical +blocks natively and through the proving path. 3. Test zero, minimum, maximum and transition-boundary +values plus malformed producer accounting. +Pass. Conservation and recipient rules match F0 exactly; no inflation, rounding leakage or duplicate reward. +Fee-table and prose discrepancies are resolved before the run, not guessed by the tester. +Evidence. Independent accounting ledger; balance/supply diffs; boundary vectors. + +INC-02 BLOCKER / P01; P12; P14 / NOT RUN + +Keep revenue streams and claims separate +Setup. Prepare jobs and blocks producing mining income, internal proof rewards and external payments. +1. Trace money from source to operator, protocol, developer and any burn. 2. Compare node records, +settlement records and Ember displays. 3. Attempt to classify testnet rewards, reimbursed purchases or +token appreciation as external customer revenue. +Pass. Every stream reconciles and is labelled correctly. No double-counted revenue or fabricated protocol +demand; mining subsidy and external service income remain distinct in dashboards and ECO. +Evidence. Money-flow register; UI reconciliation; rejected classifications. + +INC-03 GATE / P07; P12 / NOT RUN + +Let a modified client choose the most profitable task +Setup. Permit independent schedulers to mine, prove internally, prove externally or switch off. +1. Publish common costs and vary relative task rewards, memory pressure and switching costs. 2. Run +clients that ignore the official scheduling recommendation. 3. Measure realised operator margin, internal +capacity and network progress. +Pass. Required P12 sustainable worlds maintain paid essential capacity without compelled altruism. +Profitability and availability are based on realised outcomes, including switching and wasted work. +Evidence. Scheduler source/policies; switching traces; capacity and margin series. + + + + +Source: 2.0 plan pp. 13, 16, 17, 18, 24, 26. Procedures and P-profile thresholds are proposed. + +IGNEUM + MASTER 2.0 + 100 // PROPOSED + 292 / NOT EXECUTED 45 / 73 + TEST STANDARD / 1.0 + + + + +INC / INC-04 TO INC-06 + + + +Rewards, incentives and selfish +operators +Assume operators optimise their own returns. Do not depend on the official client choosing a less +profitable task. + +Lead: Protocol economics + proving leads +Fixtures: F0 fee/reward rules; F4 adversarial operators; F7 incentive models +INC-04 GATE / P07; P08; P12 / NOT RUN + + +Survive external-demand spikes and token declines +Setup. Use F7 scenarios with 10x external job offers and token-denominated mining-income shocks. +1. Allow miners/provers to switch freely under the declared reward and difficulty rules. 2. Observe hash +participation, proof backlog, fees and recovery without an administrator. 3. Repeat with external demand +dropping to zero and with a dominant operator withdrawn. +Pass. Mandatory viable worlds meet P07/P12; stressed nonviable worlds fail or pause safely with truthful +status. No emergency rule, fabricated demand or unofficial subsidy is inserted to force a pass. +Evidence. Shock timeline; fee/hash/capacity paths; failure-region report. + +INC-05 BLOCKER / P01; P07; P09 / NOT RUN + +Contain job reservation and identity-splitting abuse +Setup. Freeze the actual assignment/payment mechanism; do not assume unimplemented collateral or +identity controls. +1. Create many worker identities, reserve jobs, withhold proofs and submit late results. 2. Attempt free +option-taking, duplicate work rewards and displacement of honest assignments. 3. Price attacker costs and +observe honest completion under the approved abuse load. +Pass. F0 rules and P07 service limits hold under the declared adversary. Identity splitting does not create +unauthorised rewards or control; any unmitigated starvation path blocks the permissionless-service claim. +Evidence. Attack clients; assignment trace; cost-to-disrupt analysis; honest-user outcomes. + +INC-06 BLOCKER / P01; P08; P12 / NOT RUN + +Test difficulty and timestamp manipulation +Setup. Use the actual adjustment algorithm and consensus timestamp rule with independent miners. +1. Inject large hashrate arrivals/departures, periodic selective mining and boundary-timed bursts. 2. Try +allowed and invalid timestamp skew, withheld blocks and replayed work. 3. Observe block intervals, reward +allocation and recovery after hashrate stabilises. +Pass. Invalid inputs are rejected; valid adversarial strategies remain within F0/P08 bounds and are priced in +ECO. No unexplained reward amplification, permanent stall or conflicting accepted work. +Evidence. Difficulty trace; timestamp corpus; revenue analysis; independent rule review. + + + + +Source: 2.0 plan pp. 13, 16, 17, 18, 24, 26. Procedures and P-profile thresholds are proposed. + +IGNEUM + MASTER 2.0 + 101 // PROPOSED + 292 / NOT EXECUTED 46 / 73 + TEST STANDARD / 1.0 + + + + +INC / INC-07 TO INC-08 + + + +Rewards, incentives and selfish +operators +Assume operators optimise their own returns. Do not depend on the official client choosing a less +profitable task. + +Lead: Protocol economics + proving leads +Fixtures: F0 fee/reward rules; F4 adversarial operators; F7 incentive models +INC-07 BLOCKER / P01; P12; P14 / NOT RUN + + +Resist self-dealing fees and fake proving demand +Setup. Use self-funded operators and related customer identities in the isolated economic model/network. +1. Cycle funds through jobs, tips, developer shares and rebates to seek net reward extraction. 2. Attempt to +inflate external-demand metrics without genuine unrelated customer expenditure. 3. Reconcile all +counterparties and net cash contribution rather than gross transaction volume. +Pass. No unauthorised subsidy extraction or metric inflation passes. Related-party volume is +disclosed/excluded from P14; net external cash and legitimate protocol incentives are reported separately. +Evidence. Circular-flow tests; ownership/conflict review; net-cash reconciliation. + +INC-08 GATE / P08; P11; P12 / NOT RUN + +Quantify provider and supplier failure concentration +Setup. Model control of hashing, signing, proving, aggregation and hardware supply separately. +1. Remove each largest operational dependency and combine correlated failures. 2. Measure replacement +cost/time and whether essential roles share hidden ownership. 3. Compare results with the approved fault +model and no-rescue exercise. +Pass. No hidden single dependency defeats the claimed independence; within-tolerance withdrawals +recover under P08/P11. Hardware supply concentration is disclosed without equating vendor sales to +operator voting control. +Evidence. Role/ownership map; dependency removals; recovery and concentration report. + + + + SUITE CLOSE / INC + + + Confirm the frozen release and P-profiles, all positive/negative controls, complete raw artifacts and + independent review. A missing result is not a pass. Re-run affected cases after relevant changes. + + + +Execution owner: ____________________ Review: ____________________ +Evidence root: _______________________ Decision: NOT RUN + + + + +Source: 2.0 plan pp. 13, 16, 17, 18, 24, 26. Procedures and P-profile thresholds are proposed. + +IGNEUM + MASTER 2.0 + 102 // PROPOSED + 292 / NOT EXECUTED 47 / 73 + TEST STANDARD / 1.0 + + + + +FIN / FIN-01 TO FIN-03 + + + +Consensus safety and recovery +Test safety under the stated fault bounds. Demand liveness only when synchrony and participation +assumptions actually hold. + +Lead: Consensus lead + independent formal/security review +Fixtures: F0 exact fault model; F4 real-node partitions; F5 certificates and historical failures +FIN-01 BLOCKER / P01; P08 / NOT RUN + + +Agree on ordering, work and executed state +Setup. Use real fork-choice/DAG handling and independent miners, not only a simplified simulator. +1. Generate concurrent branches, delayed blocks, duplicates and invalid work with deterministic seeds. 2. +Compare selected ordering, accumulated work, transaction execution and state roots after delivery +converges. 3. Replay from independent checkpoints and from genesis where practical. +Pass. Honest nodes converge under F0 assumptions with exact roots and rewards. No duplicated work +accounting or undocumented ordering dependence; simulator-only success cannot substitute. +Evidence. Block/ordering corpus; root/work diffs; real-node replay logs. + +FIN-02 BLOCKER / P01; P08 / NOT RUN + +Attack finality with split honest populations +Setup. Use the source-discussed 40/40/20 weight split, plus threshold-boundary splits under F0. +1. Let the 20% adversarial group sign conflicting histories while honest groups are partitioned. 2. Delay +messages and eligibility updates independently; keep total historical weights auditable. 3. Try to form two +certificates and reconnect nodes to observe accepted final history. +Pass. No conflicting final certificates are accepted within the declared fault bound. A safe pause is valid +when quorum is unavailable; making progress on both sides is not required. +Evidence. Signed votes; certificate attempts; voter-table snapshots; safety checker output. + +FIN-03 BLOCKER / P01; P08 / NOT RUN + +Cross authority expiry in a long partition +Setup. Recover historical expiry failures where available; use the actual current authority-transition rules. +1. Partition for 31, 35, 60 and 90 logical days and around every retention/expiry boundary. 2. Attempt +independently renewed authority sets and conflicting checkpoint locks. 3. Repeat selected boundary cases +on real nodes with accelerated timers explicitly labelled. +Pass. Authority continuity remains authenticated and no conflicting final history appears within F0 +assumptions. A timeout is not accepted as proof absent voters ceased to exist. Compressed time is not +multi-month field evidence. +Evidence. Expiry timeline; table/certificate history; historical regression tests. + + + + +Source: 2.0 plan pp. 19, 21, 24, 25. Procedures and P-profile thresholds are proposed. + +IGNEUM + MASTER 2.0 + 103 // PROPOSED + 292 / NOT EXECUTED 48 / 73 + TEST STANDARD / 1.0 + + + + +FIN / FIN-04 TO FIN-06 + + + +Consensus safety and recovery +Test safety under the stated fault bounds. Demand liveness only when synchrony and participation +assumptions actually hold. + +Lead: Consensus lead + independent formal/security review +Fixtures: F0 exact fault model; F4 real-node partitions; F5 certificates and historical failures +FIN-04 BLOCKER / P01; P08 / NOT RUN + + +Stop signing while mining continues +Setup. Remove enough signing participation to invalidate the liveness assumption without forging votes. +1. Continue mining and execution, cross seed boundaries and monitor proof queues. 2. Check which +user-visible states advance and which remain unfinalised. 3. Restore eligible weight and bounded message +delay, then verify recovery. +Pass. No false finality or fabricated authority. Behaviour matches F0 during the pause and P08 after +assumptions return; unfinished transactions are not displayed as irreversible. +Evidence. Signing/mining trace; UI/RPC states; recovery roots and timing. + +FIN-05 BLOCKER / P01; P08 / NOT RUN + +Authenticate voter-set changes and pooled keys +Setup. Use normal transitions, pool members retaining keys and malicious substitution attempts. +1. Alter voter weights, membership proofs, miner/pool identity bindings and prior-certificate links. 2. Race +updates across boundaries and replay old signed changes. 3. Have a new node verify the authority chain +from its declared trust anchor. +Pass. Only correctly authenticated changes are accepted; weights cannot be double-counted or redirected +by a pool. All honest nodes agree on the active authority set for each certified point. +Evidence. Authority-chain fixtures; substitution attacks; new-node verification log. + +FIN-06 BLOCKER / P01; P08 / NOT RUN + +Analyse old-key compromise and long-range histories +Setup. Freeze assumptions about key erasure, retained weights, trust anchors and offline recovery. +1. Use previously eligible keys to build alternative histories after their operators disappear. 2. Present these +histories to recently offline and newly joining clients. 3. Test replayed certificates, stale anchors and +compromised signer subsets. +Pass. Acceptance matches the explicit security model with no hidden trusted recovery step. Any reliance on +a recent trusted anchor is disclosed and tested; hashpower assumptions cannot replace old-key analysis. +Evidence. Long-range corpus; trust-anchor policy; key-compromise review; client results. + + + + +Source: 2.0 plan pp. 19, 21, 24, 25. Procedures and P-profile thresholds are proposed. + +IGNEUM + MASTER 2.0 + 104 // PROPOSED + 292 / NOT EXECUTED 49 / 73 + TEST STANDARD / 1.0 + + + + +FIN / FIN-07 TO FIN-08 + + + +Consensus safety and recovery +Test safety under the stated fault bounds. Demand liveness only when synchrony and participation +assumptions actually hold. + +Lead: Consensus lead + independent formal/security review +Fixtures: F0 exact fault model; F4 real-node partitions; F5 certificates and historical failures +FIN-07 BLOCKER / P01; P08 / NOT RUN + + +Recover deterministically after reconnection and crash +Setup. Combine partitions with node crash, partial writes, restarts and proof backlog. +1. Reconnect networks under bounded latency and restore required honest participation. 2. Verify fork +choice, unfinalised reorganisation, finality, reward rollback and proof reassignments. 3. Compare all honest +nodes and customer-visible receipts after recovery. +Pass. P08 recovery holds without reversing a previously valid final guarantee. Only permitted unfinalised +state is reorganised; no duplicate rewards or inconsistent receipt statuses survive. +Evidence. Recovery timelines; roots/certificates; payout rollback; customer-state reconciliation. + +FIN-08 BLOCKER / P01; P08 / NOT RUN + +Combine boundaries, faults and adversarial scheduling +Setup. Use an independent model checker/scheduler and production-node scenarios from F4. +1. Combine epoch changes, authority transitions, mining churn, data delays and prover/aggregator loss. 2. +Explore bounded adversarial message schedules and minimise any counterexample. 3. Replay model +findings on real code and have an independent reviewer assess uncovered states. +Pass. No unresolved safety failure; liveness claims hold only within declared assumptions and P08. Model +bounds and untested schedules are published, not described as proof over every possible execution. +Evidence. Model/spec artifacts; schedule corpus; replay evidence; independent assessment. + + + + SUITE CLOSE / FIN + + + Confirm the frozen release and P-profiles, all positive/negative controls, complete raw artifacts and + independent review. A missing result is not a pass. Re-run affected cases after relevant changes. + + + +Execution owner: ____________________ Review: ____________________ +Evidence root: _______________________ Decision: NOT RUN + + + + +Source: 2.0 plan pp. 19, 21, 24, 25. Procedures and P-profile thresholds are proposed. + +IGNEUM + MASTER 2.0 + 105 // PROPOSED + 292 / NOT EXECUTED 50 / 73 + TEST STANDARD / 1.0 + + + + +VER / VER-01 TO VER-03 + + + +Wallets, receipts and data +availability +Verify the exact property shown to the user. An inclusion proof, execution proof and finality certificate are +not interchangeable. + +Lead: Wallet + light-client lead; independent security review +Fixtures: F0 trust/availability model; F5 malformed roots, receipts and authority chains +VER-01 BLOCKER / P01; P09 / NOT RUN + + +Authenticate light-client bootstrap +Setup. Give a clean client malicious RPC responses, fabricated voter tables and valid-looking signatures. +1. Start from the approved trust anchor and verify every required link to the advertised state. 2. Substitute +otherwise well-formed but unauthorised keys, weights and checkpoints. 3. Remove the bootstrap service +and use another independently operated source. +Pass. The client rejects unauthorised authority and discloses any trust anchor. Signatures over a +node-supplied table do not by themselves pass; missing authentication never silently degrades to trusted +RPC. +Evidence. Bootstrap corpus; trust-chain trace; fail-closed tests. + +VER-02 BLOCKER / P01; P09 / NOT RUN + +Verify evolving authority and execution statements +Setup. Use valid state proofs paired with wrong execution statements or stale authority histories. +1. Cross voter and verifier changes with offline clients returning after long intervals. 2. Alter roots, aggregate +identity and proof/public-input bindings independently. 3. Check local verification rather than merely a +server-reported verified flag. +Pass. All advertised proof checks occur locally or the remaining trust is explicitly disclosed. Wrong roots and +unauthenticated authority are rejected; unsupported verification paths are not claimed. +Evidence. Client verification trace; corrupted inputs; offline/upgrade results. + +VER-03 BLOCKER / P01; P09 / NOT RUN + +Prove successful payment rather than inclusion +Setup. Create successful, reverted, wrong-asset, wrong-recipient and wrong-amount transfers. +1. Generate receipts for included transactions, including failures and replaced/unfinalised transactions. 2. +Verify execution status plus asset, recipient, amount and canonical-state/receipt commitment. 3. Replay +the receipt on another chain and after an allowed unfinalised reorganisation. +Pass. Only the actual successful, correctly bound transfer is labelled payment proof. Inclusion-only receipts +are labelled as such; no node-reported success flag substitutes for authenticated outcome. +Evidence. Payment fixture corpus; receipt verification; merchant-facing status checks. + + + + +Source: 2.0 plan pp. 20, 25, 35, 37. Procedures and P-profile thresholds are proposed. + +IGNEUM + MASTER 2.0 + 106 // PROPOSED + 292 / NOT EXECUTED 51 / 73 + TEST STANDARD / 1.0 + + + + +VER / VER-04 TO VER-06 + + + +Wallets, receipts and data +availability +Verify the exact property shown to the user. An inclusion proof, execution proof and finality certificate are +not interchangeable. + +Lead: Wallet + light-client lead; independent security review +Fixtures: F0 trust/availability model; F5 malformed roots, receipts and authority chains +VER-04 BLOCKER / P00; P01; P09 / NOT RUN + + +Bound cross-chain oracle trust and replay +Setup. For a claimed oracle, freeze destination verifier, authority updates, accepted proof types and replay +policy. +1. Try deployer-substituted keys, stale certificates, unchecked signatures and wrong source/destination +identities. 2. Exercise legitimate authority updates and source reorganisations under the approved model. 3. +Measure gas/cost with realistic header sets and test disabled/unavailable verification. +Pass. The oracle enforces its declared trust model and fails closed. Deployer privileges and unavailable +guarantees are explicit; no trustless-bridge claim exceeds the checks performed. Excluded oracle scope +earns no pass credit. +Evidence. Oracle code/parameters; attack cases; cost report; privilege disclosure. + +VER-05 BLOCKER / P01; P08; P09 / NOT RUN + +Reconstruct required state without founder storage +Setup. Remove founder archival/input services and start an independent operator from the documented +entry point. +1. Fetch authenticated blocks, state/proof inputs and any required witnesses from permitted peers. 2. +Rebuild the expected state and continue validation/proving. 3. Measure bandwidth, disk, time and retention +requirements against advertised operator budgets. +Pass. Required data can be obtained and verified within the declared availability model. Hidden archives or +unpublished files block independence. A valid execution proof alone does not satisfy this test. +Evidence. Download/reconstruction logs; data hashes; resource costs; dependency inventory. + +VER-06 BLOCKER / P01; P08; P09 / NOT RUN + +Detect withholding, corruption and stale data +Setup. Serve valid commitments with missing data, corrupted chunks, stale witnesses and conflicting peer +replies. +1. Attempt to make a validator or light client accept an unavailable or incorrect state under F0. 2. Test +retrieval from independent peers and expiry/retry policy. 3. Restore data and check that recovery cannot +alter an already verified commitment. +Pass. No unjustified available/verified status; safety and admission rules match F0. Recovery is bounded +where assumptions permit, and unavailable-data states remain visible instead of hidden behind proofs. +Evidence. Withholding corpus; peer retrieval traces; availability/status checks. + + + + +Source: 2.0 plan pp. 20, 25, 35, 37. Procedures and P-profile thresholds are proposed. + +IGNEUM + MASTER 2.0 + 107 // PROPOSED + 292 / NOT EXECUTED 52 / 73 + TEST STANDARD / 1.0 + + + + +VER / VER-07 TO VER-08 + + + +Wallets, receipts and data +availability +Verify the exact property shown to the user. An inclusion proof, execution proof and finality certificate are +not interchangeable. + +Lead: Wallet + light-client lead; independent security review +Fixtures: F0 trust/availability model; F5 malformed roots, receipts and authority chains +VER-07 BLOCKER / P01; P09 / NOT RUN + + +Protect wallet keys, signing and recovery +Setup. Use test-only keys, encrypted backups and clean replacement devices; no real user funds. +1. Attempt secret access from proving jobs, logs, crash dumps, clipboard and telemetry paths. 2. Verify +transaction destination/amount before signing; test backup/restore and wrong-password handling. 3. +Upgrade and recover without silently changing signing authority or exposing seed material. +Pass. No unintended secret disclosure or unauthorised signature. Supported recovery restores the correct +keys and accounts; users receive explicit risk/backup information. Logs are sanitised without hiding security +evidence. +Evidence. Security review; canary-secret tests; signing fixtures; restore journey. + +VER-08 BLOCKER / P01; P09 / NOT RUN + +Keep every user-facing state truthful +Setup. Create included-only, executed, proven, finalised, reverted, stale and paused examples. +1. Compare explorer, wallet, receipt, RPC and customer API labels against authenticated evidence. 2. +Interrupt finality and proof services and observe refresh/reconnect behaviour. 3. Check statements about +privacy, Ethereum security and device support. +Pass. No stronger state is implied than verified; stale data is marked and failures are actionable. EVM +compatibility is not labelled Ethereum security, and ZK technology is not automatically labelled transaction +privacy. +Evidence. Cross-surface screenshots/logs; state mapping; claim review. + + + + SUITE CLOSE / VER + + + Confirm the frozen release and P-profiles, all positive/negative controls, complete raw artifacts and + independent review. A missing result is not a pass. Re-run affected cases after relevant changes. + + + +Execution owner: ____________________ Review: ____________________ +Evidence root: _______________________ Decision: NOT RUN + + + + +Source: 2.0 plan pp. 20, 25, 35, 37. Procedures and P-profile thresholds are proposed. + +IGNEUM + MASTER 2.0 + 108 // PROPOSED + 292 / NOT EXECUTED 53 / 73 + TEST STANDARD / 1.0 + + + + +OPS / OPS-01 TO OPS-03 + + + +Independent operation and release +security +A permissionless specification must remain operational without privileged infrastructure or unsafe +automatic updates. + +Lead: Operations + release leads; independent operators +Fixtures: F4 isolated multi-operator network; F0 signed releases; F9 telemetry +OPS-01 BLOCKER / P07; P08; P11 / NOT RUN + + +Run the complete no-founder exercise +Setup. Use the P11 independent network, adequate honest participation and enough non-founder capacity +for W. +1. Remove founder miners, provers, aggregators, RPC, DNS/bootstrap dependencies and private support +access. 2. Run the full P11 period while crossing real and separately labelled accelerated boundaries. 3. +Introduce scheduled faults and have independent operators recover using published instructions. +Pass. No founder action, secret file, privileged key or emergency anti-chip rule is needed. P07/P08 +outcomes hold within assumptions; any intervention is recorded as a failed no-rescue run, not erased. +Evidence. Operator roster/conflict checks; dependency removals; full activity/intervention log. + +OPS-02 BLOCKER / P01; P08; P09 / NOT RUN + +Diversify bootstrap and resist peer isolation +Setup. Start nodes without the default bootstrap host and give others adversarial peer lists. +1. Attempt eclipse through peer concentration, stale discovery, poisoned DNS and repeated identities in an +isolated lab. 2. Use independent documented discovery paths and validate returned chain data. 3. Measure +synchronisation, peer diversity and recovery after benign connectivity returns. +Pass. No unauthenticated history is trusted; bootstrap has no hidden single-provider requirement. Isolation +is detected/contained according to F0 and recovery meets P08 when assumptions return. +Evidence. Peer/discovery traces; eclipse scenarios; startup and recovery evidence. + +OPS-03 BLOCKER / P01; P09 / NOT RUN + +Separate update distribution from consensus authority +Setup. Use test signing keys and clean desktop/node installations with valid, stale and malicious packages. +1. Offer signed updates with unexpected consensus rules, downgraded binaries and corrupted payloads. 2. +Test explicit operator acceptance and the published signing-key incident procedure. 3. Confirm that +distribution-key possession cannot independently activate new consensus rules. +Pass. Tampering/unauthorised rollback is rejected; updates do not silently transfer authority. Approved +acceptance and activation are separate. No test touches production signing material. +Evidence. Package corpus; approval/activation traces; compromised-key rehearsal. + + + + +Source: 2.0 plan pp. 21, 24, 25, 26. Procedures and P-profile thresholds are proposed. + +IGNEUM + MASTER 2.0 + 109 // PROPOSED + 292 / NOT EXECUTED 54 / 73 + TEST STANDARD / 1.0 + + + + +OPS / OPS-04 TO OPS-06 + + + +Independent operation and release +security +A permissionless specification must remain operational without privileged infrastructure or unsafe +automatic updates. + +Lead: Operations + release leads; independent operators +Fixtures: F4 isolated multi-operator network; F0 signed releases; F9 telemetry +OPS-04 BLOCKER / P01; P08 / NOT RUN + + +Recover nodes from crash and storage damage +Setup. Use production database/snapshot paths with controlled interrupted writes and corrupted test +storage. +1. Crash during import, proof acceptance, reward application and snapshot generation. 2. Restore from +independently verified snapshots or re-sync through documented procedures. 3. Compare roots, +certificates, balances and processed-job IDs with an unaffected node. +Pass. No corrupt snapshot is trusted, no duplicate payout and no loss of authenticated final state. Recovery +meets P08 where data is available; ambiguous corruption fails closed and is actionable. +Evidence. Crash schedule; snapshot hashes; root/balance diffs; recovery timing. + +OPS-05 BLOCKER / P01; P09 / NOT RUN + +Isolate untrusted proving workloads +Setup. Run hostile test jobs with secret canaries and restrictive worker permissions. +1. Attempt filesystem escape, process spawning, resource exhaustion, network access and key-store reads. +2. Crash workers and inspect host, wallet and node availability plus dump/log contents. 3. Retry on every +supported isolation backend and check dependency vulnerability handling. +Pass. No secret leakage or unauthorised host action; P09 resource containment holds. Worker failure does +not compromise validator/wallet authority; unsupported isolation is not marketed as safe execution. +Evidence. Sandbox penetration report; canary logs; resource limits; host-integrity checks. + +OPS-06 BLOCKER / P01; P09 / NOT RUN + +Contain malicious network and API traffic +Setup. Use an authorised isolated load environment with declared resource and request-rate budgets. +1. Send malformed headers, proofs, oversized messages, floods and invalid peer sequences. 2. Measure +legitimate traffic, memory/disk growth and validator CPU use. 3. Test limit resets, peer reconnect and +graceful degradation without disabling validation. +Pass. P09 abuse budgets hold; no unbounded allocation, persistent crash or invalid acceptance. +Backpressure is visible and honest users retain the specified service at admitted load. +Evidence. Load/corpus manifests; resource series; valid-traffic metrics; incident traces. + + + + +Source: 2.0 plan pp. 21, 24, 25, 26. Procedures and P-profile thresholds are proposed. + +IGNEUM + MASTER 2.0 + 110 // PROPOSED + 292 / NOT EXECUTED 55 / 73 + TEST STANDARD / 1.0 + + + + +OPS / OPS-07 TO OPS-08 + + + +Independent operation and release +security +A permissionless specification must remain operational without privileged infrastructure or unsafe +automatic updates. + +Lead: Operations + release leads; independent operators +Fixtures: F4 isolated multi-operator network; F0 signed releases; F9 telemetry +OPS-07 GATE / P09; P10 / NOT RUN + + +Detect failures with usable evidence and runbooks +Setup. Define alerts for invalid acceptance, conflicting finality, backlog, data loss, payout mismatch and +stale status. +1. Inject one instance of each monitored failure in the lab. 2. Have an unaffiliated operator diagnose it using +only emitted evidence and published instructions. 3. Test redaction, metric freshness and duplicate-alert +suppression without suppressing serious failures. +Pass. P10 alert/detection limits hold; every blocker produces actionable evidence. Monitoring does not leak +secrets or mislabel intentional safe pauses as successful finality. +Evidence. Alert matrix; detection timelines; independent runbook exercise. + +OPS-08 BLOCKER / P00; P08; P11 / NOT RUN + +Repeat independent operation across releases +Setup. Use a clean previous supported version and the final candidate with independent operators. +1. Perform documented rolling upgrade, rollback of non-consensus software where allowed and +resynchronisation. 2. Cross activation with mixed versions and unavailable founder distribution hosts. 3. +Re-run affected gates after changes and preserve prior failures and incident lessons. +Pass. No undocumented privileged migration or automatic consensus rewrite. All affected evidence is +refreshed; P11 no-rescue results remain tied to the final release, not an earlier build. +Evidence. Upgrade/replay logs; invalidation map; repeated gate signatures. + + + + SUITE CLOSE / OPS + + + Confirm the frozen release and P-profiles, all positive/negative controls, complete raw artifacts and + independent review. A missing result is not a pass. Re-run affected cases after relevant changes. + + + +Execution owner: ____________________ Review: ____________________ +Evidence root: _______________________ Decision: NOT RUN + + + + +Source: 2.0 plan pp. 21, 24, 25, 26. Procedures and P-profile thresholds are proposed. + +IGNEUM + MASTER 2.0 + 111 // PROPOSED + 292 / NOT EXECUTED 56 / 73 + TEST STANDARD / 1.0 + + + + +UX / UX-01 TO UX-03 + + + +Ember, payouts and operator +control +Successful participation must be practical for ordinary owners without hidden custody or loss of +consensus authority. + +Lead: Desktop product + pool leads; independent usability study +Fixtures: F2 supported desktops; F8 user study; F4 honest/malicious pools +UX-01 GATE / P10 / NOT RUN + + +Onboard ordinary owners on native desktop apps +Setup. Recruit the P10 first-time user cohort across Windows and macOS using supported physical +hardware. +1. Observe install, hardware detection, safety explanation and first accepted work without staff intervention. +2. Record download/data preparation separately as well as complete end-to-end time. 3. Test unsupported +hardware and insufficient memory messaging rather than forcing a failed start. +Pass. P10 completion/time targets hold with no unsafe default or concealed prerequisite. The product is +tested as the actual desktop app, not only a browser preview. +Evidence. Consent-based study records; task timings; failure reasons; compatibility outcomes. + +UX-02 BLOCKER / P01; P10 / NOT RUN + +Make pause, stop and safe tuning reliable +Setup. Run mining/proving on active desktops under contention and safe thermal stress. +1. Use pause, stop, power limit, task selection and emergency local shutdown controls. 2. Crash or restart +the UI while workers run and verify ownership of background processes. 3. Restore the original hardware +settings and test power-saving/low-battery behaviour where supported. +Pass. P10 control latency and safe-state requirements hold. Stopping does not strand an uncontrolled +process; tuning never depends on unsafe settings or silent privilege escalation. +Evidence. Control timings; process/settings audit; restart and safety traces. + +UX-03 BLOCKER / P01; P10; P12 / NOT RUN + +Show net earnings and compatibility honestly +Setup. Use known rewards, fees, energy readings, retries and operator-entered tariffs. +1. Compare mining, internal proof and external proof income with authoritative ledgers. 2. Show gross/net +estimates, measurement boundaries, tariff assumptions and payout status. 3. Test stale data, losses, +negative margins and mining-only versus proving-compatible devices. +Pass. P10 reconciliation limits hold and uncertainty is visible. No guaranteed profits, fabricated fiat price or +inferred proving support; provisional earnings are not shown as settled payments. +Evidence. UI/ledger comparisons; tariff fixtures; stale/negative examples. + + + + +Source: 2.0 plan pp. 14, 21, 25, 26. Procedures and P-profile thresholds are proposed. + +IGNEUM + MASTER 2.0 + 112 // PROPOSED + 292 / NOT EXECUTED 57 / 73 + TEST STANDARD / 1.0 + + + + +UX / UX-04 TO UX-06 + + + +Ember, payouts and operator +control +Successful participation must be practical for ordinary owners without hidden custody or loss of +consensus authority. + +Lead: Desktop product + pool leads; independent usability study +Fixtures: F2 supported desktops; F8 user study; F4 honest/malicious pools +UX-04 BLOCKER / P01; P10 / NOT RUN + + +Pay small operators without hidden custody +Setup. Use ordinary single-card balances and the actual pooling/payment path. +1. Earn, request/receive payment, disconnect and reconnect; include low balances, fees and a pool outage. +2. Attempt redirection, delayed accounting and withdrawal of another user's entitlement. 3. Reconcile +displayed balances with canonical entitlement and actual settlement. +Pass. P10 payout limits hold for the declared small-operator case. No unauthorised custody, redirection or +unexplained loss; thresholds and fees are disclosed rather than masked by larger test balances. +Evidence. Single-card payout ledger; pool failure record; custody/authorisation review. + +UX-05 BLOCKER / P01; P09 / NOT RUN + +Keep voting keys with the miner through pooling +Setup. Use an honest pool and a modified pool that replaces worker identity or voting credentials. +1. Verify the consensus binding from performed work to the miner's retained key. 2. Attempt substitution, +replay and reassignment without the miner's authorisation. 3. Leave the pool and verify retained +voting/finality rights under F0. +Pass. No silent transfer of governance/finality authority. If the protocol cannot establish retained keys, this +requirement fails; a pool-protocol name or user-interface promise does not pass. +Evidence. Work/key binding vectors; malicious-pool attempts; leave-pool authority check. + +UX-06 BLOCKER / P01; P10 / NOT RUN + +Verify actual miner-selected work templates +Setup. Provide a pool interface with declared job-declaration support and independent miner templates. +1. Submit miner-selected valid transaction templates and verify what is actually hashed and accepted. 2. +Have a pool substitute or censor templates and test local verification/fallback. 3. Measure payout and +acceptance consequences without moving authority to the pool. +Pass. The advertised selection control exists in accepted work, not only configuration. Undisclosed +substitution is detected; supported independent operation remains practical under P10. +Evidence. Template commitments; accepted-block evidence; malicious-pool/fallback report. + + + + +Source: 2.0 plan pp. 14, 21, 25, 26. Procedures and P-profile thresholds are proposed. + +IGNEUM + MASTER 2.0 + 113 // PROPOSED + 292 / NOT EXECUTED 58 / 73 + TEST STANDARD / 1.0 + + + + +UX / UX-07 TO UX-08 + + + +Ember, payouts and operator +control +Successful participation must be practical for ordinary owners without hidden custody or loss of +consensus authority. + +Lead: Desktop product + pool leads; independent usability study +Fixtures: F2 supported desktops; F8 user study; F4 honest/malicious pools +UX-07 BLOCKER / P09; P10 / NOT RUN + + +Expose actionable failures and safe updates +Setup. Create failed proofs, memory pressure, expired jobs, missing payouts and available software +updates. +1. Ask independent users to identify the issue, stop safely and follow the recommended action. 2. Test +explicit update approval, version visibility and a failed/corrupt update. 3. Confirm diagnostic exports remove +keys and private inputs while retaining useful evidence. +Pass. P10 task-success requirements hold; no silent update or false success state. Recovery instructions +work on supported desktops and secret canaries never enter exported logs. +Evidence. Observed tasks; update traces; sanitised export tests. + +UX-08 GATE / P02; P10 / NOT RUN + +Publish competitive accessible software +Setup. Provide open documented builds, tuning parameters and known fee conditions for all supported +platforms. +1. Compare Ember against independently optimised permissible implementations on identical work. 2. +Measure efficiency, fees, false rejection, installation and update transparency. 3. Scan for hidden developer +fees, hardware whitelists, per-address privilege or undisclosed remote controls. +Pass. P10 relative-efficiency limits hold and all fees/privileges are explicit. No self-reported device tier +earns consensus advantage. A superior external implementation triggers investigation, not selective +exclusion. +Evidence. Matched software comparison; code/config review; fee/privilege inventory. + + + + SUITE CLOSE / UX + + + Confirm the frozen release and P-profiles, all positive/negative controls, complete raw artifacts and + independent review. A missing result is not a pass. Re-run affected cases after relevant changes. + + + +Execution owner: ____________________ Review: ____________________ +Evidence root: _______________________ Decision: NOT RUN + + + + +Source: 2.0 plan pp. 14, 21, 25, 26. Procedures and P-profile thresholds are proposed. + +IGNEUM + MASTER 2.0 + 114 // PROPOSED + 292 / NOT EXECUTED 59 / 73 + TEST STANDARD / 1.0 + + + + +COM / COM-01 TO COM-03 + + + +Paid demand and sustainable +delivery +Devnet payouts and subsidised pilots demonstrate mechanics, not independent willingness to pay. + +Lead: Commercial lead + independent financial/customer reviewer +Fixtures: F8 real consenting customers; F7 full service costs; private identity proofs +COM-01 GATE / P07; P14 / NOT RUN + + +Deliver a genuine contracted proof pilot +Setup. Select one real external customer with a meaningful fixed workload and no required migration to +Igneum. +1. Agree program, inputs, proof format, deadline, price, failure/refund policy and verification method. 2. Run +paid jobs through ordinary independently operated infrastructure. 3. Have the customer verify usefulness, +correctness and its reason for choosing the service. +Pass. The pilot satisfies its actual contract and settles genuine external payment. Trial subsidies are +disclosed and cannot satisfy the repeat-demand gate; no invented customer or testimonial. +Evidence. Redacted contract; verified jobs; settlement proof; consented customer confirmation. + +COM-02 GATE / P14 / NOT RUN + +Establish independent repeat purchasing +Setup. Use the P14 multi-customer observation period and ownership/conflict checks. +1. Track paid purchases on distinct occasions, including refunds and stopped customers. 2. Audit related +parties, project reimbursements, token grants and circular funding. 3. Reconcile external cash received with +correctly delivered meaningful work. +Pass. P14 buyer, duration and volume minima are met without reimbursement or related-party substitution. +Repeat orders are separate buying decisions, not a single payment split into many jobs. +Evidence. Anonymised buyer ledger; repeat-order dates; conflict review; net receipts. + +COM-03 GATE / P12; P14 / NOT RUN + +Demonstrate service and operator margins +Setup. Allocate all delivery costs, including aggregation, retries, hardware, power, host, network and +support. +1. Calculate gross contribution and fully loaded unit costs for each contracted workload. 2. Reconcile a +representative operator's realised earnings against metered costs and opportunity cost. 3. Repeat under the +declared demand and price sensitivities. +Pass. P14 contribution targets hold and at least the required operator cohort has positive realised +contribution. Excluded overhead is visible; token appreciation or unpriced founder labour cannot silently +create profitability. +Evidence. Unit-economics ledger; metered operator sample; allocation rules; sensitivity report. + + + + +Source: 2.0 plan pp. 4, 17, 18, 24, 26, 27, 31, 32, 33. Procedures and P-profile thresholds are proposed. + +IGNEUM + MASTER 2.0 + 115 // PROPOSED + 292 / NOT EXECUTED 60 / 73 + TEST STANDARD / 1.0 + + + + +COM / COM-04 TO COM-06 + + + +Paid demand and sustainable +delivery +Devnet payouts and subsidised pilots demonstrate mechanics, not independent willingness to pay. + +Lead: Commercial lead + independent financial/customer reviewer +Fixtures: F8 real consenting customers; F7 full service costs; private identity proofs +COM-04 BLOCKER / P01; P07; P14 / NOT RUN + + +Meet the customer service guarantee +Setup. Observe actual delivery deadlines, validity, failure handling and support over the contracted period. +1. Count all accepted jobs, including failed, retried and abandoned cases. 2. Have the customer +independently verify results and invoke one authorised refund/failure exercise. 3. Compare offered capacity +and quoted price with what was actually delivered. +Pass. P07 and contracted obligations hold; validity has zero accepted exceptions. Failure terms are +honoured, and demand beyond capacity is explicitly refused rather than quietly omitted from metrics. +Evidence. Customer-verifier records; SLO report; refunds; promised-versus-delivered comparison. + +COM-05 GATE / P14; P15 / NOT RUN + +Compare against the buyer's real alternative +Setup. Identify a credible alternative supplier or in-house option for the same workload, proof format and +security. +1. Obtain comparable quotes or consented measured trials at the evaluation date. 2. Include integration, +verification, deadlines and all operational costs, not only proof-generation time. 3. Document the customer's +actual trade-off without inventing unavailable comparator evidence. +Pass. P15 commercial comparison is satisfied with like-for-like scope and a evidenced purchase reason. +Missing alternative data remains MISSING; it is not scored as an Igneum win. +Evidence. Dated comparison; workload/security match; customer decision record. + +COM-06 GATE / P14 / NOT RUN + +Retain buyers after the pilot and subsidy period +Setup. Follow all recruited customers through the P14 observation period, including churn. +1. Remove disclosed trial incentives before measuring repeat demand. 2. Track renewal, expansion, +cancellation reasons, unresolved incidents and buyer concentration. 3. Review whether one affiliated or +subsidised buyer dominates the apparent market. +Pass. P14 repeat/concentration conditions hold with honest denominator and churn reporting. Paying +demand survives beyond a demonstration; unsatisfied or departed buyers are not removed retrospectively. +Evidence. Cohort/renewal ledger; churn notes; concentration and incentive report. + + + + +Source: 2.0 plan pp. 4, 17, 18, 24, 26, 27, 31, 32, 33. Procedures and P-profile thresholds are proposed. + +IGNEUM + MASTER 2.0 + 116 // PROPOSED + 292 / NOT EXECUTED 61 / 73 + TEST STANDARD / 1.0 + + + + +COM / COM-07 TO COM-08 + + + +Paid demand and sustainable +delivery +Devnet payouts and subsidised pilots demonstrate mechanics, not independent willingness to pay. + +Lead: Commercial lead + independent financial/customer reviewer +Fixtures: F8 real consenting customers; F7 full service costs; private identity proofs +COM-07 GATE / P13 / NOT RUN + + +Fund maintenance without assumed appreciation +Setup. Prepare a costed plan for development, review, infrastructure, support and incident response. +1. Separate committed resources from revenue dependent on adoption or token price. 2. Stress lower +income and an unexpected security/operations expense. 3. Verify responsible owners and continuity +arrangements without changing fair-launch promises. +Pass. P13 committed-runway requirement holds and downside responses are documented. No +uncommitted financing, rising token price or burn accounting is presented as available maintenance funding. +Evidence. Budget and commitment evidence; downside plan; owner/continuity roster. + +COM-08 GATE / P09; P14 / NOT RUN + +Let independent developers build useful integrations +Setup. Recruit unaffiliated developers unfamiliar with unpublished implementation details. +1. Use public docs to deploy a supported application or integrate an external proof request and verification +flow. 2. Record time, undocumented dependencies, workarounds and correctness issues. 3. Retest after +documentation fixes without founder-written hidden integration code. +Pass. P14 developer-task minimum passes on the final release; all required public instructions exist. +Successful bytecode deployment alone does not count as a working application or service integration. +Evidence. Consented developer logs; public examples; issue closure; verified end-to-end journeys. + + + + SUITE CLOSE / COM + + + Confirm the frozen release and P-profiles, all positive/negative controls, complete raw artifacts and + independent review. A missing result is not a pass. Re-run affected cases after relevant changes. + + + +Execution owner: ____________________ Review: ____________________ +Evidence root: _______________________ Decision: NOT RUN + + + + +Source: 2.0 plan pp. 4, 17, 18, 24, 26, 27, 31, 32, 33. Procedures and P-profile thresholds are proposed. + +IGNEUM + MASTER 2.0 + 117 // PROPOSED + 292 / NOT EXECUTED 62 / 73 + TEST STANDARD / 1.0 + + + + +LEAD / LEAD-01 TO LEAD-03 + + + +Comparative leadership evidence +A serious contention claim requires comparative outcomes and real adoption evidence, not just an +internally green test dashboard. + +Lead: Independent assessment panel + product/economics reviewers +Fixtures: F8 peer/customer studies; full signed technical evidence; 90-day observation +LEAD-01 GATE / P15 / NOT RUN + + +Register a fair contemporary comparison +Setup. Choose at least the P15 peer coverage and an evaluation date before collecting confirmatory results. +1. Include the plan's Ravencoin, Ergo and Firo reference set where comparable, then check for other +relevant current options. 2. Freeze versions, supported hardware, methods, noninferiority margins and +commercial alternatives. 3. Publish exclusions and prohibit cross-algorithm raw-hashrate comparisons. +Pass. The protocol covers material alternatives fairly and is signed independently. A missing or +non-comparable feature is not scored zero; no arbitrary universal rank is inferred from selected metrics. +Evidence. Timestamped peer protocol; source/version records; comparison/exclusion rationale. + +LEAD-02 GATE / P02; P10; P15 / NOT RUN + +Demonstrate comparable operator advantages +Setup. Use matched user tasks and operating conditions on the selected GPU-first networks. +1. Measure install-to-first-accepted-work, software overhead versus each network's tuned baseline, payout +friction and retained control. 2. Measure rejection/availability under the same network conditions; report +fees separately. 3. Use blinded analysis where possible and independent runs for decisive differences. +Pass. P15 noninferiority and superiority requirements hold on meaningful comparable dimensions. No raw +hashes from different algorithms are compared, and transient token price is not labelled engineering +superiority. +Evidence. Matched task data; uncertainty/effect sizes; independent comparison report. + +LEAD-03 GATE / P04; P12; P15 / NOT RUN + +Substantiate the specialist-coexistence claim +Setup. Assemble G1-G4 plus frozen rules and all surviving-adversary assumptions. +1. Have independent reviewers trace each public competitiveness statement to its narrowest evidence. 2. +Separate measured GPUs, modelled silicon and economic scenarios in all summaries. 3. Evaluate residual +uncertainty, excluded technologies and the no-new-rules counterfactual. +Pass. All claimed envelopes meet P04/P12 without unsupported universal bounds. Reviewers agree the +evidence supports scoped commodity competitiveness even when chips remain compatible; an exact +chip-arrival probability is not inferred. +Evidence. Claim-to-evidence map; signed envelope review; limitations statement. + + + + +Source: 2.0 plan pp. 4, 22, 25, 27, 31, 32, 33. Procedures and P-profile thresholds are proposed. + +IGNEUM + MASTER 2.0 + 118 // PROPOSED + 292 / NOT EXECUTED 63 / 73 + TEST STANDARD / 1.0 + + + + +LEAD / LEAD-04 TO LEAD-06 + + + +Comparative leadership evidence +A serious contention claim requires comparative outcomes and real adoption evidence, not just an +internally green test dashboard. + +Lead: Independent assessment panel + product/economics reviewers +Fixtures: F8 peer/customer studies; full signed technical evidence; 90-day observation +LEAD-04 GATE / P12; P16 / NOT RUN + + +Observe ordinary-operator retention and margins +Setup. Recruit the P16 independent cohort before observing results; use privacy-preserving evidence. +1. Follow participation, realised margin, hardware changes, failures and reasons for leaving for 90 days. 2. +Report trial incentives separately and include every initial participant in retention denominators. 3. Compare +behaviour with matched alternatives where feasible; disclose absence of an actual downturn. +Pass. P16 retention/margin minima hold with verified independence and no removal of churned users. +Simulated downturns cannot be called observed bear-market retention; historical claims stay limited to the +period measured. +Evidence. Pseudonymous cohort ledger; margin/retention calculations; departure reasons. + +LEAD-05 GATE / P11; P16 / NOT RUN + +Measure control and dependency concentration +Setup. Audit operational control of mining, voting, proving, aggregation, hosting and software distribution +separately. +1. Use opt-in attestations, observed dependencies and independent corroboration; disclose uncertain +common ownership. 2. Compare concentration and provider-removal outcomes to the approved security +and availability assumptions. 3. Check that pooled payments do not hide authority concentration and +hardware vendors are not equated with operators. +Pass. P11/P16 concentration requirements hold within disclosed uncertainty; unidentified control cannot +be counted as independent. No single removable dependency is falsely marketed as decentralised +operation. +Evidence. Control/failure-domain map; uncertainty notes; concentration/removal results. + +LEAD-06 BLOCKER / P01; P16 / NOT RUN + +Complete the reliability observation window +Setup. Observe the final candidate and approved compatible updates for the full P16 real-time period. +1. Measure promised service availability, invalid acceptance, finality safety, payouts and incident impact. 2. +Reconcile external probes, customer records and operator logs, including maintenance and exclusions. 3. +Repeat affected critical tests after every material change; reset observation where comparability breaks. +Pass. P16 availability and safety criteria hold on live observation; no hidden downtime or compressed-time +substitution. This supports the recorded window only, not multi-year operational maturity. +Evidence. 90-day SLO ledger; independent probes; incident reports; change/retest history. + + + + +Source: 2.0 plan pp. 4, 22, 25, 27, 31, 32, 33. Procedures and P-profile thresholds are proposed. + +IGNEUM + MASTER 2.0 + 119 // PROPOSED + 292 / NOT EXECUTED 64 / 73 + TEST STANDARD / 1.0 + + + + +LEAD / LEAD-07 TO LEAD-08 + + + +Comparative leadership evidence +A serious contention claim requires comparative outcomes and real adoption evidence, not just an +internally green test dashboard. + +Lead: Independent assessment panel + product/economics reviewers +Fixtures: F8 peer/customer studies; full signed technical evidence; 90-day observation +LEAD-07 GATE / P00; P15; P16 / NOT RUN + + +Issue an independent contender assessment +Setup. Provide the full evidence packet, commercial results, comparative study and unresolved-limit +register to the panel. +1. Check every mandatory and claimed-option test, source requirement and approved threshold. 2. Require +separate signoffs for hardware/economics, security/operations and customer/operator evidence. 3. +Document dissent and challenge any inference that passing an internal checklist proves number-one rank. +Pass. Every required gate is PASS with no unresolved material challenge, critical/high defect or missing +comparator/customer evidence. The panel supports a credible leadership-contender conclusion within +scope, not a guaranteed rank. +Evidence. Signed assessment; full status index; dissent/limitations; approved claim wording. + +LEAD-08 GATE / P00; P16 / NOT RUN + +Keep leadership claims valid after release +Setup. Define material-change triggers and scheduled reviews before publishing the assessment. +1. Refresh competitor, hardware-cost, demand and security evidence at the P16 cadence. 2. Test a newly +credible specialist, lost customer, major outage and verifier change against invalidation rules. 3. Withdraw or +narrow stale claims promptly while publishing the new evidence status. +Pass. Claims remain dated, scoped and revisable; material contrary evidence reopens the appropriate gate. +The network may remain usable while a leadership claim is suspended. No permanent self-awarded +certification. +Evidence. Review calendar; invalidation drills; versioned public claim register. + + + + SUITE CLOSE / LEAD + + + Confirm the frozen release and P-profiles, all positive/negative controls, complete raw artifacts and + independent review. A missing result is not a pass. Re-run affected cases after relevant changes. + + + +Execution owner: ____________________ Review: ____________________ +Evidence root: _______________________ Decision: NOT RUN + + + + +Source: 2.0 plan pp. 4, 22, 25, 27, 31, 32, 33. Procedures and P-profile thresholds are proposed. + +IGNEUM + MASTER 2.0 + 120 // PROPOSED + 292 / NOT EXECUTED 65 / 73 + TEST STANDARD / 1.0 + + + + +APPENDIX A / EVIDENCE CONTRACT + + + +One record for every result. +Use a machine-readable record in addition to the human report. The example below is a schema template, +not a test result. + + + FIELD GROUP REQUIRED CONTENT + + + test_id, run_id, release_manifest_hash, profile_hash, source_commit, binary_hashes, + Identity + time window. + + fixture/workload IDs, seed set, supported hardware/OS/roles, network topology, + Scope + security assumptions. + + Exact adapter/command, operator, environment, steps completed, exclusions, crashes + Execution + and interventions. + + Raw artifacts, units, numerator/denominator, point/interval values, model assumptions + Measures + and failed controls. + + Expected result, observed result, PASS/FAIL/BLOCKED/INCONCLUSIVE/EXCLUDED, + Decision + defects and review scope. + + Independent reviewer identity/conflicts, signature, approved evidence hashes and + Approval + expiry/invalidation triggers. + + +Example record +{ + "test_id": "ZKP-01", + "run_id": null, + "release_manifest_hash": null, + "profile_hash": null, + "status": "NOT RUN", + "observed": null, + "artifacts": [], + "defects": [], + "independent_review": null +} + + + PUBLISH SAFELY + + + Public summaries should carry hashes, methods and redacted outcomes. Keep customer contracts, + personal identities, secret keys and private inputs out of public artifacts. Qualified reviewers can + inspect protected originals with consent. + + + + +Basis: 2.0 plan pp. 5 and 25. Record fields and schema are proposed. + +IGNEUM + MASTER 2.0 + 121 // PROPOSED + 292 / NOT EXECUTED 66 / 73 + TEST STANDARD / 1.0 + + + + +APPENDIX B / DEFECT AND RETEST POLICY + + + +Failure must change the decision. +No waiver converts a violated core safety or competitiveness criterion into a pass. + + + CLASS RESPONSE CLOSURE + + + Stop/isolate. Protect keys/funds, preserve Independent root-cause review, fix and + Critical + artifacts, suspend affected claims. complete affected gate rerun. + + Block release/claim. Assign accountable owner Independent retest plus regression + High + and containment. case and dependency review. + + Track with owner and deadline. Do not ignore Documented remediation or scoped + Medium/low + violations of a named pass criterion. non-blocking risk acceptance. + + New hypothesis or source-plan + Keep raw negative result. Do not call a + Research failure revision, re-freeze and confirmatory + completed experiment an improved candidate. + retest. + + BLOCKED or INCONCLUSIVE. No silent zero or Obtain required evidence and reviewer; + Missing evidence + favourable replacement. repeat the affected procedure. + + +Retest dependencies +A generator/dataset change reopens GPU, POW, ADV, ROT, ECO, CAP and relevant commercial cost claims. A +verifier/EVM change reopens EVM, ZKP, CAP, VER, OPS and customer-delivery evidence. A quorum/authority +change reopens FIN, ROT, VER, OPS and the no-rescue assessment. Fee or supply changes reopen INC, ECO, +COM and earnings claims. + +Withdrawal, not retrospective rewriting +If the final claim no longer holds, date the original evidence, publish its limitation and suspend the affected +wording. Do not edit a failed historical run into a success. The network remaining usable and a leadership +claim remaining justified are separate questions. + + NO RANK FROM PASS PERCENTAGE + + + 127 of 128 tests passing can still mean not ready. A full scoped pass supports an assessment only + when the difficult hardware, security, economic, commercial and comparative outcomes all hold. + + + + +Basis: 2.0 plan pp. 23-27. Defect workflow is proposed. + +IGNEUM + MASTER 2.0 + 122 // PROPOSED + 292 / NOT EXECUTED 67 / 73 + TEST STANDARD / 1.0 + + + + +APPENDIX C / INDEPENDENT SIGN-OFF + + + +The release decision sheet. +Complete this sheet only after the applicable evidence packets exist. The blank state is deliberate. + + + DECISION ITEM INITIAL STATUS REVIEW / EVIDENCE + + + G0 / source and thresholds NOT RUN Manifest and approval hashes required + + G1 / independent baseline NOT RUN GPU/build packets required + + Matched experiments and negative controls + G2 / improved candidate NOT RUN + required + + Physical/cost envelope and independent + G3 / surviving specialist NOT RUN + challenge required + + Required-world results and failure regions + G4 / five-year coexistence NOT RUN + required + + G5 / no-rescue network NOT RUN Independent real-node exercise required + + Security, proving, EVM, wallet and + Technical readiness NOT RUN + operator-control packets + + Unrelated repeat customers, settlement and unit + Commercial evidence NOT RUN + costs + + Comparative/90-day evidence NOT RUN Peer study, independent retention and reliability + + All above plus scoped independent panel + Contender assessment NOT RUN + conclusion + + +Named approvals to collect +Release/accountable owner: __________________________ +Hardware and economics reviewer: ____________________ +Security and operations reviewer: _____________________ +Customer and operator reviewer: ______________________ +Manifest / evidence root / decision date: ________________ + + PERMITTED CONCLUSION AFTER A FULL PASS + + + The evaluated release supports a credible leadership-contender assessment within the published + hardware, economic, security and observation scope. This is not a guarantee of number-one market + rank or resistance to every future design. + + + + +Basis: 2.0 plan pp. 23-27. All gates remain NOT RUN in this document. + +IGNEUM + MASTER 2.0 + 123 // PROPOSED + 292 / NOT EXECUTED 68 / 73 + TEST STANDARD / 1.0 + + + + +APPENDIX D / PROVENANCE AND PUBLIC WORDING + + + +Scope the claim. Keep the sources. +The source plan is a strategy snapshot. This manual expands it into proposed tests without silently +changing its factual status. + +Source basis +S1. IGNEUM_2.0_Plan.pdf. 37 pages. Strategy edition dated 8 October 2026. All source-page references in +this manual refer to this file. +S2. IGNEUM 2.0.rtf, retained in S1 appendices A/B. Leadership assessment and EVM/zkVM strategy. +B1. Original Igneum brand kit dated 7 October 2026. Logo, obsidian/ember palette, Unbounded and IBM Plex +typography. + +Source PDF SHA-256: +418b3b9f68f96a413872fecb16f8508a40063891c70054c65e92e6e5f5fb70b6 + + +Editorial additions +The 128-case catalogue, P00-P16 profiles, sample sizes, proposed tolerances, evidence schema, gate +workflow and contender-assessment criteria are new acceptance-design proposals. They are not +represented as already approved requirements, current performance, independent audit findings or +externally standardised certification. + +Wording before and after validation + + BEFORE + + + Igneum is designed to keep accessible GPUs competitive even when specialised mining hardware + exists, without depending on emergency anti-chip changes. + + + + AFTER THE SCOPED EVIDENCE PASSES + + + Independent evaluation supports Igneum's commodity-GPU competitiveness against the assessed + adaptable specialist designs, under the published conditions. Technical, commercial and + comparative evidence makes the evaluated release a credible leadership contender. + + + +Leave out guaranteed chip death, a universal silicon-efficiency ceiling, chip-arrival percentages without a calibrated model, +guaranteed profits, automatic privacy, inherited Ethereum security and an unsupported number-one rank. Reassess +whenever material contrary evidence appears. + + + + +Primary basis: supplied 2.0 plan and original source document. No fresh deployment or market audit was performed. + +IGNEUM + MASTER 2.0 + 124 // PROPOSED + 292 / NOT EXECUTED 69 / 73 + TEST STANDARD / 1.0 + + + + +TEST INDEX / 1 OF 4 + + + +Find a test. +Test IDs are stable. Every entry links to the complete procedure and its acceptance criteria. + +GOV / Release identity and evidence +GOV-01 Freeze the release and its claims 18 +GOV-02 Approve thresholds before results 18 +GOV-03 Reproduce builds outside the founding team 18 +GOV-04 Preserve raw and negative evidence 19 +GOV-05 Prove the test oracle detects broken behaviour 19 +GOV-06 Enforce scope and optional-feature discipline 19 +GOV-07 Independent review and finding closure 20 +GOV-08 Invalidate stale evidence and control public status 20 + + +GPU / Whole-system GPU measurements +GPU-01 Cover the declared commodity population 21 +GPU-02 Reproduce Ember clock-lock savings 21 +GPU-03 Measure the real 64-register GPU cost 21 +GPU-04 Find the memory-clock operating ladder 22 +GPU-05 Test dataset fit and support-horizon costs 22 +GPU-06 Measure accepted work under ordinary connectivity 22 +GPU-07 Survive sustained thermal and power operation 23 +GPU-08 Reproduce the full baseline independently 23 + + +POW / Proof-of-work correctness and coupling +POW-01 Match independent execution across every backend 24 +POW-02 Validate generated programs and index folding 24 +POW-03 Test whether live state is unavoidable 24 +POW-04 Evaluate connected-resource restructuring 25 +POW-05 Prevent amortised cheap winning attempts 25 +POW-06 Bound verifier work and malformed-input cost 25 +POW-07 Constrain any mixed-resource or FP32 branch 26 +POW-08 Keep rejected mechanisms out of the shipped claim 26 + + +ADV / Programmable specialist adversaries +ADV-01 Build a multi-family programmable opponent 27 +ADV-02 Price shared, reduced and reconstructed memory 27 +ADV-03 Attack with data-local and hybrid execution 27 +ADV-04 Measure profitable selective participation 28 +ADV-05 Validate physical and complete-board costs 28 +ADV-06 Separate process advantage from specialisation 28 +ADV-07 Evaluate lifetime without forced obsolescence 29 +ADV-08 Independently challenge the best-cost envelope 29 + + + + +IGNEUM + MASTER 2.0 + 125 // PROPOSED + 292 / NOT EXECUTED 70 / 73 + TEST STANDARD / 1.0 + + + + +TEST INDEX / 2 OF 4 + + + +Find a test. +Test IDs are stable. Every entry links to the complete procedure and its acceptance criteria. + +ROT / Epochs, seeds and memory transitions +ROT-01 Agree across every hourly boundary 30 +ROT-02 Cross weekly and family boundaries together 30 +ROT-03 Test miner-voted bring-forward governance 30 +ROT-04 Resist seed selection and faster evaluators 31 +ROT-05 Continue or pause correctly when finality stops 31 +ROT-06 Activate datasets without hidden exclusions 31 +ROT-07 Ablate redundant rotation layers 32 +ROT-08 Pass the no-new-rules counterfactual 32 + + +ECO / Five-year coexistence economics +ECO-01 Reconcile complete cost per accepted work 33 +ECO-02 Separate existing-owner and new-entrant viability 33 +ECO-03 Let the specialist keep its sunk development 33 +ECO-04 Model entry, exit and difficulty response 34 +ECO-05 Stress success, contraction and cheap electricity 34 +ECO-06 Fund security and proving as issuance falls 34 +ECO-07 Price memory growth and honest-card displacement 35 +ECO-08 Reproduce and adversarially audit the model 35 + + +EVM / Execution and developer compatibility +EVM-01 Match the selected EVM semantics 36 +EVM-02 Preserve transaction binding and replay protection 36 +EVM-03 Test two-dimensional fees and proving limits 36 +EVM-04 Exercise block context and randomness assumptions 37 +EVM-05 Run representative contract integration journeys 37 +EVM-06 Validate wallets, RPC and indexers 37 +EVM-07 Handle execution denial-of-service workloads 38 +EVM-08 Verify controlled execution and verifier upgrades 38 + + +ZKP / Consensus-enforced proof validity +ZKP-01 Reject missing and invalid proofs 39 +ZKP-02 Bind program, verifier and security parameters 39 +ZKP-03 Bind network, epoch, job and state roots 39 +ZKP-04 Prevent reward and payout substitution 40 +ZKP-05 Make proof payment idempotent across races 40 +ZKP-06 Verify aggregation coverage and completeness 40 +ZKP-07 Review soundness and verifier resource limits 41 +ZKP-08 Preserve authority and audit all acceptance paths 41 + + + + +IGNEUM + MASTER 2.0 + 126 // PROPOSED + 292 / NOT EXECUTED 71 / 73 + TEST STANDARD / 1.0 + + + + +TEST INDEX / 3 OF 4 + + + +Find a test. +Test IDs are stable. Every entry links to the complete procedure and its acceptance criteria. + +CAP / Sustained proving and delivery +CAP-01 Reproduce the historical consumer-shard result 42 +CAP-02 Prove on the actual mining configuration 42 +CAP-03 Measure the entire request-to-payment path 42 +CAP-04 Sustain meaningful load without queue growth 43 +CAP-05 Overload and recover without false acceptance 43 +CAP-06 Calibrate assignment windows to paid completion 43 +CAP-07 Reassign work when inputs or providers disappear 44 +CAP-08 Deliver customer-verifiable output at scale 44 + + +INC / Rewards, incentives and selfish operators +INC-01 Reconcile issuance, fees, burns and recipients 45 +INC-02 Keep revenue streams and claims separate 45 +INC-03 Let a modified client choose the most profitable task 45 +INC-04 Survive external-demand spikes and token declines 46 +INC-05 Contain job reservation and identity-splitting abuse 46 +INC-06 Test difficulty and timestamp manipulation 46 +INC-07 Resist self-dealing fees and fake proving demand 47 +INC-08 Quantify provider and supplier failure concentration 47 + + +FIN / Consensus safety and recovery +FIN-01 Agree on ordering, work and executed state 48 +FIN-02 Attack finality with split honest populations 48 +FIN-03 Cross authority expiry in a long partition 48 +FIN-04 Stop signing while mining continues 49 +FIN-05 Authenticate voter-set changes and pooled keys 49 +FIN-06 Analyse old-key compromise and long-range histories 49 +FIN-07 Recover deterministically after reconnection and crash 50 +FIN-08 Combine boundaries, faults and adversarial scheduling 50 + + +VER / Wallets, receipts and data availability +VER-01 Authenticate light-client bootstrap 51 +VER-02 Verify evolving authority and execution statements 51 +VER-03 Prove successful payment rather than inclusion 51 +VER-04 Bound cross-chain oracle trust and replay 52 +VER-05 Reconstruct required state without founder storage 52 +VER-06 Detect withholding, corruption and stale data 52 +VER-07 Protect wallet keys, signing and recovery 53 +VER-08 Keep every user-facing state truthful 53 + + + + +IGNEUM + MASTER 2.0 + 127 // PROPOSED + 292 / NOT EXECUTED 72 / 73 + TEST STANDARD / 1.0 + + + + +TEST INDEX / 4 OF 4 + + + +Find a test. +Test IDs are stable. Every entry links to the complete procedure and its acceptance criteria. + +OPS / Independent operation and release security +OPS-01 Run the complete no-founder exercise 54 +OPS-02 Diversify bootstrap and resist peer isolation 54 +OPS-03 Separate update distribution from consensus authority 54 +OPS-04 Recover nodes from crash and storage damage 55 +OPS-05 Isolate untrusted proving workloads 55 +OPS-06 Contain malicious network and API traffic 55 +OPS-07 Detect failures with usable evidence and runbooks 56 +OPS-08 Repeat independent operation across releases 56 + + +UX / Ember, payouts and operator control +UX-01 Onboard ordinary owners on native desktop apps 57 +UX-02 Make pause, stop and safe tuning reliable 57 +UX-03 Show net earnings and compatibility honestly 57 +UX-04 Pay small operators without hidden custody 58 +UX-05 Keep voting keys with the miner through pooling 58 +UX-06 Verify actual miner-selected work templates 58 +UX-07 Expose actionable failures and safe updates 59 +UX-08 Publish competitive accessible software 59 + + +COM / Paid demand and sustainable delivery +COM-01 Deliver a genuine contracted proof pilot 60 +COM-02 Establish independent repeat purchasing 60 +COM-03 Demonstrate service and operator margins 60 +COM-04 Meet the customer service guarantee 61 +COM-05 Compare against the buyer's real alternative 61 +COM-06 Retain buyers after the pilot and subsidy period 61 +COM-07 Fund maintenance without assumed appreciation 62 +COM-08 Let independent developers build useful integrations 62 + + +LEAD / Comparative leadership evidence +LEAD-01 Register a fair contemporary comparison 63 +LEAD-02 Demonstrate comparable operator advantages 63 +LEAD-03 Substantiate the specialist-coexistence claim 63 +LEAD-04 Observe ordinary-operator retention and margins 64 +LEAD-05 Measure control and dependency concentration 64 +LEAD-06 Complete the reliability observation window 64 +LEAD-07 Issue an independent contender assessment 65 +LEAD-08 Keep leadership claims valid after release 65 + + + + +IGNEUM + MASTER 2.0 + 128 // PROPOSED + 292 / NOT EXECUTED 73 / 73 + C / REQUIREMENTS INTEGRATION + + + + +Keep every closure visible. +The original 128 test cases and 17 proposed profiles are preserved in Part B. This section adds the 18 INT +gates from R1 and the 44 closure requirements from R2. These overlap the original tests and one +another; they are not 62 new independent demonstrations of security. + +The original wording is retained below. Stable R2-Fxx-Ryy identifiers are editorial additions for tracking. +No new technical tests were run for this master edition. + + + RECORD SET COUNT STATUS + + + + Original test cases 128 Original NOT RUN statuses retained + + + Original acceptance profiles 17 PROPOSED; approval required + + + R1 integration gates 18 PROPOSED / NOT RUN + + + R2 closure requirements 44 PROPOSED / NOT RUN + + + + + NO SUBSTITUTION + + + A script successfully reproducing a defect is evidence that the defect exists in the model. + It is not a pass of the system requirement that the defect must be absent. + + + +Use the accompanying master traceability JSON to retain the full original test registry, the add-on +requirements and the finding-to-test links. Missing fixtures, missing native tooling or unresolved release +identity remain BLOCKED, not PASS. + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 1 + +MASTER 129 / 292 + CLOSURE REGISTER + + + + +C / R1 INTEGRATION GATES + + + + +INT-01 to INT-09 +ALL PROPOSED / NOT RUN AS FULL-SYSTEM TESTS + + + + GATE REQUIRED CLOSURE - SOURCE WORDING + + + + INT-01 Real proof H cannot authenticate a different statement under a warm cache. + + + Warm/cold/relay/restart/concurrent cache order does not change block or payout decisions; + INT-02 + negative cache isolated. + + + INT-03 Durable payout outbox survives every crash/RPC boundary without duplicate or lost liabilities. + + + INT-04 Corrupt existing pool state, disk-full and reorg cause safe recovery, not silent empty balances. + + + INT-05 The supplied finality implementation matches the approved anchor rule after >window healing. + + + Recovery tests state and preserve their weaker fault bound; interfaces never label it as a + INT-06 + stronger guarantee. + + + INT-07 One v6 object agrees in node, pool, CPU verifier and each supported GPU host across activation. + + + Census, production acceptance, schedule counters and live-dataset tests use the identical + INT-08 + frozen contract. + + + Eight- and twelve-GiB epoch transitions recover deliberately without relying on repeated OOM/ + INT-09 + watchdog cycles. + + +Source: R1, Additional regression gates for the 2.0 registry. These are integrated closures, not replacements for the base standard. + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 2 + +MASTER 130 / 292 + CLOSURE REGISTER + + + + +C / R1 INTEGRATION GATES + + + + +INT-10 to INT-18 +ALL PROPOSED / NOT RUN AS FULL-SYSTEM TESTS + + + + GATE REQUIRED CLOSURE - SOURCE WORDING + + + + INT-10 Metal/CUDA/OpenCL exact dataset geometry agrees; unsupported packs reject before launch. + + + INT-11 Only a memory-reserved proving job launches; mining buffers really release when required. + + + Transient shard errors can retry safely; expiration, loss and paid work remain distinct durable + INT-12 + outcomes. + + + Ember cannot retain a rate-ineligible prior; material workload changes invalidate incompatible + INT-13 + profiles. + + + Protected helper and per-device leases restore owned settings on normal/abnormal exit; real + INT-14 + ACL/security tests. + + + INT-15 Public PoP replay is not session authorization; payout/server/network binding enforced. + + + Pool parsing/queues/connection and crypto budgets remain bounded under controlled + INT-16 + adversarial traffic. + + + Missing oracle/keys/mandatory real-proof fixture blocks the applicable production acceptance + INT-17 + gate. + + + Whole-system economics pass the strongest feasible adversary, including sunk development + INT-18 + and multi-epoch survival. + + +Source: R1, Additional regression gates for the 2.0 registry. These are integrated closures, not replacements for the base standard. + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 3 + +MASTER 131 / 292 + CLOSURE REGISTER + + + + +C / R2 CLOSURE REQUIREMENTS + + + + +Closure requirements F01-F02 +ALL PROPOSED / NOT RUN AS FULL-SYSTEM TESTS + + + + +F01 / Proof-verdict cache omits the statement +being verified +Base tests: ZKP-02, ZKP-03, ZKP-04, ZKP-08 | Related INT: INT-01, INT-02 + + + ID CLOSURE REQUIREMENT - SOURCE WORDING + + + + F01-R01 Valid proof A, warm cache, carried statement B: refuse exactly as a cold node does. + + + F01-R02 Run valid/invalid contexts in both orders, concurrently and across cache eviction/restart. + + + Change payout, network, kind, program ID and activation context; no accepted + F01-R03 + misbinding. + + + A native two-node test must agree on block validity and payouts despite different cache + F01-R04 + histories. + + + + +F02 / Proof-rule infrastructure can fail open +Base tests: GOV-05, ZKP-01, ZKP-07, ZKP-08 | Related INT: INT-17 + + + ID CLOSURE REQUIREMENT - SOURCE WORDING + + + + F02-R01 Release build cannot activate test bypass. + + + F02-R02 Missing oracle or pinned keys prevents service readiness after enforcement activation. + + + F02-R03 Missing proof bytes retry without incorrectly marking a valid block permanently invalid. + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 4 + +MASTER 132 / 292 + CLOSURE REGISTER + + + + +C / R2 CLOSURE REQUIREMENTS + + + + +Closure requirements F03-F04 +ALL PROPOSED / NOT RUN AS FULL-SYSTEM TESTS + + + + +F03 / The bundle contains a v6 candidate, not a +demonstrated integrated v6 release +Base tests: GOV-01, GOV-03, POW-01, ROT-02 | Related INT: INT-07, INT-08 + + + ID CLOSURE REQUIREMENT - SOURCE WORDING + + + + Clean build from one manifest, including the pool and workers, with no unpublished + F03-R01 + vendor tree. + + + Same job context produces identical accepted work in node, CPU reference, CUDA, + F03-R02 + Metal, OpenCL and pool. + + + Cross every scheduled transition with old/new client behavior documented and identical + F03-R03 + rule identities. + + + + +F04 / Finality v4 recovery deliberately has a weaker +safety boundary +Base tests: FIN-02, FIN-03, FIN-07, FIN-08, VER-08 | Related INT: INT-05, INT-06 + + + ID CLOSURE REQUIREMENT - SOURCE WORDING + + + + Native multi-node 40/40/20 partition, equivocation and dust-valid mining on both sides + F04-R01 + past the window. + + + Proof that the chosen recovery guarantee matches the public finality claim; two valid + F04-R02 + contradictory certificates are a hard failure for strong finality. + + + Pause-only resume with historical backfill, missing historical data and all old keys + F04-R03 + returning. + + + F04-R04 Wallet, receipt and oracle consumers distinguish any weaker recovery state. + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 5 + +MASTER 133 / 292 + CLOSURE REGISTER + + + + +C / R2 CLOSURE REQUIREMENTS + + + + +Closure requirements F05-F06 +ALL PROPOSED / NOT RUN AS FULL-SYSTEM TESTS + + + + +F05 / reg64 address coupling has an exact +incremental alternative +Base tests: POW-03, POW-04, ADV-03, ADV-05 | Related INT: INT-18 + + + ID CLOSURE REQUIREMENT - SOURCE WORDING + + + + Native reference-vs-incremental expression equivalence across all source registers and + F05-R01 + real instruction updates. + + + Full-kernel output equivalence, registers, spills, wall power and accepted throughput + F05-R02 + across target GPUs. + + + Adversary physical design includes prefix caching/recomputation cost; no assumed full + F05-R03 + 63-read cost on every load. + + + + +F06 / The v6 acceptance and census gates are not +complete for the final execution +Base tests: GOV-05, POW-01, POW-02, POW-06 | Related INT: INT-08 + + + ID CLOSURE REQUIREMENT - SOURCE WORDING + + + + F06-R01 Acceptance/reference/emitter evaluate the same activated schedule. + + + F06-R02 Full live-dataset census on unseen seeds and the complete v6 pack. + + + A failed experimental rule does not silently exhaust generation or bypass the intended + F06-R03 + resource requirement. + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 6 + +MASTER 134 / 292 + CLOSURE REGISTER + + + + +C / R2 CLOSURE REQUIREMENTS + + + + +Closure requirements F07-F08 +ALL PROPOSED / NOT RUN AS FULL-SYSTEM TESTS + + + + +F07 / VRAM admission and proving deadlines need +one operator-level scheduler +Base tests: GPU-05, CAP-02, CAP-05, UX-02 | Related INT: INT-09, INT-11 + + + ID CLOSURE REQUIREMENT - SOURCE WORDING + + + + Same final v6 configuration: mine -> evict -> prove -> aggregate -> submit -> rebuild -> + F07-R01 + resume; no leaked reservations. + + + OOM, process crash and stale work recover without losing wallet state or silently + F07-R02 + consuming power. + + + 16 GB+ simultaneous mode only after measured peak plus next-epoch headroom; + F07-R03 + smaller-card modes labelled separately. + + + + +F08 / The proving pipeline reports waste and +deadline censoring, not sustained capacity +Base tests: CAP-03, CAP-04, CAP-06, CAP-07 | Related INT: INT-12 + + + ID CLOSURE REQUIREMENT - SOURCE WORDING + + + + Report every eligible job outcome, including expired work; a bounded list cannot hide + F08-R01 + losses. + + + Consumer tiers complete and receive payment for declared jobs before claims about + F08-R02 + income. + + + Sustained real workload across class transitions, with restart/retry and no publisher + F08-R03 + intervention. + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 7 + +MASTER 135 / 292 + CLOSURE REGISTER + + + + +C / R2 CLOSURE REQUIREMENTS + + + + +Closure requirements F09-F10 +ALL PROPOSED / NOT RUN AS FULL-SYSTEM TESTS + + + + +F09 / The economic model explicitly retains a failed +specialist case +Base tests: ADV-05, ADV-08, ECO-03, ECO-08, LEAD-03 | Related INT: INT-18 + + + ID CLOSURE REQUIREMENT - SOURCE WORDING + + + + F09-R01 Generate all pass/fail cells directly from the declared inequalities and inputs. + + + Independent feasibility and cost evaluation of the strongest modeled SRAM/hybrid + F09-R02 + opponent. + + + GPU owners and entrants remain viable under the approved scenario envelope without + F09-R03 + assuming chip absence or death. + + + + +F10 / CUDA production readback has an existing +OpenCL optimization to borrow +Base tests: GPU-06, GPU-08, POW-01, UX-08 | Related INT: INT-07 + + + ID CLOSURE REQUIREMENT - SOURCE WORDING + + + + Compare exact found nonce/hash sets with full-read mode, including all-hit overflow + F10-R01 + and zero-hit cases. + + + F10-R02 Test stale jobs, high-32 rollover, tail batches and asynchronous buffer reuse. + + + F10-R03 Compare production throughput and wall energy, not only the isolated kernel timer. + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 8 + +MASTER 136 / 292 + CLOSURE REGISTER + + + + +C / R2 CLOSURE REQUIREMENTS + + + + +Closure requirements F11-F12 +ALL PROPOSED / NOT RUN AS FULL-SYSTEM TESTS + + + + +F11 / Ember needs workload-aware identity and +objective-aware search +Base tests: GPU-02, GPU-04, UX-02, UX-03 | Related INT: INT-13, INT-14 + + + ID CLOSURE REQUIREMENT - SOURCE WORDING + + + + F11-R01 Goal switch from an efficiency prior can explore higher core/power when policy allows. + + + Driver, workload, dataset, compiler and device changes invalidate certification while + F11-R02 + retaining optional hints. + + + F11-R03 Thermal/error/late-share events revert safely, including process or machine crash. + + + + +F12 / Pool payouts have a broadcast-before- +durable-intent window +Base tests: ZKP-05, UX-04, OPS-04 | Related INT: INT-03, INT-04 + + + ID CLOSURE REQUIREMENT - SOURCE WORDING + + + + Crash before/after broadcast, response timeout, restart before snapshot: no duplicate + F12-R01 + payment or silent debt loss. + + + Same signed transaction retried, fee replacement reconciled by intent, not a new + F12-R02 + payment. + + + F12-R03 Receipt reorg and finality pause leave correct pending obligations. + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 9 + +MASTER 137 / 292 + CLOSURE REGISTER + + + + +C / R2 CLOSURE REQUIREMENTS + + + + +Closure requirements F13-F14 +ALL PROPOSED / NOT RUN AS FULL-SYSTEM TESTS + + + + +F13 / Pool admission and membership need +bounded resources +Base tests: OPS-06, UX-04, UX-05, UX-06 | Related INT: INT-15, INT-16 + + + ID CLOSURE REQUIREMENT - SOURCE WORDING + + + + F13-R01 Repeated authorization rejected or atomically replaces and cleans prior state. + + + F13-R02 Oversized unterminated frame rejected within fixed memory/time budget. + + + Slow clients and invalid share floods cannot grow unbounded member, nonce or + F13-R03 + outgoing state. + + + + +F14 / Developer fleet control must not silently +become the public client trust model +Base tests: OPS-03, OPS-05, UX-02, UX-07 | Related INT: INT-14 + + + ID CLOSURE REQUIREMENT - SOURCE WORDING + + + + Public build has no default arbitrary remote execution and a documented least-privilege + F14-R01 + boundary. + + + F14-R02 Automatic updates off remains off for urgent manifests until explicit action. + + + A compromised fleet/update signing key cannot silently acquire wallet access or activate + F14-R03 + a consensus change. + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 10 + +MASTER 138 / 292 + CLOSURE REGISTER + + + + +C / SIGN-OFF DISCIPLINE + + + + +Evidence before status. +Each closure must identify the exact release, source or finding, required environment, native procedure, +raw evidence, outcome and independent reviewer. A corrected source snippet alone does not prove that +the shipped binaries enforce it. + +Run old and new contexts, positive and negative cases, cold and warm state, restart and concurrent +operation where the underlying finding requires them. Preserve failed and blocked attempts alongside +passing runs. + + + FIELD REQUIRED RECORD + + + + Release identity Commit / lockfile / binary / network object / activation / profile hashes + + + Requirement Original test ID plus INT or R2 closure ID; no identifier reuse + + + Method Native / GPU / SP1 / model / static / team-reported; never conflate + + + Evidence Raw logs, fixtures, command, device configuration, date and reviewer + + + Decision NOT RUN / BLOCKED / FAIL / PASS within an approved scope + + + Claim impact Which public statements are supported, limited, or withdrawn + + + + + NO RANK CERTIFICATE + + + A complete pass can support a credible contender assessment. A finite test set does not + establish a perpetual hardware ceiling, guaranteed profitability, universal safety or an + automatic number-one ranking. + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 11 + +MASTER 139 / 292 + R2 / UPDATED STACK REVIEW + +Preserved report. Fourteen finding labels and 44 closure requirements. Source-review observations, isolated probes +and team data retain their original limits; none is a new full-system acceptance pass. + + + + +IGNEUM 2.0 - Updated full-stack +source review +Review snapshot: 8 October 2026 +Verdict: There is substantial room for improvement and a credible engineering programme. This is a more +complete system than the earlier algorithm pack, but it is not yet an independently validated, integrated +release suitable for the leadership claim. Prioritise proof-cache correctness, exact release integration, +finality guarantees, payment durability and useful paid-work scheduling before adding algorithm +complexity. + +This report reviews the five unique uploaded bundles. Duplicate (1) uploads were byte-identical to their +counterparts. It traces selected critical paths across the generator, node/DAG, proving guests/host, +CUDA/Metal/OpenCL worker hosts, Ember/engine and pool; it is not a line-by-line audit of every file. +Source names and branch boundaries are preserved. No source was modified or deployed. + +What ran: 13 isolated source/math/control-flow probes; within them, 33,024 reg64 address-expression +comparisons with 4,096 point updates; 10 shipped JavaScript tier tests; SHA-256 matching of two +supplied proof guest ELFs and two verifying-key files against their manifest. All these checks completed +as described. A probe reproducing a defect is NOT an acceptance pass. + +What did not run: native Rust tests (no Rust/Cargo toolchain), actual SP1 proving/verification, GPU +execution, live nodes, the pool's payment flow, physical ASIC design or the economic workbook. +Generated packs and parts of the build/vendor context are omitted from the uploads. Therefore modeled +behavior and source assertions are not represented as end-to-end exploit or performance measurements. + +Priority labels: P0 is a release-blocking correctness/integration/guarantee decision in this review, not a +formal CVSS score. P1 is a serious reliability, security, economic or public-product gate. P2 is an +optimisation/product experiment requiring measurement. + + +Improvements over the earlier review + • Real v6 research paths exist: register windows, address folding/reweighting, tracing and geometry + work. Do not repeat the old statement that the archive has no such implementation. + + • Acceptance now executes the shadow for the relevant path, with an explicit regression test. New + source/index concentration checks exist. + + • CUDA and OpenCL serving interfaces enforce 32-nonce alignment and handle high-word transitions; + Metal also partitions work at the boundary. The earlier missing-host concern is partly closed. + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 1 + +MASTER 140 / 292 + R2 / SOURCE REVIEW + + + + + • Proof verification is wired into body/payout paths behind activation, with pinned-key and succession + logic. F01/F02 explain why that still needs repair. + + • OpenCL already performs hit selection with sentinels and overflow fallback. This is an implementation + to reuse, not a missing feature across all workers. + + • Pool template generation commits member voting identities. Ember has real protection and rollback- + related machinery rather than just a preset table. + + • The research records negative results and operational failures. That is useful evidence, not a reason to + suppress them. + + +Finding register + + ID PRIORITY FINDING EVIDENCE + + + + +| F01 | P0 - public/value-bearing release blocker | Proof-verdict cache omits the statement being verified | +SOURCE + ISOLATED CONTROL-FLOW REPRODUCTION | + +| F02 | P0 - release configuration blocker | Proof-rule infrastructure can fail open | STATIC SOURCE | + +| F03 | P0 - freeze/integration blocker | The bundle contains a v6 candidate, not a demonstrated +integrated v6 release | STATIC SOURCE + ARCHIVE PROVENANCE | + +| F04 | P0 - finality guarantee decision | Finality v4 recovery deliberately has a weaker safety boundary | +SOURCE + SOURCE-REPORTED SIMULATION + PURE PREDICATE REPRODUCTION | + +| F05 | P1 - adversarial hardware evaluation | reg64 address coupling has an exact incremental alternative +| EXACT ALGEBRA + 33,024 RANDOMIZED/EDGE COMPARISONS | + +| F06 | P1 - freeze blocker | The v6 acceptance and census gates are not complete for the final execution | +STATIC SOURCE + SOURCE-REPORTED RESULTS | + +| F07 | P1 - miner economics and reliability | VRAM admission and proving deadlines need one operator- +level scheduler | SOURCE-REPORTED HARDWARE RESULTS + STATIC INTEGRATION REVIEW | + +| F08 | P1 - proving product gate | The proving pipeline reports waste and deadline censoring, not +sustained capacity | SOURCE-REPORTED OPERATIONAL DATA; NOT INDEPENDENTLY REPLAYED | + +| F09 | P1 - founding claim not yet earned | The economic model explicitly retains a failed specialist case | +SOURCE-REPORTED MODEL + DISPLAYED-ARITHMETIC CHECK | + +| F10 | P2 - byte-preserving performance experiment | CUDA production readback has an existing OpenCL +optimization to borrow | STATIC SOURCE; SPEEDUP NOT MEASURED | + +| F11 | P2 - product performance | Ember needs workload-aware identity and objective-aware search | +STATIC SOURCE + REACHABILITY EXAMPLE | + +| F12 | P1 - payment integrity | Pool payouts have a broadcast-before-durable-intent window | STATIC +SOURCE + ISOLATED CRASH SEQUENCE | + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 2 + +MASTER 141 / 292 + R2 / SOURCE REVIEW + + + + +| F13 | P1 - service resilience | Pool admission and membership need bounded resources | STATIC +SOURCE + ISOLATED MEMBERSHIP MODEL | + +| F14 | P1 - public client/independence gate | Developer fleet control must not silently become the public +client trust model | STATIC SOURCE + BOOLEAN GUARD REPRODUCTION | + + +F01 - Proof-verdict cache omits the statement +being verified +Priority: P0 - public/value-bearing release blocker +Evidence: SOURCE + ISOLATED CONTROL-FLOW REPRODUCTION + +The native cold verifier checks both the pinned program and the hash of the proof's public values against +the carried statement. That is good. However, ProofPool::verdict_for returns a cached success keyed +only by proof_hash, checking only the accepted program ID. It does not compare the carried statement on +that path. It also returns cached errors without distinguishing intrinsically invalid proof bytes from an +otherwise valid proof queried in the wrong context. + +The isolated model reproduces: a wrong statement is refused with a cold cache; the same wrong +statement is accepted after that proof was cached against its correct statement. Querying the wrong +statement first can poison the later correct lookup. The zero-ID cache wildcard can also bypass a +nonempty accepted-ID list if such an entry has been populated. Host configuration controls that second +case's reachability. + +This is NOT an SP1 forgery. It is a failure to bind a cached verification result to its use. check_record still +checks native execution and signatures, so this finding does not show arbitrary execution roots becoming +valid. But proof payment and block-validity decisions consume the cache. Warm/cold or order-dependent +decisions are unacceptable there. A malicious block producer need not use the honest producer's +template-selection code. Full native reproduction is required to establish exact network impact. + +Fix: cache immutable verified facts (proof kind, actual verifier/program identity, public-values digest, +proof format/security version) and compare the required statement and current permitted IDs on EVERY +lookup. Alternatively, key by all relevant context. Do not use zero as an accepted pinned ID. Distinguish +context-specific refusal from invalid bytes. The relay-time cache population must store the identity +actually verified, not merely a configured host label. Bound cache size and in-flight verification. + +Required closure tests + • Valid proof A, warm cache, carried statement B: refuse exactly as a cold node does. + + • Run valid/invalid contexts in both orders, concurrently and across cache eviction/restart. + + • Change payout, network, kind, program ID and activation context; no accepted misbinding. + + • A native two-node test must agree on block validity and payouts despite different cache histories. + +Exact source locations + • node/igneum/exec/src/proving.rs:1046-1102 + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 3 + +MASTER 142 / 292 + R2 / SOURCE REVIEW + + + + + • node/igneum/exec/src/proving.rs:1358-1379 + + • node/igneum/exec/src/nativeverify.rs:151-177 + + • node/igneum/exec/src/proving.rs:471-489 + + +F02 - Proof-rule infrastructure can fail open +Priority: P0 - release configuration blocker +Evidence: STATIC SOURCE + +check_carried_proofs has a production-compiled environment bypass +(IGNEUM_TEST_SKIP_PROOF_RULE=1) and returns success when the oracle is absent. The comments +explicitly describe these as harness/unit-test accommodations. This is not evidence an unauthenticated +peer can set the environment, nor evidence the normal daemon omits its oracle. It is a configuration +failure mode that contradicts mandatory enforcement if accidentally activated. + +After the rule activates, missing verifier infrastructure should stop startup or validation safely, not silently +disable the rule. Restrict deliberately unsafe test switches to test-only builds. Distinguish pending proof +bytes (retry) from invalid proof (reject) and unavailable trusted verifier (not accepted). + +Required closure tests + • Release build cannot activate test bypass. + + • Missing oracle or pinned keys prevents service readiness after enforcement activation. + + • Missing proof bytes retry without incorrectly marking a valid block permanently invalid. + +Exact source locations + • node/consensus/src/pipeline/body_processor/body_validation_in_context.rs:28-79 + + +F03 - The bundle contains a v6 candidate, not a +demonstrated integrated v6 release +Priority: P0 - freeze/integration blocker +Evidence: STATIC SOURCE + ARCHIVE PROVENANCE + +The v6 freeze contains real candidate flags, a 64-register schedule, address mixing, fold/reweight +experiments and non-power-of-two dataset geometry. It is materially newer than the earlier V2/V3/V4- +only review. Nevertheless the canonical ProgramClass enum in this snapshot ends at V5. The freeze +README itself says the D1 object cut and spec re-cut are subsequent work. The node bundle is from a +different release branch. Generated packs and relevant vendor/build context are omitted. + +There is a concrete seam: the node's EpochSeeds struct requires shadow_reps, but the pool constructs that +type without the field or a struct-update expression. Those exact files cannot be compiled together as +written. This was identified statically, not by running Cargo. It does not establish that another deployed +pool or vendor revision has the mismatch. + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 4 + +MASTER 143 / 292 + R2 / SOURCE REVIEW + + + + +Fix: produce one release manifest that pins node, generator, dataset policy, acceptance, host ABI, miner +app, pool, proof guests/keys and activation. Build the pool and all supported workers against it in CI. +Include executable packs and their authenticated identity. Never combine measurements from different +candidates into a single v6 claim. + +Required closure tests + • Clean build from one manifest, including the pool and workers, with no unpublished vendor tree. + + • Same job context produces identical accepted work in node, CPU reference, CUDA, Metal, OpenCL and + pool. + + • Cross every scheduled transition with old/new client behavior documented and identical rule + identities. + +Exact source locations + • v6/igneum-v6-freeze-tree/README-FREEZE.txt:1-1 + + • pow/src/generator.rs:249-277 + + • pow/src/generator.rs:939-954 + + • node/consensus/pow/src/igneum.rs:72-95 + + • mining/pool/src/node.rs:47-71 + + +F04 - Finality v4 recovery deliberately has a weaker +safety boundary +Priority: P0 - finality guarantee decision +Evidence: SOURCE + SOURCE-REPORTED SIMULATION + PURE PREDICATE REPRODUCTION + +The older unconditional table-expiry problem has been addressed: the v4 anchored table does not simply +disappear. However, after a full window without a lock, the recovery branch accepts strictly more than half +of the anchored weight. The supplied guarantee document openly reports conflicting recovery locks in a +prolonged partition when an equivocator both mines and signs on both sides. The 40/40/20 case is +explicitly included. + +The isolated predicate confirms two sides each holding 60 of the original 100 pass the recovery threshold +after the window, although neither passes the two-thirds threshold before it. This alone is not a full +protocol exploit: sliding tables, ancestry, dust eligibility and signed certificates also matter. The team's +simulation record supplies additional evidence. The same document says its real-node line at the +snapshot is the known-failed v3 case and the v4 line still awaits the node change. + +Do not call normal finality and recovery finality the same irreversible guarantee. Prefer a reviewed +authority-transition/recovery rule retaining the claimed safety assumptions; otherwise restrict and label +the recovery state and dependent wallet/bridge actions explicitly. A timeout does not prove that a missing +authority is permanently gone. + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 5 + +MASTER 144 / 292 + R2 / SOURCE REVIEW + + + + +The pure pause-only predicate refuses every post-window checkpoint, even with 100% anchored +signatures. This is not proof of permanent network liveness failure: historical-checkpoint backfill may re- +anchor first. The reported immediate-heal simulations must be reproduced against the actual +implementation, including that path. + +Required closure tests + • Native multi-node 40/40/20 partition, equivocation and dust-valid mining on both sides past the + window. + + • Proof that the chosen recovery guarantee matches the public finality claim; two valid contradictory + certificates are a hard failure for strong finality. + + • Pause-only resume with historical backfill, missing historical data and all old keys returning. + + • Wallet, receipt and oracle consumers distinguish any weaker recovery state. + +Exact source locations + • node/consensus/src/processes/finality.rs:1111-1128 + + • node/consensus/src/processes/finality.rs:2610-2642 + + • dag/igneum-node-dag/spec/docs/spec/finality-guarantees.md:111-136 + + • dag/igneum-node-dag/spec/docs/spec/finality-guarantees.md:184-197 + + +F05 - reg64 address coupling has an exact +incremental alternative +Priority: P1 - adversarial hardware evaluation +Evidence: EXACT ALGEBRA + 33,024 RANDOMIZED/EDGE COMPARISONS + +The full-chain window computes a rotate-XOR fold over the 63 registers other than the source, then XORs +the source. This connects every register syntactically, but it does not force a physical implementation to +reread and fold all 63 on each load. + +Define a[k] = ROL32(r[k], 63-k), S = XOR of all a[k], and P_s = XOR of a[k] for k < s. Then the exact source +expression is: + + + address_source(s) = r[s] XOR ROR32(P_s, 1) XOR S XOR P_s XOR a[s] + + + + +A prefix-XOR tree supports point updates and prefix queries in logarithmic time. The included model +checked 33,024 comparisons, including 4,096 state updates, without a mismatch. The algebra follows by +distributing the rotation across XOR: values before the excluded source have one fewer subsequent +rotation; values after it retain their original exponent. + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 6 + +MASTER 145 / 292 + R2 / SOURCE REVIEW + + + + +This is NOT evidence that the full hash is cheap, that the necessary 64-register state is compressible to +one word, or that the extra index state is free. Cached prefix state, port bandwidth and update costs must +all be priced. The GPU compiler may already remove some redundant work. It is a concrete alternative the +adversarial designer must be allowed, and potentially a byte-preserving implementation experiment for +both sides. + +Do not respond by adding unmeasured nonlinear work. First implement the cheapest alternatives, +remeasure GPU cost, then compare complete hardware designs. A one-register perturbation test cannot +establish a minimum circuit or storage cost. + +Required closure tests + • Native reference-vs-incremental expression equivalence across all source registers and real + instruction updates. + + • Full-kernel output equivalence, registers, spills, wall power and accepted throughput across target + GPUs. + + • Adversary physical design includes prefix caching/recomputation cost; no assumed full 63-read cost + on every load. + +Exact source locations + • pow/src/verify.rs:674-692 + + • pow/src/generator.rs:258-277 + + +F06 - The v6 acceptance and census gates are not +complete for the final execution +Priority: P1 - freeze blocker +Evidence: STATIC SOURCE + SOURCE-REPORTED RESULTS + +The new code explicitly executes the V4 shadow in its acceptance interpreter, includes repeated-source +and index-concentration checks, and contains a regression test for shadow agreement. That improves on +the older review. The v6 comments nevertheless say reg64's draw/acceptance are the underlying class's, +while the liveness check is a separate research check not wired into canonical acceptance. Its sampling +checks influence, not a formal unavoidable-state lower bound. + +The census is similarly candid: rw2 fails its F8 line; fold plus rw1 is stronger on the reported controls; +reg64/all results are based on the full tracing path with closed-form data, and the live-dataset point +remains owed. These source results must not be promoted into an unconditional full-v6 pass. + +Freeze one agreed acceptance rule for the actual scheduled 64-register execution, and specify safe +deterministic fallback behavior when a candidate fails. Re-run known-bad seeds, unseen seeds, real +datasets, bound headers/nonces, the combined intended width/geometry and all family transitions. +Retain rw2 as a rejected control unless new evidence changes the decision. + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 7 + +MASTER 146 / 292 + R2 / SOURCE REVIEW + + + + +Required closure tests + • Acceptance/reference/emitter evaluate the same activated schedule. + + • Full live-dataset census on unseen seeds and the complete v6 pack. + + • A failed experimental rule does not silently exhaust generation or bypass the intended resource + requirement. + +Exact source locations + • pow/src/accept.rs:114-119 + + • pow/src/accept.rs:625-637 + + • pow/src/accept.rs:867-871 + + • pow/src/generator.rs:258-264 + + • v6/igneum-v6-freeze-tree/docs/analysis/class-v6/census-packs.md:8-22 + + • v6/igneum-v6-freeze-tree/docs/analysis/class-v6/census-packs.md:40-49 + + +F07 - VRAM admission and proving deadlines need +one operator-level scheduler +Priority: P1 - miner economics and reliability +Evidence: SOURCE-REPORTED HARDWARE RESULTS + STATIC INTEGRATION REVIEW + +The coexistence records report successful standalone compressed proofs: 13.2 seconds on a 3060 12 GB +and 8.2 seconds on a 4060 8 GB after correcting the packaged prover server. They also report that both +fail when run beside the 5.5 GiB dataset miner, with device allocation failures while mining continues. +These are team measurements, not measurements made for this review. The registered reg64 rows use a +different kit configuration and must not be combined with ds55 rows as one benchmark. + +The right product path is explicit modes: simultaneous execution only on tested configurations with +headroom; time-sharing on smaller cards with actual dataset eviction/release and confirmed memory +availability; mining-only where a complete paid proof job cannot fit. Merely pausing kernel dispatch does +not establish that GPU allocations were released. + +Use per-device identity and a memory reservation/lease state machine across miner, prover, aggregation, +benchmark and next-epoch preparation. Include time to evict/rebuild datasets, WSL process startup, +aggregation and payment deadlines in job admission. Do not market an isolated successful shard as proof +that the card can finish the economically relevant segment. + +Required closure tests + • Same final v6 configuration: mine -> evict -> prove -> aggregate -> submit -> rebuild -> resume; no + leaked reservations. + + • OOM, process crash and stale work recover without losing wallet state or silently consuming power. + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 8 + +MASTER 147 / 292 + R2 / SOURCE REVIEW + + + + + • 16 GB+ simultaneous mode only after measured peak plus next-epoch headroom; smaller-card modes + labelled separately. + +Exact source locations + • v6/igneum-v6-freeze-tree/docs/analysis/class-v6/coexist-rows.md:17-37 + + • v6/igneum-v6-freeze-tree/docs/analysis/class-v6/coexist-rows.md:60-86 + + +F08 - The proving pipeline reports waste and +deadline censoring, not sustained capacity +Priority: P1 - proving product gate +Evidence: SOURCE-REPORTED OPERATIONAL DATA; NOT INDEPENDENTLY REPLAYED + +The supplied pipeline report says the requested two-hour declared-load window does not exist in its +record. It describes a class-v5 transition stall/partition and 93 paid segments in the paid interval, not a +successful end-to-end hold at 150 transactions per second. Its 3060 tier completed zero paid segments +over 313 claims. This does not prove a 3060 can never prove profitably: the same report says its +completed submissions occurred after the stall, and the standalone fixture succeeds. It does show the +claimed consumer-paid-work experience is not established by this run. + +A particularly important measurement issue: the worklist stays around 600 entries because entries expire +at a deadline whether proved or not. Therefore bounded queue length does not establish sufficient +proving capacity. The report itself discloses this mechanism. + +Add lifecycle accounting: eligible work = completed + active + expired + explicitly cancelled, with +definitions preventing double-counting. Publish deadline misses and useful accepted proof throughput, +not just queue depth. Attribute failure to protocol partition, packaging, proving, assignment race, +aggregation or submission. The source reports 70 wasted card-hours versus roughly 4 paid, dominated by +the chain incident, so it would be wrong to call that all a prover-speed failure. + +Prioritise feasible job sizing and deadlines, resumable verified shards/checkpoints, early cancellation of +obsolete claims, and bounded assignment protection. Protection must prevent slow or malicious +claimants from monopolising work; do not simply promise no competing completion can ever occur. Run +the two-hour workload test on the pinned release, then a longer independent soak. + +Required closure tests + • Report every eligible job outcome, including expired work; a bounded list cannot hide losses. + + • Consumer tiers complete and receive payment for declared jobs before claims about income. + + • Sustained real workload across class transitions, with restart/retry and no publisher intervention. + +Exact source locations + • proving/igneum-proving/docs/analysis/proving-pipeline-2026-10-08.md:7-16 + + • proving/igneum-proving/docs/analysis/proving-pipeline-2026-10-08.md:35-84 + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 9 + +MASTER 148 / 292 + R2 / SOURCE REVIEW + + + + + • proving/igneum-proving/docs/analysis/proving-pipeline-2026-10-08.md:86-121 + + +F09 - The economic model explicitly retains a failed +specialist case +Priority: P1 - founding claim not yet earned +Evidence: SOURCE-REPORTED MODEL + DISPLAYED-ARITHMETIC CHECK + +The coexistence model states that the desired competitiveness statement does not hold for its modeled +N2 SRAM die after development is sunk, and that the remaining deterrent is the investment decision. That +is not proof the proposed die is manufacturable at the stated cost or throughput. It is also not evidence +that the fundamental gate has passed. + +There are at least two items to repair before using the model as certification. Its condition (c) requires +fleet cost to exceed a year's mining revenue but labels USD 18M against USD 40-80M a pass; those +displayed numbers do not satisfy that inequality. The table or criterion may be mistaken. Condition (g) +also treats proving income as a business the specialised supplier cannot enter because its hash engine +cannot prove. A company can own companion GPUs or buy proofs; the single-device limitation does not +exclude the operator. + +Reproduce the model from raw inputs, price the SRAM/recomputation design at physical board +boundaries, include uncertainty and independent hardware critique, and test a hybrid operator. Treat +unknown feasibility as unknown, not either a proven attack or an automatic pass. No retirement credit +without a demonstrated adaptation penalty. + +Required closure tests + • Generate all pass/fail cells directly from the declared inequalities and inputs. + + • Independent feasibility and cost evaluation of the strongest modeled SRAM/hybrid opponent. + + • GPU owners and entrants remain viable under the approved scenario envelope without assuming chip + absence or death. + +Exact source locations + • v6/igneum-v6-freeze-tree/docs/analysis/class-v6/coexistence-model.md:299-321 + + +F10 - CUDA production readback has an existing +OpenCL optimization to borrow +Priority: P2 - byte-preserving performance experiment +Evidence: STATIC SOURCE; SPEEDUP NOT MEASURED + +The CUDA serving loop synchronises and copies one 64-bit result per nonce to the CPU, then scans it +while holding its GPU mutex. For 2^24 nonces that is 128 MiB of result data per batch. Its benchmark +times the kernel/synchronisation but reads the full result only for warm-up, so the benchmark does not +include the same per-batch production cost. + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 10 + +MASTER 149 / 292 + R2 / SOURCE REVIEW + + + + +OpenCL already contains a select kernel that returns matching nonce/hash pairs plus sentinel words, with +a counter and full-read fallback when more than 256 hits occur. This is not missing everywhere: it is a +cross-backend parity opportunity. Port the proven shape to CUDA first as a separate selection pass, +retaining correctness sentinels and overflow handling. Then test fusion/asynchronous overlap if justified. +Metal still scans shared output on the CPU; unified memory means it is not the same PCIe-copy problem, +so profile it separately. + +Benchmark accepted shares per wall-joule in serving mode, including setup, stale cancellation, readback, +host power and pool submission. No percentage gain is claimed here. + +Required closure tests + • Compare exact found nonce/hash sets with full-read mode, including all-hit overflow and zero-hit + cases. + + • Test stale jobs, high-32 rollover, tail batches and asynchronous buffer reuse. + + • Compare production throughput and wall energy, not only the isolated kernel timer. + +Exact source locations + • mining/proto-cuda/nvrtc/worker.cpp:1254-1295 + + • mining/proto-cuda/nvrtc/worker.cpp:1318-1341 + + • mining/proto-opencl/host.c:1652-1705 + + • mining/proto-opencl/host.c:1882-1899 + + • mining/proto-metal/main.swift:3344-3370 + + +F11 - Ember needs workload-aware identity and +objective-aware search +Priority: P2 - product performance +Evidence: STATIC SOURCE + REACHABILITY EXAMPLE + +Ember has useful thermal/fault checks, power and clock controls, calibration rows and fleet priors. Its +shipped tier tests pass in this review. Those tests do not measure actual safe tuning or globally optimal +settings. + +The five-step hill climb proposes memory-up, core-down or both, even for MaxRate (which changes the +score to MH/s). Starting from a low-clock efficiency prior, this search cannot propose a higher core clock +or change the fixed power cap to escape that starting regime. A full sweep can choose a new start, so the +finding is a limitation of this climb, not evidence every MaxRate setting is wrong. + +The prior key uses card model, driver major and class. The workload class helper is based on load/wide- +load counts. This is insufficient as a validated measurement identity for changes in memory geometry, +compiler, reg64 schedule or concurrent proving. A prior may remain a useful starting hint; it should not be +treated as a current certified optimum. + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 11 + +MASTER 150 / 292 + R2 / SOURCE REVIEW + + + + +Use a two-sided, bounded search appropriate to the chosen objective; rebase when switching goals; +fingerprint the actual workload/backend and retain per-device calibration separately from fleet hints. Use +paired A/B/A samples, a stability soak and rejected-work checks. Support separate mining-only, proving- +only and hybrid profiles, coordinated by the device scheduler. Optimise accepted work or transparent net- +return estimates, not raw displayed MH/s alone. + +Required closure tests + • Goal switch from an efficiency prior can explore higher core/power when policy allows. + + • Driver, workload, dataset, compiler and device changes invalidate certification while retaining optional + hints. + + • Thermal/error/late-share events revert safely, including process or machine crash. + +Exact source locations + • mining/app/igneum-app/src/ember.rs:211-280 + + • mining/app/igneum-app/src/ember.rs:493-520 + + • mining/app/igneum-app/src/ember.rs:606-619 + + +F12 - Pool payouts have a broadcast-before- +durable-intent window +Priority: P1 - payment integrity +Evidence: STATIC SOURCE + ISOLATED CRASH SEQUENCE + +The payout loop broadcasts first, then updates in-memory balances and records; disk snapshots are a +separate periodic loop. If a transaction succeeds externally and the process dies before the debit is +durable, restart can load the old payable balance and send again using a later nonce. A lost RPC response +creates a related uncertain-outcome problem. The isolated model shows 100 units due becoming 200 +externally paid under those assumptions; no actual transaction was sent. + +Receipt checking does exist, and failed receipts re-credit balances. Do not describe this as a pool with no +receipt logic. However, a receipt is marked confirmed immediately and the loop subsequently visits only +sent records; the supplied path does not establish finality-aware reorg handling. + +Persist an idempotent payment intent and exact signed transaction/hash BEFORE broadcast, reserve the +balance atomically, reconcile the same intent after timeout/restart, and finalise against the chain's +declared finality. Use explicit prepared/broadcast/mined/finalised/reorged/replaced states. Test crashes +around every durable step. + +Required closure tests + • Crash before/after broadcast, response timeout, restart before snapshot: no duplicate payment or + silent debt loss. + + • Same signed transaction retried, fee replacement reconciled by intent, not a new payment. + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 12 + +MASTER 151 / 292 + R2 / SOURCE REVIEW + + + + + • Receipt reorg and finality pause leave correct pending obligations. + +Exact source locations + • mining/pool/src/payout.rs:228-261 + + • mining/pool/src/payout.rs:265-296 + + • mining/pool/src/main.rs:138-149 + + +F13 - Pool admission and membership need +bounded resources +Priority: P1 - service resilience +Evidence: STATIC SOURCE + ISOLATED MEMBERSHIP MODEL + +The server checks MAX_LINE after reading a full line, uses an unbounded outgoing channel, and inserts a +nonce into a job's seen set before validation. Repeated Authorize requests create fresh members without +removing or rejecting the prior one, while disconnect removes only the latest member. The small state- +machine reproduction leaves two members after three authorizations on one connection and disconnect. + +These are resource-control issues, not demonstrated remote exploits against a running pool. The verifier +semaphore is a useful existing control but does not bound every queue or allocation. + +Enforce frame size while reading, bounded write queues, connection/request budgets, a single +authenticated membership per session, cheap target/context prefilters, and bounded deduplication with +in-flight handling. Test slow readers and malformed/invalid share floods without expensive network +attacks. Member vote keys are already committed into the template; preserve that improvement. + +Required closure tests + • Repeated authorization rejected or atomically replaces and cleans prior state. + + • Oversized unterminated frame rejected within fixed memory/time budget. + + • Slow clients and invalid share floods cannot grow unbounded member, nonce or outgoing state. + +Exact source locations + • mining/pool/src/server.rs:62-99 + + • mining/pool/src/server.rs:115-175 + + • mining/pool/src/server.rs:234-255 + + • mining/pool/src/server.rs:281-299 + + • mining/pool/src/node.rs:41-48 + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 13 + +MASTER 152 / 292 + R2 / SOURCE REVIEW + + + + +F14 - Developer fleet control must not silently +become the public client trust model +Priority: P1 - public client/independence gate +Evidence: STATIC SOURCE + BOOLEAN GUARD REPRODUCTION + +The supplied settings explicitly call remote jobs default-on for the devnet build. Jobs are signed and have +a visible disable switch; disabling aborts work. This is not a hidden unauthenticated backdoor. It is still +powerful publisher control: run-script, fetch, collect, restart and update-now jobs share the OTA signing +key, and some jobs run elevated or as WSL root. + +The updater's auto-off guard is bypassed for an urgent release (unsupported version or nearby fork). This +is intentional in the supplied policy, not a signature bypass. The remaining staging/safety checks still +apply. An operator who disabled automatic updates should not unknowingly grant an urgency label +permission to install arbitrary future software. + +Separate a controlled lab/developer build from the public miner; remove arbitrary remote execution from +the public default or use narrow explicit per-capability consent and a separate trust root. Keep user +update acceptance distinct from consensus activation. Emergency safety notifications may pause +unsupported operations; they should not silently override the user's installation choice. Review any +manifest-delivered consensus overrides under the same rule. + +Required closure tests + • Public build has no default arbitrary remote execution and a documented least-privilege boundary. + + • Automatic updates off remains off for urgent manifests until explicit action. + + • A compromised fleet/update signing key cannot silently acquire wallet access or activate a consensus + change. + +Exact source locations + • mining/app/igneum-app/src/config.rs:75-81 + + • mining/app/igneum-app/src/config.rs:135-151 + + • mining/app/igneum-app/src/jobrun.rs:1-19 + + • mining/app/igneum-app/src/ota.rs:540-555 + + • mining/app/igneum-app/src/ota.rs:589-595 + + +Work sequence + +1. Establish a coherent, enforced release +Fix F01/F02 and the F03 release seam. Pin source, parameters, guests, keys, worker contracts and +generated artifacts. Reproduce cache-order independence and exact node/worker/pool agreement +natively. Resolve the finality guarantee in F04 before calling recovery irreversible. + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 14 + +MASTER 153 / 292 + R2 / SOURCE REVIEW + + + + +2. Protect operator money and control +Implement the payment journal, bound the pool, separate public/developer controls, and reproduce +crash/restart behavior. Keep member voting ownership intact. + +3. Make proving economically useful on the declared hardware +Implement coordinated GPU memory admission and deadline-aware work selection. Re-run a declared +sustained workload across the actual transition boundary; report paid completions, expiry and wasted +work, not just worklist size or shard speed. + +4. Improve honest execution and attack the same candidate +Port the OpenCL result-selection pattern to CUDA. Evaluate objective-aware Ember tuning and exact +reg64 alternatives. Re-run full live-dataset acceptance and physical adversarial cost analysis against the +identical candidate. + +5. Earn the competitive claim +Close the economic-model failures or explicitly narrow the approved scenario envelope. Run the existing +2.0 acceptance programme on the pinned release, including independent review, repeat external buyers, +operator retention, current comparisons and sustained no-founder operation. None of the probes here +establishes a numerical market ranking. + + +What this means for the number-one ambition +The project has a concrete basis for continued engineering, and several improvements can be made +without inventing another mining primitive. The most valuable product is not a nominally complicated +hash: it is correctly enforced work, competitive complete-system cost, reliable payment, independent +control and repeat demand. + +The founding coexistence statement is not yet established by these uploads. In particular, the source's +own SRAM-die model is a failed case, its full-v6 live-dataset census is unfinished, its pipeline hold was +interrupted, and its finality recovery deliberately trades safety for recovery. These are not grounds for +declaring the ambition impossible. They are specific proof obligations that must be closed rather than +averaged away. + +Passing the repaired technical and economic gates could support a credible leadership-contender case. It +cannot guarantee adoption, all future hardware behavior, or a number-one ranking. + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 15 + +MASTER 154 / 292 + R2 / SOURCE REVIEW + + + + +Reproduction results + + { + "review": "Igneum updated-stack source review", + "date": "2026-10-08", + "native_rust_executed": false, + "gpu_executed": false, + "sp1_executed": false, + "probe_count": 13, + "probes": [ + { + "probe": "cache_wrong_statement_after_success", + "classification": "ISOLATED_CONTROL_FLOW_REPRODUCTION", + "cold_wrong_context": "Invalid", + "warm_wrong_context": "Verified", + "limitation": "No SP1 proof constructed; models the supplied early-return cache + logic." + }, + { + "probe": "cache_negative_context_poisoning", + "classification": "ISOLATED_CONTROL_FLOW_REPRODUCTION", + "valid_context_after_bad_context": "Invalid", + "fresh_valid_context": "Verified" + }, + { + "probe": "cache_zero_id_accepts_pinned_epoch", + "classification": "ISOLATED_CONTROL_FLOW_REPRODUCTION", + "result": "Verified", + "accepted_ids": [ + "vk-B" + ], + "cached_id": "ZERO", + "limitation": "Reachability depends on host configuration and how the cache entry was + populated." + }, + { + "probe": "reg64_rotate_xor_prefix_equivalence", + "classification": "EXACT_ALGEBRA_WITH_RANDOMIZED_CHECKS", + "comparisons": 33024, + "point_updates": 4096, + "mismatches": 0, + "equation": "a[k]=ROL(r[k],63-k); P=XOR(a[k],k kaspa_consensus_core::proving::ProofVerdict { + 1049: use kaspa_consensus_core::proving::{ProofKind, ProofVerdict}; + 1050: let accepted = self.cfg.accepted_ids(c.kind, c.carrier_daa); + 1051: let held = { + 1052: let inner = self.inner.lock(); + 1053: if let Some(v) = inner.verdicts.get(&c.proof_hash) { + 1054: return match v { + 1055: Ok(id) if accepted.is_empty() || *id == B256::ZERO || + accepted.contains(id) => ProofVerdict::Verified, + 1056: Ok(id) => ProofVerdict::Invalid(format!("{}: verified under + program id {id}, which the carrier's epoch at DAA {} does not accept (accepted: {})", + c.label, c.carrier_daa, accepted.iter().map(|i| i.to_string()).collect::>().join(", + "))), + 1057: Err(e) => ProofVerdict::Invalid(e.clone()), + 1058: }; + 1059: } + 1060: inner.proofs.get(&c.proof_hash).map(|(k, b)| (*k, b.clone())) + 1061: }; + 1062: let Some((kind, bytes)) = held else { return ProofVerdict::Missing }; + 1063: if kind != c.kind { + 1064: return ProofVerdict::Invalid(format!("the proof is held as a {kind:?} + proof and the record carries it as a {:?} record", c.kind)); + 1065: } + 1066: let started = std::time::Instant::now(); + 1067: // in-process on Unix; through the installed host on Windows (sp1-jit does not + build there) + 1068: let r = if crate::nativeverify::IN_PROCESS { + 1069: crate::nativeverify::verify_kind(keys, c.kind, &bytes, &c.statement, + &c.label, &accepted) + 1070: } else if let VerifyMode::Command(host) = &self.cfg.verify { + 1071: // the host pins one pair, the one it names at start + (`cfg.shard_program_id` / `aggregator_id`, zero when unnamed) + 1072: crate::nativeverify::verify_via_host(host, c.kind, &bytes, &c.statement, + &c.label).map(|()| self.host_pair_id(c.kind)) + 1073: } else { + 1074: Err(format!("{}: this build has no in-process verifier and no verifier + host is configured", c.label)) + 1075: }; + 1076: info!("[igneum-exec] consensus verify of {}: {} in {:.3} s", c.label, if + r.is_ok() { "VERIFIED" } else { "REFUSED" }, started.elapsed().as_secs_f64()); + 1077: self.inner.lock().verdicts.insert(c.proof_hash, r.clone()); + 1078: match r { + 1079: Ok(_) => ProofVerdict::Verified, + 1080: Err(e) => ProofVerdict::Invalid(e), + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 21 + +MASTER 160 / 292 + R2 / SOURCE REVIEW + + + + + 1081: } + 1082: } + 1083: + 1084: /// The pair the installed host verifies under: the ids named at start (the + object's or the host's `--mode id`), + 1085: /// zero when unnamed (then any epoch without pinned ids accepts it). + 1086: fn host_pair_id(&self, kind: kaspa_consensus_core::proving::ProofKind) -> B256 { + 1087: match kind { + 1088: kaspa_consensus_core::proving::ProofKind::Shard => + self.cfg.shard_program_id.unwrap_or(B256::ZERO), + 1089: kaspa_consensus_core::proving::ProofKind::Segment => + self.cfg.aggregator_id.unwrap_or(B256::ZERO), + 1090: } + 1091: } + 1092: + 1093: /// Enforced proving: whether a carried proof is VERIFIED by this node (the cached + verdict of the body rule or the + 1094: /// relay-time verifier, else a verify now when the bytes are held and keys + exist). Missing bytes, no keys, a wrong + 1095: /// proof, another program id: false, and the record pays nothing. + 1096: pub fn verified_for_payment(&self, c: + &kaspa_consensus_core::proving::CarriedProof, keys: Option<&crate::nativeverify::Keys>) -> + bool { + 1097: match keys { + 1098: Some(k) => matches!(self.verdict_for(c, k), + kaspa_consensus_core::proving::ProofVerdict::Verified), + 1099: None => { + 1100: let accepted = self.cfg.accepted_ids(c.kind, c.carrier_daa); + 1101: matches!(self.inner.lock().verdicts.get(&c.proof_hash), Some(Ok(id)) + if accepted.is_empty() || *id == B256::ZERO || accepted.contains(id)) + 1102: } + + + + +node/igneum/exec/src/proving.rs:1358-1379 +SHA-256: 92302ee089fca720f2ee6ac0756c0054a01c995db4c997d358683a2a08f3401b + + + 1358: fn set_verified(&self, key: (Hash, u32, Hash), ok: bool, note: String) { + 1359: let host_id = + self.host_pair_id(kaspa_consensus_core::proving::ProofKind::Shard); + 1360: let mut inner = self.inner.lock(); + 1361: if let Some(h) = inner.entries.get(&key).map(|e| e.record.proof_hash) { + 1362: inner.verdicts.insert(h, if ok { Ok(host_id) } else { Err(note.clone()) + }); + 1363: } + 1364: if ok { + 1365: inner.verified_count += 1; + 1366: } else { + 1367: inner.failed_count += 1; + 1368: } + 1369: if let Some(e) = inner.entries.get_mut(&key) { + 1370: e.verified = Some(ok); + 1371: e.note = note; + 1372: } + 1373: } + 1374: + 1375: fn set_segment_verified(&self, key: (u64, Hash), ok: bool, note: String) { + 1376: let host_id = + self.host_pair_id(kaspa_consensus_core::proving::ProofKind::Segment); + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 22 + +MASTER 161 / 292 + R2 / SOURCE REVIEW + + + + + 1377: let mut inner = self.inner.lock(); + 1378: if let Some(h) = inner.segments.get(&key).map(|e| e.record.proof_hash) { + 1379: inner.verdicts.insert(h, if ok { Ok(host_id) } else { Err(note.clone()) + }); + + + + +node/igneum/exec/src/nativeverify.rs:151-177 +SHA-256: bbb11e72495c04f44172c2ec6f230919f8ff96b8b45847e03efacd063f94da96 + + + 151: pub fn verify_kind(keys: &Keys, kind: ProofKind, bytes: &[u8], statement: &[u8; 32], + what: &str, accepted: &[B256]) -> Result { + 152: let proof: SP1ProofWithPublicValues = bincode::deserialize(bytes).map_err(|e| + format!("{what}: the proof bytes are not a bincode SP1 proof: {e}"))?; + 153: let Some(claimed) = claimed_program_id(&proof) else { return Err(format!("{what}: + the proof is not a compressed SP1 proof")) }; + 154: if !accepted.is_empty() && !accepted.contains(&claimed) { + 155: return Err(format!("{what}: the proof claims program id {claimed}, which the + carrier's epoch does not accept (accepted: {})", accepted.iter().map(|i| + i.to_string()).collect::>().join(", "))); + 156: } + 157: let Some((id, vk)) = keys.pairs(kind).into_iter().find(|(id, _)| *id == claimed) + else { + 158: return Err(format!("{what}: the proof claims program id {claimed}, which this + node does not embed (embedded: {})", keys.ids(kind).iter().map(|i| + i.to_string()).collect::>().join(", "))); + 159: }; + 160: verify(bytes, statement, vk, id, what).map(|()| id) + 161: } + 162: + 163: /// The verifier itself: the proof bytes (bincode `SP1ProofWithPublicValues`) must + claim the pinned id, carry + 164: /// public values whose keccak-256 is `statement`, and verify under `vk`. + 165: pub fn verify(bytes: &[u8], statement: &[u8; 32], vk: &SP1VerifyingKey, pinned_id: + B256, what: &str) -> Result<(), String> { + 166: let proof: SP1ProofWithPublicValues = bincode::deserialize(bytes).map_err(|e| + format!("{what}: the proof bytes are not a bincode SP1 proof: {e}"))?; + 167: let got = alloy_primitives::keccak256(proof.public_values.as_slice()); + 168: if got.as_slice() != statement { + 169: return Err(format!("{what}: the proof's public values hash to {got}, the + record's statement is 0x{}", hex::encode(statement))); + 170: } + 171: match claimed_program_id(&proof) { + 172: Some(id) if id == pinned_id => {} + 173: Some(id) => return Err(format!("{what}: the proof claims program id {id}, the + pinned id is {pinned_id}")), + 174: None => return Err(format!("{what}: the proof is not a compressed SP1 proof")), + 175: } + 176: let verifier = LightProver::new(); + 177: verifier.verify(&proof, vk, None).map_err(|e| format!("{what}: the SP1 verifier + refuses the proof: {e}")) + + + + +node/igneum/exec/src/proving.rs:471-489 +SHA-256: 92302ee089fca720f2ee6ac0756c0054a01c995db4c997d358683a2a08f3401b + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 23 + +MASTER 162 / 292 + R2 / SOURCE REVIEW + + + + + 471: pub fn carried_payouts(state: &ExecState, cfg: &ProvingConfig, carrier_number: u64, + carrier_daa: u64, carried: Vec<(Hash, ProofRecord)>, paid: &mut HashMap<(Hash, u32), + PaidShard>, verified: &dyn Fn(&kaspa_consensus_core::proving::CarriedProof) -> bool) -> + (Vec<(Address, U256)>, Vec) { + 472: let mut payouts = Vec::new(); + 473: let mut out = Vec::with_capacity(carried.len()); + 474: let active = cfg.active_at(carrier_daa); + 475: let enforced = carrier_daa >= cfg.verified_payout_from; + 476: for (carrier, record) in carried { + 477: let key = record.shard_key(); + 478: let outcome = match check_record(state, cfg, &record, carrier_number, + carrier_daa) { + 479: Err(e) => CarriedRecord { record, carrier, rejected: e, paid_wei: 0 }, + 480: Ok(_) if paid.contains_key(&key) => CarriedRecord { record, carrier, + rejected: "shard already paid".into(), paid_wei: 0 }, + 481: Ok(_) if !active => CarriedRecord { record, carrier, rejected: + format!("before activation (DAA {} of {})", carrier_daa, cfg.activation_daa), paid_wei: 0 }, + 482: Ok(_) if enforced && !verified(&carried_proof_of(&record, carrier_daa)) => + CarriedRecord { record, carrier, rejected: "proof not verified by this node (enforced + proving): no payment".into(), paid_wei: 0 }, + 483: Ok(c) => { + 484: let wei = shard_parts(cfg, c.segment_daa, c.pool_credit_wei, + c.shards)[record.shard as usize]; + 485: let payout = Address::from(record.payout); + 486: if wei > 0 { + 487: payouts.push((payout, U256::from(wei))); + 488: } + 489: paid.insert(key, PaidShard { carrier_number, key_hash: + record.key_hash(), payout, wei }); + + + +F02 excerpts + +node/consensus/src/pipeline/body_processor/body_validation_in_context.rs:28-79 +SHA-256: 80de37d434290030d6e17ce71a6cf11e6ed9ddd011288acc1cc6004d3312d5f5 + + + 28: /// `Params::proof_rule_active_from()` (block zero under the named switch + `verifier_in_consensus`, else the DAA floor + 29: /// `proving_consensus_verify_daa`), every proof record the coinbase carries + 30: /// must come with a proof the node holds and that verifies for the record's + statement under the pinned program + 31: /// id. A failing proof makes the block invalid (a producer paid for fake proofs in + its own blocks was the one + 32: /// attack line where a majority earned more than it spent); a proof not held yet is + `IgneumProofMissing`, which + 33: /// is retried, not marked, since the relay delivers proof bytes beside their + records a moment before or after + 34: /// the carrying block. The verifier is the execution layer's (`set_proof_oracle`); + the verdicts are cached by + 35: /// proof hash, so a proof verified at relay time costs nothing here. No oracle + (unit tests) = the rule is off. + 36: fn check_carried_proofs(self: &Arc, block: &Block) -> BlockProcessResult<()> { + 37: if block.header.daa_score < self.proof_rule_active_from { + 38: return Ok(()); + 39: } + 40: // the attacker's shape for the harness only: a node with the rule switched off + carries fake proofs; every + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 24 + +MASTER 163 / 292 + R2 / SOURCE REVIEW + + + + + 41: // honest peer refuses its blocks (IGNEUM_TEST_SKIP_PROOF_RULE=1, never set on a + live node) + 42: static SKIP: std::sync::OnceLock = std::sync::OnceLock::new(); + 43: if *SKIP.get_or_init(|| std::env::var("IGNEUM_TEST_SKIP_PROOF_RULE").map(|v| v + == "1").unwrap_or(false)) { + 44: return Ok(()); + 45: } + 46: let Some(oracle) = kaspa_consensus_core::proving::proof_oracle() else { return + Ok(()) }; + 47: // the rule applies from the floor only (never on the live Devnet 3 object): + below it a carried + 48: // record is what the record flows and the pool make of it, as on 0.3.17 + 49: if !kaspa_consensus_core::proving::proof_rule_applies(block.header.daa_score, + oracle.active_from()) { + 50: return Ok(()); + 51: } + 52: let Some(coinbase) = block.transactions.first() else { return Ok(()) }; + 53: let carried = kaspa_consensus_core::proving::carried_proofs(&coinbase.payload, + block.header.daa_score); + 54: if carried.is_empty() { + 55: return Ok(()); + 56: } + 57: // every proof in parallel: a cold verify is 0.26 to 0.53 s a proof on one core + (M5 Max to a 2019 Zen 2) + 58: let verdicts: Vec<_> = self.thread_pool.install(|| { + 59: use rayon::prelude::*; + 60: carried.par_iter().map(|c| (c, oracle.verdict(c))).collect() + 61: }); + 62: let mut missing = Vec::new(); + 63: let mut missing_hashes = Vec::new(); + 64: for (c, v) in verdicts { + 65: match v { + 66: kaspa_consensus_core::proving::ProofVerdict::Verified => {} + 67: kaspa_consensus_core::proving::ProofVerdict::Invalid(why) => { + 68: return Err(RuleError::IgneumInvalidProofRecord(format!("{} (proof + {}): {why}", c.label, faster_hex::hex_string(&c.proof_hash[..8])))); + 69: } + 70: kaspa_consensus_core::proving::ProofVerdict::Missing => { + 71: missing.push(format!("{} (proof {})", c.label, + faster_hex::hex_string(&c.proof_hash[..8]))); + 72: missing_hashes.push(Hash::from_bytes(c.proof_hash)); + 73: } + 74: } + 75: } + 76: if !missing.is_empty() { + 77: return Err(RuleError::IgneumProofMissing(missing_hashes, missing.join("; + "))); + 78: } + 79: Ok(()) + + + +F03 excerpts + +v6/igneum-v6-freeze-tree/README-FREEZE.txt:1-1 +SHA-256: 26e77e724331420c066449bc4ee5e8ff6782a516b5329cb71a6b0fc66bdf8207 + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 25 + +MASTER 164 / 292 + R2 / SOURCE REVIEW + + + + + 1: Frozen generator tree for class v6: master 2e9b3e73 on 8 Oct 2026 (igneum-pow at the + freeze sha c245d50b9, fingerprint a65e4c5a; the D1 object cut lands 23:30 BST with the five + digests and the spec re-cut). Spec section 01 here is still version 0.2 until that re-cut. + + + + +pow/src/generator.rs:249-277 +SHA-256: 751f39aeedb2987856343e2a67c7aeca7daa47ddafe5192c50a19b1d425e3a8a + + + 249: /// Class v6 lane 1 (`docs/design/class-v6-rotating-family.md` section 2, the index + fold; a research class, + 250: /// 8 October 2026): `true` folds the product's low bits in every era load address + before the stride rotation + 251: /// (`verify::load_index`: `y = x * M; y ^= y >> 16; y = rotl(y, R)`), so no era's + R lands a biased product bit + 252: /// on an address bit. The class's era carries the same bit ([`EraParams::fold`]). + `false` for every other class. + 253: pub fold: bool, + 254: /// Class v6 lane 1, the op-mix re-weight behind the fold: 0 is the plain table + [`NONLOAD_WEIGHTS`]; 1 the k lane's + 255: /// optimiser split [`NONLOAD_WEIGHTS_RW`] (sum 83, `or` never drawn); 2 the census + lane's neighbouring table + 256: /// [`NONLOAD_WEIGHTS_RW2`] (sum 75). The draw rolls against the table's own sum + ([`LoadClass::nonload_weights`]). + 257: pub rw: u8, + 258: /// The 64-register window (the hash lane's reg64 measurement, 8 October 2026, a + research class behind `+reg64` + 259: /// and `--reg64`): each lane holds 64 live 32-bit registers. r0..r7 are seeded as + today, r8..r63 derived from them + 260: /// (`r[k] = r[k & 7] * 0x9E3779B9 + k`); the 64 drawn instructions run twice per + iteration in an interleaved + 261: /// order, instruction i on window 0 (register field + 8 * (i % 4), registers + 0..31) then the same instruction on + 262: /// window 1 (+32, registers 32..63); the windows fold into r0..r7 by xor before + the hash fold + 263: /// ([`Program::scheduled`], [`crate::verify`], the emitters). The draw, the + acceptance rule and the dataset are the + 264: /// class's without the flag. `false` for every other class. + 265: pub reg64: bool, + 266: /// reg64, the full chain (the coordinator's amendment of 8 October 2026, 15:1x UK, + class suffix `+reg64c`, + 267: /// `--reg64-chain`): the address of every load consumes all 64 registers: address + source `src ^ m`, `m` the + 268: /// rotate-xor chain (`m = first; m = rotl(m, 1) ^ next`) over the 63 registers + other than `src` in index order + 269: /// (the same text in the verifier and the emitters), so an in-flight hash holds 64 + independently necessary + 270: /// values for the length of the dependent memory chain. The source stays out of + the chain: inside it, r31 and + 271: /// r63 land at rotation 0 mod 32 and cancel their own direct term (found by the + liveness rule on the pinned draw). + 272: /// Init rule: r0..r7 from the seed words as every class, `r[k] = r[k & 7] * + 0x9E3779B9 + k` for k in 8..63. + 273: /// Output rule: `r[k] ^= r[k + 8] ^ r[k + 16] ^ ... ^ r[k + 56]` for k in 0..7, + then the class's hash fold. + 274: /// Liveness rule (`accept::check_window_liveness`): xoring any one register with + either of two seed-derived + 275: /// probe words at the start of an iteration moves that iteration's first load + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 26 + +MASTER 165 / 292 + R2 / SOURCE REVIEW + + + + + address and the final hash, in + 276: /// every lane (the complement and a single bit are the patterns a linear fold + loses). Requires `reg64`. + 277: pub reg64_chain: bool, + + + + +pow/src/generator.rs:939-954 +SHA-256: 751f39aeedb2987856343e2a67c7aeca7daa47ddafe5192c50a19b1d425e3a8a + + + 939: /// The program class of an epoch (Counter ASIC 2.0, 5 October 2026, + `docs/plans/counter-asic-2-rollout.md`): one + 940: /// height switch in the node, `program_class_v3_activation_daa`, rounded up to an + epoch boundary, decides which + 941: /// class an epoch's program is drawn from. V2 is the lottery hash as adopted on 4 + October 2026, byte for byte. + 942: /// V3 is generator version 3: its program id carries `generator = 3` and its load + class is [`V3_CLASS`]. + 943: /// V4 (Counter ASIC 3.0, 6 October 2026, the candidate `mx8+sh256x27` behind + `program_class_v4_activation_daa`) is + 944: /// generator version 4: its program id carries `generator = 4` and its load class is + [`V4_CLASS`]. + 945: #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)] + 946: pub enum ProgramClass { + 947: #[default] + 948: V2, + 949: V3, + 950: V4, + 951: /// Class v5 (`docs/design/class-v5-stored-state.md`, behind + `program_class_v5_activation_daa`): class v4's program + 952: /// over a dataset whose every item is keyed by the window's execution state + ([`V5_CLASS`]), generator 5. + 953: V5, + 954: } + + + + +node/consensus/pow/src/igneum.rs:72-95 +SHA-256: 8264d300db90ee5e4c0f568f3e4f847e9c2c1028312827f38e8458d2c13bedfd + + + 72: /// The chain-derived inputs of the lottery hash for one header. + 73: #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] + 74: pub struct EpochSeeds { + 75: /// Seed of the program for this header's epoch + 76: pub epoch: Hash, + 77: /// Seed of the memory-hard cache: days since the Unix epoch of the header timestamp + 78: pub day: u64, + 79: /// The program class of the header's epoch (Counter ASIC 2.0, 5 October 2026): v2, + or v3 from the first epoch + 80: /// at or above `Params::program_class_v3_activation_daa`, or v4 (Counter ASIC 3.0) + from the first epoch at or + 81: /// above `Params::program_class_v4_activation_daa` + (`igneum::program_class_for_epoch`) + 82: pub class: ProgramClass, + 83: /// The era seed of the header's era (`E_n`; the devnet stand-in: genesis for era 0, + else the last selected-chain + 84: /// block below `pow_era_seed_score`). Read by class v3 programs only; `ZERO_HASH` + where a v2 caller has none. + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 27 + +MASTER 166 / 292 + R2 / SOURCE REVIEW + + + + + 85: pub era: Hash, + 86: /// The latency ladder's shadow pass count of the header's epoch + (`docs/design/latency-ladder.md`): the rung the + 87: /// chain's step gives the epoch, 0 for the class's own (before the ladder, every + class but v4, a caller that knows + 88: /// no rung). Part of the key: two rungs of one epoch are two programs. + 89: pub shadow_reps: u16, + 90: } + 91: + 92: impl EpochSeeds { + 93: /// Class v2 seeds with no era: the shape of every caller before Counter ASIC 2.0 + (tests, the legacy seed walk). + 94: pub fn v2(epoch: Hash, day: u64) -> Self { + 95: Self { epoch, day, class: ProgramClass::V2, era: kaspa_hashes::ZERO_HASH, + shadow_reps: 0 } + + + + +mining/pool/src/node.rs:47-71 +SHA-256: 54e52ee3ca45d2b482b2acf066d1ba613fa7fc7aaf7075fc5919d61257a126d4 + + + 47: raw.header.vote_key_hash = member.key_hash; + 48: let block: Block = raw.clone().try_into().map_err(|e| format!("block convert: + {e}"))?; + 49: let header: Header = block.header.as_ref().clone(); + 50: let info = tmpl.pow_epoch.as_ref().ok_or("the node reports no pow_epoch; a devnet-v4 + line node is needed")?; + 51: // The node's PoW schedule, genesis day and dataset size, and class v3 activation + are the pool's (what the solo + 52: // miner's `template()` installs): the share verifier's day cache and program must + be the node's exactly + 53: let wanted = PowSchedule::clamped(info.epoch_blocks, info.epoch_lead, info.day_ms); + 54: if wanted != pow_schedule() { + 55: install_pow_schedule(wanted); + 56: eprintln!("{} node PoW schedule: {} DAA per epoch, lead {}, day {} ms", now(), + wanted.epoch_blocks, wanted.epoch_lead, wanted.day_ms); + 57: } + 58: if (info.genesis_day_index, info.genesis_dataset_log2) != (pow_genesis_day_index(), + pow_genesis_dataset_log2()) { + 59: install_pow_genesis(info.genesis_day_index, info.genesis_dataset_log2); + 60: eprintln!("{} node genesis day index {} and genesis dataset 2^{} words: the day + cache follows them", now(), info.genesis_day_index, info.genesis_dataset_log2); + 61: } + 62: if info.program_class_v3_activation_daa != program_class_v3_activation_daa() { + 63: install_program_class_v3_activation(info.program_class_v3_activation_daa); + 64: eprintln!("{} node program class v3 activation: {} (epoch {} is class {}, the + next epoch class {})", now(), info.program_class_v3_activation_daa, info.epoch_index, + info.class().name(), info.next_class().name()); + 65: } + 66: // Counter ASIC 2.0: the class and the era seed of the epoch ride with the template; + the verifier hashes the + 67: // program they name, the same one the members' workers compile (6 October 2026: a + fixed class here or on the + 68: // member refused every GPU share of the fleet run) + 69: let seeds = EpochSeeds { epoch: info.epoch_seed, day: day_index(header.timestamp), + class: info.class(), era: info.era_seed.unwrap_or(kaspa_hashes::ZERO_HASH) }; + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 28 + +MASTER 167 / 292 + R2 / SOURCE REVIEW + + + + + 70: let engine = pool.engine.clone(); + 71: let epoch = tokio::task::spawn_blocking(move || + engine.epoch_for(&seeds)).await.map_err(|e| e.to_string())?; + + + +F04 excerpts + +node/consensus/src/processes/finality.rs:1111-1128 +SHA-256: 6194a96a80e5ec5a4daeb63afa8fda55a8c7a2f959d5becab60ea733790f5bf4 + + + 1111: /// The anchored test of a certificate's signers against the table frozen at lock + `C_f` (docs/spec/finality- + 1112: /// guarantees.md 6.2): inside one weight window of the lock, two thirds of `T_f` + (rule v3's Q5 and rule v4's + 1113: /// item 1); past the window, under rule v4 with the recovery, strictly more than + half of `T_f` (item 2, the + 1114: /// majority-continuity recovery: `2 x signed_f > total_f`); under rule v4 without + the recovery (6.5, the pause), + 1115: /// nothing passes past the window; under rule v3 the table has expired by then + (`frozen_table` returns None) and + 1116: /// the sliding table alone decides. Pure: (passes, signed_f, total_f, + past_the_window). + 1117: pub fn anchored_test(v4: bool, recovery: bool, lock_daa: u64, checkpoint_daa: u64, + window: u64, signed_f: u64, total_f: u64) -> (bool, bool) { + 1118: let past = checkpoint_daa >= lock_daa.saturating_add(window); + 1119: if total_f == 0 { + 1120: return (false, past); + 1121: } + 1122: if !past { + 1123: return (FinalityParams::floor_met(signed_f, total_f), past); + 1124: } + 1125: if v4 && recovery { + 1126: return ((signed_f as u128) * 2 > total_f as u128, past); + 1127: } + 1128: (false, past) + + + + +node/consensus/src/processes/finality.rs:2610-2642 +SHA-256: 6194a96a80e5ec5a4daeb63afa8fda55a8c7a2f959d5becab60ea733790f5bf4 + + + 2610: // Rule v3 (F21): the signers also need two thirds of the table frozen at the + last locked checkpoint on + 2611: // C_i's chain, at that table's weights, while it stands (less than one window + old) + 2612: let v3 = self.v3_active(cp.daa_score); + 2613: let frozen = if v3 { self.frozen_table_with_daa(state, index, cp.hash, + cp.daa_score) } else { None }; + 2614: // W7: keys that have left at this checkpoint are out of the frozen + denominator too (`frozen_floor`); the + 2615: // sliding table (`voters_at`) already excludes them + 2616: let gone = if frozen.is_some() { self.leaves_at(state, cp.hash, cp.daa_score) + } else { HashMap::new() }; + 2617: // rule v4 (6.2): past the window the anchored test is the majority-continuity + recovery (with the flag) or + 2618: // nothing (the pause); a lock that passes it past the window is a recovery + lock, reported for one window + 2619: let v4 = self.v4_active(cp.daa_score); + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 29 + +MASTER 168 / 292 + R2 / SOURCE REVIEW + + + + + 2620: let recovery_window = frozen.as_ref().map(|(_, lock_daa, _)| cp.daa_score >= + lock_daa.saturating_add(self.params.weight_window)).unwrap_or(false); + 2621: let frozen_test = |keys: &[Hash]| -> bool { + 2622: match &frozen { + 2623: Some((_, lock_daa, f)) => { + 2624: let (fs, ft) = Self::frozen_floor(f, keys, &gone); + 2625: Self::anchored_test(v4, self.v4_recovery, *lock_daa, cp.daa_score, + self.params.weight_window, fs, ft).0 + 2626: } + 2627: None => true, + 2628: } + 2629: }; + 2630: // Ledger C4: a checkpoint locks here only on the chain through the locks this + node holds. Fork choice keeps + 2631: // every other chain out of candidacy, so a record on another chain (the + node's own determination before a + 2632: // certificate-driven move, or a lock it adopted at a higher index) is + determined again after the move (F24), + 2633: // never locked where it is. Without this a side that out-works the certified + chain locks it alone once its + 2634: // own last lock is a window old. + 2635: let through_locks = locked || self.off_lock_chain(state, index, + cp.hash).is_none(); + 2636: if !through_locks && self.lock_test(signed, active_num, p, table.total) { + 2637: debug!( + 2638: "Finality: checkpoint {} on {} meets the quorum but is not on the + chain through this node's locks: not locked here (ledger C4); determined again once the + chain moves", + 2639: index, cp.hash + 2640: ); + 2641: } + 2642: let passes = through_locks && self.lock_test(signed, active_num, p, + table.total) && frozen_test(&signers); + + + + +dag/igneum-node-dag/spec/docs/spec/finality-guarantees.md:111-136 +SHA-256: bd9f640eb0396ec05c22dbb50ecb0446fb9a7397d205e792615374367797776a + + + 111: ### 6.5 The cost, stated, and the one-line alternative + 112: + 113: The recovery certificate's safety bound is weaker than one third. Two conflicting + recovery locks need a partition that has lasted a full window with no certificate on either + side AND equivocating keys that (i) hold a share of `T_f` exceeding the split's imbalance + and (ii) are still in BOTH sides' canonical voter lists at the recovery index, which means + they mined at least dust (100 blue blocks in the window, W3) on each side: a certificate's + bitmap is over the voter list at `C_i` (C3), so a key that mined on one side only is, after + a full window, not a voter on the other side whatever its anchored weight. Each side of a + 50/50 split with an equivocator at `a` that mines on both holds `(1 - a) / 2 + a` of `T_f`, + more than half for any `a > 0`; in a 60/40 split the 40 side needs `a > 0.2`. Measured (N1b, + N2b, five rows each over two seeds): an equivocator mining on one side only never produces + a recovery conflict (one side recovers at day 30.00, the other never, 0 conflicts, at 10 and + 20 percent across 50/50 and in the 40/40 case); one mining on both sides makes both sides + recover at day 30.00 and the heal shows 2,800 to 2,889 conflicting locks under `v4 recovery` + and 0 under `v4 pause`; at 34 percent both sides lock from minute 0 under every rule (the + one-third bound). Every pre-heal lock kept and the heal locks at 0 minutes in every row. In + every such case the equivocator is stripped at the heal (3.6), the history through `C_f` is + untouched (item 3), and the pair is handled as 3.11.4 says. The one-third bound of section 4 + is intact for every certificate formed within a window of the last one, which is every + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 30 + +MASTER 169 / 292 + R2 / SOURCE REVIEW + + + + + certificate of a connected network. + 114: + 115: The alternative the founder can choose by deleting item 2 is the **indefinite pause** + (`v4 pause` in the simulator, `P.recovery = False`; in the node, the recovery test left + out). Its guarantees are strictly stronger: no certificate ever forms with less than two + thirds of the last certified table, so the one-third bound holds for every certificate for + ever. Its costs, measured: one purchase of keys worth a third of a window is a permanent + veto on finality (N4: never in 31 days, against day 30 with the recovery), a sudden honest + loss of a third of weight (a pool folding with its keys) pauses finality permanently absent + succession or an operator's trusted certificate (N6: never, against day 30), and a 60/40 + partition that outlasts a window pauses the 60 side until the heal instead of recovering at + day 30 (N1). + 116: + 117: **This document recommends the recovery (items 1 to 5 as written)**, because its + failure needs an attacker, a month-long partition and equivocation that the chain then + punishes, while the pause's failure needs no attacker and has no exit inside the protocol; + and because the recovery never touches certified history, which is what the acceptance line + protects. The founder chose "the pause over the fork" on 4 October 2026 (ledger F21) against + a fork that needed no attacker; this recommendation keeps that choice (the honest 31-day + partition never forks under either variant) and adds a bounded, disclosed exit. The decision + is the founder's at the 18:00 UK report; the simulator and the node carry both as one + switch. + 118: + 119: ### 6.6 How it composes with the rest of the rule + 120: + 121: - **No certified checkpoint is ever reversed (3.11.4)** stands unchanged: a recovery + lock adds a certificate, it never withdraws one; a node holding two valid certificates at + one index keeps the first, reports `conflict`, and the protocol does not pick. + 122: - **The certificate-driven reorg (3.5, ledger C4)** carries recovery certificates: a + node on the other side of a healed 60/40 partition, holding no lock since `C_f`, verifies + the 60 side's recovery certificate against `T_f` and `T(i)` from the block's own past and + moves to it. Measured: every pre-heal lock kept, first lock after the heal 0 minutes, 0 + post-heal stalls (N1). + 123: - **Succession (W5) and the strip (3.6)** are the two in-protocol ways the anchored + table changes without a certificate, both functions of the chain: a miner that retires hands + its weight to a successor (which then counts in `T_f` at the old key's weight), and the + owner of a compromised key equivocates with it once to remove it from every table (N4: + finality resumes the day the evidence is carried). + 124: - **The trusted certificate (F5)** is the operator's exit for the cases no rule covers + (half or more of `T_f` gone for good). It gains one check: a configured trusted certificate + MUST lie on the chain through every lock the node holds, else it is refused; an operator + cannot be handed a certificate that overrides certified history. + 125: - **The exchange guidance (3.9)** gains one row: `finality_reason` `recovered` means a + lock formed under 6.2 item 2 within the last window; an operator who prefers the pause-only + reading treats it as `paused` for that window. The pause row itself is unchanged: a pause is + proof of work, the reorg bound is the finality depth in median time. + 126: - **Layer 4 of class rotation** (the emergency miner vote, + `docs/design/class-rotation-four-layers.md`): no flip vote counts while finality is paused, + and a recovery lock counts as a lock; the schedule stands throughout (8). + 127: + 128: ### 6.7 The node change + 129: + 130: One function and one switch, for the node lane; nothing here lands on any network until + the founder sets the height. `frozen_table` (the Q5 row of 3.10) keeps its reference and + loses its drop; `evaluate` and `ingest_off_chain` test `floor_met(frozen_signed, + frozen.total)` while `daa(C_i) < daa(C_f) + weight_window` and + `continuity_met(frozen_signed, frozen.total)` (`2 x signed > total`, a pure function with + its own inclusive-boundary unit test) after, provided no lock exists between; a lock that + passed by `continuity_met` is stamped `recovered` in the record and `getFinalityCheckpoints` + reports `finality_reason` `recovered` with `anchored_index` and `anchored_signed_share` for + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 31 + +MASTER 170 / 292 + R2 / SOURCE REVIEW + + + + + one window. Switch `finality_v4_activation_daa` (never on every network until set; the + digest arm entered only when set, so a binary carrying the field peers with one that does + not, the rule of every switch since 0.3.20). Unit tests, known-failed first: the M3 shape (A + at 60 percent and B at 40 percent lock together, B leaves, A alone must not lock under v4 + pause ever and must lock under v4 recovery only once the last lock is one window old; under + v3 it locks at the window, the known-failed line); and a 50/50 shape that never locks under + either v4. The fast-time harness row is `tools/finality-attacks/v3.mjs split50` extended + past the window (`SPLIT` above 120 DAA at 60x), where v3 must conflict and v4 must not; the + pass line per variant: pause-only, no lock on either side during the split, locking resumed + after the heal (a heal window of at least one weight window after the reconnect), 0 + conflicting certificates, 0 disagreeing locks; recovery, at most one side locks during the + split (the side above half of the anchored table by weight, which block-count jitter decides + in a 3/3 split), 0 conflicting certificates, 0 disagreeing locks, every node on the + recovering side's chain after the heal. Measured on the 2.0.0 node line on 8 October 2026 + (the node lane's rows in `sim/results_v2.md`, "Rule v4"). + 131: + 132: ## 7. What is NOT guaranteed + 133: + 134: 1. **At or above one third of equivocating weight** two valid certificates can exist at + one index; the rule reports and does not resolve (3.11.4). + 135: 2. **A recovery lock** is bounded as 6.5 states, not by one third: a month-long + partition plus an equivocator outweighing the split's imbalance can produce two recovery + locks after `C_f`. The history through `C_f` is never touched. + 136: 3. **A loss of half or more of the last certified table at once** has no in-protocol + exit: finality pauses until the weight returns, hands over or is stripped, or an operator + configures a trusted certificate on the chain through the last lock (F5 with 6.6's check). + The chain runs on proof of work meanwhile. + + + + +dag/igneum-node-dag/spec/docs/spec/finality-guarantees.md:184-197 +SHA-256: bd9f640eb0396ec05c22dbb50ecb0446fb9a7397d205e792615374367797776a + + + 184: ## 10. Test table + 185: + 186: Each claim, the scenario, the known-failed line first where there is one, and the + result. Simulator rows are `sim/finality_v2.py --scenarios N --seeds 7,11` at the 2/3 floor, + each side retargeting and counting only its own blocks, run on build-3 under the lease + tool; the tables are in `sim/results_v2.md`, "Rule v4". Where a row says "pending" the run + had not landed when this version was written; the 20:00 UK version carries the numbers. + 187: + 188: | Claim | Scenario | Known-failed line | Result | + 189: |---|---|---|---| + 190: | (a) The 31-day partition at the window: no conflicting locks under the chosen rule | + N1: 50/50, 60/40, 55/45 for 31 days, v3 against v4 pause and v4 recovery | v3: both sides + lock alone at day 30.00, 2,679 to 2,870 conflicts (M3, re-run in N1, reproduced to the + checkpoint) | **measured**: v4 pause: no side locks in 31 days, 0 conflicts, every pre-heal + lock kept, first lock 0 minutes after the heal, 0 post-heal stalls, every split; v4 + recovery: 50/50 the same; 60/40 and 55/45 the larger side recovery-locks once at day 30.00 + and then locks normally, the smaller side never, 0 conflicts, kept, heal 0 minutes | + 191: | (a) The recovery bound | N1b: 50/50 for 31 days with a 10, 20, 34 percent + equivocator, mining on one side and on both | 34 percent: conflicts from minute 0 under + every rule (the one-third bound: 87,428 to 87,915 conflicts in 31 days) | **measured** + (build-4, 16:06 to 16:16 UK): on one side only, 0 conflicts (one side recovers at day 30.00, + the other never); on both sides, both recover at day 30.00 and 2,800 to 2,889 conflicts + under v4 recovery, 0 under v4 pause; every pre-heal lock kept, heal 0 minutes | + 192: | (b) 40/40/20 under the active-set rules | N2: honest three-way for 150 minutes and 31 + days; 40/40 with a 20 percent equivocator reaching both for 31 days; N2b the same + equivocator mining on both sides | the 60/60 case with the equivocator mining on both sides + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 32 + +MASTER 171 / 292 + R2 / SOURCE REVIEW + + + + + under v4 recovery at day 30 (6.5) | **measured** (N2): honest three-way: no side locks for + 150 minutes or 31 days under either v4, 0 conflicts, kept, heal 0 minutes; 60/60 with the + equivocator mining on one side: v4 pause never, v4 recovery one side at day 30.00, the other + never, 0 conflicts; N2b **measured**: the same equivocator mining on both sides: v4 pause 0 + conflicts, v4 recovery both sides at day 30.00 with 2,835 to 2,860 conflicts (the bound of + 6.5) | + 193: | (c) Signing stops while mining continues | N3: 34, 40, 45 percent for 24 h under v4 + recovery; 34 percent for 31 days under both v4 | none expected (as J) | **measured**: 24 h: + every checkpoint stalled (2,880 to 2,889), longest gap 1,440 minutes, first lock 0 minutes + after the resume, 0 post-resume stalls, 0 conflicts, 0 recovery locks; 31 days at 34 + percent: no lock under either v4 for the whole silence (89,286 to 89,318 stalled), first + lock 0 minutes after the resume, 0 conflicts; under v4 recovery that first post-resume lock + passed by the majority test (the anchored checkpoint was a window old), so a node would + report `recovered` for one window after a resume that follows a pause longer than a window, + a reporting fact and not a weakening | + 194: | (d) Old keys compromised against fresh hashrate | N4: keys worth 40 percent withhold, + holder at 30 percent of hashrate, 31 days, v2, v3, v4 pause, v4 recovery; the self-strip on + day 1 | v4 pause: never (the permanent veto, 6.5) | **measured**: first lock v2 day 20.9, + v3 day 30.00, v4 pause never in 31 days (89,262 to 89,373 stalled), v4 recovery day 30.00 + (one recovery lock); the holder's share decays to 0.300 under every rule; self-strip: the + first lock on day 0 (571 to 736 stalled checkpoints before the evidence is carried), 0 + conflicts | + 195: | (e) Finality paused across an epoch boundary: seeds advance, mining continues, + certified history intact | derived from N1 and N3: blocks and checkpoints continue through + the pause (every stalled checkpoint in the tables is a block the chain mined), 744 hourly + boundaries in a 31-day pause, each seeded by its reference block (8); the fast-time harness + row (11) | none | derived; harness run owed | + 196: | (f) The heal: a deterministic path that never reverses a lock | N1, N2, N6: every + pre-heal lock kept, first lock after the heal, post-heal stalls; the certificate-driven + reorg (3.11.7, `c4.mjs`) | none | **measured**: every pre-heal lock kept in every row of N1 + and N2 (24 runs), first lock 0 minutes after every heal, 0 post-heal stalls, 0 conflicts + under both v4 rules; a sudden departure of 35 percent: v3 and v4 recovery lock at day 30.00, + v4 pause never (N6); at 50 percent the recovery is a knife edge (one seed day 30.23, one + never) | + 197: | The harness line on real nodes: the known-failed v3 partition past the window | + `tools/finality-attacks/v3.mjs split50`, 0.3.25 node pair, 60x file, SPLIT 420 s (the frozen + table expires 240 s after the last lock) | both sides lock alone, conflicting certificates + at the heal, disagreeing locks | **measured** (build-4, 17:06 to 17:20 UK): both sides + locked alone 192 to 198 s after the cut, 7 new locks each; 4/8/8 conflicting certificates + logged, 8 disagreeing locked indices after the heal, locking resumed on both forks: FAIL by + the scenario's criterion, the known-failed line; the v4 line waits on the node change (6.7) + | + + + +F05 excerpts + +pow/src/verify.rs:674-692 +SHA-256: 033ae9f2ccd32e1170e7ff4f259b206b26e78ddc9ebf68d7b26933794aa1f345 + + + 674: // reg64 full chain: a load's address source is src ^ m, m the rotate-xor chain + over the 63 other registers in + 675: // index order (m = first; m = rotl(m, 1) ^ next). The source itself stays out of + the chain: with it inside, a + 676: // register whose term lands at rotation 0 mod 32 (r31, r63) cancels its own direct + term, a dead register the + 677: // liveness rule found on the pinned draw (first load src r31, 8 October 2026, + 15:5x UK). + 678: let addr_src = |r: &[[u32; LANES]], lane: usize| -> u32 { + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 33 + +MASTER 172 / 292 + R2 / SOURCE REVIEW + + + + + 679: if !address_mix { + 680: return r[a][lane]; + 681: } + 682: let mut m = 0u32; + 683: let mut started = false; + 684: for k in 0..r.len() { + 685: if k == a { + 686: continue; + 687: } + 688: m = if started { m.rotate_left(1) ^ r[k][lane] } else { r[k][lane] }; + 689: started = true; + 690: } + 691: r[a][lane] ^ m + 692: }; + + + + +pow/src/generator.rs:258-277 +SHA-256: 751f39aeedb2987856343e2a67c7aeca7daa47ddafe5192c50a19b1d425e3a8a + + + 258: /// The 64-register window (the hash lane's reg64 measurement, 8 October 2026, a + research class behind `+reg64` + 259: /// and `--reg64`): each lane holds 64 live 32-bit registers. r0..r7 are seeded as + today, r8..r63 derived from them + 260: /// (`r[k] = r[k & 7] * 0x9E3779B9 + k`); the 64 drawn instructions run twice per + iteration in an interleaved + 261: /// order, instruction i on window 0 (register field + 8 * (i % 4), registers + 0..31) then the same instruction on + 262: /// window 1 (+32, registers 32..63); the windows fold into r0..r7 by xor before + the hash fold + 263: /// ([`Program::scheduled`], [`crate::verify`], the emitters). The draw, the + acceptance rule and the dataset are the + 264: /// class's without the flag. `false` for every other class. + 265: pub reg64: bool, + 266: /// reg64, the full chain (the coordinator's amendment of 8 October 2026, 15:1x UK, + class suffix `+reg64c`, + 267: /// `--reg64-chain`): the address of every load consumes all 64 registers: address + source `src ^ m`, `m` the + 268: /// rotate-xor chain (`m = first; m = rotl(m, 1) ^ next`) over the 63 registers + other than `src` in index order + 269: /// (the same text in the verifier and the emitters), so an in-flight hash holds 64 + independently necessary + 270: /// values for the length of the dependent memory chain. The source stays out of + the chain: inside it, r31 and + 271: /// r63 land at rotation 0 mod 32 and cancel their own direct term (found by the + liveness rule on the pinned draw). + 272: /// Init rule: r0..r7 from the seed words as every class, `r[k] = r[k & 7] * + 0x9E3779B9 + k` for k in 8..63. + 273: /// Output rule: `r[k] ^= r[k + 8] ^ r[k + 16] ^ ... ^ r[k + 56]` for k in 0..7, + then the class's hash fold. + 274: /// Liveness rule (`accept::check_window_liveness`): xoring any one register with + either of two seed-derived + 275: /// probe words at the start of an iteration moves that iteration's first load + address and the final hash, in + 276: /// every lane (the complement and a single bit are the patterns a linear fold + loses). Requires `reg64`. + 277: pub reg64_chain: bool, + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 34 + +MASTER 173 / 292 + R2 / SOURCE REVIEW + + + + +F06 excerpts + +pow/src/accept.rs:114-119 +SHA-256: a4baf9286508e73406dd05b9f89bc6660baf017f107c650ce09bda504cfc92f9 + + + 114: /// The reg64 window's liveness rule (the coordinator's spec of 8 October 2026, + `check_window_liveness`, a research + 115: /// class, not wired into the acceptance): xoring register `reg` of lane `lane` + with a probe word at the start of iteration 0 + 116: /// left the iteration's first load address unchanged (`address_changed` false) or + the final hash unchanged + 117: /// (`result_changed` false). A window whose address fold reads a subset of the + registers is refused here. + 118: DeadWindowRegister { reg: u8, lane: u8, address_changed: bool, result_changed: bool + }, + 119: /// `check_window_liveness` on a program without the reg64 window. + + + + +pow/src/accept.rs:625-637 +SHA-256: a4baf9286508e73406dd05b9f89bc6660baf017f107c650ce09bda504cfc92f9 + + + 625: // Class v4 sub-version 3 (AP-F8-3, 7 October 2026): the acceptance interpreter + runs the latency-shadow block + 626: // after instruction 63 of every iteration, `reps` times with the iteration's + `sel`, exactly as the hash does + 627: // (verify.rs). Until this commit it ran the 64 base instructions only, so every + dynamic test (c) judged a class v4 + 628: // program the chain never hashes. The shadow block holds no load, so its + instructions take the same arms. + 629: let shadow_reps = p.shadow_reps(); + 630: for it in 0..ITERATIONS { + 631: let sel = r[0]; + 632: let shadow_pass = (0..shadow_reps).flat_map(|_| + p.shadow.iter().enumerate().map(|(k, i)| (INSTR_COUNT + k, i))); + 633: for (k, ins) in p.instrs.iter().enumerate().chain(shadow_pass) { + 634: let d = ins.dst as usize; + 635: let a = ins.src as usize; + 636: match ins.op { + 637: Op::Scratch => { + + + + +pow/src/accept.rs:867-871 +SHA-256: a4baf9286508e73406dd05b9f89bc6660baf017f107c650ce09bda504cfc92f9 + + + 867: /// The whole rule: (a), (b), then (c). + 868: pub fn check(p: &Program) -> Result { + 869: check_static(p)?; + 870: check_dynamic(p) + 871: } + + + + +pow/src/generator.rs:258-264 +SHA-256: 751f39aeedb2987856343e2a67c7aeca7daa47ddafe5192c50a19b1d425e3a8a + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 35 + +MASTER 174 / 292 + R2 / SOURCE REVIEW + + + + + 258: /// The 64-register window (the hash lane's reg64 measurement, 8 October 2026, a + research class behind `+reg64` + 259: /// and `--reg64`): each lane holds 64 live 32-bit registers. r0..r7 are seeded as + today, r8..r63 derived from them + 260: /// (`r[k] = r[k & 7] * 0x9E3779B9 + k`); the 64 drawn instructions run twice per + iteration in an interleaved + 261: /// order, instruction i on window 0 (register field + 8 * (i % 4), registers + 0..31) then the same instruction on + 262: /// window 1 (+32, registers 32..63); the windows fold into r0..r7 by xor before + the hash fold + 263: /// ([`Program::scheduled`], [`crate::verify`], the emitters). The draw, the + acceptance rule and the dataset are the + 264: /// class's without the flag. `false` for every other class. + + + + +v6/igneum-v6-freeze-tree/docs/analysis/class-v6/census-packs.md:8-22 +SHA-256: 1aa41baecf0eb2683dbd7392fcc827dc69aa1cc72f1f751803081bf1c9b21885 + + + 8: |---|---|---|---|---|---|---|---| + 9: | hl-v6-fold (the index fold alone, W = 4, base mix) | 482dc0dad937135b, attempt 1 | + class-v6-fold 7880bc96 | class-v6-census-fold 5b3486f0 | accepted; min site ratio 0.99986; + bucket +5.25 sigma; worst free bit 2.84 sigma; no site over 6 sigma (class v5's own program + on the same state: -448 sigma at one site) | 256 of 256, 0 exhausted, r 0.701, mean attempt + 2.34, max 14, (c''') 0.35 percent | 16 seeds p18 to p33 at 2^22: 16 PASS, at most 1.0455x of + the window model (the class v5 control on the same seeds: 5 of 16 flagged on the 6-sigma + bucket); the known-failed set at 2^24: p4 1.0057x (from 1.2163x), p8 1.1663x (+6.6 sigma + bucket; from 1.3787x), p10 1.1868x (from 1.5052x), p15 PASS, p212 1.0411x (+27 sigma; from + 1.1917x), p225 1.2414x BEYOND (from 1.2457x: the value-level class, unmoved), p34 1.0486x + with a +11.9 sigma bucket (from +5.06: the one regression) | **PASS** | + 10: | hl-v6-rw (the k lane's table rw1: 16,14,4,12,4,11,10,2,10,0 in draw order, sum 83, + `or` never drawn) | 30628f8adcf6035e, attempt 0 | class-v6-fold 7880bc96 | the same | + accepted; min ratio 0.99990; bucket +5.5; worst bit 2.89; no site over 6 sigma | 256 of 256, + 0 exhausted, r 0.117, mean attempt 0.13, max 2, (c''') 0.34 percent | 16 seeds: ratio at + most 1.1526x (within), 4 of 16 flagged on the 6-sigma bucket (the control's own rate is 5 of + 16); known-failed under this table's draw: p4, p34, p225 PASS, p8 +22 sigma, p10 +14, p15 + +8.8, p212 +37 sigma buckets at ratios 1.00 to 1.15x | **PASS** | + 11: | hl-v6-foldrw (fold and rw1) | 605d06cabc489f94, attempt 0 | class-v6-fold 7880bc96 | + the same | accepted; min ratio 0.99993; bucket +5.75; worst bit 3.49; no site over 6 sigma | + 256 of 256, 0 exhausted, r 0.117, mean 0.13, max 2, (c''') 0.34 percent | 16 seeds: 15 + PASS, 1 flagged (p18), at most 1.0932x; known-failed: every ratio within (p4 1.0002x, p8 + 1.0138x, p10 1.0100x, p15 1.0088x, p34 1.0121x, p212 1.1111x, p225 1.0000x), buckets flagged + on p15 (+9.3) and p212 (+24.5) | **PASS** | + 12: | hl-v6-rw2 (the census lane's table 13,11,6,10,8,8,7,2,6,4, sum 75) | 09e91b0dcd458c77, + attempt 1 | class-v6-fold 7880bc96 | the same | accepted; min ratio 0.99990; two sites with + the stride bit at -64 sigma (no fold) | 256 of 256, 0 exhausted, r 0.410, mean 0.70, max 8, + (c''') 1.15 percent | 16 seeds: seed p30 1.3111x over the window model (the control + 1.0004x; hl-v6-rw's worst 1.1526x), BEYOND the 1.2x gate; known-failed under its draw: p8 + 1.2507x (+42.8), p10 1.5044x (+100.9), p225 1.4049x beyond, p34 +70.7 and p15 +13.2 sigma + buckets, p4 and p212 PASS | **FAIL** on the F8 line | + 13: | hl-v6-win (the 64-register full-chain window alone, `+reg64c`) | f42d4a743ce7d4fa, + attempt 0 (the v5-dn3-epoch0 seeds and state) | reg64-v5 198d171d | class-v6-census-reg64 + b29e690d2 | accepted (with the liveness probe); min ratio 0.99923; bucket +5.5; the base + program's stride-bit site at -448 sigma (no fold) | 256 of 256, 0 exhausted, r 0.716, mean + 2.52, max 15, (c''') 1.66 percent (the window does not enter the draw: class v5's rows) | + the window's own address stream through the interpreter's tracing probe, 32 sites of the + interleaved schedule, 16 seeds at 2^22, the era laid over, closed form: per-site distinct + ratio 1.0026 to 1.0027 on every site (the (c'') form; the control 0.9946 to 1.0027); the + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 36 + +MASTER 175 / 292 + R2 / SOURCE REVIEW + + + + + item histogram's top-0.1-percent share 1.0645 to 1.5624x of a flat control against the + control's 1.0738 to 1.5074x, paired by seed 0.968 to 1.036x of the control. The attack-f8 + mirror and the known-failed set do not apply (eight registers) | **PASS** (the live-dataset + point owed) | + 14: | hl-v6-all (window, fold and rw1) | 9d40978601a7df2a, attempt 0 | class-v6 3f25a8305 + (the texts at c245d50b9, the verifier unchanged) | class-v6-census-all 2d54a4633 | accepted; + min ratio 0.99993; bucket +5.75; worst bit 3.49; no site over 6 sigma | 256 of 256, 0 + exhausted, r 0.117, mean 0.13, max 2, (c''') 0.34 percent | the trace on 32 sites: per-site + distinct ratio 1.0026 to 1.0027; item share 1.0443 to 1.5132x flat against the foldrw + control's 1.0398 to 1.4616x, paired 1.004 to 1.035x | **PASS** (the live-dataset point owed) + | + 15: + 16: The controls: the freeze's class v5 pack v5-dn3-epoch0 (e5a4ac5978462156) through the + whole harness at 15:53 UK (the dry run: the known-failed set reproduces the record to three + places, p4 1.2163x, p8 1.3787x, p10 1.5052x, p212 1.1917x, p225 1.2457x) and class v5 on the + node1 state over the same 16 seeds at 2^22 (16 of 16 within 1.2x, worst 1.0698x; 5 of 16 + flagged on the 6-sigma windowed bucket: the statistic's own rate on the family at 2^22, so a + pack's 4 or 5 flags is the control's and a pack's 0 of 16 is a gain). + 17: + 18: What the sheet means. The index fold does what it was drawn for: the stride-bit bias is + gone from every program it ships, the F8 tails of 1.22 to 1.50x come inside the gate (1.01 + to 1.19x) and the bucket concentration at narrow-window sites falls from the control's 5 of + 16 seeds to 0 of 16; p225's value-level class is untouched and p34 gains one bucket + statistic. The k lane's table (rw1, `or` never drawn, `mul` at 4) reads clean and gives the + lowest rejection rate measured on the family (0.117); the census lane's table (rw2, `or` 4, + `mul` 6) keeps the lossy writers the tails come from and fails the F8 line, so the re-weight + is sound in the rw1 form only. The window changes nothing the rule or the F8 form sees at + 2^22 on the closed form and carries the fold's and the table's rows unchanged; its value is + the chip-side cost the adversary lane prices. + 19: + 20: ## 1. The harness + 21: + 22: The class v5 crate of each pack's branch plus lane D's family-gate harness diff + (`docs/analysis/class-v6/logs/harness-family-gate-v5-3dc3117c.diff`: `IGNEUM_FAMILY_GATE` + widens the class v4 rules to the family's shapes, with every new class flag set aside in + `is_family_shape`: state, fold, rw, wide8, reg64, reg64_chain), plus: a `sitestats` command + (the whole rule with (c'''), then per site over 2^20 evaluations the distinct ratio against + the window model, the largest 256-item bucket in sigma, the largest index-bit excess in + sigma over the free bits); the `accept` walk at the class's own cap under the flag; the + attack-pass lane's `attack-f8` with `--load-class ` (the program drawn from a class + string with the spec's era laid over it) and `--dataset-words N` (the ds55 geometry through + `load_index_geom`; not exercised: a state class refuses the non-power-of-two count); the + uniform trace tool `tools/attack/v6-census/uniform` on `verify::Probe { trace_loads }` + (every load's index per lane through the interpreter itself). Binaries pinned per crate + under `/srv/builds/v6-census/bin//` with sha256: fold-5b3486f0 (igneum-pow 50903d30, + attack-f8 9ba2210b), reg64-1b676975 (v6census-uniform b2214265 after the fixes), + all-d7d441be (igneum-pow 5a221e56, v6census-uniform 2ebd92c1). + + + + +v6/igneum-v6-freeze-tree/docs/analysis/class-v6/census-packs.md:40-49 +SHA-256: 1aa41baecf0eb2683dbd7392fcc827dc69aa1cc72f1f751803081bf1c9b21885 + + + 40: ## 4. Faults found and fixed on the way (the record, so no one repeats them) + 41: + 42: - The uniform tool's distinct sets as HashSet took 16 GB a thread at 2^22 nonces and + were killed by the lease's memory cap; bit vectors over the dataset's words now. + 43: - The reg64 interleaved schedule runs 32 load rows per iteration (instruction k on + window 0 then window 1); the first read mapped them onto 16 sites (doubling N, ratios 1.35 + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 37 + +MASTER 176 / 292 + R2 / SOURCE REVIEW + + + + + to 1.80), the second mapped site s to load s mod 16 (the wrong window's expectation, ratios + 0.84); site s is load instruction s / 2. + 44: - The all pack's attack-f8 chain died at start on the fold-base tool (`+reg64c` + unparsed); the class-v6 tool parses it but its mirror interprets eight registers, so the + mirror is not the window's instrument. + 45: - The lease pool is a race, not a queue; `env VAR="a b"` through it splits on spaces. + 46: + 47: ## 5. Owed + 48: + 49: The live-dataset F8 point at 2^24 for the two window packs (the mirror would need the + two-window interpreter: four to six hours); the 64 x 2^24 point per pack (45 to 100 + core-hours each); hl-v6-rw's files (on build-3, unreachable); the exact `or = 0` attempts + rows are lane D's. + + + +F07 excerpts + +v6/igneum-v6-freeze-tree/docs/analysis/class-v6/coexist-rows.md:17-37 +SHA-256: 1c3751990121cd258dc0d816c0d4339af9d872487687899258629944e897dc9f + + + 17: RESULT idle mem_mib=1 power_w=21.32 + 18: RESULT cmd miner_alone: /root/coex/kit/bin/linux/igneum-worker-cuda --bench --pack + /root/coex/kit/packs/ds55 --batches 100 --batch-log2 24 --block-warps 1 --device 0 + 19: RESULT miner_alone rc=0 wall_s=67 peak_mib=6129 check=PASS fingerprint=23ced07a4d28b465 + mhs=26.824 self-test PASS + 20: RESULT cmd proof_alone: env HOME=/opt/igneum-floor/home SP1_PROVER=cuda RUST_LOG=off + SP1_GPU_FLOOR_LOG=1 SP1_GPU_ELEMENT_THRESHOLD=67108864 timeout 900 + /opt/igneum-floor/bin-0317/igneum-prove-host /root/coex/fees-v1-shards2.json --mode + compressed --shard 0 --out /root/coex/proof-alone.json + 21: RESULT proof_alone rc=0 wall_s=31 peak_mib=7525 prove_s=13.2 verified=1 err="" + 22: RESULT proof_alone_line RESULT compressed shard 0: prove 13.2 s, proof 1272897 bytes, + verify 0.110 s, VERIFIED; statement + 0x6adcc7fab21512b58cfa3778756718fd37aea6cccb311e12d2ca33b5f4bf10c0 proof sha256 + 0x57e133da05ea5f6ecbcbd731b1b26c9bed2f10c5a1aa1bd04a5a5e3dab1e + 23: RESULT cmd miner_beside_comp26: /root/coex/kit/bin/linux/igneum-worker-cuda --bench + --pack /root/coex/kit/packs/ds55 --batches 400 --batch-log2 24 --block-warps 1 --device 0 + 24: RESULT cmd proof_beside_comp26: env HOME=/opt/igneum-floor/home SP1_PROVER=cuda + RUST_LOG=off SP1_GPU_FLOOR_LOG=1 SP1_GPU_ELEMENT_THRESHOLD=67108864 timeout 600 + /opt/igneum-floor/bin-0317/igneum-prove-host /root/coex/fees-v1-shards2.json --mode + compressed --shard 0 --out /root/coex/proof-beside-comp26.json (started 1s+10s after the + miner, miner resident mem_mib=6129) + 25: RESULT proof_beside_comp26 mode=compressed thr=67108864 rc=1 wall_s=34 + proof_window=1791472334..1791472368 miner_start=1791472323 prove_s= verified=0 + miner_alive_after=yes err="thread 'tokio-rt-worker' (1790) panicked at + slop/crates/alloc/src/raw_buffer.rs:271:9:" + 26: RESULT miner_beside_comp26 rc=0 wall_s=256 peak_mib=11893 check=PASS + fingerprint=23ced07a4d28b465 mhs=26.512 self-test PASS + 27: RESULT beside_fallback compressed 2^26 beside the miner did not verify; core 2^25 beside + the miner next + 28: RESULT cmd proof_beside_core25: env HOME=/opt/igneum-floor/home SP1_PROVER=cuda + RUST_LOG=off SP1_GPU_FLOOR_LOG=1 SP1_GPU_ELEMENT_THRESHOLD=33554432 timeout 600 + /opt/igneum-floor/bin-0317/igneum-prove-host /root/coex/fees-v1-shards2.json --mode core + --shard 0 --out /root/coex/proof-beside-core25.json (started 3s+10s after the miner, miner + resident mem_mib=6129) + 29: RESULT proof_beside_core25 mode=core thr=33554432 rc=1 wall_s=18 + proof_window=1791472598..1791472616 miner_start=1791472585 prove_s= verified=0 + miner_alive_after=yes err="Error: unknown mode core" + 30: RESULT miner_beside_core25 rc=0 wall_s=254 peak_mib=11013 check=PASS + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 38 + +MASTER 177 / 292 + R2 / SOURCE REVIEW + + + + + fingerprint=23ced07a4d28b465 mhs=26.775 self-test PASS + 31: RESULT beside_failed core 2^25 beside the miner did not verify either + 32: RESULT idle_after mem_mib=1 + 33: RESULT window_hl-reg64c rc=0 wall_s=130 peak_mib=1521 regs=87 blocks_per_sm=16 + check=PASS fingerprint=4e7cc25967eba280 mhs=13.467 self-test PASS + 34: RESULT window_hl-reg64 rc=0 wall_s=128 peak_mib=1521 regs=104 blocks_per_sm=16 + check=PASS fingerprint=70e786af1a457653 mhs=13.476 self-test PASS + 35: ``` + 36: + 37: Watts from the samples (busy mean of power.draw from 8 s in): miner alone 117.4 W; proof + alone 122.2 W over the 9 busy seconds; miner with the failed compressed attempt beside it + 118.6 W; hl-reg64c 120.8 W; hl-reg64 119.3 W. The card touched its 170 W limit on none of + them. + + + + +v6/igneum-v6-freeze-tree/docs/analysis/class-v6/coexist-rows.md:60-86 +SHA-256: 1c3751990121cd258dc0d816c0d4339af9d872487687899258629944e897dc9f + + + 60: The rerun on the patched server (run2.log): + 61: + 62: ``` + 63: RESULT start 2026-10-08T15:31:00Z card=NVIDIAGeForceRTX4060 total_mib=8188 + driver=570.211.01 power_limit_w=115.00 + 64: RESULT bins worker=d43be4625b78baf7 host=71bc2438856bb141 server=882bd34f7f69dc97 + fixture=20a108f159c61ff9 + 65: RESULT cmd proof_alone: env HOME=/opt/igneum-floor/home SP1_PROVER=cuda RUST_LOG=off + SP1_GPU_FLOOR_LOG=1 SP1_GPU_ELEMENT_THRESHOLD=67108864 timeout 900 + /opt/igneum-floor/bin-0317/igneum-prove-host /root/coex/fees-v1-shards2.json --mode + compressed --shard 0 --out /root/coex/proof-alone-rerun.json + 66: RESULT proof_alone_rerun rc=0 wall_s=15 peak_mib=7532 prove_s=8.2 verified=1 err="" + 67: RESULT proof_alone_rerun_line RESULT compressed shard 0: prove 8.2 s, proof 1272897 + bytes, verify 0.036 s, VERIFIED; statement + 0x6adcc7fab21512b58cfa3778756718fd37aea6cccb311e12d2ca33b5f4bf10c0 proof sha256 + 0x7b887af9426039e61345f11d2c9faf10d4b4d0d16e4850d10ee08c5fa7002 + 68: RESULT cmd proof_beside_comp26: env HOME=/opt/igneum-floor/home SP1_PROVER=cuda + RUST_LOG=off SP1_GPU_FLOOR_LOG=1 SP1_GPU_ELEMENT_THRESHOLD=67108864 timeout 600 + /opt/igneum-floor/bin-0317/igneum-prove-host /root/coex/fees-v1-shards2.json --mode + compressed --shard 0 --out /root/coex/proof-beside-comp26-rerun.json (started 3s+10s after + the miner, miner resident mem_mib=6116) + 69: RESULT proof_beside_comp26 mode=compressed thr=67108864 rc=1 wall_s=5 + proof_window=1791473509..1791473514 miner_start=1791473495 prove_s= verified=0 + miner_alive_after=yes err="thread 'tokio-rt-worker' (10627) panicked at + slop/crates/tensor/src/inner.rs:51:51:" + 70: RESULT miner_beside_comp26 rc=0 wall_s=359 peak_mib=7811 check=PASS + fingerprint=23ced07a4d28b465 mhs=18.833 self-test PASS + 71: RESULT beside_fallback compressed 2^26 beside the miner did not verify (the core 2^25 + beside row is in run.log) + 72: RESULT idle_after mem_mib=2 + 73: ``` + 74: + 75: ## The table + 76: + 77: | Card | Miner alone (ds55) | Proof alone (compressed 2^26) | Together | Register + windows (v5 kit worker) | + 78: |---|---|---|---|---| + 79: | RTX 3060 12 GB | 26.82 MH/s at 117.4 W, 6,129 MiB resident, fingerprint + 23ced07a4d28b465, PASS | 13.2 s, VERIFIED, peak 7,525 MiB, 122 W | 6,129 + 7,525 = 13,654 + MiB against 12,288: TIME-SHARING NEEDED. Live attempt: the card filled to 11,893 MiB and the + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 39 + +MASTER 178 / 292 + R2 / SOURCE REVIEW + + + + + prover died in a device allocation (raw_buffer.rs:271) after 34 s; the miner held 26.51 + MH/s through it (1.2 percent under alone). Proof with the miner paused = the proof-alone row + | hl-reg64c 13.47 MH/s, 87 regs, 16 of 24 blocks per SM, fingerprint 4e7cc25967eba280 + MATCH, 120.8 W; hl-reg64 13.48 MH/s, 104 regs, 16 of 24, 70e786af1a457653 MATCH, 119.3 W | + 80: | RTX 4060 8 GB | 18.84 MH/s, 6,116 MiB resident, fingerprint 23ced07a4d28b465, PASS (no + watts: host sensor N/A) | 8.2 s, VERIFIED, peak 7,532 MiB | 6,116 + 7,532 = 13,648 MiB + against 8,188: TIME-SHARING NEEDED. Live attempt: the server died in a tensor allocation + (inner.rs:51) at 7,811 MiB after 5 s; the miner held 18.83 MH/s | hl-reg64c 9.51 MH/s, 87 + regs, 20 of 24 blocks per SM, fingerprint MATCH; hl-reg64 9.57 MH/s, 104 regs, 16 of 24, + MATCH | + 81: + 82: Not measured and why: a core-only proof beside the miner (igneum-prove-host-0317 has no + `--mode core`: "Error: unknown mode core"; its modes are native, execute, shard, compressed, + block, all); watts on the 4060 (the host's power sensor reads N/A). + 83: + 84: ## Reconciliation with the served row + 85: + 86: The served sentence (litepaper, "Proving", from + `docs/analysis/prover-tiers-real-cards.md`, 6 October 2026) says an RTX 3060 (12 GB) "mines + at 23.78 MH/s and proves the v1 shard beside its miner at an 8.9 GB peak in 37.5 s". Today's + row on the same card tier reads a 7.5 GiB compressed peak that kills the prover beside a + 6.1 GiB miner. The two are not in conflict; they measured different things. The 6 October + row is the matrix's `miner-comp-26-v1` point (`tools/fleet/box-matrix.sh` section 7): the + patched server at threshold 2^26 in compressed mode, driven by the matrix host (the segment + host build at `/opt/igneum-segal/.../igneum-prove-host`, which also carries `--mode core`; + the matrix's core rows come from it), beside `igneum-miner mine` on the 1 GiB class v3 pack, + whose resident set was 1.4 GB: 1.4 + 7.5 = 8.9 GB, inside 12 GB, proof in 37.5 s with the + miner running. Today's row is igneum-prove-host-0317 in compressed mode at the same + threshold 2^26 (the same 7.5 GiB own footprint, 7,525 to 7,532 MiB peak alone), beside the + ds55 miner on the 5.5 GiB dataset of the genesis floor, whose resident set is 6.1 GB: 6.1 + + 7.5 = 13.6 GB, outside 12 GB and 8 GB alike, so the prover's allocation fails while the + miner keeps mining. What changed between the rows is the miner's dataset (1 GiB then, 5.5 + GiB now), not the prover. The rule that follows: at the 5.5 GiB floor a compressed shard + proof beside a running miner needs a 16 GB card (13.6 GB together; the 16 GB tier's own peak + is 18 GB on the stock sizes and 7.8 GB patched, so 16 GB holds both with about 2 GB spare); + 8 GB and 12 GB cards time-share, proving with the miner paused (13.2 s on the 3060, 8.2 s + on the 4060) and mining otherwise. The 6 October beside rows stand only for the 1 GiB + dataset; the 6 October core-only beside rows (5.6 GB own on the 3060, 27.2 s) stand only for + core mode on the segment host, which the 0317 host does not expose, and are not a + coexistence claim at the floor. The served sentence is read as a 1 GiB-dataset row until the + site lane rewrites it against this record. + + + +F08 excerpts + +proving/igneum-proving/docs/analysis/proving-pipeline-2026-10-08.md:7-16 +SHA-256: 9f96b76b32e6647b83fa8f751d695f581020b603bedadd2d515578937fb2a7fa + + + 7: ## The window and its limit + 8: + 9: The measurement window is the whole of 8 October's proving on the rented fleet, 07:00:26Z + (first claim) to 14:27:15Z (last claim), read + 10: from every prover box's own log after Devnet 3 was turned off at 15:34Z. Paid work + exists only between 07:46:55Z and 10:43:10Z: 93 paid + 11: segments, 172.88 IGN. From 11:45Z the chain stalled at the class v5 crossing and then + partitioned (every solo branch carried old-object + 12: blocks, the network restarted from the stall sink at 15:27Z and was turned off at + 15:34Z), so every segment claimed after 11:45Z was + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 40 + +MASTER 179 / 292 + R2 / SOURCE REVIEW + + + + + 13: submitted into a chain that never paid it. The hold's declared workload (150 tx/s) ran + 11:42Z to 12:23Z with inclusion, then without, so + 14: no paid shard carries a hold transaction: the stage columns below are the fleet's + proving of the chain's own blocks, under the pre-stall + 15: load (the DEX and faucet lanes, the hold's earlier steps), on the 0.3.24 node + (5b673577). The window asked for, two hours under the hold, + 16: does not exist in the record; this is the honest substitute, and the instrument is in + place for the next chain. + + + + +proving/igneum-proving/docs/analysis/proving-pipeline-2026-10-08.md:35-84 +SHA-256: 9f96b76b32e6647b83fa8f751d695f581020b603bedadd2d515578937fb2a7fa + + + 35: ## Stage columns, seconds, every segment that reached the stage + 36: + 37: | stage | n | median | slowest 5 % | slowest 1 % | max | + 38: |---|---|---|---|---|---| + 39: | inputs (claim to export and cuts done) | 2,447 | 2.4 | 7.5 | 10.1 | 14.7 | + 40: | proving (shard proofs) | 2,453 | 26.8 | 216.1 | 364.7 | 1,104.7 | + 41: | aggregation (segment chain) | 2,453 | 22.8 | 44.2 | 96.4 | 156.6 | + 42: | verification and shard-record submission | 2,453 | 0.0 | 2.0 | 2.0 | 10.0 | + 43: | segment-record submission | 1,909 | 0.0 | 1.0 | 1.0 | 1.0 | + 44: | claim to submitted (end to end) | 1,909 | 75.1 | 230.3 | 301.6 | 497.4 | + 45: | inclusion and payment (submitted to paid) | 93 | 171.0 | 543.0 | 31,397 | 31,470 | + 46: | claim to paid | 91 | 336.0 | 720.0 | 1,098 | 1,240 | + 47: | peak GPU memory during the chain, MiB | 2,453 | 11,948 | 21,174 | 25,788 | 26,210 | + 48: + 49: The two 31,000-second payments are segments submitted before the 02:4xZ pause and paid + when the chain resumed; without them the + 50: inclusion-and-payment p99 is 902 s. The assignment wait is not in the table (see the + instrument row). + 51: + 52: ## Paid segments per tier + 53: + 54: | tier | paid segments | IGN | proving median s | aggregation median s | payment median + s | payment p95 s | + 55: |---|---|---|---|---|---|---| + 56: | RTX 4090 | 48 | 89.33 | 117.3 | 20.1 | 177.5 | 649 | + 57: | RTX 3090 | 34 | 59.66 | 69.8 | 75.0 | 166.0 | 543 | + 58: | L40S | 10 | 21.86 | 67.0 | 18.7 | 125.0 | 370 | + 59: | RTX 6000 Ada | 1 | 2.03 | 20.2 | 18.4 | 116.0 | 116 | + 60: | RTX 3060 (12 GB) | 0 | 0 | | | | | + 61: + 62: The 3090's aggregation median (75 s) is three times the 4090's: the segment chain is + memory-bound and the 3090 pays for it. The 4090's + 63: proving median on paid segments (117 s) is above the all-segment median (27 s) because + paid segments are the long ones (the short ones + 64: were taken by a faster claimant, below). + 65: + 66: ## Outcomes per tier and wasted work + 67: + 68: | tier | claimed | paid | stolen | refused | submitted, never paid | claimed, never + submitted | work s paid | work s wasted | + 69: |---|---|---|---|---|---|---|---|---| + 70: | RTX 4090 | 2,515 | 48 | 98 | 93 | 1,322 | 959 | 7,025 | 183,524 | + 71: | RTX 3060 12 GB | 313 | 0 | 0 | 0 | 34 | 280 | 0 | 6,765 | + 72: | L40S | 273 | 10 | 25 | 28 | 147 | 63 | 1,196 | 26,026 | + 73: | RTX 3090 | 263 | 34 | 8 | 30 | 152 | 41 | 6,484 | 34,855 | + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 41 + +MASTER 180 / 292 + R2 / SOURCE REVIEW + + + + + 74: | RTX 6000 Ada | 45 | 1 | 6 | 0 | 26 | 12 | 57 | 3,055 | + 75: + 76: - "submitted, never paid" (1,681 segments) is the partition: records accepted into a + chain that never settled them after 11:45Z. It is + 77: the day's largest waste and is not a pipeline fault; it is the fault of the afternoon + (the fleet record). + 78: - "claimed, never submitted" (1,355): the chain step failed or the claim was abandoned. + The failures are counted below. + 79: - The 3060 tier completed no paid segment in 313 claims: at 12 GB the chain runs out of + margin (its proving median on completed chains + 80: is above the 4090's by the card's ratio, and a 4090 claimant finishes the same segment + first), so the 12 GB tier is a miner, not a + 81: prover, on this segment size. The 3060's 34 submitted segments were all after 11:45Z + (never paid for the partition's reason). + 82: - Wasted work is the end-to-end seconds of every claimed segment that was not paid; the + fleet spent 254,000 card-seconds (70 card-hours) + 83: on segments that did not pay against 14,800 (4.1 card-hours) that did. Before the + stall the ratio was about 3 to 1 (the steals and + 84: refusals below); after it, everything was waste. + + + + +proving/igneum-proving/docs/analysis/proving-pipeline-2026-10-08.md:86-121 +SHA-256: 9f96b76b32e6647b83fa8f751d695f581020b603bedadd2d515578937fb2a7fa + + + 86: ## Failures and retries + 87: + 88: - `RESULT seg N chain FAILED`: 900, median wall 2.7 s. 629 "NotFound: No such file or + directory": the sm_89 floor tarball's + 89: `igneum-prove-host` was a dangling link until the real host was served at 10:50Z + (08:00 to 10:59Z, the fleet record's floor fault); + 90: 264 "invalid string length" (the host's proof-bytes string on the 48 GB cards' larger + segments); 4 OutOfMemory (12 GB cards). After + 91: 10:50Z the NotFound class ended; the string-length class remains open for the node + lane. + 92: - `RESULT segment_refused`: 153. 62 "does not chain to segment N..N" (the previous + segment's record moved under the claim), 54 "unproven: + 93: the record is carried after the segment's deadline" (the chain step finished too + late), 35 "segment already paid" (a faster claimant). + 94: - Retries: 0 lines "record accepted on retry". The prover does not retry a failed chain; + it drops the export and claims afresh. + 95: - Failure rate on claims: 900 chain failures plus 153 refusals over 3,421 claims is 30.8 + percent; without the floor-link class (fixed) it + 96: is 12.5 percent. + 97: + 98: ## Steals: a faster claimant takes an assigned prover's reward + 99: + 100: `RESULT paid_other`: 137 segments this box had claimed were paid to another key, 4.0 + percent of claims (98 on 4090s, 25 on L40S, 8 on + 101: 3090s, 6 on the 6000 Ada). The time from this box's claim to the other key's payment + read: median 306 s, p95 9,757 s (the long tail is the + 102: same pause-and-resume as the payment column). The exclusive window (10 DAA seconds) + does not hold a slow claimant's segment for it: a + 103: second box that finishes its chain first is paid. The 3060 tier was never the winner + and never the victim (it never finished). + 104: + 105: ## Queue depth over time + 106: + 107: The worklist as the provers read it on idle passes, median entries per hour (tip in the + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 42 + +MASTER 181 / 292 + R2 / SOURCE REVIEW + + + + + line): 02Z 596, 05Z 596, 08Z 596, 11Z 713, 14Z + 108: 594. Bounded at about 600 entries (the 600 DAA unproven window times one entry a DAA) + for the whole day; it did not grow, because a + 109: segment leaves the list at its deadline whether proved or not. Growth would show the + window itself lengthening; it did not. + 110: + 111: ## What this means + 112: + 113: - With the floor link fixed, the pipeline's own stages are fast: inputs 2 s, + verification and submission under 2 s, aggregation 23 s + 114: (75 s on a 3090); the proving stage sets the pace, 27 s median and 216 s at the + slowest 5 percent, and payment lands 171 s after + 115: submission (543 s at the slowest 5 percent) when the chain settles. + 116: - The waste is structural, not incidental: 70 card-hours wasted against 4 paid, + dominated by the partition, then by the floor fault, + 117: then by steals and late chains (13 percent of claims). Two changes would cut the + pre-stall waste: a claim that is honoured for the + 118: window it was granted (the steal rate goes to zero) and a 12 GB tier that claims only + segments it can finish (the 3060's 313 claims + 119: earned nothing). + 120: - The next chain (igneum-devnet-4) starts this instrument from block zero; the two-hour + window under the hold's declared workload is + 121: the first measurement to run on it, with block timestamps read so the assignment wait + becomes a real column. + + + +F09 excerpts + +v6/igneum-v6-freeze-tree/docs/analysis/class-v6/coexistence-model.md:299-321 +SHA-256: 8b2b8964a77bac49c88c3d9c801455f18d9e730859b61ef958ffa3fa79f0de4a + + + 299: ## 12. The conditions under which the success statement holds (the result) + 300: + 301: | Condition | The number on today's rows | DRAM board | SRAM die | + 302: |---|---|---|---| + 303: | (a) the chip's all-in cost per accepted unit at its own electricity within about 1.5x + of the best GPU owner's at the GPU's electricity | the owner at 0.12: 263 to 332 micro-USD + (5070 Ti, 5080) | 307 at 3 y, 750 at 1 y: PASSES | 72 to 134: FAILS at every life | + 304: | (b) the chip's annualised hardware per MH/s not below about a quarter of the GPU + entrant's | the 5080 entrant's hardware 460 micro-USD | 239 to 677: PASSES | 33 to 95: FAILS + | + 305: | (c) a fleet above a third of the chain's hash costs more than a year's miner revenue + | at IGN 0.10 the chain is 9.6 TH/s, a third 3.2 | USD 18 M of boards against USD 40 to 80 + M: PASSES above IGN 0.05 | USD 2.5 M of dies: FAILS at every price under about 3 | + 306: | (d) GPUs keep a resale market and a use outside mining | resale 25 to 55 percent + after two years; rental 3x to 5x the mining cost | PASSES (the GPU side's property) | PASSES + (the same) | + 307: | (e) the per-joule gap at the honest knee stays under about 3x | Blackwell at the knee + 1.70 to 2.06 microjoules | 2.2x to 2.6x: PASSES | 3.7x to 4.5x: FAILS (the bare-lane floor + 10x to 12x) | + 308: | (f) the supplier's gross margin is a normal return (under about 70 percent) and does + not rise with the halvings | section 8 | 27 to 69 percent, falling with the halvings: PASSES + | 85 to 93 percent, rising, or a loss once it is the chain: FAILS | + 309: | (g) a second income (proving) for the commodity side that the specialised supplier + cannot enter | section 5: USD 3 to 7 a card-day at launch demand on the 16 GB and larger + tiers; 0 for any hash engine | PASSES (the board cannot prove either, which is the GPU's + advantage over it) | PASSES (the same) | + 310: + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 43 + +MASTER 182 / 292 + R2 / SOURCE REVIEW + + + + + 311: **The result.** The success statement holds for the stored-dataset DRAM-board chip at a + 1 to 3 year life on today's + 312: rows, in every price path, at every electricity price on the axis, with the GPU side's + own generation curve narrowing + 313: the gap further and proving as a second income the chip cannot enter; its pass needs no + small network (it holds at 42 + 314: TH/s and IGN 1.00), no token appreciation (it holds on the flat and shrinking paths) + and no scheduled ASIC death (the + 315: life axis, not the rotation, is what the board lives on). The statement does not hold + for the N2 SRAM die once that + 316: die exists with its development sunk, at any life, price path or electricity price; a + small network makes it worse, + 317: appreciation only delays it, and the rotation does not touch a programmable die. **The + model names where it fails: a + 318: sunk SRAM die fleet of USD 10 M or more at any price in the window, and of USD 1 M in a + shrinking chain.** The only + 319: condition that holds the die is that nobody pays to build it (section 6: IGN 0.73 for a + USD 150 M project at a third + 320: of the chain over three years, 0.22 taking the chain, 0.12 to 0.16 for a revision), + which is a statement about an + 321: investor's decision and is carried as such, not as a level the chain stays below. + + + +F10 excerpts + +mining/proto-cuda/nvrtc/worker.cpp:1254-1295 +SHA-256: faf4782ff0fbfdea594e4635200a75db9084f96c663053d7c074df8e5bebf92f + + + 1254: uint64_t remaining = nonceCount, hashes = 0; + 1255: uint32_t hi = (uint32_t)(nonceStart >> 32), lo = (uint32_t)nonceStart; + 1256: bool failed = false; + 1257: while (remaining > 0) { + 1258: uint64_t room = (uint64_t)(0xffffffffu - lo) + 1ull; + 1259: uint64_t chunk64 = remaining < batch ? remaining : batch; + 1260: if (chunk64 > room) chunk64 = room; + 1261: uint32_t chunk = (uint32_t)chunk64; + 1262: uint32_t iw[8]; + 1263: { + 1264: uint8_t b[49]; + 1265: std::memcpy(b, "igneum-block/", 13); + 1266: std::memcpy(b + 13, prehash, 32); + 1267: b[45] = (uint8_t)hi; b[46] = (uint8_t)(hi >> 8); b[47] = (uint8_t)(hi + >> 16); b[48] = (uint8_t)(hi >> 24); + 1268: pf_seed_words_from_bytes(b, 49, iw); + 1269: } + 1270: // A chunk that is not a multiple of the block is finished one 32-lane + block at a time. The block is the + 1271: // pair's (its winning variant's). The mutex gives a race its exclusive + windows between chunks. + 1272: std::lock_guard hold(gpuMutex); + 1273: uint32_t block = 32u * (uint32_t)cur->blockWarps; + 1274: uint32_t main = chunk - (chunk % block); + 1275: CUresult r = CUDA_SUCCESS; + 1276: if (main > 0 && !launchHash(c, cur, dOut, lo, iw, main, block, nullptr, + err)) { emit("error " + jobId + " dispatch failed: " + err); failed = true; break; } + 1277: if (main < chunk) { + 1278: for (uint32_t off = main; off < chunk && !failed; off += 32u) if + (!launchHash(c, cur, dOut + (CUdeviceptr)off * 8u, lo + off, iw, 32u, 32u, nullptr, err)) { + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 44 + +MASTER 183 / 292 + R2 / SOURCE REVIEW + + + + + emit("error " + jobId + " dispatch failed: " + err); failed = true; } + 1279: if (failed) break; + 1280: } + 1281: r = c.drv.streamSynchronize(nullptr); + 1282: if (r == CUDA_SUCCESS) r = c.drv.memcpyDtoH(hOut.data(), dOut, + (size_t)chunk * 8u); + 1283: if (r != CUDA_SUCCESS) { emit("error " + jobId + " dispatch failed: " + + c.err(r)); failed = true; break; } + 1284: for (uint32_t i = 0; i < chunk; ++i) if (hOut[i] <= target) { + 1285: uint64_t nonce = ((uint64_t)hi << 32) | (uint64_t)(uint32_t)(lo + i); + 1286: std::printf("found %s %llu %016llx\n", jobId.c_str(), (unsigned long + long)nonce, (unsigned long long)hOut[i]); + 1287: } + 1288: std::fflush(stdout); + 1289: hashes += chunk; + 1290: remaining -= chunk; + 1291: if (chunk64 == room) { hi += 1u; lo = 0u; } else lo += chunk; + 1292: } + 1293: if (failed) continue; + 1294: emit(fmt("done %s %llu %.2f", jobId.c_str(), (unsigned long long)hashes, + wallMs() - t0)); + 1295: if (switched && old) { releasePair(c, old); old = nullptr; info("dropped the + previous pair (its program, cache and dataset)"); } + + + + +mining/proto-cuda/nvrtc/worker.cpp:1318-1341 +SHA-256: faf4782ff0fbfdea594e4635200a75db9084f96c663053d7c074df8e5bebf92f + + + 1318: // --bench: the pair is built and self-tested (vectors through the bound kernel with + the seed words); then a warm-up + 1319: // dispatch at base nonce 0 (fingerprinted) and --batches timed dispatches of 2^B + nonces, wall time around + 1320: // cuStreamSynchronize (the driver API path loads no event symbols; a 2^24 dispatch is + 60 to 900 ms on the cards here, + 1321: // so the launch overhead is under 1 percent). + 1322: static int runBench(Ctx& c, const Options& o, Pair* p) { + 1323: uint32_t nonces = 1u << o.batchLog2, block = 32u * (uint32_t)c.blockWarps; + 1324: if (p->persistent) { uint32_t unit = 32u * (uint32_t)p->warps; nonces = (nonces / + unit) * unit; if (nonces == 0) nonces = unit; } + 1325: CUdeviceptr dOut = 0; + 1326: std::string err; + 1327: if (c.drv.memAlloc(&dOut, (size_t)nonces * 8u) != CUDA_SUCCESS) { + std::printf("FAIL: cuMemAlloc out\n"); return 2; } + 1328: std::vector hOut(nonces); + 1329: double sum = 0, warm = 0; + 1330: uint64_t fp = 0; + 1331: for (int b = -1; b < o.batches; ++b) { + 1332: double t0 = wallMs(); + 1333: if (!launchHash(c, p, dOut, (uint32_t)(b + 1) * nonces, p->sw, nonces, block, + nullptr, err)) { std::printf("FAIL: %s\n", err.c_str()); return 2; } + 1334: CUresult r = c.drv.streamSynchronize(nullptr); + 1335: if (r != CUDA_SUCCESS) { std::printf("FAIL: dispatch %d: %s\n", b, + c.err(r).c_str()); return 2; } + 1336: double ms = wallMs() - t0; + 1337: if (b < 0) { + 1338: warm = ms; + 1339: if (c.drv.memcpyDtoH(hOut.data(), dOut, (size_t)nonces * 8u) != + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 45 + +MASTER 184 / 292 + R2 / SOURCE REVIEW + + + + + CUDA_SUCCESS) { std::printf("FAIL: read-back\n"); return 2; } + 1340: fp = fnv1a64Bytes(hOut.data(), (size_t)nonces * 8u); + 1341: } else sum += ms; + + + + +mining/proto-opencl/host.c:1652-1705 +SHA-256: ac390fe2a6a338e24a4530fe68fd5cab3ea7b3ecf822dcd5c9504bd5ea669b6f + + + 1652: /* The select pass (5 October 2026). Before it every dispatch read back 8 bytes + per nonce (16 MiB for a 2^21-nonce + 1653: * job) over the bus and scanned them on the host; on an eGPU over USB4 that is a + measurable part of every job. + 1654: * Now a tiny kernel built here (no pack involved) writes the hits (index, hash) + behind an atomic counter plus 34 + 1655: * sentinel words (the first 32 outputs, the middle and the last), and the host + reads back a few hundred bytes. + 1656: * The fault detectors read the sentinels; the found lines are printed in nonce + order from the sorted hits. If a + 1657: * chunk has more hits than the table holds (a target that loose is a test, not a + block), the chunk falls back to the + 1658: * full read. --readback full or IGNEUM_READBACK=full keeps the old path for a + comparison. */ + 1659: #define IG_MAX_HITS 256u + 1660: cl_program selProg = NULL; + 1661: cl_kernel kSelect = NULL; + 1662: cl_mem dCount = NULL, dHits = NULL, dSentinel = NULL; + 1663: size_t selLocal = di->maxWorkGroup < 256 ? di->maxWorkGroup : 256; + 1664: uint32_t hCount = 0; + 1665: uint64_t hHits[IG_MAX_HITS * 2]; + 1666: uint64_t hSentinel[34]; + 1667: unsigned long long bytesUp = 0, bytesDown = 0; + 1668: double kernelMsSum = 0, selectMsSum = 0, readMsSum = 0, scanMsSum = 0; + 1669: unsigned long fullFallbacks = 0; + 1670: if (!o->readback) { + 1671: static const char* SELECT_SRC = + 1672: "__kernel void igneum_select(__global const ulong* out, uint n, ulong + target, volatile __global uint* count,\n" + 1673: " __global ulong* hits, uint maxHits, __global + ulong* sentinel) {\n" + 1674: " uint i = (uint)get_global_id(0);\n" + 1675: " if (i < n) {\n" + 1676: " ulong h = out[i];\n" + 1677: " if (h <= target) { uint k = atomic_inc(count); if (k < maxHits) { + hits[2u * k] = (ulong)i; hits[2u * k + 1u] = h; } }\n" + 1678: " if (i < 32u) sentinel[i] = h;\n" + 1679: " if (i == 0u) { sentinel[32] = out[n / 2u]; sentinel[33] = out[n - + 1u]; }\n" + 1680: " }\n" + 1681: "}\n"; + 1682: size_t selLen = strlen(SELECT_SRC); + 1683: selProg = clCreateProgramWithSource(dv->ctx, 1, &SELECT_SRC, &selLen, &err); + CL_CHECK_ERR(err, "clCreateProgramWithSource select"); + 1684: err = clBuildProgram(selProg, 1, &di->device, "-cl-std=CL1.2", NULL, NULL); + 1685: if (err != CL_SUCCESS) { + 1686: size_t logLen = 0; char* log; + 1687: clGetProgramBuildInfo(selProg, di->device, CL_PROGRAM_BUILD_LOG, 0, NULL, + &logLen); + 1688: log = (char*)calloc(logLen + 1, 1); + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 46 + +MASTER 185 / 292 + R2 / SOURCE REVIEW + + + + + 1689: if (logLen) clGetProgramBuildInfo(selProg, di->device, + CL_PROGRAM_BUILD_LOG, logLen, log, NULL); + 1690: printf("info the select pass did not build (%s): %.300s; using the full + read-back\n", clErrName(err), log); + 1691: free(log); clReleaseProgram(selProg); selProg = NULL; + ((Options*)o)->readback = 1; + 1692: } else { + 1693: kSelect = clCreateKernel(selProg, "igneum_select", &err); + CL_CHECK_ERR(err, "clCreateKernel igneum_select"); + 1694: dCount = clCreateBuffer(dv->ctx, CL_MEM_READ_WRITE, 4, NULL, &err); + CL_CHECK_ERR(err, "clCreateBuffer count"); + 1695: dHits = clCreateBuffer(dv->ctx, CL_MEM_READ_WRITE, IG_MAX_HITS * 2 * + sizeof(uint64_t), NULL, &err); CL_CHECK_ERR(err, "clCreateBuffer hits"); + 1696: dSentinel = clCreateBuffer(dv->ctx, CL_MEM_READ_WRITE, 34 * + sizeof(uint64_t), NULL, &err); CL_CHECK_ERR(err, "clCreateBuffer sentinel"); + 1697: gMemCreated += 3; + 1698: { + 1699: size_t wg = 0; + 1700: if (clGetKernelWorkGroupInfo(kSelect, di->device, + CL_KERNEL_WORK_GROUP_SIZE, sizeof(wg), &wg, NULL) == CL_SUCCESS && wg && wg < selLocal) + selLocal = wg; + 1701: } + 1702: } + 1703: } + 1704: printf("info readback %s (per dispatch of %u nonces: %s)\n", o->readback ? "full" + : "select", + 1705: batch, o->readback ? "8 bytes per nonce come back and the host scans them" + : "the hits and 34 sentinel words come back; the GPU scans"); + + + + +mining/proto-opencl/host.c:1882-1899 +SHA-256: ac390fe2a6a338e24a4530fe68fd5cab3ea7b3ecf822dcd5c9504bd5ea669b6f + + + 1882: r0 = wallMs(); + 1883: if (useSelect) { + 1884: SERVE_CHECK(jobId, clEnqueueReadBuffer(dv->q, dCount, CL_TRUE, 0, 4, + &hCount, 0, NULL, NULL)); + 1885: bytesDown += 4; + 1886: nHits = hCount; + 1887: if (nHits > IG_MAX_HITS) { + 1888: /* more hits than the table holds: this chunk takes the full path + (the test target case) */ + 1889: ++fullFallbacks; + 1890: useSelect = 0; + 1891: } else { + 1892: if (nHits) { SERVE_CHECK(jobId, clEnqueueReadBuffer(dv->q, dHits, + CL_TRUE, 0, (size_t)nHits * 2 * sizeof(uint64_t), hHits, 0, NULL, NULL)); bytesDown += + (unsigned long long)nHits * 16; } + 1893: SERVE_CHECK(jobId, clEnqueueReadBuffer(dv->q, dSentinel, CL_TRUE, + 0, 34 * sizeof(uint64_t), hSentinel, 0, NULL, NULL)); + 1894: bytesDown += 34 * 8; + 1895: } + 1896: } + 1897: if (!useSelect) { + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 47 + +MASTER 186 / 292 + R2 / SOURCE REVIEW + + + + + 1898: SERVE_CHECK(jobId, clEnqueueReadBuffer(dv->q, dOut, CL_TRUE, 0, + (size_t)chunk * sizeof(uint64_t), hOut, 0, NULL, NULL)); + 1899: bytesDown += (unsigned long long)chunk * 8; + + + + +mining/proto-metal/main.swift:3344-3370 +SHA-256: 0f909ca4d20345635765e03442b06c79f34bc8a2ec8bdac22a3e87f6d7e209b5 + + + 3344: let outPtr = outBuf.contents().bindMemory(to: UInt64.self, capacity: batch) + 3345: let kernel = program.compiled // the pair's kernel for + this job (a race may swap it for the next) + 3346: while remaining > 0 { + 3347: let room = UInt64(UInt32.max - lo) + 1 // lane nonces left before + the high word steps + 3348: let chunk = Int(min(min(remaining, UInt64(batch)), room)) + 3349: var initw = blockInitWords(prehash: prehash, nonceHi: hi) + 3350: gpuLock.lock() // a race's exclusive + windows fall between chunks + 3351: let cb = gpu.queue.makeCommandBuffer()! + 3352: let enc = cb.makeComputeCommandEncoder()! + 3353: encodeHash(enc, kernel, dataset: dataset.buffer, out: outBuf, base: lo, + initw: &initw, count: chunk) + 3354: enc.endEncoding() + 3355: cb.commit(); cb.waitUntilCompleted() + 3356: gpuLock.unlock() + 3357: if let e = cb.error { emit("error \(jobId) dispatch failed: \(e)"); failed + = true; break } + 3358: for i in 0.. Plan + { + 228: let mem_step = if limits.mem_max_mhz > limits.mem_default_mhz { + ((limits.mem_max_mhz - limits.mem_default_mhz) / 20).max(25) } else { 0 }; + 229: let core_step = if limits.clock_max_mhz > 0 { (limits.clock_max_mhz / + 20).max(25) } else { 0 }; + 230: let start = Point { clock_mhz: limits.clamp_clock(start.clock_mhz), power_pct: + start.power_pct.clamp(50, 100), mem_mhz: limits.clamp_mem(start.mem_mhz) }; + 231: Plan { kind: PlanKind::Climb, limits: limits.clone(), before: start, + tolerance_pct: goal.tolerance_pct(tolerance_pct), power: Vec::new(), clock_pcts: Vec::new(), + clock_fine: Vec::new(), fixed: Vec::new(), climb: Some(Climb { start, mem_step, core_step, + budget: 5, goal }) } + 232: } + 233: + 234: /// The goal's score of a row: MH per watt for efficiency and balanced, the rate + for maximum rate. + 235: pub fn score(&self, r: &Row) -> f64 { + 236: match self.climb.as_ref().map(|c| c.goal) { + 237: Some(Goal::MaxRate) => r.mhs, + 238: _ => r.eff, + 239: } + 240: } + 241: + 242: /// The climb's next probe from the rows so far: None when the budget is spent or + no move is left. + 243: fn climb_next(&self, rows: &[Row]) -> Option { + 244: let c = self.climb.as_ref()?; + 245: let step = |p: Point| Step { point: p, watts: + self.limits.watts_for(p.power_pct), kind: Kind::Climb }; + 246: if rows.is_empty() { + 247: return Some(step(c.start)); + 248: } + 249: if rows.len() >= c.budget { + 250: return None; + 251: } + 252: // the best usable row so far is the hill's top; a knob that produced a marked + (refused) row is backed off + 253: let best = rows.iter().filter(|r| r.usable()).max_by(|a, b| + self.score(a).partial_cmp(&self.score(b)).unwrap_or(std::cmp::Ordering::Equal))?; + 254: let refused_mem = rows.iter().any(|r| !r.usable() && r.point.mem_mhz > + best.point.mem_mhz); + 255: let refused_core = rows.iter().any(|r| !r.usable() && r.point.clock_mhz != 0 && + (best.point.clock_mhz == 0 || r.point.clock_mhz < best.point.clock_mhz)); + 256: let last = rows.last()?; + 257: let mem_up = |p: Point| -> Option { + 258: if c.mem_step == 0 || refused_mem { return None; } + 259: let base = if p.mem_mhz == 0 { self.limits.mem_default_mhz } else { + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 49 + +MASTER 188 / 292 + R2 / SOURCE REVIEW + + + + + p.mem_mhz }; + 260: let m = self.limits.clamp_mem(base + c.mem_step); + 261: (m > 0 && m != p.mem_mhz && m != base).then_some(Point { mem_mhz: m, ..p }) + 262: }; + 263: let core_down = |p: Point| -> Option { + 264: if c.core_step == 0 || refused_core { return None; } + 265: let base = if p.clock_mhz == 0 { self.limits.clock_max_mhz } else { + p.clock_mhz }; + 266: let k = self.limits.clamp_clock(base.saturating_sub(c.core_step)); + 267: (k > 0 && k != p.clock_mhz).then_some(Point { clock_mhz: k, ..p }) + 268: }; + 269: let tried = |p: Point| rows.iter().any(|r| r.point == p); + 270: // the last move improved: keep going the same way from the top; else turn: + memory first, then core, then both + 271: let last_improved = last.usable() && last.point == best.point && rows.len() > + 1; + 272: let last_was_mem = rows.len() > 1 && last.point.mem_mhz != rows[rows.len() - + 2].point.mem_mhz; + 273: let candidates: Vec> = if last_improved && last_was_mem { + 274: vec![mem_up(best.point), core_down(best.point)] + 275: } else if last_improved { + 276: vec![core_down(best.point), mem_up(best.point)] + 277: } else { + 278: vec![mem_up(best.point), core_down(best.point), + mem_up(best.point).and_then(core_down)] + 279: }; + 280: candidates.into_iter().flatten().find(|p| !tried(*p)).map(step) + + + + +mining/app/igneum-app/src/ember.rs:493-520 +SHA-256: e1e9d83e37b3acb47e89027994dba1638d7c4c547a0d1f587b95455cbe3c4873 + + + 493: pub fn from_samples(step: &Step, s: &Samples, baseline_mclk: f64) -> Row { + 494: let watts = mean(&s.draws); + 495: let mhs = mean(&s.rates); + 496: let mclk = mean(&s.mclks); + 497: let usable = s.draws.len() >= 3 && !s.rates.is_empty() && watts > 1.0; + 498: let mark = if s.faults > 0 { + 499: Mark::Faulted + 500: } else if s.unapplied { + 501: Mark::Unapplied + 502: } else if !usable { + 503: Mark::NoReadings + 504: } else if s.tmax >= HOT_C { + 505: Mark::Hot + 506: } else if baseline_mclk > 0.0 && mclk > 0.0 && mclk < MCLK_HOLD * baseline_mclk + { + 507: Mark::MemoryClock + 508: } else { + 509: Mark::Ok + 510: }; + 511: Row { point: step.point, limit: step.watts, watts, mhs, eff: if usable { mhs / + watts } else { 0.0 }, draws: s.draws.len(), rates: s.rates.len(), gclk: mean(&s.gclks), + mclk, tmax: s.tmax, faults: s.faults, mark: Some(mark) } + 512: } + 513: pub fn usable(&self) -> bool { + 514: self.eff > 0.0 && self.mark == Some(Mark::Ok) + 515: } + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 50 + +MASTER 189 / 292 + R2 / SOURCE REVIEW + + + + + 516: /// `TUNE card=)", f.size() > 1 ? f[1].c_str() + : "0", f.size() > 2 ? f[2].c_str() : "0")); continue; } + 1183: if (f[1].size() != 64) { emit(fmt("prepare-failed %s %s bad field + (epoch_seed 64 hex, day_seed hex)", f[1].c_str(), f[2].c_str())); continue; } + 1184: if (task) { emit(fmt("prepare-failed %s %s a prepare is still running", + f[1].c_str(), f[2].c_str())); continue; } + 1185: if (prepared && prepared->epochHex == f[1] && prepared->dayHex == f[2]) { + emit(fmt("prepared %s %s 0 (already resident)", f[1].c_str(), f[2].c_str())); continue; } + 1186: if (cur->epochHex == f[1] && cur->dayHex == f[2]) { emit(fmt("prepared %s + %s 0 (already the current pair)", f[1].c_str(), f[2].c_str())); continue; } + 1187: std::string dir = f[3]; + 1188: for (size_t i = 4; i < f.size(); ++i) dir += " " + f[i]; // a directory + with spaces arrives as several fields + 1189: prepareRoot = parentDir(dir); + 1190: task = new PrepareTask(); + 1191: task->epochHex = f[1]; task->dayHex = f[2]; task->dir = dir; task->t0 = + wallMs(); + 1192: task->wantClass = wantClass; task->wantEra = wantEra; + 1193: task->thread = std::thread(prepareRun, &c, task); + 1194: info(fmt("prepare started for epoch %.16s day %s from %s (NVRTC %s in the + background)", f[1].c_str(), f[2].c_str(), dir.c_str(), c.archOpt.c_str())); + 1195: continue; + 1196: } + 1197: if (f[0] != "job") { info("ignored: " + line); continue; } + 1198: std::string jobId = f.size() > 1 ? f[1] : "0"; + 1199: if (f.size() < 8) { emit("error " + jobId + " malformed job line (need 7 + fields after job)"); continue; } + 1200: uint8_t prehash[32], epochSeed[32], daySeed[256]; + 1201: size_t pl = 0, el = 0, dl = 0; + 1202: unsigned long long target = 0, nonceStart = 0, nonceCount = 0; + 1203: if (!pf_unhex(f[2].c_str(), prehash, 32, &pl) || pl != 32 || + std::sscanf(f[3].c_str(), "%llx", &target) != 1 || + 1204: std::sscanf(f[4].c_str(), "%llu", &nonceStart) != 1 || + std::sscanf(f[5].c_str(), "%llu", &nonceCount) != 1 || + 1205: !pf_unhex(f[6].c_str(), epochSeed, 32, &el) || el != 32 || + !pf_unhex(f[7].c_str(), daySeed, sizeof(daySeed), &dl)) { + 1206: emit("error " + jobId + " bad field (prehash 64 hex, target 16 hex, + nonce_start u64, nonce_count u64, epoch_seed 64 hex, day_seed hex)"); continue; + 1207: } + 1208: if (nonceCount == 0 || nonceCount % 32 != 0 || (nonceStart & 31) != 0) { + emit("error " + jobId + " nonce_start must be 32-aligned and nonce_count a non-zero multiple + of 32"); continue; } + 1209: uint32_t sw[8], kw[8]; + 1210: pf_seed_words_from_bytes(epochSeed, 32, sw); + 1211: pf_seed_words_from_bytes(daySeed, dl, kw); + 1212: double t0 = wallMs(); + 1213: bool switched = false; + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 31 + +MASTER 229 / 292 + R1 / SOURCE REVIEW + + + + + 1214: if (!pairIsClass(cur, f[6], f[7], wantClass, wantEra) && !task && + !pairIsClass(prepared, f[6], f[7], wantClass, wantEra)) { + 1215: // Self-heal: a job on seeds this worker has no pair for and no prepare in + flight (a prepare failed, or + 1216: // the miner never sent one). The miner writes a pack per pair under its + --prepare-packs root; find it by + 1217: // seeds.txt and build it now, in the foreground. The miner only re-sends + prepare for the pair after this one. + 1218: std::string dir = findPackFor(prepareRoot, f[6], f[7]); + 1219: if (dir.empty()) dir = findPackFor(parentDir(o.pack) + "/prepare", f[6], + f[7]); + 1220: if (dir.empty()) dir = findPackFor(parentDir(o.pack), f[6], f[7]); + 1221: if (!dir.empty()) { + 1222: info(fmt("job %s is for epoch %.16s day %s, which is not resident; + building its pack %s now (foreground)", jobId.c_str(), f[6].c_str(), f[7].c_str(), + dir.c_str())); + 1223: std::string berr; + 1224: Pair* p = buildPair(c, dir, nullptr, berr, true); + 1225: if (p && (p->epochHex != f[6] || p->dayHex != f[7])) { berr = "the + pack in " + dir + " is for other seeds"; releasePair(c, p); p = nullptr; } + 1226: if (p) { if (prepared) releasePair(c, prepared); prepared = p; + info(fmt("built %s: %s", dir.c_str(), pairSummary(p).c_str())); if (!p->raceLine.empty()) + emit(p->raceLine); } + 1227: else emit("error " + jobId + " could not build " + dir + ": " + berr); + 1228: } + 1229: } + 1230: if (!pairIsClass(cur, f[6], f[7], wantClass, wantEra)) { + 1231: char why[256]; + 1232: if (pairIsClass(prepared, f[6], f[7], wantClass, wantEra)) { + 1233: if (old) releasePair(c, old); + 1234: old = cur; cur = prepared; prepared = nullptr; switched = true; + 1235: info(fmt("switched to the prepared pair epoch %.16s day %s (class %s) + in %.2f ms", cur->epochHex.c_str(), cur->dayHex.c_str(), cur->programClass.c_str(), wallMs() + - t0)); + 1236: } else if (pairIs(cur, f[6], f[7]) && + !pf_pack_class_ok(cur->programClass.c_str(), cur->eraHex.c_str(), wantClass.c_str(), + wantEra.c_str(), why, sizeof(why))) { + 1237: // Counter ASIC 2.0: right seeds, wrong class or era. The miner + prepares the pair again from a pack of + 1238: // the class the chain is on (the `need` line), and the pack of the + other class is never mined. + 1239: emit(fmt("need %s %s", f[6].c_str(), f[7].c_str())); + + + + +I06 Metal geometry +workers/proto-metal/main.swift:3133-3209 + + + 3133: func servePackDataset(_ gpu: GPU, _ store: ServeStore, dayHex: String, dir: String, + wantClass: String, wantEra: String) throws -> (ServeDataset, Double) { + 3134: if let d = store.dataset(dayHex, cls: wantClass, era: wantEra) { return (d, 0) } + 3135: let t0 = nowNs() + 3136: func refuse(_ why: String) -> NSError { NSError(domain: "pack", code: 3, userInfo: + [NSLocalizedDescriptionKey: "pack \(dir): \(why)"]) } + 3137: guard let programH = try? String(contentsOfFile: dir + "/program.h", encoding: + .utf8) else { throw refuse("cannot read program.h") } + 3138: func defineU32(_ name: String) -> UInt32? { + 3139: guard let re = try? NSRegularExpression(pattern: "#define \(name) + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 32 + +MASTER 230 / 292 + R1 / SOURCE REVIEW + + + + + ([0-9a-fA-Fx]+)"), let m = re.firstMatch(in: programH, range: + NSRange(programH.startIndex..., in: programH)) else { return nil } + 3140: let v = String(programH[Range(m.range(at: 1), in: + programH)!]).replacingOccurrences(of: "u", with: "") + 3141: return v.hasPrefix("0x") ? UInt32(v.dropFirst(2), radix: 16) : UInt32(v) + 3142: } + 3143: func defineStr(_ name: String) -> String? { + 3144: guard let re = try? NSRegularExpression(pattern: "#define \(name) + \"([^\"]*)\""), let m = re.firstMatch(in: programH, range: NSRange(programH.startIndex..., + in: programH)) else { return nil } + 3145: return String(programH[Range(m.range(at: 1), in: programH)!]) + 3146: } + 3147: let generator = defineU32("IGNEUM_GENERATOR") ?? 1 + 3148: let packClass = packClassOf(generator: generator) + 3149: let eraHex = defineStr("IGNEUM_ERA_SEED_HEX") ?? "" + 3150: if let packDay = defineStr("IGNEUM_DAY_BYTES_HEX"), packDay.lowercased() != + dayHex.lowercased() { throw refuse("the pack's day is \(packDay), not \(dayHex)") } + 3151: if wantClass != "" && wantClass != packClass { throw refuse("program class + mismatch: this pack is class \(packClass), the line names class \(wantClass)") } + 3152: if wantEra != "" && isPackClass(packClass) && wantEra.lowercased() != + eraHex.lowercased() { throw refuse("era seed mismatch: the pack's era is + \(eraHex.prefix(16)), the line names \(wantEra.prefix(16))") } + 3153: if (defineU32("IGNEUM_HOT_MB") ?? 0) > 0 { throw refuse("a hot-table pack + (IGNEUM_HOT_MB) is not served by this worker") } + 3154: guard (defineU32("IGNEUM_DATASET_MODE") ?? 0) == 1 else { throw refuse("not a + memory-hard pack (IGNEUM_DATASET_MODE 1)") } + 3155: let datasetLog2 = Int(defineU32("IGNEUM_DATASET_LOG2") ?? 28) + 3156: let cacheLog2 = Int(defineU32("IGNEUM_CACHE_LOG2_WORDS") ?? 26) + 3157: let cacheSegments = Int(defineU32("IGNEUM_CACHE_SEGMENTS") ?? 65536) + 3158: guard datasetLog2 >= 20 && datasetLog2 <= 31 && cacheLog2 >= 16 && cacheLog2 <= 30 + && cacheSegments % 256 == 0 && cacheSegments > 0 else { throw refuse("program.h sizes out + of range") } + 3159: guard let mhSrc = try? String(contentsOfFile: dir + "/memhard.metal", encoding: + .utf8) else { throw refuse("cannot read memhard.metal") } + 3160: let lib: MTLLibrary + 3161: do { lib = try gpu.device.makeLibrary(source: mhSrc, options: MTLCompileOptions()) + } catch { throw refuse("Metal compile of memhard.metal: \(error)") } + 3162: guard let fillFn = lib.makeFunction(name: "igneum_cache_fill"), let buildFn = + lib.makeFunction(name: "igneum_build") else { throw refuse("memhard.metal lacks + igneum_cache_fill or igneum_build") } + 3163: let fillPipe = try gpu.device.makeComputePipelineState(function: fillFn) + 3164: let buildPipe = try gpu.device.makeComputePipelineState(function: buildFn) + 3165: let words = 1 << datasetLog2 + 3166: // Class v5 (docs/design/class-v5-stored-state.md, 7 October 2026): the window's + state leaves, leaves.bin beside program.h + 3167: // (IGNEUM_STATE_LEAVES leaves of 16 little-endian words), checked against the + pack's count and FNV-1a 64 + 3168: // (IGNEUM_STATE_LEAVES_FNV64) and bound as buffer 2 of igneum_build with the + count in buffer 3 (packbench.swift's shape, + 3169: // the kernel text the Rust emitter wrote). A v5 pack without its leaves builds + nothing (the known-failed case); the buffer + 3170: // is dropped after the build, so device memory while hashing is the class v4 + worker's. + 3171: func defineU64(_ name: String) -> UInt64? { + 3172: guard let re = try? NSRegularExpression(pattern: "#define \(name) + 0x([0-9a-fA-F]+)ull"), let m = re.firstMatch(in: programH, range: + NSRange(programH.startIndex..., in: programH)) else { return nil } + 3173: return UInt64(programH[Range(m.range(at: 1), in: programH)!], radix: 16) + 3174: } + 3175: let stateLeaves = defineU32("IGNEUM_STATE_LEAVES") ?? 0 + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 33 + +MASTER 231 / 292 + R1 / SOURCE REVIEW + + + + + 3176: if (packClass == "v5") != (stateLeaves > 0) { throw refuse(packClass == "v5" ? + "class v5 pack without IGNEUM_STATE_LEAVES" : "a class \(packClass) pack carries + IGNEUM_STATE_LEAVES \(stateLeaves): state leaves belong to class v5") } + 3177: var leavesBuf: MTLBuffer? = nil + 3178: var nLeaves: UInt32 = 0 + 3179: if stateLeaves > 0 { + 3180: let file = defineStr("IGNEUM_STATE_LEAVES_FILE") ?? "leaves.bin" + 3181: guard let data = FileManager.default.contents(atPath: dir + "/" + file) else { + throw refuse("class v5 pack without its leaves file \(file) (the state leaves key every + item: nothing can be built without them)") } + 3182: if data.count != Int(stateLeaves) * 64 { throw refuse("\(file) is + \(data.count) bytes, the pack says \(stateLeaves) leaves of 64") } + 3183: guard let want = defineU64("IGNEUM_STATE_LEAVES_FNV64") else { throw + refuse("class v5 pack without IGNEUM_STATE_LEAVES_FNV64: the leaves cannot be checked") } + 3184: let got = fnv1a64Bytes([UInt8](data)) + 3185: if got != want { throw refuse("\(file) FNV-1a 64 \(h64(got)) is not the pack's + IGNEUM_STATE_LEAVES_FNV64 \(h64(want)) (the leaves are of another state root; export the + pack again)") } + 3186: guard let b = gpu.device.makeBuffer(bytes: (data as NSData).bytes, length: + data.count, options: .storageModeShared) else { throw refuse("cannot allocate the + \(data.count) byte leaf buffer") } + 3187: leavesBuf = b; nLeaves = stateLeaves + 3188: } + 3189: guard let cache = gpu.device.makeBuffer(length: (1 << cacheLog2) * 4, options: + .storageModePrivate) else { throw refuse("cannot allocate the 2^\(cacheLog2) word cache") } + 3190: guard let dataset = gpu.device.makeBuffer(length: words * 4, options: + .storageModePrivate) else { throw refuse("cannot allocate the 2^\(datasetLog2) word + dataset") } + 3191: func run(_ body: (MTLComputeCommandEncoder) -> Void) throws -> Double { + 3192: let cb = gpu.queue.makeCommandBuffer()! + 3193: let enc = cb.makeComputeCommandEncoder()! + 3194: body(enc); enc.endEncoding(); cb.commit(); cb.waitUntilCompleted() + 3195: if let e = cb.error { throw refuse("command buffer: \(e)") } + 3196: return (cb.gpuEndTime - cb.gpuStartTime) * 1000 + 3197: } + 3198: let fillMs = try run { enc in + 3199: enc.setComputePipelineState(fillPipe); enc.setBuffer(cache, offset: 0, index: + 0) + 3200: enc.dispatchThreadgroups(MTLSize(width: cacheSegments / 256, height: 1, depth: + 1), threadsPerThreadgroup: MTLSize(width: 256, height: 1, depth: 1)) + 3201: } + 3202: let buildMs = try run { enc in + 3203: enc.setComputePipelineState(buildPipe); enc.setBuffer(cache, offset: 0, index: + 0); enc.setBuffer(dataset, offset: 0, index: 1) + 3204: if let lb = leavesBuf { enc.setBuffer(lb, offset: 0, index: 2); var n = + nLeaves; enc.setBytes(&n, length: 4, index: 3) } + 3205: enc.dispatchThreadgroups(MTLSize(width: words / 16 / 256, height: 1, depth: + 1), threadsPerThreadgroup: MTLSize(width: 256, height: 1, depth: 1)) + 3206: } + 3207: leavesBuf = nil + 3208: // The build's self-test when the pack carries vectors.json (igneum-pow export + writes it): the dataset's head 16 words and + 3209: // its last word against the CPU reference, as the one-click workers' pf_selftest + does; a mismatch refuses the day (the + + + + +I07 engine workload class +app/src/engine.rs:3937-3957 + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 34 + +MASTER 232 / 292 + R1 / SOURCE REVIEW + + + + + 3937: /// A worker's race line (one per hourly prepare, docs/design/miner-tuning.md): + 3938: /// `race device driver arch loads wide variants + =/r/w ... + 3939: /// winner base gain % compile bench total + ms [| : ]`. + 3940: /// Becomes the fleet record: one `TUNING {json}` line in the app log (uploaded to + the intake, aggregated by + 3941: /// tools/tuning.mjs) with the card's power figures, plus the card state and one + event. + 3942: fn race_line(&mut self, card: usize, card_name: &str, text: &str) { + 3943: let Some(body) = text.split(" worker: race ").nth(1) else { return }; + 3944: let Some(r) = parse_race(body) else { return }; + 3945: let (vendor, worker, power_limit_w, power_w, power_pct) = { + 3946: let mut st = self.st(); + 3947: match st.mining.cards.get_mut(card) { + 3948: Some(c) => { + 3949: c.variant = r.winner.clone(); + 3950: c.race_mhs = r.mhs; + 3951: c.race_gain_pct = r.gain_pct; + 3952: c.race_variants = r.variants.len() as u32; + 3953: if !r.driver.is_empty() && c.driver.is_empty() { + 3954: c.driver = r.driver.clone(); + 3955: } + 3956: c.program_class = crate::ember::program_class(r.loads as u32, + r.wide as u32); + 3957: (c.vendor.clone(), c.worker.clone(), c.power_limit_w, c.power_w, + c.power_pct) + + + + +I07 engine restore path +app/src/engine.rs:1883-1903 + + + 1883: /// On quit: the limits the cards had before the app (one more prompt; nvidia-smi + limits do not survive a reboot anyway). + 1884: fn restore_power_limits(&mut self) { + 1885: if !self.power_restore_pending { + 1886: return; + 1887: } + 1888: let st = self.st(); + 1889: let cmds: Vec = st + 1890: .mining + 1891: .cards + 1892: .iter() + 1893: .filter(|c| c.vendor == "nvidia" && c.present() && c.power_applied && + c.power_before_w > 0.0) + 1894: .map(|c| format!("\"{}\" -i {} -pl {}", + crate::platform::tool("nvidia-smi").display(), c.device, c.power_before_w.round() as u64)) + 1895: .collect(); + 1896: drop(st); + 1897: if cmds.is_empty() { + 1898: return; + 1899: } + 1900: // no administrator prompt on quit (5 October 2026: the app never asks on its + own); the limits reset at the + 1901: // next reboot, and the next start with Power control on sets them again + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 35 + +MASTER 233 / 292 + R1 / SOURCE REVIEW + + + + + 1902: self.shared.log(&format!("GPU power limits left as set (they reset at the next + reboot; no prompt on quit): {}", cmds.join(" & "))); + 1903: } + + + + +I08 auth wire +pool/src/protocol.rs:42-54 + + + 42: Authorize { + 43: /// 48 bytes hex, the member's BLS vote key + 44: pubkey: String, + 45: /// 96 bytes hex, the proof of possession (spec 3.10 KeyReveal) + 46: pop: String, + 47: /// Worker name shown on the dashboards + 48: label: String, + 49: /// EVM payout address, 0x + 40 hex (v0 addition) + 50: payout: String, + 51: /// `binding` of spec 9.3 (a signature over the TLS exporter) is absent in v0: + no TLS yet + 52: #[serde(default)] + 53: binding: String, + 54: }, + + + + +I08 pool reading and authorization +pool/src/server.rs:53-151 + + + 53: share_scheme: ShareScheme { scheme: "pplns".into(), fee_percent: + pool.cfg.fee_percent, pplns_window_blocks: pool.cfg.pplns_window_blocks, min_payout_ign: + pool.cfg.min_payout_ign }, + 54: min_shift: pool.cfg.min_shift, + 55: max_shift: pool.cfg.max_shift, + 56: share_interval_s: pool.cfg.share_interval_s, + 57: stale_grace_ms: pool.cfg.stale_grace_ms, + 58: pool_name: pool.cfg.name.clone(), + 59: } + 60: } + 61: + 62: async fn connection(pool: Arc, sock: TcpStream, remote: String) { + 63: let (rd, mut wr) = sock.into_split(); + 64: let (tx, mut rx) = tokio::sync::mpsc::unbounded_channel::(); + 65: let writer = tokio::spawn(async move { + 66: while let Some(line) = rx.recv().await { + 67: if wr.write_all(line.as_bytes()).await.is_err() { + 68: break; + 69: } + 70: } + 71: }); + 72: let mut lines = BufReader::with_capacity(64 << 10, rd).lines(); + 73: let mut member: Option> = None; + 74: let mut said_hello = false; + 75: let mut buf_guard = 0usize; + 76: loop { + 77: let l = match tokio::time::timeout(Duration::from_secs(300), + lines.next_line()).await { + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 36 + +MASTER 234 / 292 + R1 / SOURCE REVIEW + + + + + 78: Ok(Ok(Some(l))) => l, + 79: Ok(Ok(None)) => break, + 80: Ok(Err(e)) => { + 81: eprintln!("{} {remote}: read error: {e}", now()); + 82: break; + 83: } + 84: Err(_) => { + 85: let _ = tx.send(Msg::Bye { reason: "idle for 300 s".into() }.line()); + 86: break; + 87: } + 88: }; + 89: buf_guard += l.len(); + 90: if l.len() > MAX_LINE { + 91: let _ = tx.send(Msg::Bye { reason: "line over 4 MiB".into() }.line()); + 92: break; + 93: } + 94: let msg = match Msg::parse(&l) { + 95: Ok(m) => m, + 96: Err(e) => { + 97: let _ = tx.send(Msg::Error { code: "parse".into(), detail: e }.line()); + 98: continue; + 99: } + 100: }; + 101: match msg { + 102: Msg::Hello { versions, chain_id, client, .. } => { + 103: if !versions.iter().any(|v| v == VERSION) { + 104: let _ = tx.send(Msg::Bye { reason: format!("protocol {VERSION} + only") }.line()); + 105: break; + 106: } + 107: if chain_id != pool.cfg.chain_id() { + 108: let _ = tx.send(Msg::Bye { reason: format!("chain id {} here, you + said {chain_id}", pool.cfg.chain_id()) }.line()); + 109: break; + 110: } + 111: said_hello = true; + 112: println!("{} {remote}: hello from {client}", now()); + 113: let _ = tx.send(welcome(&pool).line()); + 114: } + 115: Msg::Authorize { pubkey, pop, label, payout, .. } => { + 116: if !said_hello { + 117: let _ = tx.send(Msg::Error { code: "order".into(), detail: "hello + first".into() }.line()); + 118: continue; + 119: } + 120: let (Some(pk), Some(pp)) = (parse_hex_array::<48>(&pubkey), + parse_hex_array::<96>(&pop)) else { + 121: let _ = tx.send(Msg::Bye { reason: "pubkey is 48 bytes hex and pop + 96".into() }.line()); + 122: break; + 123: }; + 124: if !verify_pop(&pk, &pp) { + 125: let _ = tx.send(Msg::Bye { reason: "proof of possession does not + verify".into() }.line()); + 126: break; + 127: } + 128: let Some(addr) = parse_hex_array::<20>(&payout) else { + 129: let _ = tx.send(Msg::Bye { reason: "payout is 0x followed by 40 + hex".into() }.line()); + 130: break; + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 37 + +MASTER 235 / 292 + R1 / SOURCE REVIEW + + + + + 131: }; + 132: let reveal = KeyReveal { pubkey: pk, pop: pp }; + 133: let key_hash = reveal.key_hash(); + 134: let worker: String = label.chars().filter(|c| c.is_ascii_alphanumeric() + || *c == '-' || *c == '_' || *c == '.').take(32).collect(); + 135: let worker = if worker.is_empty() { "worker".to_string() } else { + worker }; + 136: let id = pool.next_member_id.fetch_add(1, Ordering::Relaxed) + 1; + 137: let m = Arc::new(Member { + 138: id, + 139: address: format!("0x{}", hex::encode(addr)), + 140: worker: worker.clone(), + 141: key_hash, + 142: reveal, + 143: remote: remote.clone(), + 144: connected_at: Instant::now(), + 145: tx: tx.clone(), + 146: inner: Mutex::new(MemberInner { + 147: vardiff: Vardiff::new(pool.cfg.min_shift, pool.cfg.min_shift, + pool.cfg.max_shift, pool.cfg.share_interval_s as f64, pool.now_s()), + 148: jobs: VecDeque::new(), + 149: last_parents: None, + 150: last_seeds: None, + 151: accepted: 0, + + + + +I10 attempted-work selection +app/src/prover.rs:79-90 + + + 79: /// The shard to prove next: assigned to one of our keys, unpaid, not already in the + pool from us, not attempted + 80: /// in this session; the newest first (its exclusive window is the one still open), the + smallest among equals. + 81: /// With nothing assigned, an open shard (spec 7.2 item 4: past its exclusive window, + unpaid, anyone may prove it), + 82: /// so a machine with no weight in the window still earns on what the assignees left. + 83: pub fn choose(work: &[Work], attempted: &HashSet<(String, u32)>) -> Option { + 84: let pick = |want_assigned: bool| { + 85: let mut c: Vec<&Work> = work.iter().filter(|w| (if want_assigned { w.assigned } + else { w.open }) && !w.paid && !w.in_pool && !attempted.contains(&(w.hash.clone(), + w.shard))).collect(); + 86: c.sort_by(|a, b| b.number.cmp(&a.number).then(a.pgas.cmp(&b.pgas))); + 87: c.first().map(|w| (*w).clone()) + 88: }; + 89: pick(true).or_else(|| pick(false)) + 90: } + + + + +I10 mark attempt and launch +app/src/prover.rs:625-678 + + + 625: let boundary = exec_boundary(&shared); + 626: let work: Vec = work.into_iter().filter(|w| w.number >= + boundary).collect(); + 627: let Some(w) = choose(&work, &attempted) else { + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 38 + +MASTER 236 / 292 + R1 / SOURCE REVIEW + + + + + 628: set(&shared, |p| { + 629: p.status = if submitted.is_empty() { "idle".into() } else { + "submitted".into() }; + 630: p.message = if assigned == 0 { format!("no shard assigned to this + machine and none open in the last {} blocks", crate::segments::WORK_LOOKBACK) } else { + "every assigned and open shard is proven or paid".into() }; + 631: }); + 632: continue; + 633: }; + 634: attempted.insert((w.hash.clone(), w.shard)); + 635: let label = keys.iter().find(|(_, h)| *h == w.key_hash).map(|(l, _)| + l.clone()).unwrap_or_else(|| keys[0].0.clone()); + 636: let payout = shared.settings.lock().unwrap().address.clone(); + 637: if payout.len() != 42 { + 638: set(&shared, |p| { + 639: p.status = "waiting".into(); + 640: p.message = "no rewards address".into(); + 641: }); + 642: continue; + 643: } + 644: let started = Instant::now(); + 645: set(&shared, |p| { + 646: p.status = "proving".into(); + 647: p.current = format!("block {} shard {} ({} txs, {} pgas{})", w.number, + w.shard, w.tx_count, w.pgas, if w.assigned { "" } else { ", open" }); + 648: p.started_at = crate::platform::unix_now_f(); + 649: p.message = "exporting the chain and cutting the shard".into(); + 650: }); + 651: shared.log(&format!("prover: block {} shard {} assigned to {label}: export, + cut, prove ({}), sign, submit", w.number, w.shard, if t.cuda { "CUDA" } else { "CPU" })); + 652: // 2. export and cut + 653: let dir = shared.runtime.app_dir.join("proving"); + 654: let _ = std::fs::create_dir_all(&dir); + 655: let seq = dir.join("seq.json"); + 656: let fixture = dir.join(format!("block-{}.json", w.number)); + 657: let results = dir.join(format!("results-{}-{}.json", w.number, w.shard)); + 658: let outcome: Result<(), String> = (|| { + 659: // the export from one block below (0.3.14): the node's account dump after + block n-1 seeds the exporter; + 660: // never from 0 (on a restarted node the records below the restart carry + zero roots and the exporter + 661: // refused every cut, the fleet 16:02Z) + 662: let from = w.number.saturating_sub(1); + 663: let export = evm_rpc(&shared, "igneum_exportSegments", + json!([format!("{from:#x}"), format!("{:#x}", w.number)]), Duration::from_secs(120))?; + 664: std::fs::write(&seq, export.to_string()).map_err(|e| e.to_string())?; + 665: let (seq_p, fix_p, res_p) = if t.wsl { (wsl_path(&seq), wsl_path(&fixture), + wsl_path(&results)) } else { (seq.display().to_string(), fixture.display().to_string(), + results.display().to_string()) }; + 666: let (ok, out) = run_tool(&shared, t, &t.export, &[seq_p, + w.number.to_string(), fix_p.clone()], &[], Duration::from_secs(600), + &dir.join(format!("export-{}.log", w.number))); + 667: if !ok || !fixture.exists() { + 668: return Err(format!("exporter: {}", out.lines().rev().find(|l| + !l.trim().is_empty()).unwrap_or("failed"))); + 669: } + 670: set(&shared, |p| p.message = if t.cuda { "proving on the GPU".into() } else + { "CPU prover: about five minutes a shard, 30 GB of RAM, paid only when no card proves + first".into() }); + 671: let prover_env = if t.cuda { "cuda" } else { "cpu" }; + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 39 + +MASTER 237 / 292 + R1 / SOURCE REVIEW + + + + + 672: let (ok, out) = run_tool(&shared, t, &t.host, &[fix_p, "--mode".into(), + "compressed".into(), "--shard".into(), w.shard.to_string(), "--prover".into(), + payout.clone(), "--out".into(), res_p], &[("SP1_PROVER", prover_env), ("RUST_LOG", "off")], + Duration::from_secs(3 * 3600), &dir.join(format!("prove-{}-{}.log", w.number, w.shard))); + 673: if !ok || !results.exists() { + 674: let last = out.lines().rev().find(|l| l.contains("RESULT") || + l.contains("rror")).unwrap_or("failed").to_string(); + 675: // the root-socket class (5 October 2026, PC 2 at 20:00Z and 21:25Z): a + job that ran the host as root + 676: // inside WSL2 left /tmp/sp1-cuda-0.sock owned by root, and this user's + client cannot open it + 677: let hint = if last.contains("PermissionDenied") { " (a GPU-server + socket /tmp/sp1-cuda-*.sock owned by another user, left by a job that ran the prover as + root: remove it as that user, or run the socket-fix job)" } else { "" }; + 678: return Err(format!("prover: {last}{hint}")); + + + + +I10 failure +app/src/prover.rs:701-724 + + + 701: })(); + 702: match outcome { + 703: Ok(()) => { + 704: shared.event("proving", &format!("block {} shard {} proven and + submitted in {:.0} s", w.number, w.shard, started.elapsed().as_secs_f64())); + 705: submitted.push((w.number, w.hash.clone(), w.shard, w.shard_wei)); + 706: set(&shared, |p| { + 707: p.proved += 1; + 708: p.submitted += 1; + 709: p.status = "submitted".into(); + 710: p.message = format!("block {} shard {} submitted; paid when a block + carries it", w.number, w.shard); + 711: p.current = String::new(); + 712: }); + 713: } + 714: Err(e) => { + 715: shared.log(&format!("prover: block {} shard {}: {e}", w.number, + w.shard)); + 716: set(&shared, |p| { + 717: p.failed += 1; + 718: p.status = "idle".into(); + 719: p.message = e; + 720: p.current = String::new(); + 721: }); + 722: } + 723: } + 724: } + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 40 + +MASTER 238 / 292 + R1 / SOURCE REVIEW + + + + +Earlier v6/proving source excerpts +Paths below are relative to each archive's top-level directory. Line numbering is from the supplied text, +not web pagination. Excerpts preserve the source; historical comments may not equal the current +implementation. Unquoted context should be inspected before patching. + +F01 / predicate + +igneum-v6-freeze-tree/igneum-pow/src/accept.rs:485-558 + + + 485: /// Whether `class` is the class v4 shape (the 256-instruction shadow block over the + class v3 base, the pass count and + 486: /// the era set aside): the shape the sub-version 2 rules (a') and (c') apply to, on + every draw path. + 487: pub fn is_class_v4_shape(class: &LoadClass) -> bool { + 488: matches!(class.shadow, Some(ShadowClass { instrs: V4_SHADOW_INSTRS, .. })) + 489: // class v5 (docs/design/class-v5-stored-state.md) is judged under the same + rules: its state flag is set aside; + 490: // class v6 lane 1's index fold and re-weight table are set aside too (the + address path and the op table are + 491: // not the shape) + 492: && LoadClass { era: None, shadow: None, state: false, fold: false, rw: 0, + ..*class } == LoadClass { shadow: None, ..V4_CLASS } + 493: } + 494: + 495: /// One pass of the dataflow freshness over the base program then the shadow block (the + order of one iteration), + 496: /// from `fresh`; `check` reports the first load that reads a register that is not + fresh. The rule (AP-F8-1, + 497: /// `docs/analysis/ca3-v4-uniform.md`): a load leaves its destination fresh only if its + source was (a saturated + 498: /// source reads one fixed word); add, sub, xor, mad and shfl if either operand was; + rotl and rotr if the operand + 499: /// was (a rotate maps all-ones and zero to themselves); or, mul and mulhi never. + 500: fn freshness_pass(p: &Program, fresh: &mut [bool; 8], pair_op: &mut [Option<(Op, + usize)>; 8], check: bool) -> Result<(), Reject> { + 501: for (k, i) in p.instrs.iter().chain(p.shadow.iter()).enumerate() { + 502: let (d, a) = (i.dst as usize, i.src as usize); + 503: if check && i.op.is_load() && !fresh[a] { + 504: return Err(Reject::UnfreshLoadSource { instr: k as u8, reg: i.src }); + 505: } + 506: // the shared-operand idiom (sub-version 3): or-then-xor or or-then-sub on one + operand is `d & ~s`, xor-then-or + 507: // is `d | s`: lossy, though the second op would inject on its own (F8's p23: + `or r6 |= r4; xor r6 ^= r4`) + 508: let masked = matches!((pair_op[d], i.op), (Some((Op::Or, s)), Op::Xor) | + (Some((Op::Or, s)), Op::Sub) | (Some((Op::Xor, s)), Op::Or) if s == a); + 509: fresh[d] = !masked + 510: && match i.op { + 511: Op::Load | Op::WLoad | Op::Scratch | Op::Hot => fresh[a], + 512: Op::Add | Op::Sub | Op::Xor | Op::Mad | Op::Shfl => fresh[d] || + fresh[a], + 513: Op::Rotl | Op::Rotr => fresh[d], + 514: Op::Or | Op::Mul | Op::MulHi => false, + 515: }; + 516: pair_op[d] = if matches!(i.op, Op::Or | Op::Xor) && !masked { Some((i.op, a)) } + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 41 + +MASTER 239 / 292 + R1 / SOURCE REVIEW + + + + + else { None }; + 517: for r in 0..8 { + 518: if r != d { + 519: if let Some((_, s)) = pair_op[r] { + 520: if s == d { + 521: pair_op[r] = None; + 522: } + 523: } + 524: } + 525: } + 526: } + 527: Ok(()) + 528: } + 529: + 530: /// Part (a'), class v4 sub-version 2: every load's source is fresh by dataflow in the + loop's steady state. The draw + 531: /// of `candidate_from_words_class` keeps in-pass sources fresh; this closes the + iteration boundary (a source last + 532: /// written late in the previous iteration or in the shadow block, which the draw's + no-eligible fallback can pick: + 533: /// F8's p11, an `or` at 63 feeding a load at 1). The state starts all fresh (the init + words are a per-lane hash of + 534: /// the nonce) and is run to its fixpoint (it only ever falls, so at most 8 passes + change it), then one checking pass. + 535: pub fn check_fresh_sources_v4(p: &Program) -> Result<(), Reject> { + 536: if !is_class_v4_shape(&p.class) { + 537: return Ok(()); + 538: } + 539: let mut fresh = [true; 8]; + 540: let mut pair_op: [Option<(Op, usize)>; 8] = [None; 8]; + 541: for _ in 0..9 { + 542: let before = (fresh, pair_op); + 543: freshness_pass(p, &mut fresh, &mut pair_op, false)?; + 544: if (fresh, pair_op) == before { + 545: break; + 546: } + 547: } + 548: freshness_pass(p, &mut fresh, &mut pair_op, true) + 549: } + 550: + 551: /// Parts (a), (b) and, for class v4 sub-version 2, (a'). + 552: pub fn check_static(p: &Program) -> Result<(), Reject> { + 553: if p.instrs.len() != INSTR_COUNT { + 554: panic!("acceptance needs a {INSTR_COUNT}-instruction program"); + 555: } + 556: check_stale_loads(&p.instrs)?; + 557: check_injecting_writes(&p.instrs)?; + 558: check_fresh_sources_v4(p) + + + +F01 / gated dynamic checks + +igneum-v6-freeze-tree/igneum-pow/src/accept.rs:808-871 + + + 808: pub fn check_dynamic(p: &Program) -> Result { + 809: let loads = p.loads_per_hash(); + 810: let v4 = is_class_v4_shape(&p.class); + 811: let sites = loads / ITERATIONS; + 812: let mut acc = Acc { + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 42 + +MASTER 240 / 292 + R1 / SOURCE REVIEW + + + + + 813: sources: None, + 814: indices: None, + 815: sat_source: vec![0; sites], + 816: and_acc: [u32::MAX; 8], + 817: or_acc: [0; 8], + 818: saturated: 0, + 819: bit_ones: [0; 64], + 820: distinct_sum: 0, + 821: }; + 822: let mut lane_addrs = vec![0u32; LANES * loads]; + 823: for (unit, &base) in accept_base_nonces(&p.seed).iter().enumerate() { + 824: run_unit(p, unit, base, &mut acc, &mut lane_addrs)?; + 825: } + 826: for reg in 0..8 { + 827: let bits = (acc.and_acc[reg] | !acc.or_acc[reg]).count_ones(); + 828: if bits != 0 { + 829: return Err(Reject::ConstantBit { reg: reg as u8, bits: bits as u8 }); + 830: } + 831: } + 832: if acc.saturated >= MAX_SATURATED { + 833: return Err(Reject::Saturated { count: acc.saturated }); + 834: } + 835: // (c'), class v4 sub-version 2 (AP-F8-1, 7 October 2026): a load whose source is + saturated reads one fixed word, + 836: // whatever delivered the saturation (an or-written value, a rotate of one, a load + after a saturated load); the + 837: // source rule of the draw removes the writers it can see and this count catches + every delivery. Keyed on the + 838: // class v4 shape as the draw's rule is, so v2 and v3 verdicts do not move. + 839: if v4 { + 840: if let Some((site, &count)) = acc.sat_source.iter().enumerate().find(|(_, &c)| + c >= MAX_SATURATED) { + 841: return Err(Reject::SaturatedSource { site: site as u8, count }); + 842: } + 843: // (c''), the ratio on the candidate that passed everything else (the draw's + last and dearest test); class v5 + 844: // reads (c''') the hot-item rule on the same run + (`docs/design/class-v5-stored-state.md` section 14), keyed + 845: // on the state flag so no class v4 verdict moves + 846: if p.class.state { + 847: check_indices_v5(p)?; + 848: } else { + 849: check_distinct_indices_v4(p)?; + 850: } + 851: } + 852: let half = (ACCEPT_HASHES / 2) as u32; + 853: let mut bias_max = 0u32; + 854: for (bit, &ones) in acc.bit_ones.iter().enumerate() { + 855: let d = ones.abs_diff(half); + 856: if d > BIAS_TOLERANCE { + 857: return Err(Reject::OutputBias { bit: bit as u8, ones }); + 858: } + 859: bias_max = bias_max.max(d); + 860: } + 861: if acc.distinct_sum <= min_distinct_sum(loads - p.scratch_ops_per_hash()) { + 862: return Err(Reject::DistinctAddresses { sum: acc.distinct_sum }); + 863: } + 864: Ok(AcceptReport { distinct_sum: acc.distinct_sum, saturated: acc.saturated, + bias_max }) + 865: } + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 43 + +MASTER 241 / 292 + R1 / SOURCE REVIEW + + + + + 866: + 867: /// The whole rule: (a), (b), then (c). + 868: pub fn check(p: &Program) -> Result { + 869: check_static(p)?; + 870: check_dynamic(p) + 871: } + + + +F01 / generation and exhaustion + +igneum-v6-freeze-tree/igneum-pow/src/generator.rs:1640-1657 + + + 1640: // Class v4's load-source rule (AP-F8-1, 7 October 2026, + `docs/analysis/ca3-v4-uniform.md`; sub-version 2): + 1641: // a load's source is drawn only from registers that are FRESH by dataflow. Fresh + at the program start (the init + 1642: // words are a per-lane hash of the nonce); after an op, the destination is fresh + when: a load's source was fresh + 1643: // (a saturated source reads one fixed word and leaves a constant); add, sub, xor, + mad or shfl had a fresh operand + 1644: // (dst or src); rotl or rotr rotated a fresh value (a rotate maps all-ones to + all-ones); never after or, mul or + 1645: // mulhi (an or-written value is all-ones with probability (3/4)^32 per read, the + 153x item of the finding; mul + 1646: // zeroes low bits; mulhi is dense near zero). Sub-version 1 looked one writer + back and counted every load and + 1647: // rotate as fresh, which let an or-saturated value through a rotate or a + load-after-load chain (F8's p6, p31). + 1648: // Keyed on the class v4 shape (the 256-instruction shadow block over the class v3 + base, the pass count and the + 1649: // era set aside) on EVERY draw path, era or not, so a census through + candidate_class reads the same stream as + 1650: // the chain; v2, v3 and every other class take no part. The draw order and the + stream are otherwise the same. + 1651: // class v5 (docs/design/class-v5-stored-state.md) draws under the same rule: its + state flag is set aside here too + 1652: // class v6 lane 1: the index fold and the re-weight table are set aside too (the + address path and the table are not + 1653: // the shape; a +fold or +rw program draws its sources under the same rule) + 1654: let source_rule_v4 = matches!(class.shadow, Some(ShadowClass { instrs: + V4_SHADOW_INSTRS, .. })) + 1655: && LoadClass { era: None, shadow: None, state: false, fold: false, rw: 0, + ..class } == LoadClass { shadow: None, ..V4_CLASS }; + 1656: // the op table and the roll's range: the plain table at 75 for every class + without the re-weight flag + 1657: let (weights, weights_sum) = class.nonload_weights(); + + + +F01 / attempt policy + +igneum-v6-freeze-tree/igneum-pow/src/generator.rs:54-68 + + + 54: /// Attempts before an implementation may treat the seed as a consensus fault (spec 01 + section 1.4.6). At the + 55: /// measured 5.14 percent rejection rate the chance of 32 consecutive rejections is + below 2^-136. + 56: pub const MAX_ATTEMPTS: u32 = 32; + 57: + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 44 + +MASTER 242 / 292 + R1 / SOURCE REVIEW + + + + + 58: /// The attempt cap of class v4 sub-version 2 (AP-F8-2, 7 October 2026): rules (a') and + (c') reject about two thirds of + 59: /// candidates, so 32 attempts exhaust with probability about (2/3)^32, 2e-6 per epoch + seed, one epoch no node could + 60: /// draw every few decades at one epoch an hour (seen at chain-shaped seed + igneum-f9/331672). At 256 attempts the + 61: /// exhaustion probability is (2/3)^256, under 1e-45; the cost of a rejected attempt is + one draw and the 64-unit check, + 62: /// about 2 ms on one core, so the worst case is half a second. Keyed on the class v4 + shape, so v2 and v3 keep 32. + 63: pub const MAX_ATTEMPTS_V4: u32 = 256; + 64: + 65: /// The attempt cap of a class: [`MAX_ATTEMPTS_V4`] for the class v4 shape, + [`MAX_ATTEMPTS`] otherwise. + 66: pub fn max_attempts_for(class: &LoadClass) -> u32 { + 67: if crate::accept::is_class_v4_shape(class) { MAX_ATTEMPTS_V4 } else { MAX_ATTEMPTS } + 68: } + + + +F01 / fallback branch + +igneum-v6-freeze-tree/igneum-pow/src/generator.rs:1848-1876 + + + 1848: /// This is what the chain calls (`Epoch::from_seed_bytes`) with the 32-byte epoch + seed, and what the packs call + 1849: /// with the UTF-8 of a seed string. + 1850: pub fn try_generate_from_seed_bytes(seed_string: &str, seed_bytes: &[u8]) -> + Result { + 1851: try_generate_class(seed_string, seed_bytes, LoadClass::V2) + 1852: } + 1853: + 1854: /// [`try_generate_from_seed_bytes`] for a load class. + 1855: pub fn try_generate_class(seed_string: &str, seed_bytes: &[u8], class: LoadClass) -> + Result { + 1856: let mut last = None; + 1857: let cap = max_attempts_for(&class); + 1858: for attempt in 0..cap { + 1859: let p = candidate_class(seed_string, seed_bytes, attempt, class); + 1860: match check(&p) { + 1861: Ok(_) => return Ok(p), + 1862: Err(r) => last = Some(r), + 1863: } + 1864: } + 1865: if crate::accept::is_class_v4_shape(&class) { + 1866: // AP-F8-2 (7 October 2026, main's ruling: the draw is total and no consensus + path panics): a class v4 seed that + 1867: // exhausts its attempts takes the last-resort program, deterministic. + Sub-version 3's is accepted as drawn + 1868: // (unreachable at 4.6e-44 per epoch and unverified against the rule: + adv-accept-3's finding, 223 of 2,500 + 1869: // rewritten candidates fail it, 209 by part (a)); class v5's is the verified + one. + 1870: if class.state { + 1871: return Ok(last_resort_v5(seed_string, seed_bytes, cap, class)); + 1872: } + 1873: return Ok(last_resort_v4(candidate_class(seed_string, seed_bytes, cap, + class))); + 1874: } + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 45 + +MASTER 243 / 292 + R1 / SOURCE REVIEW + + + + + 1875: Err(Exhausted { seed_string: seed_string.to_string(), attempts: cap, last: + last.unwrap() }) + 1876: } + + + +F01 / separate census harness + +igneum-v6-freeze-tree/docs/analysis/class-v6/census-packs.md:7-22 + + + 7: | Pack | Program id (reproduced from the pack's seeds before any row) | Crate | Harness + (branch, commit) | (A) the rule with (c''') on the pack's program | (B) attempts census, 256 + chain-shaped seeds under the pack's era and state | (C) F8 on the live state-keyed dataset + | Verdict | + 8: |---|---|---|---|---|---|---|---| + 9: | hl-v6-fold (the index fold alone, W = 4, base mix) | 482dc0dad937135b, attempt 1 | + class-v6-fold 7880bc96 | class-v6-census-fold 5b3486f0 | accepted; min site ratio 0.99986; + bucket +5.25 sigma; worst free bit 2.84 sigma; no site over 6 sigma (class v5's own program + on the same state: -448 sigma at one site) | 256 of 256, 0 exhausted, r 0.701, mean attempt + 2.34, max 14, (c''') 0.35 percent | 16 seeds p18 to p33 at 2^22: 16 PASS, at most 1.0455x of + the window model (the class v5 control on the same seeds: 5 of 16 flagged on the 6-sigma + bucket); the known-failed set at 2^24: p4 1.0057x (from 1.2163x), p8 1.1663x (+6.6 sigma + bucket; from 1.3787x), p10 1.1868x (from 1.5052x), p15 PASS, p212 1.0411x (+27 sigma; from + 1.1917x), p225 1.2414x BEYOND (from 1.2457x: the value-level class, unmoved), p34 1.0486x + with a +11.9 sigma bucket (from +5.06: the one regression) | **PASS** | + 10: | hl-v6-rw (the k lane's table rw1: 16,14,4,12,4,11,10,2,10,0 in draw order, sum 83, + `or` never drawn) | 30628f8adcf6035e, attempt 0 | class-v6-fold 7880bc96 | the same | + accepted; min ratio 0.99990; bucket +5.5; worst bit 2.89; no site over 6 sigma | 256 of 256, + 0 exhausted, r 0.117, mean attempt 0.13, max 2, (c''') 0.34 percent | 16 seeds: ratio at + most 1.1526x (within), 4 of 16 flagged on the 6-sigma bucket (the control's own rate is 5 of + 16); known-failed under this table's draw: p4, p34, p225 PASS, p8 +22 sigma, p10 +14, p15 + +8.8, p212 +37 sigma buckets at ratios 1.00 to 1.15x | **PASS** | + 11: | hl-v6-foldrw (fold and rw1) | 605d06cabc489f94, attempt 0 | class-v6-fold 7880bc96 | + the same | accepted; min ratio 0.99993; bucket +5.75; worst bit 3.49; no site over 6 sigma | + 256 of 256, 0 exhausted, r 0.117, mean 0.13, max 2, (c''') 0.34 percent | 16 seeds: 15 + PASS, 1 flagged (p18), at most 1.0932x; known-failed: every ratio within (p4 1.0002x, p8 + 1.0138x, p10 1.0100x, p15 1.0088x, p34 1.0121x, p212 1.1111x, p225 1.0000x), buckets flagged + on p15 (+9.3) and p212 (+24.5) | **PASS** | + 12: | hl-v6-rw2 (the census lane's table 13,11,6,10,8,8,7,2,6,4, sum 75) | 09e91b0dcd458c77, + attempt 1 | class-v6-fold 7880bc96 | the same | accepted; min ratio 0.99990; two sites with + the stride bit at -64 sigma (no fold) | 256 of 256, 0 exhausted, r 0.410, mean 0.70, max 8, + (c''') 1.15 percent | 16 seeds: seed p30 1.3111x over the window model (the control + 1.0004x; hl-v6-rw's worst 1.1526x), BEYOND the 1.2x gate; known-failed under its draw: p8 + 1.2507x (+42.8), p10 1.5044x (+100.9), p225 1.4049x beyond, p34 +70.7 and p15 +13.2 sigma + buckets, p4 and p212 PASS | **FAIL** on the F8 line | + 13: | hl-v6-win (the 64-register full-chain window alone, `+reg64c`) | f42d4a743ce7d4fa, + attempt 0 (the v5-dn3-epoch0 seeds and state) | reg64-v5 198d171d | class-v6-census-reg64 + b29e690d2 | accepted (with the liveness probe); min ratio 0.99923; bucket +5.5; the base + program's stride-bit site at -448 sigma (no fold) | 256 of 256, 0 exhausted, r 0.716, mean + 2.52, max 15, (c''') 1.66 percent (the window does not enter the draw: class v5's rows) | + the window's own address stream through the interpreter's tracing probe, 32 sites of the + interleaved schedule, 16 seeds at 2^22, the era laid over, closed form: per-site distinct + ratio 1.0026 to 1.0027 on every site (the (c'') form; the control 0.9946 to 1.0027); the + item histogram's top-0.1-percent share 1.0645 to 1.5624x of a flat control against the + control's 1.0738 to 1.5074x, paired by seed 0.968 to 1.036x of the control. The attack-f8 + mirror and the known-failed set do not apply (eight registers) | **PASS** (the live-dataset + point owed) | + 14: | hl-v6-all (window, fold and rw1) | 9d40978601a7df2a, attempt 0 | class-v6 3f25a8305 + (the texts at c245d50b9, the verifier unchanged) | class-v6-census-all 2d54a4633 | accepted; + min ratio 0.99993; bucket +5.75; worst bit 3.49; no site over 6 sigma | 256 of 256, 0 + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 46 + +MASTER 244 / 292 + R1 / SOURCE REVIEW + + + + + exhausted, r 0.117, mean 0.13, max 2, (c''') 0.34 percent | the trace on 32 sites: per-site + distinct ratio 1.0026 to 1.0027; item share 1.0443 to 1.5132x flat against the foldrw + control's 1.0398 to 1.4616x, paired 1.004 to 1.035x | **PASS** (the live-dataset point owed) + | + 15: + 16: The controls: the freeze's class v5 pack v5-dn3-epoch0 (e5a4ac5978462156) through the + whole harness at 15:53 UK (the dry run: the known-failed set reproduces the record to three + places, p4 1.2163x, p8 1.3787x, p10 1.5052x, p212 1.1917x, p225 1.2457x) and class v5 on the + node1 state over the same 16 seeds at 2^22 (16 of 16 within 1.2x, worst 1.0698x; 5 of 16 + flagged on the 6-sigma windowed bucket: the statistic's own rate on the family at 2^22, so a + pack's 4 or 5 flags is the control's and a pack's 0 of 16 is a gain). + 17: + 18: What the sheet means. The index fold does what it was drawn for: the stride-bit bias is + gone from every program it ships, the F8 tails of 1.22 to 1.50x come inside the gate (1.01 + to 1.19x) and the bucket concentration at narrow-window sites falls from the control's 5 of + 16 seeds to 0 of 16; p225's value-level class is untouched and p34 gains one bucket + statistic. The k lane's table (rw1, `or` never drawn, `mul` at 4) reads clean and gives the + lowest rejection rate measured on the family (0.117); the census lane's table (rw2, `or` 4, + `mul` 6) keeps the lossy writers the tails come from and fails the F8 line, so the re-weight + is sound in the rw1 form only. The window changes nothing the rule or the F8 form sees at + 2^22 on the closed form and carries the fold's and the table's rows unchanged; its value is + the chip-side cost the adversary lane prices. + 19: + 20: ## 1. The harness + 21: + 22: The class v5 crate of each pack's branch plus lane D's family-gate harness diff + (`docs/analysis/class-v6/logs/harness-family-gate-v5-3dc3117c.diff`: `IGNEUM_FAMILY_GATE` + widens the class v4 rules to the family's shapes, with every new class flag set aside in + `is_family_shape`: state, fold, rw, wide8, reg64, reg64_chain), plus: a `sitestats` command + (the whole rule with (c'''), then per site over 2^20 evaluations the distinct ratio against + the window model, the largest 256-item bucket in sigma, the largest index-bit excess in + sigma over the free bits); the `accept` walk at the class's own cap under the flag; the + attack-pass lane's `attack-f8` with `--load-class ` (the program drawn from a class + string with the spec's era laid over it) and `--dataset-words N` (the ds55 geometry through + `load_index_geom`; not exercised: a state class refuses the non-power-of-two count); the + uniform trace tool `tools/attack/v6-census/uniform` on `verify::Probe { trace_loads }` + (every load's index per lane through the interpreter itself). Binaries pinned per crate + under `/srv/builds/v6-census/bin//` with sha256: fold-5b3486f0 (igneum-pow 50903d30, + attack-f8 9ba2210b), reg64-1b676975 (v6census-uniform b2214265 after the fixes), + all-d7d441be (igneum-pow 5a221e56, v6census-uniform 2ebd92c1). + + + +F02 / base acceptance execution + +igneum-v6-freeze-tree/igneum-pow/src/accept.rs:601-634 + + + 601: /// One unit of the dynamic test: the interpreter of `verify.rs` with the closed-form + dataset, instrumented. + 602: /// Returns the first lane-constant load site, if any. + 603: fn run_unit(p: &Program, unit: usize, base: u32, acc: &mut Acc, lane_addrs: &mut [u32]) + -> Result<(), Reject> { + 604: let seed = &p.seed; + 605: let mask: u32 = (1u32 << ACCEPT_DATASET_LOG2) - 1; + 606: let (d0, d1) = (seed[0], seed[1]); + 607: let (h0, h1) = (seed[2], seed[3]); + 608: let hot_words = p.hot_words(); + 609: let loads = p.loads_per_hash(); + 610: let mut r = [[0u32; LANES]; 8]; + 611: for lane in 0..LANES { + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 47 + +MASTER 245 / 292 + R1 / SOURCE REVIEW + + + + + 612: let nonce = base.wrapping_add(lane as u32); + 613: for i in 0..8 { + 614: let mut x = nonce ^ seed[i]; + 615: x = x.wrapping_add(0x9e3779b9u32.wrapping_mul(i as u32 + 1)); + 616: x = splitmix32(x); + 617: r[i][lane] = x ^ seed[(i + 1) & 7]; + 618: } + 619: } + 620: let mut idx = [0u32; LANES]; + 621: let mut nload = 0usize; + 622: let mut scratch = if p.has_scratch() { + Some(ScratchModel::new(p.class.scratch_slots_per_lane())) } else { None }; + 623: let slot_mask = p.class.scratch_slot_mask(); + 624: let era = p.class.era; + 625: // Class v4 sub-version 3 (AP-F8-3, 7 October 2026): the acceptance interpreter + runs the latency-shadow block + 626: // after instruction 63 of every iteration, `reps` times with the iteration's + `sel`, exactly as the hash does + 627: // (verify.rs). Until this commit it ran the 64 base instructions only, so every + dynamic test (c) judged a class v4 + 628: // program the chain never hashes. The shadow block holds no load, so its + instructions take the same arms. + 629: let shadow_reps = p.shadow_reps(); + 630: for it in 0..ITERATIONS { + 631: let sel = r[0]; + 632: let shadow_pass = (0..shadow_reps).flat_map(|_| + p.shadow.iter().enumerate().map(|(k, i)| (INSTR_COUNT + k, i))); + 633: for (k, ins) in p.instrs.iter().enumerate().chain(shadow_pass) { + 634: let d = ins.dst as usize; + + + +F02 / actual schedule and counters + +igneum-v6-freeze-tree/igneum-pow/src/generator.rs:1153-1209 + + + 1153: /// The reg64 full-chain fold in the program id: 1 = the load's own source out of the + rotate-xor chain. + 1154: pub const REG64_CHAIN_FOLD: u8 = 1; + 1155: + 1156: impl Program { + 1157: /// Registers per lane (8, or 64 under `class.reg64`). + 1158: pub fn registers(&self) -> usize { + 1159: if self.class.reg64 { REG64_REGISTERS } else { 8 } + 1160: } + 1161: /// Whether every load's address consumes all 64 registers (the reg64 full-chain + variant). + 1162: pub fn address_mix(&self) -> bool { + 1163: self.class.reg64 && self.class.reg64_chain + 1164: } + 1165: /// The pack's liveness statement (the reg64 variants): which reads keep every + register necessary. + 1166: pub fn reg64_liveness(&self) -> String { + 1167: if !self.class.reg64 { + 1168: return String::new(); + 1169: } + 1170: let loads = self.scheduled().iter().filter(|i| i.op == Op::Load).count(); + 1171: if self.address_mix() { + 1172: format!("every one of the 64 registers is read by the address of each of + the {loads} loads per iteration (the load's source directly, the 63 others through the + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 48 + +MASTER 246 / 292 + R1 / SOURCE REVIEW + + + + + rotate-xor chain) and by the end fold; 64 independently necessary values for the length of + the dependent chain; xoring any register with either of two seed-derived probe words at the + start of an iteration moves the first load address and the final hash") + 1173: } else { + 1174: "every one of the 64 registers is read by the end fold (r[k] ^= r[k + 8] ^ + ... ^ r[k + 56]); a load's address reads its own window's register only, so the chain needs + 8 live values at a time and the other 56 are live across it as state (window, + arithmetic-only)".to_string() + 1175: } + 1176: } + 1177: /// The instructions one iteration executes, in order, with their register fields + as the kernels name them. + 1178: /// Without the reg64 flag this is the drawn program as it stands. Under the flag, + instruction i of the drawn + 1179: /// program runs on window 0 with every register field widened by `8 * (i % 4)` + (so the 64 instructions touch all + 1180: /// 32 registers of the window), then the same instruction runs on window 1 (the + widened field + 32): 128 + 1181: /// statements per iteration over registers 0..63. The CPU verifier and every + emitter read this list, so the + 1182: /// vectors and the kernel text agree by construction. + 1183: pub fn scheduled(&self) -> Vec { + 1184: if !self.class.reg64 { + 1185: return self.instrs.clone(); + 1186: } + 1187: let mut out = Vec::with_capacity(self.instrs.len() * 2); + 1188: for (i, ins) in self.instrs.iter().enumerate() { + 1189: let off = (8 * (i % 4)) as u8; + 1190: let a = Instr { dst: ins.dst + off, src: ins.src + off, src2: ins.src2 + + off, ..*ins }; + 1191: let b = Instr { dst: a.dst + 32, src: a.src + 32, src2: a.src2 + 32, ..a + }; + 1192: out.push(a); + 1193: out.push(b); + 1194: } + 1195: out + 1196: } + 1197: pub fn loads_per_hash(&self) -> usize { + 1198: self.instrs.iter().filter(|i| i.op.is_load()).count() * ITERATIONS + 1199: } + 1200: pub fn wide_loads_per_hash(&self) -> usize { + 1201: self.instrs.iter().filter(|i| i.op == Op::WLoad).count() * ITERATIONS + 1202: } + 1203: pub fn has_wide(&self) -> bool { + 1204: self.instrs.iter().any(|i| i.op == Op::WLoad) + 1205: } + 1206: /// Dataset bytes read per hash: 4 per one-word load, 16 and 64 for the wider + loads of the experiment. + 1207: pub fn bytes_per_hash(&self) -> usize { + 1208: self.instrs.iter().filter(|i| i.op == Op::Load).map(|i| i.width as usize * + 4).sum::() * ITERATIONS + 1209: } + + + +F02 / live-dataset work owed + +igneum-v6-freeze-tree/docs/analysis/class-v6/census-packs.md:40-49 + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 49 + +MASTER 247 / 292 + R1 / SOURCE REVIEW + + + + + 40: ## 4. Faults found and fixed on the way (the record, so no one repeats them) + 41: + 42: - The uniform tool's distinct sets as HashSet took 16 GB a thread at 2^22 nonces and + were killed by the lease's memory cap; bit vectors over the dataset's words now. + 43: - The reg64 interleaved schedule runs 32 load rows per iteration (instruction k on + window 0 then window 1); the first read mapped them onto 16 sites (doubling N, ratios 1.35 + to 1.80), the second mapped site s to load s mod 16 (the wrong window's expectation, ratios + 0.84); site s is load instruction s / 2. + 44: - The all pack's attack-f8 chain died at start on the fold-base tool (`+reg64c` + unparsed); the class-v6 tool parses it but its mirror interprets eight registers, so the + mirror is not the window's instrument. + 45: - The lease pool is a race, not a queue; `env VAR="a b"` through it splits on spaces. + 46: + 47: ## 5. Owed + 48: + 49: The live-dataset F8 point at 2^24 for the two window packs (the mirror would need the + two-window interpreter: four to six hours); the 64 x 2^24 point per pack (45 to 100 + core-hours each); hl-v6-rw's files (on build-3, unreachable); the exact `or = 0` attempts + rows are lane D's. + + + +F03 / full chain definition + +igneum-v6-freeze-tree/igneum-pow/src/verify.rs:674-691 + + + 674: // reg64 full chain: a load's address source is src ^ m, m the rotate-xor chain + over the 63 other registers in + 675: // index order (m = first; m = rotl(m, 1) ^ next). The source itself stays out of + the chain: with it inside, a + 676: // register whose term lands at rotation 0 mod 32 (r31, r63) cancels its own direct + term, a dead register the + 677: // liveness rule found on the pinned draw (first load src r31, 8 October 2026, + 15:5x UK). + 678: let addr_src = |r: &[[u32; LANES]], lane: usize| -> u32 { + 679: if !address_mix { + 680: return r[a][lane]; + 681: } + 682: let mut m = 0u32; + 683: let mut started = false; + 684: for k in 0..r.len() { + 685: if k == a { + 686: continue; + 687: } + 688: m = if started { m.rotate_left(1) ^ r[k][lane] } else { r[k][lane] }; + 689: started = true; + 690: } + 691: r[a][lane] ^ m + + + +F04 / choice and confirmation + +igneum-ember/app/igneum-app/src/ember.rs:549-619 + + + 549: /// The choice: among the usable rows within `tolerance_pct` of the fastest row's rate, + the best MH per watt; within + 550: /// 1% on efficiency the higher rate wins; within 1% on both, the lower draw. A card + never gives up more than the + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 50 + +MASTER 248 / 292 + R1 / SOURCE REVIEW + + + + + 551: /// tolerance in blocks for the saving. Marked rows never win. + 552: pub fn choose(rows: &[Row], tolerance_pct: f64) -> Option { + 553: let top = rows.iter().filter(|r| r.usable()).map(|r| r.mhs).fold(0.0, f64::max); + 554: if top <= 0.0 { + 555: return None; + 556: } + 557: let floor = top * (1.0 - tolerance_pct.max(0.0) / 100.0); + 558: let mut best: Option<&Row> = None; + 559: for r in rows.iter().filter(|r| r.usable() && r.mhs >= floor) { + 560: best = Some(match best { + 561: None => r, + 562: Some(b) => { + 563: let eff_tie = (r.eff - b.eff).abs() <= 0.01 * b.eff.max(r.eff); + 564: if !eff_tie { + 565: if r.eff > b.eff { r } else { b } + 566: } else { + 567: let mhs_tie = (r.mhs - b.mhs).abs() <= 0.01 * b.mhs.max(r.mhs); + 568: if !mhs_tie { + 569: if r.mhs > b.mhs { r } else { b } + 570: } else if r.watts < b.watts { + 571: r + 572: } else { + 573: b + 574: } + 575: } + 576: } + 577: }); + 578: } + 579: best.cloned() + 580: } + 581: + 582: /// A confirm check's verdict: the prior stands, or the neighbour beat it by over + CONFIRM_GAIN_PCT (the full plan is + 583: /// due), or nothing could be read. + 584: #[derive(Clone, Debug, PartialEq)] + 585: pub enum Verdict { + 586: Keep(Row), + 587: FullDue { prior: Row, better: Row }, + 588: NoReadings, + 589: } + 590: + 591: pub fn confirm_verdict(rows: &[Row], tolerance_pct: f64) -> Verdict { + 592: let Some(prior) = rows.first().filter(|r| r.usable()).cloned() else { + 593: return match choose(rows, tolerance_pct) { + 594: Some(r) => Verdict::FullDue { prior: Row::default(), better: r }, + 595: None => Verdict::NoReadings, + 596: }; + 597: }; + 598: match choose(rows, tolerance_pct) { + 599: Some(best) if best.point != prior.point && best.eff > prior.eff * (1.0 + + CONFIRM_GAIN_PCT / 100.0) => Verdict::FullDue { prior, better: best }, + 600: _ => Verdict::Keep(prior), + 601: } + 602: } + 603: + 604: // ---- the fleet prior + ------------------------------------------------------------------------------------------ + 605: + 606: /// The key a prior is filed under: card model (spaces as underscores), driver major, + program class. + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 51 + +MASTER 249 / 292 + R1 / SOURCE REVIEW + + + + + 607: pub fn prior_key(card: &str, driver: &str, class: &str) -> String { + 608: format!("{}|{}|{}", card.trim().replace(' ', "_"), driver_major(driver), if + class.is_empty() { "v2" } else { class }) + 609: } + 610: + 611: /// "581.57" -> "581", "32.0.15801" -> "32", "" -> "0". + 612: pub fn driver_major(driver: &str) -> String { + 613: let d: String = driver.trim().chars().take_while(|c| c.is_ascii_digit()).collect(); + 614: if d.is_empty() { "0".into() } else { d } + 615: } + 616: + 617: /// The program class from a race line's features (loads and wide loads per hash); the + generator fixes both today. + 618: pub fn program_class(loads: u32, wide: u32) -> String { + 619: if loads == 0 { "v2".into() } else { format!("l{loads}w{wide}") } + + + +F04 / final confirmation behaviour + +igneum-ember/app/igneum-app/src/ember.rs:948-973 + + + 948: /// What the plan concludes: the full plan's choice; the confirm plan keeps its + prior unless the neighbour beat + 949: /// it (then the prior still holds the card and the engine schedules the full + plan); the baseline is itself. + 950: fn decide(&self) -> Option { + 951: match self.plan.kind { + 952: PlanKind::Baseline => self.rows.first().cloned().filter(|r| r.usable()), + 953: PlanKind::Confirm => match confirm_verdict(&self.rows, + self.plan.tolerance_pct) { + 954: Verdict::Keep(r) => Some(r), + 955: Verdict::FullDue { prior, .. } if prior.usable() => Some(prior), + 956: Verdict::FullDue { better, .. } => Some(better), + 957: Verdict::NoReadings => None, + 958: }, + 959: PlanKind::Full => choose(&self.rows, self.plan.tolerance_pct), + 960: PlanKind::Climb => { + 961: if self.plan.climb.as_ref().map(|c| c.goal) == Some(Goal::MaxRate) { + 962: self.rows.iter().filter(|r| r.usable()).max_by(|a, b| + a.mhs.partial_cmp(&b.mhs).unwrap_or(std::cmp::Ordering::Equal)).cloned() + 963: } else { + 964: choose(&self.rows, self.plan.tolerance_pct) + 965: } + 966: } + 967: } + 968: } + 969: + 970: /// After a confirm plan: did the neighbour beat the prior (the full plan is due)? + 971: pub fn full_due(&self) -> bool { + 972: self.plan.kind == PlanKind::Confirm && matches!(confirm_verdict(&self.rows, + self.plan.tolerance_pct), Verdict::FullDue { .. }) + 973: } + + + +F06 / helper candidates and task + +igneum-ember/app/igneum-app/src/powertask.rs:113-142 + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 52 + +MASTER 250 / 292 + R1 / SOURCE REVIEW + + + + + 113: /// Where the installed exe lives: the per-user install, then the old administrator + install. + 114: pub fn install_candidates() -> Vec { + 115: [ + 116: std::env::var_os("LOCALAPPDATA").map(|l| + PathBuf::from(l).join("Programs").join("Igneum Miner").join("igneum-app.exe")), + 117: std::env::var_os("ProgramFiles").map(|p| PathBuf::from(p).join("Igneum + Miner").join("igneum-app.exe")), + 118: ] + 119: .into_iter() + 120: .flatten() + 121: .collect() + 122: } + 123: + 124: /// The PowerShell that prints the task's action (what `reregister` is proven by). + 125: pub fn readback_command() -> String { + 126: format!("$t = Get-ScheduledTask -TaskName '{TASK_NAME}' -ErrorAction + SilentlyContinue; if ($t) {{ Write-Output ($t.Actions[0].Execute + ' ' + + $t.Actions[0].Arguments) }}; exit 0") + 127: } + 128: + 129: /// The PowerShell that registers the task (run inside the ONE elevated step, with the + caps). `exe` is this + 130: /// executable's path in the install folder. Principal: the signed-in user, interactive + logon, highest run level; no + 131: /// trigger; may start on battery; one hour limit per run; multiple starts are ignored + while one runs. + 132: pub fn register_script(exe: &Path) -> String { + 133: let exe = exe.display().to_string().replace('\'', "''"); + 134: format!( + 135: "$a = New-ScheduledTaskAction -Execute '{exe}' -Argument '--power-helper' + -WorkingDirectory '{dir}'\r\n\ + 136: $p = New-ScheduledTaskPrincipal -UserId + ([System.Security.Principal.WindowsIdentity]::GetCurrent().Name) -LogonType Interactive + -RunLevel Highest\r\n\ + 137: $s = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries + -DontStopIfGoingOnBatteries -ExecutionTimeLimit (New-TimeSpan -Hours 1) -MultipleInstances + IgnoreNew -Hidden\r\n\ + 138: Register-ScheduledTask -TaskName '{name}' -Action $a -Principal $p -Settings + $s -Force | Out-Null\r\n\ + 139: exit 0\r\n", + 140: dir = exe.rfind(['\\', '/']).map(|i| exe[..i].to_string()).unwrap_or_default(), + 141: name = TASK_NAME + 142: ) + + + +F06 / helper elevated path and exits + +igneum-ember/app/igneum-app/src/powertask.rs:184-267 + + + 184: /// The helper process (`igneum-app --power-helper`): polls `/cmd.txt` twice a + second, runs the parsed commands + 185: /// through nvidia-smi, logs what it ran to `/helper.log`, ends on `quit`, on + `remove` (after unregistering the + 186: /// task) or after 20 idle minutes. `dir` is `/app/sweep`. + 187: pub fn run_helper(dir: &Path) -> i32 { + 188: let _ = std::fs::create_dir_all(dir); + 189: let cmd_file = dir.join("cmd.txt"); + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 53 + +MASTER 251 / 292 + R1 / SOURCE REVIEW + + + + + 190: let log_file = dir.join("helper.log"); + 191: let log = |line: &str| { + 192: use std::io::Write; + 193: if let Ok(mut f) = + std::fs::OpenOptions::new().append(true).create(true).open(&log_file) { + 194: let _ = writeln!(f, "{} {line}", crate::platform::unix_now()); + 195: } + 196: }; + 197: log("helper started (scheduled task, elevated)"); + 198: // a stale file from an earlier run is not a command: only lines after the start + count + 199: let mut last_seq: u64 = std::fs::read_to_string(&cmd_file).ok().and_then(|t| + t.lines().filter_map(parse_line).map(|(s, _)| s).max()).unwrap_or(0); + 200: let mut last_text = String::new(); + 201: let mut dev = "0".to_string(); + 202: let mut idle = Instant::now(); + 203: let smi = crate::platform::tool("nvidia-smi"); + 204: loop { + 205: let text = std::fs::read_to_string(&cmd_file).unwrap_or_default(); + 206: if text != last_text { + 207: last_text = text.clone(); + 208: for (seq, c) in text.lines().filter_map(parse_line) { + 209: match c { + 210: HelperCmd::Quit => { + 211: log("quit"); + 212: return 0; + 213: } + 214: HelperCmd::Remove => { + 215: let mut p = + std::process::Command::new(crate::platform::tool("powershell")); + 216: p.args(["-NoProfile", "-ExecutionPolicy", "Bypass", "-Command", + &remove_command()]); + 217: crate::platform::quiet(&mut p); + 218: let ok = p.status().map(|s| s.success()).unwrap_or(false); + 219: log(&format!("remove: the task is {}", if ok { "unregistered" } + else { "still registered (Unregister-ScheduledTask failed)" })); + 220: return if ok { 0 } else { 1 }; + 221: } + 222: _ if seq <= last_seq => continue, + 223: HelperCmd::Reregister => { + 224: last_seq = seq; + 225: idle = Instant::now(); + 226: let Some(target) = install_candidates().into_iter().find(|p| + p.is_file()) else { + 227: log(&format!("{seq} reregister: no installed exe found")); + 228: continue; + 229: }; + 230: let script = dir.join("register-power-task.ps1"); + 231: let ok = std::fs::write(&script, [b"\xEF\xBB\xBF".as_slice(), + register_script(&target).as_bytes()].concat()).is_ok() && { + 232: let mut p = + std::process::Command::new(crate::platform::tool("powershell")); + 233: p.args(["-NoProfile", "-ExecutionPolicy", "Bypass", + "-File", &script.display().to_string()]); + 234: crate::platform::quiet(&mut p); + 235: p.status().map(|s| s.success()).unwrap_or(false) + 236: }; + 237: let mut q = + std::process::Command::new(crate::platform::tool("powershell")); + 238: q.args(["-NoProfile", "-ExecutionPolicy", "Bypass", "-Command", + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 54 + +MASTER 252 / 292 + R1 / SOURCE REVIEW + + + + + &readback_command()]); + 239: crate::platform::quiet(&mut q); + 240: let now = q.output().map(|o| + String::from_utf8_lossy(&o.stdout).trim().to_string()).unwrap_or_default(); + 241: log(&format!("{seq} reregister {}: the task now runs {now}", if + ok { "ok" } else { "failed" })); + 242: } + 243: HelperCmd::Dev(d) => { + 244: last_seq = seq; + 245: idle = Instant::now(); + 246: dev = d; + 247: log(&format!("{seq} dev {dev}")); + 248: } + 249: other => { + 250: last_seq = seq; + 251: idle = Instant::now(); + 252: let args = smi_args(&dev, &other).unwrap_or_default(); + 253: let mut p = std::process::Command::new(&smi); + 254: p.args(&args); + 255: crate::platform::quiet(&mut p); + 256: let out = p.output().map(|o| format!("{}{}", + String::from_utf8_lossy(&o.stdout), String::from_utf8_lossy(&o.stderr))).unwrap_or_else(|e| + e.to_string()); + 257: log(&format!("{seq} nvidia-smi {} : {}", args.join(" "), + out.replace('\n', " ").trim())); + 258: } + 259: } + 260: } + 261: } + 262: if idle.elapsed() >= Duration::from_secs(IDLE_S) { + 263: log("idle 20 min: exit (the engine starts the task again when it needs + it)"); + 264: return 0; + 265: } + 266: std::thread::sleep(Duration::from_millis(500)); + 267: } + + + +F07 / physical coexistence rows + +igneum-v6-freeze-tree/docs/analysis/class-v6/coexist-rows.md:75-86 + + + 75: ## The table + 76: + 77: | Card | Miner alone (ds55) | Proof alone (compressed 2^26) | Together | Register + windows (v5 kit worker) | + 78: |---|---|---|---|---| + 79: | RTX 3060 12 GB | 26.82 MH/s at 117.4 W, 6,129 MiB resident, fingerprint + 23ced07a4d28b465, PASS | 13.2 s, VERIFIED, peak 7,525 MiB, 122 W | 6,129 + 7,525 = 13,654 + MiB against 12,288: TIME-SHARING NEEDED. Live attempt: the card filled to 11,893 MiB and the + prover died in a device allocation (raw_buffer.rs:271) after 34 s; the miner held 26.51 + MH/s through it (1.2 percent under alone). Proof with the miner paused = the proof-alone row + | hl-reg64c 13.47 MH/s, 87 regs, 16 of 24 blocks per SM, fingerprint 4e7cc25967eba280 + MATCH, 120.8 W; hl-reg64 13.48 MH/s, 104 regs, 16 of 24, 70e786af1a457653 MATCH, 119.3 W | + 80: | RTX 4060 8 GB | 18.84 MH/s, 6,116 MiB resident, fingerprint 23ced07a4d28b465, PASS (no + watts: host sensor N/A) | 8.2 s, VERIFIED, peak 7,532 MiB | 6,116 + 7,532 = 13,648 MiB + against 8,188: TIME-SHARING NEEDED. Live attempt: the server died in a tensor allocation + (inner.rs:51) at 7,811 MiB after 5 s; the miner held 18.83 MH/s | hl-reg64c 9.51 MH/s, 87 + regs, 20 of 24 blocks per SM, fingerprint MATCH; hl-reg64 9.57 MH/s, 104 regs, 16 of 24, + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 55 + +MASTER 253 / 292 + R1 / SOURCE REVIEW + + + + + MATCH | + 81: + 82: Not measured and why: a core-only proof beside the miner (igneum-prove-host-0317 has no + `--mode core`: "Error: unknown mode core"; its modes are native, execute, shard, compressed, + block, all); watts on the 4060 (the host's power sensor reads N/A). + 83: + 84: ## Reconciliation with the served row + 85: + 86: The served sentence (litepaper, "Proving", from + `docs/analysis/prover-tiers-real-cards.md`, 6 October 2026) says an RTX 3060 (12 GB) "mines + at 23.78 MH/s and proves the v1 shard beside its miner at an 8.9 GB peak in 37.5 s". Today's + row on the same card tier reads a 7.5 GiB compressed peak that kills the prover beside a + 6.1 GiB miner. The two are not in conflict; they measured different things. The 6 October + row is the matrix's `miner-comp-26-v1` point (`tools/fleet/box-matrix.sh` section 7): the + patched server at threshold 2^26 in compressed mode, driven by the matrix host (the segment + host build at `/opt/igneum-segal/.../igneum-prove-host`, which also carries `--mode core`; + the matrix's core rows come from it), beside `igneum-miner mine` on the 1 GiB class v3 pack, + whose resident set was 1.4 GB: 1.4 + 7.5 = 8.9 GB, inside 12 GB, proof in 37.5 s with the + miner running. Today's row is igneum-prove-host-0317 in compressed mode at the same + threshold 2^26 (the same 7.5 GiB own footprint, 7,525 to 7,532 MiB peak alone), beside the + ds55 miner on the 5.5 GiB dataset of the genesis floor, whose resident set is 6.1 GB: 6.1 + + 7.5 = 13.6 GB, outside 12 GB and 8 GB alike, so the prover's allocation fails while the + miner keeps mining. What changed between the rows is the miner's dataset (1 GiB then, 5.5 + GiB now), not the prover. The rule that follows: at the 5.5 GiB floor a compressed shard + proof beside a running miner needs a 16 GB card (13.6 GB together; the 16 GB tier's own peak + is 18 GB on the stock sizes and 7.8 GB patched, so 16 GB holds both with about 2 GB spare); + 8 GB and 12 GB cards time-share, proving with the miner paused (13.2 s on the 3060, 8.2 s + on the 4060) and mining otherwise. The 6 October beside rows stand only for the 1 GiB + dataset; the 6 October core-only beside rows (5.6 GB own on the 3060, 27.2 s) stand only for + core mode on the segment host, which the 0317 host does not expose, and are not a + coexistence claim at the floor. The served sentence is read as a 1 GiB-dataset row until the + site lane rewrites it against this record. + + + +F07 / default memory profile patch + +igneum-proving/proving/prover-floor/sp1-gpu-6.8.1-floor.patch:111-190 + + + 111: +/// Igneum prover-floor patch (5 October 2026). Upstream sizes every device buffer for + a 24 GB card or larger + 112: +/// and panics below that, whatever the shard. Here the card's memory (or + `SP1_GPU_MEMORY_BUDGET_GB`) picks a + 113: +/// tier, and `SP1_GPU_ELEMENT_THRESHOLD` / `SP1_GPU_RECURSION_TRACE_ALLOCATION` set + the two buffers directly. + 114: +/// The proof format, the verifier and the program ids do not change: the element + threshold only decides where + 115: +/// the executor splits shards, as upstream's own 24 GB tier already does. + 116: +fn env_usize(name: &str) -> Option { + 117: + std::env::var(name).ok().and_then(|s| s.parse::().ok()) + 118: +} + 119: + + 120: +fn env_f64(name: &str) -> Option { + 121: + std::env::var(name).ok().and_then(|s| s.parse::().ok()) + 122: +} + 123: + + 124: +/// The core element threshold for a memory budget in GB (upstream's own figure for + the budget, +4, as it + 125: +/// computed it: a 32 GB card is 36, a 24 GB card 28, a 16 GB card 20, a 12 GB card + 16). + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 56 + +MASTER 254 / 292 + R1 / SOURCE REVIEW + + + + + 126: +pub fn element_threshold_for_budget(gpu_memory_gb: usize, full_size_shards: bool) -> + u64 { + 127: + if gpu_memory_gb > 30 || (full_size_shards && gpu_memory_gb >= 24) { + 128: + ELEMENT_THRESHOLD + 129: + } else if gpu_memory_gb >= 24 { + 130: + ELEMENT_THRESHOLD - (1 << 26) - (1 << 25) - (1 << 24) + 131: + } else if gpu_memory_gb >= 18 { + 132: + (1 << 27) + (1 << 26) + 133: + } else { + 134: + 1 << 27 + 135: + } + 136: +} + 137: + + 138: +/// The recursion trace allocation (elements) for a memory budget. + 139: +pub fn recursion_trace_allocation_for_budget(gpu_memory_gb: usize) -> usize { + 140: + if gpu_memory_gb >= 24 { + 141: + RECURSION_TRACE_ALLOCATION + 142: + } else { + 143: + RECURSION_TRACE_ALLOCATION + 144: + } + 145: +} + 146: + + 147: +pub fn gpu_memory_gb() -> usize { + 148: + let gb = 1024.0 * 1024.0 * 1024.0; + 149: + match env_f64("SP1_GPU_MEMORY_BUDGET_GB") { + 150: + Some(b) => (b.ceil() as usize) + 4, + 151: + None => (((cuda_memory_info().unwrap().1 as f64) / gb).ceil() as usize) + 4, + 152: + } + 153: +} + 154: + + 155: +pub fn recursion_trace_allocation() -> usize { + 156: + env_usize("SP1_GPU_RECURSION_TRACE_ALLOCATION") + 157: + .unwrap_or_else(|| recursion_trace_allocation_for_budget(gpu_memory_gb())) + 158: +} + 159: + + 160: pub fn local_gpu_opts() -> SP1CoreOpts { + 161: let mut opts = SP1CoreOpts::default(); + 162: + 163: let log2_shard_size = 24; + 164: opts.shard_size = 1 << log2_shard_size; + 165: + 166: - let gb = 1024.0 * 1024.0 * 1024.0; + 167: - + 168: - // Get the amount of memory on the GPU. + 169: - let gpu_memory_gb: usize = (((cuda_memory_info().unwrap().1 as f64) / gb).ceil() + as usize) + 4; + 170: - + 171: - if gpu_memory_gb < 24 { + 172: - panic!("Unsupported GPU memory: {gpu_memory_gb}, must be at least 24GB"); + 173: - } + 174: + // The card's memory plus 4, as upstream computed it (a 32 GB card reads 36), or + the budget given. + 175: + let gpu_memory_gb = gpu_memory_gb(); + 176: + 177: - let shard_threshold = if !opts.full_size_shards && gpu_memory_gb <= 30 { + 178: - ELEMENT_THRESHOLD - (1 << 26) - (1 << 25) - (1 << 24) + 179: - } else { + 180: - ELEMENT_THRESHOLD + 181: + let shard_threshold = match env_usize("SP1_GPU_ELEMENT_THRESHOLD") { + 182: + Some(t) => t as u64, + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 57 + +MASTER 255 / 292 + R1 / SOURCE REVIEW + + + + + 183: + None => element_threshold_for_budget(gpu_memory_gb, opts.full_size_shards), + 184: }; + 185: + let height_threshold = opts.sharding_threshold.height_threshold; + 186: + 187: - tracing::debug!("Shard threshold: {shard_threshold}"); + 188: + eprintln!( + 189: + "FLOOR opts gpu_memory_gb={gpu_memory_gb} element_threshold={shard_threshold} + height_threshold={height_threshold} recursion_trace_allocation={} full_size_shards={}", + 190: + recursion_trace_allocation(), + + + +F08 / pipeline scope and distributions + +igneum-proving/docs/analysis/proving-pipeline-2026-10-08.md:7-50 + + + 7: ## The window and its limit + 8: + 9: The measurement window is the whole of 8 October's proving on the rented fleet, 07:00:26Z + (first claim) to 14:27:15Z (last claim), read + 10: from every prover box's own log after Devnet 3 was turned off at 15:34Z. Paid work + exists only between 07:46:55Z and 10:43:10Z: 93 paid + 11: segments, 172.88 IGN. From 11:45Z the chain stalled at the class v5 crossing and then + partitioned (every solo branch carried old-object + 12: blocks, the network restarted from the stall sink at 15:27Z and was turned off at + 15:34Z), so every segment claimed after 11:45Z was + 13: submitted into a chain that never paid it. The hold's declared workload (150 tx/s) ran + 11:42Z to 12:23Z with inclusion, then without, so + 14: no paid shard carries a hold transaction: the stage columns below are the fleet's + proving of the chain's own blocks, under the pre-stall + 15: load (the DEX and faucet lanes, the hold's earlier steps), on the 0.3.24 node + (5b673577). The window asked for, two hours under the hold, + 16: does not exist in the record; this is the honest substitute, and the instrument is in + place for the next chain. + 17: + 18: ## The instrument + 19: + 20: Collector `tools/fleet/pipeline-collect.py` (hub-1's Devnet 3 node, + `igneum_getProvingStatus` every 30 s; every prover's RESULT lines + 21: every 5 min) and the per-box logs `/root/fleet/out/prover.log` written by + `tools/fleet/box-prover.py`, pulled whole after the stop. Each + 22: column names its lines. + 23: + 24: | column | source lines in prover.log | how the number is read | + 25: |---|---|---| + 26: | assignment wait | `RESULT claim segment A..B (n shards, fresh) margin=M tip=T` | + not separable from the logs: a segment becomes claimable when its last block settles and the + box claims on its next pass (passes every 15 s). The proxy recorded is the margin at claim, + the DAA left before the deadline (600 DAA window): median 467, p5 (slowest) 557 is not a + wait but an early claim. Block timestamps would give the wait exactly; Devnet 3 is off, so + they are not read. | + 27: | inputs | claim stamp to the chain's start (the `RESULT seg N chain` stamp minus its + `wall`) | the export of the segment's records from the node, the pair check and the cuts | + 28: | proving | `RESULT seg N chain k shard records, chain_len c, proof b bytes, shards + P s, aggregation A s, wall W s, peak MiB` field P | the shard proofs on the card (SP1 floor + server) | + 29: | aggregation | the same line's A | the segment chain over the shard proofs | + 30: | verification | chain stamp to `RESULT seg N shards accepted k of n` | the node's + verification of each shard record at submission; it answers inside the second, so + verification and submission are one column | + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 58 + +MASTER 256 / 292 + R1 / SOURCE REVIEW + + + + + 31: | inclusion and payment | `RESULT submitted ... end to end E s` to `RESULT paid + ... after S s` | S is the prover's own clock from the record's acceptance to the payment + read on its node | + 32: | failure, retry | `RESULT seg N ... FAILED`, `RESULT segment_refused`, `RESULT unpaid`, + `RESULT paid_other`, `record accepted on retry` | counted per kind | + 33: | queue depth | `RESULT pass n no whole segment inside the margin (worklist N + entries, tip T)` | N is the node's assigned-shard worklist as the prover reads it on each + idle pass | + 34: + 35: ## Stage columns, seconds, every segment that reached the stage + 36: + 37: | stage | n | median | slowest 5 % | slowest 1 % | max | + 38: |---|---|---|---|---|---| + 39: | inputs (claim to export and cuts done) | 2,447 | 2.4 | 7.5 | 10.1 | 14.7 | + 40: | proving (shard proofs) | 2,453 | 26.8 | 216.1 | 364.7 | 1,104.7 | + 41: | aggregation (segment chain) | 2,453 | 22.8 | 44.2 | 96.4 | 156.6 | + 42: | verification and shard-record submission | 2,453 | 0.0 | 2.0 | 2.0 | 10.0 | + 43: | segment-record submission | 1,909 | 0.0 | 1.0 | 1.0 | 1.0 | + 44: | claim to submitted (end to end) | 1,909 | 75.1 | 230.3 | 301.6 | 497.4 | + 45: | inclusion and payment (submitted to paid) | 93 | 171.0 | 543.0 | 31,397 | 31,470 | + 46: | claim to paid | 91 | 336.0 | 720.0 | 1,098 | 1,240 | + 47: | peak GPU memory during the chain, MiB | 2,453 | 11,948 | 21,174 | 25,788 | 26,210 | + 48: + 49: The two 31,000-second payments are segments submitted before the 02:4xZ pause and paid + when the chain resumed; without them the + 50: inclusion-and-payment p99 is 902 s. The assignment wait is not in the table (see the + instrument row). + + + +F08 / paid outcomes and expiry + +igneum-proving/docs/analysis/proving-pipeline-2026-10-08.md:66-121 + + + 66: ## Outcomes per tier and wasted work + 67: + 68: | tier | claimed | paid | stolen | refused | submitted, never paid | claimed, never + submitted | work s paid | work s wasted | + 69: |---|---|---|---|---|---|---|---|---| + 70: | RTX 4090 | 2,515 | 48 | 98 | 93 | 1,322 | 959 | 7,025 | 183,524 | + 71: | RTX 3060 12 GB | 313 | 0 | 0 | 0 | 34 | 280 | 0 | 6,765 | + 72: | L40S | 273 | 10 | 25 | 28 | 147 | 63 | 1,196 | 26,026 | + 73: | RTX 3090 | 263 | 34 | 8 | 30 | 152 | 41 | 6,484 | 34,855 | + 74: | RTX 6000 Ada | 45 | 1 | 6 | 0 | 26 | 12 | 57 | 3,055 | + 75: + 76: - "submitted, never paid" (1,681 segments) is the partition: records accepted into a + chain that never settled them after 11:45Z. It is + 77: the day's largest waste and is not a pipeline fault; it is the fault of the afternoon + (the fleet record). + 78: - "claimed, never submitted" (1,355): the chain step failed or the claim was abandoned. + The failures are counted below. + 79: - The 3060 tier completed no paid segment in 313 claims: at 12 GB the chain runs out of + margin (its proving median on completed chains + 80: is above the 4090's by the card's ratio, and a 4090 claimant finishes the same segment + first), so the 12 GB tier is a miner, not a + 81: prover, on this segment size. The 3060's 34 submitted segments were all after 11:45Z + (never paid for the partition's reason). + 82: - Wasted work is the end-to-end seconds of every claimed segment that was not paid; the + fleet spent 254,000 card-seconds (70 card-hours) + 83: on segments that did not pay against 14,800 (4.1 card-hours) that did. Before the + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 59 + +MASTER 257 / 292 + R1 / SOURCE REVIEW + + + + + stall the ratio was about 3 to 1 (the steals and + 84: refusals below); after it, everything was waste. + 85: + 86: ## Failures and retries + 87: + 88: - `RESULT seg N chain FAILED`: 900, median wall 2.7 s. 629 "NotFound: No such file or + directory": the sm_89 floor tarball's + 89: `igneum-prove-host` was a dangling link until the real host was served at 10:50Z + (08:00 to 10:59Z, the fleet record's floor fault); + 90: 264 "invalid string length" (the host's proof-bytes string on the 48 GB cards' larger + segments); 4 OutOfMemory (12 GB cards). After + 91: 10:50Z the NotFound class ended; the string-length class remains open for the node + lane. + 92: - `RESULT segment_refused`: 153. 62 "does not chain to segment N..N" (the previous + segment's record moved under the claim), 54 "unproven: + 93: the record is carried after the segment's deadline" (the chain step finished too + late), 35 "segment already paid" (a faster claimant). + 94: - Retries: 0 lines "record accepted on retry". The prover does not retry a failed chain; + it drops the export and claims afresh. + 95: - Failure rate on claims: 900 chain failures plus 153 refusals over 3,421 claims is 30.8 + percent; without the floor-link class (fixed) it + 96: is 12.5 percent. + 97: + 98: ## Steals: a faster claimant takes an assigned prover's reward + 99: + 100: `RESULT paid_other`: 137 segments this box had claimed were paid to another key, 4.0 + percent of claims (98 on 4090s, 25 on L40S, 8 on + 101: 3090s, 6 on the 6000 Ada). The time from this box's claim to the other key's payment + read: median 306 s, p95 9,757 s (the long tail is the + 102: same pause-and-resume as the payment column). The exclusive window (10 DAA seconds) + does not hold a slow claimant's segment for it: a + 103: second box that finishes its chain first is paid. The 3060 tier was never the winner + and never the victim (it never finished). + 104: + 105: ## Queue depth over time + 106: + 107: The worklist as the provers read it on idle passes, median entries per hour (tip in the + line): 02Z 596, 05Z 596, 08Z 596, 11Z 713, 14Z + 108: 594. Bounded at about 600 entries (the 600 DAA unproven window times one entry a DAA) + for the whole day; it did not grow, because a + 109: segment leaves the list at its deadline whether proved or not. Growth would show the + window itself lengthening; it did not. + 110: + 111: ## What this means + 112: + 113: - With the floor link fixed, the pipeline's own stages are fast: inputs 2 s, + verification and submission under 2 s, aggregation 23 s + 114: (75 s on a 3090); the proving stage sets the pace, 27 s median and 216 s at the + slowest 5 percent, and payment lands 171 s after + 115: submission (543 s at the slowest 5 percent) when the chain settles. + 116: - The waste is structural, not incidental: 70 card-hours wasted against 4 paid, + dominated by the partition, then by the floor fault, + 117: then by steals and late chains (13 percent of claims). Two changes would cut the + pre-stall waste: a claim that is honoured for the + 118: window it was granted (the steal rate goes to zero) and a 12 GB tier that claims only + segments it can finish (the 3060's 313 claims + 119: earned nothing). + 120: - The next chain (igneum-devnet-4) starts this instrument from block zero; the two-hour + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 60 + +MASTER 258 / 292 + R1 / SOURCE REVIEW + + + + + window under the hold's declared workload is + 121: the first measurement to run on it, with block timestamps read so the assignment wait + becomes a real column. + + + +F09 / host verification + +igneum-proving/proving/igneum-prove/host/src/main.rs:477-509 + + + 477: fn run_verify(pinned: &pinned::Pinned, proof_path: &str, statement: &str) -> Result<()> + { + 478: use sp1_sdk::blocking::{LightProver, Prover}; + 479: let bytes = std::fs::read(proof_path).with_context(|| format!("read + {proof_path}"))?; + 480: let want: B256 = statement.parse().context("statement is not 32 bytes of hex")?; + 481: stage("setup"); + 482: let t = Instant::now(); + 483: let verifier = LightProver::new(); + 484: println!("RESULT setup: {:.3} s (light verifier, pinned key), shard program id {} + at {}", t.elapsed().as_secs_f64(), pinned.shard_id, now()); + 485: stage("verify"); + 486: let t = Instant::now(); + 487: let proof: sp1_sdk::SP1ProofWithPublicValues = + bincode::deserialize(&bytes).context("the file is not a bincode SP1 proof")?; + 488: let got = alloy_primitives::keccak256(proof.public_values.as_slice()); + 489: let output = ShardOutput::from_bytes(proof.public_values.as_slice()); + 490: let claimed = pinned::claimed_program_id(&proof); + 491: let same_program = claimed == Some(pinned.shard_id); + 492: let crypto_ok = same_program && verifier.verify(&proof, &pinned.shard_vk, + None).is_ok(); + 493: let ok = crypto_ok && got == want && output.is_some(); + 494: let dt = t.elapsed().as_secs_f64(); + 495: let program = match claimed { + 496: Some(c) if same_program => format!("program id {c} (ours)"), + 497: Some(c) => format!("program id {c} IS NOT OURS {} (the prover runs another + guest build)", pinned.shard_id), + 498: None => "not a compressed proof".to_string(), + 499: }; + 500: match &output { + 501: Some(o) => println!("RESULT verify: {} in {dt:.3} s; block {} shard {} prover + {} statement {got} (want {want}) {program} proof {} bytes at {}", if ok { "VERIFIED" } else + { "NOT VERIFIED" }, o.number, o.shard_index, o.prover, bytes.len(), now()), + 502: None => println!("RESULT verify: NOT VERIFIED in {dt:.3} s; public values are + not a shard statement; {program} at {}", now()), + 503: } + 504: if ok { + 505: Ok(()) + 506: } else { + 507: std::process::exit(3) + 508: } + 509: } + + + +F09 / aggregation verification + +igneum-proving/proving/igneum-prove/host/src/main.rs:869-911 + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 61 + +MASTER 259 / 292 + R1 / SOURCE REVIEW + + + + + 869: fn run_verify_segment(pinned: &pinned::Pinned, proof_path: &str, statement: &str) -> + Result<()> { + 870: use sp1_sdk::blocking::{LightProver, Prover}; + 871: let bytes = std::fs::read(proof_path).with_context(|| format!("read + {proof_path}"))?; + 872: let want: B256 = statement.parse().context("statement is not 32 bytes of hex")?; + 873: stage("setup"); + 874: let t = Instant::now(); + 875: let verifier = LightProver::new(); + 876: println!("RESULT setup: {:.3} s (light verifier, pinned aggregator key), aggregator + id {} shard program id {} at {}", t.elapsed().as_secs_f64(), pinned.agg_id, + pinned.shard_id, now()); + 877: stage("verify-segment"); + 878: let t = Instant::now(); + 879: let proof: sp1_sdk::SP1ProofWithPublicValues = + bincode::deserialize(&bytes).context("the file is not a bincode SP1 proof")?; + 880: let got = alloy_primitives::keccak256(proof.public_values.as_slice()); + 881: let output = BlockOutput::from_bytes(proof.public_values.as_slice()); + 882: let claimed = pinned::claimed_program_id(&proof); + 883: let same_program = claimed == Some(pinned.agg_id); + 884: let crypto_ok = same_program && verifier.verify(&proof, &pinned.agg_vk, + None).is_ok(); + 885: let ids_ok = output.as_ref().map(|o| o.shard_vk == pinned.shard_id && (o.agg_vk == + pinned.agg_id || (o.chain_len == 1 && o.agg_vk == B256::ZERO))).unwrap_or(false); + 886: let ok = crypto_ok && ids_ok && got == want; + 887: let dt = t.elapsed().as_secs_f64(); + 888: let program = match claimed { + 889: Some(c) if same_program => format!("aggregator id {c} (ours)"), + 890: Some(c) => format!("aggregator id {c} IS NOT OURS {} (the aggregator runs + another guest build)", pinned.agg_id), + 891: None => "not a compressed proof".to_string(), + 892: }; + 893: match &output { + 894: Some(o) => println!( + 895: "RESULT verify-segment: {} in {dt:.3} s; block {} ({}) chain_len {} shards + {} statement {got} (want {want}) {program}; inner ids {}; proof {} bytes at {}", + 896: if ok { "VERIFIED" } else { "NOT VERIFIED" }, + 897: o.number, + 898: o.block_hash, + 899: o.chain_len, + 900: o.shard_count, + 901: if ids_ok { "ours".to_string() } else { format!("NOT OURS (shard {} agg {} + chain_len {})", o.shard_vk, o.agg_vk, o.chain_len) }, + 902: bytes.len(), + 903: now() + 904: ), + 905: None => println!("RESULT verify-segment: NOT VERIFIED in {dt:.3} s; public + values are not a block statement; {program} at {}", now()), + 906: } + 907: if ok { + 908: Ok(()) + 909: } else { + 910: std::process::exit(3) + 911: } + + + +F09 / recorded enforcement and cold verification + +igneum-proving/docs/spec/proving-enforcement.md:72-117 + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 62 + +MASTER 260 / 292 + R1 / SOURCE REVIEW + + + + + 72: | (6) incorrect rewards or consensus inputs: derivation authenticated, not only + execution over supplied inputs | `enforced_a_statement_over_altered_rewards_or_payouts_is_ve + toed_native_derivation_is_the_check` (a statement whose post-root came from execution over + other rewards or payouts is not the native statement and pays nothing: the native veto, + every node's own derivation) | executor, branch proving-payment of the fork at 421bb852 (on + release-2.0.0-node's c04674fe), igneum-exec 67 passed on build-2 at 17:10 UK | team-tested + for what the test holds (the derivation authenticated by every node's own execution: a + statement over other rewards or payouts pays nothing); PENDING for the proof side, the + register row "Negative test six, proof side: derivation inside the aggregator guest (P22 + stage 3)", clock 18:00 UK on 9 October 2026, when its served label moves from PENDING to + team-tested on its own test (section 7, stages 1 to 3) | + 73: + 74: The boundary sentence of the plan, carried in every served text that names the rule: a + proof of execution is not a proof of authenticated consensus inputs, canonical history or + data availability. What the rule proves today is that the carried record's statement is the + native statement of this node's own execution and that an SP1 proof of that statement + verifies; what consensus inputs the execution used, which history is canonical and whether + the data is available are each the node's own reading, not the proof's. + 75: + 76: ## 4. The cost + 77: + 78: The verifier's time per record on the node, measured on build-2 under the lease tool + (section 6 carries the RESULT lines). The budget per block: at most 8 shard records and 2 + segment records per block (`MAX_RECORDS_PER_BLOCK`, `MAX_SEGMENT_RECORDS_PER_BLOCK`), + verified in parallel on the body processor's thread pool, each verdict cached by proof hash, + so a proof verified at relay time costs the block nothing. Measured (section 6, build-2, + one EPYC 9454P core at nice 19 under the lease tool, the box loaded): 0.668 to 0.710 s per + record and about 30 MB per concurrent verify. What the switch costs a block, from those + figures: nothing for a block that carries no records; nothing for a proof the relay verified + before its block (the cached verdict); the worst case is a block whose ten proofs all + arrive cold with it, about 0.7 s wall on ten cores of the body processor's pool (7 s of CPU) + and about 300 MB peak. At the hold's rate of one block a second, a producer that fills + every block with cold proofs costs a validator 0.7 s of wall per block on ten cores, which + the pool absorbs; a validator with fewer cores serialises the ten verifies (7 s a block) and + falls behind, which is why the relay-time verify is the design's budget and the block-time + verify its backstop. Per tier: every node class holds the 300 MB (8 GB rig, 12 and 16 GB + card nodes, pool nodes); a Windows node verifies through `igneum-prove-host` and the daemon + refuses to start with the rule set and no host. The 10 ms gate of the overview is the hash's + per-warp CPU-verify gate, not this check's: an SP1 compressed proof verify is 70x it, a + different class of check, and the cache above is what keeps it off the block's critical + path. + 79: + 80: ## 5. Activation + 81: + 82: 1. The live Devnet 3 object does not move: the switch is false, the floor never, the + digest unchanged, and the tests say so. + 83: 2. igneum-testnet-1 already runs the body rule from block zero under its two pinned ids; + this rollout adds the payment rule on the same floor (0), which changes nothing a testnet + node pays (every carried record on the testnet has passed the body rule), and is the first + live network under the full condition. + 84: 3. The class v6 object (`docs/design/class-v6-rotating-family.md`, no consensus code + yet) carries `verifier_in_consensus: true`: on from its block zero. Until that object + exists, a network that wants the rule before class v6 sets its own floor through + `proving_consensus_verify_daa` in the override file, the way the 0.3.16 rule was designed to + land, one weight window above the rollout so every node runs the binary first. + 85: 4. Every node must run a binary whose embedded keys are the object's pinned ids before + the floor; the daemon refuses to start otherwise. + 86: 5. Shipping: consensus code on the release line the shipper names (release-0.3.26 is the + hotfix pair; the next node line opens as release-0.3.27); the main-repository branch lands + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 63 + +MASTER 261 / 292 + R1 / SOURCE REVIEW + + + + + on the box mirror master through the gate on the coordinator's word. + 87: + 88: ## 6. Results and measurements + 89: + 90: Filled from the box runs as they land; each line names the box, the command class and + the time. + 91: + 92: | Time (UK) | Box | What | Result | + 93: |---|---|---|---| + 94: | 16:08 | build-2, suite class, 12 threads, nice 10 (the bounded pool held 13 free + cores; the 24-thread ask waited) | `cargo test --release -p igneum-exec --lib enforced_` | 7 + passed, 0 failed (the seven executor tests of section 3), 229 s wall with the compile | + 95: | 16:11 | build-2, same class | `cargo test --release -p kaspa-consensus-core --lib + the_verifier_switch` | 1 passed (the switch is off on every compiled object; Devnet 3 at + never; the testnet floor 0; the digest moves once set; a file that omits it changes nothing) + | + 96: | 16:15 | build-2, suite class, 12 threads | `cargo test --release -p + kaspa-consensus-core -p igneum-exec -p kaspa-consensus --lib` (the full lib suites on the + branch; the first consensus build stopped on a missing `ConsensusApi` import at 16:11, fixed + at 16:12) | igneum-exec 64 passed 0 failed; kaspa-consensus 138 passed 0 failed, 3 ignored + (the six `proving_enforcement_tests::enforced_*` among them); kaspa-consensus-core 171 + passed 0 failed, 4 ignored; 172 s wall with the compile | + 97: | 17:22 | build-2, `tools/fast-time-remote.sh` (normal class), three local nodes, one + CPU mining thread each | `infra/fast-time/proving-enforcement.mjs --floor 240 --before 90 + --after 150 --real-proof ` (the fifth attempt; the first four were + the harness's own faults: a bare boolean in the override file, the block tag's hex form, the + forged block inside the exclusive window, a dead ssh leaving three nodes on the box) | + RESULT PASS. Below the floor (A at DAA 118, block 101): A's trusting pool took shapes a, b, + c, d and g and its templates carried them; A's own unmodified pool refused e (bad signature) + and f (the native-execution veto), the same checks every honest node runs; H1 paid the + first carried record, shape c (the real proof of another chain under A's statement), + 0x8cc611991c3c400 wei to A's payout: ledger P21's finding, observed; the three records after + it read "shard already paid" (shape g's duplicate among them). At the floor (A at DAA 247, + block 229): the same five shapes carried by A; H1 paid nothing, carried nothing of A's (its + blocks never entered H1's DAG), and H1 and H2 each logged four new REFUSED verdicts (3 to + 7), one per carried record, in 0.000 to 0.003 s each (the cached verdict from the relay-time + verify, the measured cold path above being the first verify). Result file on build-2: + `/home/build/enforced-fixtures/floor-240-expect-refuse.json` | + 98: | 16:34 | build-2 (AMD EPYC 9454P, 96 threads, 125 GB), `lease pool 1 --nice 19`, one + core, the box at load 85 to 95 | the verify cost per record: + `nativeverify::tests::a_real_proof_verifies_and_a_wrong_statement_is_refused` on a real + compressed shard proof of the testnet join pass (build-1 + `/srv/builds/tn-join-pass/prover/block-763-shard-0-compressed.bin`, 1,272,897 bytes), seven + runs; `/usr/bin/time -v` for the memory | measured: 0.710, 0.683, 0.701, 0.671, 0.700, + 0.687, 0.668 s one core (0.668 to 0.710 s, a loaded-box figure); peak resident 34.6 MB with + the verify against 4.6 MB for the same binary without it, so about 30 MB per concurrent + verify | + 99: + 100: ## 7. The staging statement for P22 + 101: + 102: P22: the rewards and the prover payouts are inputs to the shard proof, not outputs. The + shard guest takes the segment's rewards and payouts as data and commits the post-root after + them; a host can feed any list and the proof still verifies. Today the node's own + derivation is the check: the statement must equal the node's native statement for that shard + and payout, which used the rewards and payouts consensus derived, so a proof over another + list matches no node's statement and pays nothing. + 103: + 104: The closure is staged. Each stage is a claim about one input and the check that holds + it; no stage claims a self-contained proof of the whole state. + 105: + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 64 + +MASTER 262 / 292 + R1 / SOURCE REVIEW + + + + + 106: | Stage | What becomes an output of a proof | What checks it until then | Status | + 107: |---|---|---|---| + 108: | 0 (today) | nothing: rewards and payouts are data in the shard statement + (`BlockFixture.rewards`, `payouts`) | every node's native execution derives both and vetoes + a statement that differs; enforced proving (this document) adds that the record's proof must + verify for that statement | implemented | + 109: | 1 | the shard proof's rewards list is checked against a commitment the aggregator + carries in its public values (the mergeset's blue blocks and their subsidies, hashed) | the + aggregator's commitment is itself data; every node recomputes it from the mergeset it holds + and vetoes a segment statement whose commitment differs (spec 7.8 item 5, the native block + statement) | next: the consensus-proof work of design 7, phase 2 | + 110: | 2 | the payouts list is derived inside the aggregator guest from the carried records + it verifies (the first valid record per shard, the pool credit split) | the node's + `carried_payouts` is the native check of the same derivation; a segment statement whose + payouts differ is vetoed | phase 2, after stage 1 | + 111: | 3 | the rewards are derived inside the aggregator guest from consensus data it + verifies (headers, blue sets) | the node's own derivation vetoes; this is the consensus + proof proper, and only here do rewards stop being an input anywhere | phase 2, the last step + | + 112: + 113: Until stage 3 lands, every stage's output is checked natively by every node, and the + statement "the rewards and payouts are proven" is not made in any served text. The ledger + entry P22 carries this table. + 114: + 115: ## 8. The fast-time harness case + 116: + 117: `infra/fast-time/proving-enforcement.mjs` (ran, PASS at 17:22 UK, section 6): three + nodes on one fast-time network, two honest under the floor set a few epochs ahead + (`proving_consensus_verify_daa` in the override, the boundary), one attacker with the body + rule off and the verifier in trust mode. The attacker reads each shard's native statement + for its own payout address from its node (`igneum_getShardPlan(block, payout)`), signs it + (`igneum-miner sign-record`) and submits it with proof bytes of the seven shapes through + `igneum_submitProofRecord`; its templates carry the records. Below the boundary the honest + nodes accept the attacker's blocks and the v0 rule pays (the finding, observed); from the + boundary every honest node refuses the carrying block (`IgneumInvalidProofRecord` or the + 20-s drop) and `igneum_getProofRecords` shows no paid entry for any of the seven. The + honest-pays-once case needs a real shard proof of the harness's own chain, which a CPU + prover makes in minutes; the unit tests hold it meanwhile and the testnet holds it live. + + + +F10 / fee split in source + +igneum-proving/proving/igneum-prove/core/src/executor.rs:194-213 + + + 194: /// Igneum 2.0 D4: how a transaction's proving charge divides, exactly as the node + (`igneum_exec::executor::proving_payment_split`). + 195: /// Off: the whole charge burns. On: 90 percent is the provers' payment (to the pool + escrow), 10 percent burns, the + 196: /// rounding wei to the burn. + 197: pub fn proving_payment_split(charge: u128, to_pool: bool) -> (u128, u128) { + 198: if !to_pool { + 199: return (0, charge); + 200: } + 201: let payment = charge / 100 * 90 + (charge % 100) * 90 / 100; + 202: (payment, charge - payment) + 203: } + 204: + 205: pub fn execute_range(db: &mut IgneumDb, chain_id: u64, env: &FixtureEnv, schedule: + &FeeSchedule, rewards: Option<(&[(Address, U256)], U256, &[(Address, U256)])>, txs: + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 65 + +MASTER 263 / 292 + R1 / SOURCE REVIEW + + + + + &[ShardTx], carry_in: Carry, roots: bool) -> RangeOutcome { + 206: // The fee set that meters this chain block: the schedule read at the block's own + DAA score, so the guest + 207: // replays the height switch as the node does. The base fees carried in are raised + to this set's floors here + 208: // (the node does the same; the record, and so the fixture, already carry the + raised values). + 209: let fees = schedule.at(env.daa_score); + 210: let env = &FixtureEnv { base_fee_exec: + env.base_fee_exec.max(fees.floor_exec_u64()), base_fee_proving: + env.base_fee_proving.max(fees.floor_proving_u64()), ..env.clone() }; + 211: let intrinsic_pgas = fees.pgas.intrinsic_pgas_per_tx; + 212: let block_proving_limit = fees.block_proving_gas_limit; + 213: let base_fee_exec = env.base_fee_exec as u128; + + + +F10 / execution fee credits + +igneum-proving/proving/igneum-prove/core/src/executor.rs:297-337 + + + 297: // Fee flows (design 4.1 and 4.4, spec 7.5 item 2), exactly as the node + applies them. + 298: let (status, gas_used, logs) = if insp.over_budget { + 299: let gas_used = tx.gas_limit(); + 300: let burned_exec = (gas_used as u128) * base_fee_exec; + 301: let proving_charge = ((pgas_used as u128) * + base_fee_proving).min(budget.saturating_sub(burned_exec)); + 302: let tip_total = budget.saturating_sub(burned_exec + proving_charge); + 303: db.bump_nonce(tx.sender); + 304: db.sub_balance(tx.sender, U256::from(budget)); + 305: let (proving_payment, _burned_proving) = + proving_payment_split(proving_charge, env.proving_payment_to_pool); + 306: if proving_payment > 0 { + 307: db.add_balance(PROVING_POOL_ADDRESS, U256::from(proving_payment)); + 308: } + 309: let shares = developer_shares(tip_total, &insp.attributions, |code| + registered_payee(db, code)); + 310: let dev_total: u128 = shares.iter().map(|(_, w)| *w).sum(); + 311: db.add_balance(t.miner, U256::from(tip_total - dev_total)); + 312: for (payee, wei) in &shares { + 313: if let Some(p) = payee { + 314: db.add_balance(*p, U256::from(*wei)); + 315: } + 316: } + 317: (false, gas_used, Vec::new()) + 318: } else { + 319: db.commit(state); + 320: let (status, gas_used, logs) = if insp.pgas_aborted { + 321: // Spec 7.5 item 2: charged like an out-of-gas transaction for what + it consumed up to the abort; + 322: // the gas beyond the abort point goes back to the sender and its + tip part comes back from the + 323: // miner. State changes reverted, nonce advanced (committed above), + status 0, no logs. + 324: let consumed = + insp.gas_at_abort.unwrap_or(gas_used).clamp(tx.intrinsic_gas, gas_used); + 325: let unconsumed = (gas_used - consumed) as u128; + 326: db.add_balance(tx.sender, U256::from(unconsumed * price)); + 327: db.sub_balance(t.miner, U256::from(unconsumed * (price - + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 66 + +MASTER 264 / 292 + R1 / SOURCE REVIEW + + + + + base_fee_exec))); + 328: (false, consumed, Vec::new()) + 329: } else { + 330: (status, gas_used, logs) + 331: }; + 332: // The proving charge never takes the sender past the signed budget + (design 4.1). + 333: let proving_charge = ((pgas_used as u128) * + base_fee_proving).min(budget.saturating_sub((gas_used as u128) * price)); + 334: db.sub_balance(tx.sender, U256::from(proving_charge)); + 335: let (proving_payment, _burned_proving) = + proving_payment_split(proving_charge, env.proving_payment_to_pool); + 336: if proving_payment > 0 { + 337: db.add_balance(PROVING_POOL_ADDRESS, U256::from(proving_payment)); + + + +F10 / guest input + +igneum-proving/proving/igneum-prove/core/src/fixture.rs:11-34 + + + 11: /// The chain block's environment (design section 3), as the node computed it. + 12: #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] + 13: pub struct FixtureEnv { + 14: pub number: u64, + 15: pub hash: B256, + 16: pub parent_hash: B256, + 17: pub timestamp: u64, + 18: pub miner: Address, + 19: pub prevrandao: B256, + 20: /// Base fees in wei per unit, both dimensions (fit in u64 on the devnet; the + executor widens to u128). As the + 21: /// node recorded them: already raised to the floors of the set that meters this + block. + 22: pub base_fee_exec: u64, + 23: pub base_fee_proving: u64, + 24: /// The chain block's DAA score: what the fee schedule is read at + (`fees_v1_activation_daa`, 5 October 2026). + 25: /// A fixture written before the switch existed has none, and 0 keeps it on the + schedule's base set. + 26: #[serde(default)] + 27: pub daa_score: u64, + 28: /// Igneum 2.0 D4 (`docs/design/proving-payment.md`): the node's + `proving_payment_activation_daa` reached at this + 29: /// chain block, so a transaction's proving charge (pgas used x f_p) is the provers' + payment: 90 percent credited to + 30: /// the proving pool escrow, 10 percent burned; false (every fixture written before + the field) burns the whole + 31: /// charge, as spec 5.1 stood. Exactly what the node does + (`igneum_exec::executor::proving_payment_split`). + 32: #[serde(default)] + 33: pub proving_payment_to_pool: bool, + 34: } + + + +F10 / guest deserialisation + +igneum-proving/proving/igneum-prove/program/src/main.rs:1-16 + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 67 + +MASTER 265 / 292 + R1 / SOURCE REVIEW + + + + + 1: //! The shard guest. Input: bincode of `ShardInput` (environment, the shard's + transactions, the carried-in + 2: //! position, the prover's payout address, the witness). Output (public values): + `ShardOutput` in its fixed byte + 3: //! layout. Everything between is `igneum_prove_core::shard::shard_statement`, the same + code the host runs + 4: //! natively first. + 5: + 6: #![no_main] + 7: sp1_zkvm::entrypoint!(main); + 8: + 9: use igneum_prove_core::shard::{shard_statement, ShardInput}; + 10: + 11: pub fn main() { + 12: let input = sp1_zkvm::io::read_vec(); + 13: let input: ShardInput = bincode::deserialize(&input).expect("ShardInput decodes"); + 14: let out = shard_statement(&input); + 15: sp1_zkvm::io::commit_slice(&out.to_bytes()); + 16: } + + + +F10 / pinned build behaviour + +igneum-proving/proving/igneum-prove/host/build.rs:1-39 + + + 1: //! Stamps the host with a hash of the native sources it was built from + (`IGNEUM_PROVE_SOURCES`, printed in the + 2: //! host's first line; the stale-build class of 5 October 2026): `cat $(ls core/src/*.rs + host/src/*.rs | sort) | + 3: //! shasum -a 256 | cut -c1-16` in proving/igneum-prove. Same recipe as export/build.rs. + 4: //! + 5: //! The guests are pinned build artefacts (host/src/pinned.rs, elf/manifest.json), so a + normal host build compiles + 6: //! nothing for the zkVM and needs no Succinct toolchain. `IGNEUM_BUILD_GUESTS=1` builds + both guests with sp1-build + 7: //! (into target/elf-compilation/...), for `igneum-prove-pin` to turn into the next + pinned set; see + 8: //! proving/igneum-prove/pin-guests.sh. Building the guest on every machine is what gave + the Mac and PC 2 different + 9: //! program ids on 5 October 2026. + 10: + 11: use sha2::{Digest, Sha256}; + 12: use std::path::Path; + 13: + 14: fn main() { + 15: println!("cargo:rerun-if-env-changed=IGNEUM_BUILD_GUESTS"); + 16: if std::env::var("IGNEUM_BUILD_GUESTS").map(|v| v == "1").unwrap_or(false) { + 17: sp1_build::build_program("../program"); + 18: sp1_build::build_program("../aggregator"); + 19: } + 20: + 21: let root = Path::new(env!("CARGO_MANIFEST_DIR")).join(".."); + 22: let mut files: Vec = Vec::new(); + 23: for dir in ["core/src", "host/src"] { + 24: for entry in std::fs::read_dir(root.join(dir)).expect("source dir") { + 25: let name = entry.expect("entry").file_name().to_string_lossy().into_owned(); + 26: if name.ends_with(".rs") { + 27: files.push(format!("{dir}/{name}")); + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 68 + +MASTER 266 / 292 + R1 / SOURCE REVIEW + + + + + 28: } + 29: } + 30: } + 31: files.sort(); + 32: let mut h = Sha256::new(); + 33: for f in &files { + 34: let path = root.join(f); + 35: println!("cargo:rerun-if-changed={}", path.display()); + 36: h.update(std::fs::read(&path).expect("read source")); + 37: } + 38: println!("cargo:rerun-if-changed=build.rs"); + 39: println!("cargo:rustc-env=IGNEUM_PROVE_SOURCES={}", + &hex::encode(h.finalize())[..16]); + + + +F10 / new fee regression present + +igneum-proving/proving/igneum-prove/host/src/main.rs:985-1018 + + + 985: /// charges (pgas used x f_p over the executed transactions) sit in + PROVING_POOL_ADDRESS, the post-root differs from + 986: /// the recorded one (another statement, which is why the floor stays at never + until this guest is pinned), and the + 987: /// split's arithmetic is the node's. + 988: #[test] + 989: fn the_proving_payment_flag_moves_90_percent_of_the_charge_to_the_pool() { + 990: use igneum_prove_core::config::PROVING_POOL_ADDRESS; + 991: use igneum_prove_core::executor::{execute_block, load_pre_state, + proving_payment_split}; + 992: let f = load("fees-v1-shards2.json"); + 993: assert!(f.expected.pgas_used > 0); + 994: // off: the recorded roots, the pool holds the subsidy credit alone + 995: let mut db = load_pre_state(&f.block); + 996: let before = db.balance(PROVING_POOL_ADDRESS); + 997: let off = execute_block(&mut db, &f.block); + 998: assert_eq!(off.state_root, f.expected.post_state_root); + 999: let pool_off = db.balance(PROVING_POOL_ADDRESS) - before; + 1000: assert_eq!(pool_off, f.block.proving_pool_credit, "off: the 20 percent credit + alone reaches the escrow"); + 1001: // on: 90 percent of every executed transaction's proving charge joins it + 1002: let mut block = f.block.clone(); + 1003: block.env.proving_payment_to_pool = true; + 1004: let mut db = load_pre_state(&block); + 1005: let before = db.balance(PROVING_POOL_ADDRESS); + 1006: let on = execute_block(&mut db, &block); + 1007: let pool_on = db.balance(PROVING_POOL_ADDRESS) - before; + 1008: let charges: u128 = on.executed.iter().map(|t| t.pgas_used as u128 * + block.env.base_fee_proving as u128).sum(); + 1009: let payment: u128 = on.executed.iter().map(|t| + proving_payment_split(t.pgas_used as u128 * block.env.base_fee_proving as u128, + true).0).sum(); + 1010: assert!(charges > 0, "the fixture carries proving charges"); + 1011: assert_eq!(pool_on - pool_off, alloy_primitives::U256::from(payment), "90 + percent of the charges reach the escrow"); + 1012: assert!(payment >= charges / 100 * 90 && payment <= charges / 100 * 90 + + on.executed.len() as u128); + 1013: assert_ne!(on.state_root, off.state_root, "another post-root: another + statement"); + 1014: assert_eq!(on.pgas_used, off.pgas_used, "the proving work is unchanged"); + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 69 + +MASTER 267 / 292 + R1 / SOURCE REVIEW + + + + + 1015: assert_eq!(proving_payment_split(100, true), (90, 10)); + 1016: assert_eq!(proving_payment_split(7, true), (6, 1)); + 1017: assert_eq!(proving_payment_split(7, false), (0, 7)); + 1018: } + + + +F11 / late hardware model + +igneum-v6-freeze-tree/docs/design/class-v6-rotating-family.md:572-584 + + + 572: #### 10.0r The placed energies, and the three chips scored at them (the adversary + lane's placed row, 17:5x UK: the 8-lane genesis core placed and routed on ASAP7 with its + SRAM macros, SPEF, a gate-level VCD; the full core's routed run 38 of 58 tags in; the SRAM + term modelled; node factors claimed; the coordinator's order 18:0x UK: these are the + energies the served form uses) + 573: + 574: Placement and the clock tree add 32 percent to the class v4 draw (7.78 pJ per lane-op + routed against 5.91 synthesised at ASAP7; 5.44 against 4.13 at N5), inside the k lane's +20 + to +40 expectation; node-for-node k 0.53 at the 5090's lock for the genesis core (0.38 a + node ahead), the full 18-family core scaled 0.59 and 0.42 until its routed row lands; the + 32-lane genesis core (synthesis) 3.70 pJ at N5, k 0.36, 10 percent under the 8-lane core. + **Placement takes a tenth off every per-joule ratio and nothing off the per-dollar ones.** + The served convention at the placed energy, the 5090 at its 1,300 MHz lock over the complete + machine (controller, host share, PSU, VRM, cooling in): + 575: + 576: | Chip, as a complete machine | Per joule, node-for-node | Per joule, a node ahead | + USD per MH/s (per dollar against the card's about 16) | Label | + 577: |---|---|---|---|---| + 578: | The GDDR7 board (the chip anyone can build) | **1.6x** (1.4x to 1.8x); 1.4x the 5080; + 2.5x the cohort card | 1.9x (1.5x to 2.1x); 1.7x the 5080; 2.9x the cohort | 4.84 (3.3x) | + placed core, modelled memory and machine, measured card | + 579: | The stored-half hybrid board (1 GiB of SRAM beside the DRAM; 10.0q) | about 2.4x | + about 2.9x | 1.88 (8.5x); the 5.5 GiB floor raises its SRAM ticket to USD 690 a board | + modelled on the placed core | + 580: | The N2 SRAM die | 2.4x | 3.3x | 0.8 (about 20x) | modelled on the placed core | + 581: + 582: Scored on lane 3's seven conditions at these energies (a first reading on lane 3's + rows, approximate; its own scoring with the sunk-development case replaces it by 21:00): the + board's verdicts stand (its per-joule ratio falls a tenth, its dollars do not move; it + passes all seven at a one to three year life); the hybrid's stand (it fails (b) and (c), the + dollar conditions, which placement does not touch; on (e) it sits on the 3x line a node + ahead and under it node-for-node); the die's stand on (a), (b), (c) and (f) (its dollars are + the die's) and on (e) it now holds node-for-node (2.4x) and fails a node ahead (3.3x). **So + the success statement holds for the pure DRAM board, fails for the SRAM die once sunk, and + fails for the hybrid on the dollar conditions; the placed energies change no verdict and + tighten every per-joule figure by a tenth.** The served energy sentence (10.0h) reads from + this table. + 583: + 584: The proving-payment pin is in the code (the node-side hand, 17:03 UK): branch + proving-payment of the fork at eaddbf83 on release-2.0.0-node's c04674fe, the suites green + on build-2 (igneum-exec 66 passed, kaspa-consensus-core 174 passed): behind + `Params::proving_payment_activation_daa` (u64::MAX on every object; the height is main's + word) a transaction's proving charge (pgas used x f_p) is 90 percent credited to + `PROVING_POOL_ADDRESS` and the block's `proving_pool_credit` (so 5.3's per-shard payout + carries it) and 10 percent burned, the rounding wei to the burn; below the height the whole + charge burns as 5.1 stood; the receipt's new field `proving_payment` shows the provers' part + beside `burned_proving`. One fact before any height is named: the shard guest + (`proving/igneum-prove/core/src/executor.rs` lines 290 and 318) still burns the whole + charge, so the floor stays at never until the guest carries the same split behind the same + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 70 + +MASTER 268 / 292 + R1 / SOURCE REVIEW + + + + + switch and the object pins the new shard program id; set before that, no shard proof + verifies past the floor. The economics row reads: "designed, in the code behind the + constant; the guest's mirror owed before any height". + + + +F12 / launch boundary + +igneum-v6-freeze-tree/igneum-pow/src/emit.rs:1553-1573 + + + 1553: if p.has_scratch() { + 1554: s.push_str("// Variant 5: the wrapper launches `warps` persistent warps over + `nonces / 32` units (host.cu does not use it).\n"); + 1555: s.push_str("cudaError_t igneum_launch_hash_bound(const uint32_t* ds, uint64_t* + out, uint32_t baseNonce, uint32_t mask,\n"); + 1556: s.push_str(&format!(" IgneumInitWords + iw,{hot_decl} uint32_t nonces, uint32_t blockWarps, uint32_t* scratch, uint32_t warps, + uint32_t salt) {{\n")); + 1557: s.push_str(" if (blockWarps == 0u || blockWarps > 32u || warps == 0u || + (warps % blockWarps) != 0u) return cudaErrorInvalidValue;\n"); + 1558: s.push_str(" uint32_t block = 32u * blockWarps;\n"); + 1559: s.push_str(" if (nonces == 0u || (nonces % (32u * warps)) != 0u) return + cudaErrorInvalidValue;\n"); + 1560: s.push_str(&format!(" igneum_hash_bound<<>>(ds, + out, baseNonce, mask, iw{hot_pass}, scratch, nonces / 32u, salt);\n")); + 1561: s.push_str(" return cudaGetLastError();\n"); + 1562: s.push_str("}\n"); + 1563: } else { + 1564: s.push_str( + 1565: "cudaError_t igneum_launch_hash_bound(const uint32_t* ds, uint64_t* out, + uint32_t baseNonce, uint32_t mask,\n", + 1566: ); + 1567: s.push_str(&format!(" IgneumInitWords + iw,{hot_decl} uint32_t nonces, uint32_t blockWarps) {{\n")); + 1568: s.push_str(" if (blockWarps == 0u || blockWarps > 32u) return + cudaErrorInvalidValue;\n"); + 1569: s.push_str(" uint32_t block = 32u * blockWarps;\n"); + 1570: s.push_str(" if (nonces == 0u || (nonces % block) != 0u) return + cudaErrorInvalidValue;\n"); + 1571: s.push_str(&format!(" igneum_hash_bound<<>>(ds, out, + baseNonce, mask, iw{hot_pass});\n")); + 1572: s.push_str(" return cudaGetLastError();\n"); + 1573: s.push_str("}\n"); + + + + +Supplementary primary references +These provide external implementation context, not validation of Igneum's results. Accessed 8 October +2026. + + • NVIDIA CUDA C++ Best Practices: https://docs.nvidia.com/cuda/cuda-c-best-practices-guide/ + index.html - profiling, transfer minimisation, register occupancy and allocation trade-offs. + + • NVIDIA System Management Interface: https://docs.nvidia.com/deploy/nvidia-smi/index.html - + supported power and clock controls and device identification. + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 71 + +MASTER 269 / 292 + R1 / SOURCE REVIEW + + + + + • Succinct SP1 proof types: https://docs.succinct.xyz/docs/sp1/generating-proofs/proof-types - + distinguish core/compressed proof costs and stages. + + • Microsoft AppLocker path conditions: https://learn.microsoft.com/en-us/windows/security/ + application-security/application-control/app-control-for-business/applocker/understanding-the-path- + rule-condition-in-applocker - path trust depends on who can change files. This is general security + context, not an ACL audit of the user's installation. + + +Reproduction package +Run reproduce.py for the original three-package checks and integration_reproduce.py for the added +source-guarded models and supplied C99 unit test. See the ZIP README for root layout and commands. +No network, GPU setting changes or fund transfers occur. + +The proposed native Rust assertions are included but NOT RUN. The model results intentionally expose +discrepancies; they are not a declaration that these application behaviours are acceptable. Hardware +rows and cost models remain team-reported. Unreviewed source or future changes require a new review. + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 72 + +MASTER 270 / 292 + R0 / ORIGINAL ALGORITHM REVIEW + +Historical V2/V3/V4 snapshot, retained in full. Later reviews report progress on v6 presence, shadow acceptance and +worker alignment. Old observations are not automatically current v6 defects. + + + + +IGNEUM - Mining algorithm source +review and reproducible evidence +Date: 8 October 2026 +Basis: igneum-mining-algorithm-2026-10-08.zip +Archive SHA-256: 94edb290005ecb8379cc599da90c877c7e25562f727cc4291069b4fbc149c7c1 + + +Executive assessment +There is concrete room to improve this snapshot, especially program-resource guarantees, acceptance +coverage, cryptographic boundaries, artifact identity and launch safety. This review does not establish +that Igneum has the best GPU algorithm, reaches a 1.5x specialised-hardware ceiling, or contains a +profitable live-network exploit. + +The supplied snapshot contains V2/V3/V4 paths, not the 64-register v6 described in the strategy +discussion. Its actual production activation status is unknown from these files. Do not transfer old +benchmark ratios to a modified candidate. + + +Scope and execution boundary +The archive contains 13 source/document files (527,803 uncompressed bytes), including 11 Rust files, +the algorithm specification and a README. It does not include Cargo.toml/Cargo.lock, the pack fixtures +referenced by tests, the complete mining worker host, the node integration, raw GPU measurements, or +adversarial RTL/physical-design reports. + +Rust, Cargo and CUDA were unavailable in the review environment. No original Rust test binary was built; +no GPU kernel, live-node test or ASIC benchmark was run. The executable work is an independent C/ +Python transcription of the selected source paths. It is a diagnostic model, not a replacement +implementation. + +The transcription matches the supplied genesis program id/op mix, two closed-form hashes, three +rejection/attempt vectors, and all eight published header-bound memory-hard hash vectors. Those +anchors increase confidence in the probes but do not prove complete equivalence for untested classes or +hardware. + +The model supports V2 and the V3 era draw/base instructions, the fixed V2 cache/mixer, and optional ALU +shadows. It excludes the experimental scratch, hot-table and derive-class variants. It does not certify all +of the approximately 9,769 source/document lines. + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 1 + +MASTER 271 / 292 + R0 / SOURCE REVIEW + + + + +Reproduced observations + + PROBE OBSERVATION LIMIT + + + 909/1,000 accepted programs lack Structural bound, no ASIC speedup + V2 lane communication + all five shuffle dimensions measured + + + 887/1,000 accepted programs lack + V3 lane communication One fixed era; not V4 with its shadow + all five dimensions + + + 312/2,048 hashes hit 0x0fffffff at one One accepted V2 program and site; + Memory concentration + site, with zero-header binding not overall traffic + + + A deliberately mutated zeroing + Not a canonically generated program + Shadow coverage shadow is invisible to the acceptance + or chain exploit + report + + + Two eras share program id + Separate expected-era checking can + Identity ef42100d5403c90d but compute + mitigate + different hashes + + + Starting a batch at 1 changes the Host code is absent; no physical GPU + Dispatch grouping + modelled result for nonce 2 run + + + Hypothetical bad patch, not current + Naive rejection patch 32/1,000 seeds exhaust 32 attempts + behaviour + + + +All counts, seeds, vectors and detailed qualifications are in the accompanying JSON and runnable +harness. CPU elapsed times in diagnostic logs are not mining-performance benchmarks. + + +Findings and exact source locations + +A01 - The supplied snapshot is not the planned v6 +The public class enum exposes V2, V3 and V4. Mutable per-lane state is eight 32-bit logical registers. V3 +fixes reads to one 32-bit word (4 bytes); V4 adds a 256-instruction block repeated 27 times per iteration. +These facts do not establish what is deployed or implemented elsewhere. + +Original source: igneum-pow-src/generator.rs:780-819; igneum-pow-src/generator.rs:850-858; +igneum-pow-src/verify.rs:335-354. + + +A02 - Accepted short programs need not connect all 32 lanes +For XOR-shuffle masks drawn from 1,2,4,8,16, k distinct dimensions allow components of at most 2^k +lanes. An independent census of 1,000 accepted V2 and 1,000 accepted V3 programs found full mask +span in only 91 and 113 respectively. Missing dimensions establish a connectivity bound, not a measured +ASIC speedup. Full span is necessary, not sufficient, for all-lane influence. The V3 run uses one fixed era; +these are not V4-shadow results. + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 2 + +MASTER 272 / 292 + R0 / SOURCE REVIEW + + + + +Original source: igneum-pow-src/generator.rs:1230-1298; igneum-pow-src/accept.rs:276-304; igneum- +pow-src/accept.rs:368-404. + + +A03 - Per-hash address diversity can conceal per-site concentration +An accepted V2 example, seed SHA256("igneum-review/139"), passes the transcribed acceptance +checks. At iteration 5, instruction 51 (zero indexed), 312 of 2,048 sampled header-bound hashes read +address 0x0fffffff when the exact V2 memory-hard dataset construction is used. Two additional +initialisation contexts give 318 and 325 hits. This is one load site, not that fraction of all mining traffic, and +it is not a demonstrated profitable caching attack. Proposed remedies are entropy-preserving state +transitions and measured per-site/address-cache analysis. + +Original source: igneum-pow-src/accept.rs:289-317; igneum-pow-src/accept.rs:347-397; igneum-pow- +src/generator.rs:124-147. + + +A04 - The acceptance interpreter omits the shadow that runtime executes +accept.rs runs only p.instrs; verify.rs also runs program.shadow. A deliberately mutated Program with a +valid-operand, zeroing 256-instruction shadow still passes the base-only acceptance check in the model +and produces 32 zero outputs. The fixture is NOT generated by the canonical generator and does NOT +show that the network accepts attacker-supplied programs. It demonstrates that the acceptance report +does not cover full shadow semantics. Either retire the excluded long-program path in the new class or +test its complete execution. + +Original source: igneum-pow-src/accept.rs:178-207; igneum-pow-src/accept.rs:327-350; igneum-pow- +src/verify.rs:370-395. + + +A05 - Header binding and final digest deserve independent cryptographic review +The seed/binding layer uses four salted FNV-1a runs with a final mixing step. The final result is a rotated- +XOR fold into 64 bits, inserted into the top 64 bits of a 256-bit value. The target comparison is internally +consistent: lane <= floor(T/2^192). This is not a demonstrated comparison bug, but it is not a 256-bit +cryptographic final digest. Recommend reviewing a domain-separated cryptographic input/output +envelope, including nonce and template binding, while keeping cheap inner operations where justified. +Such a change needs new consensus versioning and benchmarks. + +Original source: igneum-pow-src/seed.rs:34-49; igneum-pow-src/bind.rs:47-83; igneum-pow-src/ +verify.rs:390-395. + + +A06 - Different V3 eras can have the same program_id +The V3 and base-rung V4 identity path excludes the era parameters. The independent model produces +two V3 programs with id ef42100d5403c90d and different era-dependent hashes. This is structural +aliasing, not a brute-force collision. packcheck can compare a separately supplied expected era, which +mitigates that path when used. Its directory check reads metadata, not kernel content. Use distinct, full +semantic program, dataset and work identities; validate or regenerate executable artifacts against trusted +inputs. + +Original source: igneum-pow-src/generator.rs:1049-1065; igneum-pow-src/packcheck.rs:166-185; +igneum-pow-src/packcheck.rs:215-229; igneum-pow-src/packcheck.rs:263-272. + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 3 + +MASTER 273 / 292 + R0 / SOURCE REVIEW + + + + +A07 - CUDA dispatch needs explicit canonical-group constraints +The bound CUDA wrapper validates block shape but not 32-aligned baseNonce. The canonical verifier +aligns nonce groups to a 32 boundary. CPU emulation of the kernel grouping gives nonce 2 = +e5f5f4b14e9c87ae for a batch starting at 1, versus canonical 7342f96cbedb41d1. No GPU was run, and +the omitted host may already prevent this. Add wrapper/host guards and tests for alignment, nonce-low +rollover and refresh of nonce-high init words. + +Original source: igneum-pow-src/emit.rs:1219-1243; igneum-pow-src/emit.rs:1260-1270; igneum-pow- +src/bind.rs:99-119. + + +A08 - An operation described as bijective is not always bijective +Mad permits src2 == dst. For src == 1, dst += srcdst is 2dst modulo 2^32. Distinct old destinations 0 and +2^31 both map to 0. This contradicts the unconditional bijective-in-dst description of injects(), but is not +alone a lottery exploit. Restrict aliases or revise the invariant; separately examine destructive operations +and address-state entropy. + +Original source: igneum-pow-src/generator.rs:124-147; igneum-pow-src/generator.rs:1266-1282; +igneum-pow-src/verify.rs:403-475. + + +A09 - A naive stronger rejection test can exhaust all candidates +In a hypothetical patch requiring all five XOR-shuffle dimensions while retaining the existing draw +distribution and 32-attempt limit, 32 of 1,000 test seeds exhaust all attempts. This is NOT a failure +observed under the unmodified acceptance rule. Construct essential invariants into the generator rather +than naively adding a high-rejection check or using an unbounded consensus loop. + +Original source: igneum-pow-src/generator.rs:1377-1404. + + +Proposed next candidate - not a production patch + 1. Freeze the actual intended source and activation manifest; establish what is v6 and what has been + retired. + + 2. Construct live state and lane-connectivity properties by design; do not rely only on a random + instruction count or statistical rejection. + + 3. Analyse per-site addresses across nonces and headers, whole-dataset working sets and caching/ + recomputation alternatives. A permutation cannot restore entropy already collapsed to one value. + + 4. Use a common instruction semantics core for acceptance, reference execution and instrumentation. + Keep CPU verification costs bounded. + + 5. Review a domain-separated cryptographic envelope and full-width final result. Bind expensive work to + the job/nonce before finalisation; a cheap final hash alone must not allow intermediate-work reuse. + + 6. Introduce explicit semantic identities and trusted artifact validation. Keep work identity distinct from + reusable program/dataset identity. + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 4 + +MASTER 274 / 292 + R0 / SOURCE REVIEW + + + + + 7. Fix dispatch preconditions and test all backends for canonical results. Target filtering, compilation + caching and asynchronous staging are candidate byte-preserving miner optimisations, subject to + inspecting the missing host implementation. + + 8. Compare every candidate with tuned commodity GPUs and a redesigned multi-epoch adversary at + complete-board cost. No speedup or resistance multiplier is forecast by this review. + +Changes to program generation, binding, digest, operation semantics or dataset layout change the +consensus function. They require a versioned transition, new vectors and compatibility tests. Host guards +and byte-exact implementation optimisation should not silently change accepted hashes. + + +Native follow-up acceptance tests + • Reproduce the exact corpus counts and vectors in the original Rust crate and independently check + their source semantics. + + • Add generated-program dependency/communication analysis and adversarial algebraic simplification, + not just mask coverage. + + • Census per-site address distributions over independent holdout seeds, multiple headers/nonces, + actual memory-hard datasets and every proposed size; measure effective cache and bandwidth cost. + + • Mutation-test the acceptance checker against all activated execution components. Keep canonical- + generator tests separate from hostile fixtures. + + • Check every semantic identity component for accidental omission and every pack input for + substitution, stale state and mismatched compiled artifacts. + + • Compare CUDA/Metal/OpenCL/CPU results at aligned/unaligned starts, tails, epoch transitions and 32- + bit nonce rollover; preserve active-lane shuffle semantics. + + • Reassess GPU register spills, occupancy, wall energy, CPU-verifier latency and sustained mining/ + proving coexistence on the final configuration. + + • Rerun the 2.0 multi-epoch hardware and economic gates with no assumed chip retirement. An + algorithm review cannot establish customer demand, network security, retention or category rank. + + +External primary-source context +These references support the general engineering context, not the numerical observations about Igneum. + + • RFC 9923, FNV Non-Cryptographic Hash Algorithm, section 1.2: https://www.rfc-editor.org/rfc/ + rfc9923.html#section-1.2 + + • ProgPoW reference design, program generation and cryptographic encapsulation: https://github.com/ + ifdefelse/ProgPOW + + • NVIDIA CUDA Best Practices Guide, register/occupancy and memory optimisation: https:// + docs.nvidia.com/cuda/cuda-c-best-practices-guide/index.html + + • RandomX design, device binding and easy-program selection: https://github.com/tevador/RandomX/ + blob/master/doc/design.md + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 5 + +MASTER 275 / 292 + R0 / SOURCE REVIEW + + + + +Source excerpts +Line numbers below refer to the unmodified files inside the supplied archive. These excerpts are included +so the findings are auditable without assuming this report's interpretation. The source manifest records +every file's SHA-256. + +igneum-pow-src/generator.rs:780-819 + + + 780 | pub const GENERATOR_VERSION_V3: u32 = 3; + 781 | + 782 | /// Generator version of a class v4 program (Counter ASIC 3.0, 6 October 2026, + PROPOSED: `program_id(4, seed, attempt)`). + 783 | pub const GENERATOR_VERSION_V4: u32 = 4; + 784 | + 785 | /// The program class of an epoch (Counter ASIC 2.0, 5 October 2026, + `docs/plans/counter-asic-2-rollout.md`): one + 786 | /// height switch in the node, `program_class_v3_activation_daa`, rounded up to an + epoch boundary, decides which + 787 | /// class an epoch's program is drawn from. V2 is the lottery hash as adopted on 4 + October 2026, byte for byte. + 788 | /// V3 is generator version 3: its program id carries `generator = 3` and its load + class is [`V3_CLASS`]. + 789 | /// V4 (Counter ASIC 3.0, 6 October 2026, the candidate `mx8+sh256x27` behind + `program_class_v4_activation_daa`) is + 790 | /// generator version 4: its program id carries `generator = 4` and its load class is + [`V4_CLASS`]. + 791 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)] + 792 | pub enum ProgramClass { + 793 | #[default] + 794 | V2, + 795 | V3, + 796 | V4, + 797 | } + 798 | + 799 | /// The load class of program class v3, decided 5 October 2026 (Counter ASIC 2.0, + `docs/plans/counter-asic-2-status.md` + 800 | /// "22:00 decided", `docs/plans/mixer-x4.md`): [`LoadClass::MX4`], version 2 loads + (the width stays 4 bytes, the + 801 | /// per-load mix and the scratch share are out), the mixer applied 4 times per round + and the cache growth rule. The + 802 | /// placeholder of the seam (w16) is replaced here; nothing else in the seam names + the class. + 803 | /// Composed on 5 October 2026 (branch ca2-era): the era layout of + `docs/plans/era-layout.md` is drawn inside this class by + 804 | /// [`generate_from_seed_bytes_program_class`] (`LoadClass::era(V3_CLASS, era, + &V3_ALLOWED)`); here `era` is `None`. + 805 | pub const V3_CLASS: LoadClass = LoadClass { era: None, hot: None, ..LoadClass::MX8 }; + 806 | + 807 | /// The load class of program class v4 (Counter ASIC 3.0 item 8, + `docs/analysis/latency-shadow-2026-10-06.md`, the + 808 | /// candidate of 6 October 2026, gated by `docs/plans/counter-asic-3-node.md`): class + v3 plus the latency-shadow block + 809 | /// of 256 ALU instructions run 27 times per iteration ("mx8+sh256x27", 55,296 shadow + instructions per hash). The + 810 | /// base program, the 16 loads, the item construction, the cache growth rule and the + era draw are class v3's, draw + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 6 + +MASTER 276 / 292 + R0 / SOURCE REVIEW + + + + + 811 | /// for draw, so a v4 epoch's day cache and dataset are the v3 day's. Composed with + the era exactly as V3 is. + 812 | pub const V4_CLASS: LoadClass = LoadClass { shadow: Some(ShadowClass { instrs: + V4_SHADOW_INSTRS, reps: V4_SHADOW_REPS }), ..V3_CLASS }; + 813 | + 814 | /// The shadow block size of class v4 at every rung of the latency ladder + (`docs/design/latency-ladder.md`): 256 + 815 | /// instructions. The ladder moves the pass count alone. + 816 | pub const V4_SHADOW_INSTRS: u16 = 256; + 817 | + 818 | /// The shadow passes of class v4 at rung 0 of the latency ladder: 27 + (`mx8+sh256x27`, about 102,100 counted ops). + 819 | pub const V4_SHADOW_REPS: u16 = 27; + + + +igneum-pow-src/generator.rs:850-858 + + + 850 | /// The width set class v3's era draw chooses from: 4 bytes only (the read-width + decision of 5 October 2026; the + 851 | /// draw is consumed, so widening the set at genesis keeps the derivation). + 852 | pub const V3_ALLOWED: [u8; 1] = [1]; + 853 | + 854 | /// The program of an era class (generator version 3): `base` with the era parameters + drawn from `era_bytes` + 855 | /// over the width set `allowed`, generator 3 stamped and the era bytes recorded + (`docs/plans/era-layout.md`). + 856 | /// The chain's path is this with `base = V3_CLASS` and `allowed = V3_ALLOWED`. + 857 | pub fn generate_era(seed_string: &str, seed_bytes: &[u8], base: LoadClass, era_bytes: + &[u8], allowed: &[u8]) -> Program { + 858 | generate_era_generator(seed_string, seed_bytes, base, era_bytes, allowed, + era_generator_of(&base)) + + + +igneum-pow-src/generator.rs:124-147 + + + 124 | /// An injecting op: bijective in `dst` and bringing another register (or the + dataset) in. The acceptance + 125 | /// rule's part (b) requires one such write per register. + 126 | pub fn injects(self) -> bool { + 127 | matches!(self, Op::Add | Op::Sub | Op::Xor | Op::Mad | Op::Shfl | Op::Load | + Op::WLoad | Op::Scratch | Op::Hot) + 128 | } + 129 | + 130 | /// A memory operation: the fresh-source rule, the acceptance tests and the load + count treat the scratch + 131 | /// read-modify-write and the hot-table load as loads (each is one of the + program's 128 memory operations). + 132 | pub fn is_load(self) -> bool { + 133 | matches!(self, Op::Load | Op::WLoad | Op::Scratch | Op::Hot) + 134 | } + 135 | } + 136 | + 137 | /// One instruction. Every field is drawn for every instruction whether the op uses + it or not, so the + 138 | /// draw stream is identical for every op. + 139 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] + 140 | pub struct Instr { + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 7 + +MASTER 277 / 292 + R0 / SOURCE REVIEW + + + + + 141 | pub op: Op, + 142 | /// Destination register 0..7. + 143 | pub dst: u8, + 144 | /// Source register 0..7, never equal to `dst`. + 145 | pub src: u8, + 146 | /// Second source (mad only). + 147 | pub src2: u8, + + + +igneum-pow-src/generator.rs:1049-1065 + + + 1049 | /// The program id: FNV-1a 64 over `"igneum-program/" || generator_le32 || seed + words as little-endian bytes + 1050 | /// || attempt_le32`. Written into every pack so a version 1 program, or another + attempt of the same seed, + 1051 | /// can never be mistaken for this one. + 1052 | pub fn program_id(&self) -> u64 { + 1053 | // Latency ladder (docs/design/latency-ladder.md section 7): a class v4 + program above rung 0 carries its shadow + 1054 | // size in the id (`program_id_class`, the "shadow/" bytes), so two rungs of + one seed never share an id and a + 1055 | // pack of another rung is refused as a pack of another class is. Rung 0 + keeps `program_id(4, seed, attempt)` + 1056 | // byte for byte, so every v4 id written before the ladder stands. + 1057 | let v4_rung_0 = self.generator == GENERATOR_VERSION_V4 && LoadClass { era: + None, ..self.class } == V4_CLASS; + 1058 | if self.class.is_v2() || self.generator == GENERATOR_VERSION_V3 || v4_rung_0 + { + 1059 | // Spec 01 section 1.4.6: a class v3 program's id is `program_id(3, seed, + attempt)`, a class v4 program's + 1060 | // `program_id(4, seed, attempt)` (Counter ASIC 3.0); the generator + version in the preimage separates + 1061 | // them from every version 2 program of the same seed + 1062 | program_id(self.generator, &self.seed, self.attempt) + 1063 | } else { + 1064 | program_id_class(self.generator, &self.seed, self.attempt, &self.class) + 1065 | } + + + +igneum-pow-src/generator.rs:1266-1310 + + + 1266 | eligible[rng.below(n as u64) as usize] + 1267 | } + 1268 | } else { + 1269 | let a = rng.below(7); + 1270 | if a >= dst { + 1271 | a + 1 + 1272 | } else { + 1273 | a + 1274 | } + 1275 | }; + 1276 | let b = rng.below(8); + 1277 | let imm = rng.next() as u32; + 1278 | let imm2 = rng.next() as u32; + 1279 | let rot = 1 + rng.below(31) as u32; + 1280 | let bit = rng.below(32); + 1281 | let mask = 1u8 << rng.below(5); + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 8 + +MASTER 278 / 292 + R0 / SOURCE REVIEW + + + + + 1282 | // Version 2 loads take no width roll, so a mixer class with version 2 loads + draws the version 2 program + 1283 | let width = if class.takes_width_roll() { + class.width_for_roll(rng.below(100)) } else { 1 }; + 1284 | let width = if op == Op::Load { width } else { 1 }; + 1285 | // Era layout, layer 8: two window draws per instruction (drawn on every + slot, used on a load slot). + 1286 | let (win, off) = if class.era.is_some() { + 1287 | let k = rng.below(3) as u8; + 1288 | let o = (rng.next() as u32 & ((1u32 << k) - 1)) as u8; + 1289 | if op == Op::Load { + 1290 | (k, o) + 1291 | } else { + 1292 | (0, 0) + 1293 | } + 1294 | } else { + 1295 | (0, 0) + 1296 | }; + 1297 | if op.is_load() { + 1298 | fresh[src as usize] = false; + 1299 | } + 1300 | fresh[dst as usize] = true; + 1301 | instrs.push(Instr { op, dst: dst as u8, src: src as u8, src2: b as u8, imm, + imm2, rot, bit: bit as u8, mask, width, win, off }); + 1302 | } + 1303 | // (3) The latency-shadow block (Counter ASIC 3.0 item 8): drawn after the base + program from the same stream, so + 1304 | // the 64 instructions above are the class's without the shadow, draw for draw. + Every slot is an ALU slot: the + 1305 | // op from the non-load table, the source as on an ALU slot, the same + per-instruction draws (the width roll and + 1306 | // the era windows included when the class takes them, drawn and ignored) so the + stream shape is the program's. + 1307 | let mut shadow = Vec::new(); + 1308 | if let Some(sh) = class.shadow { + 1309 | for _ in 0..sh.instrs { + 1310 | let mut roll = rng.below(75); + + + +igneum-pow-src/generator.rs:1377-1404 + + + 1377 | /// The program of a seed: the first accepted candidate over attempts `0, 1, 2, ...`, + at most [`MAX_ATTEMPTS`]. + 1378 | /// This is what the chain calls (`Epoch::from_seed_bytes`) with the 32-byte epoch + seed, and what the packs call + 1379 | /// with the UTF-8 of a seed string. + 1380 | pub fn try_generate_from_seed_bytes(seed_string: &str, seed_bytes: &[u8]) -> + Result { + 1381 | try_generate_class(seed_string, seed_bytes, LoadClass::V2) + 1382 | } + 1383 | + 1384 | /// [`try_generate_from_seed_bytes`] for a load class. + 1385 | pub fn try_generate_class(seed_string: &str, seed_bytes: &[u8], class: LoadClass) -> + Result { + 1386 | let mut last = None; + 1387 | for attempt in 0..MAX_ATTEMPTS { + 1388 | let p = candidate_class(seed_string, seed_bytes, attempt, class); + 1389 | match check(&p) { + 1390 | Ok(_) => return Ok(p), + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 9 + +MASTER 279 / 292 + R0 / SOURCE REVIEW + + + + + 1391 | Err(r) => last = Some(r), + 1392 | } + 1393 | } + 1394 | Err(Exhausted { seed_string: seed_string.to_string(), attempts: MAX_ATTEMPTS, + last: last.unwrap() }) + 1395 | } + 1396 | + 1397 | /// [`try_generate_from_seed_bytes`], treating exhaustion as the consensus fault it + is. + 1398 | pub fn generate_from_seed_bytes(seed_string: &str, seed_bytes: &[u8]) -> Program { + 1399 | try_generate_from_seed_bytes(seed_string, seed_bytes).unwrap_or_else(|e| + panic!("{e}")) + 1400 | } + 1401 | + 1402 | /// [`generate_from_seed_bytes`] for a load class. + 1403 | pub fn generate_from_seed_bytes_class(seed_string: &str, seed_bytes: &[u8], class: + LoadClass) -> Program { + 1404 | try_generate_class(seed_string, seed_bytes, class).unwrap_or_else(|e| + panic!("{e}")) + + + +igneum-pow-src/accept.rs:178-205 + + + 178 | /// Returns the first lane-constant load site, if any. + 179 | fn run_unit(p: &Program, unit: usize, base: u32, acc: &mut Acc, lane_addrs: &mut + [u32]) -> Result<(), Reject> { + 180 | let seed = &p.seed; + 181 | let mask: u32 = (1u32 << ACCEPT_DATASET_LOG2) - 1; + 182 | let (d0, d1) = (seed[0], seed[1]); + 183 | let (h0, h1) = (seed[2], seed[3]); + 184 | let hot_words = p.hot_words(); + 185 | let loads = p.loads_per_hash(); + 186 | let mut r = [[0u32; LANES]; 8]; + 187 | for lane in 0..LANES { + 188 | let nonce = base.wrapping_add(lane as u32); + 189 | for i in 0..8 { + 190 | let mut x = nonce ^ seed[i]; + 191 | x = x.wrapping_add(0x9e3779b9u32.wrapping_mul(i as u32 + 1)); + 192 | x = splitmix32(x); + 193 | r[i][lane] = x ^ seed[(i + 1) & 7]; + 194 | } + 195 | } + 196 | let mut idx = [0u32; LANES]; + 197 | let mut nload = 0usize; + 198 | let mut scratch = if p.has_scratch() { + Some(ScratchModel::new(p.class.scratch_slots_per_lane())) } else { None }; + 199 | let slot_mask = p.class.scratch_slot_mask(); + 200 | let era = p.class.era; + 201 | for it in 0..ITERATIONS { + 202 | let sel = r[0]; + 203 | for (k, ins) in p.instrs.iter().enumerate() { + 204 | let d = ins.dst as usize; + 205 | let a = ins.src as usize; + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 10 + +MASTER 280 / 292 + R0 / SOURCE REVIEW + + + + +igneum-pow-src/accept.rs:276-317 + + + 276 | for lane in 0..LANES { + 277 | r[d][lane] = + src[lane].wrapping_mul(src2[lane]).wrapping_add(r[d][lane]); + 278 | } + 279 | } + 280 | Op::Shfl => { + 281 | let src = r[a]; + 282 | let m = ins.mask as usize; + 283 | for lane in 0..LANES { + 284 | r[d][lane] ^= src[lane ^ m]; + 285 | } + 286 | } + 287 | Op::Load => { + 288 | // Read-width experiment: a load of `width` words reads from the + aligned address and folds every + 289 | // word (verify::fold_words); width 1 is the lottery hash's xor + of one word. + 290 | let width = ins.width as usize; + 291 | let align = !(ins.width as u32 - 1); + 292 | for lane in 0..LANES { + 293 | idx[lane] = load_index(era.as_ref(), ins, r[a][lane], mask, + ACCEPT_DATASET_LOG2) & align; + 294 | } + 295 | if idx.iter().all(|&x| x == idx[0]) { + 296 | return Err(Reject::LaneConstantSite { iteration: it as u8, + instr: k as u8, unit: unit as u8 }); + 297 | } + 298 | for lane in 0..LANES { + 299 | if width == 1 { + 300 | r[d][lane] ^= dataset_elem(idx[lane], d0, d1); + 301 | } else { + 302 | let mut w = [0u32; 16]; + 303 | for j in 0..width { + 304 | w[j] = dataset_elem(idx[lane] + j as u32, d0, d1); + 305 | } + 306 | r[d][lane] = fold_words(r[d][lane], &w[..width]); + 307 | } + 308 | lane_addrs[lane * loads + nload] = idx[lane]; + 309 | } + 310 | nload += 1; + 311 | } + 312 | Op::Hot => { + 313 | // Hot table: the stand-in is dataset_elem keyed by seed words 2 + and 3; the address is tagged with + 314 | // bit 30 so a hot word and a dataset word at one index count as + two addresses. + 315 | for lane in 0..LANES { + 316 | idx[lane] = hot_index(r[a][lane], hot_words); + 317 | } + + + +igneum-pow-src/accept.rs:327-404 + + + 327 | Op::WLoad => { + 328 | let b = (r[a][0] & mask) & !31; + 329 | for lane in 0..LANES { + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 11 + +MASTER 281 / 292 + R0 / SOURCE REVIEW + + + + + 330 | idx[lane] = b + lane as u32; + 331 | r[d][lane] ^= dataset_elem(idx[lane], d0, d1); + 332 | lane_addrs[lane * loads + nload] = idx[lane]; + 333 | } + 334 | nload += 1; + 335 | } + 336 | } + 337 | } + 338 | } + 339 | for i in 0..8 { + 340 | for lane in 0..LANES { + 341 | let v = r[i][lane]; + 342 | acc.and_acc[i] &= v; + 343 | acc.or_acc[i] |= v; + 344 | acc.saturated += (v == 0 || v == u32::MAX) as u32; + 345 | } + 346 | } + 347 | for lane in 0..LANES { + 348 | let lo = r[0][lane] ^ r[1][lane].rotate_left(7) ^ r[2][lane].rotate_left(14) + ^ r[3][lane].rotate_left(21); + 349 | let hi = r[4][lane] ^ r[5][lane].rotate_left(9) ^ r[6][lane].rotate_left(18) + ^ r[7][lane].rotate_left(27); + 350 | let h = ((hi as u64) << 32) | lo as u64; + 351 | for j in 0..64 { + 352 | acc.bit_ones[j] += ((h >> j) & 1) as u32; + 353 | } + 354 | let sl = &mut lane_addrs[lane * loads..(lane + 1) * loads]; + 355 | sl.sort_unstable(); + 356 | let mut distinct = 0u64; + 357 | for k in 0..loads { + 358 | // scratch slots carry bit 31 (variant 5) and are not dataset addresses + 359 | if sl[k] & 0x8000_0000 == 0 && (k == 0 || sl[k] != sl[k - 1]) { + 360 | distinct += 1; + 361 | } + 362 | } + 363 | acc.distinct_sum += distinct; + 364 | } + 365 | Ok(()) + 366 | } + 367 | + 368 | /// Part (c). + 369 | pub fn check_dynamic(p: &Program) -> Result { + 370 | let loads = p.loads_per_hash(); + 371 | let mut acc = Acc { and_acc: [u32::MAX; 8], or_acc: [0; 8], saturated: 0, + bit_ones: [0; 64], distinct_sum: 0 }; + 372 | let mut lane_addrs = vec![0u32; LANES * loads]; + 373 | for (unit, &base) in accept_base_nonces(&p.seed).iter().enumerate() { + 374 | run_unit(p, unit, base, &mut acc, &mut lane_addrs)?; + 375 | } + 376 | for reg in 0..8 { + 377 | let bits = (acc.and_acc[reg] | !acc.or_acc[reg]).count_ones(); + 378 | if bits != 0 { + 379 | return Err(Reject::ConstantBit { reg: reg as u8, bits: bits as u8 }); + 380 | } + 381 | } + 382 | if acc.saturated >= MAX_SATURATED { + 383 | return Err(Reject::Saturated { count: acc.saturated }); + 384 | } + 385 | let half = (ACCEPT_HASHES / 2) as u32; + 386 | let mut bias_max = 0u32; + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 12 + +MASTER 282 / 292 + R0 / SOURCE REVIEW + + + + + 387 | for (bit, &ones) in acc.bit_ones.iter().enumerate() { + 388 | let d = ones.abs_diff(half); + 389 | if d > BIAS_TOLERANCE { + 390 | return Err(Reject::OutputBias { bit: bit as u8, ones }); + 391 | } + 392 | bias_max = bias_max.max(d); + 393 | } + 394 | if acc.distinct_sum <= min_distinct_sum(loads - p.scratch_ops_per_hash()) { + 395 | return Err(Reject::DistinctAddresses { sum: acc.distinct_sum }); + 396 | } + 397 | Ok(AcceptReport { distinct_sum: acc.distinct_sum, saturated: acc.saturated, + bias_max }) + 398 | } + 399 | + 400 | /// The whole rule: (a), (b), then (c). + 401 | pub fn check(p: &Program) -> Result { + 402 | check_static(p)?; + 403 | check_dynamic(p) + 404 | } + + + +igneum-pow-src/verify.rs:335-398 + + + 335 | pub fn interpret_warp_scratch( + 336 | program: &Program, + 337 | seed: &[u32; 8], + 338 | base_nonce: u32, + 339 | ds: &DatasetSource, + 340 | trace: bool, + 341 | ) -> (WarpResult, Vec) { + 342 | let mask = ds.mask; + 343 | let log2 = ds.log2_words; + 344 | let era = program.class.era; + 345 | let layout = program.class.layout(); + 346 | let mut r = [[0u32; LANES]; 8]; + 347 | for lane in 0..LANES { + 348 | let nonce = base_nonce.wrapping_add(lane as u32); + 349 | for i in 0..8 { + 350 | let mut x = nonce ^ seed[i]; + 351 | x = x.wrapping_add(0x9e3779b9u32.wrapping_mul(i as u32 + 1)); + 352 | x = splitmix32(x); + 353 | r[i][lane] = x ^ seed[(i + 1) & 7]; + 354 | } + 355 | } + 356 | let mut items_derived = 0usize; + 357 | let mut idx = [0u32; LANES]; + 358 | let mut val = [0u32; LANES]; + 359 | let mut scratch = if program.has_scratch() { + Some(ScratchModel::new(program.class.scratch_slots_per_lane())) } else { None }; + 360 | if trace { + 361 | if let Some(m) = scratch.as_mut() { + 362 | m.trace = Some(Vec::new()); + 363 | } + 364 | } + 365 | let slot_mask = program.class.scratch_slot_mask(); + 366 | if program.has_hot() { + 367 | let h = ds.hot.as_ref().expect("a hot-table program needs the epoch's hot + table on the dataset source"); + 368 | assert_eq!(h.n_words(), program.hot_words(), "the hot table's size is the + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 13 + +MASTER 283 / 292 + R0 / SOURCE REVIEW + + + + + class's"); + 369 | } + 370 | for _ in 0..ITERATIONS { + 371 | let sel = r[0]; + 372 | for ins in &program.instrs { + 373 | step(ins, &mut r, &sel, mask, log2, era.as_ref(), layout, ds, &mut idx, + &mut val, &mut items_derived); + 374 | if ins.op == Op::Scratch { + 375 | let m = scratch.as_mut().expect("a scratch op needs a scratch + class"); + 376 | let (d, a) = (ins.dst as usize, ins.src as usize); + 377 | for lane in 0..LANES { + 378 | let slot = r[a][lane] & slot_mask; + 379 | r[d][lane] = m.rmw(&program.seed, base_nonce, lane, slot, + r[d][lane]); + 380 | } + 381 | } + 382 | } + 383 | // Latency-shadow block (Counter ASIC 3.0 item 8): the block runs `reps` + times after instruction 63 with the + 384 | // iteration's `sel`; it is empty on every class without a shadow, so version + 2 and class v3 run nothing here. + 385 | for _ in 0..program.shadow_reps() { + 386 | for ins in &program.shadow { + 387 | step(ins, &mut r, &sel, mask, log2, era.as_ref(), layout, ds, &mut + idx, &mut val, &mut items_derived); + 388 | } + 389 | } + 390 | } + 391 | let mut hashes = [0u64; LANES]; + 392 | for lane in 0..LANES { + 393 | let lo = r[0][lane] ^ r[1][lane].rotate_left(7) ^ r[2][lane].rotate_left(14) + ^ r[3][lane].rotate_left(21); + 394 | let hi = r[4][lane] ^ r[5][lane].rotate_left(9) ^ r[6][lane].rotate_left(18) + ^ r[7][lane].rotate_left(27); + 395 | hashes[lane] = ((hi as u64) << 32) | lo as u64; + 396 | } + 397 | let events = scratch.and_then(|m| m.trace).unwrap_or_default(); + 398 | (WarpResult { hashes, items_derived }, events) + + + +igneum-pow-src/seed.rs:34-49 + + + 34 | + 35 | /// The 32-byte seed (8 x u32) from arbitrary bytes: FNV-1a 64 with four salts, each + finalised with the + 36 | /// murmur-style mix `h ^= h >> 33; h *= 0xff51afd7ed558ccd; h ^= h >> 33`; low word + then high word. + 37 | pub fn seed_words_from_bytes(bytes: &[u8]) -> [u32; 8] { + 38 | let mut words = [0u32; 8]; + 39 | for salt in 0..4u64 { + 40 | let basis = 0xcbf29ce484222325u64 ^ salt.wrapping_mul(0x9E3779B97F4A7C15); + 41 | let mut h = fnv1a64_with_basis(basis, bytes); + 42 | h ^= h >> 33; + 43 | h = h.wrapping_mul(0xff51afd7ed558ccd); + 44 | h ^= h >> 33; + 45 | words[2 * salt as usize] = h as u32; + 46 | words[2 * salt as usize + 1] = (h >> 32) as u32; + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 14 + +MASTER 284 / 292 + R0 / SOURCE REVIEW + + + + + 47 | } + 48 | words + 49 | } + + + +igneum-pow-src/bind.rs:47-83 + + + 47 | /// `"igneum-block/" || H || nonce_hi_le32`, the bytes the init words are derived + from. + 48 | pub fn block_init_bytes(header_prehash: &[u8; 32], nonce: u64) -> [u8; 49] { + 49 | let mut b = [0u8; 49]; + 50 | b[..13].copy_from_slice(BLOCK_TAG); + 51 | b[13..45].copy_from_slice(header_prehash); + 52 | b[45..49].copy_from_slice(&nonce_hi(nonce).to_le_bytes()); + 53 | b + 54 | } + 55 | + 56 | /// The init words `I` for a header and a 64-bit nonce (only the high 32 bits of the + nonce matter). + 57 | pub fn block_init_words(header_prehash: &[u8; 32], nonce: u64) -> [u32; 8] { + 58 | seed_words_from_bytes(&block_init_bytes(header_prehash, nonce)) + 59 | } + 60 | + 61 | /// Interim day seed bytes: `"igneum-day/" || day_le64`. + 62 | pub fn day_bytes(day_index: u64) -> [u8; 19] { + 63 | let mut b = [0u8; 19]; + 64 | b[..11].copy_from_slice(DAY_TAG); + 65 | b[11..19].copy_from_slice(&day_index.to_le_bytes()); + 66 | b + 67 | } + 68 | + 69 | /// Day index of a header timestamp in milliseconds. + 70 | #[inline] + 71 | pub fn day_index(timestamp_ms: u64) -> u64 { + 72 | timestamp_ms / DAY_MS + 73 | } + 74 | + 75 | /// The 256-bit pow value as little-endian bytes: the lane hash in bytes 24..32, zero + elsewhere. + 76 | pub fn pow256_from_lane(lane: u64) -> [u8; 32] { + 77 | let mut b = [0u8; 32]; + 78 | b[24..32].copy_from_slice(&lane.to_le_bytes()); + 79 | b + 80 | } + 81 | + 82 | /// The 64-bit target from a little-endian 256-bit target: its top 64 bits. + 83 | pub fn target64_from_le256(target: &[u8; 32]) -> u64 { + + + +igneum-pow-src/bind.rs:99-119 + + + 99 | + 100 | impl Epoch { + 101 | /// The 32 bound hashes of the aligned warp that contains `nonce`: lane `l` is + the hash of + 102 | /// `(nonce_hi << 32) | ((lane_nonce & !31) + l)`. + 103 | pub fn hash_warp_bound(&self, header_prehash: &[u8; 32], nonce: u64) -> [u64; + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 15 + +MASTER 285 / 292 + R0 / SOURCE REVIEW + + + + + LANES] { + 104 | self.interpret_warp_bound(header_prehash, nonce).hashes + 105 | } + 106 | + 107 | pub fn interpret_warp_bound(&self, header_prehash: &[u8; 32], nonce: u64) -> + WarpResult { + 108 | let init = block_init_words(header_prehash, nonce); + 109 | interpret_warp_init(&self.program, &init, lane_nonce(nonce) & !31, + &self.dataset) + 110 | } + 111 | + 112 | /// The 32 bound hashes for already-derived init words (what a GPU worker + computes per dispatch). + 113 | pub fn hash_warp_init(&self, init: &[u32; 8], base_lane_nonce: u32) -> [u64; + LANES] { + 114 | interpret_warp_init(&self.program, init, base_lane_nonce, + &self.dataset).hashes + 115 | } + 116 | + 117 | /// The bound 64-bit lane hash of one header nonce. + 118 | pub fn hash_bound(&self, header_prehash: &[u8; 32], nonce: u64) -> u64 { + 119 | self.hash_warp_bound(header_prehash, nonce)[(lane_nonce(nonce) & 31) as + usize] + + + +igneum-pow-src/emit.rs:1219-1243 + + + 1219 | s.push_str(&format!("__global__ void igneum_hash_bound(const uint32_t* ds, + uint64_t* out, uint32_t baseNonce, uint32_t mask, IgneumInitWords + iw{hot_args}{scratch_args}) {{\n")); + 1220 | if p.has_scratch() { + 1221 | s.push_str(&persistent_prologue(CoreDialect::Cuda, + p.class.scratch_words_per_lane())); + 1222 | } else { + 1223 | s.push_str(" uint32_t gid = blockIdx.x * blockDim.x + threadIdx.x;\n"); + 1224 | } + 1225 | s.push_str(" uint32_t nonce = baseNonce + gid;\n"); + 1226 | s.push_str(" uint32_t r0, r1, r2, r3, r4, r5, r6, r7;\n"); + 1227 | if p.has_wide() { + 1228 | s.push_str(" uint32_t lane = threadIdx.x & 31u;\n uint32_t wmask = mask + & ~31u;\n"); + 1229 | } + 1230 | for i in 0..8 { + 1231 | s.push_str(&format!( + 1232 | " {{ uint32_t x = nonce ^ iw.w[{i}]; x += 0x9e3779b9u * {}u; x = + splitmix32(x); r{i} = x ^ iw.w[{}]; }}\n", + 1233 | i + 1, + 1234 | (i + 1) & 7 + 1235 | )); + 1236 | } + 1237 | s.push_str(&format!("\n for (uint32_t it = 0u; it < {ITERATIONS}u; ++it) {{\n + uint32_t sel = r0;\n")); + 1238 | s.push_str(&cuda_instr_lines(p, dataset_log2)); + 1239 | s.push_str(&shadow_block(p, CoreDialect::Cuda)); + 1240 | s.push_str(" }\n"); + 1241 | s.push_str(" uint32_t lo = r0 ^ rotl_imm(r1, 7u) ^ rotl_imm(r2, 14u) ^ + rotl_imm(r3, 21u);\n"); + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 16 + +MASTER 286 / 292 + R0 / SOURCE REVIEW + + + + + 1242 | s.push_str(" uint32_t hi = r4 ^ rotl_imm(r5, 9u) ^ rotl_imm(r6, 18u) ^ + rotl_imm(r7, 27u);\n"); + 1243 | s.push_str(" out[gid] = ((uint64_t)hi << 32) | (uint64_t)lo;\n"); + + + +igneum-pow-src/emit.rs:1260-1270 + + + 1260 | } else { + 1261 | s.push_str( + 1262 | "cudaError_t igneum_launch_hash_bound(const uint32_t* ds, uint64_t* out, + uint32_t baseNonce, uint32_t mask,\n", + 1263 | ); + 1264 | s.push_str(&format!(" IgneumInitWords + iw,{hot_decl} uint32_t nonces, uint32_t blockWarps) {{\n")); + 1265 | s.push_str(" if (blockWarps == 0u || blockWarps > 32u) return + cudaErrorInvalidValue;\n"); + 1266 | s.push_str(" uint32_t block = 32u * blockWarps;\n"); + 1267 | s.push_str(" if (nonces == 0u || (nonces % block) != 0u) return + cudaErrorInvalidValue;\n"); + 1268 | s.push_str(&format!(" igneum_hash_bound<<>>(ds, + out, baseNonce, mask, iw{hot_pass});\n")); + 1269 | s.push_str(" return cudaGetLastError();\n"); + 1270 | s.push_str("}\n"); + + + +igneum-pow-src/packcheck.rs:166-185 + + + 166 | + 167 | /// [`verify_pack_texts`] that also demands a program class and, for class v3 and v4, + the era seed the chain is on + 168 | /// (Counter ASIC 2.0, 5 October 2026; class v4 Counter ASIC 3.0, 6 October 2026). + `want_class` `None` accepts any + 169 | /// class; `want_era` `None` skips the era. A pack whose `IGNEUM_GENERATOR` is not 2, + 3 or 4 is refused whatever is wanted. + 170 | pub fn verify_pack_texts_chain( + 171 | program_h: &str, + 172 | seeds_txt: Option<&str>, + 173 | want_epoch: &[u8], + 174 | want_day: &[u8], + 175 | want_class: Option, + 176 | want_era: Option<&[u8]>, + 177 | ) -> Result { + 178 | let generator = define_u32(program_h, "IGNEUM_GENERATOR").unwrap_or(1); + 179 | let Some(class) = ProgramClass::from_generator(generator) else { + 180 | return Err(PackFault::WrongClass(format!("IGNEUM_GENERATOR {generator} is not + a generator version this software runs (2, 3 or 4)"))); + 181 | }; + 182 | // IGNEUM_PROGRAM_CLASS, when present, must name the class the generator version + names + 183 | if let Some(named) = define_str(program_h, "IGNEUM_PROGRAM_CLASS") { + 184 | if ProgramClass::parse(&named) != Some(class) { + 185 | return Err(PackFault::Disagree(format!("IGNEUM_PROGRAM_CLASS {named:?} + does not match IGNEUM_GENERATOR {generator}"))); + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 17 + +MASTER 287 / 292 + R0 / SOURCE REVIEW + + + + +igneum-pow-src/packcheck.rs:208-225 + + + 208 | if let (Some(want), true) = (want_era, class.has_era()) { + 209 | let want_hex = hex(want); + 210 | match &era_hex { + 211 | Some(h) if *h == want_hex => {} + 212 | Some(h) => return Err(PackFault::WrongClass(format!("the pack's era seed + {} is not the era seed {} the job names", short(h), short(&want_hex)))), + 213 | None => return Err(PackFault::WrongClass(format!("a class {} pack without + IGNEUM_ERA_SEED_HEX; the job names an era seed", class.name()))), + 214 | } + 215 | } + 216 | let seedw = define_words(program_h, "IGNEUM_SEEDW_INIT").ok_or_else(|| + PackFault::Unreadable("program.h has no IGNEUM_SEEDW_INIT with 8 words".into()))?; + 217 | let keyw = define_words(program_h, "IGNEUM_KEY_INIT").ok_or_else(|| + PackFault::Unreadable("program.h has no IGNEUM_KEY_INIT with 8 words".into()))?; + 218 | let attempt = define_u32(program_h, "IGNEUM_PROGRAM_ATTEMPT").unwrap_or(0); + 219 | let mut epoch_hex = define_str(program_h, + "IGNEUM_SEED_BYTES_HEX").unwrap_or_default(); + 220 | let mut day_hex = define_str(program_h, + "IGNEUM_DAY_BYTES_HEX").unwrap_or_default(); + 221 | if let Some(s) = seeds_txt { + 222 | let e = seeds_line(s, "epoch_seed_hex").ok_or_else(|| + PackFault::Unreadable("seeds.txt has no epoch_seed_hex line".into()))?; + 223 | let d = seeds_line(s, "day_seed_hex").ok_or_else(|| + PackFault::Unreadable("seeds.txt has no day_seed_hex line".into()))?; + 224 | if !epoch_hex.is_empty() && !epoch_hex.eq_ignore_ascii_case(&e) { + 225 | return Err(PackFault::Disagree(format!("seeds.txt names epoch {} but + program.h was generated for epoch {} (a pack half rewritten?)", short(&e), + short(&epoch_hex)))); + + + +igneum-pow-src/packcheck.rs:263-272 + + + 263 | pub fn verify_pack_dir(dir: &Path, want_epoch: &[u8], want_day: &[u8]) -> + Result { + 264 | verify_pack_dir_chain(dir, want_epoch, want_day, None, None) + 265 | } + 266 | + 267 | /// [`verify_pack_texts_chain`] over a pack directory. + 268 | pub fn verify_pack_dir_chain(dir: &Path, want_epoch: &[u8], want_day: &[u8], + want_class: Option, want_era: Option<&[u8]>) -> Result { + 269 | let program_h = std::fs::read_to_string(dir.join("program.h")).map_err(|e| + PackFault::Unreadable(format!("cannot read {}/program.h: {e}", dir.display())))?; + 270 | let seeds = std::fs::read_to_string(dir.join("seeds.txt")).ok(); + 271 | verify_pack_texts_chain(&program_h, seeds.as_deref(), want_epoch, want_day, + want_class, want_era) + 272 | } + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 18 + +MASTER 288 / 292 + E / PRESERVATION + + + + +The exact evidence travels with it. +The readable master contains the complete plan, complete acceptance standard and all three review +reports, including their detailed source excerpts. The original machine-readable files and reviewed +archives are embedded as PDF attachments and provided in the companion ZIP. + +Some browser viewers do not expose PDF attachments. Use the companion ZIP or the attachments panel +of a compatible desktop PDF reader. These files are inert attachments; this edition does not execute their +scripts. + + + INCLUDED ASSET FAMILY PURPOSE + + + + Preserve exact original wording and source citations independently of + Original text and review Markdown + typesetting. + + + Retain every original case, profile, observation, qualification and raw + Test / finding / result JSON + machine record. + + + Retain the code and instructions underlying the earlier diagnostic reports; + Three reproduction archives + not a claim of native system validation. + + + Retain the earlier algorithm and five updated stack bundles for + Six reviewed source ZIPs + reproducibility. Repeated uploads are not duplicated. + + + Index the base tests, additive closures, related findings and exact included + Master traceability and manifest + file hashes. + + + + + SCOPE AND LIMITATIONS + + + The source ZIPs are preserved for review, not certified builds. No new code execution, + hardware measurement, external-source verification, code fix or deployment occurred + during document production. + + + +Original source fonts are used only inside the rendered documents and are not redistributed as font files. + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 1 + +MASTER 289 / 292 + EVIDENCE INVENTORY + + + + +E / SHA-256 INVENTORY + + + + +Asset manifest 1 +IGNEUM 2.0.rtf +Original supplied strategy text · 28,017 bytes + +00ca1ec477aef0e967eadd6652a35355e17a1346d42396afec202fc99abb4475 + + +IGNEUM_2.0_Test_Registry.json +128 original cases and 17 proposed profiles · 204,778 bytes + +573e0df9b4449d877eaf420279a53eef4497d3d9c67e12e62da7bd5e253a0417 + + +IGNEUM_Algorithm_Review_Evidence.md +Exact R0 source · 45,434 bytes + +fe6f4c9242574cadbd88e769d4e2c17bbc81c027e8a5fca9599dbf452078d77d + + +IGNEUM_Algorithm_Review_Results.json +Exact original observations and manifest · 82,485 bytes + +6a529f0ec8488669cfb3a8a5f702da73a092a1947a9280e7ec31d582b041d206 + + +IGNEUM_Algorithm_Review_Harness.zip +Original runnable diagnostic harness · 42,759 bytes + +566d12f1bb67c99cda2c47a7c6eb4616479da80d320925979ff0052c5784cab5 + + +IGNEUM_V6_Full_System_Review.md +Exact R1 source · 210,161 bytes + +1e62d89f743c3c3d4525f6321c53c05025e628080face878d82ff2f93ceb0213 + +Hashes computed over the included original files. The master traceability JSON is newly assembled; the source reports and +recorded results are unchanged. + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 2 + +MASTER 290 / 292 + EVIDENCE INVENTORY + + + + +E / SHA-256 INVENTORY + + + + +Asset manifest 2 +IGNEUM_V6_Full_System_Review_Results.json +Exact R1 recorded outputs · 15,353 bytes + +44c4931c657aac530f95f1a6d183943f817fd6f022afab2495555b4a1ece8c03 + + +IGNEUM_V6_Full_System_Review_Harness.zip +R1 original harness and source guards · 95,385 bytes + +13fb83611921df0b1d3d7ed9f25bea4d2af404d6aa3f55fbf578e4bc5fad9261 + + +IGNEUM_Updated_Stack_Review.md +Exact R2 source · 163,364 bytes + +3734c1d09075421976e5872baee7c00abe00d1e0a062ad56dded4a05df002a87 + + +IGNEUM_Updated_Stack_Findings.json +All 14 R2 findings, 44 closure requirements and outputs · 43,073 bytes + +9809e8284cdf841e051c6db4494af7e24159c96aa25e6c71635b411f9fac3b3e + + +IGNEUM_Updated_Stack_Reproductions.zip +R2 original reproduction pack · 16,657 bytes + +21f8bbf15a12aa4836f16464fa0af7fab1e789d4bbacc331234c6f634dfdca9a + + +IGNEUM_2.0_Master_Traceability.json +Original registry plus namespaced add-ons and mapping · 271,435 bytes + +7ebf8d60cf0e4e3889ab5472b5b4f807d791739ef62f91ffaa74236792a4810e + +Hashes computed over the included original files. The master traceability JSON is newly assembled; the source reports and +recorded results are unchanged. + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 3 + +MASTER 291 / 292 + EVIDENCE INVENTORY + + + + +E / SHA-256 INVENTORY + + + + +Asset manifest 3 +igneum-mining-algorithm-2026-10-08.zip +R0 reviewed source archive · 148,136 bytes + +94edb290005ecb8379cc599da90c877c7e25562f727cc4291069b4fbc149c7c1 + + +igneum-v6-freeze-tree-2026-10-08(1).zip +Reviewed v6 freeze archive; one byte-identical copy · 696,492 bytes + +f448981b2ceeab2e59e8bbd137a1a13ea1c730ecd9db72b9a89bd2bbf5d85acb + + +igneum-proving-2026-10-08(1).zip +Reviewed proving archive; one byte-identical copy · 1,612,294 bytes + +9ccf4112e274f586392e8e4a4f98ece2e82b4990fe5f1ee89ae0ee0a151ce01e + + +igneum-ember-2026-10-08(1).zip +Reviewed Ember archive; one byte-identical copy · 78,946 bytes + +c219211b49fccda65b151df230b10ded5971ac2a8c7d1e5847c0a68bffe4cf4a + + +igneum-node-dag-2026-10-08.zip +Reviewed node and DAG source · 1,519,903 bytes + +ead2cf94092b7e27aab2e44d653b2d969cb2a52878ef12abf6e5d7a9e7421cff + + +igneum-mining-workers-2026-10-08.zip +Reviewed workers, engine and pool source · 6,090,014 bytes + +808abcecf157a3716d1c72fa6e76c540bf5808af1c0e4dd0fd888576d546cade + +Hashes computed over the included original files. The master traceability JSON is newly assembled; the source reports and +recorded results are unchanged. + + + + +IGNEUM 2.0 / MASTER EDITION / 08 OCT 2026 4 + +MASTER 292 / 292 + \ No newline at end of file diff --git a/docs/plans/igneum-2.0-master/traceability.json b/docs/plans/igneum-2.0-master/traceability.json new file mode 100644 index 000000000..89e060bb8 --- /dev/null +++ b/docs/plans/igneum-2.0-master/traceability.json @@ -0,0 +1,5341 @@ +{ + "title": "IGNEUM 2.0 - Master traceability register", + "version": "2.0 / consolidated review edition", + "date": "2026-10-08", + "status": "COMPILATION ONLY - NO NEW TECHNICAL TESTS RUN", + "counting_note": "128 original test cases, 18 additional integration gates, 44 updated-stack closure requirements. These sets overlap and are not 190 independent tests. All original 17 proposed profiles remain subject to approval.", + "scope_note": "Preserves the source test definitions and review qualifications; new mappings are editorial, not additional verified findings. No automatic supersession or closure is inferred.", + "original_test_registry": { + "title": "IGNEUM 2.0 - Test and Acceptance Standard", + "version": "1.0", + "date": "2026-10-08", + "status": "PROPOSED - NOT EXECUTED", + "basis": "IGNEUM_2.0_Plan.pdf, 37 pages, 8 October 2026", + "suites": [ + { + "code": "GOV", + "title": "Release identity and evidence", + "source": [ + 5, + 21, + 23, + 25, + 26, + 27 + ], + "gate": "G0 / all gates", + "owner": "Release lead + independent assurance", + "fixtures": "F0 manifest; F1 source/build archives; F9 evidence vault", + "summary": "Prevent a favourable result from being attached to the wrong code, assumptions or public claim.", + "tests": [ + { + "id": "GOV-01", + "title": "Freeze the release and its claims", + "setup": "Candidate source, binaries, public documentation and the 2.0 plan are available; no run is yet accepted.", + "steps": [ + "Record exact commits, binary hashes, dependencies, genesis/network identity, mining class, datasets, execution fork, verifier IDs and fee rules in F0.", + "Map every promised capability and plan requirement to a test ID; distinguish supported mining, proving and wallet combinations.", + "Sign the manifest with protocol, product and independent review owners before confirmatory runs." + ], + "accept": "Every material rule and claim has an unambiguous version and test. Conflicts or unknown activation rules produce BLOCKED, not an inferred default. Changes create a new manifest and invalidate affected results.", + "evidence": "Signed F0; source-to-test map; claim inventory; unresolved-field register.", + "priority": "BLOCKER", + "profile": "P00", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 5, + 21, + 23, + 25, + 26, + 27 + ], + "gate": "G0 / all gates", + "owner": "Release lead + independent assurance", + "manual_page": 18 + }, + { + "id": "GOV-02", + "title": "Approve thresholds before results", + "setup": "This manual supplies proposed test thresholds, not source-approved protocol parameters.", + "steps": [ + "Approve or replace every P-profile before confirmatory testing; give each change a rationale and independent approver.", + "Register hardware cohorts, mandatory economic worlds, customer workloads, peer dimensions and exclusion rules.", + "Lock the profile hash and hold out seeds/workloads from the developers doing optimisation." + ], + "accept": "No decision-critical field is TBD. Numeric limits are frozen, commercially meaningful and not chosen from observed results. A weakened limit after failure requires a new protocol, full affected rerun and explicit claim downgrade review.", + "evidence": "Approved profile register; timestamped holdout commitments; change log.", + "priority": "BLOCKER", + "profile": "P00", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 5, + 21, + 23, + 25, + 26, + 27 + ], + "gate": "G0 / all gates", + "owner": "Release lead + independent assurance", + "manual_page": 18 + }, + { + "id": "GOV-03", + "title": "Reproduce builds outside the founding team", + "setup": "Provide public source and documented build instructions to three unaffiliated operators.", + "steps": [ + "Build on clean declared environments without private files, tokens or founder assistance.", + "Compare reproducible payload hashes; isolate signatures, notarisation and permitted non-deterministic wrappers.", + "Run reference vectors and restart a node using only documented artifacts." + ], + "accept": "All independent builds reproduce the same consensus payload or an independently explained, pre-approved wrapper difference; reference outputs match exactly. Missing private prerequisites block release.", + "evidence": "Build logs; dependency lockfiles; binary comparison; operator attestations.", + "priority": "BLOCKER", + "profile": "P00; P02", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Independent reproduction", + "status": "NOT RUN", + "source": [ + 5, + 21, + 23, + 25, + 26, + 27 + ], + "gate": "G0 / all gates", + "owner": "Release lead + independent assurance", + "manual_page": 18 + }, + { + "id": "GOV-04", + "title": "Preserve raw and negative evidence", + "setup": "Enable append-only storage for run outputs and a separate analysis workspace.", + "steps": [ + "Capture failed, aborted and successful runs with timestamps, seeds and environment hashes.", + "Recompute one published figure from raw records on a clean machine.", + "Modify a retained artifact deliberately and test integrity verification." + ], + "accept": "Every headline can be regenerated; tampering is detected; exclusions have pre-registered reasons. Failed or missing runs remain visible and are never replaced silently by a successful retry.", + "evidence": "Artifact manifest; hashes; reproduction script; exclusion ledger; negative-run archive.", + "priority": "BLOCKER", + "profile": "P00", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 5, + 21, + 23, + 25, + 26, + 27 + ], + "gate": "G0 / all gates", + "owner": "Release lead + independent assurance", + "manual_page": 19 + }, + { + "id": "GOV-05", + "title": "Prove the test oracle detects broken behaviour", + "setup": "Create controlled defective variants on an isolated network only.", + "steps": [ + "Disable proof verification, change one reward, accept an expired authority set and alter one hash output in separate mutants.", + "Run the corresponding ZKP, INC, FIN and POW tests without telling the runner which mutant is active.", + "Confirm the baseline still accepts authorised valid cases." + ], + "accept": "Every deliberately introduced fault is caught by its mapped test; valid controls pass. Any undetected critical mutant blocks acceptance of that test family until the oracle is repaired.", + "evidence": "Mutation catalogue; blinded run results; baseline controls; oracle review.", + "priority": "BLOCKER", + "profile": "P01", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 5, + 21, + 23, + 25, + 26, + 27 + ], + "gate": "G0 / all gates", + "owner": "Release lead + independent assurance", + "manual_page": 19 + }, + { + "id": "GOV-06", + "title": "Enforce scope and optional-feature discipline", + "setup": "Inventory FP32 experiments, receipts/oracles and all retained or excluded mining levers.", + "steps": [ + "Mark each capability CORE, CLAIMED-OPTIONAL or EXCLUDED before release testing.", + "For excluded code, check binaries, protocol activation and product copy for accidental enablement or implied availability.", + "For each claimed option, require the complete associated test set rather than a demonstration." + ], + "accept": "Every core and claimed-option obligation passes. Excluded items are shown as EXCLUDED, never PASS and never counted as achievements. Removing a failed core requirement prevents an all-2.0-pass claim.", + "evidence": "Scope manifest; activation scan; product-copy comparison; exclusions register.", + "priority": "BLOCKER", + "profile": "P00", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 5, + 21, + 23, + 25, + 26, + 27 + ], + "gate": "G0 / all gates", + "owner": "Release lead + independent assurance", + "manual_page": 19 + }, + { + "id": "GOV-07", + "title": "Independent review and finding closure", + "setup": "Nominate reviewers with declared conflicts and scopes covering cryptography, consensus and hardware.", + "steps": [ + "Provide pinned code, raw data, adversarial models and prior failures, including negative results.", + "Track each finding to remediation and an independent retest; do not use the author as sole approver.", + "Have reviewers state unreviewed surfaces and model limitations in their signed conclusions." + ], + "accept": "No unresolved critical or high-severity finding affects the claimed release. A finite review is described by scope, not as proof of universal security. Independent reproduction and review are both evidenced.", + "evidence": "Signed scoped reports; conflict declarations; finding/retest ledger.", + "priority": "BLOCKER", + "profile": "P09", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Independent specialist review", + "status": "NOT RUN", + "source": [ + 5, + 21, + 23, + 25, + 26, + 27 + ], + "gate": "G0 / all gates", + "owner": "Release lead + independent assurance", + "manual_page": 20 + }, + { + "id": "GOV-08", + "title": "Invalidate stale evidence and control public status", + "setup": "Create a simulated post-test change to a verifier, mining class, dataset and fee rule.", + "steps": [ + "Calculate affected test dependencies and invalidate their former PASS statuses.", + "Regenerate public status pages from F0 and the evidence register.", + "Attempt to publish a rank-one, guaranteed-profit or automatic-chip-death claim without the required evidence." + ], + "accept": "Affected gates return to NOT RUN or BLOCKED. Public claims retain version, limits and date; unsupported claims are withheld. No stale result remains attached to a different release.", + "evidence": "Dependency impact report; regenerated status page; rejected claim examples.", + "priority": "BLOCKER", + "profile": "P00", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 5, + 21, + 23, + 25, + 26, + 27 + ], + "gate": "G0 / all gates", + "owner": "Release lead + independent assurance", + "manual_page": 20 + } + ] + }, + { + "code": "GPU", + "title": "Whole-system GPU measurements", + "source": [ + 6, + 7, + 8, + 14, + 18, + 23 + ], + "gate": "G1 / G2", + "owner": "GPU lead + three independent operators", + "fixtures": "F2 retail-hardware cohort; F3 paired benchmark workloads; F9 calibrated evidence", + "summary": "Close the pending measurements and evaluate the actual configuration, including costs hidden by kernel-only results.", + "tests": [ + { + "id": "GPU-01", + "title": "Cover the declared commodity population", + "setup": "Freeze the P02 cohort, supported role matrix and the final v6 configuration.", + "steps": [ + "Inventory physical SKU, usable memory, driver, operating system, firmware, cooling and acquisition channel.", + "Run mining on every supported cohort cell and proving on every separately advertised prover cell.", + "Include lower-memory, used-generation and all advertised vendor cases; retain unsupported results separately." + ], + "accept": "All declared cells are tested, with no after-the-fact removal of weak cards. At least the P02 minimum coverage is met. Mining-only support is never reported as proof-generation support.", + "evidence": "Cohort manifest; compatibility matrix; raw results by SKU and role.", + "priority": "GATE", + "profile": "P02", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 6, + 7, + 8, + 14, + 18, + 23 + ], + "gate": "G1 / G2", + "owner": "GPU lead + three independent operators", + "manual_page": 21 + }, + { + "id": "GPU-02", + "title": "Reproduce Ember clock-lock savings", + "setup": "Use paired stock and tuned runs on the same board, host, workload and ambient conditions.", + "steps": [ + "Warm to stability; randomise stock/tuned order and run P02 repeated sessions.", + "Measure accepted work, calibrated wall energy, device telemetry and rejected work.", + "Calculate paired energy and rate changes with run-level uncertainty, retaining failed tuning attempts." + ], + "accept": "Tuning preserves correctness and meets approved P03 operating limits. The historical 34-41% saving and under-2% rate-loss statement is reproduced only for qualifying configurations; otherwise that claim is corrected. Existing savings are not counted twice.", + "evidence": "Raw power/time series; paired analysis; tuning settings; claim-by-SKU table.", + "priority": "GATE", + "profile": "P02; P03", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 6, + 7, + 8, + 14, + 18, + 23 + ], + "gate": "G1 / G2", + "owner": "GPU lead + three independent operators", + "manual_page": 21 + }, + { + "id": "GPU-03", + "title": "Measure the real 64-register GPU cost", + "setup": "Build the baseline and window variant with identical dataset, reads and semantic workload.", + "steps": [ + "Inspect compiled register allocation, spills, occupancy and memory traffic on each supported backend.", + "Measure paired complete-system energy and accepted throughput, including host work.", + "Repeat during proving coexistence and expose any memory or scheduling cliff." + ], + "accept": "Any production window meets P03 budgets for every mandatory SKU; no hidden spills or correctness changes. Zero GPU cost is claimed only where measurement supports it within uncertainty. Results feed the redesigned adversary, not an old core estimate.", + "evidence": "Compiler reports; allocation traces; paired energy/rate data; coexistence runs.", + "priority": "GATE", + "profile": "P02; P03", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 6, + 7, + 8, + 14, + 18, + 23 + ], + "gate": "G1 / G2", + "owner": "GPU lead + three independent operators", + "manual_page": 21 + }, + { + "id": "GPU-04", + "title": "Find the memory-clock operating ladder", + "setup": "Use safe vendor-supported settings only; record operator permission and original settings.", + "steps": [ + "Sweep approved core and memory operating points while holding workload constant.", + "Measure error rate, accepted throughput, wall energy and thermal equilibrium.", + "Repeat the selected knee after reboot and restore defaults after a failed or interrupted tuning session." + ], + "accept": "Selected profiles are stable, reproducible and not dependent on unsafe clocks. Every accepted hash remains correct; saved settings restore predictably. Tuning failure leaves a working safe configuration.", + "evidence": "Clock ladder; safe bounds; thermal/error logs; reboot and rollback record.", + "priority": "BLOCKER", + "profile": "P01; P02", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 6, + 7, + 8, + 14, + 18, + 23 + ], + "gate": "G1 / G2", + "owner": "GPU lead + three independent operators", + "manual_page": 22 + }, + { + "id": "GPU-05", + "title": "Test dataset fit and support-horizon costs", + "setup": "Test 5.5, 8.5 and 11.5 GiB only as source-proposed candidates; F0 determines activated sizes.", + "steps": [ + "Measure allocation plus driver, display, prover and OS headroom on the 8 GB and other cohort tiers.", + "Run near-full-memory, fragmentation, restart and next-epoch construction scenarios.", + "Compare time-sharing/eviction with concurrent mining/proving, including reload cost." + ], + "accept": "Every advertised combination completes without OOM or silent corruption. Unsupported future sizes are identified before activation. GPU exclusions and lost proving capacity appear in ECO evaluation; retirement of a tier is not a success metric.", + "evidence": "Memory budget per SKU; OOM traces; support horizon; concurrency cost table.", + "priority": "BLOCKER", + "profile": "P01; P02; P06", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 6, + 7, + 8, + 14, + 18, + 23 + ], + "gate": "G1 / G2", + "owner": "GPU lead + three independent operators", + "manual_page": 22 + }, + { + "id": "GPU-06", + "title": "Measure accepted work under ordinary connectivity", + "setup": "Use the same hardware against clean, delayed, lossy and intermittent links in F4.", + "steps": [ + "Measure kernel rate and accepted work separately under home and datacentre link profiles.", + "Include reconnects, template changes, expired submissions and pool failover.", + "Attribute loss to network, local software, validation and protocol causes." + ], + "accept": "Results use accepted work, never kernel rate alone. Ordinary-link incremental rejection stays within P10; all losses remain priced in ECO. Unreachable links may pause but must not claim paid work.", + "evidence": "Per-submission ledger; network trace; rejection reasons; accepted-work comparison.", + "priority": "GATE", + "profile": "P02; P10", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 6, + 7, + 8, + 14, + 18, + 23 + ], + "gate": "G1 / G2", + "owner": "GPU lead + three independent operators", + "manual_page": 22 + }, + { + "id": "GPU-07", + "title": "Survive sustained thermal and power operation", + "setup": "Run the selected profile on actual reference machines for the P02 soak period.", + "steps": [ + "Track wall power, temperatures, clocks, memory and accepted work continuously.", + "Inject safe power interruptions, process restarts and normal competing desktop load.", + "Check restored settings and compare late-run efficiency with the first stable period." + ], + "accept": "No invalid work or unsafe persistent settings; P02/P10 stability limits hold. Thermal throttling, crashes and recovery time remain in throughput and energy denominators. A crash-free short benchmark cannot substitute for the soak.", + "evidence": "Seven-day time series; crash reports; settings-restoration checks; drift analysis.", + "priority": "BLOCKER", + "profile": "P01; P02; P10", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 6, + 7, + 8, + 14, + 18, + 23 + ], + "gate": "G1 / G2", + "owner": "GPU lead + three independent operators", + "manual_page": 23 + }, + { + "id": "GPU-08", + "title": "Reproduce the full baseline independently", + "setup": "Three unaffiliated operators receive F0, F2 and F3, including the final miner/prover build.", + "steps": [ + "Repeat identical-SKU paired runs with documented meter calibration and environment differences.", + "Recompute joules and total cost per accepted work from the shared raw schema.", + "Investigate divergence before accepting a pooled headline or uncertainty band." + ], + "accept": "Reproductions meet P02 tolerance and exact correctness. No unexplained divergence or selectively missing low-end cell remains. Report manufactured GPU measurements separately from modelled specialist estimates.", + "evidence": "Three signed reproduction packs; reconciliation report; final baseline table.", + "priority": "GATE", + "profile": "P02", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Independent reproduction", + "status": "NOT RUN", + "source": [ + 6, + 7, + 8, + 14, + 18, + 23 + ], + "gate": "G1 / G2", + "owner": "GPU lead + three independent operators", + "manual_page": 23 + } + ] + }, + { + "code": "POW", + "title": "Proof-of-work correctness and coupling", + "source": [ + 7, + 9, + 10, + 23 + ], + "gate": "G2 / technical readiness", + "owner": "Cryptography + GPU lead", + "fixtures": "F0 rule set; F3 independent CPU/GPU oracles; F5 mutation corpus", + "summary": "Find semantic disagreements and structural shortcuts before treating a harder-looking program as a stronger defence.", + "tests": [ + { + "id": "POW-01", + "title": "Match independent execution across every backend", + "setup": "Implement an independently written reference evaluator, not a wrapper around the production GPU path.", + "steps": [ + "Execute the P01 corpus across every family, boundary seed and supported backend.", + "Exercise zero, maximum, sign, shift, rotate, overflow and unaligned-address cases allowed by the spec.", + "Minimise every mismatch and rerun it on clean builds." + ], + "accept": "Bit-for-bit agreement for all valid cases and identical rejection for invalid cases. One unexplained mismatch is a blocker. Large sample counts are evidence of testing, not proof that unseen disagreements cannot exist.", + "evidence": "Reference implementation review; seeds/vectors; backend matrix; mismatch archive.", + "priority": "BLOCKER", + "profile": "P01", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 7, + 9, + 10, + 23 + ], + "gate": "G2 / technical readiness", + "owner": "Cryptography + GPU lead", + "manual_page": 24 + }, + { + "id": "POW-02", + "title": "Validate generated programs and index folding", + "setup": "Use the frozen grammar, opcode semantics and index-fold rule; include boundary and malformed programs.", + "steps": [ + "Enumerate small constrained programs and fuzz the full generator at P01 depth.", + "Check bounds, valid dependencies, address distribution and forbidden encodings.", + "Compare source-level operations with optimised compiled code for removed or altered work." + ], + "accept": "No accepted program violates semantics, termination or memory bounds. Distribution claims have predeclared tests and effect-size limits; passing randomness checks is not treated as a cryptographic proof.", + "evidence": "Generator/fuzzer logs; reduced counterexamples; disassembly comparison; index tests.", + "priority": "BLOCKER", + "profile": "P01", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 7, + 9, + 10, + 23 + ], + "gate": "G2 / technical readiness", + "owner": "Cryptography + GPU lead", + "manual_page": 24 + }, + { + "id": "POW-03", + "title": "Test whether live state is unavoidable", + "setup": "Take the 64-register candidate and the cheapest independently proposed storage organisations.", + "steps": [ + "Trace value liveness across dependent reads and final output, distinguishing distinct information from duplicated values.", + "Try banking, compression, recomputation, fewer ports and time-multiplexed contexts.", + "Quantify the best complete-system cost/throughput trade-off rather than the reference register count." + ], + "accept": "Production selection is supported by measured or physically modelled penalties after these alternatives. G2 requires the P03 improvement; an attractive source-level register count alone does not pass.", + "evidence": "Liveness traces; alternative implementations; Pareto table; reviewer analysis.", + "priority": "GATE", + "profile": "P03; P04", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Experiment + independent hardware review", + "status": "NOT RUN", + "source": [ + 7, + 9, + 10, + 23 + ], + "gate": "G2 / technical readiness", + "owner": "Cryptography + GPU lead", + "manual_page": 24 + }, + { + "id": "POW-04", + "title": "Evaluate connected-resource restructuring", + "setup": "Use a candidate initially matched to baseline instruction count, read count and dataset size.", + "steps": [ + "Connect state, addresses, arithmetic and lane communication according to the written hypothesis.", + "Measure GPU cost and allow the specialist reviewer to redesign the entire core.", + "Repeat on held-out program seeds and compare the worst supported adversary, not only the original design." + ], + "accept": "The selected upgrade meets P03 and improves the adversarial result outside declared uncertainty. A negative experiment remains a negative outcome; adopting a different design requires a new frozen comparison.", + "evidence": "Matched workloads; GPU runs; redesigned core estimates; held-out results.", + "priority": "GATE", + "profile": "P03; P04", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Controlled experiment", + "status": "NOT RUN", + "source": [ + 7, + 9, + 10, + 23 + ], + "gate": "G2 / technical readiness", + "owner": "Cryptography + GPU lead", + "manual_page": 25 + }, + { + "id": "POW-05", + "title": "Prevent amortised cheap winning attempts", + "setup": "Prepare valid templates, nonces, intermediate-state captures and independent acceptance checks.", + "steps": [ + "Vary nonce, payout identity, transactions, roots and other committed fields after expensive work.", + "Try replay, precomputation, shared prefixes, partial evaluation and many cheap suffix candidates.", + "Price any valid strategy against fresh evaluation; independently review all bindings." + ], + "accept": "Invalid modifications are rejected. Any valid cost-saving strategy is incorporated into ADV and must still meet P04/ECO gates. No unresolved shortcut is hidden behind passing reference vectors.", + "evidence": "Attack implementations; valid/invalid controls; work-cost analysis; binding review.", + "priority": "BLOCKER", + "profile": "P01; P04", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 7, + 9, + 10, + 23 + ], + "gate": "G2 / technical readiness", + "owner": "Cryptography + GPU lead", + "manual_page": 25 + }, + { + "id": "POW-06", + "title": "Bound verifier work and malformed-input cost", + "setup": "Use ordinary CPU validators with a manifest-defined resource budget and untrusted submissions.", + "steps": [ + "Submit shortest/longest programs, malformed encodings and adversarial memory references.", + "Measure verification time, peak memory and work amplification across valid and invalid inputs.", + "Sustain the approved hostile request rate while ordinary valid traffic continues." + ], + "accept": "All semantics remain correct and P09 resource budgets hold. Invalid traffic cannot cause unbounded allocation, crashes or disproportionate free work. Rate limits must not replace consensus validation.", + "evidence": "CPU profiles; adversarial corpus; allocation traces; valid-traffic latency.", + "priority": "BLOCKER", + "profile": "P01; P09", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 7, + 9, + 10, + 23 + ], + "gate": "G2 / technical readiness", + "owner": "Cryptography + GPU lead", + "manual_page": 25 + }, + { + "id": "POW-07", + "title": "Constrain any mixed-resource or FP32 branch", + "setup": "If this branch is excluded, verify that it is unreachable and not claimed; if included, use a separate frozen candidate.", + "steps": [ + "Specify exact rounding, fusion, special values and backend behaviour before compiling.", + "Differentially test all supported architectures and allow numerical-domain simplification in the specialist model.", + "Include verifier cost and candidate energy in P03/P04, not just arithmetic-unit area." + ], + "accept": "Included branches achieve exact agreed semantics and all hardware budgets. An excluded branch earns no performance credit. No approximate operation or unspecified compiler choice enters consensus.", + "evidence": "Scope decision; semantic specification; vectors; simplified datapath model.", + "priority": "BLOCKER", + "profile": "P00; P01; P03", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Conditional implementation test", + "status": "NOT RUN", + "source": [ + 7, + 9, + 10, + 23 + ], + "gate": "G2 / technical readiness", + "owner": "Cryptography + GPU lead", + "manual_page": 26 + }, + { + "id": "POW-08", + "title": "Keep rejected mechanisms out of the shipped claim", + "setup": "Inventory long programs, select trees, SM gating, wider reads, sealed classes, random epoch lengths, per-tier scoring and VRF draws.", + "steps": [ + "Retain their historic negative tests and realistic SRAM instruction-memory control.", + "Inspect the release for reintroduction through renamed settings or hidden paths.", + "Require a new written hypothesis and complete adversarial retest for any proposed return." + ], + "accept": "Excluded levers remain excluded unless separately approved and retested. Flip-flop instruction-memory area is never presented as the cost of a realistic SRAM implementation.", + "evidence": "Decision register; binary/config scan; negative-control results.", + "priority": "GATE", + "profile": "P00; P03", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 7, + 9, + 10, + 23 + ], + "gate": "G2 / technical readiness", + "owner": "Cryptography + GPU lead", + "manual_page": 26 + } + ] + }, + { + "code": "ADV", + "title": "Programmable specialist adversaries", + "source": [ + 8, + 10, + 12, + 22, + 23 + ], + "gate": "G3", + "owner": "Independent hardware team", + "fixtures": "F2 reference GPUs; F6 RTL/physical models; all published families", + "summary": "Give the opponent permission to adapt, share resources and remain operational; test cost rather than imagined chip death.", + "tests": [ + { + "id": "ADV-01", + "title": "Build a multi-family programmable opponent", + "setup": "Provide the complete published family bank and future known parameter schedule to the reviewer.", + "steps": [ + "Design one programmable architecture that supports all retained families, including firmware and emulation paths.", + "Optimise clocks, lanes, ports and pipelines without requiring a graphics-card layout.", + "Verify its outputs against POW vectors before measuring any advantage." + ], + "accept": "At least the P04 design diversity is evaluated; every estimated competitive design is functionally validated. Inability of one narrow design to adapt is not evidence that all chips expire.", + "evidence": "Architecture reports; functional simulations; adaptation matrix; reviewer signature.", + "priority": "GATE", + "profile": "P01; P04", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Independent hardware study", + "status": "NOT RUN", + "source": [ + 8, + 10, + 12, + 22, + 23 + ], + "gate": "G3", + "owner": "Independent hardware team", + "manual_page": 27 + }, + { + "id": "ADV-02", + "title": "Price shared, reduced and reconstructed memory", + "setup": "Allow multiple engines to share a dataset and to store selected fractions rather than a complete per-engine copy.", + "steps": [ + "Sweep sharing factors, memory fractions, caches and recomputation depth across many simultaneous hashes.", + "Include construction/update amortisation, bandwidth contention and retained state.", + "Take the most favourable feasible point for the specialist into the complete-board model." + ], + "accept": "No omitted feasible trade-off materially lowers the accepted cost estimate. Any winning alternative is included in P04 and ECO; capacity alone is not accepted as an energy bound.", + "evidence": "Sweep definitions; energy/bandwidth data; best-feasible envelope; excluded-design reasons.", + "priority": "GATE", + "profile": "P04", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Model + adversarial implementation", + "status": "NOT RUN", + "source": [ + 8, + 10, + 12, + 22, + 23 + ], + "gate": "G3", + "owner": "Independent hardware team", + "manual_page": 27 + }, + { + "id": "ADV-03", + "title": "Attack with data-local and hybrid execution", + "setup": "Permit distributed memories, state migration and companion CPU/GPU/FPGA components.", + "steps": [ + "Compare moving computation, intermediate state or fetched data to each read location.", + "Test specialised mining alongside outsourced proof generation rather than assuming one physical GPU does both.", + "Include interconnect, host, synchronisation, idle and conversion costs." + ], + "accept": "The cheapest feasible combined system is included in the adversarial envelope and economic model. A worker identity or account is never treated as proof of a single physical device.", + "evidence": "Hybrid architecture diagrams; traffic traces; system cost and energy ledger.", + "priority": "GATE", + "profile": "P04", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Independent system modelling", + "status": "NOT RUN", + "source": [ + 8, + 10, + 12, + 22, + 23 + ], + "gate": "G3", + "owner": "Independent hardware team", + "manual_page": 27 + }, + { + "id": "ADV-04", + "title": "Measure profitable selective participation", + "setup": "Use all declared families plus held-out generated programs and the protocol difficulty rule.", + "steps": [ + "Identify favourable execution paths and add cheap fallbacks for other periods.", + "Simulate entry/exit around profitable periods, including idle time, compilation and re-entry costs.", + "Evaluate revenue and costs across the full schedule, not just average program energy." + ], + "accept": "Intermittent specialists meet P04/ECO limits when evaluated on full-period economics. A weak tail cannot be concealed by a favourable mean; known valid shortcuts must be priced.", + "evidence": "Per-program advantage distribution; policy simulator; full-period returns.", + "priority": "GATE", + "profile": "P04; P12", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 8, + 10, + 12, + 22, + 23 + ], + "gate": "G3", + "owner": "Independent hardware team", + "manual_page": 28 + }, + { + "id": "ADV-05", + "title": "Validate physical and complete-board costs", + "setup": "Use feasible process/library assumptions and documented component boundaries; no fabricated foundry access.", + "steps": [ + "Model SRAM macros, ports, wiring, clocking, memory PHYs, external memory, host and power conversion.", + "Run place-and-route where available; mark unmodelled items as uncertainty rather than zero.", + "Compare against a calibrated existing hardware block or equivalent validation case." + ], + "accept": "No decision-critical cost is omitted. Physically unvalidated or proprietary estimates are labelled and independently bounded; synthesis alone cannot earn a manufactured-chip claim.", + "evidence": "Netlist/physical reports; macro assumptions; bill of materials; model calibration.", + "priority": "GATE", + "profile": "P04", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Independent physical-design review", + "status": "NOT RUN", + "source": [ + 8, + 10, + 12, + 22, + 23 + ], + "gate": "G3", + "owner": "Independent hardware team", + "manual_page": 28 + }, + { + "id": "ADV-06", + "title": "Separate process advantage from specialisation", + "setup": "Evaluate same-node, one-node-ahead and two-node-ahead scenarios with explicit technology definitions.", + "steps": [ + "Use independently justified process factors, voltages, memory and packaging assumptions for each design.", + "Allow reusable IP and modular revisions; credit GPU improvement consistently.", + "Evaluate measurement confidence and model-parameter sensitivity separately." + ], + "accept": "P04 primary limits hold for all competitive-reference cells; two-node futures are reported and pass the predeclared economic stress envelope. A model range is never labelled a statistical confidence interval without justification.", + "evidence": "Node-specific reports; factor provenance; uncertainty and sensitivity tables.", + "priority": "GATE", + "profile": "P04; P12", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 8, + 10, + 12, + 22, + 23 + ], + "gate": "G3", + "owner": "Independent hardware team", + "manual_page": 28 + }, + { + "id": "ADV-07", + "title": "Evaluate lifetime without forced obsolescence", + "setup": "Assume multi-year productive survival and known schedule support before testing optional retirement penalties.", + "steps": [ + "Price firmware, emulation, memory expansion, companion hardware and incremental redesign.", + "Include 1-, 3- and 5-year productive lifetimes plus idle/resale possibilities.", + "Grant a retirement credit only if all feasible cheaper adaptations lose competitiveness." + ], + "accept": "The primary case does not require chip death or a fresh full development bill per family. Every retirement credit has a documented adaptation comparison; incompatible and unprofitable are reported separately.", + "evidence": "Lifetime/adaptation ledger; revision costs; feasible-alternative analysis.", + "priority": "GATE", + "profile": "P04; P12", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 8, + 10, + 12, + 22, + 23 + ], + "gate": "G3", + "owner": "Independent hardware team", + "manual_page": 29 + }, + { + "id": "ADV-08", + "title": "Independently challenge the best-cost envelope", + "setup": "Publish the non-sensitive model and negative results; commission an unaffiliated second hardware reviewer.", + "steps": [ + "Reward cheaper valid designs and reproduced shortcuts, not confirmation of the preferred number.", + "Re-run P04 with the strongest submitted feasible design, including a low-cost funded-development case.", + "Record unresolved modelling disagreements and future technology exclusions." + ], + "accept": "Both reviews accept the scoped envelope or all material disagreements are resolved transparently. Passing supports only evaluated designs and conditions, never a universal bound on all future silicon.", + "evidence": "Two review reports; challenge log; final envelope; unresolved-limit statement.", + "priority": "GATE", + "profile": "P04", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Independent challenge/review", + "status": "NOT RUN", + "source": [ + 8, + 10, + 12, + 22, + 23 + ], + "gate": "G3", + "owner": "Independent hardware team", + "manual_page": 29 + } + ] + }, + { + "code": "ROT", + "title": "Epochs, seeds and memory transitions", + "source": [ + 7, + 11, + 19, + 21 + ], + "gate": "G5 / G2", + "owner": "Consensus + GPU leads", + "fixtures": "F0 activation rules; F4 fault network; F5 historical and boundary vectors", + "summary": "Transitions must agree across nodes and remain usable during failures; crossing a boundary is not a chip-retirement test.", + "tests": [ + { + "id": "ROT-01", + "title": "Agree across every hourly boundary", + "setup": "Use real nodes, CPU/GPU miners and independent clocks around successive program boundaries.", + "steps": [ + "Submit valid work immediately before, at and after the activation boundary under clock skew and delayed delivery.", + "Restart nodes from both sides and replay the same headers.", + "Compare selected seed, program, validity, rewards and local wall-clock dependence." + ], + "accept": "All honest nodes derive identical consensus outcomes from the frozen rule. Late work is handled exactly as specified; no wall-clock ambiguity or cross-backend split occurs.", + "evidence": "Boundary vectors; node/miner traces; acceptance and reward matrix.", + "priority": "BLOCKER", + "profile": "P01; P08", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 7, + 11, + 19, + 21 + ], + "gate": "G5 / G2", + "owner": "Consensus + GPU leads", + "manual_page": 30 + }, + { + "id": "ROT-02", + "title": "Cross weekly and family boundaries together", + "setup": "Use the retained schedule in F0, including coincident program, parameter and family changes.", + "steps": [ + "Run every known family transition and all coincident-boundary combinations on production code.", + "Interrupt downloads, compilation and restart during activation; include mixed old/new clients.", + "Repeat selected cases under real elapsed time and the remainder under disclosed accelerated time." + ], + "accept": "Deterministic activation, documented old-client behaviour and no unsafe fallback. Compilation/setup costs satisfy P03; accelerated runs are not reported as years of operating history.", + "evidence": "Transition matrix; code-path evidence; compile timing; old-client logs.", + "priority": "BLOCKER", + "profile": "P01; P03; P08", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 7, + 11, + 19, + 21 + ], + "gate": "G5 / G2", + "owner": "Consensus + GPU leads", + "manual_page": 30 + }, + { + "id": "ROT-03", + "title": "Test miner-voted bring-forward governance", + "setup": "Freeze eligibility, threshold, windows and activation semantics before testing; do not invent a no-veto rule.", + "steps": [ + "Attempt threshold-minus-one, threshold, conflicting proposals, duplicate votes and coalition withholding.", + "Partition voters, restore them and test vote-key substitution through pools.", + "Verify adoption and refusal behaviour of already running nodes." + ], + "accept": "The actual mechanism enforces F0, with authenticated voting and no conflicting activation. Any coalition capable of blocking or manipulating changes is disclosed; labels such as no veto do not override arithmetic.", + "evidence": "Executable governance model; signed-vote corpus; coalition/partition results.", + "priority": "BLOCKER", + "profile": "P00; P01; P08", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 7, + 11, + 19, + 21 + ], + "gate": "G5 / G2", + "owner": "Consensus + GPU leads", + "manual_page": 30 + }, + { + "id": "ROT-04", + "title": "Resist seed selection and faster evaluators", + "setup": "Provide the specified seed pipeline and delay proof implementation plus independently parameterised fast-adversary models.", + "steps": [ + "Try withholding candidate seeds, grinding alternatives, replaying delay proofs and biased checkpoint selection.", + "Vary adversarial speed advantage and outage duration; trace influence on program choice.", + "Validate inputs, parameters and proofs against independent vectors." + ], + "accept": "No invalid seed or proof is accepted; selection advantage stays within the approved threat-model bound. Missing bounds block this gate. A delay mechanism is not credited as generic ASIC resistance.", + "evidence": "Seed/grinding simulations; speed sensitivity; proof vectors; threat-model signoff.", + "priority": "BLOCKER", + "profile": "P00; P01; P08", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 7, + 11, + 19, + 21 + ], + "gate": "G5 / G2", + "owner": "Consensus + GPU leads", + "manual_page": 31 + }, + { + "id": "ROT-05", + "title": "Continue or pause correctly when finality stops", + "setup": "Stop checkpoint signing while mining continues, then cross seed and family boundaries.", + "steps": [ + "Remove the required signing weight and observe the documented fallback or safe pause.", + "Prevent access to any founder seed service; restart from persisted state.", + "Restore the stated fault assumptions and verify deterministic recovery." + ], + "accept": "Mining/seed behaviour matches F0 without manufacturing certificates or reinterpreting finality. Safety holds during the outage; liveness is required only after its stated assumptions return.", + "evidence": "Fault timeline; seed/certificate history; node-state comparison; recovery log.", + "priority": "BLOCKER", + "profile": "P01; P08", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 7, + 11, + 19, + 21 + ], + "gate": "G5 / G2", + "owner": "Consensus + GPU leads", + "manual_page": 31 + }, + { + "id": "ROT-06", + "title": "Activate datasets without hidden exclusions", + "setup": "Freeze memory sizes, support horizon and sync/update procedure; test all advertised roles.", + "steps": [ + "Construct the next dataset while current work remains active; test slow disks, low free memory and interruption.", + "Try stale-state/dataset submissions and maliciously expensive state growth where coupling exists.", + "Measure data transfer, restart and excluded-card costs before approving progression." + ], + "accept": "No invalid stale work is accepted, no supported card silently fails, and P06 is met. Hardware retirement and sync burden are included in the economic decision, not treated as automatic chip protection.", + "evidence": "Dataset hashes; memory/update traces; stale-work tests; exclusion decision.", + "priority": "BLOCKER", + "profile": "P01; P06", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 7, + 11, + 19, + 21 + ], + "gate": "G5 / G2", + "owner": "Consensus + GPU leads", + "manual_page": 31 + }, + { + "id": "ROT-07", + "title": "Ablate redundant rotation layers", + "setup": "Use matched baseline and ablated variants in the lab; do not change a running public network.", + "steps": [ + "Remove each weekly/family component independently and measure adversarial cost, GPU setup and verifier complexity.", + "Include favourable-period specialists and all retained known families.", + "Keep a layer only with a distinct, independently supported benefit or a documented non-resistance purpose." + ], + "accept": "Every retained layer has explicit justification and full boundary coverage. Redundant complexity is removed or its rationale recorded; the security model does not double-count the same versatility cost.", + "evidence": "Ablation report; decision log; complexity/cost comparison.", + "priority": "GATE", + "profile": "P03; P04", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 7, + 11, + 19, + 21 + ], + "gate": "G5 / G2", + "owner": "Consensus + GPU leads", + "manual_page": 32 + }, + { + "id": "ROT-08", + "title": "Pass the no-new-rules counterfactual", + "setup": "Freeze the complete published rule bank and known schedule for the five-year evaluation.", + "steps": [ + "Allow a programmable adversary to know and survive all planned changes.", + "Remove assumed future emergency instructions and manual retirement actions from the model.", + "Run the required ECO scenarios and link them to independent network-transition tests." + ], + "accept": "Competitiveness survives the approved envelope without future rescue assumptions. Any result that needs unannounced changes fails this claim; ordinary bug maintenance is distinguished from anti-chip intervention.", + "evidence": "Frozen-rule model; scenario results; excluded-rescue audit; G5 evidence.", + "priority": "GATE", + "profile": "P04; P12", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 7, + 11, + 19, + 21 + ], + "gate": "G5 / G2", + "owner": "Consensus + GPU leads", + "manual_page": 32 + } + ] + }, + { + "code": "ECO", + "title": "Five-year coexistence economics", + "source": [ + 8, + 13, + 18, + 24, + 26 + ], + "gate": "G4", + "owner": "Economics lead + independent reviewer", + "fixtures": "F6 adversarial costs; F7 scenario model; F2 operator costs", + "summary": "Test the world after specialised hardware exists, including new entrants and an already-funded competitor.", + "tests": [ + { + "id": "ECO-01", + "title": "Reconcile complete cost per accepted work", + "setup": "Use benchmark outputs, current-source cost inputs recorded at execution time and separate reference scenarios.", + "steps": [ + "Calculate hardware annualisation, electricity, host, cooling/hosting, failures, fees, downtime and residual value.", + "Use actual accepted work and independently verify units and period conversions.", + "Cross-check formulas using hand-worked fixtures, edge cases and a second implementation." + ], + "accept": "All material costs and rejected-work effects appear once; model totals reconcile to raw inputs. No GPU upgrade is free, development cost is not double-counted, and burn is not mislabelled operator income.", + "evidence": "Versioned model; unit fixtures; independent reconciliation; input sources.", + "priority": "GATE", + "profile": "P12", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 8, + 13, + 18, + 24, + 26 + ], + "gate": "G4", + "owner": "Economics lead + independent reviewer", + "manual_page": 33 + }, + { + "id": "ECO-02", + "title": "Separate existing-owner and new-entrant viability", + "setup": "Use both installed hardware and purchasable replacement hardware in every mandatory cohort.", + "steps": [ + "Evaluate marginal operation separately from recovery of a new purchase.", + "Stress resale at zero, hardware failures, financing and replacement cycles.", + "Report break-even power price and total cost relative to the strongest feasible specialist." + ], + "accept": "P12 competitiveness conditions hold for the predeclared cohorts in required sustainable worlds. Existing-owner profitability cannot substitute for viable new entry; cards outside the envelope remain visible.", + "evidence": "Owner/entrant curves; price-date records; break-even tables; cohort outcomes.", + "priority": "GATE", + "profile": "P12", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 8, + 13, + 18, + 24, + 26 + ], + "gate": "G4", + "owner": "Economics lead + independent reviewer", + "manual_page": 33 + }, + { + "id": "ECO-03", + "title": "Let the specialist keep its sunk development", + "setup": "Use three development cases: fully funded elsewhere, source-range low and source-range high.", + "steps": [ + "Evaluate private mining, public hardware sales and a hybrid business model.", + "Allow shared IP, incremental revisions, multi-year survival and resale where justified.", + "Re-evaluate GPU entry after the specialist fleet is already installed." + ], + "accept": "The coexistence claim does not depend on recovering the original chip research bill. Required P12 cases meet the approved envelope even at zero incremental development cost; failures cannot be hidden by the $23M/$340M source thresholds.", + "evidence": "Business-model variants; sunk-cost case; full cash-flow and adaptation records.", + "priority": "GATE", + "profile": "P12", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 8, + 13, + 18, + 24, + 26 + ], + "gate": "G4", + "owner": "Economics lead + independent reviewer", + "manual_page": 33 + }, + { + "id": "ECO-04", + "title": "Model entry, exit and difficulty response", + "setup": "Use independently reviewed dynamic operator policies, not fixed market shares.", + "steps": [ + "Let agents buy, sell, switch off, re-enter and choose tasks based on declared costs and expected income.", + "Apply the actual difficulty/reward rules and test optimistic and adversarial liquidity/capital availability.", + "Compare equilibrium and transient outcomes across independent starting conditions." + ], + "accept": "Mandatory worlds satisfy P12 without an imposed GPU share or artificial specialist capacity limit. Concentration, oscillations and excluded regions are reported; model behaviour matches unit and conservation checks.", + "evidence": "Agent policies; sensitivity seeds; market-share paths; independent model review.", + "priority": "GATE", + "profile": "P12", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 8, + 13, + 18, + 24, + 26 + ], + "gate": "G4", + "owner": "Economics lead + independent reviewer", + "manual_page": 34 + }, + { + "id": "ECO-05", + "title": "Stress success, contraction and cheap electricity", + "setup": "Freeze mandatory scenarios before results: revenue bands, tariff range, lifetimes and demand states.", + "steps": [ + "Run the P12 factorial grid plus adversarial combinations selected by the independent reviewer.", + "Test a large successful network as well as weak-revenue and heterogeneous-tariff cases.", + "Distinguish feasible sustained-entry worlds from collapse scenarios with no rational profitable operator." + ], + "accept": "No small-network or token-appreciation assumption props up the primary claim. Required viable worlds pass the envelope; collapse worlds show honest contraction and safety, not fabricated profits. Failure regions are explicit.", + "evidence": "Scenario register; full result cube; boundary plots; failed-world explanations.", + "priority": "GATE", + "profile": "P12", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 8, + 13, + 18, + 24, + 26 + ], + "gate": "G4", + "owner": "Economics lead + independent reviewer", + "manual_page": 34 + }, + { + "id": "ECO-06", + "title": "Fund security and proving as issuance falls", + "setup": "Use the frozen supply, halving, fee, burn and reward rules rather than source prose assumptions.", + "steps": [ + "Reconcile revenue reaching miners, internal provers, developers and burns over the full horizon.", + "Test flat/declining fees and no external proving income; separately introduce external demand.", + "Calculate capacity and security-provider coverage after each reward transition." + ], + "accept": "Recurring compensation is explicit and internally consistent; mandatory sustainable scenarios meet P12. Burned amounts are never counted as payments, and external operator income is not assumed to fund internal work automatically.", + "evidence": "Issuance/fee ledger; scenario cash flows; funding-shortfall report.", + "priority": "GATE", + "profile": "P12", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 8, + 13, + 18, + 24, + 26 + ], + "gate": "G4", + "owner": "Economics lead + independent reviewer", + "manual_page": 34 + }, + { + "id": "ECO-07", + "title": "Price memory growth and honest-card displacement", + "setup": "Use GPU-05 and ROT-06 costs with the cheapest specialist adaptation.", + "steps": [ + "For each dataset increment, compare specialist cost increases with excluded cards and lost proving capacity.", + "Include ordinary-owner replacement, resale and reloading expenses.", + "Run alternate bounded schedules without assigning automatic chip death." + ], + "accept": "The retained schedule meets P06/P12 and has an evidence-backed net competitiveness benefit. A schedule that mainly harms accessible GPUs fails; excluded tiers and mitigations are documented before activation.", + "evidence": "Per-step cost/retention table; alternative schedules; approval record.", + "priority": "GATE", + "profile": "P06; P12", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 8, + 13, + 18, + 24, + 26 + ], + "gate": "G4", + "owner": "Economics lead + independent reviewer", + "manual_page": 35 + }, + { + "id": "ECO-08", + "title": "Reproduce and adversarially audit the model", + "setup": "Give an independent economist or qualified analyst the code, inputs and frozen success criteria.", + "steps": [ + "Recalculate required worlds and perturb favourable assumptions against the team.", + "Check dependence on discounts, utilisation, capital limits, artificial prices and future upgrades.", + "Publish the sensitivity range and state which conclusions are conditional." + ], + "accept": "Material results reproduce, required scenarios pass and no unacknowledged assumption dominates the claim. The model supports a bounded coexistence conclusion, not a percentage probability that no chip will appear.", + "evidence": "Independent report; rerun outputs; model limitations; approved claim envelope.", + "priority": "GATE", + "profile": "P12", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Independent economic review", + "status": "NOT RUN", + "source": [ + 8, + 13, + 18, + 24, + 26 + ], + "gate": "G4", + "owner": "Economics lead + independent reviewer", + "manual_page": 35 + } + ] + }, + { + "code": "EVM", + "title": "Execution and developer compatibility", + "source": [ + 15, + 25, + 34, + 35, + 36, + 37 + ], + "gate": "Technical readiness", + "owner": "Execution lead + independent implementer", + "fixtures": "F0 execution-fork semantics; F5 transactions/contracts; F4 multi-node network", + "summary": "Keep familiar applications while making every difference and metering rule explicit and reproducible.", + "tests": [ + { + "id": "EVM-01", + "title": "Match the selected EVM semantics", + "setup": "Pin the intended execution fork, revm version and all Igneum deviations in F0.", + "steps": [ + "Run the applicable upstream execution/state fixtures plus independently written deviation tests.", + "Execute identical blocks on multiple nodes and compare roots, receipts, logs, gas and failure outcomes.", + "Minimise mismatches and distinguish intended differences from implementation defects." + ], + "accept": "All applicable vectors match; every deviation has a documented test and developer consequence. No claim of universal Ethereum equivalence or Ethereum settlement security is inferred.", + "evidence": "Fixture/version inventory; root/receipt diffs; deviation matrix.", + "priority": "BLOCKER", + "profile": "P01; P09", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 15, + 25, + 34, + 35, + 36, + 37 + ], + "gate": "Technical readiness", + "owner": "Execution lead + independent implementer", + "manual_page": 36 + }, + { + "id": "EVM-02", + "title": "Preserve transaction binding and replay protection", + "setup": "Use signed transfers, contract calls and deployment transactions with boundary field values.", + "steps": [ + "Alter chain identity, nonce, signature, fee caps and recipient after signing.", + "Replay across nodes, forks and distinct test networks; resubmit around reorganisation.", + "Check mempool admission and final consensus execution independently." + ], + "accept": "Unauthorised, wrong-network or duplicate spends are rejected according to F0. Valid replacements follow the declared rule; mempool filtering alone is not evidence of consensus enforcement.", + "evidence": "Signed corpus; admission/execution outcomes; account-state reconciliation.", + "priority": "BLOCKER", + "profile": "P01", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 15, + 25, + 34, + 35, + 36, + 37 + ], + "gate": "Technical readiness", + "owner": "Execution lead + independent implementer", + "manual_page": 36 + }, + { + "id": "EVM-03", + "title": "Test two-dimensional fees and proving limits", + "setup": "Freeze fee dimensions, estimator rules, abort behaviour and refund policy.", + "steps": [ + "Run workloads near and beyond execution and proving budgets, including state-heavy pathological cases.", + "Compare estimated fees with charged fees and validate rollback/receipt status on abort.", + "Mutate a block producer to omit or undercharge expensive work." + ], + "accept": "Deterministic metering, charged amounts and aborted state agree across nodes and proofs. Resource bounds hold; fee estimates meet P09 for accepted supported cases. Undercharged invalid blocks cannot bypass consensus.", + "evidence": "Metering traces; fee fixtures; estimator errors; invalid-block rejection.", + "priority": "BLOCKER", + "profile": "P01; P09", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 15, + 25, + 34, + 35, + 36, + 37 + ], + "gate": "Technical readiness", + "owner": "Execution lead + independent implementer", + "manual_page": 36 + }, + { + "id": "EVM-04", + "title": "Exercise block context and randomness assumptions", + "setup": "Use contracts sensitive to timestamp, height/context, randomness and ordering.", + "steps": [ + "Compare the declared Igneum semantics with developers' documented expectations.", + "Test boundary transitions, miner-influenced inputs and adversarial ordering in the isolated network.", + "Run dependency reviews for applications using these values for economic decisions." + ], + "accept": "Semantics match F0 and differences are surfaced in compatibility documentation. No source of miner influence is marketed as unbiased randomness; incompatible applications are not included in the compatibility claim.", + "evidence": "Context-contract results; threat notes; compatibility exclusions.", + "priority": "BLOCKER", + "profile": "P01; P09", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 15, + 25, + 34, + 35, + 36, + 37 + ], + "gate": "Technical readiness", + "owner": "Execution lead + independent implementer", + "manual_page": 37 + }, + { + "id": "EVM-05", + "title": "Run representative contract integration journeys", + "setup": "Use versioned transfer/token, NFT, multisignature, exchange and upgrade-pattern fixtures where supported.", + "steps": [ + "Deploy, initialise, transact, revert and upgrade each contract using ordinary tooling.", + "Exercise events, logs, balances, storage and call traces across node restart/reorganisation.", + "Compare expected application invariants with native execution and proved results." + ], + "accept": "Supported journeys preserve their stated invariants; all deviations are documented. Example deployment success alone cannot stand in for application-level correctness or financial audit.", + "evidence": "Contract fixture hashes; transaction journeys; invariant and state comparisons.", + "priority": "BLOCKER", + "profile": "P01; P09", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 15, + 25, + 34, + 35, + 36, + 37 + ], + "gate": "Technical readiness", + "owner": "Execution lead + independent implementer", + "manual_page": 37 + }, + { + "id": "EVM-06", + "title": "Validate wallets, RPC and indexers", + "setup": "Pin supported RPC methods and response semantics; use normal developer clients and an independent indexer.", + "steps": [ + "Test fee estimation, pending/final states, subscriptions, pagination and reconnects.", + "Reindex from genesis or the documented trust anchor after pruning and restart.", + "Compare logs, receipts and balances with independently validated chain state." + ], + "accept": "No missing/duplicate canonical records; unsupported methods are explicit. UI states distinguish included, executed, proven and finalised. Malformed RPC input cannot crash validators or leak secrets.", + "evidence": "RPC conformance report; reindex comparison; reconnect/edge-case logs.", + "priority": "BLOCKER", + "profile": "P01; P09", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 15, + 25, + 34, + 35, + 36, + 37 + ], + "gate": "Technical readiness", + "owner": "Execution lead + independent implementer", + "manual_page": 37 + }, + { + "id": "EVM-07", + "title": "Handle execution denial-of-service workloads", + "setup": "Create bounded pathological bytecode, calls, state growth, storage and precompile inputs.", + "steps": [ + "Measure CPU, memory, disk and proving cost against charged budgets.", + "Saturate admission with invalid/expensive requests while valid workloads continue.", + "Restart mid-execution and verify atomic state recovery." + ], + "accept": "P09 limits hold with no unbounded free work or divergent rollback. State remains consistent after crash; availability under overload follows the declared admission policy, not silent dropping of accepted transactions.", + "evidence": "Resource profiles; adversarial corpus; state recovery comparisons.", + "priority": "BLOCKER", + "profile": "P01; P09", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 15, + 25, + 34, + 35, + 36, + 37 + ], + "gate": "Technical readiness", + "owner": "Execution lead + independent implementer", + "manual_page": 38 + }, + { + "id": "EVM-08", + "title": "Verify controlled execution and verifier upgrades", + "setup": "Prepare two authorised versions and malicious, stale or unknown versions.", + "steps": [ + "Cross activation with mixed clients, queued transactions and proofs from both versions.", + "Bind each accepted proof to the correct execution semantics and program identity.", + "Exercise a failed software distribution without altering consensus activation." + ], + "accept": "No unknown or wrong-version execution is accepted. Pre/post-boundary handling is deterministic and documented; software delivery cannot silently redefine transaction semantics or proof acceptance.", + "evidence": "Upgrade vectors; mixed-version traces; manifest/version bindings.", + "priority": "BLOCKER", + "profile": "P01; P08; P09", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 15, + 25, + 34, + 35, + 36, + 37 + ], + "gate": "Technical readiness", + "owner": "Execution lead + independent implementer", + "manual_page": 38 + } + ] + }, + { + "code": "ZKP", + "title": "Consensus-enforced proof validity", + "source": [ + 16, + 20, + 24, + 25, + 36, + 37 + ], + "gate": "Technical readiness / G5", + "owner": "Proving + protocol leads; independent cryptography review", + "fixtures": "F0 pinned programs/verifiers; F5 valid and hostile proof corpus; unmodified validators", + "summary": "The validator, not merely the official producer, must reject unauthorised or invalid proof records and rewards.", + "tests": [ + { + "id": "ZKP-01", + "title": "Reject missing and invalid proofs", + "setup": "Start from a native-correct statement and an independently verified valid proof.", + "steps": [ + "Submit the statement with no proof, truncated bytes, random bytes and targeted proof mutations using a modified producer.", + "Submit the genuine proof as a positive control through ordinary network paths.", + "Inspect block acceptance and resulting reward/state on unmodified validators." + ], + "accept": "Every invalid proof record is rejected and earns no reward; valid controls succeed. A producer-side filter is not sufficient. Record rejection semantics exactly as defined by F0.", + "evidence": "Hostile record corpus; validator decisions; before/after balances; positive controls.", + "priority": "BLOCKER", + "profile": "P01; P09", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 16, + 20, + 24, + 25, + 36, + 37 + ], + "gate": "Technical readiness / G5", + "owner": "Proving + protocol leads; independent cryptography review", + "manual_page": 39 + }, + { + "id": "ZKP-02", + "title": "Bind program, verifier and security parameters", + "setup": "Use valid proofs from authorised and unauthorised programs and parameter sets.", + "steps": [ + "Swap program digest, verifier version, security settings and verification key where applicable.", + "Attempt downgrade through configuration, serialized metadata or an old node path.", + "Test authorised boundary transitions and unsupported future identities." + ], + "accept": "Only explicitly authorised combinations are accepted in the correct epoch. No implicit trust in producer-supplied metadata or lower-security fallback; all accepted settings have scoped soundness review.", + "evidence": "Identity/parameter matrix; rejection traces; cryptographic review.", + "priority": "BLOCKER", + "profile": "P01; P09", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 16, + 20, + 24, + 25, + 36, + 37 + ], + "gate": "Technical readiness / G5", + "owner": "Proving + protocol leads; independent cryptography review", + "manual_page": 39 + }, + { + "id": "ZKP-03", + "title": "Bind network, epoch, job and state roots", + "setup": "Prepare valid proofs for distinct chains, epochs, jobs and initial/final states.", + "steps": [ + "Replay each proof under another network, job, epoch, shard range or state commitment.", + "Alter public inputs while retaining the proof and test valid-but-wrong-context statements.", + "Check duplicated and reordered records across forks and replayed sync data." + ], + "accept": "Every misbound proof is rejected; valid authorised replays follow only explicitly allowed semantics and never create extra rewards. Native reexecution cannot conceal missing proof-context binding.", + "evidence": "Binding matrix; public-input hashes; replay traces; reward reconciliation.", + "priority": "BLOCKER", + "profile": "P01", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 16, + 20, + 24, + 25, + 36, + 37 + ], + "gate": "Technical readiness / G5", + "owner": "Proving + protocol leads; independent cryptography review", + "manual_page": 39 + }, + { + "id": "ZKP-04", + "title": "Prevent reward and payout substitution", + "setup": "Use proofs that commit to authorisation and all reward-relevant fields required by F0.", + "steps": [ + "Alter payout key, amount, beneficiary, source work or fee allocation independently.", + "Supply correct execution over malicious producer-provided consensus/reward inputs.", + "Compare consensus-derived rewards with the proved/publicly authenticated derivation." + ], + "accept": "Unauthorised payout changes and incorrect consensus inputs are rejected; no statement accepted merely because execution over supplied inputs is internally correct. Legitimate authorisations are preserved.", + "evidence": "Mutation cases; reward derivation trace; signature/proof binding review.", + "priority": "BLOCKER", + "profile": "P01", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 16, + 20, + 24, + 25, + 36, + 37 + ], + "gate": "Technical readiness / G5", + "owner": "Proving + protocol leads; independent cryptography review", + "manual_page": 40 + }, + { + "id": "ZKP-05", + "title": "Make proof payment idempotent across races", + "setup": "Use competing provers submitting valid results for the same work and simulate retries/reorganisations.", + "steps": [ + "Submit simultaneous duplicates, reordered receipts and repeated messages after disconnects.", + "Crash validators between validation and reward application, then recover.", + "Reconcile canonical payouts against the exact F0 duplicate policy." + ], + "accept": "Only the authorised total payment is made; no double payout, lost accepted entitlement or fork-retained balance. Transactions and payout records recover atomically.", + "evidence": "Concurrency schedule; canonical payment ledger; crash/recovery evidence.", + "priority": "BLOCKER", + "profile": "P01", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 16, + 20, + 24, + 25, + 36, + 37 + ], + "gate": "Technical readiness / G5", + "owner": "Proving + protocol leads; independent cryptography review", + "manual_page": 40 + }, + { + "id": "ZKP-06", + "title": "Verify aggregation coverage and completeness", + "setup": "Build valid multi-shard workloads plus omitted, duplicated, overlapping and misordered shard sets.", + "steps": [ + "Attempt an aggregate with a correct outer proof but wrong coverage/public-input construction.", + "Alter shard ranges, roots and aggregation-program identity.", + "Verify native execution, aggregate validity and coverage commitments independently." + ], + "accept": "Only complete, correctly ordered authorised coverage is accepted. No valid proof of the wrong computation becomes an accepted chain result; aggregation failures do not fabricate successful delivery.", + "evidence": "Coverage corpus; aggregate/public-input verification; rejection ledger.", + "priority": "BLOCKER", + "profile": "P01; P09", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 16, + 20, + 24, + 25, + 36, + 37 + ], + "gate": "Technical readiness / G5", + "owner": "Proving + protocol leads; independent cryptography review", + "manual_page": 40 + }, + { + "id": "ZKP-07", + "title": "Review soundness and verifier resource limits", + "setup": "Provide proof-system code, parameters, patches and the pinned verification path to an independent specialist.", + "steps": [ + "Review soundness assumptions, parameter margins and consequences of performance patches.", + "Fuzz deserialization and adversarial proofs; measure verification CPU and memory under load.", + "Cross-check an independent verifier or reference path and test crash containment." + ], + "accept": "P09 review and resource requirements pass with no unresolved critical/high finding. Random proof rejection counts are not described as evidence of a particular cryptographic security level.", + "evidence": "Scoped soundness review; parameter sheet; fuzzer corpus; verifier profiles.", + "priority": "BLOCKER", + "profile": "P01; P09", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Independent cryptographic review + testing", + "status": "NOT RUN", + "source": [ + 16, + 20, + 24, + 25, + 36, + 37 + ], + "gate": "Technical readiness / G5", + "owner": "Proving + protocol leads; independent cryptography review", + "manual_page": 41 + }, + { + "id": "ZKP-08", + "title": "Preserve authority and audit all acceptance paths", + "setup": "Inspect block import, sync, RPC, light verification, database restoration and fast paths.", + "steps": [ + "Try bypassing validation via each path with a proof rejected by the normal path.", + "Remove the dominant prover/aggregator and have independent replacements process available inputs.", + "Attempt to use proof-production status as ordering, voting or finality authority." + ], + "accept": "No bypass accepts invalid work; proofs alone confer no unauthorised consensus control. Replacement and pause behaviour meet F0/P07/P08 without privileged keys or a trusted aggregator shortcut.", + "evidence": "Path coverage report; bypass corpus; replacement run; authority checks.", + "priority": "BLOCKER", + "profile": "P01; P07; P08", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 16, + 20, + 24, + 25, + 36, + 37 + ], + "gate": "Technical readiness / G5", + "owner": "Proving + protocol leads; independent cryptography review", + "manual_page": 41 + } + ] + }, + { + "code": "CAP", + "title": "Sustained proving and delivery", + "source": [ + 17, + 18, + 24, + 25 + ], + "gate": "Technical readiness / commercial track", + "owner": "Proving lead + independent operators", + "fixtures": "F3 meaningful workload catalogue; F4 network; F8 external job harness", + "summary": "A correct fast shard is only one stage; capacity, latency, payment and retries must work together.", + "tests": [ + { + "id": "CAP-01", + "title": "Reproduce the historical consumer-shard result", + "setup": "Recover the exact source-era workload/build if available; keep it separate from the release-candidate workload.", + "steps": [ + "Attempt independent reproduction of the 4,717,439-cycle workload and reported 3060/4060/4070 results.", + "Record proof format, memory, energy, host and whether aggregation/compression are included.", + "Repeat on the final release and label all configuration changes." + ], + "accept": "Historical figures are either reproduced within P02 tolerance or corrected/labelled non-reproduced. Release acceptance uses the current complete workload, never an unmatched historical time or a smaller substituted shard.", + "evidence": "Historical/current manifests; proof verification; timing and memory records.", + "priority": "GATE", + "profile": "P02; P07", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 17, + 18, + 24, + 25 + ], + "gate": "Technical readiness / commercial track", + "owner": "Proving lead + independent operators", + "manual_page": 42 + }, + { + "id": "CAP-02", + "title": "Prove on the actual mining configuration", + "setup": "Use final dataset sizes, registers, clocks, drivers and proof pipeline on every advertised proving tier.", + "steps": [ + "Run mining alone, proving alone, concurrent execution and supported time-sharing.", + "Measure wall energy, memory headroom, reloads, proof latency and forgone accepted mining work.", + "Induce memory pressure and GPU task failure without losing wallet control." + ], + "accept": "Every advertised mode completes correctly and meets P06/P07. Net output includes opportunity cost; unsupported concurrency is not claimed. Mining-only vendor support remains separately labelled.", + "evidence": "Four-mode results; OOM/failure logs; memory and opportunity-cost ledger.", + "priority": "BLOCKER", + "profile": "P01; P06; P07", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 17, + 18, + 24, + 25 + ], + "gate": "Technical readiness / commercial track", + "owner": "Proving lead + independent operators", + "manual_page": 42 + }, + { + "id": "CAP-03", + "title": "Measure the entire request-to-payment path", + "setup": "Assign a unique job ID and immutable timestamps to every stage of F3/F8 jobs.", + "steps": [ + "Record request, input availability, assignment, execution, shard proof, aggregation, verification, delivery and payment.", + "Compare monotonic elapsed time with any protocol/DAA clock and document their relationship.", + "Reconcile failed, censored, retried and abandoned jobs with the original request denominator." + ], + "accept": "No hidden stage or missing job; latency distributions and cost cover the complete path. Delivery, finality and payment are reported separately; protocol seconds are not silently relabelled wall-clock seconds.", + "evidence": "Stage event ledger; clock calibration; end-to-end latency/cost report.", + "priority": "GATE", + "profile": "P07", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 17, + 18, + 24, + 25 + ], + "gate": "Technical readiness / commercial track", + "owner": "Proving lead + independent operators", + "manual_page": 42 + }, + { + "id": "CAP-04", + "title": "Sustain meaningful load without queue growth", + "setup": "Freeze W: payload mix, input sizes, execution work and per-hour demand; prohibit tiny-workload substitution.", + "steps": [ + "Run 72 hours at W and a separate 24 hours at 1.2W on the declared fleet.", + "Measure arrival/completion counts, backlog trend, oldest-job age, deadlines and all retries.", + "Use held-out workloads and an independent observer to detect discarded or delayed requests." + ], + "accept": "P07 completion, tail-latency and bounded-backlog criteria hold. Capacity is stated for the tested W/fleet, not as universal TPS. A queue that grows indefinitely or shrinks through silent loss fails.", + "evidence": "Request/completion reconciliation; backlog series; held-out results; observer report.", + "priority": "GATE", + "profile": "P07", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 17, + 18, + 24, + 25 + ], + "gate": "Technical readiness / commercial track", + "owner": "Proving lead + independent operators", + "manual_page": 43 + }, + { + "id": "CAP-05", + "title": "Overload and recover without false acceptance", + "setup": "Start at W and inject 2W for 15 minutes with valid and invalid jobs, then return to W.", + "steps": [ + "Observe admission, explicit backpressure, reservations and deadline estimates.", + "Track accepted jobs to valid completion or the pre-agreed failure/refund outcome.", + "Measure recovery time and ensure ordinary users are not silently starved." + ], + "accept": "P07 overload policy and recovery limits hold; no accepted job vanishes or earns an invalid reward. Rejected demand is reported separately from delivery success, preventing denominator manipulation.", + "evidence": "Overload timeline; admission/refund logs; backlog-drain proof.", + "priority": "BLOCKER", + "profile": "P01; P07", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 17, + 18, + 24, + 25 + ], + "gate": "Technical readiness / commercial track", + "owner": "Proving lead + independent operators", + "manual_page": 43 + }, + { + "id": "CAP-06", + "title": "Calibrate assignment windows to paid completion", + "setup": "Use a heterogeneous proving fleet, including the slowest advertised consumer tier.", + "steps": [ + "Measure actual completion distributions with network delay, competing load and failed attempts.", + "Test the chosen exclusive window, open claiming and faster challengers after expiry.", + "Compare assignment frequency, paid completions and wasted work by tier." + ], + "accept": "P07 fairness and wasted-work limits hold for advertised tiers. A provisional 10-DAA-second window is not treated as approved. Fair assignment counts alone cannot pass; payment outcomes and operator margins matter.", + "evidence": "Window sweep; paid-completion distribution; wasted-work and margin report.", + "priority": "GATE", + "profile": "P07; P12", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 17, + 18, + 24, + 25 + ], + "gate": "Technical readiness / commercial track", + "owner": "Proving lead + independent operators", + "manual_page": 43 + }, + { + "id": "CAP-07", + "title": "Reassign work when inputs or providers disappear", + "setup": "Remove input providers, assigned provers and the dominant aggregator independently and together.", + "steps": [ + "Have replacement operators retrieve authenticated inputs without founder files.", + "Retry expired assignments while preserving idempotent reward and customer outcomes.", + "Restore providers and test late submissions racing with replacements." + ], + "accept": "P07/P08 replacement deadlines hold when availability assumptions permit. Otherwise a truthful bounded pause/refund occurs; no fake proof, double payment or hidden privileged input source is used.", + "evidence": "Failure schedule; input hashes; reassignment and payout ledger; recovery trace.", + "priority": "BLOCKER", + "profile": "P01; P07; P08", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 17, + 18, + 24, + 25 + ], + "gate": "Technical readiness / commercial track", + "owner": "Proving lead + independent operators", + "manual_page": 44 + }, + { + "id": "CAP-08", + "title": "Deliver customer-verifiable output at scale", + "setup": "Run the external workload using a customer-controlled verifier and independently operated workers.", + "steps": [ + "Verify every delivered proof against the contracted program and input commitment.", + "Reject wrong-format, stale and partial deliveries; test customer retry and delivery failure.", + "Reconcile delivery, acceptance, payment and refund records without exposing private inputs publicly." + ], + "accept": "P07 delivery performance and exact validity hold. Payment depends on the contracted correct result; a valid proof for the wrong job is not a successful delivery.", + "evidence": "Customer verification log; proof-format contract; settlement reconciliation.", + "priority": "BLOCKER", + "profile": "P01; P07; P14", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 17, + 18, + 24, + 25 + ], + "gate": "Technical readiness / commercial track", + "owner": "Proving lead + independent operators", + "manual_page": 44 + } + ] + }, + { + "code": "INC", + "title": "Rewards, incentives and selfish operators", + "source": [ + 13, + 16, + 17, + 18, + 24, + 26 + ], + "gate": "G4 / G5", + "owner": "Protocol economics + proving leads", + "fixtures": "F0 fee/reward rules; F4 adversarial operators; F7 incentive models", + "summary": "Assume operators optimise their own returns. Do not depend on the official client choosing a less profitable task.", + "tests": [ + { + "id": "INC-01", + "title": "Reconcile issuance, fees, burns and recipients", + "setup": "Use a deterministic short chain containing all reward types, fee paths and rounding cases.", + "steps": [ + "Calculate balances, total supply changes, burns and distributions independently.", + "Execute identical blocks natively and through the proving path.", + "Test zero, minimum, maximum and transition-boundary values plus malformed producer accounting." + ], + "accept": "Conservation and recipient rules match F0 exactly; no inflation, rounding leakage or duplicate reward. Fee-table and prose discrepancies are resolved before the run, not guessed by the tester.", + "evidence": "Independent accounting ledger; balance/supply diffs; boundary vectors.", + "priority": "BLOCKER", + "profile": "P01; P12", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 13, + 16, + 17, + 18, + 24, + 26 + ], + "gate": "G4 / G5", + "owner": "Protocol economics + proving leads", + "manual_page": 45 + }, + { + "id": "INC-02", + "title": "Keep revenue streams and claims separate", + "setup": "Prepare jobs and blocks producing mining income, internal proof rewards and external payments.", + "steps": [ + "Trace money from source to operator, protocol, developer and any burn.", + "Compare node records, settlement records and Ember displays.", + "Attempt to classify testnet rewards, reimbursed purchases or token appreciation as external customer revenue." + ], + "accept": "Every stream reconciles and is labelled correctly. No double-counted revenue or fabricated protocol demand; mining subsidy and external service income remain distinct in dashboards and ECO.", + "evidence": "Money-flow register; UI reconciliation; rejected classifications.", + "priority": "BLOCKER", + "profile": "P01; P12; P14", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 13, + 16, + 17, + 18, + 24, + 26 + ], + "gate": "G4 / G5", + "owner": "Protocol economics + proving leads", + "manual_page": 45 + }, + { + "id": "INC-03", + "title": "Let a modified client choose the most profitable task", + "setup": "Permit independent schedulers to mine, prove internally, prove externally or switch off.", + "steps": [ + "Publish common costs and vary relative task rewards, memory pressure and switching costs.", + "Run clients that ignore the official scheduling recommendation.", + "Measure realised operator margin, internal capacity and network progress." + ], + "accept": "Required P12 sustainable worlds maintain paid essential capacity without compelled altruism. Profitability and availability are based on realised outcomes, including switching and wasted work.", + "evidence": "Scheduler source/policies; switching traces; capacity and margin series.", + "priority": "GATE", + "profile": "P07; P12", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 13, + 16, + 17, + 18, + 24, + 26 + ], + "gate": "G4 / G5", + "owner": "Protocol economics + proving leads", + "manual_page": 45 + }, + { + "id": "INC-04", + "title": "Survive external-demand spikes and token declines", + "setup": "Use F7 scenarios with 10x external job offers and token-denominated mining-income shocks.", + "steps": [ + "Allow miners/provers to switch freely under the declared reward and difficulty rules.", + "Observe hash participation, proof backlog, fees and recovery without an administrator.", + "Repeat with external demand dropping to zero and with a dominant operator withdrawn." + ], + "accept": "Mandatory viable worlds meet P07/P12; stressed nonviable worlds fail or pause safely with truthful status. No emergency rule, fabricated demand or unofficial subsidy is inserted to force a pass.", + "evidence": "Shock timeline; fee/hash/capacity paths; failure-region report.", + "priority": "GATE", + "profile": "P07; P08; P12", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 13, + 16, + 17, + 18, + 24, + 26 + ], + "gate": "G4 / G5", + "owner": "Protocol economics + proving leads", + "manual_page": 46 + }, + { + "id": "INC-05", + "title": "Contain job reservation and identity-splitting abuse", + "setup": "Freeze the actual assignment/payment mechanism; do not assume unimplemented collateral or identity controls.", + "steps": [ + "Create many worker identities, reserve jobs, withhold proofs and submit late results.", + "Attempt free option-taking, duplicate work rewards and displacement of honest assignments.", + "Price attacker costs and observe honest completion under the approved abuse load." + ], + "accept": "F0 rules and P07 service limits hold under the declared adversary. Identity splitting does not create unauthorised rewards or control; any unmitigated starvation path blocks the permissionless-service claim.", + "evidence": "Attack clients; assignment trace; cost-to-disrupt analysis; honest-user outcomes.", + "priority": "BLOCKER", + "profile": "P01; P07; P09", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 13, + 16, + 17, + 18, + 24, + 26 + ], + "gate": "G4 / G5", + "owner": "Protocol economics + proving leads", + "manual_page": 46 + }, + { + "id": "INC-06", + "title": "Test difficulty and timestamp manipulation", + "setup": "Use the actual adjustment algorithm and consensus timestamp rule with independent miners.", + "steps": [ + "Inject large hashrate arrivals/departures, periodic selective mining and boundary-timed bursts.", + "Try allowed and invalid timestamp skew, withheld blocks and replayed work.", + "Observe block intervals, reward allocation and recovery after hashrate stabilises." + ], + "accept": "Invalid inputs are rejected; valid adversarial strategies remain within F0/P08 bounds and are priced in ECO. No unexplained reward amplification, permanent stall or conflicting accepted work.", + "evidence": "Difficulty trace; timestamp corpus; revenue analysis; independent rule review.", + "priority": "BLOCKER", + "profile": "P01; P08; P12", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 13, + 16, + 17, + 18, + 24, + 26 + ], + "gate": "G4 / G5", + "owner": "Protocol economics + proving leads", + "manual_page": 46 + }, + { + "id": "INC-07", + "title": "Resist self-dealing fees and fake proving demand", + "setup": "Use self-funded operators and related customer identities in the isolated economic model/network.", + "steps": [ + "Cycle funds through jobs, tips, developer shares and rebates to seek net reward extraction.", + "Attempt to inflate external-demand metrics without genuine unrelated customer expenditure.", + "Reconcile all counterparties and net cash contribution rather than gross transaction volume." + ], + "accept": "No unauthorised subsidy extraction or metric inflation passes. Related-party volume is disclosed/excluded from P14; net external cash and legitimate protocol incentives are reported separately.", + "evidence": "Circular-flow tests; ownership/conflict review; net-cash reconciliation.", + "priority": "BLOCKER", + "profile": "P01; P12; P14", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 13, + 16, + 17, + 18, + 24, + 26 + ], + "gate": "G4 / G5", + "owner": "Protocol economics + proving leads", + "manual_page": 47 + }, + { + "id": "INC-08", + "title": "Quantify provider and supplier failure concentration", + "setup": "Model control of hashing, signing, proving, aggregation and hardware supply separately.", + "steps": [ + "Remove each largest operational dependency and combine correlated failures.", + "Measure replacement cost/time and whether essential roles share hidden ownership.", + "Compare results with the approved fault model and no-rescue exercise." + ], + "accept": "No hidden single dependency defeats the claimed independence; within-tolerance withdrawals recover under P08/P11. Hardware supply concentration is disclosed without equating vendor sales to operator voting control.", + "evidence": "Role/ownership map; dependency removals; recovery and concentration report.", + "priority": "GATE", + "profile": "P08; P11; P12", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 13, + 16, + 17, + 18, + 24, + 26 + ], + "gate": "G4 / G5", + "owner": "Protocol economics + proving leads", + "manual_page": 47 + } + ] + }, + { + "code": "FIN", + "title": "Consensus safety and recovery", + "source": [ + 19, + 21, + 24, + 25 + ], + "gate": "G5 / technical readiness", + "owner": "Consensus lead + independent formal/security review", + "fixtures": "F0 exact fault model; F4 real-node partitions; F5 certificates and historical failures", + "summary": "Test safety under the stated fault bounds. Demand liveness only when synchrony and participation assumptions actually hold.", + "tests": [ + { + "id": "FIN-01", + "title": "Agree on ordering, work and executed state", + "setup": "Use real fork-choice/DAG handling and independent miners, not only a simplified simulator.", + "steps": [ + "Generate concurrent branches, delayed blocks, duplicates and invalid work with deterministic seeds.", + "Compare selected ordering, accumulated work, transaction execution and state roots after delivery converges.", + "Replay from independent checkpoints and from genesis where practical." + ], + "accept": "Honest nodes converge under F0 assumptions with exact roots and rewards. No duplicated work accounting or undocumented ordering dependence; simulator-only success cannot substitute.", + "evidence": "Block/ordering corpus; root/work diffs; real-node replay logs.", + "priority": "BLOCKER", + "profile": "P01; P08", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 19, + 21, + 24, + 25 + ], + "gate": "G5 / technical readiness", + "owner": "Consensus lead + independent formal/security review", + "manual_page": 48 + }, + { + "id": "FIN-02", + "title": "Attack finality with split honest populations", + "setup": "Use the source-discussed 40/40/20 weight split, plus threshold-boundary splits under F0.", + "steps": [ + "Let the 20% adversarial group sign conflicting histories while honest groups are partitioned.", + "Delay messages and eligibility updates independently; keep total historical weights auditable.", + "Try to form two certificates and reconnect nodes to observe accepted final history." + ], + "accept": "No conflicting final certificates are accepted within the declared fault bound. A safe pause is valid when quorum is unavailable; making progress on both sides is not required.", + "evidence": "Signed votes; certificate attempts; voter-table snapshots; safety checker output.", + "priority": "BLOCKER", + "profile": "P01; P08", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 19, + 21, + 24, + 25 + ], + "gate": "G5 / technical readiness", + "owner": "Consensus lead + independent formal/security review", + "manual_page": 48 + }, + { + "id": "FIN-03", + "title": "Cross authority expiry in a long partition", + "setup": "Recover historical expiry failures where available; use the actual current authority-transition rules.", + "steps": [ + "Partition for 31, 35, 60 and 90 logical days and around every retention/expiry boundary.", + "Attempt independently renewed authority sets and conflicting checkpoint locks.", + "Repeat selected boundary cases on real nodes with accelerated timers explicitly labelled." + ], + "accept": "Authority continuity remains authenticated and no conflicting final history appears within F0 assumptions. A timeout is not accepted as proof absent voters ceased to exist. Compressed time is not multi-month field evidence.", + "evidence": "Expiry timeline; table/certificate history; historical regression tests.", + "priority": "BLOCKER", + "profile": "P01; P08", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 19, + 21, + 24, + 25 + ], + "gate": "G5 / technical readiness", + "owner": "Consensus lead + independent formal/security review", + "manual_page": 48 + }, + { + "id": "FIN-04", + "title": "Stop signing while mining continues", + "setup": "Remove enough signing participation to invalidate the liveness assumption without forging votes.", + "steps": [ + "Continue mining and execution, cross seed boundaries and monitor proof queues.", + "Check which user-visible states advance and which remain unfinalised.", + "Restore eligible weight and bounded message delay, then verify recovery." + ], + "accept": "No false finality or fabricated authority. Behaviour matches F0 during the pause and P08 after assumptions return; unfinished transactions are not displayed as irreversible.", + "evidence": "Signing/mining trace; UI/RPC states; recovery roots and timing.", + "priority": "BLOCKER", + "profile": "P01; P08", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 19, + 21, + 24, + 25 + ], + "gate": "G5 / technical readiness", + "owner": "Consensus lead + independent formal/security review", + "manual_page": 49 + }, + { + "id": "FIN-05", + "title": "Authenticate voter-set changes and pooled keys", + "setup": "Use normal transitions, pool members retaining keys and malicious substitution attempts.", + "steps": [ + "Alter voter weights, membership proofs, miner/pool identity bindings and prior-certificate links.", + "Race updates across boundaries and replay old signed changes.", + "Have a new node verify the authority chain from its declared trust anchor." + ], + "accept": "Only correctly authenticated changes are accepted; weights cannot be double-counted or redirected by a pool. All honest nodes agree on the active authority set for each certified point.", + "evidence": "Authority-chain fixtures; substitution attacks; new-node verification log.", + "priority": "BLOCKER", + "profile": "P01; P08", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 19, + 21, + 24, + 25 + ], + "gate": "G5 / technical readiness", + "owner": "Consensus lead + independent formal/security review", + "manual_page": 49 + }, + { + "id": "FIN-06", + "title": "Analyse old-key compromise and long-range histories", + "setup": "Freeze assumptions about key erasure, retained weights, trust anchors and offline recovery.", + "steps": [ + "Use previously eligible keys to build alternative histories after their operators disappear.", + "Present these histories to recently offline and newly joining clients.", + "Test replayed certificates, stale anchors and compromised signer subsets." + ], + "accept": "Acceptance matches the explicit security model with no hidden trusted recovery step. Any reliance on a recent trusted anchor is disclosed and tested; hashpower assumptions cannot replace old-key analysis.", + "evidence": "Long-range corpus; trust-anchor policy; key-compromise review; client results.", + "priority": "BLOCKER", + "profile": "P01; P08", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 19, + 21, + 24, + 25 + ], + "gate": "G5 / technical readiness", + "owner": "Consensus lead + independent formal/security review", + "manual_page": 49 + }, + { + "id": "FIN-07", + "title": "Recover deterministically after reconnection and crash", + "setup": "Combine partitions with node crash, partial writes, restarts and proof backlog.", + "steps": [ + "Reconnect networks under bounded latency and restore required honest participation.", + "Verify fork choice, unfinalised reorganisation, finality, reward rollback and proof reassignments.", + "Compare all honest nodes and customer-visible receipts after recovery." + ], + "accept": "P08 recovery holds without reversing a previously valid final guarantee. Only permitted unfinalised state is reorganised; no duplicate rewards or inconsistent receipt statuses survive.", + "evidence": "Recovery timelines; roots/certificates; payout rollback; customer-state reconciliation.", + "priority": "BLOCKER", + "profile": "P01; P08", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 19, + 21, + 24, + 25 + ], + "gate": "G5 / technical readiness", + "owner": "Consensus lead + independent formal/security review", + "manual_page": 50 + }, + { + "id": "FIN-08", + "title": "Combine boundaries, faults and adversarial scheduling", + "setup": "Use an independent model checker/scheduler and production-node scenarios from F4.", + "steps": [ + "Combine epoch changes, authority transitions, mining churn, data delays and prover/aggregator loss.", + "Explore bounded adversarial message schedules and minimise any counterexample.", + "Replay model findings on real code and have an independent reviewer assess uncovered states." + ], + "accept": "No unresolved safety failure; liveness claims hold only within declared assumptions and P08. Model bounds and untested schedules are published, not described as proof over every possible execution.", + "evidence": "Model/spec artifacts; schedule corpus; replay evidence; independent assessment.", + "priority": "BLOCKER", + "profile": "P01; P08", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Model checking + real-node testing", + "status": "NOT RUN", + "source": [ + 19, + 21, + 24, + 25 + ], + "gate": "G5 / technical readiness", + "owner": "Consensus lead + independent formal/security review", + "manual_page": 50 + } + ] + }, + { + "code": "VER", + "title": "Wallets, receipts and data availability", + "source": [ + 20, + 25, + 35, + 37 + ], + "gate": "Technical readiness / claimed options", + "owner": "Wallet + light-client lead; independent security review", + "fixtures": "F0 trust/availability model; F5 malformed roots, receipts and authority chains", + "summary": "Verify the exact property shown to the user. An inclusion proof, execution proof and finality certificate are not interchangeable.", + "tests": [ + { + "id": "VER-01", + "title": "Authenticate light-client bootstrap", + "setup": "Give a clean client malicious RPC responses, fabricated voter tables and valid-looking signatures.", + "steps": [ + "Start from the approved trust anchor and verify every required link to the advertised state.", + "Substitute otherwise well-formed but unauthorised keys, weights and checkpoints.", + "Remove the bootstrap service and use another independently operated source." + ], + "accept": "The client rejects unauthorised authority and discloses any trust anchor. Signatures over a node-supplied table do not by themselves pass; missing authentication never silently degrades to trusted RPC.", + "evidence": "Bootstrap corpus; trust-chain trace; fail-closed tests.", + "priority": "BLOCKER", + "profile": "P01; P09", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 20, + 25, + 35, + 37 + ], + "gate": "Technical readiness / claimed options", + "owner": "Wallet + light-client lead; independent security review", + "manual_page": 51 + }, + { + "id": "VER-02", + "title": "Verify evolving authority and execution statements", + "setup": "Use valid state proofs paired with wrong execution statements or stale authority histories.", + "steps": [ + "Cross voter and verifier changes with offline clients returning after long intervals.", + "Alter roots, aggregate identity and proof/public-input bindings independently.", + "Check local verification rather than merely a server-reported verified flag." + ], + "accept": "All advertised proof checks occur locally or the remaining trust is explicitly disclosed. Wrong roots and unauthenticated authority are rejected; unsupported verification paths are not claimed.", + "evidence": "Client verification trace; corrupted inputs; offline/upgrade results.", + "priority": "BLOCKER", + "profile": "P01; P09", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 20, + 25, + 35, + 37 + ], + "gate": "Technical readiness / claimed options", + "owner": "Wallet + light-client lead; independent security review", + "manual_page": 51 + }, + { + "id": "VER-03", + "title": "Prove successful payment rather than inclusion", + "setup": "Create successful, reverted, wrong-asset, wrong-recipient and wrong-amount transfers.", + "steps": [ + "Generate receipts for included transactions, including failures and replaced/unfinalised transactions.", + "Verify execution status plus asset, recipient, amount and canonical-state/receipt commitment.", + "Replay the receipt on another chain and after an allowed unfinalised reorganisation." + ], + "accept": "Only the actual successful, correctly bound transfer is labelled payment proof. Inclusion-only receipts are labelled as such; no node-reported success flag substitutes for authenticated outcome.", + "evidence": "Payment fixture corpus; receipt verification; merchant-facing status checks.", + "priority": "BLOCKER", + "profile": "P01; P09", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 20, + 25, + 35, + 37 + ], + "gate": "Technical readiness / claimed options", + "owner": "Wallet + light-client lead; independent security review", + "manual_page": 51 + }, + { + "id": "VER-04", + "title": "Bound cross-chain oracle trust and replay", + "setup": "For a claimed oracle, freeze destination verifier, authority updates, accepted proof types and replay policy.", + "steps": [ + "Try deployer-substituted keys, stale certificates, unchecked signatures and wrong source/destination identities.", + "Exercise legitimate authority updates and source reorganisations under the approved model.", + "Measure gas/cost with realistic header sets and test disabled/unavailable verification." + ], + "accept": "The oracle enforces its declared trust model and fails closed. Deployer privileges and unavailable guarantees are explicit; no trustless-bridge claim exceeds the checks performed. Excluded oracle scope earns no pass credit.", + "evidence": "Oracle code/parameters; attack cases; cost report; privilege disclosure.", + "priority": "BLOCKER", + "profile": "P00; P01; P09", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Claimed-option verification", + "status": "NOT RUN", + "source": [ + 20, + 25, + 35, + 37 + ], + "gate": "Technical readiness / claimed options", + "owner": "Wallet + light-client lead; independent security review", + "manual_page": 52 + }, + { + "id": "VER-05", + "title": "Reconstruct required state without founder storage", + "setup": "Remove founder archival/input services and start an independent operator from the documented entry point.", + "steps": [ + "Fetch authenticated blocks, state/proof inputs and any required witnesses from permitted peers.", + "Rebuild the expected state and continue validation/proving.", + "Measure bandwidth, disk, time and retention requirements against advertised operator budgets." + ], + "accept": "Required data can be obtained and verified within the declared availability model. Hidden archives or unpublished files block independence. A valid execution proof alone does not satisfy this test.", + "evidence": "Download/reconstruction logs; data hashes; resource costs; dependency inventory.", + "priority": "BLOCKER", + "profile": "P01; P08; P09", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 20, + 25, + 35, + 37 + ], + "gate": "Technical readiness / claimed options", + "owner": "Wallet + light-client lead; independent security review", + "manual_page": 52 + }, + { + "id": "VER-06", + "title": "Detect withholding, corruption and stale data", + "setup": "Serve valid commitments with missing data, corrupted chunks, stale witnesses and conflicting peer replies.", + "steps": [ + "Attempt to make a validator or light client accept an unavailable or incorrect state under F0.", + "Test retrieval from independent peers and expiry/retry policy.", + "Restore data and check that recovery cannot alter an already verified commitment." + ], + "accept": "No unjustified available/verified status; safety and admission rules match F0. Recovery is bounded where assumptions permit, and unavailable-data states remain visible instead of hidden behind proofs.", + "evidence": "Withholding corpus; peer retrieval traces; availability/status checks.", + "priority": "BLOCKER", + "profile": "P01; P08; P09", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 20, + 25, + 35, + 37 + ], + "gate": "Technical readiness / claimed options", + "owner": "Wallet + light-client lead; independent security review", + "manual_page": 52 + }, + { + "id": "VER-07", + "title": "Protect wallet keys, signing and recovery", + "setup": "Use test-only keys, encrypted backups and clean replacement devices; no real user funds.", + "steps": [ + "Attempt secret access from proving jobs, logs, crash dumps, clipboard and telemetry paths.", + "Verify transaction destination/amount before signing; test backup/restore and wrong-password handling.", + "Upgrade and recover without silently changing signing authority or exposing seed material." + ], + "accept": "No unintended secret disclosure or unauthorised signature. Supported recovery restores the correct keys and accounts; users receive explicit risk/backup information. Logs are sanitised without hiding security evidence.", + "evidence": "Security review; canary-secret tests; signing fixtures; restore journey.", + "priority": "BLOCKER", + "profile": "P01; P09", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 20, + 25, + 35, + 37 + ], + "gate": "Technical readiness / claimed options", + "owner": "Wallet + light-client lead; independent security review", + "manual_page": 53 + }, + { + "id": "VER-08", + "title": "Keep every user-facing state truthful", + "setup": "Create included-only, executed, proven, finalised, reverted, stale and paused examples.", + "steps": [ + "Compare explorer, wallet, receipt, RPC and customer API labels against authenticated evidence.", + "Interrupt finality and proof services and observe refresh/reconnect behaviour.", + "Check statements about privacy, Ethereum security and device support." + ], + "accept": "No stronger state is implied than verified; stale data is marked and failures are actionable. EVM compatibility is not labelled Ethereum security, and ZK technology is not automatically labelled transaction privacy.", + "evidence": "Cross-surface screenshots/logs; state mapping; claim review.", + "priority": "BLOCKER", + "profile": "P01; P09", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 20, + 25, + 35, + 37 + ], + "gate": "Technical readiness / claimed options", + "owner": "Wallet + light-client lead; independent security review", + "manual_page": 53 + } + ] + }, + { + "code": "OPS", + "title": "Independent operation and release security", + "source": [ + 21, + 24, + 25, + 26 + ], + "gate": "G5", + "owner": "Operations + release leads; independent operators", + "fixtures": "F4 isolated multi-operator network; F0 signed releases; F9 telemetry", + "summary": "A permissionless specification must remain operational without privileged infrastructure or unsafe automatic updates.", + "tests": [ + { + "id": "OPS-01", + "title": "Run the complete no-founder exercise", + "setup": "Use the P11 independent network, adequate honest participation and enough non-founder capacity for W.", + "steps": [ + "Remove founder miners, provers, aggregators, RPC, DNS/bootstrap dependencies and private support access.", + "Run the full P11 period while crossing real and separately labelled accelerated boundaries.", + "Introduce scheduled faults and have independent operators recover using published instructions." + ], + "accept": "No founder action, secret file, privileged key or emergency anti-chip rule is needed. P07/P08 outcomes hold within assumptions; any intervention is recorded as a failed no-rescue run, not erased.", + "evidence": "Operator roster/conflict checks; dependency removals; full activity/intervention log.", + "priority": "BLOCKER", + "profile": "P07; P08; P11", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 21, + 24, + 25, + 26 + ], + "gate": "G5", + "owner": "Operations + release leads; independent operators", + "manual_page": 54 + }, + { + "id": "OPS-02", + "title": "Diversify bootstrap and resist peer isolation", + "setup": "Start nodes without the default bootstrap host and give others adversarial peer lists.", + "steps": [ + "Attempt eclipse through peer concentration, stale discovery, poisoned DNS and repeated identities in an isolated lab.", + "Use independent documented discovery paths and validate returned chain data.", + "Measure synchronisation, peer diversity and recovery after benign connectivity returns." + ], + "accept": "No unauthenticated history is trusted; bootstrap has no hidden single-provider requirement. Isolation is detected/contained according to F0 and recovery meets P08 when assumptions return.", + "evidence": "Peer/discovery traces; eclipse scenarios; startup and recovery evidence.", + "priority": "BLOCKER", + "profile": "P01; P08; P09", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 21, + 24, + 25, + 26 + ], + "gate": "G5", + "owner": "Operations + release leads; independent operators", + "manual_page": 54 + }, + { + "id": "OPS-03", + "title": "Separate update distribution from consensus authority", + "setup": "Use test signing keys and clean desktop/node installations with valid, stale and malicious packages.", + "steps": [ + "Offer signed updates with unexpected consensus rules, downgraded binaries and corrupted payloads.", + "Test explicit operator acceptance and the published signing-key incident procedure.", + "Confirm that distribution-key possession cannot independently activate new consensus rules." + ], + "accept": "Tampering/unauthorised rollback is rejected; updates do not silently transfer authority. Approved acceptance and activation are separate. No test touches production signing material.", + "evidence": "Package corpus; approval/activation traces; compromised-key rehearsal.", + "priority": "BLOCKER", + "profile": "P01; P09", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 21, + 24, + 25, + 26 + ], + "gate": "G5", + "owner": "Operations + release leads; independent operators", + "manual_page": 54 + }, + { + "id": "OPS-04", + "title": "Recover nodes from crash and storage damage", + "setup": "Use production database/snapshot paths with controlled interrupted writes and corrupted test storage.", + "steps": [ + "Crash during import, proof acceptance, reward application and snapshot generation.", + "Restore from independently verified snapshots or re-sync through documented procedures.", + "Compare roots, certificates, balances and processed-job IDs with an unaffected node." + ], + "accept": "No corrupt snapshot is trusted, no duplicate payout and no loss of authenticated final state. Recovery meets P08 where data is available; ambiguous corruption fails closed and is actionable.", + "evidence": "Crash schedule; snapshot hashes; root/balance diffs; recovery timing.", + "priority": "BLOCKER", + "profile": "P01; P08", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 21, + 24, + 25, + 26 + ], + "gate": "G5", + "owner": "Operations + release leads; independent operators", + "manual_page": 55 + }, + { + "id": "OPS-05", + "title": "Isolate untrusted proving workloads", + "setup": "Run hostile test jobs with secret canaries and restrictive worker permissions.", + "steps": [ + "Attempt filesystem escape, process spawning, resource exhaustion, network access and key-store reads.", + "Crash workers and inspect host, wallet and node availability plus dump/log contents.", + "Retry on every supported isolation backend and check dependency vulnerability handling." + ], + "accept": "No secret leakage or unauthorised host action; P09 resource containment holds. Worker failure does not compromise validator/wallet authority; unsupported isolation is not marketed as safe execution.", + "evidence": "Sandbox penetration report; canary logs; resource limits; host-integrity checks.", + "priority": "BLOCKER", + "profile": "P01; P09", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 21, + 24, + 25, + 26 + ], + "gate": "G5", + "owner": "Operations + release leads; independent operators", + "manual_page": 55 + }, + { + "id": "OPS-06", + "title": "Contain malicious network and API traffic", + "setup": "Use an authorised isolated load environment with declared resource and request-rate budgets.", + "steps": [ + "Send malformed headers, proofs, oversized messages, floods and invalid peer sequences.", + "Measure legitimate traffic, memory/disk growth and validator CPU use.", + "Test limit resets, peer reconnect and graceful degradation without disabling validation." + ], + "accept": "P09 abuse budgets hold; no unbounded allocation, persistent crash or invalid acceptance. Backpressure is visible and honest users retain the specified service at admitted load.", + "evidence": "Load/corpus manifests; resource series; valid-traffic metrics; incident traces.", + "priority": "BLOCKER", + "profile": "P01; P09", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 21, + 24, + 25, + 26 + ], + "gate": "G5", + "owner": "Operations + release leads; independent operators", + "manual_page": 55 + }, + { + "id": "OPS-07", + "title": "Detect failures with usable evidence and runbooks", + "setup": "Define alerts for invalid acceptance, conflicting finality, backlog, data loss, payout mismatch and stale status.", + "steps": [ + "Inject one instance of each monitored failure in the lab.", + "Have an unaffiliated operator diagnose it using only emitted evidence and published instructions.", + "Test redaction, metric freshness and duplicate-alert suppression without suppressing serious failures." + ], + "accept": "P10 alert/detection limits hold; every blocker produces actionable evidence. Monitoring does not leak secrets or mislabel intentional safe pauses as successful finality.", + "evidence": "Alert matrix; detection timelines; independent runbook exercise.", + "priority": "GATE", + "profile": "P09; P10", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 21, + 24, + 25, + 26 + ], + "gate": "G5", + "owner": "Operations + release leads; independent operators", + "manual_page": 56 + }, + { + "id": "OPS-08", + "title": "Repeat independent operation across releases", + "setup": "Use a clean previous supported version and the final candidate with independent operators.", + "steps": [ + "Perform documented rolling upgrade, rollback of non-consensus software where allowed and resynchronisation.", + "Cross activation with mixed versions and unavailable founder distribution hosts.", + "Re-run affected gates after changes and preserve prior failures and incident lessons." + ], + "accept": "No undocumented privileged migration or automatic consensus rewrite. All affected evidence is refreshed; P11 no-rescue results remain tied to the final release, not an earlier build.", + "evidence": "Upgrade/replay logs; invalidation map; repeated gate signatures.", + "priority": "BLOCKER", + "profile": "P00; P08; P11", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 21, + 24, + 25, + 26 + ], + "gate": "G5", + "owner": "Operations + release leads; independent operators", + "manual_page": 56 + } + ] + }, + { + "code": "UX", + "title": "Ember, payouts and operator control", + "source": [ + 14, + 21, + 25, + 26 + ], + "gate": "Operator readiness / G5", + "owner": "Desktop product + pool leads; independent usability study", + "fixtures": "F2 supported desktops; F8 user study; F4 honest/malicious pools", + "summary": "Successful participation must be practical for ordinary owners without hidden custody or loss of consensus authority.", + "tests": [ + { + "id": "UX-01", + "title": "Onboard ordinary owners on native desktop apps", + "setup": "Recruit the P10 first-time user cohort across Windows and macOS using supported physical hardware.", + "steps": [ + "Observe install, hardware detection, safety explanation and first accepted work without staff intervention.", + "Record download/data preparation separately as well as complete end-to-end time.", + "Test unsupported hardware and insufficient memory messaging rather than forcing a failed start." + ], + "accept": "P10 completion/time targets hold with no unsafe default or concealed prerequisite. The product is tested as the actual desktop app, not only a browser preview.", + "evidence": "Consent-based study records; task timings; failure reasons; compatibility outcomes.", + "priority": "GATE", + "profile": "P10", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Independent observed user study", + "status": "NOT RUN", + "source": [ + 14, + 21, + 25, + 26 + ], + "gate": "Operator readiness / G5", + "owner": "Desktop product + pool leads; independent usability study", + "manual_page": 57 + }, + { + "id": "UX-02", + "title": "Make pause, stop and safe tuning reliable", + "setup": "Run mining/proving on active desktops under contention and safe thermal stress.", + "steps": [ + "Use pause, stop, power limit, task selection and emergency local shutdown controls.", + "Crash or restart the UI while workers run and verify ownership of background processes.", + "Restore the original hardware settings and test power-saving/low-battery behaviour where supported." + ], + "accept": "P10 control latency and safe-state requirements hold. Stopping does not strand an uncontrolled process; tuning never depends on unsafe settings or silent privilege escalation.", + "evidence": "Control timings; process/settings audit; restart and safety traces.", + "priority": "BLOCKER", + "profile": "P01; P10", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 14, + 21, + 25, + 26 + ], + "gate": "Operator readiness / G5", + "owner": "Desktop product + pool leads; independent usability study", + "manual_page": 57 + }, + { + "id": "UX-03", + "title": "Show net earnings and compatibility honestly", + "setup": "Use known rewards, fees, energy readings, retries and operator-entered tariffs.", + "steps": [ + "Compare mining, internal proof and external proof income with authoritative ledgers.", + "Show gross/net estimates, measurement boundaries, tariff assumptions and payout status.", + "Test stale data, losses, negative margins and mining-only versus proving-compatible devices." + ], + "accept": "P10 reconciliation limits hold and uncertainty is visible. No guaranteed profits, fabricated fiat price or inferred proving support; provisional earnings are not shown as settled payments.", + "evidence": "UI/ledger comparisons; tariff fixtures; stale/negative examples.", + "priority": "BLOCKER", + "profile": "P01; P10; P12", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 14, + 21, + 25, + 26 + ], + "gate": "Operator readiness / G5", + "owner": "Desktop product + pool leads; independent usability study", + "manual_page": 57 + }, + { + "id": "UX-04", + "title": "Pay small operators without hidden custody", + "setup": "Use ordinary single-card balances and the actual pooling/payment path.", + "steps": [ + "Earn, request/receive payment, disconnect and reconnect; include low balances, fees and a pool outage.", + "Attempt redirection, delayed accounting and withdrawal of another user's entitlement.", + "Reconcile displayed balances with canonical entitlement and actual settlement." + ], + "accept": "P10 payout limits hold for the declared small-operator case. No unauthorised custody, redirection or unexplained loss; thresholds and fees are disclosed rather than masked by larger test balances.", + "evidence": "Single-card payout ledger; pool failure record; custody/authorisation review.", + "priority": "BLOCKER", + "profile": "P01; P10", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 14, + 21, + 25, + 26 + ], + "gate": "Operator readiness / G5", + "owner": "Desktop product + pool leads; independent usability study", + "manual_page": 58 + }, + { + "id": "UX-05", + "title": "Keep voting keys with the miner through pooling", + "setup": "Use an honest pool and a modified pool that replaces worker identity or voting credentials.", + "steps": [ + "Verify the consensus binding from performed work to the miner's retained key.", + "Attempt substitution, replay and reassignment without the miner's authorisation.", + "Leave the pool and verify retained voting/finality rights under F0." + ], + "accept": "No silent transfer of governance/finality authority. If the protocol cannot establish retained keys, this requirement fails; a pool-protocol name or user-interface promise does not pass.", + "evidence": "Work/key binding vectors; malicious-pool attempts; leave-pool authority check.", + "priority": "BLOCKER", + "profile": "P01; P09", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 14, + 21, + 25, + 26 + ], + "gate": "Operator readiness / G5", + "owner": "Desktop product + pool leads; independent usability study", + "manual_page": 58 + }, + { + "id": "UX-06", + "title": "Verify actual miner-selected work templates", + "setup": "Provide a pool interface with declared job-declaration support and independent miner templates.", + "steps": [ + "Submit miner-selected valid transaction templates and verify what is actually hashed and accepted.", + "Have a pool substitute or censor templates and test local verification/fallback.", + "Measure payout and acceptance consequences without moving authority to the pool." + ], + "accept": "The advertised selection control exists in accepted work, not only configuration. Undisclosed substitution is detected; supported independent operation remains practical under P10.", + "evidence": "Template commitments; accepted-block evidence; malicious-pool/fallback report.", + "priority": "BLOCKER", + "profile": "P01; P10", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 14, + 21, + 25, + 26 + ], + "gate": "Operator readiness / G5", + "owner": "Desktop product + pool leads; independent usability study", + "manual_page": 58 + }, + { + "id": "UX-07", + "title": "Expose actionable failures and safe updates", + "setup": "Create failed proofs, memory pressure, expired jobs, missing payouts and available software updates.", + "steps": [ + "Ask independent users to identify the issue, stop safely and follow the recommended action.", + "Test explicit update approval, version visibility and a failed/corrupt update.", + "Confirm diagnostic exports remove keys and private inputs while retaining useful evidence." + ], + "accept": "P10 task-success requirements hold; no silent update or false success state. Recovery instructions work on supported desktops and secret canaries never enter exported logs.", + "evidence": "Observed tasks; update traces; sanitised export tests.", + "priority": "BLOCKER", + "profile": "P09; P10", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 14, + 21, + 25, + 26 + ], + "gate": "Operator readiness / G5", + "owner": "Desktop product + pool leads; independent usability study", + "manual_page": 59 + }, + { + "id": "UX-08", + "title": "Publish competitive accessible software", + "setup": "Provide open documented builds, tuning parameters and known fee conditions for all supported platforms.", + "steps": [ + "Compare Ember against independently optimised permissible implementations on identical work.", + "Measure efficiency, fees, false rejection, installation and update transparency.", + "Scan for hidden developer fees, hardware whitelists, per-address privilege or undisclosed remote controls." + ], + "accept": "P10 relative-efficiency limits hold and all fees/privileges are explicit. No self-reported device tier earns consensus advantage. A superior external implementation triggers investigation, not selective exclusion.", + "evidence": "Matched software comparison; code/config review; fee/privilege inventory.", + "priority": "GATE", + "profile": "P02; P10", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 14, + 21, + 25, + 26 + ], + "gate": "Operator readiness / G5", + "owner": "Desktop product + pool leads; independent usability study", + "manual_page": 59 + } + ] + }, + { + "code": "COM", + "title": "Paid demand and sustainable delivery", + "source": [ + 4, + 17, + 18, + 24, + 26, + 27, + 31, + 32, + 33 + ], + "gate": "Commercial evidence", + "owner": "Commercial lead + independent financial/customer reviewer", + "fixtures": "F8 real consenting customers; F7 full service costs; private identity proofs", + "summary": "Devnet payouts and subsidised pilots demonstrate mechanics, not independent willingness to pay.", + "tests": [ + { + "id": "COM-01", + "title": "Deliver a genuine contracted proof pilot", + "setup": "Select one real external customer with a meaningful fixed workload and no required migration to Igneum.", + "steps": [ + "Agree program, inputs, proof format, deadline, price, failure/refund policy and verification method.", + "Run paid jobs through ordinary independently operated infrastructure.", + "Have the customer verify usefulness, correctness and its reason for choosing the service." + ], + "accept": "The pilot satisfies its actual contract and settles genuine external payment. Trial subsidies are disclosed and cannot satisfy the repeat-demand gate; no invented customer or testimonial.", + "evidence": "Redacted contract; verified jobs; settlement proof; consented customer confirmation.", + "priority": "GATE", + "profile": "P07; P14", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 4, + 17, + 18, + 24, + 26, + 27, + 31, + 32, + 33 + ], + "gate": "Commercial evidence", + "owner": "Commercial lead + independent financial/customer reviewer", + "manual_page": 60 + }, + { + "id": "COM-02", + "title": "Establish independent repeat purchasing", + "setup": "Use the P14 multi-customer observation period and ownership/conflict checks.", + "steps": [ + "Track paid purchases on distinct occasions, including refunds and stopped customers.", + "Audit related parties, project reimbursements, token grants and circular funding.", + "Reconcile external cash received with correctly delivered meaningful work." + ], + "accept": "P14 buyer, duration and volume minima are met without reimbursement or related-party substitution. Repeat orders are separate buying decisions, not a single payment split into many jobs.", + "evidence": "Anonymised buyer ledger; repeat-order dates; conflict review; net receipts.", + "priority": "GATE", + "profile": "P14", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 4, + 17, + 18, + 24, + 26, + 27, + 31, + 32, + 33 + ], + "gate": "Commercial evidence", + "owner": "Commercial lead + independent financial/customer reviewer", + "manual_page": 60 + }, + { + "id": "COM-03", + "title": "Demonstrate service and operator margins", + "setup": "Allocate all delivery costs, including aggregation, retries, hardware, power, host, network and support.", + "steps": [ + "Calculate gross contribution and fully loaded unit costs for each contracted workload.", + "Reconcile a representative operator's realised earnings against metered costs and opportunity cost.", + "Repeat under the declared demand and price sensitivities." + ], + "accept": "P14 contribution targets hold and at least the required operator cohort has positive realised contribution. Excluded overhead is visible; token appreciation or unpriced founder labour cannot silently create profitability.", + "evidence": "Unit-economics ledger; metered operator sample; allocation rules; sensitivity report.", + "priority": "GATE", + "profile": "P12; P14", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 4, + 17, + 18, + 24, + 26, + 27, + 31, + 32, + 33 + ], + "gate": "Commercial evidence", + "owner": "Commercial lead + independent financial/customer reviewer", + "manual_page": 60 + }, + { + "id": "COM-04", + "title": "Meet the customer service guarantee", + "setup": "Observe actual delivery deadlines, validity, failure handling and support over the contracted period.", + "steps": [ + "Count all accepted jobs, including failed, retried and abandoned cases.", + "Have the customer independently verify results and invoke one authorised refund/failure exercise.", + "Compare offered capacity and quoted price with what was actually delivered." + ], + "accept": "P07 and contracted obligations hold; validity has zero accepted exceptions. Failure terms are honoured, and demand beyond capacity is explicitly refused rather than quietly omitted from metrics.", + "evidence": "Customer-verifier records; SLO report; refunds; promised-versus-delivered comparison.", + "priority": "BLOCKER", + "profile": "P01; P07; P14", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 4, + 17, + 18, + 24, + 26, + 27, + 31, + 32, + 33 + ], + "gate": "Commercial evidence", + "owner": "Commercial lead + independent financial/customer reviewer", + "manual_page": 61 + }, + { + "id": "COM-05", + "title": "Compare against the buyer's real alternative", + "setup": "Identify a credible alternative supplier or in-house option for the same workload, proof format and security.", + "steps": [ + "Obtain comparable quotes or consented measured trials at the evaluation date.", + "Include integration, verification, deadlines and all operational costs, not only proof-generation time.", + "Document the customer's actual trade-off without inventing unavailable comparator evidence." + ], + "accept": "P15 commercial comparison is satisfied with like-for-like scope and a evidenced purchase reason. Missing alternative data remains MISSING; it is not scored as an Igneum win.", + "evidence": "Dated comparison; workload/security match; customer decision record.", + "priority": "GATE", + "profile": "P14; P15", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 4, + 17, + 18, + 24, + 26, + 27, + 31, + 32, + 33 + ], + "gate": "Commercial evidence", + "owner": "Commercial lead + independent financial/customer reviewer", + "manual_page": 61 + }, + { + "id": "COM-06", + "title": "Retain buyers after the pilot and subsidy period", + "setup": "Follow all recruited customers through the P14 observation period, including churn.", + "steps": [ + "Remove disclosed trial incentives before measuring repeat demand.", + "Track renewal, expansion, cancellation reasons, unresolved incidents and buyer concentration.", + "Review whether one affiliated or subsidised buyer dominates the apparent market." + ], + "accept": "P14 repeat/concentration conditions hold with honest denominator and churn reporting. Paying demand survives beyond a demonstration; unsatisfied or departed buyers are not removed retrospectively.", + "evidence": "Cohort/renewal ledger; churn notes; concentration and incentive report.", + "priority": "GATE", + "profile": "P14", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 4, + 17, + 18, + 24, + 26, + 27, + 31, + 32, + 33 + ], + "gate": "Commercial evidence", + "owner": "Commercial lead + independent financial/customer reviewer", + "manual_page": 61 + }, + { + "id": "COM-07", + "title": "Fund maintenance without assumed appreciation", + "setup": "Prepare a costed plan for development, review, infrastructure, support and incident response.", + "steps": [ + "Separate committed resources from revenue dependent on adoption or token price.", + "Stress lower income and an unexpected security/operations expense.", + "Verify responsible owners and continuity arrangements without changing fair-launch promises." + ], + "accept": "P13 committed-runway requirement holds and downside responses are documented. No uncommitted financing, rising token price or burn accounting is presented as available maintenance funding.", + "evidence": "Budget and commitment evidence; downside plan; owner/continuity roster.", + "priority": "GATE", + "profile": "P13", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 4, + 17, + 18, + 24, + 26, + 27, + 31, + 32, + 33 + ], + "gate": "Commercial evidence", + "owner": "Commercial lead + independent financial/customer reviewer", + "manual_page": 62 + }, + { + "id": "COM-08", + "title": "Let independent developers build useful integrations", + "setup": "Recruit unaffiliated developers unfamiliar with unpublished implementation details.", + "steps": [ + "Use public docs to deploy a supported application or integrate an external proof request and verification flow.", + "Record time, undocumented dependencies, workarounds and correctness issues.", + "Retest after documentation fixes without founder-written hidden integration code." + ], + "accept": "P14 developer-task minimum passes on the final release; all required public instructions exist. Successful bytecode deployment alone does not count as a working application or service integration.", + "evidence": "Consented developer logs; public examples; issue closure; verified end-to-end journeys.", + "priority": "GATE", + "profile": "P09; P14", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Independent integration study", + "status": "NOT RUN", + "source": [ + 4, + 17, + 18, + 24, + 26, + 27, + 31, + 32, + 33 + ], + "gate": "Commercial evidence", + "owner": "Commercial lead + independent financial/customer reviewer", + "manual_page": 62 + } + ] + }, + { + "code": "LEAD", + "title": "Comparative leadership evidence", + "source": [ + 4, + 22, + 25, + 27, + 31, + 32, + 33 + ], + "gate": "Leadership-contender decision", + "owner": "Independent assessment panel + product/economics reviewers", + "fixtures": "F8 peer/customer studies; full signed technical evidence; 90-day observation", + "summary": "A serious contention claim requires comparative outcomes and real adoption evidence, not just an internally green test dashboard.", + "tests": [ + { + "id": "LEAD-01", + "title": "Register a fair contemporary comparison", + "setup": "Choose at least the P15 peer coverage and an evaluation date before collecting confirmatory results.", + "steps": [ + "Include the plan's Ravencoin, Ergo and Firo reference set where comparable, then check for other relevant current options.", + "Freeze versions, supported hardware, methods, noninferiority margins and commercial alternatives.", + "Publish exclusions and prohibit cross-algorithm raw-hashrate comparisons." + ], + "accept": "The protocol covers material alternatives fairly and is signed independently. A missing or non-comparable feature is not scored zero; no arbitrary universal rank is inferred from selected metrics.", + "evidence": "Timestamped peer protocol; source/version records; comparison/exclusion rationale.", + "priority": "GATE", + "profile": "P15", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Pre-registered comparative study", + "status": "NOT RUN", + "source": [ + 4, + 22, + 25, + 27, + 31, + 32, + 33 + ], + "gate": "Leadership-contender decision", + "owner": "Independent assessment panel + product/economics reviewers", + "manual_page": 63 + }, + { + "id": "LEAD-02", + "title": "Demonstrate comparable operator advantages", + "setup": "Use matched user tasks and operating conditions on the selected GPU-first networks.", + "steps": [ + "Measure install-to-first-accepted-work, software overhead versus each network's tuned baseline, payout friction and retained control.", + "Measure rejection/availability under the same network conditions; report fees separately.", + "Use blinded analysis where possible and independent runs for decisive differences." + ], + "accept": "P15 noninferiority and superiority requirements hold on meaningful comparable dimensions. No raw hashes from different algorithms are compared, and transient token price is not labelled engineering superiority.", + "evidence": "Matched task data; uncertainty/effect sizes; independent comparison report.", + "priority": "GATE", + "profile": "P02; P10; P15", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 4, + 22, + 25, + 27, + 31, + 32, + 33 + ], + "gate": "Leadership-contender decision", + "owner": "Independent assessment panel + product/economics reviewers", + "manual_page": 63 + }, + { + "id": "LEAD-03", + "title": "Substantiate the specialist-coexistence claim", + "setup": "Assemble G1-G4 plus frozen rules and all surviving-adversary assumptions.", + "steps": [ + "Have independent reviewers trace each public competitiveness statement to its narrowest evidence.", + "Separate measured GPUs, modelled silicon and economic scenarios in all summaries.", + "Evaluate residual uncertainty, excluded technologies and the no-new-rules counterfactual." + ], + "accept": "All claimed envelopes meet P04/P12 without unsupported universal bounds. Reviewers agree the evidence supports scoped commodity competitiveness even when chips remain compatible; an exact chip-arrival probability is not inferred.", + "evidence": "Claim-to-evidence map; signed envelope review; limitations statement.", + "priority": "GATE", + "profile": "P04; P12; P15", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 4, + 22, + 25, + 27, + 31, + 32, + 33 + ], + "gate": "Leadership-contender decision", + "owner": "Independent assessment panel + product/economics reviewers", + "manual_page": 63 + }, + { + "id": "LEAD-04", + "title": "Observe ordinary-operator retention and margins", + "setup": "Recruit the P16 independent cohort before observing results; use privacy-preserving evidence.", + "steps": [ + "Follow participation, realised margin, hardware changes, failures and reasons for leaving for 90 days.", + "Report trial incentives separately and include every initial participant in retention denominators.", + "Compare behaviour with matched alternatives where feasible; disclose absence of an actual downturn." + ], + "accept": "P16 retention/margin minima hold with verified independence and no removal of churned users. Simulated downturns cannot be called observed bear-market retention; historical claims stay limited to the period measured.", + "evidence": "Pseudonymous cohort ledger; margin/retention calculations; departure reasons.", + "priority": "GATE", + "profile": "P12; P16", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 4, + 22, + 25, + 27, + 31, + 32, + 33 + ], + "gate": "Leadership-contender decision", + "owner": "Independent assessment panel + product/economics reviewers", + "manual_page": 64 + }, + { + "id": "LEAD-05", + "title": "Measure control and dependency concentration", + "setup": "Audit operational control of mining, voting, proving, aggregation, hosting and software distribution separately.", + "steps": [ + "Use opt-in attestations, observed dependencies and independent corroboration; disclose uncertain common ownership.", + "Compare concentration and provider-removal outcomes to the approved security and availability assumptions.", + "Check that pooled payments do not hide authority concentration and hardware vendors are not equated with operators." + ], + "accept": "P11/P16 concentration requirements hold within disclosed uncertainty; unidentified control cannot be counted as independent. No single removable dependency is falsely marketed as decentralised operation.", + "evidence": "Control/failure-domain map; uncertainty notes; concentration/removal results.", + "priority": "GATE", + "profile": "P11; P16", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 4, + 22, + 25, + 27, + 31, + 32, + 33 + ], + "gate": "Leadership-contender decision", + "owner": "Independent assessment panel + product/economics reviewers", + "manual_page": 64 + }, + { + "id": "LEAD-06", + "title": "Complete the reliability observation window", + "setup": "Observe the final candidate and approved compatible updates for the full P16 real-time period.", + "steps": [ + "Measure promised service availability, invalid acceptance, finality safety, payouts and incident impact.", + "Reconcile external probes, customer records and operator logs, including maintenance and exclusions.", + "Repeat affected critical tests after every material change; reset observation where comparability breaks." + ], + "accept": "P16 availability and safety criteria hold on live observation; no hidden downtime or compressed-time substitution. This supports the recorded window only, not multi-year operational maturity.", + "evidence": "90-day SLO ledger; independent probes; incident reports; change/retest history.", + "priority": "BLOCKER", + "profile": "P01; P16", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 4, + 22, + 25, + 27, + 31, + 32, + 33 + ], + "gate": "Leadership-contender decision", + "owner": "Independent assessment panel + product/economics reviewers", + "manual_page": 64 + }, + { + "id": "LEAD-07", + "title": "Issue an independent contender assessment", + "setup": "Provide the full evidence packet, commercial results, comparative study and unresolved-limit register to the panel.", + "steps": [ + "Check every mandatory and claimed-option test, source requirement and approved threshold.", + "Require separate signoffs for hardware/economics, security/operations and customer/operator evidence.", + "Document dissent and challenge any inference that passing an internal checklist proves number-one rank." + ], + "accept": "Every required gate is PASS with no unresolved material challenge, critical/high defect or missing comparator/customer evidence. The panel supports a credible leadership-contender conclusion within scope, not a guaranteed rank.", + "evidence": "Signed assessment; full status index; dissent/limitations; approved claim wording.", + "priority": "GATE", + "profile": "P00; P15; P16", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Independent final assessment", + "status": "NOT RUN", + "source": [ + 4, + 22, + 25, + 27, + 31, + 32, + 33 + ], + "gate": "Leadership-contender decision", + "owner": "Independent assessment panel + product/economics reviewers", + "manual_page": 65 + }, + { + "id": "LEAD-08", + "title": "Keep leadership claims valid after release", + "setup": "Define material-change triggers and scheduled reviews before publishing the assessment.", + "steps": [ + "Refresh competitor, hardware-cost, demand and security evidence at the P16 cadence.", + "Test a newly credible specialist, lost customer, major outage and verifier change against invalidation rules.", + "Withdraw or narrow stale claims promptly while publishing the new evidence status." + ], + "accept": "Claims remain dated, scoped and revisable; material contrary evidence reopens the appropriate gate. The network may remain usable while a leadership claim is suspended. No permanent self-awarded certification.", + "evidence": "Review calendar; invalidation drills; versioned public claim register.", + "priority": "GATE", + "profile": "P00; P16", + "cadence": "Release candidate; repeat after relevant changes", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + 4, + 22, + 25, + 27, + 31, + 32, + 33 + ], + "gate": "Leadership-contender decision", + "owner": "Independent assessment panel + product/economics reviewers", + "manual_page": 65 + } + ] + } + ], + "profiles": { + "P00": { + "title": "Frozen scope and approval", + "requirements": [ + "Approve the release manifest, supported roles, numerical profiles, mandatory scenarios, trust/fault model, workload W, adapters and claims before confirmatory tests. Unknown values are BLOCKED, not defaults.", + "Core safety and authentication invariants admit no waiver. Proposed performance or commercial targets may be replaced only before the confirmatory run, with an independent rationale and a versioned public scope.", + "After a failure, weakening a target creates a different claim and requires a new assessment. Preserve all failed runs; do not average a blocker away." + ], + "status": "PROPOSED - REQUIRES APPROVAL" + }, + "P01": { + "title": "Correctness and negative-test depth", + "requirements": [ + "Zero observed invalid acceptance, unauthorised signature, conflicting finality within assumptions, duplicated reward or unexplained cross-backend state/hash disagreement.", + "Minimum proposed campaign: 1,000,000 full-hash vectors per supported backend across all families, plus at least 10,000 malformed/boundary cases per relevant parser or binding class. Include exhaustive small-domain cases and historical regressions.", + "All prescribed critical mutants must be detected. This sampling target is not a bound on cryptographic failure probability and does not replace independent reasoning about soundness or safety." + ], + "status": "PROPOSED - REQUIRES APPROVAL" + }, + "P02": { + "title": "Hardware coverage and reproducibility", + "requirements": [ + "At least 12 physical retail configurations: at least 3 NVIDIA, 3 AMD and 2 Apple configurations, at least two discrete-GPU generations, an advertised 8 GB mining tier and 12 GB proving tiers where claimed. Record usable, not nominal, memory.", + "Declare a competitive core of at least 6 configurations spanning every advertised vendor and at least two discrete generations before optimisation. The wider cohort remains mandatory for access and economic tests; it cannot be silently dropped.", + "Use 5 paired 30-minute steady-state runs per primary cell after at least 15 minutes of warm-up and a stable temperature trend. Calibrated wall meter uncertainty must be at most 2%. Run a 7-day soak on representative low/mid/high tiers.", + "Three unaffiliated operators participate; every competitive-core cell is reproduced by at least two. Identical-SKU energy/accepted-work results must agree within 5% after declared environment corrections; unexplained variance blocks the headline." + ], + "status": "PROPOSED - REQUIRES APPROVAL" + }, + "P03": { + "title": "Candidate improvement and honest-card budget", + "requirements": [ + "For production candidate changes, per mandatory GPU cell: no more than 5% increase in joules per accepted work and no more than 2% decrease in accepted throughput versus the paired tuned baseline. Absolute safety limits always apply.", + "G2 requires at least a 10% reduction in the strongest evaluated specialist advantage after redesign, outside the declared measurement/model uncertainty, while meeting those budgets. A failed experiment is not a successful upgrade.", + "Existing clock-lock savings belong in the baseline. Long programs cannot pass by adding enough equally costly work to both devices to improve a ratio while materially worsening honest operation." + ], + "status": "PROPOSED - REQUIRES APPROVAL" + }, + "P04": { + "title": "Scoped specialist-competition target", + "requirements": [ + "Define R_E as GPU wall joules per accepted work divided by the lowest credible complete-system specialist joules for that same work. The proposed target is R_E at most 1.5 for every competitive-core cell at the same node and one node ahead.", + "Evaluate at least three materially distinct specialist architectures, with one programmable multi-family design, and a second independent reviewer. Include shared/reduced memory, hybrid execution, selective participation and realistic power/host costs.", + "Publish two-node-ahead and modular/reused-IP stress cases; they must satisfy the predeclared P12 economic envelope. No universal ceiling for unknown future hardware is claimed. Report model bounds separately from statistical confidence.", + "A lower-bound specialist estimate, not a convenient average or a deliberately constrained reference architecture, drives the conservative comparison. Undefined or unbounded decision-critical assumptions make the result BLOCKED." + ], + "status": "PROPOSED - REQUIRES APPROVAL" + }, + "P05": { + "title": "Measurement and inference protocol", + "requirements": [ + "Pre-register primary metrics, cohorts, holdout seeds, run order, exclusions and analysis before confirmation. Keep tuning/training runs separate from holdout runs.", + "Use independent runs/operators as measurement units. Report point estimates, two-sided 95% measurement intervals and absolute sample counts; handle time-series dependence with a declared block or run-level method.", + "Apply conservative uncertainty to pass decisions. A confidence interval around measured GPU energy does not capture unknown ASIC architectures; model parameter ranges and expert judgement must be reported as such.", + "Never compare raw hashes per second across different algorithms. Do not transform a five-year scenario sweep into a probability of chip arrival or a guarantee of future profitability." + ], + "status": "PROPOSED - REQUIRES APPROVAL" + }, + "P06": { + "title": "Memory and support policy", + "requirements": [ + "All advertised role/configuration combinations must finish without OOM, corruption or unsafe fallback. Publish a component memory budget, including display/OS, driver, miner, prover, aggregation and epoch construction.", + "Proposed support horizon: at least 24 months of known schedule compatibility for the advertised entry tier, unless a narrower horizon is prominently approved before sale or launch. Removal changes the claim and must pass ECO-07.", + "Treat 5.5 / 8.5 / 11.5 GiB as source candidates, not imposed final rules. Simultaneous operation, eviction and time-sharing are distinct advertised modes with separately measured cost." + ], + "status": "PROPOSED - REQUIRES APPROVAL" + }, + "P07": { + "title": "Proof service capacity and fairness", + "requirements": [ + "Freeze W as a meaningful workload mix, input sizes, proof format, fleet and requests/hour. Primary proposed target: 72 hours at W, plus 24 hours at 1.2W; at least 99.5% accepted jobs delivered valid within the contracted deadline.", + "Default delivery targets for the declared internal reference workload: p95 at most 60 seconds and p99 at most 120 seconds from input-ready assignment through verified delivery. Also publish request-to-delivery including input wait; no claim may omit that delay.", + "Request-to-delivery p99 must meet the separately approved customer deadline. Payment p99 must be at most 10 minutes after verified payable eligibility, with chain finality time reported separately. These defaults do not override a stricter contract.", + "No statistically supported positive backlog drift at steady load, no silent drops; after 2W for 15 minutes, drain excess backlog within 30 minutes of return to W. Report rejected demand and accepted-job success separately.", + "Proposed advertised-tier fairness: at least 90% timely valid assigned completions are paid under the approved rules; avoidable duplicate/retry work is at most 10% of total work. Reassignment policy must bound abandonment without promising every assignment a reward." + ], + "status": "PROPOSED - REQUIRES APPROVAL" + }, + "P08": { + "title": "Fault assumptions and recovery", + "requirements": [ + "F0 must state the exact safety threshold, quorum and authority-transition rule; the synchrony/participation assumptions for liveness; trusted inputs; and clock/expiry semantics. This manual supplies no substitute consensus rule.", + "Exercise threshold-minus/at/plus cases, the 40/40/20 partition fixture, signing outages and 31/35/60/90 logical-day expiry cases. Preserve safety when liveness assumptions fail; do not demand finality from an unavailable quorum.", + "After assumptions and input availability are restored: service replacement within 10 minutes and deterministic network convergence within 30 minutes on the reference topology. Different certified bounds must be approved beforehand.", + "Accelerated-time simulation and real elapsed operation are separate evidence classes. Recovery may not reverse a guarantee previously represented as final." + ], + "status": "PROPOSED - REQUIRES APPROVAL" + }, + "P09": { + "title": "Security and bounded resource requirements", + "requirements": [ + "Zero unresolved critical or high-severity security findings on the claimed release. Independent scopes must cover consensus, proof soundness/parameters, implementation bypasses, wallet/isolation and relevant operational controls.", + "Review the intended proof-system security level and assumptions explicitly; do not infer a security-bit claim from random rejection tests. Version every verifier, program and parameter set.", + "Freeze maximum valid/invalid verification time, memory, disk and admission rates for ordinary validator hardware. At rated valid load plus the approved hostile load, no unbounded growth, invalid acceptance or unrecoverable process failure.", + "For supported wallet fee-estimation cases, proposed absolute error at most 5% versus the specified charge when inputs are unchanged; deterministic fee-cap handling and explicit uncertainty otherwise. Customer contracts remain separately binding." + ], + "status": "PROPOSED - REQUIRES APPROVAL" + }, + "P10": { + "title": "Ordinary-operator product targets", + "requirements": [ + "At least 30 unaffiliated first-time study participants across supported Windows/macOS combinations. At least 90% install, configure safely and submit accepted work without staff help; p90 active setup at most 15 minutes. Publish complete download/dataset time separately.", + "Pause/stop acknowledgement within 2 seconds, safe worker stop within 5 seconds where no documented atomic operation prevents it, and reliable restoration of original tuning settings. No hidden custody or silent update.", + "Net-energy/fee displays reconcile within 5% under the declared measurement boundary. Incremental rejected-work loss on the normal home-link profile is at most 2 percentage points over the matched datacentre profile.", + "Open miner efficiency is within 5% of the best independently tuned permitted implementation on identical work. For the declared single-card payout case, p95 payable-to-payment at most 24 hours and total payout friction at most 2% of earned value.", + "Critical alerts are emitted within 60 seconds of detectable evidence. At least 90% of study users can identify the injected failure and follow the published safe action. No control target excuses a security failure." + ], + "status": "PROPOSED - REQUIRES APPROVAL" + }, + "P11": { + "title": "No-founder exercise and independence", + "requirements": [ + "At least 10 verified unaffiliated operators, three independently administered network/hosting domains and sufficient honest weight/capacity to satisfy F0 and W after founders are removed.", + "Run at least 30 real elapsed days without founder mining, proving, aggregation, bootstrap, required RPC, private files or privileged interventions. Cross all known logical transitions separately without calling accelerated time real history.", + "Document control by role and common dependencies; uncertain identities are not counted as independent. Within-assumption withdrawals must satisfy P08; losing more than the assumed quorum may cause a visible safe pause." + ], + "status": "PROPOSED - REQUIRES APPROVAL" + }, + "P12": { + "title": "Five-year coexistence envelope", + "requirements": [ + "Freeze a sourced revenue reference R and mandatory worlds before results. Sweep 0.25R, R, 4R and 10R; electricity at $0.03/$0.10/$0.25/$0.40 per kWh; 1/3/5-year productive life; zero/$20M/$75M development; private mining and hardware sales; no/normal/spiking external demand.", + "Those values are proposed stress inputs, not current prices or forecasts. Declare which worlds have enough funded demand for rational ongoing service before running; retain collapse worlds as explicit safety/exit tests, not profitable successes.", + "Proposed matched-tariff new-entry target in every mandatory sustainable world: median GPU/specialist total cost per accepted work at most 1.5, 90th percentile at most 1.75, and no advertised competitive-core cell above 2.0. Publish every cell, including heterogeneous tariffs.", + "At least three purchasable GPU configurations across at least two advertised vendors must have positive modelled new-entry economics; at least 75% of the entry cohort must have positive marginal operating economics in those worlds. Report model uncertainty and failure regions.", + "Do not impose GPU market share, specialist production limits, token appreciation, full research-cost recovery or automatic chip death to force the result. Any such condition must become an explicit limitation rather than a hidden assumption." + ], + "status": "PROPOSED - REQUIRES APPROVAL" + }, + "P13": { + "title": "Maintenance continuity", + "requirements": [ + "Before a readiness claim, document at least 12 months of committed maintenance resources at the approved operating scope. Include engineering, security review, infrastructure, support and incident response.", + "Use independently reviewable commitments and downside budgets. Uncommitted future sales, rising token prices, burned fees or assumed fundraising are not available resources.", + "This is a proposed governance test, not a directive to change the supply cap, issuance allocation or fair-launch design." + ], + "status": "PROPOSED - REQUIRES APPROVAL" + }, + "P14": { + "title": "Genuine commercial and developer proof", + "requirements": [ + "At least three unrelated paying buyer organisations, each making at least three separate purchase decisions across at least 30 days; at least 1,000 meaningful verified external jobs in aggregate. Split invoices do not create independent demand.", + "No project reimbursement, circular funding or undisclosed related party counts. Report customer concentration and churn; proposed maximum largest-buyer share is 70% of qualifying revenue.", + "At least 20% aggregate contribution margin after directly attributable delivery costs, retries, refunds and support; publish fully loaded economics separately. At least 75% of sampled eligible operators have positive realised contribution on the declared workload.", + "At least five unaffiliated developers complete a useful supported application or proof-service integration using public documentation. Customer confirmation and raw commercial evidence may remain confidential to the reviewer." + ], + "status": "PROPOSED - REQUIRES APPROVAL" + }, + "P15": { + "title": "Comparative contention threshold", + "requirements": [ + "Pre-register at least three relevant operating GPU-first peers, plus a real proving alternative for customer comparisons. Verify current versions at execution time. The source reference set is a starting point, not a claim about current rankings.", + "Require at least three meaningful comparable dimensions with no material inferiority beyond a pre-agreed 10% margin against the best valid comparator, and at least two independently evidenced advantages against at least two peers.", + "Advantages must be either a greater-than-10% measured improvement outside uncertainty or a directly tested control/capability difference with demonstrated user value. Non-comparable or missing data is not a win.", + "A panel with hardware/economics, security/operations and customer/operator expertise must support the scoped contender conclusion. Passing these judgement-based thresholds does not certify a universal number-one ranking." + ], + "status": "PROPOSED - REQUIRES APPROVAL" + }, + "P16": { + "title": "Observed durability and claim freshness", + "requirements": [ + "At least 90 real elapsed days on the final compatible release family, at least 30 independently verified operators, and transparent eligibility/churn denominators. Material uncomparable changes reset affected observations.", + "Proposed outcomes: at least 60% day-90 operator retention and at least 75% of eligible observed operators with positive measured marginal operation over the period. Report incentives and electricity assumptions; do not claim a downturn was observed if it was not.", + "At least 99.9% availability for the declared customer service during eligible operating conditions, with all-in availability also reported; zero accepted invalid proofs or conflicting finality within F0 assumptions. Do not remove real incidents as maintenance to force a pass.", + "Run fault injection on isolated infrastructure, not unsuspecting customers. Publish planned test windows separately. Reassess claims at least quarterly and immediately after material hardware, protocol, economics or security changes." + ], + "status": "PROPOSED - REQUIRES APPROVAL" + } + }, + "fixtures": [ + { + "id": "F0", + "title": "Release and assurance manifest", + "contents": "Exact commits, binaries, genesis/network ID, mining class, dataset schedule, EVM fork/deviations, program/verifier IDs, fees, supply, quorum/fault rules, trust anchors, activation and supported roles." + }, + { + "id": "F1", + "title": "Clean build environments", + "contents": "Pinned toolchains, dependency locks, clean OS images and documented signing/notarisation boundaries. No production secrets or private founder files." + }, + { + "id": "F2", + "title": "Hardware and measurement lab", + "contents": "Approved physical GPU cohort, calibrated wall meters, stable thermal conditions, driver/OS images and realistic home/datacentre link conditions." + }, + { + "id": "F3", + "title": "Workload and oracle catalogue", + "contents": "Fixed full-hash and EVM/proving jobs, independent reference implementations, real customer-sized payloads, held-out seeds and complete expected results." + }, + { + "id": "F4", + "title": "Authorised fault network", + "contents": "Independent nodes/operators; controllable latency, loss, clocks, partitions, storage faults and role withdrawals. Actual consensus paths plus separately labelled simulators." + }, + { + "id": "F5", + "title": "Negative and regression corpus", + "contents": "Malformed transactions/proofs, wrong roots/IDs, duplicate payments, bad authority tables, historical failures and deliberately faulty code mutants." + }, + { + "id": "F6", + "title": "Specialist implementation pack", + "contents": "Functionally checked architectures, RTL/physical estimates where feasible, memory and board assumptions, cost inputs, adaptation paths and uncertainty ranges." + }, + { + "id": "F7", + "title": "Economic and incentive models", + "contents": "Independently reproducible costs, entry/exit/difficulty policies, scenario grid, operator opportunity costs and money-flow conservation fixtures." + }, + { + "id": "F8", + "title": "User/customer/peer studies", + "contents": "Consenting unaffiliated users, contracted meaningful workloads, private ownership checks, dated competitor methods and independent analysis." + }, + { + "id": "F9", + "title": "Evidence and status vault", + "contents": "Immutable run IDs, raw logs, hashes, analysis code, exclusions, defects, reviewers, signatures, privacy controls and public redacted summaries." + } + ], + "source_sha256": "418b3b9f68f96a413872fecb16f8508a40063891c70054c65e92e6e5f5fb70b6", + "scope_note": "Test design, not executed evidence. All numeric additions are proposed, not source-approved protocol rules. Optional claimed features require their tests; excluded features earn no pass credit.", + "all_pass_note": "Independent passage of all mandatory and claimed-option gates, including commercial and comparative observation, can support a scoped leadership-contender assessment. It does not prove a universal rank or eliminate unknown future hardware risks.", + "manual_page_count": 73 + }, + "integration_gates": [ + { + "id": "INT-01", + "requirement": "Real proof H cannot authenticate a different statement under a warm cache.", + "status": "PROPOSED / NOT RUN", + "source": "R1 / Additional regression gates" + }, + { + "id": "INT-02", + "requirement": "Warm/cold/relay/restart/concurrent cache order does not change block or payout decisions; negative cache isolated.", + "status": "PROPOSED / NOT RUN", + "source": "R1 / Additional regression gates" + }, + { + "id": "INT-03", + "requirement": "Durable payout outbox survives every crash/RPC boundary without duplicate or lost liabilities.", + "status": "PROPOSED / NOT RUN", + "source": "R1 / Additional regression gates" + }, + { + "id": "INT-04", + "requirement": "Corrupt existing pool state, disk-full and reorg cause safe recovery, not silent empty balances.", + "status": "PROPOSED / NOT RUN", + "source": "R1 / Additional regression gates" + }, + { + "id": "INT-05", + "requirement": "The supplied finality implementation matches the approved anchor rule after >window healing.", + "status": "PROPOSED / NOT RUN", + "source": "R1 / Additional regression gates" + }, + { + "id": "INT-06", + "requirement": "Recovery tests state and preserve their weaker fault bound; interfaces never label it as a stronger guarantee.", + "status": "PROPOSED / NOT RUN", + "source": "R1 / Additional regression gates" + }, + { + "id": "INT-07", + "requirement": "One v6 object agrees in node, pool, CPU verifier and each supported GPU host across activation.", + "status": "PROPOSED / NOT RUN", + "source": "R1 / Additional regression gates" + }, + { + "id": "INT-08", + "requirement": "Census, production acceptance, schedule counters and live-dataset tests use the identical frozen contract.", + "status": "PROPOSED / NOT RUN", + "source": "R1 / Additional regression gates" + }, + { + "id": "INT-09", + "requirement": "Eight- and twelve-GiB epoch transitions recover deliberately without relying on repeated OOM/watchdog cycles.", + "status": "PROPOSED / NOT RUN", + "source": "R1 / Additional regression gates" + }, + { + "id": "INT-10", + "requirement": "Metal/CUDA/OpenCL exact dataset geometry agrees; unsupported packs reject before launch.", + "status": "PROPOSED / NOT RUN", + "source": "R1 / Additional regression gates" + }, + { + "id": "INT-11", + "requirement": "Only a memory-reserved proving job launches; mining buffers really release when required.", + "status": "PROPOSED / NOT RUN", + "source": "R1 / Additional regression gates" + }, + { + "id": "INT-12", + "requirement": "Transient shard errors can retry safely; expiration, loss and paid work remain distinct durable outcomes.", + "status": "PROPOSED / NOT RUN", + "source": "R1 / Additional regression gates" + }, + { + "id": "INT-13", + "requirement": "Ember cannot retain a rate-ineligible prior; material workload changes invalidate incompatible profiles.", + "status": "PROPOSED / NOT RUN", + "source": "R1 / Additional regression gates" + }, + { + "id": "INT-14", + "requirement": "Protected helper and per-device leases restore owned settings on normal/abnormal exit; real ACL/security tests.", + "status": "PROPOSED / NOT RUN", + "source": "R1 / Additional regression gates" + }, + { + "id": "INT-15", + "requirement": "Public PoP replay is not session authorization; payout/server/network binding enforced.", + "status": "PROPOSED / NOT RUN", + "source": "R1 / Additional regression gates" + }, + { + "id": "INT-16", + "requirement": "Pool parsing/queues/connection and crypto budgets remain bounded under controlled adversarial traffic.", + "status": "PROPOSED / NOT RUN", + "source": "R1 / Additional regression gates" + }, + { + "id": "INT-17", + "requirement": "Missing oracle/keys/mandatory real-proof fixture blocks the applicable production acceptance gate.", + "status": "PROPOSED / NOT RUN", + "source": "R1 / Additional regression gates" + }, + { + "id": "INT-18", + "requirement": "Whole-system economics pass the strongest feasible adversary, including sunk development and multi-epoch survival.", + "status": "PROPOSED / NOT RUN", + "source": "R1 / Additional regression gates" + } + ], + "updated_stack_closure_requirements": [ + { + "id": "R2-F01-R01", + "finding": "F01", + "requirement": "Valid proof A, warm cache, carried statement B: refuse exactly as a cold node does.", + "status": "PROPOSED / NOT RUN", + "source": "R2 / F01", + "base_test_ids": [ + "ZKP-02", + "ZKP-03", + "ZKP-04", + "ZKP-08" + ] + }, + { + "id": "R2-F01-R02", + "finding": "F01", + "requirement": "Run valid/invalid contexts in both orders, concurrently and across cache eviction/restart.", + "status": "PROPOSED / NOT RUN", + "source": "R2 / F01", + "base_test_ids": [ + "ZKP-02", + "ZKP-03", + "ZKP-04", + "ZKP-08" + ] + }, + { + "id": "R2-F01-R03", + "finding": "F01", + "requirement": "Change payout, network, kind, program ID and activation context; no accepted misbinding.", + "status": "PROPOSED / NOT RUN", + "source": "R2 / F01", + "base_test_ids": [ + "ZKP-02", + "ZKP-03", + "ZKP-04", + "ZKP-08" + ] + }, + { + "id": "R2-F01-R04", + "finding": "F01", + "requirement": "A native two-node test must agree on block validity and payouts despite different cache histories.", + "status": "PROPOSED / NOT RUN", + "source": "R2 / F01", + "base_test_ids": [ + "ZKP-02", + "ZKP-03", + "ZKP-04", + "ZKP-08" + ] + }, + { + "id": "R2-F02-R01", + "finding": "F02", + "requirement": "Release build cannot activate test bypass.", + "status": "PROPOSED / NOT RUN", + "source": "R2 / F02", + "base_test_ids": [ + "GOV-05", + "ZKP-01", + "ZKP-07", + "ZKP-08" + ] + }, + { + "id": "R2-F02-R02", + "finding": "F02", + "requirement": "Missing oracle or pinned keys prevents service readiness after enforcement activation.", + "status": "PROPOSED / NOT RUN", + "source": "R2 / F02", + "base_test_ids": [ + "GOV-05", + "ZKP-01", + "ZKP-07", + "ZKP-08" + ] + }, + { + "id": "R2-F02-R03", + "finding": "F02", + "requirement": "Missing proof bytes retry without incorrectly marking a valid block permanently invalid.", + "status": "PROPOSED / NOT RUN", + "source": "R2 / F02", + "base_test_ids": [ + "GOV-05", + "ZKP-01", + "ZKP-07", + "ZKP-08" + ] + }, + { + "id": "R2-F03-R01", + "finding": "F03", + "requirement": "Clean build from one manifest, including the pool and workers, with no unpublished vendor tree.", + "status": "PROPOSED / NOT RUN", + "source": "R2 / F03", + "base_test_ids": [ + "GOV-01", + "GOV-03", + "POW-01", + "ROT-02" + ] + }, + { + "id": "R2-F03-R02", + "finding": "F03", + "requirement": "Same job context produces identical accepted work in node, CPU reference, CUDA, Metal, OpenCL and pool.", + "status": "PROPOSED / NOT RUN", + "source": "R2 / F03", + "base_test_ids": [ + "GOV-01", + "GOV-03", + "POW-01", + "ROT-02" + ] + }, + { + "id": "R2-F03-R03", + "finding": "F03", + "requirement": "Cross every scheduled transition with old/new client behavior documented and identical rule identities.", + "status": "PROPOSED / NOT RUN", + "source": "R2 / F03", + "base_test_ids": [ + "GOV-01", + "GOV-03", + "POW-01", + "ROT-02" + ] + }, + { + "id": "R2-F04-R01", + "finding": "F04", + "requirement": "Native multi-node 40/40/20 partition, equivocation and dust-valid mining on both sides past the window.", + "status": "PROPOSED / NOT RUN", + "source": "R2 / F04", + "base_test_ids": [ + "FIN-02", + "FIN-03", + "FIN-07", + "FIN-08", + "VER-08" + ] + }, + { + "id": "R2-F04-R02", + "finding": "F04", + "requirement": "Proof that the chosen recovery guarantee matches the public finality claim; two valid contradictory certificates are a hard failure for strong finality.", + "status": "PROPOSED / NOT RUN", + "source": "R2 / F04", + "base_test_ids": [ + "FIN-02", + "FIN-03", + "FIN-07", + "FIN-08", + "VER-08" + ] + }, + { + "id": "R2-F04-R03", + "finding": "F04", + "requirement": "Pause-only resume with historical backfill, missing historical data and all old keys returning.", + "status": "PROPOSED / NOT RUN", + "source": "R2 / F04", + "base_test_ids": [ + "FIN-02", + "FIN-03", + "FIN-07", + "FIN-08", + "VER-08" + ] + }, + { + "id": "R2-F04-R04", + "finding": "F04", + "requirement": "Wallet, receipt and oracle consumers distinguish any weaker recovery state.", + "status": "PROPOSED / NOT RUN", + "source": "R2 / F04", + "base_test_ids": [ + "FIN-02", + "FIN-03", + "FIN-07", + "FIN-08", + "VER-08" + ] + }, + { + "id": "R2-F05-R01", + "finding": "F05", + "requirement": "Native reference-vs-incremental expression equivalence across all source registers and real instruction updates.", + "status": "PROPOSED / NOT RUN", + "source": "R2 / F05", + "base_test_ids": [ + "POW-03", + "POW-04", + "ADV-03", + "ADV-05" + ] + }, + { + "id": "R2-F05-R02", + "finding": "F05", + "requirement": "Full-kernel output equivalence, registers, spills, wall power and accepted throughput across target GPUs.", + "status": "PROPOSED / NOT RUN", + "source": "R2 / F05", + "base_test_ids": [ + "POW-03", + "POW-04", + "ADV-03", + "ADV-05" + ] + }, + { + "id": "R2-F05-R03", + "finding": "F05", + "requirement": "Adversary physical design includes prefix caching/recomputation cost; no assumed full 63-read cost on every load.", + "status": "PROPOSED / NOT RUN", + "source": "R2 / F05", + "base_test_ids": [ + "POW-03", + "POW-04", + "ADV-03", + "ADV-05" + ] + }, + { + "id": "R2-F06-R01", + "finding": "F06", + "requirement": "Acceptance/reference/emitter evaluate the same activated schedule.", + "status": "PROPOSED / NOT RUN", + "source": "R2 / F06", + "base_test_ids": [ + "GOV-05", + "POW-01", + "POW-02", + "POW-06" + ] + }, + { + "id": "R2-F06-R02", + "finding": "F06", + "requirement": "Full live-dataset census on unseen seeds and the complete v6 pack.", + "status": "PROPOSED / NOT RUN", + "source": "R2 / F06", + "base_test_ids": [ + "GOV-05", + "POW-01", + "POW-02", + "POW-06" + ] + }, + { + "id": "R2-F06-R03", + "finding": "F06", + "requirement": "A failed experimental rule does not silently exhaust generation or bypass the intended resource requirement.", + "status": "PROPOSED / NOT RUN", + "source": "R2 / F06", + "base_test_ids": [ + "GOV-05", + "POW-01", + "POW-02", + "POW-06" + ] + }, + { + "id": "R2-F07-R01", + "finding": "F07", + "requirement": "Same final v6 configuration: mine -> evict -> prove -> aggregate -> submit -> rebuild -> resume; no leaked reservations.", + "status": "PROPOSED / NOT RUN", + "source": "R2 / F07", + "base_test_ids": [ + "GPU-05", + "CAP-02", + "CAP-05", + "UX-02" + ] + }, + { + "id": "R2-F07-R02", + "finding": "F07", + "requirement": "OOM, process crash and stale work recover without losing wallet state or silently consuming power.", + "status": "PROPOSED / NOT RUN", + "source": "R2 / F07", + "base_test_ids": [ + "GPU-05", + "CAP-02", + "CAP-05", + "UX-02" + ] + }, + { + "id": "R2-F07-R03", + "finding": "F07", + "requirement": "16 GB+ simultaneous mode only after measured peak plus next-epoch headroom; smaller-card modes labelled separately.", + "status": "PROPOSED / NOT RUN", + "source": "R2 / F07", + "base_test_ids": [ + "GPU-05", + "CAP-02", + "CAP-05", + "UX-02" + ] + }, + { + "id": "R2-F08-R01", + "finding": "F08", + "requirement": "Report every eligible job outcome, including expired work; a bounded list cannot hide losses.", + "status": "PROPOSED / NOT RUN", + "source": "R2 / F08", + "base_test_ids": [ + "CAP-03", + "CAP-04", + "CAP-06", + "CAP-07" + ] + }, + { + "id": "R2-F08-R02", + "finding": "F08", + "requirement": "Consumer tiers complete and receive payment for declared jobs before claims about income.", + "status": "PROPOSED / NOT RUN", + "source": "R2 / F08", + "base_test_ids": [ + "CAP-03", + "CAP-04", + "CAP-06", + "CAP-07" + ] + }, + { + "id": "R2-F08-R03", + "finding": "F08", + "requirement": "Sustained real workload across class transitions, with restart/retry and no publisher intervention.", + "status": "PROPOSED / NOT RUN", + "source": "R2 / F08", + "base_test_ids": [ + "CAP-03", + "CAP-04", + "CAP-06", + "CAP-07" + ] + }, + { + "id": "R2-F09-R01", + "finding": "F09", + "requirement": "Generate all pass/fail cells directly from the declared inequalities and inputs.", + "status": "PROPOSED / NOT RUN", + "source": "R2 / F09", + "base_test_ids": [ + "ADV-05", + "ADV-08", + "ECO-03", + "ECO-08", + "LEAD-03" + ] + }, + { + "id": "R2-F09-R02", + "finding": "F09", + "requirement": "Independent feasibility and cost evaluation of the strongest modeled SRAM/hybrid opponent.", + "status": "PROPOSED / NOT RUN", + "source": "R2 / F09", + "base_test_ids": [ + "ADV-05", + "ADV-08", + "ECO-03", + "ECO-08", + "LEAD-03" + ] + }, + { + "id": "R2-F09-R03", + "finding": "F09", + "requirement": "GPU owners and entrants remain viable under the approved scenario envelope without assuming chip absence or death.", + "status": "PROPOSED / NOT RUN", + "source": "R2 / F09", + "base_test_ids": [ + "ADV-05", + "ADV-08", + "ECO-03", + "ECO-08", + "LEAD-03" + ] + }, + { + "id": "R2-F10-R01", + "finding": "F10", + "requirement": "Compare exact found nonce/hash sets with full-read mode, including all-hit overflow and zero-hit cases.", + "status": "PROPOSED / NOT RUN", + "source": "R2 / F10", + "base_test_ids": [ + "GPU-06", + "GPU-08", + "POW-01", + "UX-08" + ] + }, + { + "id": "R2-F10-R02", + "finding": "F10", + "requirement": "Test stale jobs, high-32 rollover, tail batches and asynchronous buffer reuse.", + "status": "PROPOSED / NOT RUN", + "source": "R2 / F10", + "base_test_ids": [ + "GPU-06", + "GPU-08", + "POW-01", + "UX-08" + ] + }, + { + "id": "R2-F10-R03", + "finding": "F10", + "requirement": "Compare production throughput and wall energy, not only the isolated kernel timer.", + "status": "PROPOSED / NOT RUN", + "source": "R2 / F10", + "base_test_ids": [ + "GPU-06", + "GPU-08", + "POW-01", + "UX-08" + ] + }, + { + "id": "R2-F11-R01", + "finding": "F11", + "requirement": "Goal switch from an efficiency prior can explore higher core/power when policy allows.", + "status": "PROPOSED / NOT RUN", + "source": "R2 / F11", + "base_test_ids": [ + "GPU-02", + "GPU-04", + "UX-02", + "UX-03" + ] + }, + { + "id": "R2-F11-R02", + "finding": "F11", + "requirement": "Driver, workload, dataset, compiler and device changes invalidate certification while retaining optional hints.", + "status": "PROPOSED / NOT RUN", + "source": "R2 / F11", + "base_test_ids": [ + "GPU-02", + "GPU-04", + "UX-02", + "UX-03" + ] + }, + { + "id": "R2-F11-R03", + "finding": "F11", + "requirement": "Thermal/error/late-share events revert safely, including process or machine crash.", + "status": "PROPOSED / NOT RUN", + "source": "R2 / F11", + "base_test_ids": [ + "GPU-02", + "GPU-04", + "UX-02", + "UX-03" + ] + }, + { + "id": "R2-F12-R01", + "finding": "F12", + "requirement": "Crash before/after broadcast, response timeout, restart before snapshot: no duplicate payment or silent debt loss.", + "status": "PROPOSED / NOT RUN", + "source": "R2 / F12", + "base_test_ids": [ + "ZKP-05", + "UX-04", + "OPS-04" + ] + }, + { + "id": "R2-F12-R02", + "finding": "F12", + "requirement": "Same signed transaction retried, fee replacement reconciled by intent, not a new payment.", + "status": "PROPOSED / NOT RUN", + "source": "R2 / F12", + "base_test_ids": [ + "ZKP-05", + "UX-04", + "OPS-04" + ] + }, + { + "id": "R2-F12-R03", + "finding": "F12", + "requirement": "Receipt reorg and finality pause leave correct pending obligations.", + "status": "PROPOSED / NOT RUN", + "source": "R2 / F12", + "base_test_ids": [ + "ZKP-05", + "UX-04", + "OPS-04" + ] + }, + { + "id": "R2-F13-R01", + "finding": "F13", + "requirement": "Repeated authorization rejected or atomically replaces and cleans prior state.", + "status": "PROPOSED / NOT RUN", + "source": "R2 / F13", + "base_test_ids": [ + "OPS-06", + "UX-04", + "UX-05", + "UX-06" + ] + }, + { + "id": "R2-F13-R02", + "finding": "F13", + "requirement": "Oversized unterminated frame rejected within fixed memory/time budget.", + "status": "PROPOSED / NOT RUN", + "source": "R2 / F13", + "base_test_ids": [ + "OPS-06", + "UX-04", + "UX-05", + "UX-06" + ] + }, + { + "id": "R2-F13-R03", + "finding": "F13", + "requirement": "Slow clients and invalid share floods cannot grow unbounded member, nonce or outgoing state.", + "status": "PROPOSED / NOT RUN", + "source": "R2 / F13", + "base_test_ids": [ + "OPS-06", + "UX-04", + "UX-05", + "UX-06" + ] + }, + { + "id": "R2-F14-R01", + "finding": "F14", + "requirement": "Public build has no default arbitrary remote execution and a documented least-privilege boundary.", + "status": "PROPOSED / NOT RUN", + "source": "R2 / F14", + "base_test_ids": [ + "OPS-03", + "OPS-05", + "UX-02", + "UX-07" + ] + }, + { + "id": "R2-F14-R02", + "finding": "F14", + "requirement": "Automatic updates off remains off for urgent manifests until explicit action.", + "status": "PROPOSED / NOT RUN", + "source": "R2 / F14", + "base_test_ids": [ + "OPS-03", + "OPS-05", + "UX-02", + "UX-07" + ] + }, + { + "id": "R2-F14-R03", + "finding": "F14", + "requirement": "A compromised fleet/update signing key cannot silently acquire wallet access or activate a consensus change.", + "status": "PROPOSED / NOT RUN", + "source": "R2 / F14", + "base_test_ids": [ + "OPS-03", + "OPS-05", + "UX-02", + "UX-07" + ] + } + ], + "finding_crosswalk": { + "F01": { + "topic": "Proof-cache context", + "related_R1": "I01", + "base_tests": [ + "ZKP-02", + "ZKP-03", + "ZKP-04", + "ZKP-08" + ], + "integration_gates": [ + "INT-01", + "INT-02" + ] + }, + "F02": { + "topic": "Mandatory proof enforcement", + "related_R1": "I09 / V6-09", + "base_tests": [ + "GOV-05", + "ZKP-01", + "ZKP-07", + "ZKP-08" + ], + "integration_gates": [ + "INT-17" + ] + }, + "F03": { + "topic": "One executable release", + "related_R1": "I04 / V6-01, V6-12", + "base_tests": [ + "GOV-01", + "GOV-03", + "POW-01", + "ROT-02" + ], + "integration_gates": [ + "INT-07", + "INT-08" + ] + }, + "F04": { + "topic": "Finality / recovery contract", + "related_R1": "I03", + "base_tests": [ + "FIN-02", + "FIN-03", + "FIN-07", + "FIN-08", + "VER-08" + ], + "integration_gates": [ + "INT-05", + "INT-06" + ] + }, + "F05": { + "topic": "Incremental register fold", + "related_R1": "V6-03", + "base_tests": [ + "POW-03", + "POW-04", + "ADV-03", + "ADV-05" + ], + "integration_gates": [ + "INT-18" + ] + }, + "F06": { + "topic": "Complete v6 acceptance", + "related_R1": "V6-01, V6-02", + "base_tests": [ + "GOV-05", + "POW-01", + "POW-02", + "POW-06" + ], + "integration_gates": [ + "INT-08" + ] + }, + "F07": { + "topic": "One device memory owner", + "related_R1": "I05 / V6-07", + "base_tests": [ + "GPU-05", + "CAP-02", + "CAP-05", + "UX-02" + ], + "integration_gates": [ + "INT-09", + "INT-11" + ] + }, + "F08": { + "topic": "All-job proving outcomes", + "related_R1": "I10 / V6-08", + "base_tests": [ + "CAP-03", + "CAP-04", + "CAP-06", + "CAP-07" + ], + "integration_gates": [ + "INT-12" + ] + }, + "F09": { + "topic": "Strongest feasible specialist", + "related_R1": "V6-11", + "base_tests": [ + "ADV-05", + "ADV-08", + "ECO-03", + "ECO-08", + "LEAD-03" + ], + "integration_gates": [ + "INT-18" + ] + }, + "F10": { + "topic": "Production worker efficiency", + "related_R1": "Implementation opportunity", + "base_tests": [ + "GPU-06", + "GPU-08", + "POW-01", + "UX-08" + ], + "integration_gates": [ + "INT-07" + ] + }, + "F11": { + "topic": "Ember search and identity", + "related_R1": "I07 / V6-04, V6-05", + "base_tests": [ + "GPU-02", + "GPU-04", + "UX-02", + "UX-03" + ], + "integration_gates": [ + "INT-13", + "INT-14" + ] + }, + "F12": { + "topic": "Durable pool obligations", + "related_R1": "I02", + "base_tests": [ + "ZKP-05", + "UX-04", + "OPS-04" + ], + "integration_gates": [ + "INT-03", + "INT-04" + ] + }, + "F13": { + "topic": "Bounded pool service", + "related_R1": "I08", + "base_tests": [ + "OPS-06", + "UX-04", + "UX-05", + "UX-06" + ], + "integration_gates": [ + "INT-15", + "INT-16" + ] + }, + "F14": { + "topic": "Public operator control", + "related_R1": "V6-06 is related, not identical", + "base_tests": [ + "OPS-03", + "OPS-05", + "UX-02", + "UX-07" + ], + "integration_gates": [ + "INT-14" + ] + } + }, + "source_review_findings": [ + { + "id": "F01", + "title": "Proof-verdict cache omits the statement being verified", + "priority": "P0 - public/value-bearing release blocker", + "evidence_status": "SOURCE + ISOLATED CONTROL-FLOW REPRODUCTION", + "body": "\nThe native cold verifier checks both the pinned program and the hash of the proof's public values against the carried statement. That is good. However, `ProofPool::verdict_for` returns a cached success keyed only by `proof_hash`, checking only the accepted program ID. It does not compare the carried statement on that path. It also returns cached errors without distinguishing intrinsically invalid proof bytes from an otherwise valid proof queried in the wrong context.\n\nThe isolated model reproduces: a wrong statement is refused with a cold cache; the same wrong statement is accepted after that proof was cached against its correct statement. Querying the wrong statement first can poison the later correct lookup. The zero-ID cache wildcard can also bypass a nonempty accepted-ID list if such an entry has been populated. Host configuration controls that second case's reachability.\n\nThis is NOT an SP1 forgery. It is a failure to bind a cached verification result to its use. `check_record` still checks native execution and signatures, so this finding does not show arbitrary execution roots becoming valid. But proof payment and block-validity decisions consume the cache. Warm/cold or order-dependent decisions are unacceptable there. A malicious block producer need not use the honest producer's template-selection code. Full native reproduction is required to establish exact network impact.\n\nFix: cache immutable verified facts (proof kind, actual verifier/program identity, public-values digest, proof format/security version) and compare the required statement and current permitted IDs on EVERY lookup. Alternatively, key by all relevant context. Do not use zero as an accepted pinned ID. Distinguish context-specific refusal from invalid bytes. The relay-time cache population must store the identity actually verified, not merely a configured host label. Bound cache size and in-flight verification.\n", + "source_ranges": [ + { + "path": "node/igneum/exec/src/proving.rs", + "start": 1046, + "end": 1102 + }, + { + "path": "node/igneum/exec/src/proving.rs", + "start": 1358, + "end": 1379 + }, + { + "path": "node/igneum/exec/src/nativeverify.rs", + "start": 151, + "end": 177 + }, + { + "path": "node/igneum/exec/src/proving.rs", + "start": 471, + "end": 489 + } + ], + "required_regressions": [ + "Valid proof A, warm cache, carried statement B: refuse exactly as a cold node does.", + "Run valid/invalid contexts in both orders, concurrently and across cache eviction/restart.", + "Change payout, network, kind, program ID and activation context; no accepted misbinding.", + "A native two-node test must agree on block validity and payouts despite different cache histories." + ] + }, + { + "id": "F02", + "title": "Proof-rule infrastructure can fail open", + "priority": "P0 - release configuration blocker", + "evidence_status": "STATIC SOURCE", + "body": "\n`check_carried_proofs` has a production-compiled environment bypass (`IGNEUM_TEST_SKIP_PROOF_RULE=1`) and returns success when the oracle is absent. The comments explicitly describe these as harness/unit-test accommodations. This is not evidence an unauthenticated peer can set the environment, nor evidence the normal daemon omits its oracle. It is a configuration failure mode that contradicts mandatory enforcement if accidentally activated.\n\nAfter the rule activates, missing verifier infrastructure should stop startup or validation safely, not silently disable the rule. Restrict deliberately unsafe test switches to test-only builds. Distinguish pending proof bytes (retry) from invalid proof (reject) and unavailable trusted verifier (not accepted).\n", + "source_ranges": [ + { + "path": "node/consensus/src/pipeline/body_processor/body_validation_in_context.rs", + "start": 28, + "end": 79 + } + ], + "required_regressions": [ + "Release build cannot activate test bypass.", + "Missing oracle or pinned keys prevents service readiness after enforcement activation.", + "Missing proof bytes retry without incorrectly marking a valid block permanently invalid." + ] + }, + { + "id": "F03", + "title": "The bundle contains a v6 candidate, not a demonstrated integrated v6 release", + "priority": "P0 - freeze/integration blocker", + "evidence_status": "STATIC SOURCE + ARCHIVE PROVENANCE", + "body": "\nThe v6 freeze contains real candidate flags, a 64-register schedule, address mixing, fold/reweight experiments and non-power-of-two dataset geometry. It is materially newer than the earlier V2/V3/V4-only review. Nevertheless the canonical `ProgramClass` enum in this snapshot ends at V5. The freeze README itself says the D1 object cut and spec re-cut are subsequent work. The node bundle is from a different release branch. Generated packs and relevant vendor/build context are omitted.\n\nThere is a concrete seam: the node's `EpochSeeds` struct requires `shadow_reps`, but the pool constructs that type without the field or a struct-update expression. Those exact files cannot be compiled together as written. This was identified statically, not by running Cargo. It does not establish that another deployed pool or vendor revision has the mismatch.\n\nFix: produce one release manifest that pins node, generator, dataset policy, acceptance, host ABI, miner app, pool, proof guests/keys and activation. Build the pool and all supported workers against it in CI. Include executable packs and their authenticated identity. Never combine measurements from different candidates into a single v6 claim.\n", + "source_ranges": [ + { + "path": "v6/igneum-v6-freeze-tree/README-FREEZE.txt", + "start": 1, + "end": 1 + }, + { + "path": "pow/src/generator.rs", + "start": 249, + "end": 277 + }, + { + "path": "pow/src/generator.rs", + "start": 939, + "end": 954 + }, + { + "path": "node/consensus/pow/src/igneum.rs", + "start": 72, + "end": 95 + }, + { + "path": "mining/pool/src/node.rs", + "start": 47, + "end": 71 + } + ], + "required_regressions": [ + "Clean build from one manifest, including the pool and workers, with no unpublished vendor tree.", + "Same job context produces identical accepted work in node, CPU reference, CUDA, Metal, OpenCL and pool.", + "Cross every scheduled transition with old/new client behavior documented and identical rule identities." + ] + }, + { + "id": "F04", + "title": "Finality v4 recovery deliberately has a weaker safety boundary", + "priority": "P0 - finality guarantee decision", + "evidence_status": "SOURCE + SOURCE-REPORTED SIMULATION + PURE PREDICATE REPRODUCTION", + "body": "\nThe older unconditional table-expiry problem has been addressed: the v4 anchored table does not simply disappear. However, after a full window without a lock, the recovery branch accepts strictly more than half of the anchored weight. The supplied guarantee document openly reports conflicting recovery locks in a prolonged partition when an equivocator both mines and signs on both sides. The 40/40/20 case is explicitly included.\n\nThe isolated predicate confirms two sides each holding 60 of the original 100 pass the recovery threshold after the window, although neither passes the two-thirds threshold before it. This alone is not a full protocol exploit: sliding tables, ancestry, dust eligibility and signed certificates also matter. The team's simulation record supplies additional evidence. The same document says its real-node line at the snapshot is the known-failed v3 case and the v4 line still awaits the node change.\n\nDo not call normal finality and recovery finality the same irreversible guarantee. Prefer a reviewed authority-transition/recovery rule retaining the claimed safety assumptions; otherwise restrict and label the recovery state and dependent wallet/bridge actions explicitly. A timeout does not prove that a missing authority is permanently gone.\n\nThe pure pause-only predicate refuses every post-window checkpoint, even with 100% anchored signatures. This is not proof of permanent network liveness failure: historical-checkpoint backfill may re-anchor first. The reported immediate-heal simulations must be reproduced against the actual implementation, including that path.\n", + "source_ranges": [ + { + "path": "node/consensus/src/processes/finality.rs", + "start": 1111, + "end": 1128 + }, + { + "path": "node/consensus/src/processes/finality.rs", + "start": 2610, + "end": 2642 + }, + { + "path": "dag/igneum-node-dag/spec/docs/spec/finality-guarantees.md", + "start": 111, + "end": 136 + }, + { + "path": "dag/igneum-node-dag/spec/docs/spec/finality-guarantees.md", + "start": 184, + "end": 197 + } + ], + "required_regressions": [ + "Native multi-node 40/40/20 partition, equivocation and dust-valid mining on both sides past the window.", + "Proof that the chosen recovery guarantee matches the public finality claim; two valid contradictory certificates are a hard failure for strong finality.", + "Pause-only resume with historical backfill, missing historical data and all old keys returning.", + "Wallet, receipt and oracle consumers distinguish any weaker recovery state." + ] + }, + { + "id": "F05", + "title": "reg64 address coupling has an exact incremental alternative", + "priority": "P1 - adversarial hardware evaluation", + "evidence_status": "EXACT ALGEBRA + 33,024 RANDOMIZED/EDGE COMPARISONS", + "body": "\nThe full-chain window computes a rotate-XOR fold over the 63 registers other than the source, then XORs the source. This connects every register syntactically, but it does not force a physical implementation to reread and fold all 63 on each load.\n\nDefine a[k] = ROL32(r[k], 63-k), S = XOR of all a[k], and P_s = XOR of a[k] for k < s. Then the exact source expression is:\n\n address_source(s) = r[s] XOR ROR32(P_s, 1) XOR S XOR P_s XOR a[s]\n\nA prefix-XOR tree supports point updates and prefix queries in logarithmic time. The included model checked 33,024 comparisons, including 4,096 state updates, without a mismatch. The algebra follows by distributing the rotation across XOR: values before the excluded source have one fewer subsequent rotation; values after it retain their original exponent.\n\nThis is NOT evidence that the full hash is cheap, that the necessary 64-register state is compressible to one word, or that the extra index state is free. Cached prefix state, port bandwidth and update costs must all be priced. The GPU compiler may already remove some redundant work. It is a concrete alternative the adversarial designer must be allowed, and potentially a byte-preserving implementation experiment for both sides.\n\nDo not respond by adding unmeasured nonlinear work. First implement the cheapest alternatives, remeasure GPU cost, then compare complete hardware designs. A one-register perturbation test cannot establish a minimum circuit or storage cost.\n", + "source_ranges": [ + { + "path": "pow/src/verify.rs", + "start": 674, + "end": 692 + }, + { + "path": "pow/src/generator.rs", + "start": 258, + "end": 277 + } + ], + "required_regressions": [ + "Native reference-vs-incremental expression equivalence across all source registers and real instruction updates.", + "Full-kernel output equivalence, registers, spills, wall power and accepted throughput across target GPUs.", + "Adversary physical design includes prefix caching/recomputation cost; no assumed full 63-read cost on every load." + ] + }, + { + "id": "F06", + "title": "The v6 acceptance and census gates are not complete for the final execution", + "priority": "P1 - freeze blocker", + "evidence_status": "STATIC SOURCE + SOURCE-REPORTED RESULTS", + "body": "\nThe new code explicitly executes the V4 shadow in its acceptance interpreter, includes repeated-source and index-concentration checks, and contains a regression test for shadow agreement. That improves on the older review. The v6 comments nevertheless say reg64's draw/acceptance are the underlying class's, while the liveness check is a separate research check not wired into canonical acceptance. Its sampling checks influence, not a formal unavoidable-state lower bound.\n\nThe census is similarly candid: rw2 fails its F8 line; fold plus rw1 is stronger on the reported controls; reg64/all results are based on the full tracing path with closed-form data, and the live-dataset point remains owed. These source results must not be promoted into an unconditional full-v6 pass.\n\nFreeze one agreed acceptance rule for the actual scheduled 64-register execution, and specify safe deterministic fallback behavior when a candidate fails. Re-run known-bad seeds, unseen seeds, real datasets, bound headers/nonces, the combined intended width/geometry and all family transitions. Retain rw2 as a rejected control unless new evidence changes the decision.\n", + "source_ranges": [ + { + "path": "pow/src/accept.rs", + "start": 114, + "end": 119 + }, + { + "path": "pow/src/accept.rs", + "start": 625, + "end": 637 + }, + { + "path": "pow/src/accept.rs", + "start": 867, + "end": 871 + }, + { + "path": "pow/src/generator.rs", + "start": 258, + "end": 264 + }, + { + "path": "v6/igneum-v6-freeze-tree/docs/analysis/class-v6/census-packs.md", + "start": 8, + "end": 22 + }, + { + "path": "v6/igneum-v6-freeze-tree/docs/analysis/class-v6/census-packs.md", + "start": 40, + "end": 49 + } + ], + "required_regressions": [ + "Acceptance/reference/emitter evaluate the same activated schedule.", + "Full live-dataset census on unseen seeds and the complete v6 pack.", + "A failed experimental rule does not silently exhaust generation or bypass the intended resource requirement." + ] + }, + { + "id": "F07", + "title": "VRAM admission and proving deadlines need one operator-level scheduler", + "priority": "P1 - miner economics and reliability", + "evidence_status": "SOURCE-REPORTED HARDWARE RESULTS + STATIC INTEGRATION REVIEW", + "body": "\nThe coexistence records report successful standalone compressed proofs: 13.2 seconds on a 3060 12 GB and 8.2 seconds on a 4060 8 GB after correcting the packaged prover server. They also report that both fail when run beside the 5.5 GiB dataset miner, with device allocation failures while mining continues. These are team measurements, not measurements made for this review. The registered reg64 rows use a different kit configuration and must not be combined with ds55 rows as one benchmark.\n\nThe right product path is explicit modes: simultaneous execution only on tested configurations with headroom; time-sharing on smaller cards with actual dataset eviction/release and confirmed memory availability; mining-only where a complete paid proof job cannot fit. Merely pausing kernel dispatch does not establish that GPU allocations were released.\n\nUse per-device identity and a memory reservation/lease state machine across miner, prover, aggregation, benchmark and next-epoch preparation. Include time to evict/rebuild datasets, WSL process startup, aggregation and payment deadlines in job admission. Do not market an isolated successful shard as proof that the card can finish the economically relevant segment.\n", + "source_ranges": [ + { + "path": "v6/igneum-v6-freeze-tree/docs/analysis/class-v6/coexist-rows.md", + "start": 17, + "end": 37 + }, + { + "path": "v6/igneum-v6-freeze-tree/docs/analysis/class-v6/coexist-rows.md", + "start": 60, + "end": 86 + } + ], + "required_regressions": [ + "Same final v6 configuration: mine -> evict -> prove -> aggregate -> submit -> rebuild -> resume; no leaked reservations.", + "OOM, process crash and stale work recover without losing wallet state or silently consuming power.", + "16 GB+ simultaneous mode only after measured peak plus next-epoch headroom; smaller-card modes labelled separately." + ] + }, + { + "id": "F08", + "title": "The proving pipeline reports waste and deadline censoring, not sustained capacity", + "priority": "P1 - proving product gate", + "evidence_status": "SOURCE-REPORTED OPERATIONAL DATA; NOT INDEPENDENTLY REPLAYED", + "body": "\nThe supplied pipeline report says the requested two-hour declared-load window does not exist in its record. It describes a class-v5 transition stall/partition and 93 paid segments in the paid interval, not a successful end-to-end hold at 150 transactions per second. Its 3060 tier completed zero paid segments over 313 claims. This does not prove a 3060 can never prove profitably: the same report says its completed submissions occurred after the stall, and the standalone fixture succeeds. It does show the claimed consumer-paid-work experience is not established by this run.\n\nA particularly important measurement issue: the worklist stays around 600 entries because entries expire at a deadline whether proved or not. Therefore bounded queue length does not establish sufficient proving capacity. The report itself discloses this mechanism.\n\nAdd lifecycle accounting: eligible work = completed + active + expired + explicitly cancelled, with definitions preventing double-counting. Publish deadline misses and useful accepted proof throughput, not just queue depth. Attribute failure to protocol partition, packaging, proving, assignment race, aggregation or submission. The source reports 70 wasted card-hours versus roughly 4 paid, dominated by the chain incident, so it would be wrong to call that all a prover-speed failure.\n\nPrioritise feasible job sizing and deadlines, resumable verified shards/checkpoints, early cancellation of obsolete claims, and bounded assignment protection. Protection must prevent slow or malicious claimants from monopolising work; do not simply promise no competing completion can ever occur. Run the two-hour workload test on the pinned release, then a longer independent soak.\n", + "source_ranges": [ + { + "path": "proving/igneum-proving/docs/analysis/proving-pipeline-2026-10-08.md", + "start": 7, + "end": 16 + }, + { + "path": "proving/igneum-proving/docs/analysis/proving-pipeline-2026-10-08.md", + "start": 35, + "end": 84 + }, + { + "path": "proving/igneum-proving/docs/analysis/proving-pipeline-2026-10-08.md", + "start": 86, + "end": 121 + } + ], + "required_regressions": [ + "Report every eligible job outcome, including expired work; a bounded list cannot hide losses.", + "Consumer tiers complete and receive payment for declared jobs before claims about income.", + "Sustained real workload across class transitions, with restart/retry and no publisher intervention." + ] + }, + { + "id": "F09", + "title": "The economic model explicitly retains a failed specialist case", + "priority": "P1 - founding claim not yet earned", + "evidence_status": "SOURCE-REPORTED MODEL + DISPLAYED-ARITHMETIC CHECK", + "body": "\nThe coexistence model states that the desired competitiveness statement does not hold for its modeled N2 SRAM die after development is sunk, and that the remaining deterrent is the investment decision. That is not proof the proposed die is manufacturable at the stated cost or throughput. It is also not evidence that the fundamental gate has passed.\n\nThere are at least two items to repair before using the model as certification. Its condition (c) requires fleet cost to exceed a year's mining revenue but labels USD 18M against USD 40-80M a pass; those displayed numbers do not satisfy that inequality. The table or criterion may be mistaken. Condition (g) also treats proving income as a business the specialised supplier cannot enter because its hash engine cannot prove. A company can own companion GPUs or buy proofs; the single-device limitation does not exclude the operator.\n\nReproduce the model from raw inputs, price the SRAM/recomputation design at physical board boundaries, include uncertainty and independent hardware critique, and test a hybrid operator. Treat unknown feasibility as unknown, not either a proven attack or an automatic pass. No retirement credit without a demonstrated adaptation penalty.\n", + "source_ranges": [ + { + "path": "v6/igneum-v6-freeze-tree/docs/analysis/class-v6/coexistence-model.md", + "start": 299, + "end": 321 + } + ], + "required_regressions": [ + "Generate all pass/fail cells directly from the declared inequalities and inputs.", + "Independent feasibility and cost evaluation of the strongest modeled SRAM/hybrid opponent.", + "GPU owners and entrants remain viable under the approved scenario envelope without assuming chip absence or death." + ] + }, + { + "id": "F10", + "title": "CUDA production readback has an existing OpenCL optimization to borrow", + "priority": "P2 - byte-preserving performance experiment", + "evidence_status": "STATIC SOURCE; SPEEDUP NOT MEASURED", + "body": "\nThe CUDA serving loop synchronises and copies one 64-bit result per nonce to the CPU, then scans it while holding its GPU mutex. For 2^24 nonces that is 128 MiB of result data per batch. Its benchmark times the kernel/synchronisation but reads the full result only for warm-up, so the benchmark does not include the same per-batch production cost.\n\nOpenCL already contains a select kernel that returns matching nonce/hash pairs plus sentinel words, with a counter and full-read fallback when more than 256 hits occur. This is not missing everywhere: it is a cross-backend parity opportunity. Port the proven shape to CUDA first as a separate selection pass, retaining correctness sentinels and overflow handling. Then test fusion/asynchronous overlap if justified. Metal still scans shared output on the CPU; unified memory means it is not the same PCIe-copy problem, so profile it separately.\n\nBenchmark accepted shares per wall-joule in serving mode, including setup, stale cancellation, readback, host power and pool submission. No percentage gain is claimed here.\n", + "source_ranges": [ + { + "path": "mining/proto-cuda/nvrtc/worker.cpp", + "start": 1254, + "end": 1295 + }, + { + "path": "mining/proto-cuda/nvrtc/worker.cpp", + "start": 1318, + "end": 1341 + }, + { + "path": "mining/proto-opencl/host.c", + "start": 1652, + "end": 1705 + }, + { + "path": "mining/proto-opencl/host.c", + "start": 1882, + "end": 1899 + }, + { + "path": "mining/proto-metal/main.swift", + "start": 3344, + "end": 3370 + } + ], + "required_regressions": [ + "Compare exact found nonce/hash sets with full-read mode, including all-hit overflow and zero-hit cases.", + "Test stale jobs, high-32 rollover, tail batches and asynchronous buffer reuse.", + "Compare production throughput and wall energy, not only the isolated kernel timer." + ] + }, + { + "id": "F11", + "title": "Ember needs workload-aware identity and objective-aware search", + "priority": "P2 - product performance", + "evidence_status": "STATIC SOURCE + REACHABILITY EXAMPLE", + "body": "\nEmber has useful thermal/fault checks, power and clock controls, calibration rows and fleet priors. Its shipped tier tests pass in this review. Those tests do not measure actual safe tuning or globally optimal settings.\n\nThe five-step hill climb proposes memory-up, core-down or both, even for MaxRate (which changes the score to MH/s). Starting from a low-clock efficiency prior, this search cannot propose a higher core clock or change the fixed power cap to escape that starting regime. A full sweep can choose a new start, so the finding is a limitation of this climb, not evidence every MaxRate setting is wrong.\n\nThe prior key uses card model, driver major and class. The workload class helper is based on load/wide-load counts. This is insufficient as a validated measurement identity for changes in memory geometry, compiler, reg64 schedule or concurrent proving. A prior may remain a useful starting hint; it should not be treated as a current certified optimum.\n\nUse a two-sided, bounded search appropriate to the chosen objective; rebase when switching goals; fingerprint the actual workload/backend and retain per-device calibration separately from fleet hints. Use paired A/B/A samples, a stability soak and rejected-work checks. Support separate mining-only, proving-only and hybrid profiles, coordinated by the device scheduler. Optimise accepted work or transparent net-return estimates, not raw displayed MH/s alone.\n", + "source_ranges": [ + { + "path": "mining/app/igneum-app/src/ember.rs", + "start": 211, + "end": 280 + }, + { + "path": "mining/app/igneum-app/src/ember.rs", + "start": 493, + "end": 520 + }, + { + "path": "mining/app/igneum-app/src/ember.rs", + "start": 606, + "end": 619 + } + ], + "required_regressions": [ + "Goal switch from an efficiency prior can explore higher core/power when policy allows.", + "Driver, workload, dataset, compiler and device changes invalidate certification while retaining optional hints.", + "Thermal/error/late-share events revert safely, including process or machine crash." + ] + }, + { + "id": "F12", + "title": "Pool payouts have a broadcast-before-durable-intent window", + "priority": "P1 - payment integrity", + "evidence_status": "STATIC SOURCE + ISOLATED CRASH SEQUENCE", + "body": "\nThe payout loop broadcasts first, then updates in-memory balances and records; disk snapshots are a separate periodic loop. If a transaction succeeds externally and the process dies before the debit is durable, restart can load the old payable balance and send again using a later nonce. A lost RPC response creates a related uncertain-outcome problem. The isolated model shows 100 units due becoming 200 externally paid under those assumptions; no actual transaction was sent.\n\nReceipt checking does exist, and failed receipts re-credit balances. Do not describe this as a pool with no receipt logic. However, a receipt is marked confirmed immediately and the loop subsequently visits only sent records; the supplied path does not establish finality-aware reorg handling.\n\nPersist an idempotent payment intent and exact signed transaction/hash BEFORE broadcast, reserve the balance atomically, reconcile the same intent after timeout/restart, and finalise against the chain's declared finality. Use explicit prepared/broadcast/mined/finalised/reorged/replaced states. Test crashes around every durable step.\n", + "source_ranges": [ + { + "path": "mining/pool/src/payout.rs", + "start": 228, + "end": 261 + }, + { + "path": "mining/pool/src/payout.rs", + "start": 265, + "end": 296 + }, + { + "path": "mining/pool/src/main.rs", + "start": 138, + "end": 149 + } + ], + "required_regressions": [ + "Crash before/after broadcast, response timeout, restart before snapshot: no duplicate payment or silent debt loss.", + "Same signed transaction retried, fee replacement reconciled by intent, not a new payment.", + "Receipt reorg and finality pause leave correct pending obligations." + ] + }, + { + "id": "F13", + "title": "Pool admission and membership need bounded resources", + "priority": "P1 - service resilience", + "evidence_status": "STATIC SOURCE + ISOLATED MEMBERSHIP MODEL", + "body": "\nThe server checks MAX_LINE after reading a full line, uses an unbounded outgoing channel, and inserts a nonce into a job's seen set before validation. Repeated Authorize requests create fresh members without removing or rejecting the prior one, while disconnect removes only the latest member. The small state-machine reproduction leaves two members after three authorizations on one connection and disconnect.\n\nThese are resource-control issues, not demonstrated remote exploits against a running pool. The verifier semaphore is a useful existing control but does not bound every queue or allocation.\n\nEnforce frame size while reading, bounded write queues, connection/request budgets, a single authenticated membership per session, cheap target/context prefilters, and bounded deduplication with in-flight handling. Test slow readers and malformed/invalid share floods without expensive network attacks. Member vote keys are already committed into the template; preserve that improvement.\n", + "source_ranges": [ + { + "path": "mining/pool/src/server.rs", + "start": 62, + "end": 99 + }, + { + "path": "mining/pool/src/server.rs", + "start": 115, + "end": 175 + }, + { + "path": "mining/pool/src/server.rs", + "start": 234, + "end": 255 + }, + { + "path": "mining/pool/src/server.rs", + "start": 281, + "end": 299 + }, + { + "path": "mining/pool/src/node.rs", + "start": 41, + "end": 48 + } + ], + "required_regressions": [ + "Repeated authorization rejected or atomically replaces and cleans prior state.", + "Oversized unterminated frame rejected within fixed memory/time budget.", + "Slow clients and invalid share floods cannot grow unbounded member, nonce or outgoing state." + ] + }, + { + "id": "F14", + "title": "Developer fleet control must not silently become the public client trust model", + "priority": "P1 - public client/independence gate", + "evidence_status": "STATIC SOURCE + BOOLEAN GUARD REPRODUCTION", + "body": "\nThe supplied settings explicitly call remote jobs default-on for the devnet build. Jobs are signed and have a visible disable switch; disabling aborts work. This is not a hidden unauthenticated backdoor. It is still powerful publisher control: run-script, fetch, collect, restart and update-now jobs share the OTA signing key, and some jobs run elevated or as WSL root.\n\nThe updater's auto-off guard is bypassed for an urgent release (unsupported version or nearby fork). This is intentional in the supplied policy, not a signature bypass. The remaining staging/safety checks still apply. An operator who disabled automatic updates should not unknowingly grant an urgency label permission to install arbitrary future software.\n\nSeparate a controlled lab/developer build from the public miner; remove arbitrary remote execution from the public default or use narrow explicit per-capability consent and a separate trust root. Keep user update acceptance distinct from consensus activation. Emergency safety notifications may pause unsupported operations; they should not silently override the user's installation choice. Review any manifest-delivered consensus overrides under the same rule.\n", + "source_ranges": [ + { + "path": "mining/app/igneum-app/src/config.rs", + "start": 75, + "end": 81 + }, + { + "path": "mining/app/igneum-app/src/config.rs", + "start": 135, + "end": 151 + }, + { + "path": "mining/app/igneum-app/src/jobrun.rs", + "start": 1, + "end": 19 + }, + { + "path": "mining/app/igneum-app/src/ota.rs", + "start": 540, + "end": 555 + }, + { + "path": "mining/app/igneum-app/src/ota.rs", + "start": 589, + "end": 595 + } + ], + "required_regressions": [ + "Public build has no default arbitrary remote execution and a documented least-privilege boundary.", + "Automatic updates off remains off for urgent manifests until explicit action.", + "A compromised fleet/update signing key cannot silently acquire wallet access or activate a consensus change." + ] + } + ], + "unresolved_interpretations": [ + { + "id": "REC-01", + "topic": "Finality pause-only healing", + "R1": "I03 identifies stale post-window predicate and cites a later documented correction.", + "R2": "F04 warns the predicate alone does not establish permanent failure; historical-checkpoint backfill can affect healing.", + "closure": "Pin exact commit, spec and mode; run native post-window healing with and without required historical data. This edition does not choose a winner." + } + ], + "claim": "A complete, independently substantiated technical/economic/operational/commercial pass supports a credible leadership-contender assessment, not a numerical rank certificate." +} \ No newline at end of file diff --git a/tools/ci/checks.txt b/tools/ci/checks.txt index 7efc1ff48..fe3169d84 100644 --- a/tools/ci/checks.txt +++ b/tools/ci/checks.txt @@ -74,6 +74,7 @@ the acceptance recorder: a run batch writes the registry's live fields and never the test map: every automated case of the registry maps to a cell or carries a NOT RUN reason; the map's ids exist the harness map page is generated from tools/ci/test-map.json and current P01 part A, the million-vector driver: a clean run is PASS, one wrong hash or one unanswered nonce is FAIL naming it (self-test, a fake worker) +the proving outcome ledger (review B F08): every claimed job ends in one outcome; the report's self-test reads a log and a state file to known numbers the registry's evidence rules: a PASS names evidence that exists, a touched evidence file moves with its row, stale evidence never reads PASS, a run_status needs the approval (self-test) the public ledger (docs/ledger-public.md) is what docs/fud-ledger.md generates: one row per item, no commit ids, times or team names (self-test first) the ledger page reads both entry heading forms (M1 and AP-F8-1) so no in-house pass row is dropped from /ledger (known-failed first) diff --git a/tools/ci/export-exclude.txt b/tools/ci/export-exclude.txt index b6b424184..9fb03be53 100644 --- a/tools/ci/export-exclude.txt +++ b/tools/ci/export-exclude.txt @@ -43,3 +43,4 @@ docs/design/app-audit-2026-10-08.md docs/ledger-public-pre-2.0.md # 8 October 2026: the Devnet 3 proving pipeline record (the fleet lane: box names, the operations record, the external review quoted) docs/analysis/proving-pipeline-2026-10-08.md +docs/analysis/proving-outcome-ledger.md diff --git a/tools/ci/pre-push.sh b/tools/ci/pre-push.sh index ba54d5e05..47f4ad888 100755 --- a/tools/ci/pre-push.sh +++ b/tools/ci/pre-push.sh @@ -173,6 +173,7 @@ tree_checks() { run "the test map: every automated case of the registry maps to a cell or carries a NOT RUN reason; the map's ids exist" node tools/ci/test-record.mjs --check run "the harness map page is generated from tools/ci/test-map.json and current" node tools/ci/test-map-doc.mjs --check run "P01 part A, the million-vector driver: a clean run is PASS, one wrong hash or one unanswered nonce is FAIL naming it (self-test, a fake worker)" python3 tools/ci/p01-vectors.py --self-test + run "the proving outcome ledger (review B F08): every claimed job ends in one outcome; the report's self-test reads a log and a state file to known numbers" python3 tools/fleet/prover-outcomes.py --self-test run "the registry's evidence rules: a PASS names evidence that exists, a touched evidence file moves with its row, stale evidence never reads PASS, a run_status needs the approval (self-test)" bash tools/ci/registry-evidence-check.sh --self-test run "the public ledger (docs/ledger-public.md) is what docs/fud-ledger.md generates: one row per item, no commit ids, times or team names (self-test first)" bash -c 'node tools/ledger/export-public.mjs --self-test && node tools/ledger/export-public.mjs --check' run "the ledger page reads both entry heading forms (M1 and AP-F8-1) so no in-house pass row is dropped from /ledger (known-failed first)" node tools/ledger-page.mjs --self-test diff --git a/tools/fleet/box-prover.py b/tools/fleet/box-prover.py index 074843de8..521a1afc9 100644 --- a/tools/fleet/box-prover.py +++ b/tools/fleet/box-prover.py @@ -16,6 +16,14 @@ proving-v1, 272b025) and tools/proving-v1/pc2-segments.ps1 around the four binar (sign-segment-record, igneum_submitSegmentRecord) once every shard is accepted and the statement equals the node's. 5. the paid state of every submitted segment polled each pass (igneum_getSegmentRecords); a state file for the collector: /root/fleet/out/prover-state.json; every event a RESULT line in /root/fleet/out/prover.log. + 6. the outcome ledger (review B F08, 8 October 2026): every claimed segment is an eligible job and ends in exactly one + outcome, paid, expired (its deadline passed with no paid record: unpaid after the submit, or held past it) or + cancelled (this prover gave it up for a cause: disk, export, cut, chain, timeout, shards, statement, sign, + refused); until then it is active. Each segment row carries outcome, cause, deadline, the margin at the claim, + the seconds spent (export, cut, chain; wasted unless paid) and the deadline miss in DAA; the state carries the + counters (outcomes, wasted_s by cause, deadline_misses) and every close is a RESULT outcome line. + tools/fleet/prover-outcomes.py reads the state files and the logs into the report (paid completions, missed + deadlines, wasted work by cause, accepted-proof throughput). Env: LABEL (the key label, kept for the box's life), WALLET (payout), THRESHOLD (element threshold or empty), MINER (keep|pause), RUN_HOURS (default 9). @@ -105,7 +113,23 @@ for _ in range(120): say(f"RESULT node {stamp()} {w}") miner_start() state = {"passes": 0, "claimed": 0, "submitted": 0, "paid": 0, "paid_wei": 0, "shards_accepted": 0, "shards_refused": 0, "segment_refused": 0, "held": 0, - "last_segment_s": 0, "segments": [], "started": stamp(), "label": LABEL, "wallet": WALLET, "key": kh} + "last_segment_s": 0, "segments": [], "started": stamp(), "label": LABEL, "wallet": WALLET, "key": kh, + "outcomes": {"paid": 0, "active": 0, "expired": 0, "cancelled": 0}, "wasted_s": {}, "deadline_misses": 0} +OUTCOMES = ("paid", "expired", "cancelled") +def seg_row(first): return next((x for x in state["segments"] if x["first"] == first), None) +def close(first, outcome, cause=None, tip=None): + """The outcome ledger's close (docstring point 6): one outcome per claimed segment, never a second one.""" + x = seg_row(first) + if x is None or x.get("outcome") in OUTCOMES: return + spent = round(float(x.get("export_s", 0)) + float(x.get("cut_s", 0)) + float(x.get("chain_s", 0)), 1) + x["outcome"] = outcome; x["closed_at"] = stamp(); x["spent_s"] = spent + if cause: x["cause"] = cause + if outcome == "expired" and tip is not None and x.get("deadline") is not None: x["miss_daa"] = max(0, int(tip) - int(x["deadline"])); state["deadline_misses"] += 1 + if outcome != "paid": + x["wasted_s"] = spent; k = cause or outcome; state["wasted_s"][k] = round(state["wasted_s"].get(k, 0) + spent, 1) + o = state["outcomes"]; o[outcome] = o.get(outcome, 0) + 1; o["active"] = max(0, state["claimed"] - o["paid"] - o["expired"] - o["cancelled"]) + say(f"RESULT outcome {stamp()} segment {first}..{x.get('last')} {outcome}" + (f" cause={cause}" if cause else "") + f" spent={spent} s" + + (f" miss={x['miss_daa']} DAA" if "miss_daa" in x else "") + f" ledger paid={o['paid']} active={o['active']} expired={o['expired']} cancelled={o['cancelled']}") attempted = set(); submitted = {}; held = {} # held: first -> {body file, deadline, last} last_seg_secs = 0; t_run0 = time.time() def save_state(): @@ -163,13 +187,13 @@ while (time.time() - t_run0) / 3600 < RUN_HOURS: say(f"RESULT paid {stamp()} segment {first}..{submitted[first]['last']} wei={wei} ({wei/1e18:.4f} IGN) carrier={hexi(rec['paid'].get('carrierNumber'))} after {int(time.time()-submitted[first]['at'])} s") for s in state["segments"]: if s["first"] == first: s["paid_wei"] = wei; s["paid_at"] = stamp() - del submitted[first] + close(first, "paid"); del submitted[first] elif rec is not None and tip > submitted[first]["deadline"] + 50: - say(f"RESULT unpaid {stamp()} segment {first} past its deadline unpaid; carried={len(rec.get('carried') or [])} pool={len(rec.get('pool') or [])}"); del submitted[first] + say(f"RESULT unpaid {stamp()} segment {first} past its deadline unpaid; carried={len(rec.get('carried') or [])} pool={len(rec.get('pool') or [])}"); close(first, "expired", "unpaid", tip); del submitted[first] # held fresh records offered again for first in list(held): h = held[first] - if tip > h["deadline"]: say(f"RESULT held_expired {stamp()} segment {first} deadline passed"); del held[first]; continue + if tip > h["deadline"]: say(f"RESULT held_expired {stamp()} segment {first} deadline passed"); close(first, "expired", "held_expired", tip); del held[first]; continue rr = submit("igneum_submitSegmentRecord", h["record"], h["proof_file"]) if rr and rr.get("accepted"): state["submitted"] += 1; submitted[first] = {"last": h["last"], "at": time.time(), "deadline": h["deadline"]}; drop_export(first, "record accepted"); say(f"RESULT submitted {stamp()} segment {first}..{h['last']} record accepted on retry (held {int(time.time()-h['since'])} s)"); del held[first] @@ -198,9 +222,11 @@ while (time.time() - t_run0) / 3600 < RUN_HOURS: if not picked: say(f"RESULT pass {p} {stamp()} {len(cands)} candidates, none usable; waiting"); time.sleep(15); continue first, last = picked["first"], picked["last"]; attempted.add(first); state["claimed"] += 1 say(f"RESULT claim {stamp()} segment {first}..{last} ({len(picked['shards'])} shards, {'continuing' if prev_file else 'fresh'}) margin={picked['margin']} tip={tip} candidates={len(cands)} rank_by=fnv") - seg = {"first": first, "last": last, "claimed_at": stamp(), "shards": len(picked["shards"]), "fresh": prev_file is None}; state["segments"].append(seg) + seg = {"first": first, "last": last, "claimed_at": stamp(), "shards": len(picked["shards"]), "fresh": prev_file is None, + "deadline": picked["deadline"], "margin_daa": picked["margin"], "outcome": "active"}; state["segments"].append(seg) + state["outcomes"]["active"] = max(0, state["claimed"] - state["outcomes"]["paid"] - state["outcomes"]["expired"] - state["outcomes"]["cancelled"]) prune_exports(); free = disk_free_pct() - if free < DISK_MIN_FREE_PCT: say(f"RESULT skip {stamp()} segment {first}: disk {free:.1f}% free is under the {DISK_MIN_FREE_PCT:.0f}% floor, no export"); time.sleep(60); continue + if free < DISK_MIN_FREE_PCT: say(f"RESULT skip {stamp()} segment {first}: disk {free:.1f}% free is under the {DISK_MIN_FREE_PCT:.0f}% floor, no export"); close(first, "cancelled", "disk"); time.sleep(60); continue d = f"{OUT}/segs/seg-{first}"; os.makedirs(d, exist_ok=True); t_seg0 = time.time() # export # a node whose EVM restarted at a chain block (0.3.13's exec restart rule) exports from that block, not genesis: the @@ -215,7 +241,7 @@ while (time.time() - t_run0) / 3600 < RUN_HOURS: seg["export_from"] = start_blk r = subprocess.run(["curl", "-s", "-m", "600", "-X", "POST", EVM, "-H", "Content-Type: application/json", "--data-binary", body, "-o", f"{d}/seq.json"]) try: json.dump(json.load(open(f"{d}/seq.json"))["result"], open(f"{d}/export.json", "w")) - except Exception as e: say(f"RESULT seg {first} export FAILED {str(e)[:100]}"); continue + except Exception as e: say(f"RESULT seg {first} export FAILED {str(e)[:100]}"); seg["export_s"] = round(time.time() - t, 1); close(first, "cancelled", "export"); continue seg["export_s"] = round(time.time() - t, 1); os.remove(f"{d}/seq.json") # cut t = time.time(); fixtures = [] @@ -224,7 +250,7 @@ while (time.time() - t_run0) / 3600 < RUN_HOURS: rr = subprocess.run([EXPORT, f"{d}/export.json", str(b), f"{d}/block-{b}.json", "--source", f"fleet {LABEL} live devnet, segment-aligned prover"], capture_output=True, text=True, timeout=600) if rr.returncode != 0: say(f"RESULT seg {first} cut {b} FAILED: {(rr.stdout + rr.stderr)[-200:]}"); ok = False; break fixtures.append(f"{d}/block-{b}.json") - if not ok: continue + if not ok: seg["cut_s"] = round(time.time() - t, 1); close(first, "cancelled", "cut"); continue seg["cut_s"] = round(time.time() - t, 1) # chain if MINER == "pause": miner_stop() @@ -244,7 +270,7 @@ while (time.time() - t_run0) / 3600 < RUN_HOURS: seg["peak_mib"] = peak open(f"{d}/chain.log", "w").write((rr.stdout if rr else "") + "\n" + (rr.stderr if rr else "TIMEOUT")) if not rr or rr.returncode != 0 or not os.path.exists(f"{d}/chain-results.json"): - say(f"RESULT seg {first} chain FAILED {stamp()} rc={rr.returncode if rr else 'timeout'} wall={seg['chain_s']} s: {((rr.stderr if rr else '') or '')[-200:].strip()}"); seg["failed"] = "chain"; continue + say(f"RESULT seg {first} chain FAILED {stamp()} rc={rr.returncode if rr else 'timeout'} wall={seg['chain_s']} s: {((rr.stderr if rr else '') or '')[-200:].strip()}"); seg["failed"] = "chain"; close(first, "cancelled", "chain" if rr else "timeout"); continue res = json.load(open(f"{d}/chain-results.json")) recs = [s for blk in res.get("blocks", []) for s in blk.get("shard_records", [])] say(f"RESULT seg {first} chain {stamp()} {len(recs)} shard records, chain_len {res.get('segment_chain_len')}, proof {res.get('segment_proof_bytes')} bytes, shards {res.get('shard_prove_seconds_total', 0):.1f} s, aggregation {res.get('aggregate_prove_seconds_total', 0):.1f} s, wall {seg['chain_s']} s, peak {peak:.0f} MiB") @@ -260,17 +286,17 @@ while (time.time() - t_run0) / 3600 < RUN_HOURS: else: state["shards_refused"] += 1; say(f"RESULT seg {first} shard {rcd['number']}/{rcd['shard']} refused: {(reply or {}).get('reason', reply)}") seg["shards_accepted"] = ok_shards say(f"RESULT seg {first} shards {stamp()} accepted {ok_shards} of {len(recs)}") - if ok_shards != len(recs): seg["failed"] = "shards"; continue + if ok_shards != len(recs): seg["failed"] = "shards"; close(first, "cancelled", "shards"); continue pv = res.get("segment_public_values", "") strip = lambda h: (h[2:] if h.startswith("0x") else h); strip2 = lambda h: (strip(h)[:472] + strip(h)[536:]) if len(strip(h)) == 680 else strip(h) if strip2(pv) != strip2(expected): a, b = strip2(pv), strip2(expected); off = next((i for i in range(min(len(a), len(b))) if a[i] != b[i]), min(len(a), len(b))) - say(f"RESULT seg {first} FAILED: statement differs from the node's at hex offset {off} (lengths {len(a)} vs {len(b)}); ours ...{a[max(0,off-8):off+56]} node ...{b[max(0,off-8):off+56]}"); seg["failed"] = "statement"; continue + say(f"RESULT seg {first} FAILED: statement differs from the node's at hex offset {off} (lengths {len(a)} vs {len(b)}); ours ...{a[max(0,off-8):off+56]} node ...{b[max(0,off-8):off+56]}"); seg["failed"] = "statement"; close(first, "cancelled", "statement"); continue last_hash = next(s["hash"] for s in picked["shards"] if s["number"] == last) sg = subprocess.run([f"{B}/igneum-miner", "sign-segment-record", LABEL, CHAIN, str(first), str(last), last_hash, WALLET, pv, res["segment_proof_sha256"]], capture_output=True, text=True).stdout.strip().split("\n")[-1] try: record = json.loads(sg).get("record") except Exception: record = None - if not record: say(f"RESULT seg {first} segment sign FAILED: {sg[:120]}"); seg["failed"] = "sign"; continue + if not record: say(f"RESULT seg {first} segment sign FAILED: {sg[:120]}"); seg["failed"] = "sign"; close(first, "cancelled", "sign"); continue reply = submit("igneum_submitSegmentRecord", record, res["segment_proof_file"]) seg_s = round(time.time() - t_seg0, 1); seg["end_to_end_s"] = seg_s if reply and reply.get("accepted"): @@ -283,6 +309,7 @@ while (time.time() - t_run0) / 3600 < RUN_HOURS: say(f"RESULT segment_refused {stamp()} segment {first}..{last}: {reason}; end to end {seg_s} s") if "pending until" in reason or "does not chain" in reason: held[first] = {"record": record, "proof_file": res["segment_proof_file"], "last": last, "deadline": picked["deadline"], "since": time.time()}; say(f"RESULT held {stamp()} segment {first} held for retry until DAA {picked['deadline']}") + else: close(first, "cancelled", "refused") for b in range(first, last + 1): try: os.remove(f"{d}/block-{b}.json") except OSError: pass @@ -290,5 +317,6 @@ while (time.time() - t_run0) / 3600 < RUN_HOURS: except OSError: pass save_state() miner_stop(); kill_server(); save_state() +_o = state["outcomes"]; say(f"RESULT ledger {stamp()} paid={_o['paid']} active={_o['active']} expired={_o['expired']} cancelled={_o['cancelled']} deadline_misses={state['deadline_misses']} wasted_s={json.dumps(state['wasted_s'], sort_keys=True)} active_segments={[x['first'] for x in state['segments'] if x.get('outcome') == 'active']}") say(f"RESULT summary {stamp()} passes={state['passes']} claimed={state['claimed']} submitted={state['submitted']} paid={state['paid']} paid_wei={state['paid_wei']} shards_accepted={state['shards_accepted']} shards_refused={state['shards_refused']} segment_refused={state['segment_refused']}") say(f"RESULT prover_done {stamp()}") diff --git a/tools/fleet/night.py b/tools/fleet/night.py index 697cebd7e..9a9508be9 100644 --- a/tools/fleet/night.py +++ b/tools/fleet/night.py @@ -16,11 +16,11 @@ curl -s -m 6 -X POST -H 'Content-Type: application/json' --data '{"jsonrpc":"2.0 curl -s -m 6 -X POST -H 'Content-Type: application/json' --data '{"jsonrpc":"2.0","id":1,"method":"igneum_getProvingStatus","params":[]}' http://127.0.0.1:26790/ | python3 -c 'import sys,json; r=sys.stdin.read(); d=json.loads(r).get("result",{}) if r.strip() else {}; v=d.get("v1",{}); w=v.get("segmentsInWindow",{}); print("tipDaa", int(d.get("tipDaa","0x0"),16), "fresh", v.get("freshRuleActive"), "paidShards", d.get("paidShards"), "pending", w.get("pending"), "proven", w.get("proven"), "unproven", w.get("unproven"), "paidSeg", v.get("paidSegments"))' 2>/dev/null /opt/igneum/pkg/bin/igneum-miner watch 1 grpc://127.0.0.1:26610 2>/dev/null | grep -o 'daa=[0-9]*' | tail -1 pgrep -c -f '[p]ython3 -u /root/fleet/in/box-prover.py' -for f in /root/fleet/out/prover-state.json /root/fleet/card*/out/prover-state.json; do [ -f $f ] && python3 -c 'import json,sys; s=json.load(open(sys.argv[1])); print("ps", s.get("claimed",0), s.get("submitted",0), s.get("paid",0), s.get("shards_accepted",0), s.get("shards_refused",0), s.get("segment_refused",0), s.get("held",0), s.get("miner_mhs",0))' $f; done; true""" +for f in /root/fleet/out/prover-state.json /root/fleet/card*/out/prover-state.json; do [ -f $f ] && python3 -c 'import json,sys; s=json.load(open(sys.argv[1])); print("ps", s.get("claimed",0), s.get("submitted",0), s.get("paid",0), s.get("shards_accepted",0), s.get("shards_refused",0), s.get("segment_refused",0), s.get("held",0), s.get("miner_mhs",0)); o=s.get("outcomes",{}); print("po", o.get("paid",0), o.get("active",0), o.get("expired",0), o.get("cancelled",0), s.get("deadline_misses",0), round(sum(s.get("wasted_s",{}).values()),1))' $f; done; true""" def probe(b): r, out, err = fleet.ssh(b, PROBE, timeout=45) if r != 0 or not out.strip(): return None - l = out.strip().split("\n"); d = {"swap": "", "exec": None, "blocked": "", "from": "", "tipDaa": None, "fresh": "", "paidShards": None, "pending": None, "proven": None, "unproven": None, "paidSeg": None, "daa": None, "provers": 0, "ps": []} + l = out.strip().split("\n"); d = {"swap": "", "exec": None, "blocked": "", "from": "", "tipDaa": None, "fresh": "", "paidShards": None, "pending": None, "proven": None, "unproven": None, "paidSeg": None, "daa": None, "provers": 0, "ps": [], "po": []} for x in l: if x.startswith("RESULT swap"): d["swap"] = x elif x.startswith("exec "): p = x.split(); d["exec"] = int(p[1]); d["blocked"] = p[3]; d["from"] = " ".join(p[5:]) @@ -28,6 +28,7 @@ def probe(b): elif x.startswith("daa="): d["daa"] = int(x[4:]) elif x.isdigit(): d["provers"] = int(x) elif x.startswith("ps "): d["ps"].append([float(v) for v in x.split()[1:]]) + elif x.startswith("po "): d["po"].append([float(v) for v in x.split()[1:]]) # the outcome ledger (review B F08): paid active expired cancelled deadline_misses wasted_s return d zero_since = {}; launched = set(); last_row = 0; last_hour = None hub = next(b for b in fleet.load().values() if b.get("hub") and b.get("state") != "destroyed" and b.get("hub_peer")) @@ -35,7 +36,8 @@ while True: reg = fleet.load() live = [(iid, b) for iid, b in reg.items() if b.get("state") != "destroyed" and b.get("ssh_host") and (b.get("phase") in ("1", "2") or b.get("hub"))] with ThreadPoolExecutor(14) as ex: res = dict(zip([i for i, _ in live], ex.map(lambda x: probe(x[1]), live))) - tot = {"provers": 0, "claimed": 0, "submitted": 0, "paid": 0, "shards": 0, "refused": 0, "segref": 0, "held": 0, "exec_ok": 0, "boxes": 0} + tot = {"provers": 0, "claimed": 0, "submitted": 0, "paid": 0, "shards": 0, "refused": 0, "segref": 0, "held": 0, "exec_ok": 0, "boxes": 0, + "outcomes": {"paid": 0, "active": 0, "expired": 0, "cancelled": 0}, "deadline_misses": 0, "wasted_s": 0.0} hubd = None for iid, b in live: d = res.get(iid) @@ -55,11 +57,15 @@ while True: launched.add(iid); fleet.patch(iid, stage="prover", state="running", doing=f"phase 2 prover on the executed tip ({d['exec']})"); log(f"{b['label']}: replay at the tip (exec {d['exec']}), prover started") tot["provers"] += d["provers"] for p in d["ps"]: tot["claimed"] += p[0]; tot["submitted"] += p[1]; tot["paid"] += p[2]; tot["shards"] += p[3]; tot["refused"] += p[4]; tot["segref"] += p[5]; tot["held"] += p[6] + for p in d["po"]: + for k, v in zip(("paid", "active", "expired", "cancelled"), p[:4]): tot["outcomes"][k] += int(v) + tot["deadline_misses"] += int(p[4]); tot["wasted_s"] = round(tot["wasted_s"] + p[5], 1) fleet.patch(iid, last_line=f"exec {d['exec']} tip {d['tipDaa']} provers {d['provers']} " + (" ".join(f"{int(p[0])}/{int(p[1])}/{int(p[2])}" for p in d["ps"]))) if time.time() - last_row > 900: row = {"hour": now()[:13], "at": now(), "provers": tot["provers"], "boxes_executing": tot["exec_ok"], "boxes": tot["boxes"], "claimed": tot["claimed"], "segments_submitted": tot["submitted"], "segments_done": tot["paid"], "shards_paid": tot["shards"], "shards_refused": tot["refused"], "segment_records_refused": tot["segref"], "held": tot["held"], "chain": ({"tipDaa": hubd["tipDaa"], "fresh": hubd["fresh"], "pending": hubd["pending"], "proven": hubd["proven"], "unproven": hubd["unproven"], "paidSeg": hubd["paidSeg"], "paidShards": hubd["paidShards"]} if hubd else {}), "coverage_pct": (round(100 * int(hubd["proven"]) / max(1, int(hubd["proven"]) + int(hubd["pending"]) + int(hubd["unproven"])), 1) if hubd and hubd["proven"] not in (None, "None") else None), + "outcomes": tot["outcomes"], "deadline_misses": tot["deadline_misses"], "wasted_s": tot["wasted_s"], # the fleet's outcome ledger totals (review B F08) "note": f"{tot['exec_ok']} of {tot['boxes']} boxes executing"} rows = json.load(open(NIGHT)) if os.path.exists(NIGHT) else []; rows.append(row); json.dump(rows, open(NIGHT, "w"), indent=1) log("row " + json.dumps(row)); last_row = time.time() diff --git a/tools/fleet/prover-outcomes.py b/tools/fleet/prover-outcomes.py new file mode 100755 index 000000000..3dea8aaf6 --- /dev/null +++ b/tools/fleet/prover-outcomes.py @@ -0,0 +1,231 @@ +#!/usr/bin/env python3 +"""The proving pipeline's outcome ledger (review B F08, 8 October 2026): every eligible job a prover claimed and the one +outcome it ended in, read from the fleet's prover state files (tools/fleet/box-prover.py point 6: segments[].outcome) and, +for a prover from before the ledger, reconstructed from its RESULT lines in prover.log. The report answers the finding's +three questions: paid completions, missed deadlines and wasted work by cause, plus the accepted-proof throughput. + + tools/fleet/prover-outcomes.py --state out/prover-state.json [--state ...] [--log out/prover.log ...] [--json] + tools/fleet/prover-outcomes.py --self-test + +Outcomes: paid (a carrying block paid the segment record), active (claimed and not yet closed: in work, submitted and +waiting, or held for a retry), expired (the deadline passed with no paid record: cause unpaid after a submit, held_expired +for a held record, or never_submitted when the log ends past the deadline with no submit), cancelled (the prover gave the +job up: cause disk, export, cut, chain, timeout, shards, statement, sign, refused). Wasted work is the export, cut and +chain seconds of every job that was not paid, by cause. A job row from a state file wins over the same segment in a log. +""" +import sys, os, json, re, datetime, statistics + +CAUSES_CANCELLED = ("disk", "export", "cut", "chain", "timeout", "shards", "statement", "sign", "refused") +CAUSES_EXPIRED = ("unpaid", "held_expired", "never_submitted") + +def ts(s): + try: return datetime.datetime.strptime(s, "%Y-%m-%dT%H:%M:%SZ").replace(tzinfo=datetime.timezone.utc).timestamp() + except Exception: return None + +def jobs_from_state(state, label=None): + """One job per segment row; an old row (no outcome field) is classified from what it carries.""" + out = [] + for x in state.get("segments") or []: + j = {"label": label or state.get("label"), "first": x.get("first"), "last": x.get("last"), "claimed_at": x.get("claimed_at"), "deadline": x.get("deadline"), + "margin_daa": x.get("margin_daa"), "shards": x.get("shards"), "fresh": x.get("fresh"), + "spent_s": x.get("spent_s", round(float(x.get("export_s", 0)) + float(x.get("cut_s", 0)) + float(x.get("chain_s", 0)), 1)), + "chain_s": x.get("chain_s"), "end_to_end_s": x.get("end_to_end_s"), "submitted_at": x.get("submitted_at"), "paid_at": x.get("paid_at"), + "paid_wei": x.get("paid_wei"), "closed_at": x.get("closed_at"), "miss_daa": x.get("miss_daa"), "source": "state"} + o = x.get("outcome") + if o in ("paid", "expired", "cancelled", "active"): j["outcome"] = o; j["cause"] = x.get("cause") + elif x.get("paid_wei") is not None: j["outcome"] = "paid"; j["cause"] = None + elif x.get("failed"): j["outcome"] = "cancelled"; j["cause"] = x["failed"] + elif x.get("refused") and not x.get("submitted_at"): j["outcome"] = "cancelled"; j["cause"] = "refused" + else: j["outcome"] = "active"; j["cause"] = None + out.append(j) + return out + +def miss(tip, deadline): + """The deadline miss in DAA from the last tip the log named; None when that tip is stale (before the deadline), never negative.""" + return tip - deadline if tip is not None and deadline is not None and tip > deadline else None + +LINE = re.compile(r"^RESULT (\S+) (\S+)(?: (.*))?$") +def jobs_from_log(text, label=None): + """Reconstruct the ledger from a prover.log: claim opens a job; chain / shards / statement / sign / segment_refused / + held / submitted / paid / unpaid / held_expired / outcome lines move it. The last tip seen dates a never_submitted expiry.""" + jobs = {}; order = []; last_tip = None; last_at = None; label = label + for raw in text.split("\n"): + m = LINE.match(raw.strip()) + if not m: continue + kind, a, rest = m.group(1), m.group(2), m.group(3) or "" + at = a if ts(a) else None + if at: last_at = at + if kind == "start": + mm = re.search(r"label=(\S+)", rest); label = label or (mm.group(1) if mm else None); continue + mt = re.search(r"\btip[= ](\d+)", rest) + if mt: last_tip = int(mt.group(1)) + if kind == "claim": + mm = re.match(r"segment (\d+)\.\.(\d+) \((\d+) shards, (\w+)\) margin=(\d+) tip=(\d+)", rest) + if not mm: continue + first = int(mm.group(1)); j = {"label": label, "first": first, "last": int(mm.group(2)), "claimed_at": at, "shards": int(mm.group(3)), "fresh": mm.group(4) == "fresh", + "margin_daa": int(mm.group(5)), "deadline": int(mm.group(6)) + 1 + int(mm.group(5)), "spent_s": 0.0, "chain_s": None, "end_to_end_s": None, + "submitted_at": None, "paid_at": None, "paid_wei": None, "closed_at": None, "miss_daa": None, "outcome": "active", "cause": None, "source": "log"} + jobs[first] = j; order.append(first); continue + if kind == "outcome": + mm = re.match(r"segment (\d+)\.\.(\d+) (\w+)(?: cause=(\w+))? spent=([\d.]+) s(?: miss=(\d+) DAA)?", rest) + if not mm or int(mm.group(1)) not in jobs: continue + j = jobs[int(mm.group(1))]; j.update(outcome=mm.group(3), cause=mm.group(4), spent_s=float(mm.group(5)), closed_at=at, miss_daa=int(mm.group(6)) if mm.group(6) else None); continue + if kind == "seg": + first = int(a) if a.isdigit() else None + if first not in jobs: continue + j = jobs[first] + if j["outcome"] != "active": continue + if rest.startswith("chain FAILED"): + mw = re.search(r"wall=([\d.]+) s", rest); w = float(mw.group(1)) if mw else 0.0 + j["chain_s"] = w; j["spent_s"] = round(j["spent_s"] + w, 1); j.update(outcome="cancelled", cause="timeout" if "rc=timeout" in rest else "chain", closed_at=at) + elif rest.startswith("chain "): + ms_ = re.search(r"shards ([\d.]+) s, aggregation ([\d.]+)", rest) + if ms_: j["chain_s"] = round(float(ms_.group(1)) + float(ms_.group(2)), 1); j["spent_s"] = round(j["spent_s"] + j["chain_s"], 1) + elif rest.startswith("export FAILED"): j.update(outcome="cancelled", cause="export", closed_at=at) + elif " cut " in (" " + rest) and "FAILED" in rest: j.update(outcome="cancelled", cause="cut", closed_at=at) + elif rest.startswith("shards "): + mm = re.search(r"accepted (\d+) of (\d+)", rest) + if mm and mm.group(1) != mm.group(2): j.update(outcome="cancelled", cause="shards", closed_at=at) + elif rest.startswith("FAILED: statement"): j.update(outcome="cancelled", cause="statement", closed_at=at) + elif "segment sign FAILED" in rest: j.update(outcome="cancelled", cause="sign", closed_at=at) + continue + mm = re.match(r"segment (\d+)", rest) + if not mm or int(mm.group(1)) not in jobs: continue + j = jobs[int(mm.group(1))] + if kind == "submitted": + j["submitted_at"] = at; me = re.search(r"end to end ([\d.]+) s", rest) + if me: j["end_to_end_s"] = float(me.group(1)) + elif kind == "segment_refused": + me = re.search(r"end to end ([\d.]+) s", rest) + if me: j["end_to_end_s"] = float(me.group(1)) + j["_refused_at"] = at + elif kind == "held": j.pop("_refused_at", None) + elif kind == "paid" and j["outcome"] == "active": + mw = re.search(r"wei=(\d+)", rest); j.update(outcome="paid", paid_at=at, closed_at=at, paid_wei=int(mw.group(1)) if mw else None) + elif kind == "unpaid" and j["outcome"] == "active": j.update(outcome="expired", cause="unpaid", closed_at=at, miss_daa=miss(last_tip, j.get("deadline"))) + elif kind == "held_expired" and j["outcome"] == "active": j.update(outcome="expired", cause="held_expired", closed_at=at, miss_daa=miss(last_tip, j.get("deadline"))) + for first in order: + j = jobs[first] + if j["outcome"] == "active" and j.pop("_refused_at", None): j.update(outcome="cancelled", cause="refused", closed_at=j.get("closed_at") or last_at) + # a job never submitted whose deadline the chain passed while the log went on: expired, never_submitted + if j["outcome"] == "active" and j["submitted_at"] is None and last_tip is not None and j.get("deadline") and last_tip > j["deadline"] + 50: + j.update(outcome="expired", cause="never_submitted", closed_at=last_at, miss_daa=last_tip - j["deadline"]) + j.pop("_refused_at", None) + return [jobs[f] for f in order] + +def median(xs): + xs = [x for x in xs if x is not None] + return round(statistics.median(xs), 1) if xs else None + +def report(jobs): + tot = {k: sum(1 for j in jobs if j["outcome"] == k) for k in ("paid", "active", "expired", "cancelled")} + paid = [j for j in jobs if j["outcome"] == "paid"]; exp = [j for j in jobs if j["outcome"] == "expired"]; can = [j for j in jobs if j["outcome"] == "cancelled"] + to_pay = [ts(j["paid_at"]) - ts(j["submitted_at"]) for j in paid if j.get("paid_at") and j.get("submitted_at") and ts(j["paid_at"]) and ts(j["submitted_at"])] + wasted = {} + for j in exp + can: + k = j.get("cause") or j["outcome"]; w = wasted.setdefault(k, {"jobs": 0, "seconds": 0.0}); w["jobs"] += 1; w["seconds"] = round(w["seconds"] + float(j.get("spent_s") or 0), 1) + t0 = min((ts(j["claimed_at"]) for j in jobs if j.get("claimed_at") and ts(j["claimed_at"])), default=None) + t1 = max((ts(j[k]) for j in jobs for k in ("closed_at", "paid_at", "submitted_at", "claimed_at") if j.get(k) and ts(j[k])), default=None) + span_h = round((t1 - t0) / 3600, 2) if t0 is not None and t1 is not None and t1 > t0 else None + shards_paid = sum(int(j.get("shards") or 0) for j in paid) + return { + "jobs": len(jobs), "outcomes": tot, + "paid": {"segments": tot["paid"], "shards": shards_paid, "ign": round(sum(int(j.get("paid_wei") or 0) for j in paid) / 1e18, 4), + "median_end_to_end_s": median([j.get("end_to_end_s") for j in paid]), "median_time_to_pay_s": median(to_pay), "median_margin_daa": median([j.get("margin_daa") for j in paid])}, + "missed_deadlines": {"jobs": tot["expired"], "by_cause": {c: sum(1 for j in exp if j.get("cause") == c) for c in CAUSES_EXPIRED if any(j.get("cause") == c for j in exp)}, + "median_miss_daa": median([j.get("miss_daa") for j in exp]), "median_margin_daa": median([j.get("margin_daa") for j in exp]), "wasted_s": round(sum(float(j.get("spent_s") or 0) for j in exp), 1)}, + "wasted_by_cause": dict(sorted(wasted.items(), key=lambda kv: -kv[1]["seconds"])), "wasted_s": round(sum(w["seconds"] for w in wasted.values()), 1), + "spent_s": round(sum(float(j.get("spent_s") or 0) for j in jobs), 1), + "throughput": {"span_h": span_h, "segments_paid_per_h": round(tot["paid"] / span_h, 2) if span_h else None, "shards_paid_per_h": round(shards_paid / span_h, 1) if span_h else None, + "paid_share_of_spent": round(sum(float(j.get("spent_s") or 0) for j in paid) / max(1e-9, sum(float(j.get("spent_s") or 0) for j in jobs)), 3) if jobs else None}, + "active": [{"label": j.get("label"), "first": j["first"], "last": j["last"], "claimed_at": j.get("claimed_at"), "submitted_at": j.get("submitted_at"), "deadline": j.get("deadline")} for j in jobs if j["outcome"] == "active"], + } + +def text(r): + o = r["outcomes"]; p = r["paid"]; m = r["missed_deadlines"]; t = r["throughput"] + L = [f"Outcome ledger: {r['jobs']} jobs: paid {o['paid']}, active {o['active']}, expired {o['expired']}, cancelled {o['cancelled']}", + f"Paid completions: {p['segments']} segments ({p['shards']} shards, {p['ign']} IGN); median end to end {p['median_end_to_end_s']} s, median time to pay {p['median_time_to_pay_s']} s, median margin at claim {p['median_margin_daa']} DAA", + f"Missed deadlines: {m['jobs']} (" + ", ".join(f"{k} {v}" for k, v in m["by_cause"].items()) + f"); median miss {m['median_miss_daa']} DAA past the deadline, median margin at claim {m['median_margin_daa']} DAA, {m['wasted_s']} s of work", + f"Wasted work by cause ({r['wasted_s']} s of {r['spent_s']} s spent):"] + for k, w in r["wasted_by_cause"].items(): L.append(f" {k}: {w['jobs']} jobs, {w['seconds']} s") + if not r["wasted_by_cause"]: L.append(" none") + L.append(f"Throughput over {t['span_h']} h: {t['segments_paid_per_h']} segments paid per hour, {t['shards_paid_per_h']} shards paid per hour; {t['paid_share_of_spent']} of the seconds spent were paid") + if r["active"]: L.append("Active: " + ", ".join(f"{a['label'] or '?'} {a['first']}..{a['last']}" + (" submitted" if a["submitted_at"] else "") for a in r["active"])) + return "\n".join(L) + +SELF_LOG = """RESULT start 2026-10-08T10:00:00Z label=t1 key=0xabc wallet=0x19 threshold=default miner=keep host=True +RESULT claim 2026-10-08T10:00:10Z segment 100..109 (10 shards, fresh) margin=400 tip=1000 candidates=3 rank_by=fnv +RESULT seg 100 chain 2026-10-08T10:05:00Z 10 shard records, chain_len 1, proof 1000 bytes, shards 200.0 s, aggregation 80.0 s +RESULT seg 100 shards 2026-10-08T10:05:10Z accepted 10 of 10 +RESULT submitted 2026-10-08T10:05:20Z segment 100..109 record accepted (new=True, chain_len 1), aggregator share 0.1 IGN, end to end 310.0 s, mhs 1 +RESULT paid 2026-10-08T10:08:20Z segment 100..109 wei=2000000000000000000 (2.0000 IGN) carrier=1500 after 180 s +RESULT claim 2026-10-08T10:10:00Z segment 110..119 (10 shards, continuing) margin=300 tip=1600 candidates=2 rank_by=fnv +RESULT seg 110 chain FAILED 2026-10-08T10:40:00Z rc=timeout wall=1800.0 s: +RESULT claim 2026-10-08T10:41:00Z segment 120..129 (10 shards, fresh) margin=250 tip=2400 candidates=2 rank_by=fnv +RESULT seg 120 chain 2026-10-08T10:46:00Z 10 shard records, chain_len 1, proof 1000 bytes, shards 210.0 s, aggregation 70.0 s +RESULT seg 120 shards 2026-10-08T10:46:10Z accepted 10 of 10 +RESULT submitted 2026-10-08T10:46:20Z segment 120..129 record accepted (new=True, chain_len 1), aggregator share 0.1 IGN, end to end 320.0 s, mhs 1 +RESULT pass 5 2026-10-08T10:50:00Z no whole segment inside the margin (worklist 20 entries, tip 2700, mhs 1); waiting +RESULT unpaid 2026-10-08T11:00:00Z segment 120 past its deadline unpaid; carried=0 pool=1 +RESULT claim 2026-10-08T11:01:00Z segment 130..139 (10 shards, fresh) margin=240 tip=3000 candidates=1 rank_by=fnv +RESULT seg 130 chain 2026-10-08T11:06:00Z 10 shard records, chain_len 1, proof 1000 bytes, shards 190.0 s, aggregation 60.0 s +RESULT seg 130 shards 2026-10-08T11:06:10Z accepted 9 of 10 +RESULT claim 2026-10-08T11:07:00Z segment 140..149 (10 shards, fresh) margin=240 tip=3200 candidates=1 rank_by=fnv +RESULT seg 140 chain 2026-10-08T11:12:00Z 10 shard records, chain_len 1, proof 1000 bytes, shards 190.0 s, aggregation 60.0 s +RESULT seg 140 shards 2026-10-08T11:12:10Z accepted 10 of 10 +RESULT segment_refused 2026-10-08T11:12:20Z segment 140..149: pending until the previous segment pays; end to end 300.0 s +RESULT held 2026-10-08T11:12:20Z segment 140 held for retry until DAA 3441 +RESULT held_expired 2026-10-08T11:30:00Z segment 140 deadline passed +RESULT claim 2026-10-08T11:31:00Z segment 150..159 (10 shards, fresh) margin=240 tip=3800 candidates=1 rank_by=fnv +RESULT pass 9 2026-10-08T11:40:00Z no whole segment inside the margin (worklist 20 entries, tip 3900, mhs 1); waiting +""" + +def self_test(): + # known-failed first: a log with no claim has no jobs and an empty report; a paid row never counts as waste + assert jobs_from_log("RESULT start 2026-10-08T10:00:00Z label=x\nRESULT paid 2026-10-08T10:00:01Z segment 5..9 wei=1 (0 IGN) carrier=1 after 1 s\n") == [] + r0 = report([]); assert r0["jobs"] == 0 and r0["wasted_s"] == 0 and r0["throughput"]["span_h"] is None + assert report(jobs_from_state({"segments": [{"first": 1, "last": 2, "paid_wei": 5, "chain_s": 100.0, "outcome": "paid"}]}))["wasted_s"] == 0 + # an old state row (no outcome field) classifies from what it carries + old = jobs_from_state({"label": "o", "segments": [{"first": 1, "last": 2, "failed": "chain", "chain_s": 50.0}, {"first": 3, "last": 4, "paid_wei": 7}, {"first": 5, "last": 6, "refused": "no"}, {"first": 7, "last": 8, "submitted_at": "2026-10-08T10:00:00Z"}]}) + assert [(j["outcome"], j["cause"]) for j in old] == [("cancelled", "chain"), ("paid", None), ("cancelled", "refused"), ("active", None)], old + jobs = jobs_from_log(SELF_LOG) + got = [(j["first"], j["outcome"], j["cause"]) for j in jobs] + assert got == [(100, "paid", None), (110, "cancelled", "timeout"), (120, "expired", "unpaid"), (130, "cancelled", "shards"), (140, "expired", "held_expired"), (150, "active", None)], got + assert jobs[0]["deadline"] == 1401 and jobs[0]["spent_s"] == 280.0 and jobs[0]["paid_wei"] == 2 * 10**18 and jobs[0]["end_to_end_s"] == 310.0 + assert jobs[2]["miss_daa"] == 2700 - (2401 + 250) and jobs[4]["miss_daa"] is None, (jobs[2], jobs[4]) # the held_expired line's last tip is stale: no miss figure, never a negative one + r = report(jobs) + assert r["outcomes"] == {"paid": 1, "active": 1, "expired": 2, "cancelled": 2}, r["outcomes"] + assert r["paid"]["segments"] == 1 and r["paid"]["shards"] == 10 and r["paid"]["ign"] == 2.0 and r["paid"]["median_time_to_pay_s"] == 180.0 + assert r["missed_deadlines"]["jobs"] == 2 and r["missed_deadlines"]["by_cause"] == {"unpaid": 1, "held_expired": 1} + assert r["wasted_by_cause"]["timeout"] == {"jobs": 1, "seconds": 1800.0} and r["wasted_by_cause"]["unpaid"]["seconds"] == 280.0 and r["wasted_by_cause"]["shards"]["seconds"] == 250.0 + assert r["wasted_s"] == 1800.0 + 280.0 + 250.0 + 250.0 and r["spent_s"] == r["wasted_s"] + 280.0 + assert r["throughput"]["span_h"] == 1.51 and r["throughput"]["segments_paid_per_h"] == 0.66 and r["throughput"]["paid_share_of_spent"] == 0.098, r["throughput"] + assert len(r["active"]) == 1 and r["active"][0]["first"] == 150 + # a state row wins over the log's row for the same segment + merged = merge(jobs_from_state({"label": "t1", "segments": [{"first": 150, "last": 159, "outcome": "paid", "paid_wei": 10**18, "claimed_at": "2026-10-08T11:31:00Z"}]}), jobs) + assert sum(1 for j in merged if j["first"] == 150) == 1 and next(j for j in merged if j["first"] == 150)["outcome"] == "paid" + out = text(r); assert "paid 1, active 1, expired 2, cancelled 2" in out and "timeout: 1 jobs, 1800.0 s" in out + print("RESULT prover-outcomes self-test PASS: 6 log jobs, 4 state rows, merge, report and text as expected") + +def merge(state_jobs, log_jobs): + seen = {(j.get("label"), j["first"]) for j in state_jobs} + return state_jobs + [j for j in log_jobs if (j.get("label"), j["first"]) not in seen] + +def main(argv): + if "--self-test" in argv: self_test(); return 0 + states, logs, as_json, i = [], [], "--json" in argv, 0 + while i < len(argv): + if argv[i] == "--state": states.append(argv[i + 1]); i += 2 + elif argv[i] == "--log": logs.append(argv[i + 1]); i += 2 + else: i += 1 + if not states and not logs: print(__doc__); return 2 + sj = []; lj = [] + for f in states: + s = json.load(open(f)); sj += jobs_from_state(s, s.get("label") or os.path.basename(os.path.dirname(f))) + for f in logs: lj += jobs_from_log(open(f, errors="replace").read()) + jobs = merge(sj, lj); r = report(jobs) + if as_json: print(json.dumps({"report": r, "jobs": jobs}, indent=1)) + else: print(text(r)) + return 0 + +if __name__ == "__main__": sys.exit(main(sys.argv[1:]))