Merge master 51edbe9ae into tv-d02 under the master-landing lock
This commit is contained in:
commit
6267787bbc
41 changed files with 1607 additions and 36 deletions
|
|
@ -298,7 +298,7 @@ Pin: Leadership tests, first box (Ergo).
|
|||
|
||||
Status: Conceded (8 October 2026): no "number one" claim before comparative results and adoption exist.
|
||||
|
||||
Answer: No present-tense rank is served. Published claims name the evaluated release, evidence and boundary conditions. Designed to compete for leadership among GPU-first networks. That is the scoped wording until a ranking is measured (the Token Value volume’s rule VR-30, scoped claims only, 9 October 2026): an independently substantiated pass of the acceptance standard would not award a numerical rank, nor guarantee adoption, perpetual GPU profitability or the defeat of every future chip. The tests that would earn it are miners staying through hard conditions, customers repeatedly paying for proofs, and the network running without the founding team (D5); none is met yet.
|
||||
Answer: No present-tense rank is served. Published claims name the evaluated release, evidence and boundary conditions. Designed to compete for leadership among GPU-first networks. That is the scoped wording until a ranking is measured (the Token Value volume’s rule VR-30 and decision D06, scoped claims only, ratified 9 October 2026): an independently substantiated pass of the acceptance standard would not award a numerical rank, nor guarantee adoption, perpetual GPU profitability or the defeat of every future chip. The tests that would earn it are miners staying through hard conditions, customers repeatedly paying for proofs, and the network running without the founding team (D5); none is met yet.
|
||||
|
||||
Evidence: `docs/plans/igneum-2.0.md` (Leadership tests, second to fifth boxes).
|
||||
|
||||
|
|
|
|||
47
docs/ops/build-queue.md
Normal file
47
docs/ops/build-queue.md
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
# Build queue: the nine build boxes and their standing work
|
||||
|
||||
Set up 9 October 2026, 09:1x UK, on the order relayed by the coordinator: every box has one owner lane and a standing queue, a reader on
|
||||
build-1 reads this file every 30 minutes against the merged workers.json and reports an idle box as a fault. The live copy is
|
||||
build-1:/srv/queue/build-queue.md (the reader reads that one; this file is its source on master, landed through the gate).
|
||||
|
||||
## Rules that bind every entry
|
||||
|
||||
- Kill by recorded pid or pid file only, never by a name or a pattern (`pkill` and `killall` refuse on every box, exit 97;
|
||||
tools/ci/kill-by-name-check.sh reads the tree). Every job writes its pid file before it starts; a stop reads that file.
|
||||
- A box never builds for the fleet: fleet binaries come only from the cross-build kit (x86-64-v3, the ISA gate at 0 AVX-512 lines).
|
||||
- Nothing on the chain by hand; the devnet, hub-1 and every node are the node and fleet lanes' through their own harnesses.
|
||||
- An entry carries its owner lane, its box, its pid-file path and its clock (UK). A box with no live pid file from its queue and
|
||||
a load under 1.0 for a 30-minute read is a fault, reported by the reader to the coordinator (/srv/queue/faults.log).
|
||||
- A lane that finishes an entry replaces it with the next or hands the box back here with a line; an empty box is the fault.
|
||||
|
||||
## Owners (one lane per box)
|
||||
|
||||
| box | threads | owner lane | standing use |
|
||||
|---|---|---|---|
|
||||
| build-1 | 96 | build-server lane | cuts and kits, the hands (observer-node, node1), the capacity fuzz slices, the workers page, the queue reader |
|
||||
| build-2 | 96 | site lane | the site gate (Playwright), the scene-parity suites; spare slots for the node lane's suites |
|
||||
| build-3 | 32 | node lane | the long consensus fuzz and property suites (kaspa-consensus, kaspa-consensus-core) |
|
||||
| build-4 | 96 | adversary lane | the chip model (OpenROAD, kepler-formal): the 20 to 25 percent floorplan for the converged SPEF row |
|
||||
| build-5 | 32 vCPU | research lane | TV-02's two independent supply-replay implementations, CPU only |
|
||||
| build-6 | 32 vCPU | HEAL lane | the long p2p and exec property suites (kaspa-p2p-flows, igneum-exec) |
|
||||
| build-7 | 96 | node lane | the 2.0.3 flows items: their suites and known-failed tests; the heal-on harness |
|
||||
| build-8 | 96 | fleet lane | 2.0.3 kit canaries the moment a chain moves; the heal-off harness; the dn4 roll node |
|
||||
| build-9 | 96 | steward | the board's rows that need only a box (ZKP, EVM, VER fixtures), the pow fuzz on the side |
|
||||
|
||||
## Queue (first entries, 9 October 2026)
|
||||
|
||||
| # | entry | owner | box | pid file | clock (UK) |
|
||||
|---|---|---|---|---|---|
|
||||
| 1 | 2.0.3 flows items: the suites and the known-failed tests on release-2.0.3-node-k6 (bf60948a and after) | node lane | build-7 | /srv/queue/pids/build-7-node-flows.pid | from 09:30, continuous |
|
||||
| 2 | long fuzz and property suites, consensus (kaspa-consensus, kaspa-consensus-core) | node lane | build-3 | /srv/queue/pids/build-3-consensus-fuzz.pid | from 09:45, continuous |
|
||||
| 3 | long fuzz and property suites, exec and p2p (igneum-exec, kaspa-p2p-flows, kaspa-p2p-lib) | HEAL lane | build-6 | /srv/queue/pids/build-6-exec-p2p-fuzz.pid | from 09:45, continuous |
|
||||
| 4 | long fuzz and property suites, pow (kaspa-pow, igneum-pow mixer and scratch) | node lane | build-9 | /srv/queue/pids/build-9-pow-fuzz.pid | from 09:45, continuous |
|
||||
| 5 | TV-02: two independent supply-replay implementations, CPU only | research lane | build-5 | /srv/queue/pids/build-5-tv02-replay.pid | from 10:00, until both agree |
|
||||
| 6 | chip model: the 20 to 25 percent floorplan for the converged SPEF row (about four host-hours) | adversary lane | build-4 | /srv/queue/pids/build-4-floorplan.pid | running (OpenROAD 844081, kepler-formal 1797623), about 13:30 |
|
||||
| 7 | the board's rows that need only a box: ZKP, EVM and VER fixtures (the steward names them) | steward | build-9 | /srv/queue/pids/build-9-board-rows.pid | from 10:00, by row |
|
||||
| 8 | 2.0.3 kit canaries the moment a chain moves (the evidence kits under /srv/workers/fleet) | fleet lane | build-8 | /srv/queue/pids/build-8-kit-canary.pid | on the chain's move |
|
||||
| 9 | the site gate and the scene-parity suites | site lane | build-2 | /srv/queue/pids/build-2-site-gate.pid | on each landing |
|
||||
| 10 | cuts, kits, the hands, the capacity fuzz slices, the workers page, the queue reader | build-server lane | build-1 | /srv/queue/queue-reader.pid and the cut pid files under the cutter's scratch | continuous |
|
||||
|
||||
A lane starts its entry by writing its pid file (`<pid> <start UTC> <label>`, the format of the slot files) under /srv/queue/pids on
|
||||
build-1 (or on its own box, mirrored there by the lane) and ends it by removing the file and replacing the entry.
|
||||
File diff suppressed because one or more lines are too long
253
docs/plans/igneum-2.0-master/token-value/phase0/tv-04/README.md
Normal file
253
docs/plans/igneum-2.0-master/token-value/phase0/tv-04/README.md
Normal file
|
|
@ -0,0 +1,253 @@
|
|||
# TV-04, the security budget without price rescue (Token Value Phase 0)
|
||||
|
||||
Status: **NOT RUN**. Phase 0 lands documents and tests only; nothing activates. The independent panel reads this model; until it does, every verdict below reads NOT RUN, and the rows that wait on an unratified choice read BLOCKED. This document never writes PASS.
|
||||
|
||||
Every figure on this page and in the CSVs beside it is written by `tools/token-value/tv-04/tv04_budget.py` from `tools/token-value/tv-04/inputs.json`. No price figure appears anywhere in it (VR-04 and the never-published list); the minus-90-percent case is a 0.1x multiple of the 1x path.
|
||||
|
||||
## The gate
|
||||
|
||||
TV-04, Security budget without price rescue (the volume, p. 58; rules-and-gates.json). Setup: "Ratified reward/fee rules; role costs; horizons 1, 5, 10 and 20 years." Method: "Model falling issuance, fee volatility and .25x/1x/4x/10x revenue, zero external jobs and -90% price. Separate role receipts and funding." Pass words: "Approved viable scenarios fund minimum required roles without hidden issuance or assumed appreciation; failure regions stated. Collapse scenarios need safe behaviour, not universal profit." Evidence: "Reproducible cash-flow model, assumptions, independent review."
|
||||
|
||||
## Sources, by sha256
|
||||
|
||||
| Source | Path | sha256 |
|
||||
|---|---|---|
|
||||
| The volume's rules, gates and decisions | `docs/plans/igneum-2.0-master/token-value/rules-and-gates.json` | `10ce307329e1663dcb6dce849317c9276c19252de5f483e9ee06015fc77cbe3d` |
|
||||
| The volume | `docs/plans/igneum-2.0-master/token-value/igneum-2.0-token-value.pdf` | `b79d295c99d9cf0a121b62efdc6743e7282a0d2de33a98f6811616afcbcaeaee` |
|
||||
| The master (light edition in the tree) | `docs/plans/igneum-2.0-master/igneum-2.0-complete-master.pdf` | `f54f12117fd10ebcd1cad83b41342cf2a21ba7e0cf0abfa100d48b101b02b18b` |
|
||||
| The litepaper (the box mirror's master 6824d49c) | `site/litepaper.html` | `35ac65e151339089ef6ddeea3842b24d95e00d327a2b12faa9ea190ff85e463f` |
|
||||
| The node, release-2.0.2-node a284380b | `consensus/core/src/emission.rs` | `07b39c410222a43001c83dddbd85cff4a8a370184588dbc28ab48c8803964fbd` |
|
||||
| The node, release-2.0.2-node a284380b | `consensus/core/src/igneum.rs` | `6c859d4268e653978bfa07aaaad2dff304635b892255368cbbadecca3c35705f` |
|
||||
| The node, release-2.0.2-node a284380b | `consensus/core/src/config/params.rs` | `0c07ddcf0c5383255f1b0cfba54c6f637375b9a5b5514ab4b2affdad717e787f` |
|
||||
| The node, release-2.0.2-node a284380b | `consensus/core/src/fees.rs` | `5e7a319c0fc538a6960e18ee02d3c23a0f514cef27fff6f4fdaa727c484d3136` |
|
||||
| The node, release-2.0.2-node a284380b | `igneum/exec/src/config.rs` | `fdc4ba56109ddab4dadfe3d184247cf2cda8774dc5542337acaa38c8da716aaf` |
|
||||
| The node, release-2.0.2-node a284380b | `igneum/exec/src/executor.rs` | `ff12ef5fed88f1cd1d1449c6878a5acc0f7efe098abad7315791d59b5c5cc79c` |
|
||||
| The TV-01 supply spec | `docs/plans/igneum-2.0-master/token-value/phase0/tv-01/supply-spec.json` | not in the tree |
|
||||
|
||||
The supplied master original reads `c878ee4f80adf1da58fcc78fb91a8008de2e9fc44060bec143d020a780c5093e` in the volume's original_artifacts; the tree carries the light edition of the same substance. The TV-01 supply spec: not in the tree at generation; the node's code (release-2.0.2-node a284380b) is the source.
|
||||
|
||||
## The ratified rules this model applies
|
||||
|
||||
| Rule | As ratified (the founder, 9 October 2026, 09:2x UK) | What it does here |
|
||||
|---|---|---|
|
||||
| D01 | Capped issuance, subject to TV-04 | The schedule's tail is the cap; no row mints after the curve; the test fails on a tail mint. |
|
||||
| D02 | The same-cap emission comparison approved, the schedule pending evidence | Every figure is conditional on the node's current schedule (BLOCKED row B-08). |
|
||||
| D03 | Separate accountable budgets | Four roles, four budgets, never pooled; a role with no recurring payer is a BLOCKED row. |
|
||||
| D04 | Explicit routing; the external-job rate not ratified | Each receipt names its route and status; external jobs are zero and the published rate is a parameter only. |
|
||||
| D05 | Recovery never shown as finality | No row reads a contraction, a pause or a recovery path as finality; the model carries no finality figure (B-09). |
|
||||
| VR-05 | Fund necessary security (p. 50) | Miners, internal provers, minimum validators and maintenance modelled separately through declining issuance; no external sale funds any role. |
|
||||
| VR-04, VR-08 | No artificial return; separate value and money flows | No price, no appreciation, every coin in exactly one route, burns never a receipt. |
|
||||
| P12, P13 | The master, p. 68 | The revenue bands and the viable or collapse declaration (P12); committed maintenance only (P13). |
|
||||
|
||||
## Method
|
||||
|
||||
1. The schedule. The node's `EmissionSchedule::CURRENT` on the mainnet params (emission.rs lines 103 to 110; params.rs line 1858): 3,168,808,781 base units a DAA second at 8 decimals, a 2,592,000-second ramp from 10%, the rate halved every 63,115,200 DAA seconds, the tail the cap. Each year's emission is the node's closed-form scheduled supply at the year's end minus its start, in integers. The rate reaches zero after 32 halvings (64 years) and sums to 3,963,038,988 coins under the 4,000,000,000 cap. Per-block rounding (the per-block floor of the rate and the pool's floor) moves a year's figures by under 7 coins at up to ten blocks a second.
|
||||
2. The baseline. The whole year-1 subsidy, 963,038,999 coins (963038999.99163249), the ramp included. One BU is its purchasing power on the 1x path.
|
||||
3. The routing. Emission: 80% to the block's producer (miners), 20% to the proving pool (internal provers), nothing to validators or maintenance (igneum.rs lines 43 to 44, 85 to 88, 123 to 126; the signing bonus is off on the mainnet params, lines 1809 to 1810). Fees: the base fee of both gas dimensions burned in full; the tip 80% to the beneficiary and 20% to developers (exec config.rs lines 75 to 76). External jobs: zero; the published 90/10 is UNRATIFIED under D04 and enters no row.
|
||||
4. The scenarios. Multiples 0.1x (the minus-90-percent case), 0.25x, 1x, 4x and 10x of the baseline's purchasing power, each one constant over the whole horizon, so no row assumes appreciation. Native receipts are the same in every scenario; the multiple scales what they buy.
|
||||
5. The cost side. The volume gives no cost figure (p. 14 lists what counts as revenue; p. 31 the maintenance evidence) and the master gives stress grids, not role costs (p. 68, P12: tariffs, productive lives, development cases; p. 36: historical shard timings, not reproduced for this edition). So each role's minimum cost is a PANEL cell in BU, empty here. For each cell the model gives the fundable-cost ceiling, multiple x role receipts / baseline: a panel cost above it is the failure region.
|
||||
6. The verdict. In the gate's words: an approved viable scenario must fund the minimum required roles without hidden issuance or assumed appreciation, with failure regions stated; a collapse scenario needs safe behaviour, not universal profit. Which cells are viable and which are collapse cases is the panel's declaration before results (P12). Every cell reads NOT RUN, or BLOCKED where the role has no payer.
|
||||
7. Fee volatility. The tables carry zero tips (the subsidy alone). The fee-replacement table gives, year by year, the tip volume that would hold the miners' year-1 receipts at constant purchasing power through the code's 80% tip route. Tip timing and spikes (p. 14) are the panel's T-tip cell.
|
||||
|
||||
## The parameter table
|
||||
|
||||
Every cell's status: RATIFIED (the founder's ratification), IMPLEMENTED (the node's code, cited by line, taken under D04's explicit routing), UNRATIFIED (a parameter, never a result), PANEL (the independent panel fills it; empty here), BLOCKED (waits on a named choice). The full table with sources is `parameters.csv`.
|
||||
|
||||
| Id | Parameter | Value | Status |
|
||||
|---|---|---|---|
|
||||
| S-rate | launch rate | 3168808781 | IMPLEMENTED |
|
||||
| S-ramp | launch ramp | 2592000 s from 10% | IMPLEMENTED |
|
||||
| S-step | decay step | 63115200 s, rate divided by 2 | IMPLEMENTED |
|
||||
| S-tail | tail | cap | RATIFIED (D01) and IMPLEMENTED |
|
||||
| S-cap | cap | 4000000000 | RATIFIED (D01) and IMPLEMENTED |
|
||||
| R1-miner | emission, producer share | 80% | IMPLEMENTED |
|
||||
| R1-pool | emission, proving pool share | 20% | IMPLEMENTED |
|
||||
| R1-validators | emission to minimum validators | 0% | IMPLEMENTED |
|
||||
| R1-maintenance | emission to maintenance | 0% | IMPLEMENTED |
|
||||
| R2-base | base fee, both gas dimensions | 100% | IMPLEMENTED |
|
||||
| R3-tip-miner | priority fee (tip), beneficiary share | 80% | IMPLEMENTED |
|
||||
| R3-tip-dev | priority fee (tip), developer share | 20% | IMPLEMENTED |
|
||||
| R3-tip-provers | priority fee (tip), provers' part | 0% | **BLOCKED** |
|
||||
| R4-external-launch | external job at launch (customer's chain) | not used (zero) | **UNRATIFIED** |
|
||||
| R5-external-bridge | external job after the proof bridge | not used (zero) | **UNRATIFIED** |
|
||||
| R6-devfee | the official miner client's optional dev fee | not used (zero) | **UNRATIFIED** |
|
||||
| m010 | scenario multiple | 0.10 | RATIFIED (TV-04 method words) |
|
||||
| m025 | scenario multiple | 0.25 | RATIFIED (TV-04 method words) |
|
||||
| m100 | scenario multiple | 1.00 | RATIFIED (TV-04 method words) |
|
||||
| m400 | scenario multiple | 4.00 | RATIFIED (TV-04 method words) |
|
||||
| m1000 | scenario multiple | 10.00 | RATIFIED (TV-04 method words) |
|
||||
| X-ext | external jobs per year | 0 | **UNRATIFIED (D04)** |
|
||||
| C-miners | minimum required miner cost per year | (empty) | **PANEL** |
|
||||
| C-provers | minimum required internal proving cost per year | (empty) | **PANEL** |
|
||||
| C-validators | minimum required validator cost per year | (empty) | **PANEL** |
|
||||
| C-maintenance | minimum required maintenance cost per year | (empty) | **PANEL** |
|
||||
| K-class | which scenario-year cells are approved viable and which are collapse cases | (empty) | **PANEL** |
|
||||
| T-tip | native tip volume per year (fee level and its volatility) | (empty) | **PANEL** |
|
||||
|
||||
## Horizon: year 1
|
||||
|
||||
The budget each role receives in year 1 (zero tips, zero external jobs), and the fundable-cost ceiling in BU at each multiple.
|
||||
|
||||
| Role | Route (status) | Receipts in year 1 (coins) | Of the role's year 1 | Years 1 to 1 (coins) | Ceiling at 0.1x | Ceiling at 0.25x | Ceiling at 1x | Ceiling at 4x | Ceiling at 10x | Panel cost | Decision |
|
||||
|---|---|---|---|---|---|---|---|---|---|---|---|
|
||||
| miners | R1-miner (IMPLEMENTED) | 770,431,199 | 100.00% | 770,431,199 | 0.080000 | 0.200000 | 0.800000 | 3.200000 | 8.000000 | (empty) | NOT RUN |
|
||||
| internal provers | R1-pool (IMPLEMENTED) | 192,607,799 | 100.00% | 192,607,799 | 0.020000 | 0.050000 | 0.200000 | 0.800000 | 2.000000 | (empty) | NOT RUN |
|
||||
| minimum validators | R1-validators (IMPLEMENTED) | 0 | none (no route) | 0 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | (empty) | BLOCKED |
|
||||
| maintenance | R1-maintenance (IMPLEMENTED) | 0 | none (no route) | 0 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | (empty) | BLOCKED |
|
||||
| external jobs | R4, R5 (UNRATIFIED) | 0 | none | 0 | 0 | 0 | 0 | 0 | 0 | (not used) | parameter only |
|
||||
|
||||
What each row means:
|
||||
|
||||
- miners: the role's year-1 budget buys at most 0.080000 BU in the minus-90-percent case, 0.800000 BU at 1x and 8.000000 BU at 10x, so a panel minimum cost above the cell's ceiling is the failure region for that scenario.
|
||||
- internal provers: the role's year-1 budget buys at most 0.020000 BU in the minus-90-percent case, 0.200000 BU at 1x and 2.000000 BU at 10x, so a panel minimum cost above the cell's ceiling is the failure region for that scenario.
|
||||
- minimum validators: the protocol pays this role nothing in year 1 at any multiple, so it is funded only by a payer D03 has not yet named (B-03, B-04), and any positive minimum cost is in the failure region.
|
||||
- maintenance: the protocol pays this role nothing in year 1 at any multiple, so it is funded only by a payer D03 has not yet named (B-03, B-04), and any positive minimum cost is in the failure region.
|
||||
- external jobs: zero in every scenario by the method; the published rate is unratified (D04) and funds no role here.
|
||||
|
||||
## Horizon: year 5
|
||||
|
||||
The budget each role receives in year 5 (zero tips, zero external jobs), and the fundable-cost ceiling in BU at each multiple.
|
||||
|
||||
| Role | Route (status) | Receipts in year 5 (coins) | Of the role's year 1 | Years 1 to 5 (coins) | Ceiling at 0.1x | Ceiling at 0.25x | Ceiling at 1x | Ceiling at 4x | Ceiling at 10x | Panel cost | Decision |
|
||||
|---|---|---|---|---|---|---|---|---|---|---|---|
|
||||
| miners | R1-miner (IMPLEMENTED) | 199,999,999 | 25.96% | 2,570,431,199 | 0.020768 | 0.051919 | 0.207676 | 0.830704 | 2.076759 | (empty) | NOT RUN |
|
||||
| internal provers | R1-pool (IMPLEMENTED) | 49,999,999 | 25.96% | 642,607,799 | 0.005192 | 0.012980 | 0.051919 | 0.207676 | 0.519190 | (empty) | NOT RUN |
|
||||
| minimum validators | R1-validators (IMPLEMENTED) | 0 | none (no route) | 0 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | (empty) | BLOCKED |
|
||||
| maintenance | R1-maintenance (IMPLEMENTED) | 0 | none (no route) | 0 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | (empty) | BLOCKED |
|
||||
| external jobs | R4, R5 (UNRATIFIED) | 0 | none | 0 | 0 | 0 | 0 | 0 | 0 | (not used) | parameter only |
|
||||
|
||||
What each row means:
|
||||
|
||||
- miners: the role's year-5 budget buys at most 0.020768 BU in the minus-90-percent case, 0.207676 BU at 1x and 2.076759 BU at 10x, so a panel minimum cost above the cell's ceiling is the failure region for that scenario.
|
||||
- internal provers: the role's year-5 budget buys at most 0.005192 BU in the minus-90-percent case, 0.051919 BU at 1x and 0.519190 BU at 10x, so a panel minimum cost above the cell's ceiling is the failure region for that scenario.
|
||||
- minimum validators: the protocol pays this role nothing in year 5 at any multiple, so it is funded only by a payer D03 has not yet named (B-03, B-04), and any positive minimum cost is in the failure region.
|
||||
- maintenance: the protocol pays this role nothing in year 5 at any multiple, so it is funded only by a payer D03 has not yet named (B-03, B-04), and any positive minimum cost is in the failure region.
|
||||
- external jobs: zero in every scenario by the method; the published rate is unratified (D04) and funds no role here.
|
||||
|
||||
## Horizon: year 10
|
||||
|
||||
The budget each role receives in year 10 (zero tips, zero external jobs), and the fundable-cost ceiling in BU at each multiple.
|
||||
|
||||
| Role | Route (status) | Receipts in year 10 (coins) | Of the role's year 1 | Years 1 to 10 (coins) | Ceiling at 0.1x | Ceiling at 0.25x | Ceiling at 1x | Ceiling at 4x | Ceiling at 10x | Panel cost | Decision |
|
||||
|---|---|---|---|---|---|---|---|---|---|---|---|
|
||||
| miners | R1-miner (IMPLEMENTED) | 49,999,999 | 6.49% | 3,070,431,198 | 0.005192 | 0.012980 | 0.051919 | 0.207676 | 0.519190 | (empty) | NOT RUN |
|
||||
| internal provers | R1-pool (IMPLEMENTED) | 12,499,999 | 6.49% | 767,607,799 | 0.001298 | 0.003245 | 0.012980 | 0.051919 | 0.129797 | (empty) | NOT RUN |
|
||||
| minimum validators | R1-validators (IMPLEMENTED) | 0 | none (no route) | 0 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | (empty) | BLOCKED |
|
||||
| maintenance | R1-maintenance (IMPLEMENTED) | 0 | none (no route) | 0 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | (empty) | BLOCKED |
|
||||
| external jobs | R4, R5 (UNRATIFIED) | 0 | none | 0 | 0 | 0 | 0 | 0 | 0 | (not used) | parameter only |
|
||||
|
||||
What each row means:
|
||||
|
||||
- miners: the role's year-10 budget buys at most 0.005192 BU in the minus-90-percent case, 0.051919 BU at 1x and 0.519190 BU at 10x, so a panel minimum cost above the cell's ceiling is the failure region for that scenario.
|
||||
- internal provers: the role's year-10 budget buys at most 0.001298 BU in the minus-90-percent case, 0.012980 BU at 1x and 0.129797 BU at 10x, so a panel minimum cost above the cell's ceiling is the failure region for that scenario.
|
||||
- minimum validators: the protocol pays this role nothing in year 10 at any multiple, so it is funded only by a payer D03 has not yet named (B-03, B-04), and any positive minimum cost is in the failure region.
|
||||
- maintenance: the protocol pays this role nothing in year 10 at any multiple, so it is funded only by a payer D03 has not yet named (B-03, B-04), and any positive minimum cost is in the failure region.
|
||||
- external jobs: zero in every scenario by the method; the published rate is unratified (D04) and funds no role here.
|
||||
|
||||
## Horizon: year 20
|
||||
|
||||
The budget each role receives in year 20 (zero tips, zero external jobs), and the fundable-cost ceiling in BU at each multiple.
|
||||
|
||||
| Role | Route (status) | Receipts in year 20 (coins) | Of the role's year 1 | Years 1 to 20 (coins) | Ceiling at 0.1x | Ceiling at 0.25x | Ceiling at 1x | Ceiling at 4x | Ceiling at 10x | Panel cost | Decision |
|
||||
|---|---|---|---|---|---|---|---|---|---|---|---|
|
||||
| miners | R1-miner (IMPLEMENTED) | 1,562,499 | 0.20% | 3,167,306,197 | 0.000162 | 0.000406 | 0.001622 | 0.006490 | 0.016225 | (empty) | NOT RUN |
|
||||
| internal provers | R1-pool (IMPLEMENTED) | 390,624 | 0.20% | 791,826,549 | 0.000041 | 0.000101 | 0.000406 | 0.001622 | 0.004056 | (empty) | NOT RUN |
|
||||
| minimum validators | R1-validators (IMPLEMENTED) | 0 | none (no route) | 0 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | (empty) | BLOCKED |
|
||||
| maintenance | R1-maintenance (IMPLEMENTED) | 0 | none (no route) | 0 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | (empty) | BLOCKED |
|
||||
| external jobs | R4, R5 (UNRATIFIED) | 0 | none | 0 | 0 | 0 | 0 | 0 | 0 | (not used) | parameter only |
|
||||
|
||||
What each row means:
|
||||
|
||||
- miners: the role's year-20 budget buys at most 0.000162 BU in the minus-90-percent case, 0.001622 BU at 1x and 0.016225 BU at 10x, so a panel minimum cost above the cell's ceiling is the failure region for that scenario.
|
||||
- internal provers: the role's year-20 budget buys at most 0.000041 BU in the minus-90-percent case, 0.000406 BU at 1x and 0.004056 BU at 10x, so a panel minimum cost above the cell's ceiling is the failure region for that scenario.
|
||||
- minimum validators: the protocol pays this role nothing in year 20 at any multiple, so it is funded only by a payer D03 has not yet named (B-03, B-04), and any positive minimum cost is in the failure region.
|
||||
- maintenance: the protocol pays this role nothing in year 20 at any multiple, so it is funded only by a payer D03 has not yet named (B-03, B-04), and any positive minimum cost is in the failure region.
|
||||
- external jobs: zero in every scenario by the method; the published rate is unratified (D04) and funds no role here.
|
||||
|
||||
## The verdict per scenario and year
|
||||
|
||||
In the gate's words. The class of each cell (approved viable, or collapse) is the panel's declaration before results; the computed ceilings stand beside it. The failure region of a cell is every role whose minimum cost exceeds its ceiling, and minimum validators and maintenance at any positive cost.
|
||||
|
||||
| Year | Scenario | Miners' ceiling (BU) | Internal provers' ceiling (BU) | Validators, maintenance | Class (panel) | Gate test that applies | Verdict |
|
||||
|---|---|---|---|---|---|---|---|
|
||||
| 1 | 0.1x: the minus-90-percent case, the 1x path at one tenth | 0.080000 | 0.020000 | 0 (no payer, BLOCKED) | (empty) | viable: funds the minimum required roles without hidden issuance or assumed appreciation; collapse: safe behaviour, not universal profit | NOT RUN |
|
||||
| 1 | 0.25x | 0.200000 | 0.050000 | 0 (no payer, BLOCKED) | (empty) | viable: funds the minimum required roles without hidden issuance or assumed appreciation; collapse: safe behaviour, not universal profit | NOT RUN |
|
||||
| 1 | 1x (the baseline path) | 0.800000 | 0.200000 | 0 (no payer, BLOCKED) | (empty) | viable: funds the minimum required roles without hidden issuance or assumed appreciation; collapse: safe behaviour, not universal profit | NOT RUN |
|
||||
| 1 | 4x | 3.200000 | 0.800000 | 0 (no payer, BLOCKED) | (empty) | viable: funds the minimum required roles without hidden issuance or assumed appreciation; collapse: safe behaviour, not universal profit | NOT RUN |
|
||||
| 1 | 10x | 8.000000 | 2.000000 | 0 (no payer, BLOCKED) | (empty) | viable: funds the minimum required roles without hidden issuance or assumed appreciation; collapse: safe behaviour, not universal profit | NOT RUN |
|
||||
| 5 | 0.1x: the minus-90-percent case, the 1x path at one tenth | 0.020768 | 0.005192 | 0 (no payer, BLOCKED) | (empty) | viable: funds the minimum required roles without hidden issuance or assumed appreciation; collapse: safe behaviour, not universal profit | NOT RUN |
|
||||
| 5 | 0.25x | 0.051919 | 0.012980 | 0 (no payer, BLOCKED) | (empty) | viable: funds the minimum required roles without hidden issuance or assumed appreciation; collapse: safe behaviour, not universal profit | NOT RUN |
|
||||
| 5 | 1x (the baseline path) | 0.207676 | 0.051919 | 0 (no payer, BLOCKED) | (empty) | viable: funds the minimum required roles without hidden issuance or assumed appreciation; collapse: safe behaviour, not universal profit | NOT RUN |
|
||||
| 5 | 4x | 0.830704 | 0.207676 | 0 (no payer, BLOCKED) | (empty) | viable: funds the minimum required roles without hidden issuance or assumed appreciation; collapse: safe behaviour, not universal profit | NOT RUN |
|
||||
| 5 | 10x | 2.076759 | 0.519190 | 0 (no payer, BLOCKED) | (empty) | viable: funds the minimum required roles without hidden issuance or assumed appreciation; collapse: safe behaviour, not universal profit | NOT RUN |
|
||||
| 10 | 0.1x: the minus-90-percent case, the 1x path at one tenth | 0.005192 | 0.001298 | 0 (no payer, BLOCKED) | (empty) | viable: funds the minimum required roles without hidden issuance or assumed appreciation; collapse: safe behaviour, not universal profit | NOT RUN |
|
||||
| 10 | 0.25x | 0.012980 | 0.003245 | 0 (no payer, BLOCKED) | (empty) | viable: funds the minimum required roles without hidden issuance or assumed appreciation; collapse: safe behaviour, not universal profit | NOT RUN |
|
||||
| 10 | 1x (the baseline path) | 0.051919 | 0.012980 | 0 (no payer, BLOCKED) | (empty) | viable: funds the minimum required roles without hidden issuance or assumed appreciation; collapse: safe behaviour, not universal profit | NOT RUN |
|
||||
| 10 | 4x | 0.207676 | 0.051919 | 0 (no payer, BLOCKED) | (empty) | viable: funds the minimum required roles without hidden issuance or assumed appreciation; collapse: safe behaviour, not universal profit | NOT RUN |
|
||||
| 10 | 10x | 0.519190 | 0.129797 | 0 (no payer, BLOCKED) | (empty) | viable: funds the minimum required roles without hidden issuance or assumed appreciation; collapse: safe behaviour, not universal profit | NOT RUN |
|
||||
| 20 | 0.1x: the minus-90-percent case, the 1x path at one tenth | 0.000162 | 0.000041 | 0 (no payer, BLOCKED) | (empty) | viable: funds the minimum required roles without hidden issuance or assumed appreciation; collapse: safe behaviour, not universal profit | NOT RUN |
|
||||
| 20 | 0.25x | 0.000406 | 0.000101 | 0 (no payer, BLOCKED) | (empty) | viable: funds the minimum required roles without hidden issuance or assumed appreciation; collapse: safe behaviour, not universal profit | NOT RUN |
|
||||
| 20 | 1x (the baseline path) | 0.001622 | 0.000406 | 0 (no payer, BLOCKED) | (empty) | viable: funds the minimum required roles without hidden issuance or assumed appreciation; collapse: safe behaviour, not universal profit | NOT RUN |
|
||||
| 20 | 4x | 0.006490 | 0.001622 | 0 (no payer, BLOCKED) | (empty) | viable: funds the minimum required roles without hidden issuance or assumed appreciation; collapse: safe behaviour, not universal profit | NOT RUN |
|
||||
| 20 | 10x | 0.016225 | 0.004056 | 0 (no payer, BLOCKED) | (empty) | viable: funds the minimum required roles without hidden issuance or assumed appreciation; collapse: safe behaviour, not universal profit | NOT RUN |
|
||||
|
||||
## Fee replacement: the tips the miners' year-1 budget would need
|
||||
|
||||
Tips per year, at constant purchasing power, that would bring the miners' receipts back to their year-1 level through the code's 80% tip route (year 2 pays more than the ramped year 1, so it needs none). Base fees are burned and restore nothing; provers have no tip route in the code (B-01). The full series is `fee-replacement.csv`.
|
||||
|
||||
| Year | Miners' gap to year 1 (coins) | Tips needed per year (coins) | As a fraction of the baseline |
|
||||
|---|---|---|---|
|
||||
| 1 | 0 | 0 | 0.0000 |
|
||||
| 2 | 0 | 0 | 0.0000 |
|
||||
| 3 | 370,431,200 | 463,039,000 | 0.4808 |
|
||||
| 5 | 570,431,200 | 713,039,000 | 0.7404 |
|
||||
| 10 | 720,431,200 | 900,539,000 | 0.9351 |
|
||||
| 20 | 768,868,700 | 961,085,875 | 0.9980 |
|
||||
|
||||
## What the result means
|
||||
|
||||
Under the ratified cap with zero external jobs, the subsidy that pays the miners and the internal provers falls to 25.96% of year 1 in year 5, 6.49% in year 10 and 0.20% in year 20; at 10x purchasing power the year-20 miner budget buys 0.016225 BU, and in the minus-90-percent case 0.000162 BU.
|
||||
Holding the miners' year-1 budget needs tips of 0.9351 of the baseline a year by year 10 and 0.9980 by year 20; the internal provers have no fee route in the node's code, so nothing in the ratified routing replaces their declining 20%; minimum validators and maintenance receive nothing from the protocol at any horizon.
|
||||
So whether TV-04 can pass turns on four things this model cannot supply: the panel's role costs and viable-or-collapse declarations, the tip level, a named payer for validators and maintenance, and the provers' fee route. Those are the BLOCKED rows below.
|
||||
|
||||
## BLOCKED rows
|
||||
|
||||
| Id | Row | Waits on | Earliest clock (UK) |
|
||||
|---|---|---|---|
|
||||
| B-01 | the internal provers' share of the priority fee | D04's frozen routes (TV-01): the node's code pays the 80% tip share to the block's beneficiary alone (igneum/exec executor.rs lines 318 to 329, line 729), the litepaper's routing table row 3 and the design text read '80% the block's miner and provers' with no split; the master, p. 36, asks for the discrepancy resolved before security income is modelled | the TV-01 supply spec, due 13:00 UK today; the node lane names where the rule lives |
|
||||
| B-02 | internal provers: paid against assigned | the stranded-credit rule (the litepaper: unclaimed pool credit stays in the escrow, the fix is designed) and the single coinbase payout that replaces the devnet's burn of the 20% output; this table carries the assigned 20%, an upper bound on what provers are paid | the node lane's answer; TV-02's replay separates assigned, paid and burned |
|
||||
| B-03 | minimum validators: the recurring payer | D03 (ratified: separate accountable budgets) names no payer for the minimum validator role; the protocol routes it nothing (no coinbase output, no fee share) | the panel and the founder; no clock in the ratified rules |
|
||||
| B-04 | maintenance: committed resources | the master, p. 68, P13 (at least 12 months committed; burned fees, rising prices and uncommitted sales excluded) and the volume, p. 31; the registry's P13 deferral note (the founder, 8 October 2026, 18:2x UK); the protocol routes maintenance nothing | the founder's lifting of the P13 deferral |
|
||||
| B-05 | role costs (four cells) and the scenario classes | the independent panel: the minimum required cost per role per year in BU, and which scenario-year cells are approved viable and which are collapse cases, declared before results (the master, p. 68, P12) | the panel's reading; every coverage cell reads NOT RUN until then |
|
||||
| B-06 | the tail-vote clause beside the cap | D01 (ratified: capped issuance) against the litepaper's clause sending a tail reward to the miners' vote when external proving revenue is under one fifth of the subsidy after year 5 (with zero external jobs that condition holds from year 5 in every scenario here); the volume, p. 12: no undisclosed future rescue. This model mints no tail | TV-01's frozen contract (13:00 UK today) and the site lane's wording |
|
||||
| B-07 | the testnet parameters' 1% tail | params.rs line 2014: TESTNET_PARAMS carries EmissionSchedule::TESTNET_1 (emission.rs lines 116 to 123, a 1 percent a year tail), while MAINNET_PARAMS carries the capped CURRENT (line 1858); this model reads the mainnet params; the node lane answers which schedule a value-bearing network carries | the node lane's one-question answer |
|
||||
| B-08 | the schedule itself | D02 (approved: the same-cap comparison; the schedule pending evidence): every figure here is conditional on EmissionSchedule::CURRENT and regenerates from inputs.json if the schedule changes | TV-03's emission comparison |
|
||||
| B-09 | safe behaviour in the collapse cases | the gate's words for collapse scenarios (safe behaviour, not universal profit) are native evidence this model cannot give: contraction of the finality vote weight, honest pauses and recovery labelled apart from finality (D05) belong to TV-07, TV-09 and TV-15 | those gates' native runs |
|
||||
|
||||
## Files
|
||||
|
||||
| File | What | sha256 |
|
||||
|---|---|---|
|
||||
| `blocked.csv` | the BLOCKED rows | `525723db53c072a4f7f0fec6301bd6f931fd8f905c2fa0ba719de6f6c24a95bd` |
|
||||
| `budget.csv` | every horizon x scenario x role row, with its meaning | `06f467bed99df956a3d2c9d52dbe98ae4ffc13cb59e007ea5f982c77264b69d1` |
|
||||
| `emission.csv` | the schedule and the role split, years 1 to 20 | `e0f30dba6489a9c59dfa2acc4d070aad04f273811ea4c1064efa1c5a9d8f835c` |
|
||||
| `fee-replacement.csv` | the tips the miners' year-1 budget would need, years 1 to 20 | `6da376136be6be9769c817b90cd8b7cc60ca9f7720b30ca600fd93bbea07f5d0` |
|
||||
| `parameters.csv` | every parameter with its status and source | `20b548ea79c05396afc460db41b5a5f7062e8a10f781fe11863204259dedb7a5` |
|
||||
|
||||
## Reproduce
|
||||
|
||||
The generator `tools/token-value/tv-04/tv04_budget.py` (sha256 `72c775cb85a809b39f305f7b1c83f26b32e8fd113340ac7ac8dc32b3e6260282`), its inputs `tools/token-value/tv-04/inputs.json` (sha256 `ca40b0e9686422cfb8506add4e4202f04863f890c9440eb82e739aff9fb06e88`) and its tests `tools/token-value/tv-04/test_tv04.py` (sha256 `88dae13438cd551d1a1f94631efb515315f453179f14e9a2add440bf58e6ef26`). Standard-library Python 3, integers and fractions, no clock, no network.
|
||||
|
||||
```
|
||||
python3 tools/token-value/tv-04/tv04_budget.py --out docs/plans/igneum-2.0-master/token-value/phase0/tv-04
|
||||
python3 tools/token-value/tv-04/tv04_budget.py --check docs/plans/igneum-2.0-master/token-value/phase0/tv-04
|
||||
python3 tools/token-value/tv-04/test_tv04.py
|
||||
python3 tools/token-value/tv-04/test_tv04.py --known-failed
|
||||
tools/token-value/tv-04/run-on-box.sh red|green|known-failed|generate|check
|
||||
```
|
||||
|
||||
Runs happen on build-9 only (`run-on-box.sh`: the committed tree as a git archive, a pid file at build-9:/home/build/tv-04/run.pid before the job starts, mirrored on build-1's queue while live). The run record (the known-failed first run, the green run, the mutant run, the two-generation byte comparison and the check against the committed files) is `RUNS.md` beside this file.
|
||||
|
||||
## Registry
|
||||
|
||||
The registry batch for TV-04 is `registry-batch-tv-04.json` beside this file: one cell, the case TV-04, the verdict NOT RUN, method model, this directory's files and the build-9 run logs as its evidence. The CI steward places it under `tools/ci/batches/` with its map cell and records it through `tools/ci/test-record.mjs --record`; this landing writes no registry row.
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
# TV-04 run record (build-9, 9 October 2026)
|
||||
|
||||
Every run went through `tools/token-value/tv-04/run-on-box.sh` on build-9 (the build user): the committed tree at the named commit as a git archive, the job's pid written to build-9:/home/build/tv-04/run.pid before it started and mirrored at build-1:/srv/queue/pids/build-9-tv04.pid while live, both removed at its end. Nothing ran on the Mac. Times are UTC.
|
||||
|
||||
| Start (UTC) | Commit | Mode | Result line | Exit | Log (build-9) | Log sha256 |
|
||||
|---|---|---|---|---|---|---|
|
||||
| 08:15:47 | ea14c332 | red: the tests before the generator existed | `ModuleNotFoundError: No module named 'tv04_budget'` | 1 | /home/build/tv-04/runs/ea14c332-red/run.log | `632b432d40d2b425fcc37957b46eeb111c05655c6dba8ddbc90f559fe136b2fc` |
|
||||
| 08:20:23 | d59a9088 | green | `RESULT tv04 green all properties hold 9/9` | 0 | /home/build/tv-04/runs/d59a9088-green/run.log | `ffaf77d442c440a3ed380b5307967c0ed9b8736a1bd91d634675a2da2cd42ee5` |
|
||||
| 08:20:29 | d59a9088 | known-failed: five mutants | `RESULT tv04 known-failed every mutant caught 5/5` | 0 | /home/build/tv-04/runs/d59a9088-known-failed/run.log | `779764ab03e17b2b2344d9c3e5064253eb4f25a319352b9205a044032cccd7cf` |
|
||||
| 08:20:36 | d59a9088 | generate, twice, compared | `RESULT tv04 regeneration byte-identical` | 0 | /home/build/tv-04/runs/d59a9088-generate/run.log | `08c98508fd392d599e5bb4d64e8a48e2926d53debcefa3378ac6f7f144726a3d` |
|
||||
| 08:21:07 | 1ba62f76 | check: the committed files against a fresh generation | `RESULT tv04 check committed outputs equal a fresh generation (6/6)` | 0 | /home/build/tv-04/runs/1ba62f76-check/run.log | `19309964cf7b23695dfd2a8af346af338ead042f7b5b69fd3365891de91cf33c` |
|
||||
|
||||
The five mutants, each caught by the property it breaks: a fixed tail after the curve (no hidden issuance, D01), a multiple that rises 10 percent a year (no assumed appreciation), external-job income in a result row (D04), a currency figure in the README (VR-04), burned fees counted as a role receipt (VR-08). The earlier commits 52c51322 ran the same green, mutant and generation modes before the year-2 clamp and the six-decimal ceilings.
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
id,row,waits_on,earliest_clock_uk
|
||||
B-01,the internal provers' share of the priority fee,"D04's frozen routes (TV-01): the node's code pays the 80% tip share to the block's beneficiary alone (igneum/exec executor.rs lines 318 to 329, line 729), the litepaper's routing table row 3 and the design text read '80% the block's miner and provers' with no split; the master, p. 36, asks for the discrepancy resolved before security income is modelled","the TV-01 supply spec, due 13:00 UK today; the node lane names where the rule lives"
|
||||
B-02,internal provers: paid against assigned,"the stranded-credit rule (the litepaper: unclaimed pool credit stays in the escrow, the fix is designed) and the single coinbase payout that replaces the devnet's burn of the 20% output; this table carries the assigned 20%, an upper bound on what provers are paid","the node lane's answer; TV-02's replay separates assigned, paid and burned"
|
||||
B-03,minimum validators: the recurring payer,"D03 (ratified: separate accountable budgets) names no payer for the minimum validator role; the protocol routes it nothing (no coinbase output, no fee share)",the panel and the founder; no clock in the ratified rules
|
||||
B-04,maintenance: committed resources,"the master, p. 68, P13 (at least 12 months committed; burned fees, rising prices and uncommitted sales excluded) and the volume, p. 31; the registry's P13 deferral note (the founder, 8 October 2026, 18:2x UK); the protocol routes maintenance nothing",the founder's lifting of the P13 deferral
|
||||
B-05,role costs (four cells) and the scenario classes,"the independent panel: the minimum required cost per role per year in BU, and which scenario-year cells are approved viable and which are collapse cases, declared before results (the master, p. 68, P12)",the panel's reading; every coverage cell reads NOT RUN until then
|
||||
B-06,the tail-vote clause beside the cap,"D01 (ratified: capped issuance) against the litepaper's clause sending a tail reward to the miners' vote when external proving revenue is under one fifth of the subsidy after year 5 (with zero external jobs that condition holds from year 5 in every scenario here); the volume, p. 12: no undisclosed future rescue. This model mints no tail",TV-01's frozen contract (13:00 UK today) and the site lane's wording
|
||||
B-07,the testnet parameters' 1% tail,"params.rs line 2014: TESTNET_PARAMS carries EmissionSchedule::TESTNET_1 (emission.rs lines 116 to 123, a 1 percent a year tail), while MAINNET_PARAMS carries the capped CURRENT (line 1858); this model reads the mainnet params; the node lane answers which schedule a value-bearing network carries",the node lane's one-question answer
|
||||
B-08,the schedule itself,D02 (approved: the same-cap comparison; the schedule pending evidence): every figure here is conditional on EmissionSchedule::CURRENT and regenerates from inputs.json if the schedule changes,TV-03's emission comparison
|
||||
B-09,safe behaviour in the collapse cases,"the gate's words for collapse scenarios (safe behaviour, not universal profit) are native evidence this model cannot give: contraction of the finality vote weight, honest pauses and recovery labelled apart from finality (D05) belong to TV-07, TV-09 and TV-15",those gates' native runs
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
horizon_year,scenario,multiple,role,route,route_status,native_receipts_base_units,native_receipts_coins,cumulative_years_1_to_h_coins,fraction_of_role_year1,fundable_cost_ceiling_bu,role_cost_bu_panel,coverage,external_job_receipts,scenario_class_panel,decision,meaning
|
||||
1,m010,0.10,miners,R1-miner,IMPLEMENTED,77043119999330600,770431199.99330600,770431199.99330600,1.00000000,0.08000000,,,0 (D04: the external-job rate is not ratified),,NOT RUN,"In year 1 at 0.10x the miners receive 770,431,199 coins, 100.00% of their year-1 receipts, which covers a minimum miners cost of at most 0.080000 BU; a panel cost above 0.080000 BU puts this cell in the failure region."
|
||||
1,m010,0.10,internal provers,R1-pool,IMPLEMENTED,19260779999832649,192607799.99832649,192607799.99832649,1.00000000,0.02000000,,,0 (D04: the external-job rate is not ratified),,NOT RUN,"In year 1 at 0.10x the internal provers receive 192,607,799 coins, 100.00% of their year-1 receipts, which covers a minimum internal provers cost of at most 0.020000 BU; a panel cost above 0.020000 BU puts this cell in the failure region."
|
||||
1,m010,0.10,minimum validators,R1-validators,IMPLEMENTED,0,0.00000000,0.00000000,,0.00000000,,,0 (D04: the external-job rate is not ratified),,BLOCKED,"In year 1 at 0.10x the protocol routes nothing to minimum validators, so any positive minimum cost for the role is in the failure region until D03 names its recurring payer."
|
||||
1,m010,0.10,maintenance,R1-maintenance,IMPLEMENTED,0,0.00000000,0.00000000,,0.00000000,,,0 (D04: the external-job rate is not ratified),,BLOCKED,"In year 1 at 0.10x the protocol routes nothing to maintenance, so any positive minimum cost for the role is in the failure region until D03 names its recurring payer."
|
||||
1,m025,0.25,miners,R1-miner,IMPLEMENTED,77043119999330600,770431199.99330600,770431199.99330600,1.00000000,0.20000000,,,0 (D04: the external-job rate is not ratified),,NOT RUN,"In year 1 at 0.25x the miners receive 770,431,199 coins, 100.00% of their year-1 receipts, which covers a minimum miners cost of at most 0.200000 BU; a panel cost above 0.200000 BU puts this cell in the failure region."
|
||||
1,m025,0.25,internal provers,R1-pool,IMPLEMENTED,19260779999832649,192607799.99832649,192607799.99832649,1.00000000,0.05000000,,,0 (D04: the external-job rate is not ratified),,NOT RUN,"In year 1 at 0.25x the internal provers receive 192,607,799 coins, 100.00% of their year-1 receipts, which covers a minimum internal provers cost of at most 0.050000 BU; a panel cost above 0.050000 BU puts this cell in the failure region."
|
||||
1,m025,0.25,minimum validators,R1-validators,IMPLEMENTED,0,0.00000000,0.00000000,,0.00000000,,,0 (D04: the external-job rate is not ratified),,BLOCKED,"In year 1 at 0.25x the protocol routes nothing to minimum validators, so any positive minimum cost for the role is in the failure region until D03 names its recurring payer."
|
||||
1,m025,0.25,maintenance,R1-maintenance,IMPLEMENTED,0,0.00000000,0.00000000,,0.00000000,,,0 (D04: the external-job rate is not ratified),,BLOCKED,"In year 1 at 0.25x the protocol routes nothing to maintenance, so any positive minimum cost for the role is in the failure region until D03 names its recurring payer."
|
||||
1,m100,1.00,miners,R1-miner,IMPLEMENTED,77043119999330600,770431199.99330600,770431199.99330600,1.00000000,0.80000000,,,0 (D04: the external-job rate is not ratified),,NOT RUN,"In year 1 at 1.00x the miners receive 770,431,199 coins, 100.00% of their year-1 receipts, which covers a minimum miners cost of at most 0.800000 BU; a panel cost above 0.800000 BU puts this cell in the failure region."
|
||||
1,m100,1.00,internal provers,R1-pool,IMPLEMENTED,19260779999832649,192607799.99832649,192607799.99832649,1.00000000,0.20000000,,,0 (D04: the external-job rate is not ratified),,NOT RUN,"In year 1 at 1.00x the internal provers receive 192,607,799 coins, 100.00% of their year-1 receipts, which covers a minimum internal provers cost of at most 0.200000 BU; a panel cost above 0.200000 BU puts this cell in the failure region."
|
||||
1,m100,1.00,minimum validators,R1-validators,IMPLEMENTED,0,0.00000000,0.00000000,,0.00000000,,,0 (D04: the external-job rate is not ratified),,BLOCKED,"In year 1 at 1.00x the protocol routes nothing to minimum validators, so any positive minimum cost for the role is in the failure region until D03 names its recurring payer."
|
||||
1,m100,1.00,maintenance,R1-maintenance,IMPLEMENTED,0,0.00000000,0.00000000,,0.00000000,,,0 (D04: the external-job rate is not ratified),,BLOCKED,"In year 1 at 1.00x the protocol routes nothing to maintenance, so any positive minimum cost for the role is in the failure region until D03 names its recurring payer."
|
||||
1,m400,4.00,miners,R1-miner,IMPLEMENTED,77043119999330600,770431199.99330600,770431199.99330600,1.00000000,3.20000000,,,0 (D04: the external-job rate is not ratified),,NOT RUN,"In year 1 at 4.00x the miners receive 770,431,199 coins, 100.00% of their year-1 receipts, which covers a minimum miners cost of at most 3.200000 BU; a panel cost above 3.200000 BU puts this cell in the failure region."
|
||||
1,m400,4.00,internal provers,R1-pool,IMPLEMENTED,19260779999832649,192607799.99832649,192607799.99832649,1.00000000,0.80000000,,,0 (D04: the external-job rate is not ratified),,NOT RUN,"In year 1 at 4.00x the internal provers receive 192,607,799 coins, 100.00% of their year-1 receipts, which covers a minimum internal provers cost of at most 0.800000 BU; a panel cost above 0.800000 BU puts this cell in the failure region."
|
||||
1,m400,4.00,minimum validators,R1-validators,IMPLEMENTED,0,0.00000000,0.00000000,,0.00000000,,,0 (D04: the external-job rate is not ratified),,BLOCKED,"In year 1 at 4.00x the protocol routes nothing to minimum validators, so any positive minimum cost for the role is in the failure region until D03 names its recurring payer."
|
||||
1,m400,4.00,maintenance,R1-maintenance,IMPLEMENTED,0,0.00000000,0.00000000,,0.00000000,,,0 (D04: the external-job rate is not ratified),,BLOCKED,"In year 1 at 4.00x the protocol routes nothing to maintenance, so any positive minimum cost for the role is in the failure region until D03 names its recurring payer."
|
||||
1,m1000,10.00,miners,R1-miner,IMPLEMENTED,77043119999330600,770431199.99330600,770431199.99330600,1.00000000,8.00000000,,,0 (D04: the external-job rate is not ratified),,NOT RUN,"In year 1 at 10.00x the miners receive 770,431,199 coins, 100.00% of their year-1 receipts, which covers a minimum miners cost of at most 8.000000 BU; a panel cost above 8.000000 BU puts this cell in the failure region."
|
||||
1,m1000,10.00,internal provers,R1-pool,IMPLEMENTED,19260779999832649,192607799.99832649,192607799.99832649,1.00000000,2.00000000,,,0 (D04: the external-job rate is not ratified),,NOT RUN,"In year 1 at 10.00x the internal provers receive 192,607,799 coins, 100.00% of their year-1 receipts, which covers a minimum internal provers cost of at most 2.000000 BU; a panel cost above 2.000000 BU puts this cell in the failure region."
|
||||
1,m1000,10.00,minimum validators,R1-validators,IMPLEMENTED,0,0.00000000,0.00000000,,0.00000000,,,0 (D04: the external-job rate is not ratified),,BLOCKED,"In year 1 at 10.00x the protocol routes nothing to minimum validators, so any positive minimum cost for the role is in the failure region until D03 names its recurring payer."
|
||||
1,m1000,10.00,maintenance,R1-maintenance,IMPLEMENTED,0,0.00000000,0.00000000,,0.00000000,,,0 (D04: the external-job rate is not ratified),,BLOCKED,"In year 1 at 10.00x the protocol routes nothing to maintenance, so any positive minimum cost for the role is in the failure region until D03 names its recurring payer."
|
||||
5,m010,0.10,miners,R1-miner,IMPLEMENTED,19999999991145600,199999999.91145600,2570431199.44887080,0.25959489,0.02076759,,,0 (D04: the external-job rate is not ratified),,NOT RUN,"In year 5 at 0.10x the miners receive 199,999,999 coins, 25.96% of their year-1 receipts, which covers a minimum miners cost of at most 0.020768 BU; a panel cost above 0.020768 BU puts this cell in the failure region."
|
||||
5,m010,0.10,internal provers,R1-pool,IMPLEMENTED,4999999997786400,49999999.97786400,642607799.86221769,0.25959489,0.00519190,,,0 (D04: the external-job rate is not ratified),,NOT RUN,"In year 5 at 0.10x the internal provers receive 49,999,999 coins, 25.96% of their year-1 receipts, which covers a minimum internal provers cost of at most 0.005192 BU; a panel cost above 0.005192 BU puts this cell in the failure region."
|
||||
5,m010,0.10,minimum validators,R1-validators,IMPLEMENTED,0,0.00000000,0.00000000,,0.00000000,,,0 (D04: the external-job rate is not ratified),,BLOCKED,"In year 5 at 0.10x the protocol routes nothing to minimum validators, so any positive minimum cost for the role is in the failure region until D03 names its recurring payer."
|
||||
5,m010,0.10,maintenance,R1-maintenance,IMPLEMENTED,0,0.00000000,0.00000000,,0.00000000,,,0 (D04: the external-job rate is not ratified),,BLOCKED,"In year 5 at 0.10x the protocol routes nothing to maintenance, so any positive minimum cost for the role is in the failure region until D03 names its recurring payer."
|
||||
5,m025,0.25,miners,R1-miner,IMPLEMENTED,19999999991145600,199999999.91145600,2570431199.44887080,0.25959489,0.05191898,,,0 (D04: the external-job rate is not ratified),,NOT RUN,"In year 5 at 0.25x the miners receive 199,999,999 coins, 25.96% of their year-1 receipts, which covers a minimum miners cost of at most 0.051919 BU; a panel cost above 0.051919 BU puts this cell in the failure region."
|
||||
5,m025,0.25,internal provers,R1-pool,IMPLEMENTED,4999999997786400,49999999.97786400,642607799.86221769,0.25959489,0.01297974,,,0 (D04: the external-job rate is not ratified),,NOT RUN,"In year 5 at 0.25x the internal provers receive 49,999,999 coins, 25.96% of their year-1 receipts, which covers a minimum internal provers cost of at most 0.012980 BU; a panel cost above 0.012980 BU puts this cell in the failure region."
|
||||
5,m025,0.25,minimum validators,R1-validators,IMPLEMENTED,0,0.00000000,0.00000000,,0.00000000,,,0 (D04: the external-job rate is not ratified),,BLOCKED,"In year 5 at 0.25x the protocol routes nothing to minimum validators, so any positive minimum cost for the role is in the failure region until D03 names its recurring payer."
|
||||
5,m025,0.25,maintenance,R1-maintenance,IMPLEMENTED,0,0.00000000,0.00000000,,0.00000000,,,0 (D04: the external-job rate is not ratified),,BLOCKED,"In year 5 at 0.25x the protocol routes nothing to maintenance, so any positive minimum cost for the role is in the failure region until D03 names its recurring payer."
|
||||
5,m100,1.00,miners,R1-miner,IMPLEMENTED,19999999991145600,199999999.91145600,2570431199.44887080,0.25959489,0.20767591,,,0 (D04: the external-job rate is not ratified),,NOT RUN,"In year 5 at 1.00x the miners receive 199,999,999 coins, 25.96% of their year-1 receipts, which covers a minimum miners cost of at most 0.207676 BU; a panel cost above 0.207676 BU puts this cell in the failure region."
|
||||
5,m100,1.00,internal provers,R1-pool,IMPLEMENTED,4999999997786400,49999999.97786400,642607799.86221769,0.25959489,0.05191898,,,0 (D04: the external-job rate is not ratified),,NOT RUN,"In year 5 at 1.00x the internal provers receive 49,999,999 coins, 25.96% of their year-1 receipts, which covers a minimum internal provers cost of at most 0.051919 BU; a panel cost above 0.051919 BU puts this cell in the failure region."
|
||||
5,m100,1.00,minimum validators,R1-validators,IMPLEMENTED,0,0.00000000,0.00000000,,0.00000000,,,0 (D04: the external-job rate is not ratified),,BLOCKED,"In year 5 at 1.00x the protocol routes nothing to minimum validators, so any positive minimum cost for the role is in the failure region until D03 names its recurring payer."
|
||||
5,m100,1.00,maintenance,R1-maintenance,IMPLEMENTED,0,0.00000000,0.00000000,,0.00000000,,,0 (D04: the external-job rate is not ratified),,BLOCKED,"In year 5 at 1.00x the protocol routes nothing to maintenance, so any positive minimum cost for the role is in the failure region until D03 names its recurring payer."
|
||||
5,m400,4.00,miners,R1-miner,IMPLEMENTED,19999999991145600,199999999.91145600,2570431199.44887080,0.25959489,0.83070364,,,0 (D04: the external-job rate is not ratified),,NOT RUN,"In year 5 at 4.00x the miners receive 199,999,999 coins, 25.96% of their year-1 receipts, which covers a minimum miners cost of at most 0.830704 BU; a panel cost above 0.830704 BU puts this cell in the failure region."
|
||||
5,m400,4.00,internal provers,R1-pool,IMPLEMENTED,4999999997786400,49999999.97786400,642607799.86221769,0.25959489,0.20767591,,,0 (D04: the external-job rate is not ratified),,NOT RUN,"In year 5 at 4.00x the internal provers receive 49,999,999 coins, 25.96% of their year-1 receipts, which covers a minimum internal provers cost of at most 0.207676 BU; a panel cost above 0.207676 BU puts this cell in the failure region."
|
||||
5,m400,4.00,minimum validators,R1-validators,IMPLEMENTED,0,0.00000000,0.00000000,,0.00000000,,,0 (D04: the external-job rate is not ratified),,BLOCKED,"In year 5 at 4.00x the protocol routes nothing to minimum validators, so any positive minimum cost for the role is in the failure region until D03 names its recurring payer."
|
||||
5,m400,4.00,maintenance,R1-maintenance,IMPLEMENTED,0,0.00000000,0.00000000,,0.00000000,,,0 (D04: the external-job rate is not ratified),,BLOCKED,"In year 5 at 4.00x the protocol routes nothing to maintenance, so any positive minimum cost for the role is in the failure region until D03 names its recurring payer."
|
||||
5,m1000,10.00,miners,R1-miner,IMPLEMENTED,19999999991145600,199999999.91145600,2570431199.44887080,0.25959489,2.07675909,,,0 (D04: the external-job rate is not ratified),,NOT RUN,"In year 5 at 10.00x the miners receive 199,999,999 coins, 25.96% of their year-1 receipts, which covers a minimum miners cost of at most 2.076759 BU; a panel cost above 2.076759 BU puts this cell in the failure region."
|
||||
5,m1000,10.00,internal provers,R1-pool,IMPLEMENTED,4999999997786400,49999999.97786400,642607799.86221769,0.25959489,0.51918977,,,0 (D04: the external-job rate is not ratified),,NOT RUN,"In year 5 at 10.00x the internal provers receive 49,999,999 coins, 25.96% of their year-1 receipts, which covers a minimum internal provers cost of at most 0.519190 BU; a panel cost above 0.519190 BU puts this cell in the failure region."
|
||||
5,m1000,10.00,minimum validators,R1-validators,IMPLEMENTED,0,0.00000000,0.00000000,,0.00000000,,,0 (D04: the external-job rate is not ratified),,BLOCKED,"In year 5 at 10.00x the protocol routes nothing to minimum validators, so any positive minimum cost for the role is in the failure region until D03 names its recurring payer."
|
||||
5,m1000,10.00,maintenance,R1-maintenance,IMPLEMENTED,0,0.00000000,0.00000000,,0.00000000,,,0 (D04: the external-job rate is not ratified),,BLOCKED,"In year 5 at 10.00x the protocol routes nothing to maintenance, so any positive minimum cost for the role is in the failure region until D03 names its recurring payer."
|
||||
10,m010,0.10,miners,R1-miner,IMPLEMENTED,4999999978851840,49999999.78851840,3070431198.59635880,0.06489872,0.00519190,,,0 (D04: the external-job rate is not ratified),,NOT RUN,"In year 10 at 0.10x the miners receive 49,999,999 coins, 6.49% of their year-1 receipts, which covers a minimum miners cost of at most 0.005192 BU; a panel cost above 0.005192 BU puts this cell in the failure region."
|
||||
10,m010,0.10,internal provers,R1-pool,IMPLEMENTED,1249999994712960,12499999.94712960,767607799.64908969,0.06489872,0.00129797,,,0 (D04: the external-job rate is not ratified),,NOT RUN,"In year 10 at 0.10x the internal provers receive 12,499,999 coins, 6.49% of their year-1 receipts, which covers a minimum internal provers cost of at most 0.001298 BU; a panel cost above 0.001298 BU puts this cell in the failure region."
|
||||
10,m010,0.10,minimum validators,R1-validators,IMPLEMENTED,0,0.00000000,0.00000000,,0.00000000,,,0 (D04: the external-job rate is not ratified),,BLOCKED,"In year 10 at 0.10x the protocol routes nothing to minimum validators, so any positive minimum cost for the role is in the failure region until D03 names its recurring payer."
|
||||
10,m010,0.10,maintenance,R1-maintenance,IMPLEMENTED,0,0.00000000,0.00000000,,0.00000000,,,0 (D04: the external-job rate is not ratified),,BLOCKED,"In year 10 at 0.10x the protocol routes nothing to maintenance, so any positive minimum cost for the role is in the failure region until D03 names its recurring payer."
|
||||
10,m025,0.25,miners,R1-miner,IMPLEMENTED,4999999978851840,49999999.78851840,3070431198.59635880,0.06489872,0.01297974,,,0 (D04: the external-job rate is not ratified),,NOT RUN,"In year 10 at 0.25x the miners receive 49,999,999 coins, 6.49% of their year-1 receipts, which covers a minimum miners cost of at most 0.012980 BU; a panel cost above 0.012980 BU puts this cell in the failure region."
|
||||
10,m025,0.25,internal provers,R1-pool,IMPLEMENTED,1249999994712960,12499999.94712960,767607799.64908969,0.06489872,0.00324494,,,0 (D04: the external-job rate is not ratified),,NOT RUN,"In year 10 at 0.25x the internal provers receive 12,499,999 coins, 6.49% of their year-1 receipts, which covers a minimum internal provers cost of at most 0.003245 BU; a panel cost above 0.003245 BU puts this cell in the failure region."
|
||||
10,m025,0.25,minimum validators,R1-validators,IMPLEMENTED,0,0.00000000,0.00000000,,0.00000000,,,0 (D04: the external-job rate is not ratified),,BLOCKED,"In year 10 at 0.25x the protocol routes nothing to minimum validators, so any positive minimum cost for the role is in the failure region until D03 names its recurring payer."
|
||||
10,m025,0.25,maintenance,R1-maintenance,IMPLEMENTED,0,0.00000000,0.00000000,,0.00000000,,,0 (D04: the external-job rate is not ratified),,BLOCKED,"In year 10 at 0.25x the protocol routes nothing to maintenance, so any positive minimum cost for the role is in the failure region until D03 names its recurring payer."
|
||||
10,m100,1.00,miners,R1-miner,IMPLEMENTED,4999999978851840,49999999.78851840,3070431198.59635880,0.06489872,0.05191898,,,0 (D04: the external-job rate is not ratified),,NOT RUN,"In year 10 at 1.00x the miners receive 49,999,999 coins, 6.49% of their year-1 receipts, which covers a minimum miners cost of at most 0.051919 BU; a panel cost above 0.051919 BU puts this cell in the failure region."
|
||||
10,m100,1.00,internal provers,R1-pool,IMPLEMENTED,1249999994712960,12499999.94712960,767607799.64908969,0.06489872,0.01297974,,,0 (D04: the external-job rate is not ratified),,NOT RUN,"In year 10 at 1.00x the internal provers receive 12,499,999 coins, 6.49% of their year-1 receipts, which covers a minimum internal provers cost of at most 0.012980 BU; a panel cost above 0.012980 BU puts this cell in the failure region."
|
||||
10,m100,1.00,minimum validators,R1-validators,IMPLEMENTED,0,0.00000000,0.00000000,,0.00000000,,,0 (D04: the external-job rate is not ratified),,BLOCKED,"In year 10 at 1.00x the protocol routes nothing to minimum validators, so any positive minimum cost for the role is in the failure region until D03 names its recurring payer."
|
||||
10,m100,1.00,maintenance,R1-maintenance,IMPLEMENTED,0,0.00000000,0.00000000,,0.00000000,,,0 (D04: the external-job rate is not ratified),,BLOCKED,"In year 10 at 1.00x the protocol routes nothing to maintenance, so any positive minimum cost for the role is in the failure region until D03 names its recurring payer."
|
||||
10,m400,4.00,miners,R1-miner,IMPLEMENTED,4999999978851840,49999999.78851840,3070431198.59635880,0.06489872,0.20767591,,,0 (D04: the external-job rate is not ratified),,NOT RUN,"In year 10 at 4.00x the miners receive 49,999,999 coins, 6.49% of their year-1 receipts, which covers a minimum miners cost of at most 0.207676 BU; a panel cost above 0.207676 BU puts this cell in the failure region."
|
||||
10,m400,4.00,internal provers,R1-pool,IMPLEMENTED,1249999994712960,12499999.94712960,767607799.64908969,0.06489872,0.05191898,,,0 (D04: the external-job rate is not ratified),,NOT RUN,"In year 10 at 4.00x the internal provers receive 12,499,999 coins, 6.49% of their year-1 receipts, which covers a minimum internal provers cost of at most 0.051919 BU; a panel cost above 0.051919 BU puts this cell in the failure region."
|
||||
10,m400,4.00,minimum validators,R1-validators,IMPLEMENTED,0,0.00000000,0.00000000,,0.00000000,,,0 (D04: the external-job rate is not ratified),,BLOCKED,"In year 10 at 4.00x the protocol routes nothing to minimum validators, so any positive minimum cost for the role is in the failure region until D03 names its recurring payer."
|
||||
10,m400,4.00,maintenance,R1-maintenance,IMPLEMENTED,0,0.00000000,0.00000000,,0.00000000,,,0 (D04: the external-job rate is not ratified),,BLOCKED,"In year 10 at 4.00x the protocol routes nothing to maintenance, so any positive minimum cost for the role is in the failure region until D03 names its recurring payer."
|
||||
10,m1000,10.00,miners,R1-miner,IMPLEMENTED,4999999978851840,49999999.78851840,3070431198.59635880,0.06489872,0.51918977,,,0 (D04: the external-job rate is not ratified),,NOT RUN,"In year 10 at 10.00x the miners receive 49,999,999 coins, 6.49% of their year-1 receipts, which covers a minimum miners cost of at most 0.519190 BU; a panel cost above 0.519190 BU puts this cell in the failure region."
|
||||
10,m1000,10.00,internal provers,R1-pool,IMPLEMENTED,1249999994712960,12499999.94712960,767607799.64908969,0.06489872,0.12979744,,,0 (D04: the external-job rate is not ratified),,NOT RUN,"In year 10 at 10.00x the internal provers receive 12,499,999 coins, 6.49% of their year-1 receipts, which covers a minimum internal provers cost of at most 0.129797 BU; a panel cost above 0.129797 BU puts this cell in the failure region."
|
||||
10,m1000,10.00,minimum validators,R1-validators,IMPLEMENTED,0,0.00000000,0.00000000,,0.00000000,,,0 (D04: the external-job rate is not ratified),,BLOCKED,"In year 10 at 10.00x the protocol routes nothing to minimum validators, so any positive minimum cost for the role is in the failure region until D03 names its recurring payer."
|
||||
10,m1000,10.00,maintenance,R1-maintenance,IMPLEMENTED,0,0.00000000,0.00000000,,0.00000000,,,0 (D04: the external-job rate is not ratified),,BLOCKED,"In year 10 at 10.00x the protocol routes nothing to maintenance, so any positive minimum cost for the role is in the failure region until D03 names its recurring payer."
|
||||
20,m010,0.10,miners,R1-miner,IMPLEMENTED,156249983560320,1562499.83560320,3167306197.49234600,0.00202808,0.00016225,,,0 (D04: the external-job rate is not ratified),,NOT RUN,"In year 20 at 0.10x the miners receive 1,562,499 coins, 0.20% of their year-1 receipts, which covers a minimum miners cost of at most 0.000162 BU; a panel cost above 0.000162 BU puts this cell in the failure region."
|
||||
20,m010,0.10,internal provers,R1-pool,IMPLEMENTED,39062495890080,390624.95890080,791826549.37308649,0.00202808,0.00004056,,,0 (D04: the external-job rate is not ratified),,NOT RUN,"In year 20 at 0.10x the internal provers receive 390,624 coins, 0.20% of their year-1 receipts, which covers a minimum internal provers cost of at most 0.000041 BU; a panel cost above 0.000041 BU puts this cell in the failure region."
|
||||
20,m010,0.10,minimum validators,R1-validators,IMPLEMENTED,0,0.00000000,0.00000000,,0.00000000,,,0 (D04: the external-job rate is not ratified),,BLOCKED,"In year 20 at 0.10x the protocol routes nothing to minimum validators, so any positive minimum cost for the role is in the failure region until D03 names its recurring payer."
|
||||
20,m010,0.10,maintenance,R1-maintenance,IMPLEMENTED,0,0.00000000,0.00000000,,0.00000000,,,0 (D04: the external-job rate is not ratified),,BLOCKED,"In year 20 at 0.10x the protocol routes nothing to maintenance, so any positive minimum cost for the role is in the failure region until D03 names its recurring payer."
|
||||
20,m025,0.25,miners,R1-miner,IMPLEMENTED,156249983560320,1562499.83560320,3167306197.49234600,0.00202808,0.00040562,,,0 (D04: the external-job rate is not ratified),,NOT RUN,"In year 20 at 0.25x the miners receive 1,562,499 coins, 0.20% of their year-1 receipts, which covers a minimum miners cost of at most 0.000406 BU; a panel cost above 0.000406 BU puts this cell in the failure region."
|
||||
20,m025,0.25,internal provers,R1-pool,IMPLEMENTED,39062495890080,390624.95890080,791826549.37308649,0.00202808,0.00010140,,,0 (D04: the external-job rate is not ratified),,NOT RUN,"In year 20 at 0.25x the internal provers receive 390,624 coins, 0.20% of their year-1 receipts, which covers a minimum internal provers cost of at most 0.000101 BU; a panel cost above 0.000101 BU puts this cell in the failure region."
|
||||
20,m025,0.25,minimum validators,R1-validators,IMPLEMENTED,0,0.00000000,0.00000000,,0.00000000,,,0 (D04: the external-job rate is not ratified),,BLOCKED,"In year 20 at 0.25x the protocol routes nothing to minimum validators, so any positive minimum cost for the role is in the failure region until D03 names its recurring payer."
|
||||
20,m025,0.25,maintenance,R1-maintenance,IMPLEMENTED,0,0.00000000,0.00000000,,0.00000000,,,0 (D04: the external-job rate is not ratified),,BLOCKED,"In year 20 at 0.25x the protocol routes nothing to maintenance, so any positive minimum cost for the role is in the failure region until D03 names its recurring payer."
|
||||
20,m100,1.00,miners,R1-miner,IMPLEMENTED,156249983560320,1562499.83560320,3167306197.49234600,0.00202808,0.00162247,,,0 (D04: the external-job rate is not ratified),,NOT RUN,"In year 20 at 1.00x the miners receive 1,562,499 coins, 0.20% of their year-1 receipts, which covers a minimum miners cost of at most 0.001622 BU; a panel cost above 0.001622 BU puts this cell in the failure region."
|
||||
20,m100,1.00,internal provers,R1-pool,IMPLEMENTED,39062495890080,390624.95890080,791826549.37308649,0.00202808,0.00040562,,,0 (D04: the external-job rate is not ratified),,NOT RUN,"In year 20 at 1.00x the internal provers receive 390,624 coins, 0.20% of their year-1 receipts, which covers a minimum internal provers cost of at most 0.000406 BU; a panel cost above 0.000406 BU puts this cell in the failure region."
|
||||
20,m100,1.00,minimum validators,R1-validators,IMPLEMENTED,0,0.00000000,0.00000000,,0.00000000,,,0 (D04: the external-job rate is not ratified),,BLOCKED,"In year 20 at 1.00x the protocol routes nothing to minimum validators, so any positive minimum cost for the role is in the failure region until D03 names its recurring payer."
|
||||
20,m100,1.00,maintenance,R1-maintenance,IMPLEMENTED,0,0.00000000,0.00000000,,0.00000000,,,0 (D04: the external-job rate is not ratified),,BLOCKED,"In year 20 at 1.00x the protocol routes nothing to maintenance, so any positive minimum cost for the role is in the failure region until D03 names its recurring payer."
|
||||
20,m400,4.00,miners,R1-miner,IMPLEMENTED,156249983560320,1562499.83560320,3167306197.49234600,0.00202808,0.00648987,,,0 (D04: the external-job rate is not ratified),,NOT RUN,"In year 20 at 4.00x the miners receive 1,562,499 coins, 0.20% of their year-1 receipts, which covers a minimum miners cost of at most 0.006490 BU; a panel cost above 0.006490 BU puts this cell in the failure region."
|
||||
20,m400,4.00,internal provers,R1-pool,IMPLEMENTED,39062495890080,390624.95890080,791826549.37308649,0.00202808,0.00162247,,,0 (D04: the external-job rate is not ratified),,NOT RUN,"In year 20 at 4.00x the internal provers receive 390,624 coins, 0.20% of their year-1 receipts, which covers a minimum internal provers cost of at most 0.001622 BU; a panel cost above 0.001622 BU puts this cell in the failure region."
|
||||
20,m400,4.00,minimum validators,R1-validators,IMPLEMENTED,0,0.00000000,0.00000000,,0.00000000,,,0 (D04: the external-job rate is not ratified),,BLOCKED,"In year 20 at 4.00x the protocol routes nothing to minimum validators, so any positive minimum cost for the role is in the failure region until D03 names its recurring payer."
|
||||
20,m400,4.00,maintenance,R1-maintenance,IMPLEMENTED,0,0.00000000,0.00000000,,0.00000000,,,0 (D04: the external-job rate is not ratified),,BLOCKED,"In year 20 at 4.00x the protocol routes nothing to maintenance, so any positive minimum cost for the role is in the failure region until D03 names its recurring payer."
|
||||
20,m1000,10.00,miners,R1-miner,IMPLEMENTED,156249983560320,1562499.83560320,3167306197.49234600,0.00202808,0.01622468,,,0 (D04: the external-job rate is not ratified),,NOT RUN,"In year 20 at 10.00x the miners receive 1,562,499 coins, 0.20% of their year-1 receipts, which covers a minimum miners cost of at most 0.016225 BU; a panel cost above 0.016225 BU puts this cell in the failure region."
|
||||
20,m1000,10.00,internal provers,R1-pool,IMPLEMENTED,39062495890080,390624.95890080,791826549.37308649,0.00202808,0.00405617,,,0 (D04: the external-job rate is not ratified),,NOT RUN,"In year 20 at 10.00x the internal provers receive 390,624 coins, 0.20% of their year-1 receipts, which covers a minimum internal provers cost of at most 0.004056 BU; a panel cost above 0.004056 BU puts this cell in the failure region."
|
||||
20,m1000,10.00,minimum validators,R1-validators,IMPLEMENTED,0,0.00000000,0.00000000,,0.00000000,,,0 (D04: the external-job rate is not ratified),,BLOCKED,"In year 20 at 10.00x the protocol routes nothing to minimum validators, so any positive minimum cost for the role is in the failure region until D03 names its recurring payer."
|
||||
20,m1000,10.00,maintenance,R1-maintenance,IMPLEMENTED,0,0.00000000,0.00000000,,0.00000000,,,0 (D04: the external-job rate is not ratified),,BLOCKED,"In year 20 at 10.00x the protocol routes nothing to maintenance, so any positive minimum cost for the role is in the failure region until D03 names its recurring payer."
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
year,emission_base_units,emission_coins,cumulative_coins,cumulative_fraction_of_cap,miners_coins,internal_provers_coins,fraction_of_year1_emission
|
||||
1,96303899999163249,963038999.99163249,963038999.99163249,0.24075975,770431199.99330600,192607799.99832649,1.00000000
|
||||
2,99999999987285600,999999999.87285600,1963038999.86448849,0.49075975,799999999.89828480,199999999.97457120,1.03837955
|
||||
3,49999999977864000,499999999.77864000,2463038999.64312849,0.61575975,399999999.82291200,99999999.95572800,0.51918977
|
||||
4,49999999977864000,499999999.77864000,2963038999.42176849,0.74075975,399999999.82291200,99999999.95572800,0.51918977
|
||||
5,24999999988932000,249999999.88932000,3213038999.31108849,0.80325975,199999999.91145600,49999999.97786400,0.25959489
|
||||
6,24999999988932000,249999999.88932000,3463038999.20040849,0.86575975,199999999.91145600,49999999.97786400,0.25959489
|
||||
7,12499999978687200,124999999.78687200,3588038998.98728049,0.89700975,99999999.82949760,24999999.95737440,0.12979744
|
||||
8,12499999978687200,124999999.78687200,3713038998.77415249,0.92825975,99999999.82949760,24999999.95737440,0.12979744
|
||||
9,6249999973564800,62499999.73564800,3775538998.50980049,0.94388475,49999999.78851840,12499999.94712960,0.06489872
|
||||
10,6249999973564800,62499999.73564800,3838038998.24544849,0.95950975,49999999.78851840,12499999.94712960,0.06489872
|
||||
11,3124999986782400,31249999.86782400,3869288998.11327249,0.96732225,24999999.89425920,6249999.97356480,0.03244936
|
||||
12,3124999986782400,31249999.86782400,3900538997.98109649,0.97513475,24999999.89425920,6249999.97356480,0.03244936
|
||||
13,1562499993391200,15624999.93391200,3916163997.91500849,0.97904100,12499999.94712960,3124999.98678240,0.01622468
|
||||
14,1562499993391200,15624999.93391200,3931788997.84892049,0.98294725,12499999.94712960,3124999.98678240,0.01622468
|
||||
15,781249980916800,7812499.80916800,3939601497.65808849,0.98490037,6249999.84733440,1562499.96183360,0.00811234
|
||||
16,781249980916800,7812499.80916800,3947413997.46725649,0.98685350,6249999.84733440,1562499.96183360,0.00811234
|
||||
17,390624990458400,3906249.90458400,3951320247.37184049,0.98783006,3124999.92366720,781249.98091680,0.00405617
|
||||
18,390624990458400,3906249.90458400,3955226497.27642449,0.98880662,3124999.92366720,781249.98091680,0.00405617
|
||||
19,195312479450400,1953124.79450400,3957179622.07092849,0.98929491,1562499.83560320,390624.95890080,0.00202808
|
||||
20,195312479450400,1953124.79450400,3959132746.86543249,0.98978319,1562499.83560320,390624.95890080,0.00202808
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
year,miner_gap_to_year1_coins,tips_needed_per_year_coins_floor,tips_needed_as_fraction_of_baseline,internal_provers
|
||||
1,0.00000000,0.00000000,0.00000000,no tip route to provers in the node's code (BLOCKED row B-01)
|
||||
2,0.00000000,0.00000000,0.00000000,no tip route to provers in the node's code (BLOCKED row B-01)
|
||||
3,370431200.17039400,463039000.21299250,0.48081023,no tip route to provers in the node's code (BLOCKED row B-01)
|
||||
4,370431200.17039400,463039000.21299250,0.48081023,no tip route to provers in the node's code (BLOCKED row B-01)
|
||||
5,570431200.08185000,713039000.10231250,0.74040511,no tip route to provers in the node's code (BLOCKED row B-01)
|
||||
6,570431200.08185000,713039000.10231250,0.74040511,no tip route to provers in the node's code (BLOCKED row B-01)
|
||||
7,670431200.16380840,838039000.20476050,0.87020256,no tip route to provers in the node's code (BLOCKED row B-01)
|
||||
8,670431200.16380840,838039000.20476050,0.87020256,no tip route to provers in the node's code (BLOCKED row B-01)
|
||||
9,720431200.20478760,900539000.25598450,0.93510128,no tip route to provers in the node's code (BLOCKED row B-01)
|
||||
10,720431200.20478760,900539000.25598450,0.93510128,no tip route to provers in the node's code (BLOCKED row B-01)
|
||||
11,745431200.09904680,931789000.12380850,0.96755064,no tip route to provers in the node's code (BLOCKED row B-01)
|
||||
12,745431200.09904680,931789000.12380850,0.96755064,no tip route to provers in the node's code (BLOCKED row B-01)
|
||||
13,757931200.04617640,947414000.05772050,0.98377532,no tip route to provers in the node's code (BLOCKED row B-01)
|
||||
14,757931200.04617640,947414000.05772050,0.98377532,no tip route to provers in the node's code (BLOCKED row B-01)
|
||||
15,764181200.14597160,955226500.18246450,0.99188766,no tip route to provers in the node's code (BLOCKED row B-01)
|
||||
16,764181200.14597160,955226500.18246450,0.99188766,no tip route to provers in the node's code (BLOCKED row B-01)
|
||||
17,767306200.06963880,959132750.08704850,0.99594383,no tip route to provers in the node's code (BLOCKED row B-01)
|
||||
18,767306200.06963880,959132750.08704850,0.99594383,no tip route to provers in the node's code (BLOCKED row B-01)
|
||||
19,768868700.15770280,961085875.19712850,0.99797192,no tip route to provers in the node's code (BLOCKED row B-01)
|
||||
20,768868700.15770280,961085875.19712850,0.99797192,no tip route to provers in the node's code (BLOCKED row B-01)
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
id,parameter,value,unit,status,source
|
||||
S-rate,launch rate,3168808781,base units per DAA second (8 decimals),IMPLEMENTED,"node emission.rs lines 32 and 103 to 110 (EmissionSchedule::CURRENT, tail Cap); params.rs line 1858 (MAINNET_PARAMS carries CURRENT, rescaled to 18 decimals, the same coins); igneum.rs lines 33 to 41 (the 4,000,000,000 cap)"
|
||||
S-ramp,launch ramp,2592000 s from 10%,DAA seconds,IMPLEMENTED,"node emission.rs lines 32 and 103 to 110 (EmissionSchedule::CURRENT, tail Cap); params.rs line 1858 (MAINNET_PARAMS carries CURRENT, rescaled to 18 decimals, the same coins); igneum.rs lines 33 to 41 (the 4,000,000,000 cap)"
|
||||
S-step,decay step,"63115200 s, rate divided by 2",DAA seconds,IMPLEMENTED,"node emission.rs lines 32 and 103 to 110 (EmissionSchedule::CURRENT, tail Cap); params.rs line 1858 (MAINNET_PARAMS carries CURRENT, rescaled to 18 decimals, the same coins); igneum.rs lines 33 to 41 (the 4,000,000,000 cap)"
|
||||
S-tail,tail,cap,,RATIFIED (D01) and IMPLEMENTED,"node emission.rs lines 32 and 103 to 110 (EmissionSchedule::CURRENT, tail Cap); params.rs line 1858 (MAINNET_PARAMS carries CURRENT, rescaled to 18 decimals, the same coins); igneum.rs lines 33 to 41 (the 4,000,000,000 cap); D01 capped issuance, subject to TV-04; D02 the schedule pending evidence, so every figure here is conditional on this schedule"
|
||||
S-cap,cap,4000000000,coins,RATIFIED (D01) and IMPLEMENTED,"node emission.rs lines 32 and 103 to 110 (EmissionSchedule::CURRENT, tail Cap); params.rs line 1858 (MAINNET_PARAMS carries CURRENT, rescaled to 18 decimals, the same coins); igneum.rs lines 33 to 41 (the 4,000,000,000 cap)"
|
||||
R1-miner,"emission, producer share",80%,to miners,IMPLEMENTED,"igneum.rs lines 43 to 44 and 123 to 126; the litepaper's routing table, row 1"
|
||||
R1-pool,"emission, proving pool share",20%,to internal provers,IMPLEMENTED,"igneum.rs lines 43 to 44 and 85 to 88; the litepaper's routing table, row 1"
|
||||
R1-validators,emission to minimum validators,0%,to minimum validators,IMPLEMENTED,"no such output in the coinbase (igneum.rs lines 90 to 121); the litepaper: 0% to treasury, foundation, team or stake"
|
||||
R1-maintenance,emission to maintenance,0%,to maintenance,IMPLEMENTED,"no emission treasury (igneum.rs line 5); the litepaper: no fund, no foundation, no fee to the team"
|
||||
R2-base,"base fee, both gas dimensions",100%,to burn,IMPLEMENTED,fees.rs lines 131 to 132 (burned in full); executor.rs lines 318 to 329 (the execution base part and the proving charge burned)
|
||||
R3-tip-miner,"priority fee (tip), beneficiary share",80%,to miners,IMPLEMENTED,igneum/exec config.rs lines 75 to 76 (80% to the including miner); executor.rs line 729 (the beneficiary credited the miner tip)
|
||||
R3-tip-dev,"priority fee (tip), developer share",20%,to developers (not a security role),IMPLEMENTED,igneum/exec config.rs lines 75 to 76; pgas.rs lines 287 to 310
|
||||
R3-tip-provers,"priority fee (tip), provers' part",0%,to internal provers,BLOCKED,"the node's code pays the 80% tip share to the beneficiary alone (executor.rs lines 318 to 329, line 729); the litepaper's routing table, row 3, reads '80% the block's miner and provers' with no split. The master, p. 36: resolve the discrepancy between the fee table and prose before modelling security income."
|
||||
R4-external-launch,external job at launch (customer's chain),not used (zero),to the delivering miner (outside the native ledger),UNRATIFIED,"the litepaper's routing table, row 4 (Designed); D04: the external-job rate is not ratified"
|
||||
R5-external-bridge,external job after the proof bridge,not used (zero),to internal provers (the delivering provers),UNRATIFIED,"the litepaper's routing table, row 5 (Designed, phase two; 90% to provers, 10% burned as published); D04: the external-job rate is not ratified, so the published 90/10 is a parameter here and the tables carry zero external jobs"
|
||||
R6-devfee,the official miner client's optional dev fee,not used (zero),"to the project (operator income, outside the protocol)",UNRATIFIED,"the litepaper's routing table, row 6: never added to rows 1 to 5; switchable by every miner, so not a committed resource (the master, p. 68, P13)"
|
||||
m010,scenario multiple,0.10,"of the baseline's purchasing power, constant over the horizon",RATIFIED (TV-04 method words),"0.1x: the minus-90-percent case, the 1x path at one tenth"
|
||||
m025,scenario multiple,0.25,"of the baseline's purchasing power, constant over the horizon",RATIFIED (TV-04 method words),0.25x
|
||||
m100,scenario multiple,1.00,"of the baseline's purchasing power, constant over the horizon",RATIFIED (TV-04 method words),1x (the baseline path)
|
||||
m400,scenario multiple,4.00,"of the baseline's purchasing power, constant over the horizon",RATIFIED (TV-04 method words),4x
|
||||
m1000,scenario multiple,10.00,"of the baseline's purchasing power, constant over the horizon",RATIFIED (TV-04 method words),10x
|
||||
X-ext,external jobs per year,0,jobs,UNRATIFIED (D04),"TV-04 method: zero external jobs; the rate is a parameter, never a result"
|
||||
C-miners,minimum required miner cost per year,,"BU (one BU = the purchasing power of the baseline, the whole year-1 subsidy, on the 1x path)",PANEL,"the master, p. 68, P12: its electricity, productive-life and development grids are the panel's inputs; p. 88 to 89, ECO-01 to ECO-06 for the cost reconciliation"
|
||||
C-provers,minimum required internal proving cost per year,,BU,PANEL,"the master, p. 36 (the historical shard timings, not reproduced for this edition) and p. 89, ECO-06"
|
||||
C-validators,minimum required validator cost per year,,BU,PANEL,"the volume, p. 15 (minimum-node resources) and TV-10; no figure in the volume or the master"
|
||||
C-maintenance,minimum required maintenance cost per year,,BU,PANEL,"the master, p. 68, P13 (at least 12 months of committed resources); the volume, p. 31; no figure in the volume or the master"
|
||||
K-class,which scenario-year cells are approved viable and which are collapse cases,,"a declaration per cell, before results",PANEL,"the master, p. 68, P12: declare the viable worlds before running; collapse worlds stay as safety and exit tests"
|
||||
T-tip,native tip volume per year (fee level and its volatility),,coins a year,PANEL,"the volume, p. 14 (fee timing as well as amount); the tables carry zero, the fee-replacement table gives the volume each year would need"
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"run_id": "tv-04-20261009-01",
|
||||
"manifest_sha": "d59a9088",
|
||||
"method": "model",
|
||||
"evidence_dir": "docs/plans/igneum-2.0-master/token-value/phase0/tv-04",
|
||||
"release_identity": {
|
||||
"commit": "d59a9088 (the generator and inputs this model ran from; branch tv-04-security-budget)",
|
||||
"lockfile": "",
|
||||
"binary": "",
|
||||
"network_object": "none: a model of the ratified rules, no chain state read or written",
|
||||
"activation": "none (Phase 0 lands documents and tests only)",
|
||||
"profile_hashes": "the node's release-2.0.2-node a284380b emission.rs 07b39c41..., igneum.rs 6c859d42..., params.rs 0c07ddcf..., fees.rs 5e7a319c..., exec config.rs fdc4ba56..., executor.rs ff12ef5f...; rules-and-gates.json 10ce3073..."
|
||||
},
|
||||
"claim_impact": "none: the security budget as a reproducible cash-flow model of the ratified rules (D01, D03, D04 with the external-job rate unratified, D05, VR-05); every verdict NOT RUN until the independent panel fills the role costs and declares the viable and collapse cells; no price figure anywhere",
|
||||
"reviewer": "",
|
||||
"note": "Known-failed first: the tests ran red on build-9 before the generator existed (ea14c332, exit 1); green 9 of 9 and every one of 5 mutants caught on d59a9088; two generations byte-identical. BLOCKED rows B-01 to B-09 in blocked.csv (the provers' tip share, paid against assigned, the validators' payer, committed maintenance, the panel cells, the tail-vote clause, the testnet tail, the schedule, collapse-case safe behaviour).",
|
||||
"cells": [
|
||||
{
|
||||
"cell": "model:tv-04",
|
||||
"cases": ["TV-04"],
|
||||
"status": "NOT RUN",
|
||||
"method": "model",
|
||||
"evidence": "docs/plans/igneum-2.0-master/token-value/phase0/tv-04/README.md; docs/plans/igneum-2.0-master/token-value/phase0/tv-04/budget.csv; docs/plans/igneum-2.0-master/token-value/phase0/tv-04/emission.csv; docs/plans/igneum-2.0-master/token-value/phase0/tv-04/fee-replacement.csv; docs/plans/igneum-2.0-master/token-value/phase0/tv-04/parameters.csv; docs/plans/igneum-2.0-master/token-value/phase0/tv-04/blocked.csv; docs/plans/igneum-2.0-master/token-value/phase0/tv-04/RUNS.md; tools/token-value/tv-04/tv04_budget.py; tools/token-value/tv-04/test_tv04.py; tools/token-value/tv-04/inputs.json; build-9:/home/build/tv-04/runs/ea14c332-red/run.log; build-9:/home/build/tv-04/runs/d59a9088-green/run.log; build-9:/home/build/tv-04/runs/d59a9088-known-failed/run.log; build-9:/home/build/tv-04/runs/d59a9088-generate/run.log",
|
||||
"note": "NOT RUN: the model computed (the miners' and internal provers' budgets fall to 25.96, 6.49 and 0.20 percent of year 1 at years 5, 10 and 20; validators and maintenance receive nothing from the protocol); the panel's role costs and scenario classes are empty, so no coverage cell is decided"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -302,6 +302,8 @@ open(out, "w").write(json.dumps(m, sort_keys=True, separators=(",", ":"), ensure
|
|||
PY
|
||||
"$SIGNER" sign "$KEY" "$NEW" > "$NEW.sig"
|
||||
"$SIGNER" verify "$PUB" "$NEW" "$NEW.sig"
|
||||
# the served-file identity guard (9 October 2026, 09:15 UK class): the manifest is a served file; a hit refuses the publish and is logged
|
||||
bash "$TOOLS/ci/served-identity-guard.sh" "$NEW" || { echo "publish-manifest: REFUSED by the served-file identity guard (above); nothing written" >&2; rm -f "$NEW"; exit 1; }
|
||||
mv "$NEW" "$DEST/$MF"
|
||||
mv "$NEW.sig" "$DEST/$MF.sig"
|
||||
echo "manifest: $DEST/$MF"
|
||||
|
|
|
|||
|
|
@ -102,6 +102,7 @@ PY
|
|||
log " $name: would write $(python3 -c 'import json,sys; m=json.load(open(sys.argv[1])); print(m.get("version"), "+".join(m.get("platforms",{})))' "$tmp") with URLs under $BASE_PUB, signed"
|
||||
rm -f "$tmp"; return 0
|
||||
fi
|
||||
bash "$(cd "$(dirname "$0")/../.." && pwd)/tools/ci/served-identity-guard.sh" "$tmp" | scrub || { echo "publish-public: REFUSED by the served-file identity guard (above); nothing written" >&2; rm -f "$tmp"; return 1; } # a served file (9 October 2026 class)
|
||||
"$SIGNER" sign "$KEY" "$tmp" > "$tmp.sig"
|
||||
"$SIGNER" verify "$PUB_KEY" "$tmp" "$tmp.sig" >/dev/null
|
||||
chmod 644 "$tmp" "$tmp.sig"; mv "$tmp" "$out"; mv "$tmp.sig" "$out.sig"
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ What the 5 October rotation already did: the relay token (4 October), the intake
|
|||
|---|---|---|
|
||||
| Items (text, title, who, kind, flags, read and done marks) | Neon table `relay_items` (database `igneum`) | body 1 MB |
|
||||
| Machines (name, hostname, role, GPU and WSL facts, last seen) | Neon table `relay_machines` | |
|
||||
| Files | Vercel Blob store `igneum-relay` (public URLs with random path and suffix, London) | 50 MB per file through a client token; 4 MB when pushed through the function |
|
||||
| Files | Vercel Blob store `igneum-relay` (public URLs with random path and suffix, London) | 128 MB per file through a client token; 4 MB when pushed through the function |
|
||||
| The token and keys | `~/.config/igneum/relay-token`, `relay-key`, `relay-run-key`, `relay-machines/<name>`; project env (`RELAY_TOKEN`, `RELAY_KEY`, `RELAY_RUN_PUB`, `LOG_INTAKE_KEY`, `LOG_INTAKE_KEY_NEXT`) | never in the repo |
|
||||
| Retention | rows older than 30 days are deleted with their blobs, checked on a feed read at most every 10 minutes per instance; `delete` removes the blob with the row (X26) | 30 days |
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import { randomBytes } from 'node:crypto';
|
|||
import { authVia } from './guard.mjs';
|
||||
|
||||
export const MAX_INLINE = 4 * 1024 * 1024; // raw upload through the function (Vercel body cap is 4.5 MB)
|
||||
export const MAX_BLOB = 50 * 1024 * 1024; // direct-to-Blob upload with a client token
|
||||
export const MAX_BLOB = 128 * 1024 * 1024; // direct-to-Blob upload with a client token (128 MB since 9 October 2026: a 2.0.2 Setup is 63.9 MB and the 50 MB token refused it with a 403)
|
||||
export const MAX_BODY = 1024 * 1024; // text body per item
|
||||
// start-app (MF-11, 7 October 2026): a signed, tagged task like `run`, but the agent executes nothing from its body: it
|
||||
// starts the installed Igneum Miner (hidden console, as the user) and reports whether an engine answered. The body
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -291,7 +291,7 @@ main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--lin
|
|||
<div class="tbl"><table><thead><tr><th>Block</th><th class="n">Number</th><th class="n">DAA</th><th class="n">Blue score</th><th>Colour</th><th class="n">Subsidy</th><th class="n">Txs</th><th>Time</th></tr></thead><tbody id="blocks"></tbody></table></div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="note" data-four-words><b>Four words, used exactly.</b> <b>Included</b>: the block carries the transaction. <b>Executed</b>: the EVM ran it and the result is on the record. <b>Proven</b>: a valid proof record for its block was carried and paid. <b>Finalised</b>: the block sits under a certified checkpoint, two thirds of active and of total weight. A pause in finality is shown as a pause, never as a block losing its lock. <b>Recovery lock</b>: after a full weight window with no lock, a checkpoint signed by more than half of the anchored weight; shown as a recovery lock, never as finalised. On the devnet’s current node line the lock kind is reported by the forming node only: a node that received the certificate records an ordinary lock, so a recovery lock can read as final on a receiving node until the 2.0.3 node line lands. The definitions are the finality specification’s: <a href="https://git.igneum.network/igneum-network/igneum/src/branch/master/docs/spec/finality-guarantees.md">section 9, the guarantees</a>.</p>
|
||||
<p class="note" data-four-words><b>Four words, used exactly.</b> <b>Included</b>: the block carries the transaction. <b>Executed</b>: the EVM ran it and the result is on the record. <b>Proven</b>: a valid proof record for its block was carried and paid. <b>Finalised</b>: the block sits under a certified checkpoint, two thirds of active and of total weight. A pause in finality is shown as a pause, never as a block losing its lock. <b>Recovery lock</b>: after a full weight window with no lock, a checkpoint signed by more than half of the anchored weight; shown as a recovery lock, never as final (the Token Value volume’s D05). On the devnet’s current node line the lock kind is reported by the forming node only: a node that received the certificate records an ordinary lock, so a recovery lock can read as final on a receiving node until the 2.0.3 node line lands. The definitions are the finality specification’s: <a href="https://git.igneum.network/igneum-network/igneum/src/branch/master/docs/spec/finality-guarantees.md">section 9, the guarantees</a>.</p>
|
||||
</main>
|
||||
<!-- footer:start -->
|
||||
<footer class="site-footer">
|
||||
|
|
|
|||
|
|
@ -284,7 +284,7 @@ main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--lin
|
|||
<div class="card"><div class="viz-head"><h2>Shard plan and proofs</h2><div class="eyebrow" id="proof-eyebrow"></div></div><div id="proofs"></div></div>
|
||||
<div class="card"><div class="viz-head"><h2>Finality</h2><div class="eyebrow" id="fin-eyebrow"></div></div><div id="finality"></div><div id="recheck"></div></div>
|
||||
</div>
|
||||
<p class="note" data-four-words><b>Four words, used exactly.</b> <b>Included</b>: the block carries the transaction. <b>Executed</b>: the EVM ran it and the result is on the record. <b>Proven</b>: a valid proof record for its block was carried and paid. <b>Finalised</b>: the block sits under a certified checkpoint, two thirds of active and of total weight. A pause in finality is shown as a pause, never as a block losing its lock. <b>Recovery lock</b>: after a full weight window with no lock, a checkpoint signed by more than half of the anchored weight; shown as a recovery lock, never as finalised. On the devnet’s current node line the lock kind is reported by the forming node only: a node that received the certificate records an ordinary lock, so a recovery lock can read as final on a receiving node until the 2.0.3 node line lands. The definitions are the finality specification’s: <a href="https://git.igneum.network/igneum-network/igneum/src/branch/master/docs/spec/finality-guarantees.md">section 9, the guarantees</a>.</p>
|
||||
<p class="note" data-four-words><b>Four words, used exactly.</b> <b>Included</b>: the block carries the transaction. <b>Executed</b>: the EVM ran it and the result is on the record. <b>Proven</b>: a valid proof record for its block was carried and paid. <b>Finalised</b>: the block sits under a certified checkpoint, two thirds of active and of total weight. A pause in finality is shown as a pause, never as a block losing its lock. <b>Recovery lock</b>: after a full weight window with no lock, a checkpoint signed by more than half of the anchored weight; shown as a recovery lock, never as final (the Token Value volume’s D05). On the devnet’s current node line the lock kind is reported by the forming node only: a node that received the certificate records an ordinary lock, so a recovery lock can read as final on a receiving node until the 2.0.3 node line lands. The definitions are the finality specification’s: <a href="https://git.igneum.network/igneum-network/igneum/src/branch/master/docs/spec/finality-guarantees.md">section 9, the guarantees</a>.</p>
|
||||
</main>
|
||||
<!-- footer:start -->
|
||||
<footer class="site-footer">
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
// is never rendered here.
|
||||
// Runs on every deploy (Vercel build command) and locally with `node build.mjs`.
|
||||
import { readFileSync, writeFileSync, existsSync } from 'node:fs';
|
||||
import { spawnSync } from 'node:child_process';
|
||||
import { scrubBench } from './scrub.mjs';
|
||||
import { MARKS, VENDORS, tokensCss, markHtml } from './lib/marks.mjs';
|
||||
import { osHtml } from './lib/os-marks.mjs';
|
||||
|
|
@ -270,6 +271,15 @@ function stampProduct(html, file) {
|
|||
// Igneum 2.0 (8 October 2026): no testnet is served; any leftover paragraph marked data-testnet-notice is removed at build.
|
||||
const DL_HOST = 'https://dl.igneum.network';
|
||||
const DL_SNAPSHOT = join(here, 'downloads.json');
|
||||
const SERVED_GUARD = join(here, '..', 'tools', 'ci', 'served-identity-guard.sh');
|
||||
function guardServed(files) {
|
||||
const present = files.filter((f) => existsSync(f));
|
||||
if (!existsSync(SERVED_GUARD)) { console.log(`served-identity guard: tools/ci/served-identity-guard.sh is not in the tree yet; unguarded this build: ${present.map((f) => f.replace(here + '/', '')).join(', ')}`); return; }
|
||||
const r = spawnSync('bash', [SERVED_GUARD, ...present], { stdio: 'inherit' });
|
||||
if (r.status !== 0) throw new Error(`served-identity guard refused (exit ${r.status}: 1 = a hit, 2 = no private list) on ${present.map((f) => f.replace(here + '/', '')).join(', ')}; nothing is written`);
|
||||
console.log(`served-identity guard: clean on ${present.map((f) => f.replace(here + '/', '')).join(', ')}`);
|
||||
}
|
||||
|
||||
// The snapshot is a tracked file: the build rewrites it only on an explicit refresh (SITE_DOWNLOADS_REFRESH=1 or
|
||||
// --refresh-downloads, the ship pipeline's step, committed with the release), or in CI (a throwaway checkout). A plain
|
||||
// local build, and the pre-push hook, read live but never write: on 6 October 2026 the hook's build stamped 0.3.14's rows
|
||||
|
|
@ -311,6 +321,12 @@ function stampDownloads(html, file, dl) {
|
|||
return html;
|
||||
}
|
||||
const downloads = await loadDownloads();
|
||||
// the served-identity guard (the coordinator's 09:15 class, 9 October 2026: a served file generated from reports or merges
|
||||
// runs the identity grep at its publish step and refuses on a hit): the downloads snapshot and the release manifest (/release.json)
|
||||
// go through tools/ci/served-identity-guard.sh before the served tree is final; exit 1 is a hit, exit 2 no private list, both refuse.
|
||||
// Until the shared guard is in the tree the build says so and goes on, so a landing before it is not held by it.
|
||||
guardServed([DL_SNAPSHOT, join(here, 'release-manifest.json')]);
|
||||
|
||||
built.push(`downloads (${downloads.source}: ${Object.keys(downloads.files || {}).join(', ') || 'none'})`);
|
||||
|
||||
// the evidence page (/evidence): the claims table, the counts and the date are rendered from docs/evidence.md (6 October 2026);
|
||||
|
|
|
|||
|
|
@ -263,7 +263,7 @@
|
|||
<li><strong>Proof verification in consensus.</strong> On the Igneum 2.0 devnet, yes, from block zero (verifier_in_consensus set, the node's own start line; running since its first block at 17:14 UK on 8 October 2026). It is the prerequisite of the no-rescue network exercise (Deliverable 5), which is still owed; an earlier devnet ran with the rule off.</li>
|
||||
<li><strong>Proving on every card.</strong> No. NVIDIA proves; AMD and Apple mine. The proving stack is judged on the full pipeline: inputs, proving, aggregation, verification, payment, memory and the mining income forgone.</li>
|
||||
<li><strong>What proofs do not give.</strong> Proven execution is not automatically finality. EVM compatibility is not Ethereum security. ZK technology does not automatically make transactions private.</li>
|
||||
<li><strong>A ranking.</strong> No. Igneum makes no leading or number-one claim. Published claims name the evaluated release, evidence and boundary conditions. Designed to compete for leadership among GPU-first networks. That is the scoped wording until a ranking is measured (the Token Value volume’s rule VR-30, scoped claims only): an independently substantiated pass of the acceptance standard would not award a numerical rank, nor guarantee adoption, perpetual GPU profitability or the defeat of every future chip. Benchmarks against Ravencoin’s KAWPOW, Ergo and Firo’s reference miner are owed work; no result exists yet.</li>
|
||||
<li><strong>A ranking.</strong> No. Igneum makes no leading or number-one claim. Published claims name the evaluated release, evidence and boundary conditions. Designed to compete for leadership among GPU-first networks. That is the scoped wording until a ranking is measured (the Token Value volume’s rule VR-30 and decision D06, scoped claims only): an independently substantiated pass of the acceptance standard would not award a numerical rank, nor guarantee adoption, perpetual GPU profitability or the defeat of every future chip. Benchmarks against Ravencoin’s KAWPOW, Ergo and Firo’s reference miner are owed work; no result exists yet.</li>
|
||||
<li><strong>A finished protocol.</strong> The sustained-mining finality rule is the newest piece and the one that external review will try hardest to break. The specification, the review and the benchmarks are published as they happen.</li>
|
||||
</ul>
|
||||
<p>Everything in this document is subject to the gates on the roadmap. Nothing in it is an offer to sell anything. Found an error, or a criticism this document does not answer? Email <a href="mailto:hello@igneum.network">hello@igneum.network</a>, or open an issue on the public specification repository: <a href="https://git.igneum.network/igneum-network/spec/issues" rel="noopener">git.igneum.network/igneum-network/spec/issues</a>. Post reaches Igneum Labs LTD, Unit IH-00-01-01-OF-01, Level 01, Innovation One, Dubai International Financial Centre.</p></div>
|
||||
|
|
|
|||
|
|
@ -226,7 +226,7 @@
|
|||
<tr><td>Launch rate</td><td class="num"><span data-rm="fees.emission.launch_rate_base_units_per_daa_second">31,688,087,810,000,000,000</span> base units a DAA second at 18 decimals (the literal 3,168,808,781 of <code>emission.rs</code> 104, 10<sup>9</sup> IGN x 10<sup>8</sup> / 31,557,600 floored, widened by <code>rescaled(DEVNET_DECIMALS, EVM_DECIMALS)</code> at <code>emission.rs</code> 129 in the devnet4 parameters: one billion IGN in year one, the same rate as mainnet)</td><td><code>emission.rs</code> 85 to 123; <code>igneum.rs</code> 34</td></tr>
|
||||
<tr><td>Ramp</td><td class="num">2,592,000 s (30 days) from 10 percent</td><td><code>igneum.rs</code> 76 <code>launch_ramp</code></td></tr>
|
||||
<tr><td>Step</td><td class="num">63,115,200 s (two years), the rate halved each step (decay 2<sup>31</sup> of 2<sup>32</sup>)</td><td><code>emission.rs</code> 85 to 123</td></tr>
|
||||
<tr><td>Tail</td><td class="num">none in the code: the curve runs to zero and the sum is the hard cap, 4,000,000,000 IGN; the tail and the cap are pending decisions of the Token Value volume (D01 to D06)</td><td><code>emission.rs</code> 69 to 71</td></tr>
|
||||
<tr><td>Tail</td><td class="num">none in the code: the curve runs to zero and the sum is the hard cap, 4,000,000,000 IGN; the cap is fixed with no tail emission and no vote that expands it (the Token Value volume’s D01, subject to the pre-launch security-funding gate)</td><td><code>emission.rs</code> 69 to 71</td></tr>
|
||||
<tr><td>Where each runs</td><td>The Igneum 2.0 devnet (18 decimals, the rescaled schedule); mainnet (18)</td><td><code>params.rs</code> 2158, 1764</td></tr>
|
||||
</tbody>
|
||||
</table></div>
|
||||
|
|
@ -250,13 +250,13 @@
|
|||
<tr><td>Base fee, execution gas</td><td>burned in full: gas used times the execution base fee, debited and credited to no one</td><td>in the code on the devnet</td><td><code>igneum/exec/src/executor.rs</code> 320 to 371 (327 and 357, 328 and 360)</td></tr>
|
||||
<tr><td>Priority fee (the tip)</td><td><span data-rm="fees.priority_fee.miner_percent">80</span> percent to the block’s miner; <span data-rm="fees.priority_fee.developer_percent">20</span> percent to the developer registrations of the contracts whose code ran, pro rata by each frame’s gas; an unregistered frame’s part is credited to nobody, which is a burn</td><td>in the code on the devnet</td><td><code>executor.rs</code> 335 to 339; <code>igneum/exec/src/pgas.rs</code> 290; <code>igneum/exec/src/config.rs</code> 76 (<code>DEVELOPER_SHARE_PERCENT = 20</code>)</td></tr>
|
||||
<tr><td>The proving payment</td><td>pgas used times the proving base fee, the congestion price of proving capacity: 90 percent to the block’s proving pool, paid per shard to its provers by consensus proving cost; 10 percent burned</td><td>designed, in the code behind the constant (<code>Params::proving_payment_activation_daa</code>, never on every object, on the fork branch proving-payment); the shard guest’s mirror of the split is owed before any height; on the 2.0 devnet the proving charge burns in full</td><td>spec 05 sections 5.1 and 5.3; <code>docs/design/proving-payment.md</code> (8 October 2026)</td></tr>
|
||||
<tr><td>External proving jobs</td><td>90 percent to the provers who delivered, 10 percent burned, once jobs settle in IGN</td><td>designed, not in the code: no constant exists; at launch a job is paid on the customer’s own chain</td><td>spec 05 section 5.4; the litepaper’s Proving section</td></tr>
|
||||
<tr><td>External proving jobs</td><td>90 percent to the provers who delivered, 10 percent burned, once jobs settle in IGN</td><td>designed, not in the code: no constant exists; at launch a job is paid on the customer’s own chain and the charge is not yet set (D04)</td><td>spec 05 section 5.4; the litepaper’s Proving section</td></tr>
|
||||
<tr><td>The provers’ part of the tip</td><td>none: no part of the tip reaches the provers; the tip stays whole to the block (spec O-5.7 closed at zero, 8 October 2026)</td><td>in the code</td><td><code>docs/design/proving-payment.md</code>; <code>executor.rs</code> 335 to 339</td></tr>
|
||||
</tbody>
|
||||
</table></div>
|
||||
|
||||
<h2>The proving-fee market</h2>
|
||||
<p>A card’s second income is the proving pool: 20 percent of every block, paid per shard against a valid proof record, plus 90 percent of every block’s proving payment, which users pay at the congestion price of proving capacity (designed; on the devnet that payment is still burned in full). Nothing from the priority fee, which stays whole to the block. The reason the design routes the proving charge to the provers: the operator simulation reads a fixed internal pool as a subsidy, not a price, and only the congestion-priced user-funded fee restores service after a lasting proving spike (35 periods against never; modelled). The price a prover must charge an outside customer is the subsidy it forgoes while it proves, which falls as one over the network’s hash rate; the market itself is designed and not built. The hard cap and the absence of any development fund are unchanged in the code; both sit among the pending monetary decisions of the Token Value volume (D01 to D06).</p>
|
||||
<p>A card’s second income is the proving pool: 20 percent of every block, paid per shard against a valid proof record, plus 90 percent of every block’s proving payment, which users pay at the congestion price of proving capacity (designed; on the devnet that payment is still burned in full). Nothing from the priority fee, which stays whole to the block. The reason the design routes the proving charge to the provers: the operator simulation reads a fixed internal pool as a subsidy, not a price, and only the congestion-priced user-funded fee restores service after a lasting proving spike (35 periods against never; modelled). The price a prover must charge an outside customer is the subsidy it forgoes while it proves, which falls as one over the network’s hash rate; the market itself is designed and not built. The hard cap and the absence of any development fund are unchanged: the cap is fixed (D01); every fee and burn route on this page is explicit, the 80/20 coinbase is an emission allocation only, and external-job charges are not yet set (D04).</p>
|
||||
|
||||
<h2>The client fee and the fund it fills</h2>
|
||||
<div class="tbl"><table>
|
||||
|
|
|
|||
|
|
@ -326,7 +326,7 @@ main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--lin
|
|||
<p class="note">Every answer names the network (the Igneum 2.0 devnet) and the chain id the node reports (4465). The RPC itself is at rpc.devnet.igneum.network (read methods and eth_sendRawTransaction, 20 requests per second per address).</p>
|
||||
</div>
|
||||
</div>
|
||||
<p class="note" data-four-words><b>Four words, used exactly.</b> <b>Included</b>: the block carries the transaction. <b>Executed</b>: the EVM ran it and the result is on the record. <b>Proven</b>: a valid proof record for its block was carried and paid. <b>Finalised</b>: the block sits under a certified checkpoint, two thirds of active and of total weight. A pause in finality is shown as a pause, never as a block losing its lock. <b>Recovery lock</b>: after a full weight window with no lock, a checkpoint signed by more than half of the anchored weight; shown as a recovery lock, never as finalised. On the devnet’s current node line the lock kind is reported by the forming node only: a node that received the certificate records an ordinary lock, so a recovery lock can read as final on a receiving node until the 2.0.3 node line lands. The definitions are the finality specification’s: <a href="https://git.igneum.network/igneum-network/igneum/src/branch/master/docs/spec/finality-guarantees.md">section 9, the guarantees</a>.</p>
|
||||
<p class="note" data-four-words><b>Four words, used exactly.</b> <b>Included</b>: the block carries the transaction. <b>Executed</b>: the EVM ran it and the result is on the record. <b>Proven</b>: a valid proof record for its block was carried and paid. <b>Finalised</b>: the block sits under a certified checkpoint, two thirds of active and of total weight. A pause in finality is shown as a pause, never as a block losing its lock. <b>Recovery lock</b>: after a full weight window with no lock, a checkpoint signed by more than half of the anchored weight; shown as a recovery lock, never as final (the Token Value volume’s D05). On the devnet’s current node line the lock kind is reported by the forming node only: a node that received the certificate records an ordinary lock, so a recovery lock can read as final on a receiving node until the 2.0.3 node line lands. The definitions are the finality specification’s: <a href="https://git.igneum.network/igneum-network/igneum/src/branch/master/docs/spec/finality-guarantees.md">section 9, the guarantees</a>.</p>
|
||||
</main>
|
||||
<!-- footer:start -->
|
||||
<footer class="site-footer">
|
||||
|
|
|
|||
|
|
@ -446,7 +446,7 @@ blockquote{margin:10px 0;padding:10px 14px;border-left:3px solid var(--line-2);c
|
|||
<blockquote>You claim to be the best GPU network before anyone outside has checked anything.</blockquote>
|
||||
<div class="status"><span class="badge b-conceded">Conceded</span> <span class="did">8 October 2026): no "number one" claim before comparative results and adoption exist.</span></div>
|
||||
<div class="pin"><b>Pin</b> Leadership tests, fifth box (served ranking language); second to fourth boxes.</div>
|
||||
<details><summary>The answer as first written</summary><p>No present-tense rank is served. Published claims name the evaluated release, evidence and boundary conditions. Designed to compete for leadership among GPU-first networks. That is the scoped wording until a ranking is measured (the Token Value volume’s rule VR-30, scoped claims only, 9 October 2026): an independently substantiated pass of the acceptance standard would not award a numerical rank, nor guarantee adoption, perpetual GPU profitability or the defeat of every future chip. The tests that would earn it are miners staying through hard conditions, customers repeatedly paying for proofs, and the network running without the founding team (D5); none is met yet.</p></details>
|
||||
<details><summary>The answer as first written</summary><p>No present-tense rank is served. Published claims name the evaluated release, evidence and boundary conditions. Designed to compete for leadership among GPU-first networks. That is the scoped wording until a ranking is measured (the Token Value volume’s rule VR-30 and decision D06, scoped claims only, ratified 9 October 2026): an independently substantiated pass of the acceptance standard would not award a numerical rank, nor guarantee adoption, perpetual GPU profitability or the defeat of every future chip. The tests that would earn it are miners staying through hard conditions, customers repeatedly paying for proofs, and the network running without the founding team (D5); none is met yet.</p></details>
|
||||
</article>
|
||||
|
||||
<p class="intro" style="margin-top:var(--sec)">Source: the project's Igneum 2.0 criticism ledger, a file in the repository, rendered to this page at build time. A criticism that is not here, or that shows an entry is wrong, is added with credit if wanted: <a href="mailto:hello@igneum.network">hello@igneum.network</a> or <a href="https://git.igneum.network/igneum-network/spec/issues" rel="noopener">an issue on the specification repository</a>.</p>
|
||||
|
|
|
|||
|
|
@ -303,7 +303,7 @@ body.all .pager{display:none}
|
|||
</div>
|
||||
<div class="meta">
|
||||
<span>Published <b>3 October 2026</b> · updated <b>8 October 2026</b></span>
|
||||
<span>Coin <b>IGN</b> · cap <b>4,000,000,000</b> (a decision pending)</span>
|
||||
<span>Coin <b>IGN</b> · cap <b>4,000,000,000</b> (fixed, D01)</span>
|
||||
<span>Status <b>The Igneum 2.0 devnet is live</b></span>
|
||||
<span>Method <b>one founder with AI systems</b> · external review before gate 3</span>
|
||||
<span>This is not an offer to sell anything</span>
|
||||
|
|
@ -361,7 +361,7 @@ body.all .pager{display:none}
|
|||
<tr><td>The mining card does paid, useful, verifiable work</td><td>Primecoin's prime chains in 2013 were not useful. Aleo ran proving as consensus and the fastest prover won (both approximate)</td><td>Proving kept apart from the lottery; shards assigned by sortition, not by speed</td><td>Implemented: proving v0 and v1 on the devnet from block zero, on NVIDIA cards. The job market for other chains is Designed</td></tr>
|
||||
<tr><td>A proof-of-work chain where every block is proven</td><td>Proven-execution EVM chains run as rollups on proof-of-stake Ethereum. Conflux has run GPU-mined EVM apps on a DAG since 2020, without proofs (approximate)</td><td>Proven state on a proof-of-work base layer, produced by the miners themselves</td><td>Implemented: shards proven and paid on the devnet; proof verification enforced in consensus from block zero on the Igneum 2.0 devnet (running since 17:14 UK on 8 October 2026)</td></tr>
|
||||
<tr><td>Finality held by miners and not moved by hour-long rentals</td><td>Decred votes with stake. Horizen penalises hidden chains. Kaspa limits merge depth (approximate)</td><td>Vote weight is 30 days of blocks per key. Hashrate that appeared today has no vote</td><td>Implemented: rule v3 live on the devnet from block zero. External review is owed at gate 3</td></tr>
|
||||
<tr><td>100% of emission to the people running the hardware</td><td>Kaspa's fair launch. Zcash and Decred fund developers from emission (approximate)</td><td>No fee to any team, foundation or fund in the protocol. The miner software's optional 1% dev fee is the one payment to the project, off with one flag</td><td>Implemented in consensus: the 80/20 coinbase on the devnet</td></tr>
|
||||
<tr><td>100% of emission to the people running the hardware</td><td>Kaspa's fair launch. Zcash and Decred fund developers from emission (approximate)</td><td>No fee to any team, foundation or fund in the protocol. The miner software's optional 1% dev fee is the one payment to the project, off with one flag</td><td>Implemented in consensus: the 80/20 coinbase on the devnet (an emission allocation only, D04)</td></tr>
|
||||
<tr><td>A chain your browser verifies by itself</td><td>Light clients trust a committee, as Ethereum's trust a sync committee (approximate)</td><td>At launch, one execution proof plus a certificate the client is given. The consensus proof that makes the checkpoint self-verifying is phase two</td><td>Designed. The home page's card verifies a devnet certificate in the browser today, with the voter list taken from a node</td></tr>
|
||||
</tbody>
|
||||
</table></div>
|
||||
|
|
@ -533,7 +533,7 @@ body.all .pager{display:none}
|
|||
<h3>The proving budget</h3>
|
||||
<p>Gas prices execution. Proving cost is a different number, so Igneum meters it separately: every transaction pays in both dimensions, and each block has a proving-cost budget set in consensus from measured prover throughput. A transaction that is cheap to run and expensive to prove pays for what it costs the provers. Measured on 5 October 2026 (an RTX 5090 under SP1 6.8.1's GPU prover, the shard size the chain adopts from its fee switch, 30,000 proving gas, about 4.7 million prover cycles): one full shard proves in 4.3 seconds and needs 20.4 GB of GPU memory with the card to itself, so a 24 GB card proves full shards and a 12 GB or 16 GB card does not on this prover build, whose floor is 13.9 GB for even an empty shard; mining and proving on one card needs 32 GB today (the prototype-size shard beside the miner peaked at 30.1 GB) and 24 GB once the adopted shard size is live (22.2 GB beside the miner, 13.2 seconds a shard, measured on the 32 GB card; a 24 GB card has not run it yet). The old 12 GB gate on the roadmap was withdrawn on 5 October until a prover build with a smaller floor was measured; on 6 October a patched server proved the same shard at 7.4 to 8.0 GB alone on eleven rented cards from the RTX 3060 to the RTX 5090 (the real-card table), so the gate returns as measured and the patched server is not yet in the shipped app. The first proofs exist: on 4 October 2026 an RTX 5090 proved a small two-transaction block in 1.4 seconds (2.7 seconds compressed), verified in 0.22 and 0.038 seconds, and a laptop CPU proved a three-shard block end to end in 19 minutes. Later that day the same card proved a full shard at the provisional size, 6.75 million prover gas, which executed in 60.8 million cycles: core proof 8.3 seconds, compressed proof 10.9 seconds, verified in 0.040 seconds; a four-shard block took 44.5 seconds of GPU stages end to end. Shards are assigned and proven on the devnet from block zero. The gate asks for a mid-range card, and an RTX 5090 is not one, so the gate stands open. Once the gate is measured, the budget rises by schedule as hardware improves. The proof system is hash-based, which is what runs on consumer cards, and sits behind a versioned interface. SP1 is the one backend. A replacement is adopted only where justified, by a miner-signalled release, never as an interchangeable second backend, and the chain runs for ever on the current one if none is adopted.</p>
|
||||
<h3>Proving for everyone else</h3>
|
||||
<p>The job market for other chains is Designed, not built, and stays out of every revenue assumption until it is. The order: Igneum's own execution first; then one external customer's exact workload with repeat paid jobs; further workloads only where the fleet has a demonstrated edge. As designed, a customer posts a job, a miner wins it, proves it, and is paid, and the market is permissionless. At launch a job is paid on the customer's own chain, in the customer's currency, to a payout contract keyed by miner address, because Igneum cannot yet see Ethereum. Settlement in IGN, with 10% of each fee burned, follows when the proof bridge lets Igneum see the payment, in phase two. The Igneum miner client can also bid on other proving networks and take the best price, where a miner chooses to hold their collateral: Boundless provers post ZKC and Succinct provers stake PROVE (approximate, from their documentation). The proving market is small today. Igneum does not depend on it. We know of no proof-of-work chain that sells proofs to other chains.</p>
|
||||
<p>The job market for other chains is Designed, not built, and stays out of every revenue assumption until it is. The order: Igneum's own execution first; then one external customer's exact workload with repeat paid jobs; further workloads only where the fleet has a demonstrated edge. As designed, a customer posts a job, a miner wins it, proves it, and is paid, and the market is permissionless. At launch a job is paid on the customer's own chain, in the customer's currency, to a payout contract keyed by miner address, because Igneum cannot yet see Ethereum. The charge itself is not yet set (D04). Settlement in IGN, with 10% of each fee burned, follows when the proof bridge lets Igneum see the payment, in phase two. The Igneum miner client can also bid on other proving networks and take the best price, where a miner chooses to hold their collateral: Boundless provers post ZKC and Succinct provers stake PROVE (approximate, from their documentation). The proving market is small today. Igneum does not depend on it. We know of no proof-of-work chain that sells proofs to other chains.</p>
|
||||
</section>
|
||||
|
||||
<section id="finality">
|
||||
|
|
@ -575,7 +575,7 @@ body.all .pager{display:none}
|
|||
<h2>Economics</h2>
|
||||
<p>The coin is IGN. It is gas and the proving currency, and part of every payment on Igneum is burned. Outside customers pay in their own currency on their own chain at launch; settlement in IGN with a 10% burn follows when the proof bridge lets Igneum see the payment, in phase two.</p>
|
||||
<h3>Supply</h3>
|
||||
<p>Fair launch. No premine, no pre-sale, no allocation to anyone. The supply schedule, the cap, the tail and the fee routes are the six monetary decisions D01 to D06 of the Token Value volume, pending; what follows is the devnet’s code today, not a promise. Hard cap of 4 billion IGN, approached and never reached, because emission starts at 1 billion a year and halves every two years for ever. Nearly a quarter of all supply is mined in the first year and half in the first two. Emission ramps from 10% to 100% over the first 30 days so that nobody takes the first month before the rest of the world hears about it.</p>
|
||||
<p>Fair launch. No premine, no pre-sale, no allocation to anyone. The cap, the schedule, the fee routes and the finality display are the Token Value volume’s decisions, ratified on 9 October 2026 (D01 to D06): the cap is fixed with no tail emission and no vote that expands it, subject to the pre-launch security-funding gate (D01); the schedule’s pacing is under comparison and not final (D02); every fee and burn route is published explicitly, the 80/20 figure is an emission allocation only, and external-job charges are not yet set (D04); a recovery certificate is never shown as final (D05). A ratified decision is a rule, not a promise of value. Hard cap of 4 billion IGN, approached and never reached, because emission starts at 1 billion a year and halves every two years for ever; the pacing is under comparison and not final (D02). Nearly a quarter of all supply is mined in the first year and half in the first two. Emission ramps from 10% to 100% over the first 30 days so that nobody takes the first month before the rest of the world hears about it.</p>
|
||||
<div class="figure">
|
||||
<svg viewBox="0 0 760 300" role="img" aria-label="Half of the 4 billion cap is mined in the first two years" font-family="IBM Plex Mono, monospace" font-size="12">
|
||||
<text x="40" y="26" font-family="IBM Plex Sans, system-ui, sans-serif" font-size="15" font-weight="600" fill="var(--ink)">Half of the 4 billion cap is mined in the first two years</text>
|
||||
|
|
@ -611,13 +611,13 @@ body.all .pager{display:none}
|
|||
</tbody>
|
||||
</table></div>
|
||||
<h3>Where fees go</h3>
|
||||
<p>The base fee of every transaction is burned in full, Ethereum's rule, so a miner cannot fill blocks with its own transactions for free. The priority fee splits two ways: 80% to the miner and provers of that block, 20% to the apps whose code ran, by gas consumed inside each. External proving fees, once they settle on Igneum, pay 90% to the provers who delivered and burn 10%. The hard cap in the devnet’s code fixes supply today (a decision pending). Emission is untouched by any of this: every coin minted still goes to miners and provers.</p>
|
||||
<p>The base fee of every transaction is burned in full, Ethereum's rule, so a miner cannot fill blocks with its own transactions for free. The priority fee splits two ways: 80% to the miner and provers of that block, 20% to the apps whose code ran, by gas consumed inside each. External proving fees, once they settle on Igneum, pay 90% to the provers who delivered and burn 10%. The hard cap fixes supply (D01). Emission is untouched by any of this: every coin minted still goes to miners and provers.</p>
|
||||
<h3>Every payment route</h3>
|
||||
<p>One row per route, so operator income and protocol income never blur. The protocol pays no address of its own, and a burn pays nobody. Rows 1 to 5 are the protocol. Row 6 is the project's software, outside the protocol, and is never added to the other five.</p>
|
||||
<div class="tbl"><table>
|
||||
<thead><tr><th>Route</th><th>Currency</th><th>Recipient</th><th>Fee</th><th>Burn</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>1. Emission, per block</td><td>IGN, new coins on the schedule above</td><td>80% the block's miner, 20% the proving pool for the provers of that block</td><td>None</td><td>None. Implemented in consensus: the 80/20 coinbase on the devnet</td></tr>
|
||||
<tr><td>1. Emission, per block</td><td>IGN, new coins on the schedule above</td><td>80% the block's miner, 20% the proving pool for the provers of that block</td><td>None</td><td>None. Implemented in consensus: the 80/20 coinbase on the devnet (an emission allocation only, D04)</td></tr>
|
||||
<tr><td>2. Base fee, both gas dimensions</td><td>IGN</td><td>Nobody</td><td>The base fee the chain sets per block</td><td>All of it. Implemented on the devnet</td></tr>
|
||||
<tr><td>3. Priority fee</td><td>IGN</td><td>80% the block's miner and provers; 20% the apps whose code ran, per call frame</td><td>The tip the sender sets</td><td>The share of any frame in an unregistered contract. Implemented on the devnet</td></tr>
|
||||
<tr><td>4. External job, at launch</td><td>The customer's currency, on the customer's chain</td><td>The miner who delivered, through a payout contract keyed by miner address</td><td>Priced in the customer's money per proof, at or above the subsidy the prover forgoes (a formula in network hash, under Building on Igneum, never a fixed number); the customer chain's own bond and slashing apply</td><td>None; Igneum cannot see the payment. Designed</td></tr>
|
||||
|
|
@ -627,7 +627,7 @@ body.all .pager{display:none}
|
|||
</table></div>
|
||||
<p class="src"><b>Sources:</b> specification sections 2.5 and 5.1 to 5.4; the measurement record in the repository (docs/bench-log.md) for the earlier devnet's receipts and the dev-fee count.</p>
|
||||
<h3>Security after the subsidy</h3>
|
||||
<p>The cap stays at 4 billion in the code today, and no tail emission is coded; the year-five tail vote below is written beside that, an unresolved tension and a pending decision (D01 to D06), not a promise. The schedule is a bet, not a measurement: a halving halves emission income overnight if price and fees do nothing. Kaspa's steeper monthly reduction kept its hashrate while its price rose (approximate). Long term, security has to be paid by fees and, if it is built and bought, the proving market. The external market is Designed, not built, and is out of the numbers below. As designed, outside customers buy proofs as dollars-priced work settled in IGN, and 90% of every job goes to the provers who delivered it. The table shows the first year in which the block subsidy on its own pays miners less than the power of about 3,000 consumer cards, at three flat prices. The prices are inputs chosen to span two orders of magnitude. The model (modelled, 3 October 2026) runs a 300 W card at 124 MH/s on electricity at USD 0.12 per kWh. One rule sits beside the cap. If external proving revenue is under one fifth of the block subsidy over any 90-day window after year 5, the question of a tail reward goes to the miners' signalling vote. The protocol never changes emission by itself.</p>
|
||||
<p>The cap is fixed at 4 billion, with no tail emission and no vote that expands it (D01, subject to the pre-launch security-funding gate). The schedule is a bet, not a measurement: a halving halves emission income overnight if price and fees do nothing. Kaspa's steeper monthly reduction kept its hashrate while its price rose (approximate). Long term, security has to be paid by fees and, if it is built and bought, the proving market. The external market is Designed, not built, and is out of the numbers below. As designed, outside customers buy proofs as dollars-priced work settled in IGN, and 90% of every job goes to the provers who delivered it. The table shows the first year in which the block subsidy on its own pays miners less than the power of about 3,000 consumer cards, at three flat prices. The prices are inputs chosen to span two orders of magnitude. The model (modelled, 3 October 2026) runs a 300 W card at 124 MH/s on electricity at USD 0.12 per kWh. One rule sits beside the cap. If external proving revenue is under one fifth of the block subsidy over any 90-day window after year 5, the answer is the security-funding plan under D01, never a tail emission or a vote that expands the cap. The protocol never changes emission by itself.</p>
|
||||
<div class="tbl"><table>
|
||||
<thead><tr><th>Price per IGN</th><th>First year the subsidy alone pays under the power of 3,000 cards</th><th>Subsidy to miners that year</th></tr></thead>
|
||||
<tbody>
|
||||
|
|
@ -868,7 +868,7 @@ body.all .pager{display:none}
|
|||
<li><strong>Proof verification in consensus.</strong> On the Igneum 2.0 devnet, yes, from block zero (verifier_in_consensus set, the node's own start line; running since its first block at 17:14 UK on 8 October 2026). It is the prerequisite of the no-rescue network exercise (Deliverable 5), which is still owed; an earlier devnet ran with the rule off.</li>
|
||||
<li><strong>Proving on every card.</strong> No. NVIDIA proves; AMD and Apple mine. The proving stack is judged on the full pipeline: inputs, proving, aggregation, verification, payment, memory and the mining income forgone.</li>
|
||||
<li><strong>What proofs do not give.</strong> Proven execution is not automatically finality. EVM compatibility is not Ethereum security. ZK technology does not automatically make transactions private.</li>
|
||||
<li><strong>A ranking.</strong> No. Igneum makes no leading or number-one claim. Published claims name the evaluated release, evidence and boundary conditions. Designed to compete for leadership among GPU-first networks. That is the scoped wording until a ranking is measured (the Token Value volume’s rule VR-30, scoped claims only): an independently substantiated pass of the acceptance standard would not award a numerical rank, nor guarantee adoption, perpetual GPU profitability or the defeat of every future chip. Benchmarks against Ravencoin’s KAWPOW, Ergo and Firo’s reference miner are owed work; no result exists yet.</li>
|
||||
<li><strong>A ranking.</strong> No. Igneum makes no leading or number-one claim. Published claims name the evaluated release, evidence and boundary conditions. Designed to compete for leadership among GPU-first networks. That is the scoped wording until a ranking is measured (the Token Value volume’s rule VR-30 and decision D06, scoped claims only): an independently substantiated pass of the acceptance standard would not award a numerical rank, nor guarantee adoption, perpetual GPU profitability or the defeat of every future chip. Benchmarks against Ravencoin’s KAWPOW, Ergo and Firo’s reference miner are owed work; no result exists yet.</li>
|
||||
<li><strong>A finished protocol.</strong> The sustained-mining finality rule is the newest piece and the one that external review will try hardest to break. The specification, the review and the benchmarks are published as they happen.</li>
|
||||
</ul>
|
||||
<p>Everything in this document is subject to the gates on the roadmap. Nothing in it is an offer to sell anything. Found an error, or a criticism this document does not answer? Email <a href="mailto:hello@igneum.network">hello@igneum.network</a>, or open an issue on the public specification repository: <a href="https://git.igneum.network/igneum-network/spec/issues" rel="noopener">git.igneum.network/igneum-network/spec/issues</a>. Post reaches Igneum Labs LTD, Unit IH-00-01-01-OF-01, Level 01, Innovation One, Dubai International Financial Centre.</p>
|
||||
|
|
|
|||
|
|
@ -513,7 +513,7 @@ details.tablebar summary{display:flex;align-items:center}
|
|||
</details>
|
||||
|
||||
<div class="obs-foot"><span>Igneum / observatory</span><span>One node read every 2 s. Nothing here is a replay.</span></div>
|
||||
<p class="note" data-four-words><b>Four words, used exactly.</b> <b>Included</b>: the block carries the transaction. <b>Executed</b>: the EVM ran it and the result is on the record. <b>Proven</b>: a valid proof record for its block was carried and paid. <b>Finalised</b>: the block sits under a certified checkpoint, two thirds of active and of total weight. A pause in finality is shown as a pause, never as a block losing its lock. <b>Recovery lock</b>: after a full weight window with no lock, a checkpoint signed by more than half of the anchored weight; shown as a recovery lock, never as finalised. On the devnet’s current node line the lock kind is reported by the forming node only: a node that received the certificate records an ordinary lock, so a recovery lock can read as final on a receiving node until the 2.0.3 node line lands. The definitions are the finality specification’s: <a href="https://git.igneum.network/igneum-network/igneum/src/branch/master/docs/spec/finality-guarantees.md">section 9, the guarantees</a>.</p>
|
||||
<p class="note" data-four-words><b>Four words, used exactly.</b> <b>Included</b>: the block carries the transaction. <b>Executed</b>: the EVM ran it and the result is on the record. <b>Proven</b>: a valid proof record for its block was carried and paid. <b>Finalised</b>: the block sits under a certified checkpoint, two thirds of active and of total weight. A pause in finality is shown as a pause, never as a block losing its lock. <b>Recovery lock</b>: after a full weight window with no lock, a checkpoint signed by more than half of the anchored weight; shown as a recovery lock, never as final (the Token Value volume’s D05). On the devnet’s current node line the lock kind is reported by the forming node only: a node that received the certificate records an ordinary lock, so a recovery lock can read as final on a receiving node until the 2.0.3 node line lands. The definitions are the finality specification’s: <a href="https://git.igneum.network/igneum-network/igneum/src/branch/master/docs/spec/finality-guarantees.md">section 9, the guarantees</a>.</p>
|
||||
</main>
|
||||
|
||||
<!-- footer:start -->
|
||||
|
|
|
|||
|
|
@ -303,7 +303,7 @@ main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--lin
|
|||
<dl id="totals"></dl>
|
||||
</div>
|
||||
</div>
|
||||
<p class="note" data-four-words><b>Four words, used exactly.</b> <b>Included</b>: the block carries the transaction. <b>Executed</b>: the EVM ran it and the result is on the record. <b>Proven</b>: a valid proof record for its block was carried and paid. <b>Finalised</b>: the block sits under a certified checkpoint, two thirds of active and of total weight. A pause in finality is shown as a pause, never as a block losing its lock. <b>Recovery lock</b>: after a full weight window with no lock, a checkpoint signed by more than half of the anchored weight; shown as a recovery lock, never as finalised. On the devnet’s current node line the lock kind is reported by the forming node only: a node that received the certificate records an ordinary lock, so a recovery lock can read as final on a receiving node until the 2.0.3 node line lands. The definitions are the finality specification’s: <a href="https://git.igneum.network/igneum-network/igneum/src/branch/master/docs/spec/finality-guarantees.md">section 9, the guarantees</a>.</p>
|
||||
<p class="note" data-four-words><b>Four words, used exactly.</b> <b>Included</b>: the block carries the transaction. <b>Executed</b>: the EVM ran it and the result is on the record. <b>Proven</b>: a valid proof record for its block was carried and paid. <b>Finalised</b>: the block sits under a certified checkpoint, two thirds of active and of total weight. A pause in finality is shown as a pause, never as a block losing its lock. <b>Recovery lock</b>: after a full weight window with no lock, a checkpoint signed by more than half of the anchored weight; shown as a recovery lock, never as final (the Token Value volume’s D05). On the devnet’s current node line the lock kind is reported by the forming node only: a node that received the certificate records an ordinary lock, so a recovery lock can read as final on a receiving node until the 2.0.3 node line lands. The definitions are the finality specification’s: <a href="https://git.igneum.network/igneum-network/igneum/src/branch/master/docs/spec/finality-guarantees.md">section 9, the guarantees</a>.</p>
|
||||
</main>
|
||||
<!-- footer:start -->
|
||||
<footer class="site-footer">
|
||||
|
|
|
|||
|
|
@ -265,7 +265,7 @@
|
|||
<p class="note">One node is read every 2 s; the window is the last 120 s. Under reduced motion each scene draws a still frame on every reply. Add <code>?only=a</code>, <code>b</code> or <code>c</code> to the address for one scene full width.</p>
|
||||
</div>
|
||||
</section>
|
||||
<p class="note" data-four-words><b>Four words, used exactly.</b> <b>Included</b>: the block carries the transaction. <b>Executed</b>: the EVM ran it and the result is on the record. <b>Proven</b>: a valid proof record for its block was carried and paid. <b>Finalised</b>: the block sits under a certified checkpoint, two thirds of active and of total weight. A pause in finality is shown as a pause, never as a block losing its lock. <b>Recovery lock</b>: after a full weight window with no lock, a checkpoint signed by more than half of the anchored weight; shown as a recovery lock, never as finalised. On the devnet’s current node line the lock kind is reported by the forming node only: a node that received the certificate records an ordinary lock, so a recovery lock can read as final on a receiving node until the 2.0.3 node line lands. The definitions are the finality specification’s: <a href="https://git.igneum.network/igneum-network/igneum/src/branch/master/docs/spec/finality-guarantees.md">section 9, the guarantees</a>.</p>
|
||||
<p class="note" data-four-words><b>Four words, used exactly.</b> <b>Included</b>: the block carries the transaction. <b>Executed</b>: the EVM ran it and the result is on the record. <b>Proven</b>: a valid proof record for its block was carried and paid. <b>Finalised</b>: the block sits under a certified checkpoint, two thirds of active and of total weight. A pause in finality is shown as a pause, never as a block losing its lock. <b>Recovery lock</b>: after a full weight window with no lock, a checkpoint signed by more than half of the anchored weight; shown as a recovery lock, never as final (the Token Value volume’s D05). On the devnet’s current node line the lock kind is reported by the forming node only: a node that received the certificate records an ordinary lock, so a recovery lock can read as final on a receiving node until the 2.0.3 node line lands. The definitions are the finality specification’s: <a href="https://git.igneum.network/igneum-network/igneum/src/branch/master/docs/spec/finality-guarantees.md">section 9, the guarantees</a>.</p>
|
||||
</main>
|
||||
<!-- footer:start -->
|
||||
<footer class="site-footer">
|
||||
|
|
|
|||
|
|
@ -230,7 +230,7 @@
|
|||
<tr><td><b>Independent operation</b><div class="kv">D5</div></td><td>No-founder exercise on the real implementation.</td><td>A centrally supported demo.</td><td>PENDING: the no-rescue network exercise is owed; the devnet is the project’s own machines, its rented fleet and a few outside laptops.</td></tr>
|
||||
<tr><td><b>Commercial demand</b><div class="kv">Architecture and product</div></td><td>Repeat paid external jobs and workable operator margins.</td><td>Devnet payouts or subsidised volume.</td><td>EXCLUDED from every revenue figure today: the external proving market is designed, not built; no external job has been paid.</td></tr>
|
||||
<tr><td><b>Long-term funding</b><div class="kv">D4</div></td><td>Internal proving and security payments and maintenance runway.</td><td>Burn accounting or assumed appreciation.</td><td>MODELLED: the proving model on the economics page walks the halvings at today’s shard and key counts; the proving payment’s routing is designed behind its constant, burned in full today.</td></tr>
|
||||
<tr><td><b>Leadership</b><div class="kv">Leadership tests</div></td><td>Comparative results, adoption, retention and reliability over time.</td><td>A roadmap or unsupported rank.</td><td>EXCLUDED: no rank is claimed; the served wording until a ranking is measured is “Designed to compete for leadership among GPU-first networks.” (VR-30); the comparison set (Ravencoin KAWPOW, Ergo, Firo’s reference miner) is owed work, not a result.</td></tr>
|
||||
<tr><td><b>Leadership</b><div class="kv">Leadership tests</div></td><td>Comparative results, adoption, retention and reliability over time.</td><td>A roadmap or unsupported rank.</td><td>EXCLUDED: no rank is claimed; the served wording until a ranking is measured is “Designed to compete for leadership among GPU-first networks.” (VR-30, D06); the comparison set (Ravencoin KAWPOW, Ergo, Firo’s reference miner) is owed work, not a result.</td></tr>
|
||||
</tbody>
|
||||
</table></div>
|
||||
<p class="src"><b>Source:</b> <code>docs/plans/igneum-2.0-plan.txt</code>, section 23 (the acceptance scorecard) and the pins in <code>docs/plans/igneum-2.0.md</code>; the Today column is the facts page’s label for the rows each gate cites, and moves only with those rows. The five labels: TEAM-REPORTED, MODELLED, PROPOSED, PENDING, EXCLUDED. The public mirror follows master; a link that answers 404 is a file not yet synced.</p>
|
||||
|
|
|
|||
|
|
@ -279,7 +279,7 @@ main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--lin
|
|||
<div class="card"><div class="viz-head"><h2>Block and proof</h2><div class="eyebrow" id="blk-eyebrow"></div></div><dl id="blk"></dl></div>
|
||||
<div class="card"><div class="viz-head"><h2>Logs</h2><div class="eyebrow" id="log-n"></div></div><div class="tbl" id="logs"></div></div>
|
||||
</div>
|
||||
<p class="note" data-four-words><b>Four words, used exactly.</b> <b>Included</b>: the block carries the transaction. <b>Executed</b>: the EVM ran it and the result is on the record. <b>Proven</b>: a valid proof record for its block was carried and paid. <b>Finalised</b>: the block sits under a certified checkpoint, two thirds of active and of total weight. A pause in finality is shown as a pause, never as a block losing its lock. <b>Recovery lock</b>: after a full weight window with no lock, a checkpoint signed by more than half of the anchored weight; shown as a recovery lock, never as finalised. On the devnet’s current node line the lock kind is reported by the forming node only: a node that received the certificate records an ordinary lock, so a recovery lock can read as final on a receiving node until the 2.0.3 node line lands. The definitions are the finality specification’s: <a href="https://git.igneum.network/igneum-network/igneum/src/branch/master/docs/spec/finality-guarantees.md">section 9, the guarantees</a>.</p>
|
||||
<p class="note" data-four-words><b>Four words, used exactly.</b> <b>Included</b>: the block carries the transaction. <b>Executed</b>: the EVM ran it and the result is on the record. <b>Proven</b>: a valid proof record for its block was carried and paid. <b>Finalised</b>: the block sits under a certified checkpoint, two thirds of active and of total weight. A pause in finality is shown as a pause, never as a block losing its lock. <b>Recovery lock</b>: after a full weight window with no lock, a checkpoint signed by more than half of the anchored weight; shown as a recovery lock, never as final (the Token Value volume’s D05). On the devnet’s current node line the lock kind is reported by the forming node only: a node that received the certificate records an ordinary lock, so a recovery lock can read as final on a receiving node until the 2.0.3 node line lands. The definitions are the finality specification’s: <a href="https://git.igneum.network/igneum-network/igneum/src/branch/master/docs/spec/finality-guarantees.md">section 9, the guarantees</a>.</p>
|
||||
</main>
|
||||
<!-- footer:start -->
|
||||
<footer class="site-footer">
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
| kill-by-name rule 5 and the no-kill shim (`kill-by-name-check.sh`, `no-kill-shim/{pkill,killall}` exit 97 when first in PATH) | A `pgrep -f`/`pkill -f` pattern that is a bare path, a log name or an unanchored word; only `^`-anchored command patterns, the bracket form, a variable, -x or -F pass (fifteen Mac processes died to a grep, 8 Oct 2026) | 8 Oct 2026 |
|
||||
| a "cut" batch needs its read-back (`test-record.mjs`) | A batch declaring `cut` without the binary's build-N:/srv path, its commit string read back equal to the manifest sha, and the kit ISA check's clean line; a sha is cut only when its binary exists on build-1 with its commit string read back | 8 Oct 2026 |
|
||||
| rule 33: a release entry publishes only with a PASS fresh-install canary record for its sha (`canary-check.sh`; `tools/ci/canary/<sha>.json`, the form from `--form`; refused without by `packaging/ota/publish-manifest.sh --release-sha`, `publish-public.sh` and deploy-win.sh; the canary cell maps INT-07) | A release entry published before its sha had run a fresh install on a non-AVX-512 box with an empty datadir, synced, mined five minutes with zero refusals, claimed, proved and paid or queued one shard and quit inside a bound, every line read back (the founder's "no more lost time", 8 October 2026) |
|
||||
| the served-file identity guard (`served-identity-guard.sh` at every publisher of a served file built from reports or merges: the dl manifests in publish-manifest.sh and publish-public.sh, workers.json, the PC intake merge, release.json, the feed; `served-identity-daily.sh` over the edge copies; the box form `served-identity-hashes.sh`) | A served workers.json that carried the owner's first name from a PC report's free-text note (9 October 2026, 09:15 UK): the identity grep had guarded committed text, not served JSON built from reports |
|
||||
| the INT suite is generated from the master edition's integration gates (`int-suite.mjs`; the owner per the coordinator's crosswalk) and INT-17 is a rule of the writer: a cell declaring a missing oracle, pinned keys or mandatory real-proof fixture writes BLOCKED, never PASS | A registry whose INT suite drifts from traceability.json; a batch cell with `prereqs` where any is not "present" written as anything but BLOCKED | 8 Oct 2026 |
|
||||
| the REV suite is generated from an external review's findings.json and dispatch.md (`review-suite.mjs`; one case per required regression, NOT RUN, the owner from the dispatch table) | A registry whose REV suite differs from the generator's output (--check) | 8 Oct 2026 |
|
||||
| F03 (Review B): one release manifest (`packaging/release-manifest.json` on a release branch) and every component built from it (`release-manifest-check.sh`, `build-from-manifest.sh`) | A tree whose own pins disagree with the manifest: the Windows node-source pin, the proving manifest's elf and vk sha256s and the files' hashes, the node fork's freeze fingerprint, the pool's vendored node checkout, a redefined EpochSeeds in the pool (the shadow_reps seam closes by a build against the pinned node); the build script puts the fork at the manifest's node sha and checks kaspad with igneum-pow (rule 19), the miner, the pool, the app and the prove host on a box | 8 Oct 2026 |
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ the registry's evidence rules: a PASS names evidence that exists, a touched evid
|
|||
the kit ISA check: a distribution kit's binaries carry no AVX-512 encoding (the x86-64-v3 baseline; self-test with a fake objdump)
|
||||
F02 (Review B): the proof-rule test bypass cannot reach a release build: an env read with no cfg guard or under a default feature is red; a release binary carrying the bypass string is red (self-test)
|
||||
the test map merges structurally at a landing: master's cells plus the branch's, minus what the branch removed and master left (self-test)
|
||||
the served-file identity guard: a served file built from reports or merges is refused at its publish step on an identity hit, logged redacted; the box form matches hashed tokens under a salt (self-test)
|
||||
rule 33: a release entry publishes only with a PASS fresh-install canary record for its sha (the record check and the publish guard, self-tests)
|
||||
the guest input format moves with the pinned guests: the elf manifest's guest_input_format equals the source constant where the field exists, a format bump without a guest change is refused at the merge (self-test, then the tree)
|
||||
the REV suite is generated from Review B's findings and dispatch and matches them (self-test, then the tree)
|
||||
|
|
|
|||
|
|
@ -179,6 +179,7 @@ tree_checks() {
|
|||
run "the kit ISA check: a distribution kit's binaries carry no AVX-512 encoding (the x86-64-v3 baseline; self-test with a fake objdump)" bash tools/ci/kit-isa-check.sh --self-test
|
||||
run "F02 (Review B): the proof-rule test bypass cannot reach a release build: an env read with no cfg guard or under a default feature is red; a release binary carrying the bypass string is red (self-test)" bash tools/ci/proof-rule-bypass-check.sh --self-test
|
||||
run "the test map merges structurally at a landing: master's cells plus the branch's, minus what the branch removed and master left (self-test)" python3 tools/ci/test-map-merge.py --self-test
|
||||
run "the served-file identity guard: a served file built from reports or merges is refused at its publish step on an identity hit, logged redacted; the box form matches hashed tokens under a salt (self-test)" bash tools/ci/served-identity-guard.sh --self-test
|
||||
run "rule 33: a release entry publishes only with a PASS fresh-install canary record for its sha (the record check and the publish guard, self-tests)" bash -c 'bash tools/ci/canary-check.sh --self-test >/dev/null && bash packaging/ota/publish-manifest.sh --self-test-canary-guard >/dev/null'
|
||||
run "the guest input format moves with the pinned guests: the elf manifest's guest_input_format equals the source constant where the field exists, a format bump without a guest change is refused at the merge (self-test, then the tree)" bash -c 'bash tools/ci/guest-format-check.sh --self-test >/dev/null && bash tools/ci/guest-format-check.sh --tree .'
|
||||
run "the REV suite is generated from Review B's findings and dispatch and matches them (self-test, then the tree)" bash tools/ci/review-suite-check.sh
|
||||
|
|
|
|||
26
tools/ci/served-identity-daily.sh
Executable file
26
tools/ci/served-identity-daily.sh
Executable file
|
|
@ -0,0 +1,26 @@
|
|||
#!/usr/bin/env bash
|
||||
# The daily identity check over the EDGE copies of the served generated files (the coordinator's class, 9 October 2026): fetch each
|
||||
# served file from its public URL and run tools/ci/served-identity-guard.sh over it; a hit is a red to main the same hour. Runs on
|
||||
# build-1 from cron (the build-server lane's unit) and by hand; the list of guarded files is here and nowhere else.
|
||||
#
|
||||
# tools/ci/served-identity-daily.sh exit 0 clean, 1 a hit (named), 2 a fetch failed or no private list
|
||||
# tools/ci/served-identity-daily.sh --list print the guarded URLs
|
||||
set -euo pipefail
|
||||
HERE="$(cd "$(dirname "$0")" && pwd -P)"
|
||||
URLS=(
|
||||
https://build.igneum.network/workers.json # the workers page's merged reports (tools/workers/push.mjs, the build-server lane)
|
||||
https://build.igneum.network/intake.json # the PC intake merge (the build-server lane)
|
||||
https://igneum.network/release.json # the site's release manifest (site/build.mjs from site/release-manifest.json, the site lane)
|
||||
https://dl.igneum.network/public/igneum-app-latest.json # the public app manifest (packaging/ota/publish-public.sh)
|
||||
https://dl.igneum.network/public/igneum-wallet-latest.json # the public wallet manifest (packaging/ota/publish-public.sh)
|
||||
https://build.igneum.network/feed.json # the hourly feed on build-1 (the build-server lane's unit)
|
||||
)
|
||||
if [ "${1:-}" = --list ]; then printf '%s\n' "${URLS[@]}" | sed 's/ *#.*//'; exit 0; fi
|
||||
d=$(mktemp -d); trap 'rm -rf "$d"' EXIT; rc=0; files=()
|
||||
for u in "${URLS[@]}"; do
|
||||
u="${u%% *}"; f="$d/$(printf '%s' "$u" | sed 's#https://##; s#/#_#g')"
|
||||
if curl -fsSL --max-time 20 -o "$f" "$u" 2>/dev/null; then files+=("$f"); else echo "served-identity-daily: fetch failed or absent: $u" >&2; [ "$rc" = 0 ] && rc=2; fi
|
||||
done
|
||||
[ "${#files[@]}" -gt 0 ] || { echo "served-identity-daily: nothing fetched" >&2; exit 2; }
|
||||
bash "$HERE/served-identity-guard.sh" "${files[@]}" || rc=1
|
||||
exit $rc
|
||||
104
tools/ci/served-identity-guard.sh
Executable file
104
tools/ci/served-identity-guard.sh
Executable file
|
|
@ -0,0 +1,104 @@
|
|||
#!/usr/bin/env bash
|
||||
# The identity guard on SERVED files built from machine reports or merges (the coordinator's class, 9 October 2026, 09:15 UK: the served
|
||||
# workers.json on build.igneum.network carried the owner's first name in a free-text note from a PC report; the identity grep guarded
|
||||
# committed text, not served JSON built from reports). Every publisher of such a file calls this before its write and refuses the
|
||||
# publish on a hit; the daily edge check (tools/ci/served-identity-daily.sh) runs the same guard over the edge copies.
|
||||
#
|
||||
# tools/ci/served-identity-guard.sh <file> [<file> ...] exit 0 clean; 1 a hit (the publish is refused, the refusal logged); 2 no list
|
||||
# tools/ci/served-identity-guard.sh --self-test
|
||||
#
|
||||
# Patterns: the committed lists (tools/ci/forbidden-strings.txt, site/forbidden-strings.txt: machine model names, LAN addresses, home
|
||||
# paths, rig names, the zone word, the owner's name inside a host name) plus the PRIVATE list the export uses (the owner's names, machine
|
||||
# local names with his name, the home IP), read from IGNEUM_IDENTITY_LOCAL, else ~/.config/igneum/identity.local on the Mac, else the
|
||||
# public mirror's own list (~/Projects/igneum-public/tools/identity.local), else /srv/builds/_identity/identity.local on a box: one extended regular expression per line, comments with #. The private list never enters the
|
||||
# repository. A publish host without the private list is refused (exit 2) unless IGNEUM_IDENTITY_LOCAL_OPTIONAL=1 names the run as a
|
||||
# tree check, never a publish. Refusals are appended to IGNEUM_IDENTITY_REFUSALS (default ~/.config/igneum/identity-refusals.log, or
|
||||
# /srv/builds/_identity/refusals.log on a box) as "<utc> <file> <pattern class> <line>" with the matched text replaced by <redacted>.
|
||||
set -euo pipefail
|
||||
HERE="$(cd "$(dirname "$0")" && pwd -P)"; ME="$HERE/$(basename "$0")"; REPO="${IDENTITY_GUARD_REPO:-$(cd "$HERE/../.." && pwd -P)}"
|
||||
|
||||
# the BOX form (9 October 2026, 09:3x UK, the build-server lane's objection under the standing rule that a box holds no secret): on a box
|
||||
# the private list is a HASHED token list, /srv/builds/_identity/identity.hashes (one HMAC-SHA256 hex per literal token, under the 32-byte salt
|
||||
# at /srv/builds/_identity/salt; both mode 600), written on the Mac by tools/ci/served-identity-hashes.sh from the clear list and copied over,
|
||||
# never from the repository; the guard tokenizes the served file and matches digests, so the box carries no name and no address.
|
||||
# IGNEUM_IDENTITY_HASHES and IGNEUM_IDENTITY_SALT override the paths.
|
||||
hashed_hits() { # <file> -> prints "line" numbers whose tokens match a digest in the hashed list; empty when no hashed list
|
||||
local hf="${IGNEUM_IDENTITY_HASHES:-/srv/builds/_identity/identity.hashes}" sf="${IGNEUM_IDENTITY_SALT:-/srv/builds/_identity/salt}"
|
||||
[ -f "$hf" ] && [ -f "$sf" ] || return 0
|
||||
python3 - "$1" "$hf" "$sf" <<'PY2'
|
||||
import sys, hmac, hashlib, re
|
||||
f, hf, sf = sys.argv[1:4]; digests = {l.strip().lower() for l in open(hf) if l.strip() and not l.startswith('#')}; salt = open(sf, 'rb').read()
|
||||
for n, line in enumerate(open(f, errors='replace'), 1):
|
||||
for tok in re.findall(r"[A-Za-z0-9][A-Za-z0-9._-]*", line):
|
||||
t = tok.lower().strip('.-')
|
||||
if t and hmac.new(salt, t.encode(), hashlib.sha256).hexdigest() in digests: print(n); break
|
||||
PY2
|
||||
}
|
||||
have_hashed() { [ -f "${IGNEUM_IDENTITY_HASHES:-/srv/builds/_identity/identity.hashes}" ] && [ -f "${IGNEUM_IDENTITY_SALT:-/srv/builds/_identity/salt}" ]; }
|
||||
lists() { # prints every pattern, one per line: the committed lists, then the private one
|
||||
local got=0
|
||||
for f in "$REPO/tools/ci/forbidden-strings.txt" "$REPO/site/forbidden-strings.txt"; do [ -f "$f" ] && { grep -vE '^\s*(#|$)' "$f" || true; got=1; }; done
|
||||
if [ "$got" = 0 ]; then # a box: the shipped crate trees carry no lists; the bare mirror's master does (every box holds /srv/igneum.git)
|
||||
local mirror="${IGNEUM_IDENTITY_MIRROR:-/srv/igneum.git}"
|
||||
if [ -d "$mirror" ]; then for f in tools/ci/forbidden-strings.txt site/forbidden-strings.txt; do git -C "$mirror" show "master:$f" 2>/dev/null | grep -vE '^\s*(#|$)' || true; done; fi
|
||||
fi
|
||||
local priv="${IGNEUM_IDENTITY_LOCAL:-}"
|
||||
if [ -z "$priv" ]; then for c in "$HOME/.config/igneum/identity.local" "$HOME/Projects/igneum-public/tools/identity.local" /srv/builds/_identity/identity.local; do [ -f "$c" ] && { priv="$c"; break; }; done; fi # the public mirror's export list is the same private list on this Mac
|
||||
if [ -n "$priv" ] && [ -f "$priv" ]; then grep -vE '^\s*(#|$)' "$priv" || true; printf '%s\n' "__PRIVATE_LIST_PRESENT__"; fi
|
||||
}
|
||||
refusals_log() { if [ -n "${IGNEUM_IDENTITY_REFUSALS:-}" ]; then printf '%s' "$IGNEUM_IDENTITY_REFUSALS"; elif [ -d /srv/builds/_identity ]; then printf '%s' /srv/builds/_identity/refusals.log; else printf '%s' "$HOME/.config/igneum/identity-refusals.log"; fi; }
|
||||
|
||||
guard() { # <file...> -> 0 clean, 1 hit, 2 no private list
|
||||
local all pats have_priv=0 f hits rc=0 log; all="$(lists)"
|
||||
case "$all" in *__PRIVATE_LIST_PRESENT__*) have_priv=1 ;; esac
|
||||
pats="$(printf '%s\n' "$all" | grep -v '^__PRIVATE_LIST_PRESENT__$' || true)"
|
||||
if [ "$have_priv" = 0 ] && have_hashed; then have_priv=2; fi # the box form
|
||||
if [ "$have_priv" = 0 ] && [ "${IGNEUM_IDENTITY_LOCAL_OPTIONAL:-0}" != 1 ]; then
|
||||
echo "served-identity-guard: REFUSED: no private identity list on this host (the clear list on the Mac: IGNEUM_IDENTITY_LOCAL or ~/.config/igneum/identity.local; the hashed list on a box: /srv/builds/_identity/identity.hashes with its salt); a publish never runs without one" >&2; return 2
|
||||
fi
|
||||
[ -n "$pats" ] || { echo "served-identity-guard: no patterns at all; refusing" >&2; return 2; }
|
||||
log="$(refusals_log)"; mkdir -p "$(dirname "$log")" 2>/dev/null || true
|
||||
for f in "$@"; do
|
||||
[ -f "$f" ] || { echo "served-identity-guard: no such file $f" >&2; rc=1; continue; }
|
||||
hits="$(grep -nE -f <(printf '%s\n' "$pats") "$f" 2>/dev/null || true)"
|
||||
if [ "$have_priv" = 2 ]; then local hh; hh="$(hashed_hits "$f" | sed 's/$/:<hashed token>/')"; [ -n "$hh" ] && hits="$(printf '%s\n%s\n' "$hits" "$hh" | grep -v '^$')"; fi
|
||||
if [ -n "$hits" ]; then
|
||||
rc=1
|
||||
printf '%s\n' "$hits" | while IFS= read -r line; do
|
||||
local n="${line%%:*}"
|
||||
echo "served-identity-guard: REFUSED: $f:$n carries a forbidden identity pattern (the publish is refused; the line is in the refusals log, redacted)" >&2
|
||||
printf '%s %s line %s %s\n' "$(date -u +%Y-%m-%dT%H:%M:%SZ)" "$f" "$n" "<redacted>" >> "$log" 2>/dev/null || true
|
||||
done
|
||||
fi
|
||||
done
|
||||
[ "$rc" = 0 ] && echo "served-identity-guard: $# file(s) clean under $(printf '%s\n' "$pats" | grep -c .) patterns (private list: $([ "$have_priv" = 1 ] && echo "clear, this Mac" || { [ "$have_priv" = 2 ] && echo "hashed, this box" || echo "absent, tree check"; }))"
|
||||
return $rc
|
||||
}
|
||||
|
||||
if [ "${1:-}" = --self-test ]; then
|
||||
d=$(mktemp -d); trap 'rm -rf "$d"' EXIT; fails=0
|
||||
mkdir -p "$d/repo/tools/ci" "$d/repo/site"; printf '\\bPC [12]\\b\n' > "$d/repo/site/forbidden-strings.txt"; printf '/Users/[a-z]+\n' > "$d/repo/tools/ci/forbidden-strings.txt"
|
||||
printf '# private\n\\bOwnerName\\b\n10\\.0\\.0\\.77\n' > "$d/identity.local"
|
||||
export IDENTITY_GUARD_REPO="$d/repo" IGNEUM_IDENTITY_REFUSALS="$d/refusals.log"
|
||||
printf '{"note": "a clean report", "host": "lp-4090-11"}\n' > "$d/clean.json"
|
||||
printf '{"note": "reported by OwnerName at 10.0.0.77"}\n' > "$d/leak.json"
|
||||
printf '{"note": "ran on PC 2"}\n' > "$d/rig.json"
|
||||
IGNEUM_IDENTITY_LOCAL="$d/identity.local" bash "$ME" "$d/clean.json" >/dev/null 2>&1 || { echo "self-test failed: a clean served file was refused: $(IGNEUM_IDENTITY_LOCAL="$d/identity.local" bash "$ME" "$d/clean.json" 2>&1)"; fails=1; }
|
||||
IGNEUM_IDENTITY_LOCAL="$d/identity.local" bash "$ME" "$d/leak.json" >/dev/null 2>&1 && { echo "self-test failed: a served file carrying the owner's name and the home IP passed"; fails=1; }
|
||||
grep -q 'leak.json line 1 <redacted>' "$d/refusals.log" 2>/dev/null || { echo "self-test failed: the refusal was not logged redacted"; fails=1; }
|
||||
grep -q 'OwnerName' "$d/refusals.log" 2>/dev/null && { echo "self-test failed: the refusals log carries the matched text"; fails=1; }
|
||||
IGNEUM_IDENTITY_LOCAL="$d/identity.local" bash "$ME" "$d/rig.json" >/dev/null 2>&1 && { echo "self-test failed: a served file carrying a rig name passed"; fails=1; }
|
||||
rc=0; IGNEUM_IDENTITY_LOCAL="$d/missing.local" HOME="$d" bash "$ME" "$d/clean.json" >/dev/null 2>&1 || rc=$?; [ "$rc" = 2 ] || { echo "self-test failed: a publish host without the private list was not refused with exit 2 (got $rc)"; fails=1; }
|
||||
IGNEUM_IDENTITY_LOCAL="$d/missing.local" HOME="$d" IGNEUM_IDENTITY_LOCAL_OPTIONAL=1 bash "$ME" "$d/clean.json" >/dev/null 2>&1 || { echo "self-test failed: a tree check without the private list was refused"; fails=1; }
|
||||
# the box form: a hashed token list and a salt, no clear list; the owner's name token and the home IP are refused, a clean file passes
|
||||
printf 'saltsaltsaltsaltsaltsaltsaltsalt' > "$d/salt"; python3 -c "
|
||||
import hmac,hashlib; salt=open('$d/salt','rb').read()
|
||||
open('$d/identity.hashes','w').write('\n'.join(hmac.new(salt, t.encode(), hashlib.sha256).hexdigest() for t in ('ownername','10.0.0.77'))+'\n')"
|
||||
IGNEUM_IDENTITY_LOCAL="$d/missing.local" HOME="$d" IGNEUM_IDENTITY_HASHES="$d/identity.hashes" IGNEUM_IDENTITY_SALT="$d/salt" bash "$ME" "$d/clean.json" >/dev/null 2>&1 || { echo "self-test failed: the box form refused a clean file"; fails=1; }
|
||||
IGNEUM_IDENTITY_LOCAL="$d/missing.local" HOME="$d" IGNEUM_IDENTITY_HASHES="$d/identity.hashes" IGNEUM_IDENTITY_SALT="$d/salt" bash "$ME" "$d/leak.json" >/dev/null 2>&1 && { echo "self-test failed: the box form passed the owner's name and the home IP by their hashes"; fails=1; }
|
||||
grep -q 'ownername\|OwnerName' "$d/identity.hashes" && { echo "self-test failed: the hashed list carries a name in clear"; fails=1; }
|
||||
[ "$fails" = 0 ] && echo "self-test passed: a clean served file passes; the owner's name, the home IP (the private list) and a rig name (the committed list) are refused and logged redacted; a publish host without the private list is refused with exit 2, a tree check passes without it; the box form (a hashed token list and a salt, no name in clear) refuses the same leaks and passes the clean file"
|
||||
exit $fails
|
||||
fi
|
||||
[ $# -ge 1 ] || { echo "usage: $0 <file> [<file> ...] | --self-test" >&2; exit 2; }
|
||||
guard "$@"
|
||||
26
tools/ci/served-identity-hashes.sh
Executable file
26
tools/ci/served-identity-hashes.sh
Executable file
|
|
@ -0,0 +1,26 @@
|
|||
#!/usr/bin/env bash
|
||||
# Writes the BOX form of the private identity list (9 October 2026): one HMAC-SHA256 hex digest per literal token in the clear list, under
|
||||
# a 32-byte salt, so a box carries no name and no address. Regex entries (metacharacters) are skipped and counted; literal names, local
|
||||
# machine names and addresses are tokenized the way the guard tokenizes a served file (lowercase, [A-Za-z0-9._-] runs). Run on the Mac;
|
||||
# copy the two files to the box by scp (never through the repository): /srv/builds/_identity/identity.hashes and /srv/builds/_identity/salt (build-owned; /srv itself is root's), mode 600.
|
||||
# tools/ci/served-identity-hashes.sh <identity.local> <salt file (created if absent, 32 random bytes)> > identity.hashes
|
||||
set -euo pipefail
|
||||
[ $# -eq 2 ] || { echo "usage: $0 <identity.local> <salt file>" >&2; exit 2; }
|
||||
[ -f "$1" ] || { echo "no $1" >&2; exit 2; }
|
||||
[ -f "$2" ] || { head -c 32 /dev/urandom > "$2"; chmod 600 "$2"; echo "served-identity-hashes: a new salt at $2" >&2; }
|
||||
python3 - "$1" "$2" <<'PY'
|
||||
import sys, hmac, hashlib, re
|
||||
lst, sf = sys.argv[1:3]; salt = open(sf, 'rb').read(); n = 0; skipped = 0; out = set()
|
||||
for raw in open(lst):
|
||||
line = raw.strip()
|
||||
if not line or line.startswith('#'): continue
|
||||
if re.search(r'[\\^$.|?*+()\[\]{}]', line) and not re.fullmatch(r'[A-Za-z0-9._-]+', line.replace('\\.', '.')):
|
||||
skipped += 1; continue
|
||||
lit = line.replace('\\.', '.')
|
||||
for tok in re.findall(r"[A-Za-z0-9][A-Za-z0-9._-]*", lit):
|
||||
t = tok.lower().strip('.-')
|
||||
if t: out.add(hmac.new(salt, t.encode(), hashlib.sha256).hexdigest()); n += 1
|
||||
print('# served-identity hashed token list (HMAC-SHA256 under the host salt); no name in clear')
|
||||
for h in sorted(out): print(h)
|
||||
print(f'served-identity-hashes: {len(out)} digests from {n} tokens; {skipped} regex entries skipped (the committed pattern lists carry those forms)', file=sys.stderr)
|
||||
PY
|
||||
|
|
@ -98,7 +98,7 @@ LINK="$HOME/Projects/igneum/site/.vercel/project.json"; [ -f "$LINK" ] || { echo
|
|||
# the Vercel project's Root Directory is "site": the deploy runs from the export's root with site/ inside it
|
||||
mkdir -p "$W/.vercel"; cp "$LINK" "$W/.vercel/project.json"
|
||||
echo "site export at $SHORT ($(git log -1 --format='%ci %s' "$SHA" | cut -c1-90)); no .git in $W"
|
||||
( cd "$W/site" && node build.mjs ) 2>&1 | tail -3
|
||||
( cd "$W/site" && node build.mjs ) 2>&1 | tail -3; [ "${PIPESTATUS[0]}" = 0 ] || { echo "the site build failed (the served-identity guard or the build itself); nothing deployed" >&2; exit 1; }
|
||||
echo "deploying $(TZ=UTC date +%H:%M:%SZ)"
|
||||
OUT=$( cd "$W" && npx --yes vercel@latest --global-config "$HOME/.config/igneum/vercel" --scope igneum deploy --prod --yes 2>&1 ) || { echo "$OUT" | tail -5 >&2; exit 1; }
|
||||
URL=$(echo "$OUT" | grep -oE 'https://[a-z0-9.-]*vercel\.app' | tail -1)
|
||||
|
|
|
|||
73
tools/token-value/tv-04/inputs.json
Normal file
73
tools/token-value/tv-04/inputs.json
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
{
|
||||
"item": "TV-04",
|
||||
"title": "Security budget without price rescue",
|
||||
"statuses": {
|
||||
"RATIFIED": "the founder's ratification of 9 October 2026 (09:2x UK) of the Token Value volume's decisions, or a rule of the volume those decisions carry",
|
||||
"IMPLEMENTED": "a value the node's code carries on release-2.0.2-node, read from the cited file and line; taken under D04's ratified explicit routing",
|
||||
"UNRATIFIED": "a parameter, never a result: no table row is computed from it",
|
||||
"PANEL": "a cell the independent panel fills; empty here, so every comparison against it reads NOT RUN",
|
||||
"BLOCKED": "an open choice the ratified rules do not settle; the row names what it waits on"
|
||||
},
|
||||
"sources": {
|
||||
"rules_and_gates": {"path": "docs/plans/igneum-2.0-master/token-value/rules-and-gates.json", "sha256": "10ce307329e1663dcb6dce849317c9276c19252de5f483e9ee06015fc77cbe3d"},
|
||||
"volume_pdf": {"path": "docs/plans/igneum-2.0-master/token-value/igneum-2.0-token-value.pdf", "sha256": "b79d295c99d9cf0a121b62efdc6743e7282a0d2de33a98f6811616afcbcaeaee"},
|
||||
"master_pdf": {"path": "docs/plans/igneum-2.0-master/igneum-2.0-complete-master.pdf", "sha256": "f54f12117fd10ebcd1cad83b41342cf2a21ba7e0cf0abfa100d48b101b02b18b", "note": "the light edition in the tree; the supplied original (the volume's original_artifacts) reads c878ee4f80adf1da58fcc78fb91a8008de2e9fc44060bec143d020a780c5093e, the same substance"},
|
||||
"litepaper": {"path": "site/litepaper.html", "sha256": "35ac65e151339089ef6ddeea3842b24d95e00d327a2b12faa9ea190ff85e463f", "tree": "the box mirror's master 6824d49c"},
|
||||
"node": {"repo": "build@188.40.146.49:/srv/igneum-node.git", "branch": "release-2.0.2-node", "commit": "a284380bdd62d5d0d972cb38f2cbd1daeedda69d", "files": {
|
||||
"consensus/core/src/emission.rs": "07b39c410222a43001c83dddbd85cff4a8a370184588dbc28ab48c8803964fbd",
|
||||
"consensus/core/src/igneum.rs": "6c859d4268e653978bfa07aaaad2dff304635b892255368cbbadecca3c35705f",
|
||||
"consensus/core/src/config/params.rs": "0c07ddcf0c5383255f1b0cfba54c6f637375b9a5b5514ab4b2affdad717e787f",
|
||||
"consensus/core/src/fees.rs": "5e7a319c0fc538a6960e18ee02d3c23a0f514cef27fff6f4fdaa727c484d3136",
|
||||
"igneum/exec/src/config.rs": "fdc4ba56109ddab4dadfe3d184247cf2cda8774dc5542337acaa38c8da716aaf",
|
||||
"igneum/exec/src/executor.rs": "ff12ef5fed88f1cd1d1449c6878a5acc0f7efe098abad7315791d59b5c5cc79c"
|
||||
}},
|
||||
"tv01_supply_spec": {"path": "docs/plans/igneum-2.0-master/token-value/phase0/tv-01/supply-spec.json", "note": "the TV-01 lane's supply spec; read and reconciled when it is in the tree, the node code otherwise"}
|
||||
},
|
||||
"schedule": {
|
||||
"decimals": 8,
|
||||
"year_seconds": 31557600,
|
||||
"launch_rate_base_units_per_second": 3168808781,
|
||||
"ramp_seconds": 2592000,
|
||||
"ramp_start_percent": 10,
|
||||
"step_seconds": 63115200,
|
||||
"step_divisor": 2,
|
||||
"tail": {"kind": "cap"},
|
||||
"cap_coins": 4000000000,
|
||||
"status": "IMPLEMENTED",
|
||||
"source": "node emission.rs lines 32 and 103 to 110 (EmissionSchedule::CURRENT, tail Cap); params.rs line 1858 (MAINNET_PARAMS carries CURRENT, rescaled to 18 decimals, the same coins); igneum.rs lines 33 to 41 (the 4,000,000,000 cap)",
|
||||
"ratified_by": "D01 capped issuance, subject to TV-04; D02 the schedule pending evidence, so every figure here is conditional on this schedule"
|
||||
},
|
||||
"routes": [
|
||||
{"id": "R1-miner", "route": "emission, producer share", "role": "miners", "share_percent_num": 80, "share_percent_den": 1, "rounding": "the remainder of the pool's floor", "status": "IMPLEMENTED", "source": "igneum.rs lines 43 to 44 and 123 to 126; the litepaper's routing table, row 1"},
|
||||
{"id": "R1-pool", "route": "emission, proving pool share", "role": "internal provers", "share_percent_num": 20, "share_percent_den": 1, "rounding": "floor", "status": "IMPLEMENTED", "source": "igneum.rs lines 43 to 44 and 85 to 88; the litepaper's routing table, row 1"},
|
||||
{"id": "R1-validators", "route": "emission to minimum validators", "role": "minimum validators", "share_percent_num": 0, "share_percent_den": 1, "rounding": "none", "status": "IMPLEMENTED", "source": "no such output in the coinbase (igneum.rs lines 90 to 121); the litepaper: 0% to treasury, foundation, team or stake"},
|
||||
{"id": "R1-maintenance", "route": "emission to maintenance", "role": "maintenance", "share_percent_num": 0, "share_percent_den": 1, "rounding": "none", "status": "IMPLEMENTED", "source": "no emission treasury (igneum.rs line 5); the litepaper: no fund, no foundation, no fee to the team"},
|
||||
{"id": "R2-base", "route": "base fee, both gas dimensions", "role": "burn", "share_percent_num": 100, "share_percent_den": 1, "rounding": "none", "status": "IMPLEMENTED", "source": "fees.rs lines 131 to 132 (burned in full); executor.rs lines 318 to 329 (the execution base part and the proving charge burned)"},
|
||||
{"id": "R3-tip-miner", "route": "priority fee (tip), beneficiary share", "role": "miners", "share_percent_num": 80, "share_percent_den": 1, "rounding": "the remainder of the developer floor", "status": "IMPLEMENTED", "source": "igneum/exec config.rs lines 75 to 76 (80% to the including miner); executor.rs line 729 (the beneficiary credited the miner tip)"},
|
||||
{"id": "R3-tip-dev", "route": "priority fee (tip), developer share", "role": "developers (not a security role)", "share_percent_num": 20, "share_percent_den": 1, "rounding": "floor, unregistered frames burned", "status": "IMPLEMENTED", "source": "igneum/exec config.rs lines 75 to 76; pgas.rs lines 287 to 310"},
|
||||
{"id": "R3-tip-provers", "route": "priority fee (tip), provers' part", "role": "internal provers", "share_percent_num": 0, "share_percent_den": 1, "rounding": "none", "status": "BLOCKED", "source": "the node's code pays the 80% tip share to the beneficiary alone (executor.rs lines 318 to 329, line 729); the litepaper's routing table, row 3, reads '80% the block's miner and provers' with no split. The master, p. 36: resolve the discrepancy between the fee table and prose before modelling security income."},
|
||||
{"id": "R4-external-launch", "route": "external job at launch (customer's chain)", "role": "the delivering miner (outside the native ledger)", "share_percent_num": 0, "share_percent_den": 1, "rounding": "none", "status": "UNRATIFIED", "source": "the litepaper's routing table, row 4 (Designed); D04: the external-job rate is not ratified"},
|
||||
{"id": "R5-external-bridge", "route": "external job after the proof bridge", "role": "internal provers (the delivering provers)", "share_percent_num": 0, "share_percent_den": 1, "rounding": "none", "status": "UNRATIFIED", "source": "the litepaper's routing table, row 5 (Designed, phase two; 90% to provers, 10% burned as published); D04: the external-job rate is not ratified, so the published 90/10 is a parameter here and the tables carry zero external jobs"},
|
||||
{"id": "R6-devfee", "route": "the official miner client's optional dev fee", "role": "the project (operator income, outside the protocol)", "share_percent_num": 0, "share_percent_den": 1, "rounding": "none", "status": "UNRATIFIED", "source": "the litepaper's routing table, row 6: never added to rows 1 to 5; switchable by every miner, so not a committed resource (the master, p. 68, P13)"}
|
||||
],
|
||||
"signing_bonus": {"mainnet_activation": "never (u64::MAX)", "bps": 1000, "status": "IMPLEMENTED", "source": "params.rs lines 1809 to 1810 (MAINNET_PARAMS: off); igneum.rs lines 90 to 121 (a silent block moves bonus_bps of the producer share to the pool)", "effect_here": "none: off on the mainnet params, so the 80/20 split stands"},
|
||||
"scenarios": [
|
||||
{"id": "m010", "multiple_num": 1, "multiple_den": 10, "label": "0.1x: the minus-90-percent case, the 1x path at one tenth", "kind": "minus-90-percent"},
|
||||
{"id": "m025", "multiple_num": 1, "multiple_den": 4, "label": "0.25x", "kind": "revenue band"},
|
||||
{"id": "m100", "multiple_num": 1, "multiple_den": 1, "label": "1x (the baseline path)", "kind": "revenue band"},
|
||||
{"id": "m400", "multiple_num": 4, "multiple_den": 1, "label": "4x", "kind": "revenue band"},
|
||||
{"id": "m1000", "multiple_num": 10, "multiple_den": 1, "label": "10x", "kind": "revenue band"}
|
||||
],
|
||||
"horizons_years": [1, 5, 10, 20],
|
||||
"external_jobs_per_year": 0,
|
||||
"native_tip_volume_per_year_coins": 0,
|
||||
"roles": ["miners", "internal provers", "minimum validators", "maintenance"],
|
||||
"panel_cells": [
|
||||
{"id": "C-miners", "parameter": "minimum required miner cost per year", "unit": "BU (one BU = the purchasing power of the baseline, the whole year-1 subsidy, on the 1x path)", "value": null, "status": "PANEL", "source_hint": "the master, p. 68, P12: its electricity, productive-life and development grids are the panel's inputs; p. 88 to 89, ECO-01 to ECO-06 for the cost reconciliation"},
|
||||
{"id": "C-provers", "parameter": "minimum required internal proving cost per year", "unit": "BU", "value": null, "status": "PANEL", "source_hint": "the master, p. 36 (the historical shard timings, not reproduced for this edition) and p. 89, ECO-06"},
|
||||
{"id": "C-validators", "parameter": "minimum required validator cost per year", "unit": "BU", "value": null, "status": "PANEL", "source_hint": "the volume, p. 15 (minimum-node resources) and TV-10; no figure in the volume or the master"},
|
||||
{"id": "C-maintenance", "parameter": "minimum required maintenance cost per year", "unit": "BU", "value": null, "status": "PANEL", "source_hint": "the master, p. 68, P13 (at least 12 months of committed resources); the volume, p. 31; no figure in the volume or the master"},
|
||||
{"id": "K-class", "parameter": "which scenario-year cells are approved viable and which are collapse cases", "unit": "a declaration per cell, before results", "value": null, "status": "PANEL", "source_hint": "the master, p. 68, P12: declare the viable worlds before running; collapse worlds stay as safety and exit tests"},
|
||||
{"id": "T-tip", "parameter": "native tip volume per year (fee level and its volatility)", "unit": "coins a year", "value": null, "status": "PANEL", "source_hint": "the volume, p. 14 (fee timing as well as amount); the tables carry zero, the fee-replacement table gives the volume each year would need"}
|
||||
]
|
||||
}
|
||||
49
tools/token-value/tv-04/run-on-box.sh
Executable file
49
tools/token-value/tv-04/run-on-box.sh
Executable file
|
|
@ -0,0 +1,49 @@
|
|||
#!/usr/bin/env bash
|
||||
# TV-04: run the tests or the generator on build-9 from the lane's worktree (Token Value Phase 0, 9 October 2026).
|
||||
# Nothing runs on the Mac: the committed tree at HEAD travels as a git archive, the run takes a pid file first
|
||||
# (build-9:/home/build/tv-04/run.pid, mirrored at build-1:/srv/queue/pids/build-9-tv04.pid while live), and the
|
||||
# log and any outputs stay under build-9:/home/build/tv-04/runs/<commit>-<mode>/.
|
||||
#
|
||||
# tools/token-value/tv-04/run-on-box.sh red|green|known-failed|generate|check
|
||||
#
|
||||
# red the test file before the generator exists (the first, failing run)
|
||||
# green python3 test_tv04.py
|
||||
# known-failed python3 test_tv04.py --known-failed
|
||||
# generate python3 tv04_budget.py --out <run dir>/out, twice, and the two output trees compared byte for byte
|
||||
# check python3 tv04_budget.py --check (the committed outputs equal a fresh generation)
|
||||
set -euo pipefail
|
||||
MODE="${1:?mode: red|green|known-failed|generate|check}"
|
||||
BOX="${TV04_BOX:-build@188.40.146.46}"
|
||||
QUEUE="${TV04_QUEUE_BOX:-build@188.40.146.49}"
|
||||
ROOT="$(git rev-parse --show-toplevel)"
|
||||
SHA="$(git -C "$ROOT" rev-parse HEAD)"
|
||||
SHORT="${SHA:0:8}"
|
||||
RUN="tv-04/runs/${SHORT}-${MODE}"
|
||||
if ! git -C "$ROOT" diff --quiet HEAD -- tools/token-value/tv-04 docs/plans/igneum-2.0-master/token-value/phase0/tv-04; then
|
||||
echo "uncommitted changes under the TV-04 paths: commit first, the box runs HEAD only" >&2
|
||||
exit 2
|
||||
fi
|
||||
ssh -o BatchMode=yes "$BOX" "mkdir -p ~/${RUN}/src"
|
||||
git -C "$ROOT" archive --format=tar HEAD tools/token-value/tv-04 docs/plans/igneum-2.0-master/token-value \
|
||||
| ssh -o BatchMode=yes "$BOX" "tar -x -C ~/${RUN}/src"
|
||||
case "$MODE" in
|
||||
red|green) CMD="python3 tools/token-value/tv-04/test_tv04.py" ;;
|
||||
known-failed) CMD="python3 tools/token-value/tv-04/test_tv04.py --known-failed" ;;
|
||||
generate) CMD="python3 tools/token-value/tv-04/tv04_budget.py --out ../out-a && python3 tools/token-value/tv-04/tv04_budget.py --out ../out-b && diff -r ../out-a ../out-b && echo 'RESULT tv04 regeneration byte-identical' && (cd ../out-a && sha256sum \$(ls | sort))" ;;
|
||||
check) CMD="python3 tools/token-value/tv-04/tv04_budget.py --check docs/plans/igneum-2.0-master/token-value/phase0/tv-04" ;;
|
||||
*) echo "unknown mode $MODE" >&2; exit 2 ;;
|
||||
esac
|
||||
STAMP="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||
printf '%s\n' "set -o pipefail" "for i in \$(seq 1 100); do [ -e ~/tv-04/run.pid ] && break; sleep 0.1; done" "cd ~/${RUN}/src" \
|
||||
"{ echo \"commit ${SHA} mode ${MODE} start ${STAMP} host \$(hostname)\"; ( ${CMD} ); rc=\$?; echo \"exit \$rc end \$(date -u +%Y-%m-%dT%H:%M:%SZ)\"; echo \$rc > ~/${RUN}/exit; } > ~/${RUN}/run.log 2>&1" \
|
||||
"rm -f ~/tv-04/run.pid" | ssh -o BatchMode=yes "$BOX" "cat > ~/${RUN}/job.sh"
|
||||
ssh -o BatchMode=yes "$BOX" "rm -f ~/${RUN}/exit ~/${RUN}/run.log"
|
||||
# the pid file first: the job's pid, written by the launching shell before anything else of the job's reads a line
|
||||
PIDLINE="$(ssh -o BatchMode=yes "$BOX" "nohup bash ~/${RUN}/job.sh > /dev/null 2>&1 & echo \"\$! ${STAMP} tv04-${MODE} ${SHORT}\" > ~/tv-04/run.pid; cat ~/tv-04/run.pid")"
|
||||
echo "pid file: ${PIDLINE}"
|
||||
printf '%s\n' "${PIDLINE} build-9:/home/build/tv-04/run.pid" | ssh -o BatchMode=yes "$QUEUE" "cat > /srv/queue/pids/build-9-tv04.pid"
|
||||
ssh -o BatchMode=yes "$BOX" "for i in \$(seq 1 600); do [ -e ~/${RUN}/exit ] && break; sleep 1; done; cat ~/${RUN}/run.log"
|
||||
RC="$(ssh -o BatchMode=yes "$BOX" "cat ~/${RUN}/exit 2>/dev/null || echo 124")"
|
||||
ssh -o BatchMode=yes "$QUEUE" "rm -f /srv/queue/pids/build-9-tv04.pid"
|
||||
echo "log: build-9:/home/build/${RUN}/run.log (exit ${RC})"
|
||||
exit "$RC"
|
||||
214
tools/token-value/tv-04/test_tv04.py
Normal file
214
tools/token-value/tv-04/test_tv04.py
Normal file
|
|
@ -0,0 +1,214 @@
|
|||
#!/usr/bin/env python3
|
||||
"""TV-04 tests (Token Value Phase 0, 9 October 2026).
|
||||
|
||||
Two modes, both standalone Python 3, no third-party modules:
|
||||
|
||||
python3 tools/token-value/tv-04/test_tv04.py
|
||||
the green run: every property on the ratified inputs must hold.
|
||||
|
||||
python3 tools/token-value/tv-04/test_tv04.py --known-failed
|
||||
the known-failed run: five mutated input sets, each built to break one rule
|
||||
(a tail mint, rising purchasing power, external-job income in a result row,
|
||||
a currency figure in the output, burned fees counted as a role receipt).
|
||||
Every mutant must be caught by the property it breaks, or this run fails.
|
||||
A check that has never fired on a known-bad case is not trusted.
|
||||
|
||||
Exit 0 only when the mode's expectation holds. Each run ends with one RESULT line.
|
||||
"""
|
||||
import copy
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import tempfile
|
||||
from fractions import Fraction
|
||||
|
||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
sys.path.insert(0, HERE)
|
||||
|
||||
import tv04_budget as g # noqa: E402 (the generator; the first run of this file predates it and fails here)
|
||||
|
||||
|
||||
def load_inputs():
|
||||
with open(os.path.join(HERE, "inputs.json"), "r", encoding="utf-8") as f:
|
||||
return json.load(f)
|
||||
|
||||
|
||||
# ---- the properties -------------------------------------------------------------------------------------------
|
||||
|
||||
def p_year1_matches_node_closed_form(inp, model, files):
|
||||
"""Year 1 equals the node's closed form: rate x year minus the ramp's withheld coins (emission.rs ramp_withheld)."""
|
||||
s = inp["schedule"]
|
||||
rate, year, r, start = s["launch_rate_base_units_per_second"], s["year_seconds"], s["ramp_seconds"], s["ramp_start_percent"]
|
||||
n = r
|
||||
withheld = rate * (100 - start) * (n * r - (0 + r - 1) * n // 2) // (100 * r)
|
||||
want = rate * year - withheld
|
||||
got = model["emission"][1]
|
||||
assert got == want, f"year-1 emission {got} != node closed form {want}"
|
||||
|
||||
|
||||
def p_no_hidden_issuance(inp, model, files):
|
||||
"""D01 and VR-01: the tail is the cap, the whole schedule never exceeds the cap, and nothing mints after the curve."""
|
||||
s = inp["schedule"]
|
||||
assert s["tail"]["kind"] == "cap", f"tail is {s['tail']['kind']}, not the ratified cap (D01)"
|
||||
cap = s["cap_coins"] * 10 ** s["decimals"]
|
||||
total = model["total_schedule_base_units"]
|
||||
assert total <= cap, f"the schedule mints {total} base units, over the cap {cap}"
|
||||
for y in range(1, model["years_modelled"] + 1):
|
||||
assert model["emission"][y] >= 0
|
||||
late = model["emission_after_curve"]
|
||||
assert late == 0, f"{late} base units minted after the curve ends"
|
||||
|
||||
|
||||
def p_no_assumed_appreciation(inp, model, files):
|
||||
"""TV-04 pass words: no assumed appreciation. A scenario's multiple is one constant for every year."""
|
||||
for sc in model["scenarios"]:
|
||||
ms = set(sc["multiple_by_year"].values())
|
||||
assert len(ms) == 1, f"scenario {sc['id']} changes its multiple over the horizon: {sorted(ms)}"
|
||||
|
||||
|
||||
def p_zero_external_jobs(inp, model, files):
|
||||
"""D04: the external-job rate is not ratified, so no result row carries external-job income."""
|
||||
for row in model["rows"]:
|
||||
assert row["external_job_receipts_base_units"] == 0, f"row {row['key']} carries external-job income"
|
||||
for r in inp["routes"]:
|
||||
if r["id"].startswith("R4") or r["id"].startswith("R5"):
|
||||
assert r["status"] == "UNRATIFIED", f"route {r['id']} is marked {r['status']}, not UNRATIFIED"
|
||||
|
||||
|
||||
def p_conservation(inp, model, files):
|
||||
"""VR-08: every emitted coin lands in exactly one route; burned amounts are never a role receipt."""
|
||||
for y in range(1, model["years_modelled"] + 1):
|
||||
parts = model["split"][y]
|
||||
total = sum(parts[k] for k in ("miners", "internal provers", "minimum validators", "maintenance"))
|
||||
assert total == model["emission"][y], f"year {y}: role receipts {total} != emission {model['emission'][y]}"
|
||||
assert parts.get("burn_counted_as_receipt", 0) == 0, f"year {y}: a burn is counted as a receipt"
|
||||
|
||||
|
||||
def p_no_price_anywhere(inp, model, files):
|
||||
"""VR-04 and the never-published list: no currency figure, no price line, no em dash, no zone word, anywhere."""
|
||||
bad = ["$", "USD", "GBP", "EUR", "£", "€", "per IGN", "price per", "price of IGN", "IGN price", "—", "BST"]
|
||||
for name, data in files.items():
|
||||
text = data.decode("utf-8")
|
||||
for b in bad:
|
||||
assert b not in text, f"{name} contains {b!r}"
|
||||
|
||||
|
||||
def p_panel_cells_empty_and_verdict_not_run(inp, model, files):
|
||||
"""The cost side is the panel's: an empty cell gives NOT RUN, never PASS; no PASS word anywhere in a decision."""
|
||||
for row in model["rows"]:
|
||||
assert row["decision"] in ("NOT RUN", "BLOCKED"), f"row {row['key']} reads {row['decision']}"
|
||||
if row["role_cost_bu"] is None:
|
||||
assert row["coverage"] == "", f"row {row['key']} has a coverage without a panel cost"
|
||||
|
||||
|
||||
def p_ceiling_arithmetic(inp, model, files):
|
||||
"""The fundable-cost ceiling is m x role receipts / the baseline, exactly, for every row."""
|
||||
B = model["baseline_base_units"]
|
||||
for row in model["rows"]:
|
||||
want = Fraction(row["multiple_num"], row["multiple_den"]) * Fraction(row["native_receipts_base_units"], B)
|
||||
assert row["ceiling_exact"] == want, f"row {row['key']}: ceiling {row['ceiling_exact']} != {want}"
|
||||
|
||||
|
||||
def p_byte_identical(inp, model, files):
|
||||
"""Two generations into two fresh directories are byte-identical, file by file."""
|
||||
def gen():
|
||||
d = tempfile.mkdtemp(prefix="tv04-")
|
||||
out = g.write_outputs(inp, d, repo_root=g.repo_root())
|
||||
return {k: hashlib.sha256(v).hexdigest() for k, v in sorted(out.items())}
|
||||
a, b = gen(), gen()
|
||||
assert a == b, f"regeneration differs: {set(k for k in a if a[k] != b.get(k))}"
|
||||
|
||||
|
||||
PROPERTIES = [
|
||||
p_year1_matches_node_closed_form,
|
||||
p_no_hidden_issuance,
|
||||
p_no_assumed_appreciation,
|
||||
p_zero_external_jobs,
|
||||
p_conservation,
|
||||
p_no_price_anywhere,
|
||||
p_panel_cells_empty_and_verdict_not_run,
|
||||
p_ceiling_arithmetic,
|
||||
p_byte_identical,
|
||||
]
|
||||
|
||||
|
||||
def run_all(inp, mutate_model=None, mutate_files=None):
|
||||
model = g.build_model(inp, repo_root=g.repo_root())
|
||||
if mutate_model:
|
||||
mutate_model(model)
|
||||
files = g.render_files(inp, model, repo_root=g.repo_root())
|
||||
if mutate_files:
|
||||
mutate_files(files)
|
||||
failed = []
|
||||
for p in PROPERTIES:
|
||||
try:
|
||||
p(inp, model, files)
|
||||
print(f"ok {p.__name__}")
|
||||
except AssertionError as e:
|
||||
print(f"FAIL {p.__name__}: {e}")
|
||||
failed.append(p.__name__)
|
||||
return failed
|
||||
|
||||
|
||||
# ---- the known-failed mutants: each breaks one rule, in the inputs, the model or the written files ----------------
|
||||
|
||||
def m_appreciation(model):
|
||||
for sc in model["scenarios"]:
|
||||
sc["multiple_by_year"] = {y: sc["m"] * Fraction(11, 10) ** (y - 1) for y in sc["multiple_by_year"]}
|
||||
|
||||
|
||||
def m_external(model):
|
||||
model["rows"][0]["external_job_receipts_base_units"] = 10 ** 8
|
||||
|
||||
|
||||
def m_burn(model):
|
||||
for y in model["split"]:
|
||||
model["split"][y]["burn_counted_as_receipt"] = 10 ** 8
|
||||
model["split"][y]["miners"] += 10 ** 8
|
||||
|
||||
|
||||
def m_price(files):
|
||||
files["README.md"] = files["README.md"] + "Reference: IGN price USD 0.01\n".encode("utf-8")
|
||||
|
||||
|
||||
def mutants(base):
|
||||
tail = copy.deepcopy(base)
|
||||
tail["schedule"]["tail"] = {"kind": "fixed", "rate_base_units_per_second": 1000000000}
|
||||
return [
|
||||
("tail mint (a fixed tail after the curve)", tail, None, None, "p_no_hidden_issuance"),
|
||||
("assumed appreciation (the multiple rises 10 percent a year)", base, m_appreciation, None, "p_no_assumed_appreciation"),
|
||||
("external-job income in a result row", base, m_external, None, "p_zero_external_jobs"),
|
||||
("a currency figure in the output", base, None, m_price, "p_no_price_anywhere"),
|
||||
("burned fees counted as a role receipt", base, m_burn, None, "p_conservation"),
|
||||
]
|
||||
|
||||
|
||||
def known_failed(base):
|
||||
caught = 0
|
||||
ms = mutants(base)
|
||||
for name, inp, mm, mf, expect in ms:
|
||||
print(f"-- mutant: {name} (must fail {expect})")
|
||||
failed = run_all(inp, mm, mf)
|
||||
if expect in failed:
|
||||
print(f" caught by {expect}")
|
||||
caught += 1
|
||||
else:
|
||||
print(f" NOT caught: {expect} passed on a known-bad input")
|
||||
return caught, len(ms)
|
||||
|
||||
|
||||
def main():
|
||||
base = load_inputs()
|
||||
if "--known-failed" in sys.argv:
|
||||
caught, n = known_failed(base)
|
||||
ok = caught == n
|
||||
print(f"RESULT tv04 known-failed {'every mutant caught' if ok else 'a mutant escaped'} {caught}/{n}")
|
||||
return 0 if ok else 1
|
||||
failed = run_all(base)
|
||||
print(f"RESULT tv04 green {'all properties hold' if not failed else 'FAILED ' + ','.join(failed)} {len(PROPERTIES) - len(failed)}/{len(PROPERTIES)}")
|
||||
return 0 if not failed else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
532
tools/token-value/tv-04/tv04_budget.py
Normal file
532
tools/token-value/tv-04/tv04_budget.py
Normal file
|
|
@ -0,0 +1,532 @@
|
|||
#!/usr/bin/env python3
|
||||
"""TV-04, the security budget from the ratified rules (Token Value Phase 0, 9 October 2026).
|
||||
|
||||
A deterministic generator: standard library only, integer and Fraction arithmetic only, no clock, no randomness,
|
||||
no network. The same tree gives the same bytes.
|
||||
|
||||
python3 tools/token-value/tv-04/tv04_budget.py --out <dir> write README.md and the CSVs into <dir>
|
||||
python3 tools/token-value/tv-04/tv04_budget.py --check <dir> exit 0 only when <dir> equals a fresh generation
|
||||
|
||||
Inputs: tools/token-value/tv-04/inputs.json (every parameter with its source and status), and, when it is in the
|
||||
tree, the TV-01 lane's supply spec (docs/plans/igneum-2.0-master/token-value/phase0/tv-01/supply-spec.json),
|
||||
reconciled year by year against the node's schedule reproduced here.
|
||||
|
||||
Units. Native amounts are base units at 8 decimals (the node's EmissionSchedule::CURRENT; the mainnet's 18-decimal
|
||||
schedule is the same coins times 10^10). One BU is the purchasing power of the baseline: the whole year-1 subsidy on
|
||||
the 1x path. A scenario multiple m scales the purchasing power of every native receipt, one constant for the whole
|
||||
horizon (no assumed appreciation). No price figure is used or written.
|
||||
"""
|
||||
import argparse
|
||||
import csv
|
||||
import hashlib
|
||||
import io
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from fractions import Fraction
|
||||
|
||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
OUT_REL = "docs/plans/igneum-2.0-master/token-value/phase0/tv-04"
|
||||
TV01_REL = "docs/plans/igneum-2.0-master/token-value/phase0/tv-01/supply-spec.json"
|
||||
ROLES = ["miners", "internal provers", "minimum validators", "maintenance"]
|
||||
YEARS_MODELLED = 20
|
||||
|
||||
|
||||
def repo_root():
|
||||
return os.path.normpath(os.path.join(HERE, "..", "..", ".."))
|
||||
|
||||
|
||||
def sha256_file(path):
|
||||
h = hashlib.sha256()
|
||||
with open(path, "rb") as f:
|
||||
for chunk in iter(lambda: f.read(1 << 16), b""):
|
||||
h.update(chunk)
|
||||
return h.hexdigest()
|
||||
|
||||
|
||||
# ---- the schedule, reproduced from the node (emission.rs, EmissionTable::build and scheduled_supply_at) -----------
|
||||
|
||||
def ramp_withheld(rate, a, b, ramp_seconds, start_percent):
|
||||
if b <= a or ramp_seconds == 0:
|
||||
return 0
|
||||
n = b - a
|
||||
s = n * ramp_seconds - (a + b - 1) * n // 2
|
||||
return rate * (100 - start_percent) * s // (100 * ramp_seconds)
|
||||
|
||||
|
||||
class Schedule:
|
||||
def __init__(self, s):
|
||||
self.s = s
|
||||
self.step = s["step_seconds"]
|
||||
self.rates, self.supply = [], []
|
||||
rate, supply = s["launch_rate_base_units_per_second"], 0
|
||||
for k in range(4096):
|
||||
self.rates.append(rate)
|
||||
self.supply.append(supply)
|
||||
if rate == 0:
|
||||
break
|
||||
a = k * self.step
|
||||
b = a + self.step
|
||||
withheld = ramp_withheld(rate, a, min(b, s["ramp_seconds"]), s["ramp_seconds"], s["ramp_start_percent"]) if a < s["ramp_seconds"] else 0
|
||||
supply += rate * self.step - withheld
|
||||
rate = rate // s["step_divisor"]
|
||||
else:
|
||||
raise ValueError("the curve does not reach zero within 4096 steps")
|
||||
self.curve_total = self.supply[-1]
|
||||
self.curve_end = (len(self.rates) - 1) * self.step
|
||||
|
||||
def tail_rate(self):
|
||||
t = self.s["tail"]
|
||||
if t["kind"] == "cap":
|
||||
return 0
|
||||
if t["kind"] == "fixed":
|
||||
return t["rate_base_units_per_second"]
|
||||
raise ValueError(f"tail kind {t['kind']} is not modelled")
|
||||
|
||||
def supply_at(self, t):
|
||||
k = t // self.step
|
||||
tail = self.tail_rate()
|
||||
if k >= len(self.rates) - 1:
|
||||
return self.curve_total + tail * max(0, t - self.curve_end)
|
||||
rate = max(self.rates[k], tail)
|
||||
a = k * self.step
|
||||
withheld = ramp_withheld(rate, a, min(t, self.s["ramp_seconds"]), self.s["ramp_seconds"], self.s["ramp_start_percent"]) if a < self.s["ramp_seconds"] else 0
|
||||
return self.supply[k] + rate * (t - a) - withheld
|
||||
|
||||
|
||||
# ---- the model ------------------------------------------------------------------------------------------------
|
||||
|
||||
def route(inp, rid):
|
||||
for r in inp["routes"]:
|
||||
if r["id"] == rid:
|
||||
return r
|
||||
raise KeyError(rid)
|
||||
|
||||
|
||||
def read_tv01(inp, root, sched, years):
|
||||
path = os.path.join(root, TV01_REL)
|
||||
if not os.path.exists(path):
|
||||
return {"present": False, "status": "not in the tree at generation; the node's code (release-2.0.2-node a284380b) is the source", "rows": []}
|
||||
sha = sha256_file(path)
|
||||
try:
|
||||
with open(path, "r", encoding="utf-8") as f:
|
||||
spec = json.load(f)
|
||||
except ValueError as e:
|
||||
return {"present": True, "sha256": sha, "status": f"BLOCKED: the file does not parse as JSON ({e})", "rows": []}
|
||||
found = None
|
||||
for key in ("years", "annual", "emission_by_year", "schedule_years", "year_table"):
|
||||
v = spec.get(key) if isinstance(spec, dict) else None
|
||||
if isinstance(v, list) and v and isinstance(v[0], dict) and "year" in v[0]:
|
||||
found = v
|
||||
break
|
||||
if found is None:
|
||||
return {"present": True, "sha256": sha, "status": "BLOCKED: present, but no per-year emission list this generator reads (keys tried: years, annual, emission_by_year, schedule_years, year_table)", "rows": []}
|
||||
rows, agree = [], True
|
||||
dec = inp["schedule"]["decimals"]
|
||||
for e in found:
|
||||
y = int(e["year"])
|
||||
if y < 1 or y > years:
|
||||
continue
|
||||
theirs = None
|
||||
for k in ("emission_base_units", "emission_base_units_8dp", "emission_sompi"):
|
||||
if k in e:
|
||||
theirs = int(e[k])
|
||||
break
|
||||
if theirs is None and "emission_base_units_18dp" in e:
|
||||
theirs = int(e["emission_base_units_18dp"]) // 10 ** (18 - dec)
|
||||
ours = sched.supply_at(y * inp["schedule"]["year_seconds"]) - sched.supply_at((y - 1) * inp["schedule"]["year_seconds"])
|
||||
ok = theirs is not None and theirs == ours
|
||||
agree = agree and ok
|
||||
rows.append({"year": y, "tv01": theirs, "tv04": ours, "agree": ok})
|
||||
status = "reconciled: every year it lists agrees to the base unit" if rows and agree else "DISAGREES: see tv01-reconcile.csv" if rows else "BLOCKED: no year 1 to 20 rows"
|
||||
return {"present": True, "sha256": sha, "status": status, "rows": rows}
|
||||
|
||||
|
||||
def build_model(inp, repo_root=None):
|
||||
root = repo_root or globals()["repo_root"]()
|
||||
s = inp["schedule"]
|
||||
sched = Schedule(s)
|
||||
Y = s["year_seconds"]
|
||||
emission, split = {}, {}
|
||||
pool_pct = route(inp, "R1-pool")["share_percent_num"]
|
||||
for y in range(1, YEARS_MODELLED + 1):
|
||||
e = sched.supply_at(y * Y) - sched.supply_at((y - 1) * Y)
|
||||
emission[y] = e
|
||||
pool = e * pool_pct // 100
|
||||
split[y] = {"miners": e - pool, "internal provers": pool, "minimum validators": 0, "maintenance": 0, "burn_counted_as_receipt": 0}
|
||||
B = emission[1]
|
||||
after = sched.supply_at(sched.curve_end + Y) - sched.supply_at(sched.curve_end)
|
||||
scenarios = []
|
||||
for sc in inp["scenarios"]:
|
||||
m = Fraction(sc["multiple_num"], sc["multiple_den"])
|
||||
scenarios.append({"id": sc["id"], "label": sc["label"], "kind": sc["kind"], "m": m, "multiple_by_year": {y: m for y in range(1, YEARS_MODELLED + 1)}})
|
||||
panel = {c["id"]: c for c in inp["panel_cells"]}
|
||||
cost_id = {"miners": "C-miners", "internal provers": "C-provers", "minimum validators": "C-validators", "maintenance": "C-maintenance"}
|
||||
rows = []
|
||||
for H in inp["horizons_years"]:
|
||||
for sc in scenarios:
|
||||
for role in ROLES:
|
||||
rec = split[H][role]
|
||||
cum = sum(split[y][role] for y in range(1, H + 1))
|
||||
y1 = split[1][role]
|
||||
frac = Fraction(rec, y1) if y1 else None
|
||||
ceil_exact = sc["multiple_by_year"][H] * Fraction(rec, B)
|
||||
cost = panel[cost_id[role]]["value"]
|
||||
cov = "" if cost is None else str(Fraction(ceil_exact) / Fraction(str(cost)))
|
||||
decision = "BLOCKED" if role in ("minimum validators", "maintenance") else "NOT RUN"
|
||||
rows.append({"key": f"y{H}-{sc['id']}-{role.replace(' ', '_')}", "horizon": H, "scenario": sc["id"], "label": sc["label"],
|
||||
"multiple_num": sc["m"].numerator, "multiple_den": sc["m"].denominator, "role": role,
|
||||
"native_receipts_base_units": rec, "cumulative_base_units": cum, "fraction_of_year1": frac,
|
||||
"ceiling_exact": ceil_exact, "role_cost_bu": cost, "coverage": cov,
|
||||
"external_job_receipts_base_units": 0, "decision": decision})
|
||||
# tips that would hold the miners' year-1 receipts at constant purchasing power, through the code's 80% tip route
|
||||
tip_miner = Fraction(route(inp, "R3-tip-miner")["share_percent_num"], 100)
|
||||
feerep = []
|
||||
for y in range(1, YEARS_MODELLED + 1):
|
||||
gap = max(0, split[1]["miners"] - split[y]["miners"]) # year 2 pays more than year 1 (no ramp): no tips needed
|
||||
need = Fraction(gap) / tip_miner
|
||||
feerep.append({"year": y, "miner_gap_base_units": gap, "tips_needed_exact": need, "tips_needed_bu": need / B})
|
||||
dec = s["decimals"]
|
||||
bound_per_year = 2 * 10 * Y # two floors (rate per block, pool share), each under one base unit, at up to 10 blocks a second
|
||||
return {"emission": emission, "split": split, "baseline_base_units": B, "years_modelled": YEARS_MODELLED,
|
||||
"total_schedule_base_units": sched.curve_total if s["tail"]["kind"] == "cap" else sched.supply_at(200 * Y),
|
||||
"emission_after_curve": after, "curve_end_years": Fraction(sched.curve_end, Y), "periods": len(sched.rates) - 1,
|
||||
"scenarios": scenarios, "rows": rows, "feerep": feerep, "tv01": read_tv01(inp, root, sched, YEARS_MODELLED),
|
||||
"rounding_bound_base_units": bound_per_year, "decimals": dec, "schedule": sched}
|
||||
|
||||
|
||||
# ---- formatting ----------------------------------------------------------------------------------------------
|
||||
|
||||
def coins(b, dec=8):
|
||||
q, r = divmod(b, 10 ** dec)
|
||||
return f"{q}.{r:0{dec}d}"
|
||||
|
||||
|
||||
def whole(b, dec=8):
|
||||
return format(b // 10 ** dec, ",")
|
||||
|
||||
|
||||
def fx(fr, d):
|
||||
if fr is None:
|
||||
return ""
|
||||
fr = Fraction(fr)
|
||||
sign = "-" if fr < 0 else ""
|
||||
fr = abs(fr)
|
||||
n = (2 * fr.numerator * 10 ** d + fr.denominator) // (2 * fr.denominator)
|
||||
q, r = divmod(n, 10 ** d)
|
||||
return f"{sign}{q}.{r:0{d}d}" if d else f"{sign}{q}"
|
||||
|
||||
|
||||
def pct(fr, d=2):
|
||||
return "" if fr is None else fx(Fraction(fr) * 100, d) + "%"
|
||||
|
||||
|
||||
def mult(sc):
|
||||
m = sc["m"]
|
||||
return f"{fx(m, 2).rstrip('0').rstrip('.')}x"
|
||||
|
||||
|
||||
def csv_bytes(header, rows):
|
||||
buf = io.StringIO()
|
||||
w = csv.writer(buf, lineterminator="\n")
|
||||
w.writerow(header)
|
||||
for r in rows:
|
||||
w.writerow(r)
|
||||
return buf.getvalue().encode("utf-8")
|
||||
|
||||
|
||||
ROLE_ROUTE = {"miners": "R1-miner", "internal provers": "R1-pool", "minimum validators": "R1-validators", "maintenance": "R1-maintenance"}
|
||||
|
||||
|
||||
def meaning(row, model):
|
||||
H, role = row["horizon"], row["role"]
|
||||
c = fx(row["ceiling_exact"], 6)
|
||||
mm = f"{fx(Fraction(row['multiple_num'], row['multiple_den']), 2)}x"
|
||||
if role in ("minimum validators", "maintenance"):
|
||||
return (f"In year {H} at {mm} the protocol routes nothing to {role}, so any positive minimum cost for the role is in the failure region "
|
||||
f"until D03 names its recurring payer.")
|
||||
return (f"In year {H} at {mm} the {role} receive {whole(row['native_receipts_base_units'])} coins, {pct(row['fraction_of_year1'])} of their year-1 receipts, "
|
||||
f"which covers a minimum {role} cost of at most {c} BU; a panel cost above {c} BU puts this cell in the failure region.")
|
||||
|
||||
|
||||
def render_files(inp, model, repo_root=None):
|
||||
root = repo_root or globals()["repo_root"]()
|
||||
files = {}
|
||||
B = model["baseline_base_units"]
|
||||
dec = model["decimals"]
|
||||
# budget.csv: every horizon, scenario and role
|
||||
hdr = ["horizon_year", "scenario", "multiple", "role", "route", "route_status", "native_receipts_base_units", "native_receipts_coins",
|
||||
"cumulative_years_1_to_h_coins", "fraction_of_role_year1", "fundable_cost_ceiling_bu", "role_cost_bu_panel", "coverage",
|
||||
"external_job_receipts", "scenario_class_panel", "decision", "meaning"]
|
||||
out = []
|
||||
for r in model["rows"]:
|
||||
rt = route(inp, ROLE_ROUTE[r["role"]])
|
||||
out.append([r["horizon"], r["scenario"], fx(Fraction(r["multiple_num"], r["multiple_den"]), 2), r["role"], rt["id"], rt["status"],
|
||||
r["native_receipts_base_units"], coins(r["native_receipts_base_units"], dec), coins(r["cumulative_base_units"], dec),
|
||||
fx(r["fraction_of_year1"], 8), fx(r["ceiling_exact"], 8), "" if r["role_cost_bu"] is None else r["role_cost_bu"], r["coverage"],
|
||||
"0 (D04: the external-job rate is not ratified)", "", r["decision"], meaning(r, model)])
|
||||
files["budget.csv"] = csv_bytes(hdr, out)
|
||||
# emission.csv: the schedule year by year
|
||||
out = []
|
||||
cum = 0
|
||||
cap = inp["schedule"]["cap_coins"] * 10 ** dec
|
||||
for y in range(1, YEARS_MODELLED + 1):
|
||||
e = model["emission"][y]
|
||||
cum += e
|
||||
sp = model["split"][y]
|
||||
out.append([y, e, coins(e, dec), coins(cum, dec), fx(Fraction(cum, cap), 8), coins(sp["miners"], dec), coins(sp["internal provers"], dec),
|
||||
fx(Fraction(e, B), 8)])
|
||||
files["emission.csv"] = csv_bytes(["year", "emission_base_units", "emission_coins", "cumulative_coins", "cumulative_fraction_of_cap",
|
||||
"miners_coins", "internal_provers_coins", "fraction_of_year1_emission"], out)
|
||||
# fee-replacement.csv
|
||||
out = []
|
||||
for f in model["feerep"]:
|
||||
out.append([f["year"], coins(f["miner_gap_base_units"], dec), coins(f["tips_needed_exact"].numerator // f["tips_needed_exact"].denominator, dec),
|
||||
fx(f["tips_needed_bu"], 8), "no tip route to provers in the node's code (BLOCKED row B-01)"])
|
||||
files["fee-replacement.csv"] = csv_bytes(["year", "miner_gap_to_year1_coins", "tips_needed_per_year_coins_floor", "tips_needed_as_fraction_of_baseline",
|
||||
"internal_provers"], out)
|
||||
# parameters.csv
|
||||
out = []
|
||||
s = inp["schedule"]
|
||||
out.append(["S-rate", "launch rate", s["launch_rate_base_units_per_second"], "base units per DAA second (8 decimals)", s["status"], s["source"]])
|
||||
out.append(["S-ramp", "launch ramp", f"{s['ramp_seconds']} s from {s['ramp_start_percent']}%", "DAA seconds", s["status"], s["source"]])
|
||||
out.append(["S-step", "decay step", f"{s['step_seconds']} s, rate divided by {s['step_divisor']}", "DAA seconds", s["status"], s["source"]])
|
||||
out.append(["S-tail", "tail", s["tail"]["kind"], "", "RATIFIED (D01) and " + s["status"], s["source"] + "; " + s["ratified_by"]])
|
||||
out.append(["S-cap", "cap", s["cap_coins"], "coins", "RATIFIED (D01) and " + s["status"], s["source"]])
|
||||
for r in inp["routes"]:
|
||||
out.append([r["id"], r["route"], f"{r['share_percent_num']}%" if r["status"] != "UNRATIFIED" else "not used (zero)", f"to {r['role']}", r["status"], r["source"]])
|
||||
for sc in inp["scenarios"]:
|
||||
out.append([sc["id"], "scenario multiple", fx(Fraction(sc["multiple_num"], sc["multiple_den"]), 2), "of the baseline's purchasing power, constant over the horizon", "RATIFIED (TV-04 method words)", sc["label"]])
|
||||
out.append(["X-ext", "external jobs per year", 0, "jobs", "UNRATIFIED (D04)", "TV-04 method: zero external jobs; the rate is a parameter, never a result"])
|
||||
for c in inp["panel_cells"]:
|
||||
out.append([c["id"], c["parameter"], "" if c["value"] is None else c["value"], c["unit"], c["status"], c["source_hint"]])
|
||||
files["parameters.csv"] = csv_bytes(["id", "parameter", "value", "unit", "status", "source"], out)
|
||||
# blocked.csv
|
||||
files["blocked.csv"] = csv_bytes(["id", "row", "waits_on", "earliest_clock_uk"], [[b["id"], b["row"], b["waits_on"], b["clock"]] for b in blocked_rows(inp, model)])
|
||||
if model["tv01"]["rows"]:
|
||||
files["tv01-reconcile.csv"] = csv_bytes(["year", "tv01_base_units", "tv04_base_units", "agree"], [[r["year"], r["tv01"], r["tv04"], r["agree"]] for r in model["tv01"]["rows"]])
|
||||
files["README.md"] = readme(inp, model, files, root).encode("utf-8")
|
||||
return files
|
||||
|
||||
|
||||
def blocked_rows(inp, model):
|
||||
return [
|
||||
{"id": "B-01", "row": "the internal provers' share of the priority fee", "waits_on": "D04's frozen routes (TV-01): the node's code pays the 80% tip share to the block's beneficiary alone (igneum/exec executor.rs lines 318 to 329, line 729), the litepaper's routing table row 3 and the design text read '80% the block's miner and provers' with no split; the master, p. 36, asks for the discrepancy resolved before security income is modelled", "clock": "the TV-01 supply spec, due 13:00 UK today; the node lane names where the rule lives"},
|
||||
{"id": "B-02", "row": "internal provers: paid against assigned", "waits_on": "the stranded-credit rule (the litepaper: unclaimed pool credit stays in the escrow, the fix is designed) and the single coinbase payout that replaces the devnet's burn of the 20% output; this table carries the assigned 20%, an upper bound on what provers are paid", "clock": "the node lane's answer; TV-02's replay separates assigned, paid and burned"},
|
||||
{"id": "B-03", "row": "minimum validators: the recurring payer", "waits_on": "D03 (ratified: separate accountable budgets) names no payer for the minimum validator role; the protocol routes it nothing (no coinbase output, no fee share)", "clock": "the panel and the founder; no clock in the ratified rules"},
|
||||
{"id": "B-04", "row": "maintenance: committed resources", "waits_on": "the master, p. 68, P13 (at least 12 months committed; burned fees, rising prices and uncommitted sales excluded) and the volume, p. 31; the registry's P13 deferral note (the founder, 8 October 2026, 18:2x UK); the protocol routes maintenance nothing", "clock": "the founder's lifting of the P13 deferral"},
|
||||
{"id": "B-05", "row": "role costs (four cells) and the scenario classes", "waits_on": "the independent panel: the minimum required cost per role per year in BU, and which scenario-year cells are approved viable and which are collapse cases, declared before results (the master, p. 68, P12)", "clock": "the panel's reading; every coverage cell reads NOT RUN until then"},
|
||||
{"id": "B-06", "row": "the tail-vote clause beside the cap", "waits_on": "D01 (ratified: capped issuance) against the litepaper's clause sending a tail reward to the miners' vote when external proving revenue is under one fifth of the subsidy after year 5 (with zero external jobs that condition holds from year 5 in every scenario here); the volume, p. 12: no undisclosed future rescue. This model mints no tail", "clock": "TV-01's frozen contract (13:00 UK today) and the site lane's wording"},
|
||||
{"id": "B-07", "row": "the testnet parameters' 1% tail", "waits_on": "params.rs line 2014: TESTNET_PARAMS carries EmissionSchedule::TESTNET_1 (emission.rs lines 116 to 123, a 1 percent a year tail), while MAINNET_PARAMS carries the capped CURRENT (line 1858); this model reads the mainnet params; the node lane answers which schedule a value-bearing network carries", "clock": "the node lane's one-question answer"},
|
||||
{"id": "B-08", "row": "the schedule itself", "waits_on": "D02 (approved: the same-cap comparison; the schedule pending evidence): every figure here is conditional on EmissionSchedule::CURRENT and regenerates from inputs.json if the schedule changes", "clock": "TV-03's emission comparison"},
|
||||
{"id": "B-09", "row": "safe behaviour in the collapse cases", "waits_on": "the gate's words for collapse scenarios (safe behaviour, not universal profit) are native evidence this model cannot give: contraction of the finality vote weight, honest pauses and recovery labelled apart from finality (D05) belong to TV-07, TV-09 and TV-15", "clock": "those gates' native runs"},
|
||||
]
|
||||
|
||||
|
||||
def readme(inp, model, files, root):
|
||||
B = model["baseline_base_units"]
|
||||
dec = model["decimals"]
|
||||
src = inp["sources"]
|
||||
gen_sha = sha256_file(os.path.join(HERE, "tv04_budget.py"))
|
||||
inp_sha = sha256_file(os.path.join(HERE, "inputs.json"))
|
||||
test_sha = sha256_file(os.path.join(HERE, "test_tv04.py"))
|
||||
scs = model["scenarios"]
|
||||
L = []
|
||||
a = L.append
|
||||
a("# TV-04, the security budget without price rescue (Token Value Phase 0)")
|
||||
a("")
|
||||
a("Status: **NOT RUN**. Phase 0 lands documents and tests only; nothing activates. The independent panel reads this model; until it does, every verdict below reads NOT RUN, and the rows that wait on an unratified choice read BLOCKED. This document never writes PASS.")
|
||||
a("")
|
||||
a("Every figure on this page and in the CSVs beside it is written by `tools/token-value/tv-04/tv04_budget.py` from `tools/token-value/tv-04/inputs.json`. No price figure appears anywhere in it (VR-04 and the never-published list); the minus-90-percent case is a 0.1x multiple of the 1x path.")
|
||||
a("")
|
||||
a("## The gate")
|
||||
a("")
|
||||
g = {x["id"]: x for x in json.load(open(os.path.join(root, src["rules_and_gates"]["path"]), encoding="utf-8"))["gates"]} if os.path.exists(os.path.join(root, src["rules_and_gates"]["path"])) else {}
|
||||
t4 = g.get("TV-04", {})
|
||||
a(f"TV-04, {t4.get('title', 'Security budget without price rescue')} (the volume, p. 58; rules-and-gates.json). Setup: \"{t4.get('setup', '')}\" Method: \"{t4.get('procedure', '')}\" Pass words: \"{t4.get('pass_criterion', '')}\" Evidence: \"{t4.get('evidence', '')}\"")
|
||||
a("")
|
||||
a("## Sources, by sha256")
|
||||
a("")
|
||||
a("| Source | Path | sha256 |")
|
||||
a("|---|---|---|")
|
||||
a(f"| The volume's rules, gates and decisions | `{src['rules_and_gates']['path']}` | `{src['rules_and_gates']['sha256']}` |")
|
||||
a(f"| The volume | `{src['volume_pdf']['path']}` | `{src['volume_pdf']['sha256']}` |")
|
||||
a(f"| The master (light edition in the tree) | `{src['master_pdf']['path']}` | `{src['master_pdf']['sha256']}` |")
|
||||
a(f"| The litepaper ({src['litepaper']['tree']}) | `{src['litepaper']['path']}` | `{src['litepaper']['sha256']}` |")
|
||||
for path, sha in src["node"]["files"].items():
|
||||
a(f"| The node, {src['node']['branch']} {src['node']['commit'][:8]} | `{path}` | `{sha}` |")
|
||||
tv = model["tv01"]
|
||||
a(f"| The TV-01 supply spec | `{TV01_REL}` | {('`' + tv['sha256'] + '`') if tv.get('sha256') else 'not in the tree'} |")
|
||||
a("")
|
||||
a(f"The supplied master original reads `{src['master_pdf']['note'].split('reads ')[1].split(',')[0]}` in the volume's original_artifacts; the tree carries the light edition of the same substance. The TV-01 supply spec: {tv['status']}.")
|
||||
a("")
|
||||
a("## The ratified rules this model applies")
|
||||
a("")
|
||||
a("| Rule | As ratified (the founder, 9 October 2026, 09:2x UK) | What it does here |")
|
||||
a("|---|---|---|")
|
||||
a("| D01 | Capped issuance, subject to TV-04 | The schedule's tail is the cap; no row mints after the curve; the test fails on a tail mint. |")
|
||||
a("| D02 | The same-cap emission comparison approved, the schedule pending evidence | Every figure is conditional on the node's current schedule (BLOCKED row B-08). |")
|
||||
a("| D03 | Separate accountable budgets | Four roles, four budgets, never pooled; a role with no recurring payer is a BLOCKED row. |")
|
||||
a("| D04 | Explicit routing; the external-job rate not ratified | Each receipt names its route and status; external jobs are zero and the published rate is a parameter only. |")
|
||||
a("| D05 | Recovery never shown as finality | No row reads a contraction, a pause or a recovery path as finality; the model carries no finality figure (B-09). |")
|
||||
a("| VR-05 | Fund necessary security (p. 50) | Miners, internal provers, minimum validators and maintenance modelled separately through declining issuance; no external sale funds any role. |")
|
||||
a("| VR-04, VR-08 | No artificial return; separate value and money flows | No price, no appreciation, every coin in exactly one route, burns never a receipt. |")
|
||||
a("| P12, P13 | The master, p. 68 | The revenue bands and the viable or collapse declaration (P12); committed maintenance only (P13). |")
|
||||
a("")
|
||||
a("## Method")
|
||||
a("")
|
||||
a(f"1. The schedule. The node's `EmissionSchedule::CURRENT` on the mainnet params (emission.rs lines 103 to 110; params.rs line 1858): {inp['schedule']['launch_rate_base_units_per_second']:,} base units a DAA second at 8 decimals, a {inp['schedule']['ramp_seconds']:,}-second ramp from {inp['schedule']['ramp_start_percent']}%, the rate halved every {inp['schedule']['step_seconds']:,} DAA seconds, the tail the cap. Each year's emission is the node's closed-form scheduled supply at the year's end minus its start, in integers. The rate reaches zero after {model['periods']} halvings ({fx(model['curve_end_years'], 0)} years) and sums to {whole(model['total_schedule_base_units'])} coins under the {inp['schedule']['cap_coins']:,} cap. Per-block rounding (the per-block floor of the rate and the pool's floor) moves a year's figures by under {(model['rounding_bound_base_units'] + 10 ** dec - 1) // 10 ** dec} coins at up to ten blocks a second.")
|
||||
a(f"2. The baseline. The whole year-1 subsidy, {whole(B)} coins ({coins(B, dec)}), the ramp included. One BU is its purchasing power on the 1x path.")
|
||||
a("3. The routing. Emission: 80% to the block's producer (miners), 20% to the proving pool (internal provers), nothing to validators or maintenance (igneum.rs lines 43 to 44, 85 to 88, 123 to 126; the signing bonus is off on the mainnet params, lines 1809 to 1810). Fees: the base fee of both gas dimensions burned in full; the tip 80% to the beneficiary and 20% to developers (exec config.rs lines 75 to 76). External jobs: zero; the published 90/10 is UNRATIFIED under D04 and enters no row.")
|
||||
a("4. The scenarios. Multiples 0.1x (the minus-90-percent case), 0.25x, 1x, 4x and 10x of the baseline's purchasing power, each one constant over the whole horizon, so no row assumes appreciation. Native receipts are the same in every scenario; the multiple scales what they buy.")
|
||||
a("5. The cost side. The volume gives no cost figure (p. 14 lists what counts as revenue; p. 31 the maintenance evidence) and the master gives stress grids, not role costs (p. 68, P12: tariffs, productive lives, development cases; p. 36: historical shard timings, not reproduced for this edition). So each role's minimum cost is a PANEL cell in BU, empty here. For each cell the model gives the fundable-cost ceiling, multiple x role receipts / baseline: a panel cost above it is the failure region.")
|
||||
a("6. The verdict. In the gate's words: an approved viable scenario must fund the minimum required roles without hidden issuance or assumed appreciation, with failure regions stated; a collapse scenario needs safe behaviour, not universal profit. Which cells are viable and which are collapse cases is the panel's declaration before results (P12). Every cell reads NOT RUN, or BLOCKED where the role has no payer.")
|
||||
a("7. Fee volatility. The tables carry zero tips (the subsidy alone). The fee-replacement table gives, year by year, the tip volume that would hold the miners' year-1 receipts at constant purchasing power through the code's 80% tip route. Tip timing and spikes (p. 14) are the panel's T-tip cell.")
|
||||
a("")
|
||||
a("## The parameter table")
|
||||
a("")
|
||||
a("Every cell's status: RATIFIED (the founder's ratification), IMPLEMENTED (the node's code, cited by line, taken under D04's explicit routing), UNRATIFIED (a parameter, never a result), PANEL (the independent panel fills it; empty here), BLOCKED (waits on a named choice). The full table with sources is `parameters.csv`.")
|
||||
a("")
|
||||
a("| Id | Parameter | Value | Status |")
|
||||
a("|---|---|---|---|")
|
||||
for row in csv.reader(io.StringIO(files["parameters.csv"].decode("utf-8"))):
|
||||
if row[0] == "id":
|
||||
continue
|
||||
v = row[2] if row[2] != "" else "(empty)"
|
||||
st = row[4]
|
||||
mark = "**" if st.startswith(("UNRATIFIED", "PANEL", "BLOCKED")) else ""
|
||||
a(f"| {row[0]} | {row[1]} | {v} | {mark}{st}{mark} |")
|
||||
a("")
|
||||
for H in inp["horizons_years"]:
|
||||
a(f"## Horizon: year {H}")
|
||||
a("")
|
||||
a(f"The budget each role receives in year {H} (zero tips, zero external jobs), and the fundable-cost ceiling in BU at each multiple.")
|
||||
a("")
|
||||
a("| Role | Route (status) | Receipts in year " + str(H) + " (coins) | Of the role's year 1 | Years 1 to " + str(H) + " (coins) | " + " | ".join(f"Ceiling at {mult(sc)}" for sc in scs) + " | Panel cost | Decision |")
|
||||
a("|---|---|---|---|---|" + "---|" * len(scs) + "---|---|")
|
||||
for role in ROLES:
|
||||
rs = [r for r in model["rows"] if r["horizon"] == H and r["role"] == role]
|
||||
r0 = rs[0]
|
||||
rt = route(inp, ROLE_ROUTE[role])
|
||||
ceils = " | ".join(fx(r["ceiling_exact"], 6) for r in rs)
|
||||
a(f"| {role} | {rt['id']} ({rt['status']}) | {whole(r0['native_receipts_base_units'])} | {pct(r0['fraction_of_year1']) or 'none (no route)'} | {whole(r0['cumulative_base_units'])} | {ceils} | (empty) | {r0['decision']} |")
|
||||
a(f"| external jobs | R4, R5 (UNRATIFIED) | 0 | none | 0 | " + " | ".join("0" for _ in scs) + " | (not used) | parameter only |")
|
||||
a("")
|
||||
a("What each row means:")
|
||||
a("")
|
||||
for role in ROLES:
|
||||
r = [x for x in model["rows"] if x["horizon"] == H and x["role"] == role and x["scenario"] == "m100"][0]
|
||||
lo = [x for x in model["rows"] if x["horizon"] == H and x["role"] == role and x["scenario"] == "m010"][0]
|
||||
hi = [x for x in model["rows"] if x["horizon"] == H and x["role"] == role and x["scenario"] == "m1000"][0]
|
||||
if role in ("minimum validators", "maintenance"):
|
||||
a(f"- {role}: the protocol pays this role nothing in year {H} at any multiple, so it is funded only by a payer D03 has not yet named (B-03, B-04), and any positive minimum cost is in the failure region.")
|
||||
else:
|
||||
a(f"- {role}: the role's year-{H} budget buys at most {fx(lo['ceiling_exact'], 6)} BU in the minus-90-percent case, {fx(r['ceiling_exact'], 6)} BU at 1x and {fx(hi['ceiling_exact'], 6)} BU at 10x, so a panel minimum cost above the cell's ceiling is the failure region for that scenario.")
|
||||
a("- external jobs: zero in every scenario by the method; the published rate is unratified (D04) and funds no role here.")
|
||||
a("")
|
||||
a("## The verdict per scenario and year")
|
||||
a("")
|
||||
a("In the gate's words. The class of each cell (approved viable, or collapse) is the panel's declaration before results; the computed ceilings stand beside it. The failure region of a cell is every role whose minimum cost exceeds its ceiling, and minimum validators and maintenance at any positive cost.")
|
||||
a("")
|
||||
a("| Year | Scenario | Miners' ceiling (BU) | Internal provers' ceiling (BU) | Validators, maintenance | Class (panel) | Gate test that applies | Verdict |")
|
||||
a("|---|---|---|---|---|---|---|---|")
|
||||
for H in inp["horizons_years"]:
|
||||
for sc in scs:
|
||||
mrow = [x for x in model["rows"] if x["horizon"] == H and x["scenario"] == sc["id"] and x["role"] == "miners"][0]
|
||||
prow = [x for x in model["rows"] if x["horizon"] == H and x["scenario"] == sc["id"] and x["role"] == "internal provers"][0]
|
||||
a(f"| {H} | {sc['label']} | {fx(mrow['ceiling_exact'], 6)} | {fx(prow['ceiling_exact'], 6)} | 0 (no payer, BLOCKED) | (empty) | viable: funds the minimum required roles without hidden issuance or assumed appreciation; collapse: safe behaviour, not universal profit | NOT RUN |")
|
||||
a("")
|
||||
a("## Fee replacement: the tips the miners' year-1 budget would need")
|
||||
a("")
|
||||
a("Tips per year, at constant purchasing power, that would bring the miners' receipts back to their year-1 level through the code's 80% tip route (year 2 pays more than the ramped year 1, so it needs none). Base fees are burned and restore nothing; provers have no tip route in the code (B-01). The full series is `fee-replacement.csv`.")
|
||||
a("")
|
||||
a("| Year | Miners' gap to year 1 (coins) | Tips needed per year (coins) | As a fraction of the baseline |")
|
||||
a("|---|---|---|---|")
|
||||
for f in model["feerep"]:
|
||||
if f["year"] in inp["horizons_years"] or f["year"] in (2, 3):
|
||||
a(f"| {f['year']} | {whole(f['miner_gap_base_units'])} | {whole(f['tips_needed_exact'].numerator // f['tips_needed_exact'].denominator)} | {fx(f['tips_needed_bu'], 4)} |")
|
||||
a("")
|
||||
e = model["emission"]
|
||||
m1 = model["split"][1]["miners"]
|
||||
a("## What the result means")
|
||||
a("")
|
||||
a(f"Under the ratified cap with zero external jobs, the subsidy that pays the miners and the internal provers falls to {pct(Fraction(e[5], e[1]))} of year 1 in year 5, {pct(Fraction(e[10], e[1]))} in year 10 and {pct(Fraction(e[20], e[1]))} in year 20; at 10x purchasing power the year-20 miner budget buys {fx([x for x in model['rows'] if x['horizon'] == 20 and x['scenario'] == 'm1000' and x['role'] == 'miners'][0]['ceiling_exact'], 6)} BU, and in the minus-90-percent case {fx([x for x in model['rows'] if x['horizon'] == 20 and x['scenario'] == 'm010' and x['role'] == 'miners'][0]['ceiling_exact'], 6)} BU.")
|
||||
a(f"Holding the miners' year-1 budget needs tips of {fx(model['feerep'][9]['tips_needed_bu'], 4)} of the baseline a year by year 10 and {fx(model['feerep'][19]['tips_needed_bu'], 4)} by year 20; the internal provers have no fee route in the node's code, so nothing in the ratified routing replaces their declining 20%; minimum validators and maintenance receive nothing from the protocol at any horizon.")
|
||||
a("So whether TV-04 can pass turns on four things this model cannot supply: the panel's role costs and viable-or-collapse declarations, the tip level, a named payer for validators and maintenance, and the provers' fee route. Those are the BLOCKED rows below.")
|
||||
a("")
|
||||
a("## BLOCKED rows")
|
||||
a("")
|
||||
a("| Id | Row | Waits on | Earliest clock (UK) |")
|
||||
a("|---|---|---|---|")
|
||||
for b in blocked_rows(inp, model):
|
||||
a(f"| {b['id']} | {b['row']} | {b['waits_on']} | {b['clock']} |")
|
||||
a("")
|
||||
a("## Files")
|
||||
a("")
|
||||
a("| File | What | sha256 |")
|
||||
a("|---|---|---|")
|
||||
desc = {"budget.csv": "every horizon x scenario x role row, with its meaning", "emission.csv": "the schedule and the role split, years 1 to 20",
|
||||
"fee-replacement.csv": "the tips the miners' year-1 budget would need, years 1 to 20", "parameters.csv": "every parameter with its status and source",
|
||||
"blocked.csv": "the BLOCKED rows", "tv01-reconcile.csv": "the TV-01 supply spec against this schedule, year by year"}
|
||||
for name in sorted(files):
|
||||
a(f"| `{name}` | {desc.get(name, '')} | `{hashlib.sha256(files[name]).hexdigest()}` |")
|
||||
a("")
|
||||
a("## Reproduce")
|
||||
a("")
|
||||
a(f"The generator `tools/token-value/tv-04/tv04_budget.py` (sha256 `{gen_sha}`), its inputs `tools/token-value/tv-04/inputs.json` (sha256 `{inp_sha}`) and its tests `tools/token-value/tv-04/test_tv04.py` (sha256 `{test_sha}`). Standard-library Python 3, integers and fractions, no clock, no network.")
|
||||
a("")
|
||||
a("```")
|
||||
a(f"python3 tools/token-value/tv-04/tv04_budget.py --out {OUT_REL}")
|
||||
a(f"python3 tools/token-value/tv-04/tv04_budget.py --check {OUT_REL}")
|
||||
a("python3 tools/token-value/tv-04/test_tv04.py")
|
||||
a("python3 tools/token-value/tv-04/test_tv04.py --known-failed")
|
||||
a("tools/token-value/tv-04/run-on-box.sh red|green|known-failed|generate|check")
|
||||
a("```")
|
||||
a("")
|
||||
a("Runs happen on build-9 only (`run-on-box.sh`: the committed tree as a git archive, a pid file at build-9:/home/build/tv-04/run.pid before the job starts, mirrored on build-1's queue while live). The run record (the known-failed first run, the green run, the mutant run, the two-generation byte comparison and the check against the committed files) is `RUNS.md` beside this file.")
|
||||
a("")
|
||||
a("## Registry")
|
||||
a("")
|
||||
a("The registry batch for TV-04 is `registry-batch-tv-04.json` beside this file: one cell, the case TV-04, the verdict NOT RUN, method model, this directory's files and the build-9 run logs as its evidence. The CI steward places it under `tools/ci/batches/` with its map cell and records it through `tools/ci/test-record.mjs --record`; this landing writes no registry row.")
|
||||
a("")
|
||||
return "\n".join(L)
|
||||
|
||||
|
||||
def write_outputs(inp, out_dir, repo_root=None):
|
||||
model = build_model(inp, repo_root=repo_root)
|
||||
files = render_files(inp, model, repo_root=repo_root)
|
||||
os.makedirs(out_dir, exist_ok=True)
|
||||
for name, data in sorted(files.items()):
|
||||
with open(os.path.join(out_dir, name), "wb") as f:
|
||||
f.write(data)
|
||||
return files
|
||||
|
||||
|
||||
def main():
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument("--out")
|
||||
ap.add_argument("--check")
|
||||
a = ap.parse_args()
|
||||
with open(os.path.join(HERE, "inputs.json"), "r", encoding="utf-8") as f:
|
||||
inp = json.load(f)
|
||||
if a.out:
|
||||
files = write_outputs(inp, a.out)
|
||||
for name in sorted(files):
|
||||
print(f"{hashlib.sha256(files[name]).hexdigest()} {name}")
|
||||
return 0
|
||||
if a.check:
|
||||
model = build_model(inp)
|
||||
files = render_files(inp, model)
|
||||
bad = []
|
||||
for name, data in sorted(files.items()):
|
||||
p = os.path.join(a.check, name)
|
||||
if not os.path.exists(p) or open(p, "rb").read() != data:
|
||||
bad.append(name)
|
||||
print(f"RESULT tv04 check {'committed outputs equal a fresh generation' if not bad else 'DIFFERS: ' + ','.join(bad)} ({len(files) - len(bad)}/{len(files)})")
|
||||
return 0 if not bad else 1
|
||||
ap.print_help()
|
||||
return 2
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
|
|
@ -155,6 +155,14 @@
|
|||
.jobrow { display: flex; gap: 10px; flex-wrap: wrap; border-top: 1px solid rgba(255,255,255,.06); padding: 2px 0; }
|
||||
.jobrow b { min-width: 56px; }
|
||||
.muted { opacity: .7; }
|
||||
.server > .row { display: flex; gap: 14px; align-items: baseline; flex-wrap: wrap; cursor: pointer; padding: 10px 12px; font-size: 13px; }
|
||||
.server > .row:hover { background: rgba(255,255,255,.03); }
|
||||
.server > .row .chev { width: 12px; opacity: .8; }
|
||||
.server > .row .rname { font-weight: 600; }
|
||||
.server > .row small { opacity: .6; }
|
||||
.server > .row .rstat { flex: 1 1 auto; opacity: .9; }
|
||||
.server > .row .rage { opacity: .7; font-size: 12px; }
|
||||
.server:not(.open) > .panel { display: none; }
|
||||
</style></head><body>
|
||||
<div class="wrap">
|
||||
<header>
|
||||
|
|
@ -223,8 +231,8 @@ function boxState(b) { // live | down | provisioning, with the line the cards
|
|||
}
|
||||
const buildHeld = b => (b.slots && b.slots.held || []).filter(h => /^build-\d+$/.test(h.slot)).length;
|
||||
const boxesOf = d => (Array.isArray(d.boxes) && d.boxes.length ? d.boxes : d.box ? [{ ...d.box, source: d.sources && d.sources.box, headline: d.headline }] : []);
|
||||
// load by pid (9 October 2026): every job the box's collector lists from /proc (node, miner, prover, worker, suite, fuzz, harness,
|
||||
// service, chip, archive), not only the cargo builds; counts per kind, then the list with pid, age and resident set
|
||||
// load by process (9 October 2026; no pid number is served, the identity scrub): every job the box's collector lists from /proc (node, miner, prover, worker, suite, fuzz, harness,
|
||||
// service, chip, archive), not only the cargo builds; counts per kind, then the list with the command, age and resident set
|
||||
const JOB_ORDER = ['node', 'fuzz', 'suite', 'harness', 'prover', 'miner', 'worker', 'chip', 'archive', 'service', 'script', 'other', 'browser'];
|
||||
function jobsSummary(b) {
|
||||
const c = (b && b.jobs_by_kind) || {}; const parts = JOB_ORDER.filter(k => c[k]).map(k => `${c[k]} ${k}${c[k] === 1 ? '' : (k === 'browser' ? 's' : k.endsWith('s') ? '' : 's')}`);
|
||||
|
|
@ -232,16 +240,16 @@ function jobsSummary(b) {
|
|||
}
|
||||
function jobsBlock(b) {
|
||||
const jobs = (b && b.jobs) || []; const sum = jobsSummary(b);
|
||||
if (!jobs.length && !sum) return `<div class="jobs"><span class="muted">load by pid: nothing but the collector (no node, suite, fuzz or harness process on this box)</span></div>`;
|
||||
const rows = jobs.slice(0, 14).map(j => `<div class="jobrow"><b>${esc(j.kind)}</b> <span>pid ${j.pid}</span> <span>${esc(j.comm)}</span> <span>${j.elapsed_s === null ? '' : esc(fmtDurShort(j.elapsed_s)) + ' up'}</span> <span>${j.rss_mb} MB</span> <span class="muted" title="${esc(j.cmd)}">${esc(j.cmd.slice(0, 96))}</span></div>`).join('');
|
||||
return `<div class="jobs"><div class="jobshead">load by pid: ${esc(sum || 'none')}${jobs.length > 14 ? ` (${jobs.length - 14} more in workers.json)` : ''}</div>${rows}</div>`;
|
||||
if (!jobs.length && !sum) return `<div class="jobs"><span class="muted">load by process: nothing but the collector (no node, suite, fuzz or harness process on this box)</span></div>`;
|
||||
const rows = jobs.slice(0, 14).map(j => `<div class="jobrow"><b>${esc(j.kind)}</b> <span>${esc(j.comm)}</span> <span>${j.elapsed_s === null ? '' : esc(fmtDurShort(j.elapsed_s)) + ' up'}</span> <span>${j.rss_mb} MB</span> <span class="muted" title="${esc(j.cmd)}">${esc(j.cmd.slice(0, 96))}</span></div>`).join('');
|
||||
return `<div class="jobs"><div class="jobshead">load by process: ${esc(sum || 'none')}${jobs.length > 14 ? ` (${jobs.length - 14} more in workers.json)` : ''}</div>${rows}</div>`;
|
||||
}
|
||||
function miniMinerLine(m) {
|
||||
const x = m && m.miner; if (!x) return 'no miner report';
|
||||
const daa = x.node_daa === null || x.node_daa === undefined ? '?' : Number(x.node_daa).toLocaleString('en-GB');
|
||||
const rate = x.rate_mhs === null || x.rate_mhs === undefined ? '0 MH/s' : `${Number(x.rate_mhs).toFixed(1)} MH/s`;
|
||||
const last = x.last_accepted_at ? String(x.last_accepted_at).replace(/^\d{4}-\d{2}-\d{2}T/, '') : 'none';
|
||||
return `igneum-app ${esc(x.app_version || '?')} · node DAA ${daa} (${esc(x.node_state || (x.synced ? 'synced' : 'unknown'))}) · ${rate} ${esc(x.mining || '')} · last block ${esc(last)} · node pid ${x.node_pid ?? '?'}`;
|
||||
return `igneum-app ${esc(x.app_version || '?')} · node DAA ${daa} (${esc(x.node_state || (x.synced ? 'synced' : 'unknown'))}) · ${rate} ${esc(x.mining || '')} · last block ${esc(last)}`;
|
||||
}
|
||||
function serverSection(b, i) {
|
||||
const id = `srv${i}`;
|
||||
|
|
@ -252,7 +260,11 @@ function serverSection(b, i) {
|
|||
const m = b.mem || {}, d = b.disk || {}, sc = b.sccache;
|
||||
const hit = sc && sc.hit_rate_pct !== null && sc.hit_rate_pct !== undefined ? sc.hit_rate_pct : null;
|
||||
const stale = (b.source && !b.source.ok) || st.stale;
|
||||
return `<section class="server ${b.running && b.running.length ? 'hot' : ''}" aria-label="${esc(b.name)}">
|
||||
const key = String(b.name || ''); const open = isOpen(key);
|
||||
const rowStatus = b.running && b.running.length ? `building: ${esc(kindLabel(b.running[0].kind))}${b.running.length > 1 ? ` +${b.running.length - 1}` : ''}` : (jobsSummary(b) || 'nothing but the collector');
|
||||
return `<section class="server ${b.running && b.running.length ? 'hot' : ''} ${open ? 'open' : ''}" aria-label="${esc(b.name)}" data-box="${esc(key)}">
|
||||
<div class="row" role="button" tabindex="0" aria-expanded="${open ? 'true' : 'false'}" title="click to ${open ? 'close' : 'open'} the detail"><span class="chev">${open ? '▾' : '▸'}</span><span class="rname">${esc(b.name)}</span><small>${esc(b.os || 'build server')}</small><span><b>${b.cores}</b> threads</span><span>load <b>${b.load ? Number(b.load[0]).toFixed(1) : '?'}</b></span><span class="rstat">${rowStatus}</span><span class="rage" ${stale ? 'style="color:var(--warn)"' : ''}>${stale ? 'STALE, ' : ''}read ${esc(ago(b.collected_at))}</span></div>
|
||||
<div class="panel">
|
||||
<div class="head"><div><div class="name">${esc(b.name)}<small>${esc(b.os || 'build server')}</small></div><div class="facts">${[`<b>${b.cores}</b> threads`, `<b>${esc(fmtUptime(b.uptime_s))}</b> up`, `load <b>${(b.load || []).map(x => Number(x).toFixed(1)).join(' / ')}</b>`, b.kernel ? `kernel <b>${esc(b.kernel)}</b>` : ''].filter(Boolean).map(x => `<span>${x}</span>`).join('')}</div></div>
|
||||
<div class="facts">${[...temps, b.net ? `net ↓<b>${esc(fmtBps(b.net.rx_bps))}</b> ↑<b>${esc(fmtBps(b.net.tx_bps))}</b>` : '', `<span title="${esc(b.collected_at)}" ${stale ? 'style="color:var(--warn)"' : ''}>${stale ? 'STALE, ' : ''}read ${esc(ago(b.collected_at))}</span>`].filter(Boolean).map(x => `<span>${x}</span>`).join('')}</div></div>
|
||||
<div class="cores" style="grid-template-columns:repeat(${n > 64 ? 48 : n > 32 ? 32 : n}, 1fr)" aria-label="${n} cores, busy share per core">${Array.from({ length: n }, (_, i) => { const p = per[i] ?? 0; return `<i class="${p >= 50 ? 'hot' : ''}" style="--h:${Math.max(2, p)}%" title="core ${i}: ${p}%"></i>`; }).join('')}</div>
|
||||
|
|
@ -264,8 +276,16 @@ function serverSection(b, i) {
|
|||
<div class="g">${arc(d.used_pct, tone(d.used_pct, 80, 92))}<div><div class="l">Disk ${esc(d.mount || '/srv')}</div><div class="v">${d.used_pct ?? '?'}%</div><div class="s">${esc(fmtBytes(d.used_bytes))} used, ${esc(fmtBytes(d.avail_bytes))} free</div></div></div>
|
||||
<div class="g">${arc(hit ?? 0, 'cool')}<div><div class="l">sccache hits</div><div class="v">${hit === null ? '–' : hit + '%'}</div><div class="s">${sc ? `${sc.hits ?? 0} hit, ${sc.misses ?? 0} miss, ${esc(sc.cache_size || '?')} of ${esc(sc.max_size || '?')}` : 'sccache not answering'}</div></div></div>
|
||||
<div class="g">${arc(b.slots ? (buildHeld(b) / Math.max(1, b.slots.count)) * 100 : 0, 'good')}<div><div class="l">Build slots</div><div class="v">${b.slots ? `${buildHeld(b)}/${b.slots.count}` : '–'}</div><div class="s">${b.queue && b.queue.length ? `${b.queue.length} waiting${b.queue.some(q => q.priority === 'gate') ? ', a gate first' : ''}` : 'nobody waiting'}</div></div></div>
|
||||
</div></section>`;
|
||||
</div></div></section>`;
|
||||
}
|
||||
// the per-box detail panels are collapsed by default (the founder, 9 October 2026 09:5x UK): one compact row per box, the panel
|
||||
// opens on click, several at once, the open set kept per viewer in localStorage (nothing leaves the browser)
|
||||
const OPEN_KEY = 'workers.open-boxes';
|
||||
function openSet() { try { return new Set(JSON.parse(localStorage.getItem(OPEN_KEY) || '[]')); } catch { return new Set(); } }
|
||||
function isOpen(name) { return openSet().has(name); }
|
||||
function toggleBox(name) { const o = openSet(); if (o.has(name)) o.delete(name); else o.add(name); try { localStorage.setItem(OPEN_KEY, JSON.stringify([...o])); } catch {} renderServers(); }
|
||||
document.addEventListener('click', e => { const row = e.target.closest('.server > .row'); if (!row) return; toggleBox(row.parentElement.dataset.box); });
|
||||
document.addEventListener('keydown', e => { if (e.key !== 'Enter' && e.key !== ' ') return; const row = e.target.closest && e.target.closest('.server > .row'); if (!row) return; e.preventDefault(); toggleBox(row.parentElement.dataset.box); });
|
||||
// the Mac mini (igneum-mini, the Mac build box, M6): its own collector pushes mini.json to build-1; until then its card reads no report yet
|
||||
const MINI = { name: 'igneum-mini', label: 'the Mac build box, M6' };
|
||||
const miniLive = () => { const m = D && D.mini; return m && m.source && m.source.ok && m.cores ? m : null; };
|
||||
|
|
@ -308,7 +328,6 @@ function renderCrew() {
|
|||
if (r.rate_mhs !== undefined && r.rate_mhs !== null) f.push(`${Number(r.rate_mhs).toFixed(1)} MH/s`);
|
||||
if (Array.isArray(r.cards)) f.push(r.cards.map(c => `${esc(String(c.name || c.id || 'card'))} ${c.rate_mhs === undefined || c.rate_mhs === null ? '?' : Number(c.rate_mhs).toFixed(1)} MH/s`).join(', '));
|
||||
if (r.last_accepted_at) f.push(`last block ${esc(String(r.last_accepted_at).replace(/^\d{4}-\d{2}-\d{2}T/, ''))}`);
|
||||
if (r.agent_pid || r.node_pid) f.push(`pids agent ${r.agent_pid ?? '?'} node ${r.node_pid ?? '?'}`);
|
||||
return f.join(' · '); };
|
||||
for (const pc of pcs) {
|
||||
const r = pc.running;
|
||||
|
|
|
|||
Loading…
Reference in a new issue