From 2f53150c5a9b35cf734de1dbe4d2f42c6b6882cf Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Wed, 7 Oct 2026 16:25:18 +0000 Subject: [PATCH 1/3] The chip claim, public text: rewritten launch-first (2.1x to 3.9x under class v4 from genesis; class v5; the 5x to 9x only as the class v3 baseline; the devnet's height a devnet fact) on the project lead's word Co-Authored-By: Claude Fable 5.1 --- .../counter-asic-3-public-text-2026-10-07.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/plans/counter-asic-3-public-text-2026-10-07.md b/docs/plans/counter-asic-3-public-text-2026-10-07.md index c72a2964..ba75180b 100644 --- a/docs/plans/counter-asic-3-public-text-2026-10-07.md +++ b/docs/plans/counter-asic-3-public-text-2026-10-07.md @@ -1,33 +1,33 @@ -# The chip claim, public text (7 October 2026, 14:3x UK, on the project lead's "this needs updating with all of our updates"; served since 11:03 UK on master 9162c847 with main's two cuts: no mention of the disclosure prize until the publish word, and row 17 in evidence.md's eight-column shape) +# The chip claim, public text (7 October 2026; REWRITTEN LAUNCH-FIRST 18:3x UK on the project lead's "I thought we were making it 2.1 from launch?": the testnet and mainnet objects set program_class_v4_activation_daa to 0, so class v4 is live from genesis and the launch number is 2.1x to 3.9x on day one; the 5x to 9x is the class v3 baseline the work started from, stated only as that; the devnet's own activation height is a devnet fact only. Served since 11:03 UK on master 9162c847 with main's two cuts: no mention of the disclosure prize until the publish word, and row 17 in evidence.md's eight-column shape) Three texts and one ledger row, written by the Counter ASIC lane, which owns the chip model. Every number carries its label: measured (a card or a chain we ran, with the date), modelled (arithmetic on cited parts), claimed (a vendor's figure, never measured by us), designed (a rule in a class, not yet measured). Sources: `docs/analysis/chip-model-v3.md` sections 5 and 6, `docs/analysis/latency-shadow-2026-10-06.md`, `docs/plans/counter-asic-3-status.md`, `docs/analysis/attack-pass/f8-uniform.md` and `f4-weakday.md` (branch attack-pass), `docs/design/class-v5-stored-state.md`, the datacentre and market-cap rows of 7 October (lanes 3 and the fleet), the cryptanalysis plan in `docs/plans/funding.md`. ## 1. The home page's chip line (replaces the hero sentence served since 6 October 16:21Z) -Built for graphics cards. In our public model the strongest chip reaches 5x to 9x per joule against an RTX 5090 today; class v4, now on the vote, brings that to 2.1x to 3.9x, and class v5 makes the dataset the chain's own state, so a chip that stores it or recomputes it is wrong on every item. The model and every measurement are public. +Built for graphics cards. At launch the strongest chip in our public model reaches 2.1x to 3.9x per joule against an RTX 5090, under class v4 from the first block. Class v5 then makes the dataset the chain's own state, so a chip that stores it or recomputes it is wrong on every item. Without class v4 the same chip would reach 5x to 9x. The model and every measurement are public. ## 2. The litepaper's chip section (replaces the paragraph that begins "The chip model: 5x to 9x per joule") -The chip model. We price the strongest chip we can design against an RTX 5090 and publish the arithmetic. The honest card: an RTX 5090 mines class v3 at 136 MH/s on 350 W in the bench and 290 W in the app (measured, 6 October 2026); an Apple M5 Max at 27 MH/s on 21 W (measured, 6 October 2026); an H100 SXM at 249 MH/s, 98 percent of its random-read ceiling like the 5090, 1.78x the 5090's hash at 1.15x the tuned 5090's hash per watt and a third of the hash per rented dollar (measured, 7 October 2026), so datacentre silicon does not change the chip question. The CPU verifier takes 2.33 ms per warp of 32 hashes on one M5 Max core under class v4 (measured, 6 October 2026), against a gate of 10 ms. +The chip model. We price the strongest chip we can design against an RTX 5090 and publish the arithmetic. Class v4 is live from the first block on the testnet and the mainnet (the ladder's rung 0 at genesis), so the launch number is the class v4 row. The honest card: an RTX 5090 mines class v3 at 136 MH/s on 350 W in the bench and 290 W in the app (measured, 6 October 2026); an Apple M5 Max at 27 MH/s on 21 W (measured, 6 October 2026); an H100 SXM at 249 MH/s, 98 percent of its random-read ceiling like the 5090, 1.78x the 5090's hash at 1.15x the tuned 5090's hash per watt and a third of the hash per rented dollar (measured, 7 October 2026), so datacentre silicon does not change the chip question. The CPU verifier takes 2.33 ms per warp of 32 hashes on one M5 Max core under class v4 (measured, 6 October 2026), against a gate of 10 ms. | The chip and the class | Edge over an RTX 5090 per joule | Label and date | |---|---|---| -| A memory-controller chip that stores the whole dataset (the Ethash class), class v3 | 5x to 9x (5.1x on GDDR7, 9.2x on eight HBM3 stacks; the Ethash chips of this class reached 2.1x to 4.8x) | modelled, 6 October 2026; the precedent measured by others, 2020 to 2022 | -| The same chip under class v4 (about 100,000 integer ops per hash in the latency shadow, so the chip carries a GPU-class datapath beside its memory) | 2.1x with a core as costly per op as the GPU's (k = 1); 3.9x with the core Bitmain claimed for its Antminer X9 (k about 0.33), a product withdrawn before any unit shipped | modelled on measured card watts, 6 October 2026; the X9 figure claimed, never measured | -| The same chip at the ladder's second rung (about 200,000 ops per hash) | about 2.8x | modelled, 7 October 2026 | +| At launch: a memory-controller chip that stores the whole dataset, under class v4 (about 100,000 integer ops per hash in the latency shadow, so the chip carries a GPU-class datapath beside its memory) | 2.1x with a core as costly per op as the GPU's (k = 1); 3.9x with the core Bitmain claimed for its Antminer X9 (k about 0.33), a product withdrawn before any unit shipped | modelled on measured card watts, 6 October 2026; the X9 figure claimed, never measured | +| The same chip at the ladder's second rung (about 200,000 ops per hash), reached by miner signal | about 2.8x | modelled, 7 October 2026 | | Any chip under class v5, where the dataset is the chain's own state | a stateless or stale chip is wrong on every item, so the stored-dataset chip and the recompute chip are removed as categories; the verifier pays 0.2 ms more per warp | designed, 7 October 2026 | | A chip caching the hottest 0.1 percent of items (about 1 MB of SRAM) | bounded at 1.067x at the ceiling, 1.005x on about half the hours and 1.048x on 5 percent | measured census of 1,024 programs, 7 October 2026; the source rule in the next class | | A per-day FPGA that recomputes the dataset with cheap multipliers on a weak day | at most 12 percent more hash rate on 12 days a century, nothing on the other days and nothing for any chip | measured census of 2^24 days, 7 October 2026; the rule in the next class | | When a stored-dataset chip pays for itself | at about USD 100 M of market cap in the first two years, not before | modelled, 7 October 2026 | +| The baseline the work started from: the same chip under class v3, without the shadow (the Ethash class) | 5x to 9x (5.1x on GDDR7, 9.2x on eight HBM3 stacks; the Ethash chips of this class reached 2.1x to 4.8x) | modelled, 6 October 2026; the precedent measured by others, 2020 to 2022; never the launch state | -What a miner sees from this. Class v4 costs a 5090 about 80 W more for 0.2 percent of rate, an M5 Max 16 W more for 1.5 percent, an RX 9070 XT and an RTX 4070 nothing (all measured, 6 October 2026). The ladder that sets how much work rides in the shadow starts at rung 0 at the testnet genesis and climbs by miner signal; its third rung is inadmissible today because a server core verifies it in 10.85 ms, over the gate (measured, 7 October 2026). The next test of the model is not ours: the cryptanalysis plan buys three external lots against the mixer, the chained cache and the acceptance rule. +What a miner sees from this. Class v4 costs a 5090 about 80 W more for 0.2 percent of rate, an M5 Max 16 W more for 1.5 percent, an RX 9070 XT and an RTX 4070 nothing (all measured, 6 October 2026). The ladder that sets how much work rides in the shadow starts at rung 0 at genesis and climbs by miner signal; its third rung is inadmissible today because a server core verifies it in 10.85 ms, over the gate (measured, 7 October 2026). On the devnet, which started on class v3, class v4 arrives by miner signal at a published height (a devnet fact, not a launch one). The next test of the model is not ours: the cryptanalysis plan buys three external lots against the mixer, the chained cache and the acceptance rule. ## 3. The miner page's line -Your card against the strongest chip we can price: an RTX 5090 at 136 MH/s on 350 W (measured 6 October 2026), the chip 5x to 9x per joule in the public model today, 2.1x to 3.9x under class v4 (modelled on measured watts), and under class v5 wrong on every item because the dataset is the chain's own state (designed); the model and the measurements are public. +Your card against the strongest chip we can price: an RTX 5090 at 136 MH/s on 350 W (measured 6 October 2026); at launch the chip reaches 2.1x to 3.9x per joule under class v4 (modelled on measured watts), and under class v5 it is wrong on every item because the dataset is the chain's own state (designed). Without class v4 it would be 5x to 9x. The model and the measurements are public. ## 4. The ledger row (docs/evidence.md row 17, in the table's eight columns as served) | # | Claim | Where it is made | Status | Version or commit | Reproducible test | Result, date, machine | Independent verification | |---|---|---|---|---|---|---|---| -| 17 | The chip resistance claim: the strongest chip in the public model reaches 5x to 9x per joule against an RTX 5090 today; class v4 brings it to 2.1x (k = 1) to 3.9x (k about 0.33) and its second rung to about 2.8x; class v5 makes the dataset the chain's state so a stateless or stale chip is wrong on every item; the hot-set cache is bounded at 1.067x at the ceiling and the weak-day FPGA at 12 percent on 12 days a century, both routed to the next class; datacentre silicon does not change the question; a stored-dataset chip pays for itself only at about USD 100 M of market cap in two years | the home page's chip line, the litepaper's chip section (/litepaper#chip-model), the miner page's line | tested by the team (every card, the verifier, the two attack-pass bounds, the H100), the chip itself modelled, class v5 and the ladder designed, the X9 core claimed and never measured | `docs/analysis/chip-model-v3.md` 5 and 6; `docs/analysis/latency-shadow-2026-10-06.md`; `docs/plans/counter-asic-3-status.md`; `docs/analysis/attack-pass/f8-uniform.md`, `f4-weakday.md`, `docs/analysis/ca3-v4-uniform.md`; `docs/design/class-v5-stored-state.md`; the H100 and market-cap rows of 7 October; `docs/plans/funding.md` (the three lots) | the chip model's arithmetic in its file; the card rows by the benchmark package; the attack-pass harnesses `tools/attack/f8-uniform` and the F4 census; the verifier by `igneum-pow bench` | 136 MH/s at 350 W (5090, bench) and 290 W (app); 27 MH/s at 21 W (M5 Max); 249 MH/s (H100 SXM) at 98 percent of its read ceiling, 1.78x hash, 1.15x MH/W, a third per rented dollar; 2.33 ms per warp; 5.1x to 9.2x; 2.1x, 3.9x, 2.8x; 1.067x at the ceiling; 12 percent on 12 days a century; 10.85 ms at rung 3; USD 100 M; 6 and 7 October 2026, the M5 Max, PC 2's RTX 5090, PC 1's RX 9070 XT and RTX 4070, a rented H100 SXM, igneum-build-1 | none yet; the three cryptanalysis lots are the next test | +| 17 | The chip resistance claim: at launch the strongest chip in the public model reaches 2.1x (k = 1) to 3.9x (k about 0.33) per joule against an RTX 5090 under class v4, live from genesis on the testnet and the mainnet; the ladder's second rung brings it to about 2.8x; class v5 makes the dataset the chain's state so a stateless or stale chip is wrong on every item; the hot-set cache is bounded at 1.067x at the ceiling and the weak-day FPGA at 12 percent on 12 days a century, both routed to the next class; datacentre silicon does not change the question; a stored-dataset chip pays for itself only at about USD 100 M of market cap in two years; without class v4 the same chip would reach 5x to 9x (the class v3 baseline, the devnet's starting state, never the launch state) | the home page's chip line, the litepaper's chip section (/litepaper#chip-model), the miner page's line | tested by the team (every card, the verifier, the two attack-pass bounds, the H100), the chip itself modelled, class v5 and the ladder designed, the X9 core claimed and never measured | `docs/analysis/chip-model-v3.md` 5 and 6; `docs/analysis/latency-shadow-2026-10-06.md`; `docs/plans/counter-asic-3-status.md`; `docs/analysis/attack-pass/f8-uniform.md`, `f4-weakday.md`, `docs/analysis/ca3-v4-uniform.md`; `docs/design/class-v5-stored-state.md`; the H100 and market-cap rows of 7 October; `docs/plans/funding.md` (the three lots) | the chip model's arithmetic in its file; the card rows by the benchmark package; the attack-pass harnesses `tools/attack/f8-uniform` and the F4 census; the verifier by `igneum-pow bench` | 136 MH/s at 350 W (5090, bench) and 290 W (app); 27 MH/s at 21 W (M5 Max); 249 MH/s (H100 SXM) at 98 percent of its read ceiling, 1.78x hash, 1.15x MH/W, a third per rented dollar; 2.33 ms per warp; 2.1x, 3.9x, 2.8x at launch; 1.067x at the ceiling; 12 percent on 12 days a century; 10.85 ms at rung 3; USD 100 M; 5.1x to 9.2x the class v3 baseline; 6 and 7 October 2026, the M5 Max, PC 2's RTX 5090, PC 1's RX 9070 XT and RTX 4070, a rented H100 SXM, igneum-build-1 | none yet; the three cryptanalysis lots are the next test | From d1e42080f899dcf3819446264846c1871a851455 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Wed, 7 Oct 2026 16:30:22 +0000 Subject: [PATCH 2/3] Site currency (currency-21's site side, for master tonight): site/money.js is the miner app's currency rules for the site (navigator.language picks the currency and the typical tariff, a saved switch wins, one Intl.NumberFormat call for every money figure, no exchange rate anywhere; tables generated from the app's View block, site/lib/money-regen.mjs rewrites them, site/lib/money.test.mjs fails on drift once the app side reaches master and waits until then); the card picker (yourcard.js on /miner and /app) shows the card's electricity a day at the typical tariff with a currency switch saved in localStorage igneum-currency, loading /money.js itself so no page was edited Co-Authored-By: Claude Fable 5.1 --- site/lib/money-regen.mjs | 16 +++++++++++ site/lib/money.test.mjs | 48 +++++++++++++++++++++++++++++++ site/money.js | 61 ++++++++++++++++++++++++++++++++++++++++ site/yourcard.js | 49 +++++++++++++++++++++++--------- tools/ci/pre-push.sh | 2 +- 5 files changed, 161 insertions(+), 15 deletions(-) create mode 100644 site/lib/money-regen.mjs create mode 100644 site/lib/money.test.mjs create mode 100644 site/money.js diff --git a/site/lib/money-regen.mjs b/site/lib/money-regen.mjs new file mode 100644 index 00000000..eb12337f --- /dev/null +++ b/site/lib/money-regen.mjs @@ -0,0 +1,16 @@ +#!/usr/bin/env node +// Rewrites the four tables in site/money.js from app/igneum-app/ui/app.js (View.REGIONS, ISO_CURRENCY, EU_MEMBERS, +// CURRENCY_CODES). Run after a change to the app's tables, then commit both; site/lib/money.test.mjs fails on drift. +import { readFileSync, writeFileSync } from 'node:fs'; +import { fileURLToPath } from 'node:url'; +import { dirname, join } from 'node:path'; +const here = dirname(fileURLToPath(import.meta.url)); +const m = { exports: {} }; new Function('module', readFileSync(join(here, '../../app/igneum-app/ui/app.js'), 'utf8'))(m); +const V = m.exports.View, p = join(here, '../money.js'); +const regions = V.REGIONS.map(r => ({ code: r.code, name: r.name, cur: r.cur, price: r.price, source: r.source || '', restricted: !!r.restricted })); +let s = readFileSync(p, 'utf8'); +s = s.replace(/ M\.REGIONS = .*\n/, ' M.REGIONS = ' + JSON.stringify(regions) + ';\n'); +s = s.replace(/ M\.ISO_CURRENCY = .*\n/, ' M.ISO_CURRENCY = ' + JSON.stringify(V.ISO_CURRENCY) + ';\n'); +s = s.replace(/ M\.EU_MEMBERS = .*\n/, ' M.EU_MEMBERS = ' + JSON.stringify(V.EU_MEMBERS) + ';\n'); +s = s.replace(/ M\.CURRENCY_CODES = .*\n/, ' M.CURRENCY_CODES = ' + JSON.stringify(V.CURRENCY_CODES) + ';\n'); +writeFileSync(p, s); console.log('site/money.js tables regenerated'); diff --git a/site/lib/money.test.mjs b/site/lib/money.test.mjs new file mode 100644 index 00000000..6a42e2b8 --- /dev/null +++ b/site/lib/money.test.mjs @@ -0,0 +1,48 @@ +// node --test site/lib/money.test.mjs (the pre-push gate runs it beside the explorer and emission tests) +// site/money.js is the app's currency rules for the site: its tables must equal the app's, its formatter must place the +// symbol as the locale does, and the picker's choice must follow navigator.language with a saved override winning. +import { test } from 'node:test'; +import assert from 'node:assert/strict'; +import { readFileSync } from 'node:fs'; +import { fileURLToPath } from 'node:url'; +import { dirname, join } from 'node:path'; +const here = dirname(fileURLToPath(import.meta.url)); +const load = (p) => { const mod = { exports: {} }; new Function('module', 'window', readFileSync(p, 'utf8'))(mod, undefined); return mod.exports; }; +const M = load(join(here, '../money.js')); +const V = load(join(here, '../../app/igneum-app/ui/app.js')).View; + +test('the site tables equal the app tables (regenerate with node site/lib/money-regen.mjs)', (t) => { + // the app side rides release-0.3.21 first; on a tree whose app has no ISO_CURRENCY yet the drift check waits for it + if (!V.ISO_CURRENCY) { t.skip('the app on this tree carries no currency tables yet (currency-21 app side not merged here)'); return; } + assert.deepEqual(M.REGIONS, V.REGIONS.map(r => ({ code: r.code, name: r.name, cur: r.cur, price: r.price, source: r.source || '', restricted: !!r.restricted }))); + assert.deepEqual(M.ISO_CURRENCY, V.ISO_CURRENCY); assert.deepEqual(M.EU_MEMBERS, V.EU_MEMBERS); assert.deepEqual(M.CURRENCY_CODES, V.CURRENCY_CODES); + for (const c of ['GBP', 'EUR', 'JPY', 'CHF']) assert.deepEqual(M.minorOf(c), V.minorOf(c), c); +}); + +test('the picker follows navigator.language, a saved choice wins, no row falls back to USD and asks', () => { + assert.equal(M.currencyChoice('', 'de-DE').code, 'EUR'); assert.equal(M.currencyChoice('', 'en-GB').code, 'GBP'); assert.equal(M.currencyChoice('', 'fr-CA').code, 'CAD'); assert.equal(M.currencyChoice('', 'en-AU').code, 'AUD'); + assert.equal(M.currencyChoice('USD', 'de-DE').code, 'USD'); assert.equal(M.currencyChoice('USD', 'de-DE').source, 'override'); + const eo = M.currencyChoice('', 'eo'); assert.equal(eo.code, 'USD'); assert.equal(eo.prompt, true); + assert.equal(M.currencyChoice('zzz', 'eo').prompt, true, 'an unknown saved code is ignored'); +}); + +test('the default tariff is the region row, else the first table row in the currency, and the cost line uses one formatter', () => { + const de = M.tariffFor(M.currencyChoice('', 'de-DE')); assert.equal(de.price, 38.69); assert.match(de.source, /Eurostat/); assert.equal(de.region, 'Germany'); + const gbp = M.tariffFor(M.currencyChoice('GBP', 'de-DE')); assert.equal(gbp.price, 26.32); assert.equal(gbp.region, 'United Kingdom'); + const fr = M.tariffFor(M.currencyChoice('', 'fr-FR')); assert.equal(fr.price, 28.96, 'an EU member on the euro takes the EU average'); + assert.equal(M.tariffFor(M.currencyChoice('', 'sv-SE')), null, 'no table tariff in kronor: the picker says so'); + assert.equal(M.fmtMoney(M.costPerDay(227, 38.69), 'EUR', 'de-DE'), '2,11 €'); + assert.equal(M.fmtMoney(M.costPerDay(227, 26.32), 'GBP', 'en-GB'), '£1.43'); + assert.equal(M.fmtMoney(M.costPerDay(227, 17.7), 'USD', 'en-US'), '$0.96'); + assert.equal(M.costPerDay(null, 26.32), null, 'no watts, no cost'); + assert.equal(M.fmtMoney(1234.5, 'USD', 'en-US'), '$1,235'); assert.equal(M.fmtMoney(1.5, 'JPY', 'en-US'), '¥2'); +}); + +test('yourcard.js loads money.js and shows the electricity line with the currency switch; no hand-built money string', () => { + const yc = readFileSync(join(here, '../yourcard.js'), 'utf8'); + assert.ok(yc.includes("'/money.js'"), 'loads the module when the page did not'); + assert.ok(yc.includes('window.IgneumMoney') && yc.includes('.fmtMoney(') && yc.includes('.currencyChoice(') && yc.includes('.tariffFor('), 'the module is the only money path'); + assert.ok(yc.includes('igneum-currency'), 'the saved choice'); + assert.ok(yc.includes('class="cur"'), 'the switch'); + assert.equal(/'£'|"£"/.test(yc), false); +}); diff --git a/site/money.js b/site/money.js new file mode 100644 index 00000000..82bdf4f9 --- /dev/null +++ b/site/money.js @@ -0,0 +1,61 @@ +/* Igneum money (currency-21, 7 October 2026): the site's copy of the miner app's currency rules, for the card picker + (yourcard.js) and any page that shows a money figure. No IP lookup: navigator.language's region picks the currency and + the default tariff; a saved choice (localStorage igneum-currency) wins; every figure goes through one Intl.NumberFormat + call with the currency code and the narrow symbol, placed as the locale places it; the user's own tariff is the + number, so no exchange rate exists anywhere. The tables below are generated from app/igneum-app/ui/app.js (View.REGIONS, + View.ISO_CURRENCY, View.EU_MEMBERS, View.CURRENCY_CODES); site/lib/money.test.mjs fails when they drift, and + `node site/lib/money-regen.mjs` rewrites them. A classic script (window.IgneumMoney) so yourcard.js can load it on + pages that carry no module tag; under node it also exports through module.exports for the test. */ +(function (root) { + var M = {}; + M.REGIONS = [{"code":"gb","name":"United Kingdom","cur":"GBP","price":26.32,"source":"Ofgem cap, 1 October to 31 December 2026","restricted":false},{"code":"ie","name":"Ireland","cur":"EUR","price":40.42,"source":"Eurostat, second half of 2025","restricted":false},{"code":"de","name":"Germany","cur":"EUR","price":38.69,"source":"Eurostat, second half of 2025","restricted":false},{"code":"be","name":"Belgium","cur":"EUR","price":34.99,"source":"Eurostat, second half of 2025","restricted":false},{"code":"eu","name":"European Union, other","cur":"EUR","price":28.96,"source":"Eurostat, second half of 2025, the EU average","restricted":false},{"code":"hu","name":"Hungary","cur":"EUR","price":10.82,"source":"Eurostat, second half of 2025, in euro cents","restricted":false},{"code":"mt","name":"Malta","cur":"EUR","price":12.82,"source":"Eurostat, second half of 2025","restricted":false},{"code":"bg","name":"Bulgaria","cur":"EUR","price":13.55,"source":"Eurostat, second half of 2025, in euro cents","restricted":false},{"code":"us","name":"United States","cur":"USD","price":17.7,"source":"EIA average, second half of 2025","restricted":false},{"code":"kz","name":"Kazakhstan","cur":"USD","price":4,"source":"about 4 c, a secondary source, approximate","restricted":false},{"code":"py","name":"Paraguay","cur":"USD","price":4.4,"source":"ANDE crypto tariff, 4.4 to 6 c; every crypto contract ends 31 December 2027","restricted":false},{"code":"ir","name":"Iran","cur":"USD","price":1,"source":"licensed mining tariff, about 1 c, a secondary source, approximate","restricted":false},{"code":"et","name":"Ethiopia","cur":"USD","price":2,"source":"2 to 5.3 c, a secondary source","restricted":false},{"code":"ng","name":"Nigeria","cur":"USD","price":4.8,"source":"hosted, 4.8 c, a secondary source","restricted":false},{"code":"ru-mow","name":"Russia, Moscow region","cur":"USD","price":0,"source":"","restricted":true},{"code":"ru-irk","name":"Russia, Irkutsk","cur":"USD","price":0,"source":"","restricted":true},{"code":"ru-bur","name":"Russia, Buryatia","cur":"USD","price":0,"source":"","restricted":true},{"code":"ru-zab","name":"Russia, Zabaikalsky","cur":"USD","price":0,"source":"","restricted":true},{"code":"ru","name":"Russia, other region","cur":"USD","price":0,"source":"","restricted":true},{"code":"cn","name":"China","cur":"USD","price":0,"source":"","restricted":true},{"code":"other","name":"Somewhere else","cur":"USD","price":0,"source":"","restricted":false}]; + M.ISO_CURRENCY = {"at":"EUR","be":"EUR","cy":"EUR","de":"EUR","ee":"EUR","es":"EUR","fi":"EUR","fr":"EUR","gr":"EUR","hr":"EUR","ie":"EUR","it":"EUR","lt":"EUR","lu":"EUR","lv":"EUR","mt":"EUR","nl":"EUR","pt":"EUR","si":"EUR","sk":"EUR","gb":"GBP","us":"USD","ca":"CAD","au":"AUD","nz":"NZD","ch":"CHF","li":"CHF","se":"SEK","no":"NOK","dk":"DKK","is":"ISK","pl":"PLN","cz":"CZK","hu":"HUF","ro":"RON","bg":"BGN","rs":"RSD","tr":"TRY","ua":"UAH","ge":"GEL","kz":"KZT","ru":"RUB","jp":"JPY","kr":"KRW","cn":"CNY","hk":"HKD","tw":"TWD","sg":"SGD","my":"MYR","th":"THB","vn":"VND","ph":"PHP","id":"IDR","in":"INR","pk":"PKR","bd":"BDT","ae":"AED","sa":"SAR","il":"ILS","ir":"IRR","za":"ZAR","ng":"NGN","ke":"KES","eg":"EGP","ma":"MAD","et":"ETB","br":"BRL","mx":"MXN","ar":"ARS","cl":"CLP","co":"COP","pe":"PEN","py":"PYG"}; + M.EU_MEMBERS = ["at","be","bg","hr","cy","cz","dk","ee","fi","fr","de","gr","hu","ie","it","lv","lt","lu","mt","nl","pl","pt","ro","sk","si","es","se"]; + M.CURRENCY_CODES = ["GBP","EUR","USD","CAD","AUD","AED","ARS","BDT","BGN","BRL","CHF","CLP","CNY","COP","CZK","DKK","EGP","ETB","GEL","HKD","HUF","IDR","ILS","INR","IRR","ISK","JPY","KES","KRW","KZT","MAD","MXN","MYR","NGN","NOK","NZD","PEN","PHP","PKR","PLN","PYG","RON","RSD","RUB","SAR","SEK","SGD","THB","TRY","TWD","UAH","VND","ZAR"]; + var MINOR = { GBP: ['pence', 'p'], EUR: ['euro cents', 'c'], USD: ['cents', 'c'], CAD: ['cents', 'c'], AUD: ['cents', 'c'], NZD: ['cents', 'c'], CHF: ['rappen', 'rp'], SEK: ['öre', 'öre'], NOK: ['øre', 'øre'], DKK: ['øre', 'øre'], PLN: ['grosze', 'gr'], CZK: ['haléře', 'h'], INR: ['paise', 'p'], BRL: ['centavos', 'c'], MXN: ['centavos', 'c'], ZAR: ['cents', 'c'], JPY: ['yen', '¥'], KRW: ['won', '₩'] }; + M.minorOf = function (cur) { + cur = String(cur || '').toUpperCase(); var digits = 2; + try { digits = new Intl.NumberFormat('en', { style: 'currency', currency: cur }).resolvedOptions().maximumFractionDigits; } catch (e) { } + var mm = MINOR[cur] || (digits === 0 ? [cur.toLowerCase(), cur] : ['cents', 'c']); + return { word: mm[0], abbr: mm[1], digits: digits }; + }; + M.fmtMoney = function (v, cur, loc) { + if (v === null || v === undefined || isNaN(v)) return ''; + var d = v >= 100 ? 0 : M.minorOf(cur).digits; + try { return new Intl.NumberFormat(loc || 'en-GB', { style: 'currency', currency: cur, currencyDisplay: 'narrowSymbol', minimumFractionDigits: d, maximumFractionDigits: d }).format(v).replace(/[\u00a0\u202f]/g, ' '); } + catch (e) { return cur + ' ' + (d ? v.toFixed(d) : String(Math.round(v))); } + }; + M.regionFromLocale = function (lang) { + lang = String(lang || '').trim(); if (!lang) return ''; var reg = ''; + try { var l = new Intl.Locale(lang); reg = l.region || (l.maximize ? l.maximize().region : '') || ''; } catch (e) { var mm = /^[A-Za-z]{2,3}[-_]([A-Za-z]{2})\b/.exec(lang); reg = mm ? mm[1] : ''; } + return /^[A-Za-z]{2}$/.test(reg) ? reg.toLowerCase() : ''; + }; + var synth = {}; + function regionName(code) { try { var n = new Intl.DisplayNames(['en'], { type: 'region' }).of(code.toUpperCase()); if (n && n !== code.toUpperCase()) return n; } catch (e) { } return code.toUpperCase(); } + M.regionOf = function (code) { + for (var i = 0; i < M.REGIONS.length; i++) if (M.REGIONS[i].code === code) return M.REGIONS[i]; + if (!/^[a-z]{2}$/.test(code || '')) return null; + if (synth[code]) return synth[code]; + var cur = M.ISO_CURRENCY[code] || '', eu = M.EU_MEMBERS.indexOf(code) >= 0 && cur === 'EUR', avg = M.regionOf('eu'); + return (synth[code] = { code: code, name: regionName(code), cur: cur || 'USD', unknown: !cur, price: eu && avg ? avg.price : 0, source: eu && avg ? avg.source : '' }); + }; + // the currency in force: a saved choice, else the locale's region, else USD with the prompt + M.currencyChoice = function (saved, lang) { + var ov = String(saved || '').toUpperCase(), loc = M.regionFromLocale(lang); + if (ov && M.CURRENCY_CODES.indexOf(ov) >= 0) return { code: ov, source: 'override', region: loc, prompt: false }; + var r = loc ? M.regionOf(loc) : null; + if (r && !r.unknown) return { code: r.cur, source: 'locale', region: loc, prompt: false }; + return { code: 'USD', source: 'fallback', region: loc, prompt: true }; + }; + // the default tariff for a choice: the locale's region row when it carries the currency, else the first table row in that currency + M.tariffFor = function (choice) { + var r = choice.region ? M.regionOf(choice.region) : null; + if (r && r.cur === choice.code && r.price > 0) return { price: r.price, source: r.source, region: r.name, cur: choice.code }; + for (var i = 0; i < M.REGIONS.length; i++) if (M.REGIONS[i].cur === choice.code && M.REGIONS[i].price > 0 && !M.REGIONS[i].restricted) return { price: M.REGIONS[i].price, source: M.REGIONS[i].source, region: M.REGIONS[i].name, cur: choice.code }; + return null; + }; + // watts over a day at a tariff in hundredths of the unit per kWh: the unit amount + M.costPerDay = function (watts, pricePerKwh) { return watts > 0 && pricePerKwh > 0 ? watts * 24 / 1000 * pricePerKwh / 100 : null; }; + root.IgneumMoney = M; + if (typeof module === 'object' && module && module.exports) module.exports = M; +})(typeof window !== 'undefined' ? window : globalThis); diff --git a/site/yourcard.js b/site/yourcard.js index 4ad14adb..5fb676d1 100644 --- a/site/yourcard.js +++ b/site/yourcard.js @@ -1,21 +1,42 @@ -/* The "your card" line: a measured card, and how often it finds a block at the network's hash rate right now. One block a - second is the target, so the wait is network hashes per second over the card's rate. The rates are the bench table's - measured numbers (site/miners.html); nothing here is a promise. Reads /api/live every 15 s. */ +/* The "your card" line: a measured card, how often it finds a block at the network's hash rate right now, and what its + electricity costs a day in your currency. One block a second is the target, so the wait is network hashes per second + over the card's rate. The rates are the bench table's measured numbers (site/miners.html); the watts are the tuned + draws from the same runs (app.html's Ember table: 5090 226.8 W, 4070 75.6 W; the 9070 XT 202 W from docs/bench-log.md, + 6 October 2026; Apple silicon reports no draw). The currency follows navigator.language (no IP lookup); the switch saves + a choice in localStorage igneum-currency; the tariff is the public table's default for that region or currency, so the + cost is arithmetic from a typical price, never a promise (currency-21, 7 October 2026). Reads /api/live every 15 s. */ (function () { - var CARDS = [['NVIDIA RTX 5090', 127.7], ['NVIDIA RTX 5060 Ti', 30.9], ['NVIDIA RTX 4070', 28.8], ['Apple M5 Max', 26.7], ['AMD RX 9070 XT', 17.8]]; + var CARDS = [['NVIDIA RTX 5090', 127.7, 226.8], ['NVIDIA RTX 4070', 28.8, 75.6], ['Apple M5 Max', 26.7, null], ['AMD RX 9070 XT', 17.8, 202]]; var els = document.querySelectorAll('[data-yourcard]'); if (!els.length) return; var net = null, chosen = (function () { try { return localStorage.getItem('igneum-card'); } catch (e) { return null; } })(); + var savedCur = (function () { try { return localStorage.getItem('igneum-currency') || ''; } catch (e) { return ''; } })(); function dur(sec) { if (!(sec > 0)) return 'pending'; if (sec < 90) return Math.round(sec) + ' s'; if (sec < 5400) return Math.round(sec / 60) + ' min'; if (sec < 172800) { var h = Math.floor(sec / 3600), m = Math.round((sec % 3600) / 60); return h + ' h' + (m ? ' ' + m + ' min' : ''); } return Math.round(sec / 86400) + ' days'; } - function render() { els.forEach(function (el) { var r = parseFloat(el.querySelector('select').value) * 1e6, eta = el.querySelector('.eta'); eta.textContent = net && r ? 'every ' + dur(net / r) : 'pending'; }); } - // the vendor badge beside the picker: the five mini marks the build stamped as JSON (site/lib/marks.mjs), chosen by the card's name - var marks = {}; try { var mj = document.getElementById('gpu-marks'); if (mj) marks = JSON.parse(mj.textContent); } catch (e) { marks = {}; } - function vendorOf(n) { return /nvidia|geforce|\bRTX\b|\bGTX\b/i.test(n) ? 'nvidia' : /\bamd\b|radeon/i.test(n) ? 'amd' : /intel|\barc\b/i.test(n) ? 'intel' : /apple|\bM\d (max|pro|ultra)\b/i.test(n) ? 'apple' : 'gpu'; } - function badge(el) { var sel = el.querySelector('select'), b = el.querySelector('.badge-slot'); if (!sel || !b) return; var name = sel.options[sel.selectedIndex].text.split(' \u00b7 ')[0]; b.innerHTML = marks[vendorOf(name)] || ''; } - els.forEach(function (el) { - el.innerHTML = 'Your cardfinds a block about pending at the network\u2019s hash rate right now.'; - el.querySelector('select').addEventListener('change', function (e) { var name = e.target.options[e.target.selectedIndex].text.split(' \u00b7 ')[0]; try { localStorage.setItem('igneum-card', name); } catch (x) {} document.querySelectorAll('[data-yourcard] select').forEach(function (s) { s.value = e.target.value; }); els.forEach(badge); render(); }); - badge(el); - }); + function costWords(watts) { + var M = window.IgneumMoney; if (!M) return ''; + var ch = M.currencyChoice(savedCur, navigator.language), t = M.tariffFor(ch); + if (watts === null) return 'no power reading on this card'; + if (!t) return 'no typical ' + ch.code + ' tariff in the table; the app uses the price you type'; + var c = M.costPerDay(watts, t.price); + return 'about ' + M.fmtMoney(c, ch.code, navigator.language) + ' a day in electricity at ' + t.price + ' ' + M.minorOf(ch.code).abbr + '/kWh (' + t.region + ', typical)'; + } + function render() { + els.forEach(function (el) { + var sel = el.querySelector('select.card'), r = parseFloat(sel.value) * 1e6, eta = el.querySelector('.eta'), cost = el.querySelector('.cost'); + eta.textContent = net && r ? 'every ' + dur(net / r) : 'pending'; + var row = CARDS[sel.selectedIndex]; if (cost) cost.textContent = costWords(row ? row[2] : null); + }); + } + function init() { + var M = window.IgneumMoney, ch = M ? M.currencyChoice(savedCur, navigator.language) : null; + els.forEach(function (el) { + el.innerHTML = 'Your cardfinds a block about pending at the network\u2019s hash rate right now.' + + (M ? '' : ''); + el.querySelector('select.card').addEventListener('change', function (e) { var name = e.target.options[e.target.selectedIndex].text.split(' \u00b7 ')[0]; try { localStorage.setItem('igneum-card', name); } catch (x) {} document.querySelectorAll('[data-yourcard] select.card').forEach(function (s) { s.value = e.target.value; }); render(); }); + var cur = el.querySelector('select.cur'); if (cur) cur.addEventListener('change', function (e) { savedCur = e.target.value; try { localStorage.setItem('igneum-currency', savedCur); } catch (x) {} document.querySelectorAll('[data-yourcard] select.cur').forEach(function (s) { s.value = savedCur; }); render(); }); + }); + render(); + } + if (window.IgneumMoney) init(); else { var sc = document.createElement('script'); sc.src = '/money.js'; sc.onload = init; sc.onerror = init; document.head.appendChild(sc); } function poll() { fetch('/api/live?window=30', { cache: 'no-store' }).then(function (r) { return r.json(); }).then(function (d) { if (d && d.ok && d.state && d.state.hashes_per_second_estimate > 0) { net = d.state.hashes_per_second_estimate; render(); } }).catch(function () {}); } poll(); setInterval(function () { if (!document.hidden) poll(); }, 15000); window.IgneumYourCard = { update: function (h) { if (h > 0) { net = h; render(); } } }; diff --git a/tools/ci/pre-push.sh b/tools/ci/pre-push.sh index 04e90cb7..5699d52c 100755 --- a/tools/ci/pre-push.sh +++ b/tools/ci/pre-push.sh @@ -117,7 +117,7 @@ tree_checks() { run "chain scene: the live feed contract (the recorded reply validates; a rewritten miner, a float now, a stray key refused)" node --test tools/scene/feed-contract.test.mjs run "chain scene parity: one recorded feed through the home fold, /live and the app's Inspect view on build-2, three frames each pixel-equal apart from the app's own-key overlay (a changed token fails first; skipped with no box and no Playwright)" bash tools/scene/parity-remote.sh run "no text overlaps: every served page at 390 to 1600 px, light and dark, the hero at each step (self-test first; IGNEUM_OVERLAP_APPS=1 adds the miner and wallet UIs)" overlap_sweep - run "explorer, emission and public stats unit tests" node --test site/lib/explorer.test.mjs site/lib/emission.test.mjs site/api/public-stats.test.mjs + run "explorer, emission and public stats unit tests" node --test site/lib/explorer.test.mjs site/lib/emission.test.mjs site/lib/money.test.mjs site/api/public-stats.test.mjs run "ship tool self-test" node tools/ship-app.mjs --self-test run "relay unit tests" node --test relay/test/parse.test.mjs relay/test/auth.test.mjs relay/test/wake.test.mjs relay/test/ember.test.mjs run "miner app notice strip and update card tests" node --test app/igneum-app/ui/notices.test.mjs app/igneum-app/ui/update-card.test.mjs app/igneum-app/ui/view.test.mjs app/igneum-app/ui/tune-line.test.mjs From c12b6012e4d271be0484e5c9c3b0c2799d7b5841 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Wed, 7 Oct 2026 16:32:40 +0000 Subject: [PATCH 3/3] Counter ASIC 3.0 status: Devnet 3 now (0.3.22, genesis by 17:30Z), the frozen sub-version 3 handoff (c3d32437, byte 7, id a785001687d8688a, gates green, open items stated), the chip text rewritten launch-first Co-Authored-By: Claude Fable 5.1 --- docs/plans/counter-asic-3-status.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/plans/counter-asic-3-status.md b/docs/plans/counter-asic-3-status.md index 8f631ba8..d5831305 100644 --- a/docs/plans/counter-asic-3-status.md +++ b/docs/plans/counter-asic-3-status.md @@ -423,7 +423,7 @@ Every failing seed is ONE low-entropy load site; the mechanism is lineage-blind Known-failed test class_v4_distinct_ratio_rejects_the_low_entropy_band green on box 2 (12.95 s): p15 attempt 3 (52638ea2e8b0fd68) site 2 at 0.943; p18 attempt 2 (9a37e9489d8ba698) site 6 at 0.927; p19 attempt 0 (79d7441de0689223) site 15 at 0.933; p56 attempt 2 (486a8ad2701ec3b5) site 2 at 0.965; p23 attempt 1 (d65122675f16a1c7) draws site 7 from r5 and passes, and with r6 put back is refused by (a') UnfreshLoadSource and, run anyway, by the ratio at 0.836. Stream unchanged from ddacfbd3 (re-export diff 0 on all eight packs): id a785001687d8688a, the seven fingerprints and the packs zip sha256 4f2445c5... as recorded. THE SUITE AT 017e7037 on box 2: 103 of 103 (64 lib + 7 derive + 4 mixer + 19 packs + 2 recheck + 7 scratch, 3 diag ignored), rc 0; the lib tests 140.8 s against the 41 s whole-suite line at ddacfbd3, because every class v4 draw in the tests pays the 2^20 ratio pass on its chosen candidate (2.2 s each): a CI-time cost, not a node cost (one pass per epoch draw). CI run 37639406567 on 017e7037 success. THE CENSUS AT 017e7037 (box 2, 4,096 chain-shaped seeds plus F8's p1 to p3, draws in parallel across the cores; tools/ca3-v4-uniform now draws across available_parallelism since the serial run became a four-hour job): 4,099 programs, 0 lossy-sourced load sites of 65,584 (57,322 injecting, 8,262 bijective), 0 exhaustions; attempt histogram 0:1297 1:899 2:609 3:416 4:298 5:197 6:125 7:92 8:54 9:46 10:21 11:14 12:13 13:9 14:6 16:2 17:1, mean 2.086, max 17 (ddacfbd3 read 1328/917/622/409/284..., mean 1.998, max 17): the ratio refuses about 4 percent of candidates that pass every other test, one extra attempt on about one seed in twelve, the worst case unchanged at 17; devnet epoch-0 at attempt 1, id a785001687d8688a; F8's p2 attempt 5, p3 attempt 1. The attack-pass lane's class check: ddacfbd3's shadow-executed verdicts against 8bdcbdd8 on 598,678 chain-shaped seeds move 11,990 (2.0 percent) to a different attempt, 0 exhausted, max 32; on 017e7037 the pairing holds and the 64-seed gate at 2^24 plus the 10^6 exhaustion count run to about 16:05Z. The hash lane's ledger lines 2a111fb1 on origin and build (the GitHub 500s cleared on their own), CI run 37642582140 success at 15:25Z; the hash lane has nothing in flight. Nothing on the hash side stops a cut of sub-version 3 at 017e7037 for 0.3.22; then the attack-pass lane's 64-seed gate at 2^24 and 10^6 exhaustion count. Owed as before: G2, G3, the ladder re-measure, AMD (PC 1), the 2019-class core, the fleet and PC 2 G1 on the sub-version 3 packs (a re-run of a known result). release-0.3.21-node STAGED (the node lane, 16:0xZ): 96161037 on the mirror, at the shipper's sweep-end word, in the final order on 55768f88 (c631c64b, 52e96c94, f067f7c1, b0444f51, 437f0438, 2e32d5f6, f95178a1 cherry-picked, a6864e36 and d8bceca5), pairing igneum-pow 8c728ca3 at byte 5, no re-pin. The whole set on the tip green: consensus-core 126, the consensus crate whole (lib 120, both integration targets), igneum-miner 25, kaspa-pow 17, igneum-exec 36, the three checks, 15:49 to 15:57Z on build-2. Binary built on build-1 at 15:58Z, igneumd sha256 f99340b3cf4ce32e, the string read back; the digest eada4bda on the previous live object and 4bbbe816 on the published floor file (so the 0.3.20 floor file is published), as the pin reads them. The node lane's digest and mixed-version gates on it from 16:00Z; the fleet's set from the same minute; plan 6.9 carries the steps and the two box-input rules the staging added. THE 0.3.20 RECORD (the shipper, UTC). Cases: the dc141409 run on c18-1 CASES END rc 0 at 12:37:18Z (both halves PASS); the c4459193 run on c20-1 CASES END rc 0 at 14:54:02Z with its relay half void (one RunPod host, no hairpin) and the poison half PASS (13 rejected, 0 accepted); main's (b): the publish on the dc141409 cases plus the diff argument (the class byte the only touch in the cases' territory) and c19-1's tip-following, with the separate-host relay re-run on c19-1 on the live digest as the halt condition and the Discord card's gate (CASES END about 16:25Z). PUBLISH 14:54:17Z (15:54 BST): manifest 0.3.20, mac DMG sha256 73796c5f..., Windows installer 45b2f3fb..., the hive tar d9dd12df... on the public alias. THE FLOOR FILE: program_class_v4_activation_daa 900,000 (the live DAA 294,073 at 14:51Z; 294,073 + 604,800 = 898,873 rounded up to the 3,600 boundary), window 86,400 unchanged, file sha256 294f1f80...; the digest 4bbbe8162ea9fff277aa5b16b4ffad9e2262ba5e6a5acac7b697ff77211e7328 read on c4459193's binary before the cut and on the hub's handshake line after. The pin c4459193, igneum-pow 8c728ca3, byte 5; the sweep's node pair a80ed39c / 70a5180f (the build-server lane's native build of the same tree). THE SWEEP complete 15:39Z (16:39 BST): wave 1 the hands (observer-node, node1 at 14:57Z), the Mac (15:23Z on its poller, interface 1.0.1), the hub, pool-1 and the eight heaviest voters (15:04 to 15:21Z); wave 2 the four lighter voters (15:23 to 15:26Z); wave 3 Devnet 2's four pods and bps-seed (digest 4a0b8726 unmoved); the first new-side lock 9313 at 15:28:08Z after a 23-minute split; every lock line "sweep complete before 13 October 09:00 UK (the margin; the floor is now DAA 900,000)". 0.3.17 nodes remaining: PC 1 and PC 2 (offline for the project lead's cable work; their apps update on their pollers on return) and the three testnet seeds (on the testnet, not on the devnet's floor); no devnet node of the fleet, the hands or the Mac on 0.3.17. EARLIEST FLIP: the floor at DAA 900,000 is about 7.0 days of DAA from the publish (605,927 DAA at about one a second), so about 14 October 23:00Z (15 October 00:00 BST) at the earliest, and only once the seven 86,400-DAA windows read 95 percent of blue weight signalling byte 5; the live floor of 831,600 (13 Oct 08:00Z) is replaced by the published file on every swept node, so the chain never flips to the 6 October stream. Per tier: a solo miner on the Mac or a swept box mines on; a PC miner on 0.3.17 is refused by digest when it next connects until its app updates (its poller does this on return; nothing by hand); the pool and the hub are on the pin; the auditor reads one object, one digest, one floor. -SUB-VERSION 3 PASSES BOTH GATES (the attack-pass lane, the close line dated 7 October 2026): class v4 sub-version 3, commit 017e70376489251e18564c0abce7e466e606c8b3 on ca3-v4-amend, pairing id a785001687d8688a (verified by the harness). F8's 64-seed census (p2 to p65) at 2^24 nonces each, chain path, window-model control, box 2, 14:51Z to 16:00:20Z: PASS, 60 of 64 under 1.2x (0.9915x to 1.144x); the only four over are the named tail, unattributed and chased: p10 1.5036x (identical to sub-versions 1 and 2, hottest item 0x4004da at 362 reads, no predicted source), p8 1.3776x (0x837de4, 420 reads), p34 1.2505x (0x800010, 541 reads, the one-bit value through sub at 5), p4 1.2167x (0x4000e7, 355 reads); every strong seed gone (p23 4.82x, p19 3.32x, p15 2.57x, p18 2.50x, p56 2.01x all under 1.2x); the worst ratio on the stream 1.50x; the tail's hottest items carry 355 to 541 reads of 2^31 (one to two per 2^22 items above the mean), no chip consequence. The exhaustion gate as it is: the chain-path count on 017e7037 runs slowly (the draw evaluates (c'') at 2^20 per candidate: 20,532 seeds in 59 minutes, 0 exhausted, 0 panics, max attempt 29), so a 10^6 count is two days away and is not waited on; the substance is met by construction (the 256 cap and the last resort unchanged from 8bdcbdd8, 0 of 10^6 there) and by measurement at 017e7037 on 24,631 seeds (0 exhausted, max 29; r about 0.68); the count runs on as a strengthening line. The node's epoch draw now costs about 2 attempts at 2.2 s each, 4 to 5 s per epoch on slower cores, once an hour. The hash lane's ledger at 6941da1d. SUB-VERSION 3 AT 017e7037 IS THE FROZEN GENERATOR FOR 0.3.22 (byte 7), THE TAIL RULED (main, 18:1x UK): the four seeds (p10 1.5036x with its hottest item at 362 reads, p8 1.3776x at 420, p34 1.2505x at 541, p4 1.2167x at 355, of 2^31 reads) are accepted as the window model's unattributed residue at 1.22x to 1.50x with nil chip consequence; the AP-F8-1 row CLOSES with that wording and the hottest-item counts beside it; the 10^6 count on 017e7037 runs on as the strengthening line. The attack-pass plan's start 15 October or the morning after. 0.3.21's FIRST CANDIDATE 96161037 (sha256 f99340b3cf4ce32e, string read back) passed the node lane's two gates on its own binary: the digest gate 15:59:54Z to 16:01:32Z PASS (a89be8a7 with the peers right; db9a85f9 refused, no peer); the mixed-version gate 16:01:53Z to 16:12:05Z PASS (one digest b0afb2ee on five; 252 new and 352 old accepted, 0 rejected; counts equal at 316, 493 and 604 through both clean joins and the restart step; no panic); the node side complete; the fleet's set on the same binary (the kept start with the ids gate, the wipe canary, the cases rerun, the 12 GB line, N15's restarts of p1-5090 and p2-3090-3) is what the shipper's pin word waits on; byte 5 throughout, nothing on the class v4 seam moved. NOTHING ELSE IS OPEN ON THE COUNTER ASIC LANE TONIGHT (main's word): the record lands and the lane stops. 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 project lead 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 | +SUB-VERSION 3 PASSES BOTH GATES (the attack-pass lane, the close line dated 7 October 2026): class v4 sub-version 3, commit 017e70376489251e18564c0abce7e466e606c8b3 on ca3-v4-amend, pairing id a785001687d8688a (verified by the harness). F8's 64-seed census (p2 to p65) at 2^24 nonces each, chain path, window-model control, box 2, 14:51Z to 16:00:20Z: PASS, 60 of 64 under 1.2x (0.9915x to 1.144x); the only four over are the named tail, unattributed and chased: p10 1.5036x (identical to sub-versions 1 and 2, hottest item 0x4004da at 362 reads, no predicted source), p8 1.3776x (0x837de4, 420 reads), p34 1.2505x (0x800010, 541 reads, the one-bit value through sub at 5), p4 1.2167x (0x4000e7, 355 reads); every strong seed gone (p23 4.82x, p19 3.32x, p15 2.57x, p18 2.50x, p56 2.01x all under 1.2x); the worst ratio on the stream 1.50x; the tail's hottest items carry 355 to 541 reads of 2^31 (one to two per 2^22 items above the mean), no chip consequence. The exhaustion gate as it is: the chain-path count on 017e7037 runs slowly (the draw evaluates (c'') at 2^20 per candidate: 20,532 seeds in 59 minutes, 0 exhausted, 0 panics, max attempt 29), so a 10^6 count is two days away and is not waited on; the substance is met by construction (the 256 cap and the last resort unchanged from 8bdcbdd8, 0 of 10^6 there) and by measurement at 017e7037 on 24,631 seeds (0 exhausted, max 29; r about 0.68); the count runs on as a strengthening line. The node's epoch draw now costs about 2 attempts at 2.2 s each, 4 to 5 s per epoch on slower cores, once an hour. The hash lane's ledger at 6941da1d. SUB-VERSION 3 AT 017e7037 IS THE FROZEN GENERATOR FOR 0.3.22 (byte 7), THE TAIL RULED (main, 18:1x UK): the four seeds (p10 1.5036x with its hottest item at 362 reads, p8 1.3776x at 420, p34 1.2505x at 541, p4 1.2167x at 355, of 2^31 reads) are accepted as the window model's unattributed residue at 1.22x to 1.50x with nil chip consequence; the AP-F8-1 row CLOSES with that wording and the hottest-item counts beside it; the 10^6 count on 017e7037 runs on as the strengthening line. The attack-pass plan's start 15 October or the morning after. 0.3.21's FIRST CANDIDATE 96161037 (sha256 f99340b3cf4ce32e, string read back) passed the node lane's two gates on its own binary: the digest gate 15:59:54Z to 16:01:32Z PASS (a89be8a7 with the peers right; db9a85f9 refused, no peer); the mixed-version gate 16:01:53Z to 16:12:05Z PASS (one digest b0afb2ee on five; 252 new and 352 old accepted, 0 rejected; counts equal at 316, 493 and 604 through both clean joins and the restart step; no panic); the node side complete; the fleet's set on the same binary (the kept start with the ids gate, the wipe canary, the cases rerun, the 12 GB line, N15's restarts of p1-5090 and p2-3090-3) is what the shipper's pin word waits on; byte 5 throughout, nothing on the class v4 seam moved. DEVNET 3 NOW (the project lead through main, 17:3x BST): 0.3.22 is the Devnet 3 release (a fresh network object igneum-devnet-3 with every activation at 0 and no override file, the era VDF fork, class v4 sub-version 3 at byte 7 from genesis), the node building on build-1, genesis by 17:30Z (18:30 BST). THE HANDOFF (17:3x BST, inside the 17:40 BST line, to the shipper and the node lane): igneum-pow 017e70376489251e18564c0abce7e466e606c8b3 (the audit-freeze-2026-10-07 tag; 2a111fb1 and 6941da1d above it docs only), object byte 7, PROGRAM_SUBVERSION_V4 = 3, devnet epoch-0 program id a785001687d8688a (must-differ c120d7963abdcd96, 1a4230699a6b9c60, a788661687db4bb3), kit packs-ca3-v4-sub3 zip sha256 4f2445c50c58d76a5544023492d8b858d0b07c5e372d31f9c90c4ce51f829154, the eight fingerprints as recorded (equal on Metal, Apple OpenCL, the fleet 5090 and PC 2's 5090), both attack-pass gates GREEN, suite 103 of 103, CI success; the open items stated as open: the four-seed tail under main's ruling (the attribution for 0.3.23), the 10^6 count as a strengthening line, the 4 to 5 s epoch draw, the owed measurements that do not gate Devnet 3. NO FURTHER HASH CHANGE RIDES ON 0.3.22; anything from the tail goes to 0.3.23. The node lane stages the re-pin on the 0.3.21 tip as its own commit (the fork commit and the kaspa-pow suite line owed to this record); the hash lane's sub-version 3 pairing follows it. THE PUBLIC CHIP TEXT REWRITTEN LAUNCH-FIRST (the project lead: "I thought we were making it 2.1 from launch?"; master 9b996d06, docs/plans/counter-asic-3-public-text-2026-10-07.md): the testnet and mainnet objects set program_class_v4_activation_daa 0, so class v4 is live from genesis and the launch number is 2.1x to 3.9x on day one; the three texts and evidence row 17 lead with that (labels kept), then class v5, then the 5x to 9x only as the class v3 baseline the work started from, the devnet's activation height a devnet fact only; no em dashes, no prize mention, eight columns; with the site lane to apply in the same deploy as the padding sweep (its commit and deploy time owed to this record). The lane carries on until the re-pin line, the site commit and the genesis record land. 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 project lead 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 project lead'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) | ### AP-F4-1, the weak-day MUL draw (the attack-pass lane, 7 October, morning): PASS against v4, a class v5 rule