diff --git a/docs/community/discord/ladder.md b/docs/community/discord/ladder.md new file mode 100644 index 000000000..26913c4ee --- /dev/null +++ b/docs/community/discord/ladder.md @@ -0,0 +1,78 @@ +# Discord: the ladder's rung announcements (message shapes, not posted) + +7 October 2026, miner-ui-5 (mission item 6, docs/analysis/mission/mission.md 2.6). The shapes the bot would post for +each rung of the miner's ladder, so the words in Discord match the app and the site rung for rung. Nothing here is +posted by this lane; the Discord lane wires them into `tools/community/discord-hooks.mjs` behind its guard rails +(docs/community/discord-hooks.md: the forbidden-string guard, the limits, idempotency keys, never a mention). Every +number is a chain fact from the public API (`/api/live`, `/api/stats`), which is the observer's copy of the node's +`getFinalityWeights` and `getFinalityCheckpoints`; a post names nothing the chain does not say. + +## The rules every rung post obeys + +| Rule | How | +|---|---| +| The miner's object, never the project's | a post carries the key id, the block link, the rank and the day; never the network hashrate, the block count or a milestone of the project | +| A chain fact only | the trigger is a field of `getFinalityWeights` (`keys[].blocks`, `keys[].voter`, `keys[].participation`, `voters`) or `getFinalityCheckpoints` (`latestLockedIndex`), read through `/api/live finality.weights` | +| Opt-in for anything beyond the key id | the card model and the "(you)" link to the address page appear only when the miner switched "Make my page public" on in the app (settings.profile_public); without it the post is the key id and the block link | +| Short key id | the first 8 hex of the vote key hash, the same id the app, `/live` and the explorer show; never a payout address, never a machine name | +| One post per key per rung | idempotency key `rung::`; a rung is posted once for a key, ever (a key that drops and climbs back is not posted again) | +| Copy law | no em dashes, no two-beat antithesis, no aphorisms; the numbers in the line, nothing decorative | +| Volume | #first-blocks takes rungs 0 and 1 (one line each); #numbers takes the daily ladder summary; rungs 2 to 5 and P are never posted singly (one a minute at scale), they are counted in the summary | + +## Channel: #first-blocks + +### Rung 0, first block (trigger: a key's first blue block in the window; `keys[].blocks` goes 0 to 1 in `finality.weights`, and the block's `miner` is that key in `/api/live blocks[]`) + +``` +First block: key 6ad0e117 +Block 1,284,117 · igneum.network/block/9f3a…c21e +RTX 4070 (the miner chose to show the card) +``` + +Without the opt-in the third line is absent. Embed: ember accent, title "First block", one field "Key" = `6ad0e117`, one field "Block" = the explorer link; footer the UK time with UTC in brackets (the hooks script's footer rule). + +### Rung 1, the vote (trigger: `keys[].voter` goes false to true, that is `blocks` reaches `params.dust`) + +``` +Your key has a vote: 6ad0e117 +100 blocks in the window (the line is 100) · the key now signs every checkpoint +``` + +On the devnet the line reads `5 blocks in the window (the line is 5)`: the number is `params.dust`, never a constant. + +## Channel: #numbers, the daily ladder summary (09:00 UK, beside the daily digest) + +``` +The ladder, yesterday +First blocks: 14 keys found their first block +Votes: 9 keys crossed the dust line (now 1,213 voters) +Signatures: 1,201 keys signed a locked checkpoint (latest lock 184,220) +Full window: 406 keys at 30 of 30 days +Rank 1 by weight: 6e80f3ef with 2,592 blocks in the window +Signing streak, longest: 41 days unbroken (presence 100%) +Shards: 388 paid to 57 keys +``` + +Fields and sources, one per line: + +| Line | Field | +|---|---| +| First blocks | keys whose `blocks` went from 0 to at least 1 between the two daily reads of `finality.weights.keys[]` | +| Votes | keys whose `voter` went false to true; `voters` for the total | +| Signatures | keys with `participation` above 0 at the day's last read; `latest_locked_index` for the lock | +| Full window | keys whose `blocks` span the whole `params.weightWindow` (owed from the node: `keys[].daysMined`; until then the line is left out, never estimated) | +| Rank 1 | `keys[]` sorted by `blocks`, the top row | +| Signing streak | owed from the node (`keys[].streakDays`); until then the line is left out | +| Shards | `/api/live proving.shards_paid_10m` summed over the day's reads, provers from `live_proofs.prover` | + +A line whose field the node does not expose yet is left out of the post rather than estimated (the "no number a company server has to be trusted for" rule, reinvent.md section 6). + +## Roles (the Discord lane, from the same fields) + +| Role | Granted when | Revoked when | +|---|---|---| +| Voter | a message signed with the vote key names a key whose `voter` is true in `getFinalityWeights` | `voter` false at a daily read (a key under dust, or stripped: `strippedUntilDaa` above the DAA score) | +| Window | the key's blocks span the full `params.weightWindow` (`keys[].daysMined` owed; until then by hand from the ladder summary) | the key misses a day | +| Prover | a paid shard record names the key (`igneum_getProofRecords(block).paid[shard]`) | never (a paid record is a chain fact) | + +The signed message is the proof of key ownership; the app does not sign it yet (owed: a "prove my key" button that signs a nonce with the vote key and copies it). diff --git a/docs/plans/miner-ui-5-first-share-runbook.md b/docs/plans/miner-ui-5-first-share-runbook.md new file mode 100644 index 000000000..b0990f7be --- /dev/null +++ b/docs/plans/miner-ui-5-first-share-runbook.md @@ -0,0 +1,67 @@ +# Runbook: "first share within 10 minutes of download in 9 of 10 fresh Windows installs" + +7 October 2026, miner-ui-5. The measurement behind the `/evidence` line in mission item 6 (docs/analysis/mission/mission.md +2.6, reinvent.md 3.1). Written for the shipper (ae892a8b0f78fe31c) to run at the Devnet 2 gate of each cut; the app +lane does not run it. Nothing here touches PC 1 or a live manifest. + +## What is measured + +Ten fresh Windows 11 installs, each timed from the download's first byte to the first accepted share or block, with +three timed steps between: the installer (download start to the app's first screen), the node (first screen to +`node.synced` true), the card (synced to the first `ACCEPTED block` line, or the first share once pool-0 exists). The +claim passes when 9 of 10 reach the first accepted block or share inside 600 s of the download's start. + +## Where the numbers come from + +| Step | Start mark | End mark | Read from | +|---|---|---|---| +| Download | the first byte of `Igneum-Miner-Setup-.exe` (the fetch's own timestamp) | the file complete | the job script's clock | +| Install and first screen | the file complete | `api/state` answers with `phase` = welcome (the engine is up) | the app's URL file, then `api/state` | +| Setup | welcome | `setup_done` true (Continue, Make me an address, I have saved my key, Start mining: the playbook clicks or the job posts `api/setup`) | `api/state` | +| Node | `setup_done` | `node.synced` true and `node.state` synced | `api/state` | +| Card | synced | `ladder.first_block_at` set (the first `ACCEPTED block` line) or, with pool-0, the first `share_result` line | `api/state.ladder` | +| Total | download start | `ladder.first_block_at` (or the share) | both clocks, the box's and the VM's, read as UTC | + +`api/state.ladder.first_synced_at` and `first_mining_at` carry the node and card marks from the engine's own clock; the +runbook takes those over the script's reads when both exist. + +## The ten installs + +- Ten fresh Windows 11 VMs (or ten fresh user profiles on the two PCs is NOT acceptable: a fresh profile shares the + machine's node data and its driver state). The fleet's Windows wave boxes are the candidates; PC 1 and PC 2 are not + (PC 1 is the project lead's desk, PC 2 holds a standing node). +- Each VM: the GPU driver installed, no Igneum folder under `%LOCALAPPDATA%`, the clock right (the clock card blocks + mining otherwise and the run is void, not a fail). +- The download is the public installer URL of the cut under test, through the dl host, never a scratch copy. +- The run is `node tools/build-job.mjs run --target --script relay/playbooks/first-share.ps1` with the playbook + recording the six marks as `RESULT` lines; the collect job brings `app/ladder.json` back. + +## The playbook's RESULT lines + +``` +RESULT step=download start= end= bytes= +RESULT step=install end= +RESULT step=setup end= +RESULT step=node end= synced_at= +RESULT step=card end= mining_at= first_block_at= hash= +RESULT total_s= pass= +``` + +A run without a `first_block_at` inside 1,800 s ends with `pass=false` and the step it stalled in. A Poisson miss is +a fail too: an 8 GB card at 100 GH/s has a 46 percent chance inside the first hour (reinvent 1.4), so the claim is +about the install and the node, and the card step is measured against the Poisson expectation from +`api/ladder.network.hashrate_hps` and the card's rate (`mining.hash_total`); a run whose card step passed the +expected gap by less than one gap is reported as "within expectation" beside the pass word. + +## What is published + +`/evidence` gets one table: ten rows (card model, driver, the four step times, the total, pass), the median of each +step, the pass count, the cut's version and the installer's sha256. The site lane owns the page; the shipper hands +it the table as a JSON file (`site/evidence/first-share-.json`) with the same keys as the RESULT lines. + +## Known holes + +- Pool-0 is not built into the app yet (reinvent 3.5), so today the end mark is the first accepted block, not a share; + the claim's words say "first share or block" until the pool field ships. +- SmartScreen (reinvent 3.1) adds two clicks the playbook must make; the time they take counts in the install step. +- A VM without a GPU passthrough measures the node steps only and is reported as such, not as a pass. diff --git a/docs/plans/miner-ui-5-shots/u00-block-card-1200x630.png b/docs/plans/miner-ui-5-shots/u00-block-card-1200x630.png new file mode 100644 index 000000000..4ae7c969a Binary files /dev/null and b/docs/plans/miner-ui-5-shots/u00-block-card-1200x630.png differ diff --git a/docs/plans/miner-ui-5-shots/u01-overview-firstwait-dark-1440.png b/docs/plans/miner-ui-5-shots/u01-overview-firstwait-dark-1440.png new file mode 100644 index 000000000..e51dabd48 Binary files /dev/null and b/docs/plans/miner-ui-5-shots/u01-overview-firstwait-dark-1440.png differ diff --git a/docs/plans/miner-ui-5-shots/u02-overview-firstblock-dark-1440.png b/docs/plans/miner-ui-5-shots/u02-overview-firstblock-dark-1440.png new file mode 100644 index 000000000..eb583bc7c Binary files /dev/null and b/docs/plans/miner-ui-5-shots/u02-overview-firstblock-dark-1440.png differ diff --git a/docs/plans/miner-ui-5-shots/u03-overview-firstblock-light-1440.png b/docs/plans/miner-ui-5-shots/u03-overview-firstblock-light-1440.png new file mode 100644 index 000000000..dae90107e Binary files /dev/null and b/docs/plans/miner-ui-5-shots/u03-overview-firstblock-light-1440.png differ diff --git a/docs/plans/miner-ui-5-shots/u04-overview-inspect-dark-1440.png b/docs/plans/miner-ui-5-shots/u04-overview-inspect-dark-1440.png new file mode 100644 index 000000000..75dce4400 Binary files /dev/null and b/docs/plans/miner-ui-5-shots/u04-overview-inspect-dark-1440.png differ diff --git a/docs/plans/miner-ui-5-shots/u05-earnings-ladder-dark-1440.png b/docs/plans/miner-ui-5-shots/u05-earnings-ladder-dark-1440.png new file mode 100644 index 000000000..c9d7ccf47 Binary files /dev/null and b/docs/plans/miner-ui-5-shots/u05-earnings-ladder-dark-1440.png differ diff --git a/docs/plans/miner-ui-5-shots/u06-earnings-ladder-light-1440.png b/docs/plans/miner-ui-5-shots/u06-earnings-ladder-light-1440.png new file mode 100644 index 000000000..fa565e440 Binary files /dev/null and b/docs/plans/miner-ui-5-shots/u06-earnings-ladder-light-1440.png differ diff --git a/docs/plans/miner-ui-5-shots/u07-prove-shard-dark-1440.png b/docs/plans/miner-ui-5-shots/u07-prove-shard-dark-1440.png new file mode 100644 index 000000000..a6f32d91c Binary files /dev/null and b/docs/plans/miner-ui-5-shots/u07-prove-shard-dark-1440.png differ diff --git a/docs/plans/miner-ui-5-shots/u08-cards-ign-dark-1440.png b/docs/plans/miner-ui-5-shots/u08-cards-ign-dark-1440.png new file mode 100644 index 000000000..d60dc0fb2 Binary files /dev/null and b/docs/plans/miner-ui-5-shots/u08-cards-ign-dark-1440.png differ diff --git a/docs/plans/miner-ui-5-shots/u09-settings-profile-light-1440.png b/docs/plans/miner-ui-5-shots/u09-settings-profile-light-1440.png new file mode 100644 index 000000000..44278ffc4 Binary files /dev/null and b/docs/plans/miner-ui-5-shots/u09-settings-profile-light-1440.png differ diff --git a/docs/plans/miner-ui-5-shots/u10-overview-firstblock-dark-390.png b/docs/plans/miner-ui-5-shots/u10-overview-firstblock-dark-390.png new file mode 100644 index 000000000..3e5963296 Binary files /dev/null and b/docs/plans/miner-ui-5-shots/u10-overview-firstblock-dark-390.png differ diff --git a/docs/plans/miner-ui-5-shots/u11-overview-firstwait-light-390.png b/docs/plans/miner-ui-5-shots/u11-overview-firstwait-light-390.png new file mode 100644 index 000000000..fb7c1900b Binary files /dev/null and b/docs/plans/miner-ui-5-shots/u11-overview-firstwait-light-390.png differ diff --git a/docs/plans/miner-ui-5-shots/u12-earnings-ladder-dark-390.png b/docs/plans/miner-ui-5-shots/u12-earnings-ladder-dark-390.png new file mode 100644 index 000000000..33d3441e7 Binary files /dev/null and b/docs/plans/miner-ui-5-shots/u12-earnings-ladder-dark-390.png differ diff --git a/docs/plans/miner-ui-5-shots/u13-earnings-ladder-light-390.png b/docs/plans/miner-ui-5-shots/u13-earnings-ladder-light-390.png new file mode 100644 index 000000000..e95b6d819 Binary files /dev/null and b/docs/plans/miner-ui-5-shots/u13-earnings-ladder-light-390.png differ diff --git a/docs/plans/miner-ui-5-shots/u14-overview-inspect-light-1440.png b/docs/plans/miner-ui-5-shots/u14-overview-inspect-light-1440.png new file mode 100644 index 000000000..d59213c72 Binary files /dev/null and b/docs/plans/miner-ui-5-shots/u14-overview-inspect-light-1440.png differ diff --git a/docs/plans/miner-ui-5.md b/docs/plans/miner-ui-5.md new file mode 100644 index 000000000..e23d2c415 --- /dev/null +++ b/docs/plans/miner-ui-5.md @@ -0,0 +1,96 @@ +# Igneum Miner UI 5: the ladder shown everywhere, the miner's first month + +7 October 2026, 10:1x to 11:xx UK. Mission item 6 (docs/analysis/mission/mission.md 2.6; the brief is +docs/analysis/mission/reinvent.md 1, 2, 3.2 to 3.7 and 7). Branch `miner-ui-5` from the miner-ui-4 tip 5d9c55a2 +(release-0.3.18, since renumbered 0.3.19), worktree `../igneum-wt-miner-ui-5`. Nothing published; the shipper cuts it. +The site lane (a4b202cabca2d95c0) owns `/live` and `/miners`; the node lane (a283f5f0d364ceef0) owns the RPC fields +listed in section 6. + +## 1. What is built + +| Part | Where | What | +|---|---|---| +| (a) The Poisson count-up | Overview, `#first-wait`; `View.poisson` | from the first job until the first block of this install: "A card like yours finds a block about every 1.6 hours on today's network. Chance so far: 31%." The gap is `/api/stats hashrate` over the fleet rate (`mining.hash_total`) at one block a second; the chance is `1 - e^(-elapsed / gap)` from the moment mining started this run. Over an 8-hour gap the pool line sits under it. The ring fills with the chance. Hover names the two fields and the formula. | +| (b) The block card | Overview, `#block-card`; `View.blockCard`; `src/ladder.rs` | raised by the engine on the first block of the install, every 100th, 1,000th and 10,000th, and the first block of a new card (`ladder.milestone`); in place, never a dialog; stays until dismissed (the key is stored, so a relaunch does not re-raise it). "Block 1,284,117 is yours." (the DAA score the node logged), the card and its rate and share, "4.88 IGN to 0xdd44…86E8 (72 producer points, 8 for signing, ramp 19%)", "rank 41 of 1,204 keys · day 23 of 30", the hash, Open in the explorer (`/block/`), Save the card, Copy the link. The hash joins the miner's `ACCEPTED block nonce=` line to the node's `PoW accepted … nonce` line by nonce (the node logs every block it validates). | +| Save the card | `drawCard` in app.js, `POST /api/card`, `src/card.rs`, `platform::reveal_file` | a 1200x630 PNG drawn on a canvas from the card's own words with the fonts the app ships (no network call): the mark, "Block N is yours", the card and rate, the IGN line, rank and day, the miner key and hash, the explorer URL. The miner's object, never the project's number: no network rate, no block count. The engine writes it under `/cards/` and reveals it in Finder or Explorer. `u00-block-card-1200x630.png` is the one the mock drew. | +| (c) Earnings in IGN first | Earnings, the money card; `View.earningsLines` | line 1 "7,680 IGN a day at your last hour's rate (4 blocks, 80.00 IGN each) · about 6,912 IGN expected at 100 MH/s" (measured first, the expectation beside it; the expectation alone before the first block); line 2 "2,592 blocks in 30 days, 207,360 IGN" from `getFinalityWeights keys[].blocks` at today's reward, with the shards; line 3 the balance (unchanged); line 4 the typed price: a £ per IGN the user types, kept in the page's storage, never fetched, "about £384 a day at £0.05 per IGN, your figure · no exchange lists IGN"; line 5 "your cards are 0.100% of the network · weight rank 41 of 1,204 keys · 23 of 30 days"; line 6 electricity unchanged plus "2,133 IGN per kWh"; the dev fee unchanged. Every number's `title` names its field. | +| The per-card line | Cards rows | an "IGN a day" cell per card from its rate, the network rate and the reward (hover: the fields) | +| (d) The ladder | Earnings `#ladder-card` (the rungs with their lines and hovers), Overview `#ladder-strip` (the seven chips and the current rung's line); `View.ladderRungs` | rungs: first block; your key has a vote; your signature is in checkpoint K; full window; rank by weight; signing streak; your card proved a shard. Every threshold is read from the node's `params` (`dust`, `weightWindow`, `presenceWindow`), never a constant: the devnet reads "5 blocks to a vote" and "2 of 2 hours", mainnet "100 blocks" and "30 of 30 days". The words, in copy law: "Your key has a vote." "Your signature is in checkpoint 184,220." "30 of 30 days. Full weight." "Rank 41 of 1,204 keys." "Signing 8 of 80 points, 41 days unbroken." "Your card proved shard 3 of block 1,284,117." | +| The chain facts | `GET /api/ladder`, `src/chainfacts.rs` | the node's `igneum_getFinalityWeights` on the EVM port first (OWED on the node, section 6), else the observer's `/api/live finality.weights` (the same reply relayed, keys cut to 64, ids as 8 hex) plus `/api/stats`; this machine's keys ranked by `blocks`; cached 10 s; the reply names its source and the dashboard says it ("through the observer" until the node answers). | +| The machine's record | `src/ladder.rs`, `/ladder.json`, `api/state.ladder` | first block (time, card, hash, DAA), blocks per UTC day (the days-mined ring), the checkpoints signed and which locked (`VOTE index=` and `LOCK checkpoint` lines), the signing streak (a gap over the presence window ends it), the paid shards (`src/prover.rs`), the milestone, the first-hour marks (node synced, card mining). | +| (e) The public profile opt-in | Settings "Make my page public"; `settings.profile_public`, `api/settings {profile_public}` | off by default; the words say what becomes public (key ids, blocks, rank, presence, card model). The site reads the switch through the app's existing report path (owed to the site lane; today the switch is stored and shown, nothing leaves the machine). | +| (f) The first-hour timeline | Earnings "Your first hour"; `View.timeline` | Installed (`settings.installed_at`), App started, Node synced (`ladder.first_synced_at`), Card mining (`ladder.first_mining_at`), First block, First payout (the coinbase of the first block), each as "+N min" from the install. | +| Prove | `#shard-card` | "Your card proved shard 3 of block 1,284,117." with the IGN, on the newest paid record | +| Activity | `EVENT_MAP` | "Your first block, found by RTX 4070", "Block 1,000 of this machine, found by …", "First block on …" | + +## 2. The chain scene (EMBER 02, taken from the site lane) + +the project lead's renderer pack (11:3x UK): `ui/live-dag.js` (sha256 582f2e73…, IgneumDag 2.0.0) and `ui/proof-core.js` (c2a094a6…, +IgneumProof 2.0.0) are byte-identical copies of the site-ui-4 files; the engine serves `proof-core.js` beside +`live-dag.js`. The Overview card mounts the compact mode (`compact: true, window: 60, poll: false`); Inspect, or a +click on a block, opens the full scene under it with the block inspector in the site's words (Proof in progress / +Proof complete / Checkpoint locked / Block observed; Proof shards, Inclusion, Miner key, Blue score, DAA score, +Parent links, Header time, Checkpoint, Finality; the note on separate states), the filter tabs (All blocks, Selected +chain, Your blocks), the window stepper, Follow and Pause. One owner of the feed: the page reads the engine's +`api/live?window=120` every 2 s and pushes the reply into both scenes; `mine` matches every vote key id of this +machine's cards (the 8 hex the feed names as `b.miner`), never the payout address. `--included` and `--excluded` are on +`:root` for both themes. The fallback strip (this machine's own blocks) draws after three failed reads. The legend +reads "Your blocks" as in the reference. + +## 3. Gate results + +| Gate | Result | +|---|---| +| A Devnet 2 key walks every rung on screen in a view test | `view.test.mjs` "a Devnet 2 key walks every rung on screen": key 6ad0e117 under the finality params the devnet node reports (`api/live params`, 7 Oct 2026: dust 5, weightWindow 7,200, presenceWindow 20; Devnet 2's override file sets none of them, so it runs the same values) goes nothing → first block → vote → signature in checkpoint 8,496 → 2 of 2 hours → rank 3 of 4 → 15 min unbroken → shard 3 of block 1,284,117; every rung's `field` matches `getFinalityWeights|getFinalityCheckpoints|igneum_getProofRecords|/api/stats|this app`. The mainnet-sized walk (100 blocks, 30 days, the observer's cap of 64) is the next test. | +| Every number names its RPC field on hover | `View.FIELDS` (23 sentences) in every `title`; the rungs, the Earnings lines, the block card lines, the Cards cell, the count-up | +| The PNG opens; no network call is made to make it | `u00-block-card-1200x630.png` drawn by the mock page through Playwright's chromium; the page's only calls while drawing are `document.fonts.load` of the app's own woff2 files | +| "First share within 10 minutes of download in 9 of 10 fresh Windows installs" | written as a runbook for the shipper, not run: `docs/plans/miner-ui-5-first-share-runbook.md` | +| Tests | UI 47 (42 before; the five new ones); the app crate on the box 190 + 27 + 8 (ladder 10, chainfacts 4, card 3 among them) | + +## 4. Captures (`docs/plans/miner-ui-5-shots/`, the ui-mock's scenarios firstwait, firstblock, ladder) + +`u00-block-card-1200x630.png` the saved card; `u01-overview-firstwait-dark-1440` the count-up and the strip; `u02`/`u03` +the first block's card, dark and light; `u04`/`u14` the full scene with a block in the inspector, dark and light; +`u05`/`u06` Earnings with the ladder and the timeline open; `u07` the shard card; `u08` the Cards row with IGN a day; +`u09` Settings with the profile switch; `u10` to `u13` the Overview and Earnings at 390, both themes. Captured through +Playwright's own chromium (never Google Chrome.app) against `tools/ui-mock/server.mjs 4319`. + +## 5. Owed by this lane, and what the site lane and the Discord lane take + +| What | Who | +|---|---| +| The Cards setup screen's "about N blocks a day" from the priors file (reinvent 3.2, Cards rows) | this lane, once the priors ship in the signed manifest (the file lives on the site today) | +| The QR of the explorer link on the saved card (reinvent 3.3) | this lane; the URL is printed in full instead | +| The opt-in reaching the site (the address page's noindex lifted for a key whose app switched it on) | the site lane and this lane together: the switch rides the app's existing report upload as `profile_public` | +| `/live` weight leaderboard and `/miners` census with the same words | the site lane; the field list and the rung words were sent to it (section 7) | +| `#first-blocks` posts and the Voter and Window roles | the Discord lane; the shapes are in `docs/community/discord/ladder.md`, nothing posted | +| Sound on a block | not built (verdict table: watch) | + +## 6. RPC fields the node does not expose yet (sent to the node lane) + +| Field | Why the app needs it | What the app does meanwhile | +|---|---|---| +| `igneum_getFinalityWeights` on the EVM JSON-RPC port (the wRPC `getFinalityWeights` reply as is) | the engine carries no wRPC client; today the facts come through the observer's relay, which cuts the table to 64 keys and so cannot rank a key below 64 | reads `/api/live finality.weights` and says "through the observer" on hover; "Below the top 64 keys" when the key is not listed | +| `igneum_getFinalityCheckpoints` the same way | the locked index and the certificate list from this machine's node | `/api/stats finality.latest_locked_index` | +| `getFinalityCheckpoints checkpoints[].signers` (the key hashes in the certificate bitmap), or a per-key `lastSignedLockedIndex` | "Your signature is in checkpoint K" as a chain fact | the app's own `VOTE index=` lines, read as locked once a `LOCK checkpoint` line reaches them; the hover says so | +| `getFinalityWeights keys[].daysMined` (distinct days with a blue block in the window) and `keys[].firstBlockDaa` | "30 of 30 days" as a chain fact; the Window role; the `/live` days-mined column | the app's own day ring (`ladder.json`), which only counts what this install saw | +| `getFinalityWeights keys[].streakDays` or `keys[].lastMissedDaa` | the signing streak as a chain fact | the app's own unbroken-vote reading; `participation` is shown beside it | +| `getFinalityWeights keys[].rank` or a `getFinalityKey {keyHash}` reply with blocks, voter, participation, rank, daysMined, streak | one call per machine instead of the whole table | the table sorted on the client | +| `igneum_getProofRecords` by key (the paid shards of a key over a range) | "your card proved shard N of block M" for records this install did not watch | `src/prover.rs` reports what it submitted and saw paid | + +## 7. Sent to the site lane (so `/live` and `/miners` match the app word for word) + +The rung names and lines of section 1 (d); the fields: `getFinalityWeights params.dust / weightWindow / presenceWindow`, +`keys[].blocks / voter / participation / strippedUntilDaa / pubkey`, `totalWeight`, `activeWeight`, `voters`, +`checkpointIndex`; `getFinalityCheckpoints latestLockedIndex / nextIndex / finalityActive`; `/api/stats hashrate`, +`block_reward.miner_ign`, `block_reward.ramp_factor`; the leaderboard column order (rank, key id, blocks in window, +days mined, presence, last block) with "weight, never hashrate: a card that arrived today sits at the bottom". + +## 8. Copy added (the copy law: no em dashes, no two-beat antithesis, no aphorisms; every line names a number or an action) + +"Waiting for your first block." "A card like yours finds a block about every 1.6 hours on today's network. Chance so +far: 31%." "Above an 8-hour gap a pool pays by the share, every minute. The pool setting arrives with pool-0." "Block +1,284,117 is yours." "Open in the explorer" "Save the card" "Copy the link" "Your key has a vote." "61 of 100 blocks to +a vote." "Your signature is in checkpoint 184,220." "30 of 30 days. Full weight." "Rank 41 of 1,204 keys." "Below the +top 64 keys." "Signing 8 of 80 points, 41 days unbroken." "Your card proved shard 3 of block 1,284,117." "Proving is +off." "Type a price" "Use it" "Make my page public" "Your first hour" "The ladder".