Igneum 2.0: one network in the window, the Igneum 2.0 devnet; the testnet card and its note are gone

The founder's word of 8 October 2026 (16:2x BST): the testnet is scrapped and the devnet is one network, served as
"the Igneum 2.0 devnet" (the engine runs igneum-devnet-4 and serves the label as state.chain, the shipper's engine
commit on the same line). The network step (step 3 of 4) and the Settings Node card show one card, "Igneum 2.0 devnet
· igneum-devnet-4 · the chain may reset, coins have no value", the fresh-install default and the only choice; an
existing install keeps what it runs ("This machine runs the Igneum 2.0 devnet (igneum-devnet-4)."); an older network
name reads as the one network. The "igneum-testnet-1 opens when…" note, the testnet card, "Devnet 3" and "devnet v4"
leave index.html and app.js (the welcome eyebrow and the node facts default read "Igneum 2.0 devnet"). The mock's
recorded state carries the new chain label and network name.

Tests known-failed first on build-2 (once.test.mjs: one NETWORKS entry, one card, the words, no testnet or old label
in the window), then green; the 0.3.23 network tests follow (the Rust-source mirror keeps the network_switch name
and its test, and no longer pins the testnet_open signature or the manifest's testnet rule, which the engine commit
removes). 126 UI tests green.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
igneum-labs 2026-10-08 15:40:24 +00:00
parent c4f7bbfd22
commit 942e82bb9e
5 changed files with 45 additions and 46 deletions

View file

@ -306,21 +306,19 @@ var View = (function () {
// the tooltip on a card's name: what the tool calls it (gfx1201), its device index, the OpenCL platform, the PCI address
function cardTitle(cd) { var t = []; if (cd.code && cd.code !== cd.name) t.push(cd.code); if (cd.device !== undefined && cd.device !== '') t.push(cd.worker + ' device ' + cd.device); if (cd.platform) t.push(cd.platform); if (cd.bus) t.push('bus ' + cd.bus); return t.join(' · '); }
// ---------- the network step (0.3.23) ----------
// Two cards. A fresh install selects the manifest's default_network (Devnet 3 until the go); the testnet card reads
// "not yet open" and is refused until the manifest names it open; an existing install keeps the network it runs.
// ---------- the network step (Igneum 2.0, 8 October 2026) ----------
// One network: the Igneum 2.0 devnet (the engine runs igneum-devnet-4 and serves the label as state.chain). The card is the
// fresh-install default and the only choice; an existing install keeps what it runs; an older name reads as this one.
var NETWORKS = [
{ id: 'devnet-3', label: 'Devnet 3', name: 'igneum-devnet-3', chain: 4463, sub: 'staging: the chain may reset, coins have no value' },
{ id: 'testnet-1', label: 'igneum-testnet-1', name: 'igneum-testnet-1', chain: 4462, sub: 'the public test chain: coins have no value, resets are announced' }
{ id: 'devnet-4', label: 'Igneum 2.0 devnet', name: 'igneum-devnet-4', sub: 'the chain may reset, coins have no value' }
];
function networkIdOf(name) { for (var i = 0; i < NETWORKS.length; i++) if (NETWORKS[i].name === name) return NETWORKS[i].id; return 'devnet-3'; }
function networkIdOf(name) { for (var i = 0; i < NETWORKS.length; i++) if (NETWORKS[i].name === name) return NETWORKS[i].id; return NETWORKS[0].id; }
function networkWords(s) {
s = s || {}; var st = s.settings || {}, u = s.update || {}, open = !!u.testnet_open, current = networkIdOf(s.network_name || ''), pending = s.network_pending || '';
var chosen = st.network || '', def = (u.default_network === 'testnet-1' && open) ? 'testnet-1' : 'devnet-3';
var selected = s.setup_done ? (pending || current) : (chosen || def);
var cards = NETWORKS.map(function (n) { var isOpen = n.id !== 'testnet-1' || open; return { id: n.id, label: n.label, name: n.name, line: n.id === 'devnet-3' ? 'igneum-devnet-3, chain id 4463' : (open ? 'chain id 4462' : 'chain id 4462 · not yet open'), sub: n.sub, open: isOpen, selected: n.id === selected, current: !!s.setup_done && n.id === current }; });
s = s || {}; var st = s.settings || {}, current = networkIdOf(s.network_name || ''), pending = s.network_pending || '';
var selected = s.setup_done ? (pending || current) : (st.network || NETWORKS[0].id);
var cards = NETWORKS.map(function (n) { return { id: n.id, label: n.label, name: n.name, line: n.name, sub: n.sub, open: true, selected: n.id === selected, current: !!s.setup_done && n.id === current }; });
var pend = NETWORKS.filter(function (n) { return n.id === pending; })[0];
var line = pend ? 'Switching to ' + pend.name + ' at the next start: quit Igneum Miner and open it again.' : s.setup_done ? 'This machine runs ' + (s.network_name || 'igneum-devnet-3') + '.' : '';
var line = pend ? 'Switching to ' + pend.label + ' (' + pend.name + ') at the next start: quit Igneum Miner and open it again.' : s.setup_done ? 'This machine runs the ' + NETWORKS[0].label + ' (' + (s.network_name || NETWORKS[0].name) + ').' : '';
return { cards: cards, selected: selected, current: current, pending: pending, line: line, error: s.network_error || '' };
}
function networkAsk(want, runningName) { var n = NETWORKS.filter(function (x) { return x.id === want; })[0]; return 'Switch this machine to ' + (n ? n.name : want) + '? The node’s data and the mining state on ' + runningName + ' reset at the next start. Your key and your address stay.'; }
@ -1743,7 +1741,7 @@ if (typeof document !== 'undefined') (function () {
}
function renderNetworkStep(s) {
var w = View.networkWords(s); renderNetCards($('network-cards'), w, netPick);
var note = w.error || (w.cards[1].open ? '' : 'igneum-testnet-1 opens when the network does; Devnet 3 is the chain to mine today.');
var note = w.error || '';
setText('network-note', note); setHidden('network-note', !note);
}
$('network-cards').addEventListener('click', function (e) { var b = e.target.closest('.net-card'); if (!b || b.disabled) return; netPick = b.getAttribute('data-net'); if (state) renderNetworkStep(state); });
@ -1754,7 +1752,7 @@ if (typeof document !== 'undefined') (function () {
setText('s-network-line', w.line); setText('s-network-eyebrow', w.pending ? 'next start' : 'running');
setText('s-network-note', w.error); setHidden('s-network-note', !w.error);
}
$('s-network-cards').addEventListener('click', function (e) { var b = e.target.closest('.net-card'); if (!b || b.disabled || !state) return; var want = b.getAttribute('data-net'), w = View.networkWords(state); if (want === w.selected) return; $('ask-network-text').textContent = View.networkAsk(want, state.network_name || 'igneum-devnet-3'); $('ask-network').dataset.want = want; $('ask-network').hidden = false; });
$('s-network-cards').addEventListener('click', function (e) { var b = e.target.closest('.net-card'); if (!b || b.disabled || !state) return; var want = b.getAttribute('data-net'), w = View.networkWords(state); if (want === w.selected) return; $('ask-network-text').textContent = View.networkAsk(want, state.network_name || 'igneum-devnet-4'); $('ask-network').dataset.want = want; $('ask-network').hidden = false; });
$('ask-network-no').addEventListener('click', function () { $('ask-network').hidden = true; });
$('ask-network-yes').addEventListener('click', function () { var want = $('ask-network').dataset.want; $('ask-network').hidden = true; api('api/network', { network: want, confirm: true }).then(function (r) { if (r.ok) toast('Network saved: it takes effect at the next start'); }); });
function saveRegion(code, price, cur) {

View file

@ -73,7 +73,7 @@
<section class="screen" id="screen-welcome">
<div class="hero">
<div class="mark-wrap"><img src="mark.svg" width="72" height="72" alt=""></div>
<div class="eyebrow ember">devnet v4 &middot; nothing is bought or sold</div>
<div class="eyebrow ember">Igneum 2.0 devnet &middot; nothing is bought or sold</div>
<h1>Igneum Miner</h1>
<p class="lead">Runs a node and mines Igneum with your graphics card. Set up in two steps.</p>
<div class="three">
@ -156,8 +156,7 @@
</div>
</section>
<!-- 4. the network (0.3.23): two cards; the fresh-install default comes from the manifest's default_network, the testnet
card reads "not yet open" and is refused until the manifest names it open -->
<!-- 4. the network (Igneum 2.0, 8 October 2026): one card, the fresh-install default -->
<section class="screen" id="screen-network">
<div class="step">
<div class="eyebrow">step 3 of 4</div>
@ -414,7 +413,7 @@
<div><span class="k">whose node</span><span class="v" id="n-source"></span><span class="m" id="n-source-m"></span></div>
<div><span class="k">height</span><span class="v mono" id="n-blocks">0</span><span class="m" id="n-blocks-sub">blocks this node holds</span></div>
<div><span class="k">peers</span><span class="v mono" id="n-peers">0</span><span class="m" id="n-peers-sub">other nodes it talks to</span></div>
<div><span class="k">version</span><span class="v mono" id="n-version">--</span><span class="m" id="d-node-net">devnet v4</span></div>
<div><span class="k">version</span><span class="v mono" id="n-version">--</span><span class="m" id="d-node-net">Igneum 2.0 devnet</span></div>
<div><span class="k">headers</span><span class="v mono" id="n-headers">0</span><span class="m">headers arrive before blocks</span></div>
<div><span class="k">network blocks</span><span class="v mono" id="n-daa">0</span><span class="m">blocks the whole network has made (the DAA score)</span></div>
<div><span class="k">difficulty</span><span class="v mono" id="n-diff">0</span><span class="m">how hard the next block is to find</span></div>

View file

@ -295,3 +295,20 @@ test('T-A8 and the copy law: no uppercase on a unit label; no em dash in the win
}
assert.equal(once(html, '—'), 0, 'no em dash in index.html'); assert.equal(once(src, '—'), 0, 'no em dash in app.js');
});
// Igneum 2.0 (the founder, 8 October 2026, 16:2x BST): the testnet is scrapped and the devnet is one network, "the Igneum 2.0
// devnet" (the engine runs igneum-devnet-4 and serves the label as state.chain). The network step and the Settings Node card
// show one card; no testnet card, no "opens when" note, no "Devnet 3" or "devnet v4" text anywhere in the window. Known-failed
// first on release-2.0.0 b891444f: two cards, the testnet note, the old labels.
test('Igneum 2.0: one network, the Igneum 2.0 devnet; no testnet, no Devnet 3, no devnet v4 anywhere in the window', () => {
assert.equal(V.NETWORKS.length, 1); assert.equal(V.NETWORKS[0].id, 'devnet-4'); assert.equal(V.NETWORKS[0].name, 'igneum-devnet-4'); assert.equal(V.NETWORKS[0].label, 'Igneum 2.0 devnet');
const fresh = V.networkWords({ setup_done: false, network_name: '', network_pending: '', settings: { network: '' }, update: {} });
assert.equal(fresh.cards.length, 1); assert.equal(fresh.selected, 'devnet-4'); assert.equal(fresh.cards[0].open, true); assert.equal(fresh.cards[0].selected, true);
assert.equal(fresh.cards[0].line, 'igneum-devnet-4'); assert.equal(fresh.cards[0].sub, 'the chain may reset, coins have no value');
const running = V.networkWords({ setup_done: true, network_name: 'igneum-devnet-4', network_pending: '', settings: { network: '' }, update: {} });
assert.equal(running.line, 'This machine runs the Igneum 2.0 devnet (igneum-devnet-4).'); assert.equal(running.cards[0].current, true);
assert.equal(V.networkIdOf('igneum-devnet-3'), 'devnet-4', 'an older name reads as the one network');
for (const text of [html, src]) { assert.equal(/testnet/i.test(text), false, 'no testnet'); assert.equal(/Devnet 3|devnet-3|devnet v4/.test(text), false, 'no old devnet label'); }
assert.equal(once(html, 'Igneum 2.0 devnet'), 2, 'the welcome eyebrow and the node facts default');
assert.equal(once(src, 'opens when the network does'), 0);
});

View file

@ -1019,40 +1019,25 @@ test('Settings: "Check for an update" posts api/update/check and "Check for jobs
assert.equal(/\$\('s-update'\)[^\n]*api\/jobs\/check/.test(src), false); assert.equal(/\$\('s-jobs-check'\)[^\n]*api\/update\/check/.test(src), false);});
// ---------- the network step (0.3.23, main's design with two corrections, 7 October 2026) ----------
// A fourth first-run screen and a Settings card: two cards, Devnet 3 and igneum-testnet-1. The fresh-install default comes
// from the manifest's default_network (Devnet 3 until the go); the testnet card reads "not yet open" and is refused until the
// manifest names it open; an existing install keeps its network; nothing switches a running miner without the user's click
// and the confirm that names what resets.
test('network words: the manifest default selects the card on a fresh install, the testnet card is refused until open, an existing install keeps its network (known-failed on 0.3.23)', () => {
const fresh = { setup_done: false, network_name: 'igneum-devnet-3', network_pending: '', settings: { network: '' }, update: { default_network: 'devnet-3', testnet_open: false } };
// Igneum 2.0 (8 October 2026): one network card, the Igneum 2.0 devnet; the once-test holds the words. An existing install
// keeps what it runs and the card it runs is marked current; nothing switches a running miner without the click and the confirm.
test('network words: one card, selected on a fresh install, current on an existing one; the pending state after a confirmed switch', () => {
const fresh = { setup_done: false, network_name: '', network_pending: '', settings: { network: '' }, update: {} };
const w = V.networkWords(fresh);
assert.deepEqual(w.cards.map((c) => c.id), ['devnet-3', 'testnet-1']);
assert.equal(w.selected, 'devnet-3', 'the manifest default');
const dn3 = w.cards[0], tn = w.cards[1];
assert.equal(dn3.label, 'Devnet 3'); assert.equal(dn3.line, 'igneum-devnet-3, chain id 4463'); assert.equal(dn3.sub, 'staging: the chain may reset, coins have no value'); assert.equal(dn3.open, true);
assert.equal(tn.label, 'igneum-testnet-1'); assert.equal(tn.line, 'chain id 4462 · not yet open'); assert.equal(tn.sub, 'the public test chain: coins have no value, resets are announced'); assert.equal(tn.open, false);
assert.equal(V.networkWords({ ...fresh, update: { default_network: '', testnet_open: false } }).selected, 'devnet-3', 'no manifest read yet: Devnet 3');
const open = V.networkWords({ ...fresh, update: { default_network: 'testnet-1', testnet_open: true } });
assert.equal(open.selected, 'testnet-1'); assert.equal(open.cards[1].line, 'chain id 4462'); assert.equal(open.cards[1].open, true);
// an existing install keeps what it runs; the card it runs is marked current
const old = V.networkWords({ setup_done: true, network_name: 'igneum-devnet-3', network_pending: '', settings: { network: '' }, update: { default_network: 'testnet-1', testnet_open: true } });
assert.equal(old.selected, 'devnet-3'); assert.equal(old.current, 'devnet-3'); assert.equal(old.cards[0].current, true);
assert.equal(old.line, 'This machine runs igneum-devnet-3.');
// the pending state after a confirmed switch
const pend = V.networkWords({ setup_done: true, network_name: 'igneum-devnet-3', network_pending: 'testnet-1', settings: { network: 'testnet-1' }, update: { default_network: 'testnet-1', testnet_open: true } });
assert.equal(pend.line, 'Switching to igneum-testnet-1 at the next start: quit Igneum Miner and open it again.');
assert.deepEqual(w.cards.map((c) => c.id), ['devnet-4']); assert.equal(w.selected, 'devnet-4');
const old = V.networkWords({ setup_done: true, network_name: 'igneum-devnet-4', network_pending: '', settings: { network: '' }, update: {} });
assert.equal(old.selected, 'devnet-4'); assert.equal(old.current, 'devnet-4'); assert.equal(old.cards[0].current, true);
const pend = V.networkWords({ setup_done: true, network_name: 'igneum-devnet-4', network_pending: 'devnet-4', settings: { network: 'devnet-4' }, update: {} });
assert.equal(pend.line, 'Switching to Igneum 2.0 devnet (igneum-devnet-4) at the next start: quit Igneum Miner and open it again.');
for (const s of [w, old, pend]) for (const c of s.cards) assert.equal(/—|–/.test(c.label + c.line + c.sub), false);
});
test('the switch is refused without the confirm, and the confirm names what resets; the testnet choice is refused while not open', () => {
assert.equal(V.networkAsk('testnet-1', 'igneum-devnet-3'), 'Switch this machine to igneum-testnet-1? The node’s data and the mining state on igneum-devnet-3 reset at the next start. Your key and your address stay.');
assert.equal(V.networkAsk('devnet-3', 'igneum-testnet-1'), 'Switch this machine to igneum-devnet-3? The node’s data and the mining state on igneum-testnet-1 reset at the next start. Your key and your address stay.');
// the Rust rule the server applies (config::network_switch): mirrored here by its source text
test('the switch is refused without the confirm, and the confirm names what resets', () => {
assert.equal(V.networkAsk('devnet-4', 'igneum-devnet-3'), 'Switch this machine to igneum-devnet-4? The node’s data and the mining state on igneum-devnet-3 reset at the next start. Your key and your address stay.');
// the Rust rule the server applies (config::network_switch): mirrored here by its source text (the signature is the engine's)
const cfg = rustSrc('config.rs');
assert.match(cfg, /pub fn network_switch\(want: &str, running: &str, testnet_open: bool, confirmed: bool\) -> Result<\(\), String>/);
assert.match(cfg, /pub fn network_switch\(/);
assert.match(cfg, /fn network_switch_rules\(\)/, 'the Rust test exists');
assert.match(rustSrc('manifest.rs'), /default_network names the testnet before it is open/, 'a manifest with the testnet default before the open is refused');
assert.match(rustSrc('manifest.rs'), /fn default_network_rules\(\)/, 'the manifest test exists');
assert.match(rustSrc('server.rs'), /"\/api\/network" =>/);
// the markup: the step sits before the address step, four steps now; the Settings card exists
const idx = pageHtml;

File diff suppressed because one or more lines are too long