The banner under the header stays; the card is the first sight of an update. The same card as the miner's (one
language: the mark with a progress ring, "Igneum Wallet 0.1.3", one line (is available, is downloading with the
percent, is ready to install, Installing. The app restarts itself., did not install with the one-line cause and Try
again), up to three lines of release notes from the manifest with the rest behind "What changed", the size, Install
now and Later. Escape and the backdrop are Later. Reduced motion is honoured.
Rules (ui/update-card.js, pure, ui/update-card.test.mjs): the card never opens while the send screen is open, while
a Touch ID or Windows Hello line is on screen, while a wallet is being created or imported, or while the app quits;
it waits and comes once the block lifts. Later hides this version at this stage and leaves the banner; the card comes
back for a newer version, or when the download is ready and automatic updates are off (with them on it installs by
itself). An open card follows its update through downloading, ready, installing and failed; installing and failed
never open a card by themselves.
The engine serves ui/update-card.js next to app.js (src/server.rs). ?update=<kind>[&auto=0][&card=1] on the page
shows every state without a manifest. The version stays 0.1.2 until the next ship. CI runs the new test file.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The window host owns the prompt and the secret (app/mac/Biometric.swift): LAPolicy.deviceOwnerAuthenticationWithBiometrics
with "Use password" as the fallback button (never the device password), the wallet's password sealed to a Secure
Enclave key made with .biometryCurrentSet (the Keychain refuses biometric access controls under the ad hoc signature,
-34018, measured) in <data>/wallet/biometric.json; a fingerprint change invalidates it. The engine owns the gate
(igneum-common/src/biometric.rs): a nonce per action, read by the host with its token (the HOST line on stdout,
X-Igneum-Host on host-only calls), confirmed after the prompt, taken once within 30 s and bound to the exact quote;
/api/send refuses without it while enrolled; /api/reveal with a nonce reads the unlocked key in memory; the password
never goes through the page (enrolment parks it under a one-time token the host takes). Idle lock after 5 minutes
without window activity (setting, default on). A password change or a wallet removal deletes the sealed file.
Reason lines in our voice ("Unlock your wallet", "Send 1.5 IGN to 0x7E5F…5Bdf", "Show your recovery words"); the page
shows its own ember line after every prompt. Windows: app/windows/biometric.h (UserConsentVerifier through
IUserConsentVerifierInterop, DPAPI), wired into wallet-host.cpp and BUILD-WALLET-APP.bat, not yet compiled on a PC.
Hosts gain a @main entry so Biometric.swift compiles alongside; build-wallet-dmg.sh links LocalAuthentication.
Balance card: the coin at 56 px, "0" (or the balance) as soon as the node answers, "reading the chain, N of M blocks"
under it while the history scans. Version: v0.1.2 in the brand band, "Igneum Wallet 0.1.2 · up to date" in Settings.
Unit tests: the gate (7, igneum-common), the wallet's 17 still green. README: the flows, the threat model, what was
verified on this Mac (enrol and unlock through the real prompt) and what was not.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The 0.1.0 DMG was built before server.rs served /coin.png, so the coin was blank; 0.1.1 ships the
route (brand/igneum-coin-1024.png, checked byte for byte through the engine).
Updates: the apply side of the miner's ota.rs moved into igneum-common/src/ota.rs with the app's
names from AppId (engine_exe added): stage next to the running bundle, digest, detached helper
that swaps and relaunches, pending/result files, rollback when the new app does not start twice.
fetch.rs downloads with resume and reports progress. The wallet's updater.rs runs check (25 s,
then hourly), download, stage, apply in threads; the safe moment is no send in flight (/api/send
running, a quote in the last 180 s, a sent transaction not yet in a block, a create flow half
way). Setting "Install updates by itself when nothing is being sent" (default on), banner with
Install now and Later, settings line with the states. Unit tests: manifest, versions, plan, safe
moment, helper templates, pending/result files.
build-wallet-dmg.sh takes BUILD= and refuses to wipe a work folder an app runs from. README with
the states and what is untested (Windows path, LaunchServices relaunch with the window host,
rollback). Verified end to end with a scratch 0.1.1 bundle against a 0.1.2 test manifest on
127.0.0.1: check, download, stage, swap, relaunch, "updated to Igneum Wallet 0.1.2 from 0.1.1".
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
app/igneum-common (new library crate): the platform helpers with the app identity as a parameter, the payout key
code, the signed OTA manifest (byte-identical to the miner's), the manifest fetch and download check, the 127.0.0.1
server primitives and a JSON client, run_timeout, the packaged config and machine id. Nothing in app/igneum-app
changed; `cargo check -p igneum-app` still passes.
app/igneum-wallet (new): create (24 words, three typed back) or import (words, raw key, the miner's wallet.json),
sealed with Argon2id + XChaCha20-Poly1305 under the user's password; balance, send (EIP-1559, signed in Rust, zero
address refused, fee shown as base fee + tip), receive with a QR drawn locally, history (transfers, block rewards from
the execution records, shard payouts when they exist); finality per transaction verified by the wallet itself with the
node's own finality code (certificate from the blocks after the checkpoint, canonical voter list, aggregate BLS
signature, 2/3 of active and of total weight), shown as pending / in a block / final with the checkpoint index; export
to MetaMask (key with a warning, network parameters, add-network link); node source order: the miner app's node,
the environment's node, the bundled igneumd, the packaged public RPC. 13 unit tests.
Hosts and packaging: app/mac/IgneumWallet.swift, app/windows/wallet-host.* (untested), packaging/mac/build-wallet-dmg.sh,
packaging/windows/Igneum-Wallet.iss, publish-manifest.sh --product wallet (miner path unchanged).
tools/wallet-testnet/run.mjs and the bench-log entry: on igneum-devnet-958 a transfer went pending, in a block and
final under checkpoint 5, 170.6 s after sending, the certificate verified by the wallet.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Three watchers never saw a job finish because the closing upload starts with the app header, not the SUMMARY line,
and a shard run whose stages failed still exited 0.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
the project lead, 4 Oct 2026: 0.3.1, 0.3.2 and 0.3.3 each took eight hand steps and an hour. The tool runs them in order, each
step idempotent and resumable (--from): preflight, bump (six version files, one function, read back), push-inputs,
commit and push, the windows.yml run polled with gh (auth switch before every call), fetch, DMG under the build lock,
copy, signed manifest, one deploy, HEAD/GET verification with sizes and sha256, one console item. --dry-run prints
the plan, --check compares the version files, --self-test bumps a scratch copy. Secrets never printed.
Found by --check: Igneum-Miner.iss and Info.plist were left at 0.3.2 when 0.3.3 was cut (CI passed -Version from
Cargo.toml, so the installer was right; the Mac bundle said 0.3.2 because build-dmg.sh's sed only matched 0.3.0).
Both aligned to 0.3.3; build-dmg.sh now stamps the version with plutil. fetch-ci-artifacts.sh: CONSOLE_SKIP=1.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The intake key sits in every miner package, so the relay now lets it report only (drop text and files, ack, done,
register, upload). Posting a run or task, or renaming and re-roling a machine, needs the console token.
The prove host wrote proofs through SP1's unbuffered save: on WSL2 under /mnt/c the 18 MB core proof of a shard
took longer to save than to prove. Proofs now go through a 4 MB buffer with a timed 'saved' line, and
prove-shard.sh keeps results on the Linux side and copies them per stage. Ledger P20 updated.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The console marked any job with a RESULT line as done, so a running shard job read as finished. Done now means
the SUMMARY line carries finished_at or the job's closing 'job <id>: <status> (exit N)' line is present.
prove-shard.sh dropped the third fixture argument (block-344-shards4) because it read only $2.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Observer (tools/observer/observer.mjs): reads the execution layer's JSON-RPC of a node on the proving build
(IGNEUM_EVM_RPC, default the Mac app's node 26800): every chain block's shard plan as it joins the chain
(igneum_getShardPlan by blockHash, one live_proofs row per shard, planned), the proof records of the chain
blocks of the last 10 minutes polled in rotation (igneum_getProofRecords, four in flight, 40 blocks per tick
while active, 10 before activation): proving (in the pool), verified (SP1 proof verified, or carried and checked
by consensus), paid (a carrying segment paid it), with the prover's id8, the carrier, lag in DAA and the payout.
live_state.proving = {supported, active, activation_daa, tip_daa, verifier, pool, blocks_10m,
blocks_fully_proven_10m, shards_proven_10m, shards_paid_10m, median_proof_lag_s, provers_10m}. A node without
the RPCs gives supported false (rechecked every 5 min); an unreachable endpoint is retried every 20 s. Events:
proving (activation, first paid shard), prover_seen. Additive schema (live_proofs, live_state.proving).
API (site/api/live.mjs): proving, and per block shards: [{i, n, state, prover, lag, payout (IGN), pgas}] and
proven; ?window=N (30 to 300 s) for the page's diagnostic long view; LIVE_TABLE_PREFIX reads a test observer's
tables.
Live page (site/live.html), the design change of 4 Oct 2026: three thin strips sharing one time axis, newest at
the right. BLOCKS keeps the per-miner lanes, chain path, blue/red/pending colouring, arrival glow and tooltips;
the lock ring, dashed lock line and final band leave it. FINALITY is an 18 px bar: ember wash = final (up to the
newest locked checkpoint on screen), molten tick = locked checkpoint, faint = proposed, one label at the newest
lock ("locked #522, 12 s ago"); while finality is not active it reads "finality paused: N% of weight silent" and
nothing else (R4.6.3). PROVING shows one cell per shard under each chain block, outline (planned), molten
(proving), prover colour (verified), tick (paid), a dashed "proofs land N s behind the tip" line, or the one
honest line before activation ("Proving layer: not yet activated on this devnet; activation at DAA N" / "node
without proving"). Header stats: on screen, chain, identities, last lock, proven. Legend: one line per strip.
Hover and tap tooltips on blocks and cells (block, shard, prover, lag, payout). Lanes snap on resize (they used
to ease from a zero-height layout). Phone width, no horizontal scroll; draw 0.6 ms avg, 1 ms max with 110 blocks
on screen (playwright, 1280 px).
Hero (site/index.html): a faint second glint behind a real block once every shard of it is verified, only while
the proving layer is active; pace and sampling untouched.
Verified on the private 3-node proving network (tools/proving-v0/run.mjs --network-only, activation 60) with a
CPU prover loop signing as v0/v1/v2: records relayed, verified on node 0, carried and paid (block 155 by 405,
lag 259 DAA, 0.634 IGN); screenshots in docs/design/live-proving (devnet before activation at 1280 and 375 px,
test network active, the ?window=300 view with paid cells). The live devnet shows the "not yet activated;
activation not set" line once the observer runs this build.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
make-icons.py make_social(): og-small.png (256 square, the compact card index/live/litepaper declare), og-square.png
(1024), og-coin.png and og.png (1200x630: mark left, IGNEUM wordmark, tagline, subline; same layout as before, no ring,
no glow). bench.html, evidence.html and build.mjs referenced /og.png, which did not exist; they now get the 1200x630 card
with width/height 1200x630 and twitter:card summary_large_image. Every og:image and twitter:image carries ?v=2 so
Slack, X and iMessage refetch. brand/profile: github-social-1280x640.png (repository social preview) and
vercel-avatar-512.png. bench.html edited by hand for the meta only (a build.mjs run would publish uncommitted log entries).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
PC 2 on 0.3.3: 'wsl -d Ubuntu-24.04 -u [user]' from the app fails with getpwnam([user]) and the default user has no
cargo, while the project lead's own session has both in a distro of the same name: WSL distros belong to the Windows account,
and the engine runs under a different context than the interactive session. So the prover path is self-sufficient
inside the Ubuntu the app sees: the wsl-prover probe and the shard-benchmark job run as root (the job's wsl_user or
IGNEUM_APP_WSL_USER first, root second, the distro default last), and the shard job runs the Linux host the
payload ships next to the app (wsl2\bin\igneum-prove-host, cuda feature) directly for each fixture (shard 0 in
shard mode, the blocks in block mode, results under <app data>\prove\igneum-prove-wsl2\results); params.build
= true keeps the package's prove-shard.sh path. Every job logs the account context first (Windows user, SID,
elevated, the signed-in console user, then 'wsl user <id> uid <n> home <h>' and nvidia-smi inside the distro),
the engine logs it once at start, and the dashboard (Settings and the job strip) says 'The app runs as X
(elevated). The signed-in user is Y; WSL and its tools belong to that account.' when they differ.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
PC 2 on 0.3.3 logged 'needs wsl-prover' although the toolchain is there as user [user]. Every negative probe now
lands in the engine log with its exit code and the first 200 characters of output (it reaches the intake). The
probe sources ~/.cargo/env and sets ~/.cargo/bin and ~/.sp1/bin itself (a login shell from a console-less process
need not), runs as the job's wsl_user or IGNEUM_APP_WSL_USER first and the distro default user second, and a
payload with wsl2\bin\igneum-prove-host next to the app meets the requirement when the distro answers.
publish-jobs.sh: --requires none or "" publishes an empty list (none was a literal requirement, "" fell back
to the kind's default).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The IGNEUM-APP header is read from the newest upload's first line, from any tail, or from the first upload of
the run; the app's status: line supplies peers, lifetime accepted and synced when the node log tail has none.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
rollout-v2.sh stages the Linux igneumd (gateways from the Mac, private nodes from their gateway), rolls one node at a time with
difficulty_v2_activation_daa in every override file, checks the common chain and watches the height; results/2026-10-04/
rollout-v2*.log and v2/ (the hash-rate step under v2 and the v1 comparison). docs/plans/difficulty-v2-rollout-devnet.md: the
binaries and their sha256, the activation rule (N = DAA at publish + 10,800; baked at the cut as DAA + 14,400), the exact
restart lines for the observer node, the seed and Mac node 1, the OTA path for the two PCs through NODE_OVERRIDE_PARAMS in
packaged-config.sh (the engine side landed in 00fff5f), the rehearsal record. Bench-log entry.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
partition.sh adapted to private-network mode: the cut sits on the region's gateway (INPUT, OUTPUT and FORWARD
against the far gateways' public IPs over 26611 and the DNAT ports 27001:27099), since a per-node port-26611 rule
leaves the DNAT links up. It now records the locks per side at cut, during, at heal and after convergence, the
first lock after the heal from the journals, and the heal time as each minority node's first chain removal of 5+
blocks (the sink-count criterion is tip churn on a healthy network). hop.sh and partition.sh hold the Mac awake
with caffeinate; analyze.py gains a 10-s hop series (difficulty, block count, 1- and 2-min rates, threads) and an
overshoot table; collect.sh writes hop-series.tsv and hop.md and gzips the journals.
Results 2026-10-04: partition 1 (window still filling) reorg 431/496 on the minority, 2 on the majority, healed in
10 and 14 s; partition 2 (locks active): minority locked nothing during the cut, majority locked every interval at
66.8% to 84.5% of total, 0 conflicting locks over 107 indices, healed in 11 and 15 s, first lock after heal 13 s.
Hash-rate steps x1.42, x0.70, x0.75, x1.32: difficulty overshoots x1.67, x0.66, x0.53, x1.60, settle 751 s,
never in 900 s, 241 s, 646 s. Failures stated in summary.md: the Mac hibernated during the hop (phase 2 ran 94
min), the first partition could not see locks, the script's heal and first-lock figures were artefacts (fixed),
and another agent's v2 rollout restarted every node during the second heal.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>