Pre-public scrub, second pass (7 October 2026, 20:0x UK, main's rulings 2 and 4): the public tree names igneum-labs only; the public ledger generated from the full ledger

Ruling 2: every tracked text mention of the login's pre-rename spelling becomes igneum-labs (29 files); the commit identity in the scripts becomes igneum-labs <337424239+igneum-labs@users.noreply.github.com> (the same noreply id); the three scripts that hand the stored gh keyring name to gh (register.sh, fetch-ci-artifacts.sh, ship-app.mjs) read it from ~/.config/igneum/gh-user (never in the repository), default igneum-labs; fresh-repo.sh reads the login to rewrite from the encoded list's row 10; the old spelling joins the founder-strings list, so no tracked file may spell it; CLAUDE.md's GitHub paragraph rewritten. The red watcher's self-test fixtures use a neutral author.

Ruling 4: docs/ledger-public.md, one row per ledger item (id, the claim in one line, status, what was done in one line, the evidence link or the evidence in words), generated by tools/ledger/export-public.mjs from docs/fud-ledger.md: no round or status-update sections, no commit ids, no time of day, no lane, agent or branch names. 190 items. The gate runs its self-test (a fixture with a commit id, a time, a lane and a branch name comes out clean; --check fails on drift) and its --check on every merge; the founder check reads the output like every tracked file.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
igneum-labs 2026-10-07 18:56:08 +00:00
parent 7eed16a29a
commit 09c2634d2c
13 changed files with 359 additions and 22 deletions

198
docs/ledger-public.md Normal file
View file

@ -0,0 +1,198 @@
# Igneum criticism ledger, public shape
Generated by `tools/ledger/export-public.mjs` from `docs/fud-ledger.md`; a gate check fails when the two drift. One row per item: the claim or criticism, its status, what was done, and the evidence. Internal identifiers, times of day and team-member names are left out on purpose; the full ledger is published with the repository.
190 items. By status: Conceded, stated 50; Fixed 30; Decided 22; Fixed on a branch, pending merge 14; Answered by design 6; Fixed, stated 6; Open, counsel engaged 4; Answered with evidence 4; Closed by rule 3; Answered by design, with a correction to our own text 1; Answered with evidence, stated 1; Answered by design for finality, Conceded for the lottery 1; Conceded, implemented 1; Rule implemented and measured; launch month simulated 1; Answered by design, with the concession stated 1; Conceded, stated in the litepaper and the design doc 1; Answered with evidence at 1 block/s 1; Conceded, stated in the simulation report 1; Answered by design, with the dependency conceded. Update 7… 1; Conceded, stated in the litepaper, with the dial explained 1; Open, blocked on phase 2 1; Closed by spec 1; Conceded by decision, stated in the design doc 1; Answered by design, with the founder's edge conceded 1; Answered by design, with a metrics caveat 1; Closed by removal, 3 October 2026 1; Conceded, stated in the litepaper 1; Conceded, stated in the design doc 1; Measured on the live node line, and the overlay does NOT… 1; Conceded, stated in the simulation 1; Conceded in part, labelled, stated 1; Fixed in the node 1; Answered with evidence for the largest body the rules allow 1; Spec fixed 1; Fixed in the proving code 1; Fixed in the spec 1; Rule fixed 1; Rule written 1; Fixed, logged 1; Answered with evidence for the test half 1; Fixed in the node and shipped, rule not yet activated on… 1; Simulation half run 1; Answered with evidence for all four 1; Open, blocked on the public testnet 1; Written 1; Designed 1; Fixed and confirmed 1; Open, blocked on the phase 2 consensus proof 1; Rolled out 1; Conceded, no experiment possible 1; Conceded by decision 1; Conceded, scheduled 1; Conceded, contained by rule, reviewed 1; Fixed on a branch and verified locally 1; Answered with evidence and stated 1; Answered with evidence for PC 2 1; Answered by design and with evidence 1; Fixed on a branch, pending the 0.3.20 node ship 1; Fixed as a genesis lever, measurement owed 1; Conceded, flagged in spec 04 section 4.8 1.
| Id | Claim or criticism | Status | What was done | Evidence |
|---|---|---|---|---|
| M1 | The program space is tiny | Decided | No standing bounty. | [docs/bench-log.md](../docs/bench-log.md) |
| M2 | Your own prototype is not memory-hard | Conceded, stated | `Site/litepaper.html`, Monero's idea section, the "Measured so far" paragraph, "computing items on the fly runs 4.8x slower than loading them"; What Igneum does not claim, "A memory-hard prototype on every vendor". | [proto-metal/TESTS.md](../proto-metal/TESTS.md) |
| M3 | Kaspa said ASIC resistant too | Answered by design, with a correction to our own text | First the correction: Kaspa did not promise ASIC resistance. kHeavyHash was designed to be friendly to specialised and optical hardware, and the Kaspa community expected chips (approximate, from memory; cite the Kaspa… | design doc, "ASIC resistance" section. |
| M4 | ProgPoW already did this and you do not mention it | Conceded, stated | `Site/litepaper.html`, precedents table row 1, "ProgPoW, as KAWPOW on Ravencoin since 2020". | [vendor/](../vendor/) |
| M5 | Your load count varies 6x between programs | Fixed | Generator version 2 draws exactly 16 load slots per program (spec 01 section 1.4.2, `igneum-pow/src/generator.rs`), and the fresh-source rule of 1.4.3 with the acceptance rule of 1.4.6 fixes the distinct count too,… | [proto-metal/TESTS.md](../proto-metal/TESTS.md) |
| M6 | Weak programs | Fixed | The acceptance rule of spec 01 section 1.4.6 (`igneum-pow/src/accept.rs`, mirrored in `proto-metal/main.swift`) rejects a candidate with a stale load source, a register without an injecting write, a nonce-independent… | [proto-metal/TESTS.md](../proto-metal/TESTS.md) |
| M7 | No cryptographic analysis at all | Conceded, stated | `Site/litepaper.html`, Mining section, "The hash is a lottery, not a general-purpose cryptographic hash" and "Open: no analysis of the lottery properties exists yet". | [proto-metal/TESTS.md](../proto-metal/TESTS.md) |
| M8 | Only two vendors, two programs, one day | Decided | A discrete AMD card (9070 XT) and a 12 GB NVIDIA card (4070) are on order for PC 2; the measurement runs on arrival. | [docs/bench-log.md](../docs/bench-log.md) |
| M9 | The 10 ms CPU verification gate is unmeasured | Conceded, stated | `Site/litepaper.html`, Mining section, "Measured: 0.41 to 0.58 ms per warp on one Apple M5 Max core with the 256 MB cache"; vs RandomX "Light verification" row. | [docs/bench-log.md](../docs/bench-log.md) |
| M10 | "Bound by memory bandwidth" is wrong | Answered with evidence, stated | `Site/litepaper.html`, Mining section, "bound by random memory access. | [docs/bench-log.md](../docs/bench-log.md) |
| M11 | Hourly JIT on real rigs | Decided | The mixed-generation rig is borrowed from a farm operator later, at the HiveOS package's first test; the 9070 XT on order gives the ROCm half on PC 2. | [docs/bench-log.md](../docs/bench-log.md) |
| M12 | Rentable hashrate is not just NiceHash | Answered by design for finality, Conceded for the lottery | Both halves true. | [sim/results.md](../sim/results.md) |
| M13 | Macs mine too is marketing | Conceded, stated | `Site/litepaper.html`, For miners, Hardware, "Macs mine too, at about a fifth of a flagship card: Measured, 26.7 against 123 million hashes a second" (confirmed by grep tonight; the projected-earnings half is not… | [docs/bench-log.md](../docs/bench-log.md) |
| M32 | "Automatic anti-ASIC escalators" overstates what the era draw and the instruction reserve do | Conceded, stated | The era draw and the instruction reserve are automatic schedule changes against fixed datapaths and against human forks; against the stored-dataset chip every drawn parameter is firmware, and the defence against that… | [docs/analysis/horizon/algorithm.md](../docs/analysis/horizon/algorithm.md) |
| M33 | The FPGA ceiling rests on a tFAW the JEDEC HBM2 table does not give | Conceded, stated | The public FPGA line carries only the measured row, 2.4 G reads/s per card and 0.30x to 0.39x of the RTX 5090 per watt (Shuhai, FCCM 2020 Fig 7; the tFAW arithmetic from ICCAD 2021 Table I), and the 11.4 G bank-bound… | [docs/analysis/horizon/algorithm.md](../docs/analysis/horizon/algorithm.md) |
| M34 | The shadow size N is a constant of the binary, so the one lever against the dataset-storing chip needs a fork to move | Conceded, implemented | N is a genesis ladder of six rungs (27, 35, 53, 88, 173, 267 passes; about 102,100 to 1,001,600 counted ops) with a measured admissibility flag per rung (cold verify under 10 ms on the reference core with its SMT… | [docs/design/latency-ladder.md](../docs/design/latency-ladder.md) |
| F1 | Finality is attackable for the first month | Rule implemented and measured; launch month simulated | The harness text only: `tools/finality-attacks/run.mjs` names the 2/3-of-total floor in the s6 comments and criterion and in the s5 result line, where it still said 56.7%; the scenario logic is untouched. | [sim/](../sim/) |
| F2 | The two-hour presence window is an eclipse vector | Closed by rule | Correct that the presence window trades safety for liveness. | [sim/results.md](../sim/results.md) |
| F3 | Participation grinding through the bitmap | Decided | The per-block vote bound and the bitmap wire bound of spec 3.4.2 items 2 and 3 are adopted for gate 3; the spec moves them from Proposed to Decided at the next spec edit. | design doc Finality v2, Quorum item 2 and Checkpoints item 3. |
| F4 | It is proof of stake with extra steps | Answered by design, with the concession stated | The committee's weight is blocks mined in the last 30 days. | [sim/results.md](../sim/results.md) |
| F5 | The headline arithmetic is misread on purpose | Conceded, stated | `Site/litepaper.html`, Finality, "an attacker producing every block on the chain, with honest miners gone" and "An attacker matching the honest network needs twenty days for a third and never reaches two thirds"; the… | [sim/results.md](../sim/results.md) |
| F6 | Equivocation costs nothing that matters | Conceded, stated in the litepaper and the design doc | True. | design doc Finality v2, Checkpoints item 4 and Residual risks bullet 1. |
| F7 | A 2-minute checkpoint on a DAG with a 1-hour merge bound | Answered with evidence at 1 block/s | Fair. | design doc Finality v2, Checkpoints item 1 and "Three experiments before gate 3". |
| F8 | The simulation has no network in it | Conceded, stated in the simulation report | Correct. | [sim/results.md](../sim/results.md) |
| F9 | Half the hashrate leaves and finality stalls for ten days | Answered by design | That table is the all-keys denominator, which the simulation recommended for safety. | [sim/results.md](../sim/results.md) |
| F10 | Pools hold the votes | Conceded, stated | `Site/litepaper.html`, Finality, "Pools carry their hashers' votes, so vote concentration equals pool concentration, and it is public"; Governance, "governed by the hashrate that powers it". | design doc Finality v2, Residual risks bullet 3. |
| F11 | VDFs are exotic | Answered by design, with the dependency conceded. Update 7… | The era VDF is in the node (spec 4.4 Implemented, behind `era_vdf_activation_daa`, never until the founder sets it per network), on a fixed-width integer with no C library, with the hash-chain fallback behind the… | design doc Finality v2, Lottery seeds items 1 and 2, Residual risks bullet 5, "Three experiments before gate 3". |
| F12 | Nothing outside the chain, except | Answered by design | Those are code dependencies, chosen because each is open source and replaceable, and none is another chain's consensus. | CLAUDE.md design paragraph; design doc "Decided" paragraph. |
| F13 | Why prove every block if every node executes anyway | Answered by design | Full nodes execute natively so users see state in about a second. | design doc, "Proving speed on consumer GPUs" risk item and "Who needs" paragraph. |
| F26 | "No stake" needs its one sentence: what is at stake, and what strips it | Conceded, stated | `Site/litepaper.html`, the finality section's "What is not here" paragraph and the "Igneum at a glance" Finality row carry the sentence verbatim: "No coin is staked. | [docs/analysis/horizon/frontier.md](../docs/analysis/horizon/frontier.md) |
| P1 | The 20-second shard is a number you made up | Conceded, stated | `Site/litepaper.html`, Proving, The proving budget, "Target: shard size will be set so a 12 GB card proves one shard in about 20 seconds. | [site/journey.json](../site/journey.json) |
| P2 | Real-time proving needs a hundred GPUs per block | Conceded, stated in the litepaper, with the dial explained | True, and the litepaper says a full block needs a cluster of 100 to 200 consumer GPUs, approximate. | design doc "Unit economics of a proof"; litepaper "What Igneum does not claim" item 1. |
| P3 | A phone verifies in milliseconds is a SNARK-wrapper claim | Open, blocked on phase 2 | Next measurement the phase 2 benchmark, design R4 (Nov 2026 to Jan 2027 per the litepaper roadmap), a wrapped segment proof timed on a 12 GB and a 24 GB card and verified on a phone. | not yet. |
| P4 | Trustless light clients need a consensus proof you do not have | Conceded, stated | `Site/litepaper.html`, precedents table row 6, "The consensus proof that makes the checkpoint self-verifying is phase two"; Building item 2, "Light clients". | design doc, hostile review table rows "Slashing an external prover" and "One-proof light clients". |
| P5 | EVM "unchanged" on a DAG is false | Closed by spec | Correct. | design doc, hostile review table row "EVM semantics on a DAG". |
| P6 | The proving market is tiny | Conceded, stated | `Site/litepaper.html`, The problem, "a supplier whose marginal cost is close to power"; "cheapest supplier" and "lowest cost" absent from the page (grep, tonight). | design doc "Market size, honestly" and "Existing prover networks" table (labelled from memory). |
| P7 | A soundness bug in SP1 is a consensus failure | Conceded, stated | `Site/litepaper.html`, Abstract, "Writing new code, including an emergency fix to the proof system, is the one thing that takes a person"; Proving, "no node accepts a block with a wrong state root". | design doc "Proof system churn" risk item. |
| P8 | Fastest prover wins all the shards | Closed by rule | Fair, and the lottery/proving separation does not by itself fix it. | design doc "Proving speed on consumer GPUs" risk item and Finality v2 "Fees". |
| P9 | Shard griefing | Decided | The parameter table's values are the phase 4 devnet's starting values (8 assignees, a 25-s exclusive window, a 120-s job claim timeout, no shard bond, the external job bond set on the devnet); the devnet measurement… | design doc, Security model table row 3. |
| P10 | External jobs are paid off-chain, so where is the burn | Conceded, stated | `Site/litepaper.html`, Economics, "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"; the route table… | design doc "The first six months" risk item and hostile review table row "Slashing an external prover". |
| P24 | "20 percent of emission to provers" without the caveat that consensus does not verify the proof | Conceded, stated | `Site/litepaper.html`, Economics, the 20% proving-pool row carries the caveat: consensus does not yet verify the carried proof, it checks the record's statement against native execution and its signature, so today a… | [docs/analysis/horizon/consensus-security.md](../docs/analysis/horizon/consensus-security.md) |
| P25 | Unclaimed pool credit is stranded in the escrow | Conceded, stated | `Site/litepaper.html`, Economics, the 20% proving-pool row carries the note: unclaimed pool credit is today stranded in the escrow, no rule returns it; the fix rolls an unproven shard's credit into the next proven… | [docs/analysis/horizon/economy-and-utility.md](../docs/analysis/horizon/economy-and-utility.md) |
| E1 | Hard cap plus burn is a security budget cliff | Conceded by decision, stated in the design doc | True, and the design doc records the choice: "A 1% tail is the Monero model and the safer choice for security on its own." The argument for the cap is that Igneum miners keep earning from in-chain proving fees and… | design doc "Decision: hard cap". |
| E2 | Half the coins in two years is an insider schedule | Answered by design, with the founder's edge conceded | The schedule (1 billion a year halving every two years, 30-day ramp from 10% to 100%) is public, fixed at genesis and the same for every miner. | litepaper "Supply" and "Fair launch, announced". |
| E3 | The 20% developer share enables wash gas | Answered by design, with a metrics caveat | The base fee is burned in full, so every wash transaction loses its whole base fee. | design doc Finality v2 "Fees"; litepaper "What a builder gets for being early". |
| E4 | 5% of gas to the dev fund is a tax | Closed by removal, 3 October 2026 | There is no development fund. | spec section 5.5; design doc "No development fund, so nothing to fight over". |
| E5 | "Not one coin to a founder" is false | Conceded, stated | `Site/litepaper.html`, Economics, "No fund, no foundation, no fee to the team", "1 block in 100 pays the project"; `site/index.html`, Economics, "The one payment to the project is the Ember software's optional 1% dev… | design doc "No development fund, so nothing to fight over". |
| E6 | Two-year halvings bleed hashrate | Conceded, stated | `Site/litepaper.html`, Economics, Security after the subsidy, "The schedule is a bet, not a measurement: a halving halves emission income overnight if price and fees do nothing", with Kaspa's reduction marked… | none; decision in design doc "Supply". |
| E7 | No stablecoin liquidity without a trusted bridge | Decided | Correct. | design doc, hostile review table row "One-proof light clients and committee-free bridges". |
| E8 | Founders seeding the DEX is market making by insiders | Conceded, stated | True and stated in the litepaper. | litepaper "Liquidity from the people who are there". |
| E19 | "Proving: a second income" without the arithmetic of how small it is | Conceded, stated | `Site/litepaper.html`, "For miners", under the three-streams table: all of Ethereum L1's proving is about USD 36 a day at the September 2026 tracker cost (USD 0.005 a block x 7,200 blocks; the tracker figure is a… | [docs/analysis/horizon/frontier.md](../docs/analysis/horizon/frontier.md) |
| E20 | "Proofs at the cost of power" is the electricity, not the price | Conceded, stated | `Site/litepaper.html`, The problem ("a supplier whose electricity cost is close to power and whose price is the subsidy it forgoes, which falls as the network's hash grows"), Building on Igneum ("Proofs priced by the… | [docs/analysis/horizon/economy-and-utility.md](../docs/analysis/horizon/economy-and-utility.md) |
| E21 | The dev fee is 1 percent of the producer share, and the funding plan's ceiling took all rewards | Conceded, stated | `Site/litepaper.html`, the payment-routes row 6 and the Ember section read "default-on, switchable, 1 percent of the producer share"; `docs/plans/funding.md` section 4's ceiling is 1 percent of the producer share, USD… | [docs/analysis/horizon/economy-and-utility.md](../docs/analysis/horizon/economy-and-utility.md) |
| G1 | No cryptography team | Conceded, stated | `Site/litepaper.html`, Questions miners ask, "reviewers will be named and paid before gate 3"; What Igneum does not claim, "A cryptography team. | design doc "Team" paragraph. |
| G2 | An AI designed this | Conceded, stated | `Site/litepaper.html`, cover, "Method one founder with AI systems"; Who are you?, "One founder, pseudonymous, working with AI systems". | [.claude/agents/](../.claude/agents/) |
| G3 | Who are you | Decided | No team page for now; the litepaper says the team is pseudonymous and names no team page. | [site/journey.json](../site/journey.json) |
| G4 | No admin keys, except in everything that matters | Conceded, stated | The home page was redrawn as one statement, the live scene, three facts and the downloads, so the tile "admin keys in consensus" is no longer on `site/index.html`; the sentence stands on `site/litepaper.html`,… | litepaper "Governance". |
| G5 | No multi-client | Conceded, stated in the litepaper | True at launch. | litepaper "Governance", last bullet. |
| G6 | Stratum v2 does not make pools unable to censor | Conceded, stated | `Site/litepaper.html`, Governance, "Pools can be bypassed on transaction choice". | none in repository. |
| G7 | The one-click app is an update key over the network | Decided | Correct. | not yet. |
| G8 | Governance by hashrate is governance by two pools | Conceded, stated in the design doc | True in the same way it is true on Bitcoin, where miner signalling activated SegWit and Taproot. | design doc Finality v2, Residual risks bullet 3. |
| G15 | Three signalling thresholds, four numbers across the documents | Conceded, stated | One sentence in `site/litepaper.html`, Governance ("Miners set what genesis leaves open") and Mining ("Miners hold the switch"): miners signal three things at three thresholds, 60 percent of blue blocks over two weeks… | [docs/analysis/horizon/economy-and-utility.md](../docs/analysis/horizon/economy-and-utility.md) |
| C1 | vs Monero: GPUs were excluded on purpose | Answered by design | Monero chose the CPU for egalitarian reasons and accepted botnets as the price. | litepaper "For miners", hardware paragraph. |
| C2 | vs Monero: "no chip in seven years" is not proof | Conceded, stated | The home page no longer carries the RandomX paragraph; "since 2019 (approximate)" and "precedent, not proof" stand on `site/litepaper.html` (vs RandomX, Mining). | none. |
| C3 | vs Kaspa: you misrepresent them | Conceded, stated | `Site/litepaper.html`, The problem, "Chips arrived, as on Kaspa, whose hash was designed to welcome them"; Speed, "Kaspa has run in production since 2021 (approximate), forked from rusty-kaspa"; precedents row 5,… | none in repository; `vendor/rusty-kaspa` to be cloned and cited. |
| C4 | vs Kaspa: a finality overlay changes GHOSTDAG's guarantees | Measured on the live node line, and the overlay does NOT… | A NEW SERIOUS FINDING (5 October 2026 sweep; owner: cryptographer and consensus engineer, decision owner the founder). | [sim/results.md](../sim/results.md) |
| C5 | vs Ethereum: you compare inclusion to finality | Conceded, stated | `Site/litepaper.html`, Speed, "Inclusion is not confirmation on either chain". | litepaper "Speed". |
| C6 | vs Ethereum: every one of your components is a research project | Conceded, stated | `Site/litepaper.html`, Roadmap, "the combination is the risk the gates price" and "Dates slip. | litepaper "Roadmap". |
| C7 | vs Bitcoin: hashrate that follows price is the design, you penalise it | Conceded, stated in the simulation | Correct. | [sim/results.md](../sim/results.md) |
| C8 | vs Ergo, Ravencoin, Conflux: GPU mining has a home | Conceded, stated | `Site/litepaper.html`, The problem, "Ergo, Ravencoin and Conflux still mine on GPUs at a fraction of the 2022 fleet (approximate)"; precedents row 3 names Conflux. | none in repository; to be cited from their repositories. |
| C9 | vs Aleo: you will centralise the same way | Closed by rule | See P8. | design doc "Existing prover networks" table, Aleo row. |
| C10 | vs Boundless and Succinct: you cannot bid there without their tokens | Conceded, stated | `Site/litepaper.html`, Proving for everyone else, "Boundless provers post ZKC and Succinct provers stake PROVE (approximate, from their documentation)". | design doc "Existing prover networks" table, labelled approximate. |
| C11 | vs everyone: "firsts" that are not | Conceded, stated | `Site/litepaper.html`, precedents table, "We know of no chain that combines them"; Building, "that we know no other EVM chain offers". | this ledger. |
| C12 | vs Monero: you borrowed the hash idea and left out the point | Answered by design | Transactions on Igneum are public, as on Ethereum. | CLAUDE.md rules (privacy rejected). |
| L1 | It is a security under Howey | Open, counsel engaged | There is no sale, no premine, no allocation and no promise of return, and nothing in consensus is controlled by the team and no protocol fee reaches it (the development fund was removed on 3 October 2026), which is the… | design doc "Legal" paragraph. |
| L2 | Financial promotion rules | Open, counsel engaged | ; the text half is stated below. | none. |
| L3 | GoDaddy domains are a seizure risk | Decided | The nameserver move to deSEC in one sitting with every domain's Vercel verification checked afterwards; a non-US registrar in December 2026 when the transfer lock ends. | CLAUDE.md "Domains". |
| L4 | Paying testnet miners real money is a payment before launch | Open, counsel engaged | Correct that it needs an entity, terms and tax treatment before it happens. | design doc "The first six months". |
| L5 | Trademark | Open, counsel engaged | The clearance search is recorded in the repository as a dated one-line result per register when it returns. | none. |
| L6 | A permissionless job market paid in dollars is money transmission | Answered by design | At launch jobs are paid on the customer's chain, in the customer's asset, by the customer's contract, to the prover's address; Igneum operates no custody and takes no cut off-chain. | design doc "The first six months". |
| X1 | "Reproducible from the repository" and the repository is private | Conceded, stated | `Site/litepaper.html`, vs RandomX "Track record" row, "The specification, reference hash, test vectors and simulators are public now (github.com/igneum-network/spec). | [site/index.html](../site/index.html) |
| X2 | "Get the miner" with no miner | Conceded, stated | `Site/index.html`, hero button "See the miner"; the Mine section's download buttons carry the shipped devnet build's version and size (v0.3.9) beside "Public testnet: not yet open; the devnet build is here for people… | [site/index.html](../site/index.html) |
| X3 | "Proven by fire" when nothing has run | Conceded in part, labelled, stated | The proofs feed moved to the litepaper's proving section with the home-page redesign and reads "Live rows arrive with the public testnet. | [site/index.html](../site/index.html) |
| X4 | Thirteen months with one founder | Conceded, stated | The roadmap is aggressive and every phase is a gate that can repeat or stop the project, which the litepaper says. | litepaper "Roadmap"; design doc "Team". |
| X5 | 1,000 independent miners is a Sybil number | Decided | The independence definition as written, with the silent-fleet addition (a key with no fingerprint counts as its own class only when its address is in an autonomous system no other key uses); the observer columns on… | [site/journey.json](../site/journey.json) |
| X6 | The one-click app is a honeypot vector | Decided | Correct on all three. | not yet. |
| X7 | No community exists | Conceded, stated | This ledger's submission line names hello@igneum.network and the spec issues route; `site/litepaper.html` last paragraph and the footer on every page carry both. | [site/index.html](../site/index.html) |
| X8 | Exchange listings as a roadmap item | Conceded, stated | The home page's journey is no longer shown (the inlined feed remains in the page source); the sentence "No listing is arranged, promised or sought by the project" stands on `site/litepaper.html` Roadmap phase 6 and in… | [site/journey.json](../site/journey.json) |
| X9 | Launch hashrate will be trivial | Conceded, stated | `Site/litepaper.html`, Finality, "In the chain's first 30 days no checkpoint locks at all"; Fair launch, "The first 30 days of mainnet run on proof of work alone". | [sim/results.md](../sim/results.md) |
| X10 | Five milestones in one day | Conceded, stated | `Site/index.html`, journey section, "The log below is the engineering log's dated entries, newest first. | [site/journey.json](../site/journey.json) |
| M14 | A pulsed rental against the block-count DAA buys weight at a discount | Answered with evidence | , ledger close round 1: M14 and F14 the 50x pulse against a lagging retarget inside the finality simulator, both W2 forms"). | [sim/difficulty/devnet-2026-10-03.csv](../sim/difficulty/devnet-2026-10-03.csv) |
| M15 | A header with any past timestamp or any claimed DAA score makes the node build a 256 MiB cache | Fixed | Correct. | [docs/fork-divergence.md](../docs/fork-divergence.md) |
| M16 | The 256 MiB cache fits on a die, so the recompute attacker is compute bound | Answered with evidence | On the 5090 the recompute attacker with the cache inside the 96 MiB L2 (the SRAM emulation, 64 and 32 MiB masks, bit-exact against the stored construction) runs at 33.9 Mhash/s against 132.2 honest for the same… | [proto-metal/MEMHARD.md](../proto-metal/MEMHARD.md) |
| M17 | Every ahead-of-time miner stops at the epoch boundary; whoever compiles in process mines alone | Fixed | And measured on the live devnet at the DAA 3,600 boundary (`docs/bench-log.md`, "first hourly program swap"): prepare sent 449 DAA before the boundary; Metal compiled in 82 ms, CUDA ran nvcc in the background in 1,285… | [proto-cuda/windows-miner/start-mining.ps1](../proto-cuda/windows-miner/start-mining.ps1) |
| M18 | The per-hash random data path is a one-bit select | Conceded, stated | `Site/litepaper.html`, Mining table "Every hash" row, "The one-bit select inside the maths costs a chip nothing and is not a defence"; vs RandomX "Random program" row, "the 128 dataset addresses change with the nonce". | [site/litepaper.html](../site/litepaper.html) |
| M19 | The census that justifies the generator rule has blank cells, and the spec still carries the free load count | Fixed | Correct. | [docs/analysis/weak-program-census-2026-10-03.md](../docs/analysis/weak-program-census-2026-10-03.md) |
| M20 | Pruning proofs are checked with the kHeavyHash stub | Fixed in the node | Correct. | [docs/fork-divergence.md](../docs/fork-divergence.md) |
| M21 | GHOSTDAG k is Kaspa's table value for Kaspa-sized bodies | Answered with evidence for the largest body the rules allow | , ledger close round 1: M21 block propagation with bodies at the mass limit, k re-derived"); the red rate under such bodies is not measured. | [docs/design/execution-layer.md](../docs/design/execution-layer.md) |
| F14 | Weight in blocks over a window in blocks under a lagging retarget | Answered with evidence | , ledger close round 1: M14 and F14 the 50x pulse against a lagging retarget inside the finality simulator, both W2 forms"). | [sim/results_v2.md](../sim/results_v2.md) |
| F15 | Merge depth is not the reorg bound; the finality depth is | Spec fixed | Spec 2.1 names the finality depth as the reorg bound and merge depth as a merge limit only, spec 3.8 and 3.9 tell exchanges to wait 12 hours of past-median time when `finality_active` is false, and the simnet reorg… | the files above. |
| F16 | A lock can become uncertified after a heal | Decided | Option B, a verified certificate is never withdrawn (spec 3.11.4); the 3.5 paragraph is replaced by 3.11.4's text after `c4-fix` merges, `finality_conflict` and the `finality_active` clear go into the node, the forced… | spec 3.5, 3.9. |
| F17 | Keys are free and the official client mints eight per card | Decided | The client defaults to one vote key per machine, identities share it (spec 3.4.2 item 4); the bitmap bound as item 3. | [proto-cuda/windows-miner/start-mining.ps1](../proto-cuda/windows-miner/start-mining.ps1) |
| F18 | "A silent minority cannot freeze finality" is false under the floor | Fixed | Correct. | [sim/results_v2.md](../sim/results_v2.md) |
| P11 | The native-execution veto makes block validity depend on the node's current selected chain | Fixed | Spec 7.2 item 5 and `docs/design/execution-layer.md` 5.5 and D12 are relative to the carrying block's own selected-parent chain; the two-node reorg test is a row in the design document's 8.5. | [docs/design/execution-layer.md](../docs/design/execution-layer.md) |
| P12 | An aggregator can name itself as every prover | Fixed in the proving code | Every shard proof's public values carry the prover's payout address (`ShardOutput.prover`), the aggregated block proof commits keccak over the provers in shard order and the shard program's verifying-key hash… | [docs/design/execution-layer.md](../docs/design/execution-layer.md) |
| P13 | The litepaper still claims shards with a bond | Fixed | `Site/litepaper.html`, Proving, "How a block gets proven". | [site/litepaper.html](../site/litepaper.html) |
| P14 | Two definitions of the proving base fee, and a quote that cannot know the ratio | Fixed in the spec | One definition. | [docs/design/execution-layer.md](../docs/design/execution-layer.md) |
| P15 | RPC blocks are segments, so `gasUsed` can exceed `gasLimit` | Fixed on a branch, pending merge | `Igneum/exec/src/rpc.rs` reports `gasLimit` as k x `BLOCK_EXECUTION_GAS_LIMIT` for a k-block segment (k = the record's mergeset length, at least 1), beside the segment's `gasUsed`, so `gasUsed <= gasLimit` holds for an… | [docs/design/execution-layer.md](../docs/design/execution-layer.md) |
| E9 | The specification's year is 365 days; the code's is 365.25 | Fixed | Spec 2.5 follows the code (365.25-day year, 63,115,200-s halving, 31.688 IGN per DAA second, 8 decimals noted under O-2.6). | [consensus/core/src/igneum.rs](../consensus/core/src/igneum.rs) |
| E10 | Reds are paid in the code and "more blocks never means more coins" is false | Fixed | Spec 2.5 says reds inside the DAA window are paid to the merging miner (80%) and the pool (20%), that `E` is paid per block so coins are blocks times `E` under the controller's rate, and that the cap is unaffected;… | [docs/review/round-3-2026-10-03.md](../docs/review/round-3-2026-10-03.md) |
| E11 | The homepage burns job fees at launch | Fixed | `Site/index.html`, "Proofs sold to other chains" caption and the tile now read "phase two"; the quoted paragraph had already left the page when the homepage was trimmed (commit a commit). | [site/index.html](../site/index.html) |
| C13 | Monero's seven years do not price a 256 MiB SRAM die | Conceded, stated | `Site/litepaper.html`, What Igneum does not claim, "they say nothing about the price of a chip with the 256 MB cache on its die, and that price is a cost model, not a measurement". | none beyond M16. |
| L7 | "Where the price comes from" | Fixed | Heading "Where fees go" and the sentence deleted, `site/litepaper.html` Economics. | [site/litepaper.html](../site/litepaper.html) |
| L8 | Third-party names as implied outcomes | Conceded, stated | `Site/litepaper.html`, Questions builders ask, "whether it is issued is Circle's decision"; Canto and Blast absent from the page (grep, tonight). | [site/litepaper.html](../site/litepaper.html) |
| G9 | The release-key the team is one person, and a lost key cannot be revoked | Rule fixed | Spec 8.2 item 5, rotation signed by the current key and revocation signed by the previous key (a pre-signed certificate for K0), both published in a block; item 2 moves the policy to before the client ships and adds… | spec 8.2. |
| G10 | The signalling default on first run | Rule written | `Docs/spec/08-client-security.md` 8.3 item 2 now ends: on first run there is no last choice, the client signals nothing until the user chooses, and the interface shows that nothing is being signalled. | [docs/spec/08-client-security.md](../docs/spec/08-client-security.md) |
| X12 | Tonight's numbers are quoted before they are logged, and the worker efficiency gap is unexplained | Fixed, logged | Bench-log "5 October 2026 (night), ledger close round 1: X12 the 3 October devnet run from its record"; the launcher half (the eight processes' summed status) stays open until the PC's log is read. | [sim/difficulty/devnet-2026-10-03.csv](../sim/difficulty/devnet-2026-10-03.csv) |
| M22 | The ASIC challenge has no scoring rules, and 2x is not the economic line | Decided | No bounty, so no bounty terms; M22's metrics (hashes per second and per joule per program over at least 100 epochs as a distribution, capital cost per unit of hash rate at a stated volume, the longevity term, the… | M1, O-1.17, spec 1.13 and 1.16, M16's arithmetic. |
| F19 | Old vote keys can be bought; fresh hashrate cannot buy weight | Answered with evidence | A bought key is worth the blocks it holds and nothing more. | [sim/results_v2.md](../sim/results_v2.md) |
| F20 | During a finality pause the program must keep advancing, and nothing says which guarantees survive | Answered with evidence for the test half | , ledger close round 1: F20 finality pause under a 45% silent set through four epoch boundaries"); the gate-3 wording of the four guarantees (O-3.16, O-4.3) stays a decision for the founder. | spec 4.3 (O-4.3), 3.3.1, 3.5, 3.7 item 2, 3.9. |
| F22 | Certificates carry 8 to 10 of 12 votes on a healthy network, so locks sit a hair above the floor | Fixed in the node and shipped, rule not yet activated on… | True as measured, and the cause is not a cut-off at all: the node builds the certificate the instant the votes it holds meet Q3, and carries that one. | [infra/cloud-devnet/results/2026-10-04/partition-sin-20261004-140305/partition.md](../infra/cloud-devnet/results/2026-10-04/partition-sin-20261004-140305/partition.md) |
| P16 | The proving gate can be passed by shrinking the shard | Decided | A 12 GB NVIDIA card (4070) is on order for PC 2; O-7.1 runs end to end on it when it arrives, inside the phase 2 gate. | [docs/bench-log.md](../docs/bench-log.md) |
| P17 | Interfaces must show four states, and the design shows three | Fixed on a branch, pending merge | a fork a commit (a commit rebased onto the 0.3.11 fork tip a commit in round 3), suite igneum-exec 16 of 16 on the Mac (labelled a Mac run), the O-7.2 conformance run PASSED on a fast-time 3-node network (bench-log… | execution-layer 2.3, 2.4, 8.2; phone-app 3 and 9; spec 3.9, 10.1. |
| E12 | Selfish operators under a price shock | Simulation half run | No backlog in any scenario, every block proven within 60 s in every hour, hash troughs at 82% of its pre-event level under b and 75% under d (80% at day 30), 10% of cards off under b… | spec 5.1, 5.3, 7.2; execution-layer 4.3, 9.1 R8. |
| E13 | One diagram per payment route, or operator income and protocol income blur | Conceded, stated | `Site/litepaper.html`, Economics, "Every payment route", six rows (emission; base fee; priority fee; external job at launch; external job after the proof bridge; the official client's dev fee as operator income),… | [docs/commercial/prover-customer-brief.md](../docs/commercial/prover-customer-brief.md) |
| E14 | No funding table | Decided | The funding table stays internal until counsel has read it; one public sentence in the litepaper names the unfunded lines (the second client, the external reviewers, the bounty before escrow). | E4, E5, G1, G5; fud-fixes rows 47, 50, 71. |
| E15 | The security budget through successive halvings with low fees and no external demand | Decided | The 4,000,000,000 IGN hard cap stays absolute and there is no tail emission. | spec 2.5, 5.1 to 5.4; E1, E6. |
| G11 | Publish the inspectable components now, labelled experimental | Decided | The specification subset is public as `igneum-network/spec` (`docs/plans/public-repo.md`), labelled; the node fork, the proving code and the harnesses stay private until the benchmark. | [docs/fud-fixes.md](../docs/fud-fixes.md) |
| X13 | One paying customer for a stated reason | Decided | The paid pilot stays in phase 5, the phase 4 gate stays the signature, nothing moves earlier before counsel answers L4. | [site/journey.json](../site/journey.json) |
| X14 | Concentration is unmeasured in four places | Answered with evidence for all four | , ledger close round 2: X14 signing concentration from block payloads"); the independence definition stays the founder's (X5). | X5, F10, P12, spec 9.4.2. |
| X15 | Remove the founders from a test network and show what continues | Open, blocked on the public testnet | Next step O-X.2 run at a published time on that testnet, with the protocol already in the Answer below (every project-run node, miner, prover, aggregator and seed stopped, the observer and live page down, 24 hours of… | [site/litepaper.html](../site/litepaper.html) |
| X16 | An evidence page with four labels | Written | `Docs/evidence.md`, one row per public claim with five labels (tonight, counting the label column of the claims table: designed 9, implemented 8, tested by the team 26, reproduced externally 3, reviewed independently 2). | [docs/bench-log.md](../docs/bench-log.md) |
| X17 | The miner app must show net earnings and keep jobs away from keys | Designed | Spec 8.8 and phone-app 4.1; measurement O-8.2 and the escape test O-8.3 scheduled for the phase 4 devnet. | [site/litepaper.html](../site/litepaper.html) |
| P18 | The mempool queues transactions no block can carry | Fixed | Correct, and low: the queue slot was reserved against the sender's funds, so it was self-limited. | [docs/bench-log.md](../docs/bench-log.md) |
| P19 | An over-budget proving transaction runs for free, every time, and blocks its sender | Fixed | Correct, medium. | [docs/bench-log.md](../docs/bench-log.md) |
| P20 | The SP1 GPU client panics on shutdown and the compressed stage waited ten minutes | Fixed and confirmed | The buffered save closed the gap, the core proof finished at and the compressed stage started at; shard timings repeated within 0.3 s (core 9.1 s, compressed 10.5 s); a guest that returned 0 bytes on the second run was… | [docs/bench-log.md](../docs/bench-log.md) |
| M23 | Forge timestamps inside the rules and the controller mines you a 10x difficulty for free | Fixed | Correct on every point, and measured first by our own attack run (`sim/difficulty/attacks/README.md`, scenarios 3 and 7): in the simulator a 50% forger took the block rate to 0.12 (earliest stamp) and 0.56 (latest) of… | [docs/bench-log.md](../docs/bench-log.md) |
| P21 | The SP1 proof is not what consensus checks in proving v0 | Decided | Proving v0 (every producer verifies off the consensus path) through the public testnet; the in-consensus verifier is the execution engineer's plan item for after it; the litepaper sentence labelled Open stands. | none named |
| P22 | The rewards and payouts are inputs to the shard proof, not outputs | Open, blocked on the phase 2 consensus proof | Next step that consensus-proof work, in phase 2 (Nov 2026 to Jan 2027 per the litepaper roadmap), no earlier date. | none named |
| M24 | Your two-lane controller oscillates for an hour when a second miner joins mid-epoch | Rolled out | Rule v2 activated on the live devnet at DAA 33,000 by the height switch after a 12-node cloud rehearsal (settle 157 to 272 s, no swing); node 1, the seed, the observer and the three app machines crossed the height on… | [sim/difficulty/records/live-2026-10-04.csv](../sim/difficulty/records/live-2026-10-04.csv) |
| D1 | Your users are a gate, not a fact | Conceded, stated | Correct on the count and on the definition. | [docs/bench-log.md](../docs/bench-log.md) |
| D2 | The app share pays nothing | Conceded, stated | `Site/litepaper.html`, Building, Why build here, "a million 100,000-gas calls a day at a 1 gwei tip pays about 7,300 IGN a year"; Canto and Blast absent from the page (grep, tonight). | [docs/design/developer-adoption.md](../docs/design/developer-adoption.md) |
| D3 | Proof of work in 2027 is a perception cost you cannot measure | Conceded, no experiment possible | Correct that the cost exists and that nothing in the design measures it. | [site/litepaper.html](../site/litepaper.html) |
| D4 | No dollar, no DeFi | Conceded by decision | , restated here for builders. | [docs/review/round-3-2026-10-03.md](../docs/review/round-3-2026-10-03.md) |
| D5 | I cannot debug a revert | Conceded, scheduled | `Docs/design/developer-adoption.md` section 5, owner and gate named (the execution engineer; no outside team is invited before step 2 is done). | [docs/design/execution-layer.md](../docs/design/execution-layer.md) |
| D6 | A forged job result reaches my contract and nobody vetoes it | Conceded, contained by rule, reviewed | `Docs/review/d6-forged-job-result-2026-10-05.md`. | [docs/design/execution-layer.md](../docs/design/execution-layer.md) |
| X23 | One shipped key is an administrator channel to the founder's PCs | Fixed on a branch, pending merge | Three tiers in `relay/lib/guard.mjs` (`authVia`): the console token (header or the phone page's path), the relay's own key (`RELAY_KEY`: reads and reports, never `task`, `run`, `name`, `role`, `secret`, `delete`), and… | [docs/review/round-4-2026-10-04.md](../docs/review/round-4-2026-10-04.md) |
| X24 | The relay token rides in the URL on every request | Fixed on a branch, pending merge | Every client and Mac tool calls `/api/relay?fn=<fn>` with `x-relay-token` (and `x-igneum-key`) as headers: `igneum-agent.ps1` and `send.ps1` (`Api-Url`), `agent.sh` and `send.sh` (through a 0600 curl config file, `-K`,… | [tools/relay.mjs](../tools/relay.mjs) |
| X25 | The PC agent installs itself at every logon, at highest privilege, on every start | Fixed on a branch, pending merge | `Igneum-agent.ps1` calls `Arm-Restart` only on the two paths that end in `shutdown.exe /r` (a task that printed `RELAY-REBOOT` on its own line AND was queued with `--reboot` or `--reboot-continue`), sets… | [relay/clients/igneum-agent.ps1](../relay/clients/igneum-agent.ps1) |
| X26 | The feed is a permanent transcript, and it holds the dl token by design | Fixed on a branch, pending merge | Retention 30 days (`relay/lib/handler.mjs` `expire`: `DELETE... | [relay/lib/handler.mjs](../relay/lib/handler.mjs) |
| X27 | The relay has no clean rotation and no sender binding | Fixed on a branch, pending merge | A per-machine secret (64 hex, `node tools/relay.mjs secret PC1`: written to `~/.config/igneum/relay-machines/PC1` at 0600, its sha256 bound on the relay with `POST secret` (token only), carried to the PC as… | [relay/README.md](../relay/README.md) |
| X28 | Relay hygiene, minor | Fixed on a branch, pending merge | The remaining points. | [lib/wake.mjs](../lib/wake.mjs) |
| G12 | The PoW schedule comes from the environment on every network, including mainnet | Fixed | . | the files above. |
| G13 | The update signature covers binaries that nobody signed | Fixed on a branch and verified locally | The chain already on master was read end to end and run, not asserted. | [packaging/windows/push-inputs.sh](../packaging/windows/push-inputs.sh) |
| G14 | Secrets and identity in the history of a repository with a public date | Decided | `TZ=UTC` in every commit path the tooling owns: `tools/ship-app.mjs` (`git` runs with `env: { TZ: 'UTC' }`), `packaging/ota/publish-jobs.sh` (`export TZ=UTC`, found by the class check), `tools/repo/fresh-repo.sh`… | [tools/ship-app.mjs](../tools/ship-app.mjs) |
| X18 | Two nodes with two override files connect, and only some mismatches fork | Fixed | . | the files above. |
| F23 | The equivocation ban is node-local, so honest nodes refuse each other's certificates | Fixed | . | the files above. |
| F24 | A checkpoint determination is never revisited | Fixed | . | the files above. |
| F25 | The fast-time harnesses cannot start a node, and the timestamp probe tests the old rule | Fixed | Correct, measured. | [rt/logs/fa_s8/n0/node.log](../rt/logs/fa_s8/n0/node.log) |
| X19 | Operational knobs and silences in the shipped node | Fixed on a branch, pending merge | The node half, fork commit a commit. | [protocol/flows/src/flowcontext/clock_skew.rs](../protocol/flows/src/flowcontext/clock_skew.rs) |
| X20 | Cold-sync checkpoint determination is indices times chain length | Fixed on a branch, pending merge | `Consensus/src/processes/finality.rs` `on_virtual_changed` resolves every index the sink can determine in ONE descending walk of the selected chain (`chain_blocks_at`, targets highest first), where it walked from the… | [consensus/src/processes/finality.rs](../consensus/src/processes/finality.rs) |
| M25 | The miner takes the day length from its environment, and the schedule global can tear | Fixed on a branch, pending merge | Correct. | [igneum/miner/src/main.rs](../igneum/miner/src/main.rs) |
| M26 | The interval fault guard freezes its baseline and loops | Fixed | `IntervalGuard` builds its baseline from the healthy intervals of the current worker process (a moving average, two intervals before it can trip) and forgets it when the worker restarts; the STATUS line is printed on a… | [docs/bench-log.md](../docs/bench-log.md) |
| M27 | A flapping node makes the worker rebuild once per template | Fixed | Correct. | the files above. |
| M28 | The kernel text is bound only to its own directory | Fixed on a branch, pending merge | Correct. | [proto-cuda/nvrtc/packfile.h](../proto-cuda/nvrtc/packfile.h) |
| X21 | A wrong program burns power with a green rate | Fixed | Correct. | the files above. |
| X22 | Worker restart paths, minor | Fixed on a branch, pending merge | The four remaining paths. | [app/igneum-app/src/engine.rs](../app/igneum-app/src/engine.rs) |
| E16 | The 20% pool is burned on the live chain, and the text says it pays provers | Answered with evidence and stated | Correct for the live devnet-v4 line. | [docs/review/round-4-2026-10-04.md](../docs/review/round-4-2026-10-04.md) |
| L9 | "100% to miners and provers", "0% anyone else", and no word that devnet coins have no value | Conceded, stated | `Site/index.html`, `site/miner.html` and `site/wallet.html`, a line beside every download control, "Devnet: coins have no value and the chain may be reset."; `site/index.html` Economics tiles, "of emission to miners… | the files above. |
| M29 | The litepaper's app paragraph describes an app that does not exist | Conceded, stated | `Site/litepaper.html`, For miners, "One click, for everyone else", rewritten to Ember 0.3.9 from `app/igneum-app/ui/index.html` (hash rate, blocks found, node, next program, finality votes, the proving tile, the devnet… | [ui/app.js](../ui/app.js) |
| M30 | A block or transaction flood grows the 0.3.4 node by hundreds of megabytes in a minute | Fixed | Measured, cause not yet isolated. | [docs/bench-log.md](../docs/bench-log.md) |
| M31 | The 0.3.4 node cannot produce a block template on mainnet, testnet or simnet parameters | Fixed | Measured on the execution-layer attack network (`tools/exec-attacks/net.sh` runs `--simnet` with no override): three nodes up, 0 blocks, every template refused with that line (`docs/review/redteam-2026-10-04.md` row 27). | [rt/logs/exec_b/miner_node1.log](../rt/logs/exec_b/miner_node1.log) |
| E17 | Unlogged inputs behind the economics, minor | Answered with evidence for PC 2 | RTX 5090 honest 132.2 Mhash/s at 326.6 W median, 3,060 MHz, 50 to 54 C, 100% utilisation (0.40 Mhash/J); 346.9 W at 8 warps per block; the inline settings 415.7 W and 431.0 W (the power limit). | [docs/review/round-4-2026-10-04.md](../docs/review/round-4-2026-10-04.md) |
| E18 | The dev fee is a protocol fee with better PR | Answered by design and with evidence | The fee exists and is disclosed; the rest is wrong in three places. | [docs/design/miner-dev-fee.md](../docs/design/miner-dev-fee.md) |
| X29 | Host and file hygiene, minor | Decided | The curl part: `infra/gpu-bench/upload.sh` writes `header = "x-igneum-key:..."` to a 0600 temporary config and calls `curl -K`; `proto-cuda/windows-app/upload-log.bat` and `proto-cuda/windows-miner/upload-log.bat` do… | [infra/gpu-bench/upload.sh](../infra/gpu-bench/upload.sh) |
| X30 | The live page and the bench page exposed operational detail | Fixed | `Ac89a37` and a commit (a scrubbed copy, the build fails on any private string), a commit (none of the three in the public API), a commit (the menu). | the commits above. |
| X31 | The public testnet dated "August 2027" on the site | Fixed, stated | Every mention of the month is gone from the site. | [docs/plans/testnet-go.md](../docs/plans/testnet-go.md) |
| X32 | The roadmap carried calendar months beside a testnet that is weeks away | Fixed, stated | Every calendar month is out of the roadmap. | [site/litepaper.html](../site/litepaper.html) |
| X33 | The public benchmark dated "January 2027" | Fixed, stated | Both sentences read "The public benchmark with a leaderboard ships with the public testnet." (`site/litepaper.html`, For miners and Questions miners ask). | [site/litepaper.html](../site/litepaper.html) |
| X34 | RandomX described as chip-free | Fixed, stated | Four sentences corrected, each with the X9 as the stated fact and its date; every sentence that only names the technique stands. | [site/index.html](../site/index.html) |
| X35 | The class v4 chip headline stated as one number, 2.1x | Fixed, stated | Every public sentence that stated 2.1x alone now states the range with k named. | [docs/design/latency-ladder.md](../docs/design/latency-ladder.md) |
| X36 | The X9 described as a shipping chip | Fixed, stated | Every public sentence that had the X9 shipping now states the pre-order, the withdrawal and the unbenchmarked core. | [site/index.html](../site/index.html) |
| N1 | A 0.3.15 node on the live file wrote blocks every 0.3.14 node rejected | Fixed | The class v4 signal (PROPOSED, `docs/plans/counter-asic-3-node.md` section 6) is the producer's object version in the high byte of the header version; the first 0.3.15 build stamped it from the binary alone, so on the… | [infra/fast-time/node-compat.mjs](../infra/fast-time/node-compat.mjs) |
| N2 | Any peer could crash any pruned node with a sync request below its retention | Fixed | `SyncManager::antipast_hashes_between` (the IBD headers path, `RequestHeaders`) unwrapped the GHOSTDAG reads of the requested low block and of every chain block of the walk; a pruned node holds no GHOSTDAG data below… | unit test `a_sync_request_below_retention_is_an_error_not_a_panic` (a chain of six headers, the genesis's GHOSTDAG… |
| P23 | An unwound transaction leaves the node's view until its sender resends it | Fixed on a branch, pending merge | a fork a commit (the P23 commit, on the merge of `ledger-fixes` and `ledger-fixes-2` onto the 0.3.11 fork tip a commit); `EvmPool::on_chain_removed` (igneum/exec/src/pool.rs) and `ExecService::requeue_unwound`… | [igneum/exec/src/pool.rs](../igneum/exec/src/pool.rs) |
| AP-F8-1 | A load whose source was last written by `or`, `mul` or `mulhi` makes a cross-hash hot set | Fixed on a branch, pending the 0.3.20 node ship | `Ca3-v4-amend` a commit (the generator and the packs) and a commit (the PC 2 playbook), on origin/master a commit plus `ca3-v4-uniform` a commit (the analysis). | [docs/analysis/ca3-v4-uniform.md](../docs/analysis/ca3-v4-uniform.md) |
| GF1 | A post-quantum signature scheme would need a hard fork, and every vote key is a public BLS12-381 point | Fixed | The byte costs nothing now and a fork later. | none named |
| GF2 | A vote key cannot move: a miner who changes keys re-earns 30 days of weight, and so does the post-quantum migration | Fixed | The successor inherits the window, not a fresh one, so a key rotation costs no weight and the migration of GF1 is one item per key. | none named |
| GF3 | A 256 MB on-chip cache makes the lottery hash 2 to 3x cheaper for the card that has it, and the cache size is a constant | Fixed as a genesis lever, measurement owed | Consumer LLC is 96 to 128 MB today and datacentre 256 MB (`chip-model-v3`, approximate), so the shortcut is a datacentre card's today and a consumer card's in a generation or two. | none named |
| GF4 | The class-group VDF falls to the same quantum computer | Conceded, flagged in spec 04 section 4.8 | ; not sized. | none named |

View file

@ -51,7 +51,7 @@ for attr in ("author_date", "committer_date"):
|---|---|
| `replace.txt` (blob text) | `literal:<intake key>==>***INTAKE-KEY-REMOVED***`; `literal:<dl token>==>***DL-TOKEN-REMOVED***`; the two personal `Name <email>` strings to the standing login string; the personal email and the old noreply address to `[removed]`; `regex:\bFirst's\b==>the project lead's`; `regex:\bFirst\s+Last\b==>the project lead`; `regex:\bFirst\b==>the project lead`; `regex:\bLast\b==>[removed]`; `regex:(?i)(?<!igneum-)\bfirst\b==>[user]` (the lowercase user-name form in Windows and WSL paths, added after dry run 1 left 20 lines); `regex:(?i)\b<second login>\b==>[second-owner-login]`; `regex:(?i)\b(the other business\|the earlier entity\|the earlier business\|another brand\|another brand)\b==>[other-business]` |
| `messages.txt` (commit messages) | the first-name rules and the second-login rule |
| `mailmap` | both personal identities to `igneum-labs <337424239+[removed]>` |
| `mailmap` | both personal identities to `igneum-labs <337424239+igneum-labs@users.noreply.github.com>` |
The date callback keeps the instant and rewrites the offset to `+0000`, so no commit moves in time; only the
`+0100` fingerprint goes. `--invert-paths` drops the four internal files from every commit, which empties the

View file

@ -251,7 +251,7 @@ rewritten branch.
|---|---|---|
| commits (all refs) | 410 | 353 (57 commits that only touched the four dropped files are gone) |
| refs | 49 | 29 (filter-repo drops the remote-tracking refs of the mirror) |
| author and committer identities | 3 | 1 (`igneum-labs <337424239+[removed]>`) |
| author and committer identities | 3 | 1 (`igneum-labs <337424239+igneum-labs@users.noreply.github.com>`) |
| stamps not +0000 | 660 of 820 | 0 of 706 |
| commits touching the four dropped files | 53 | 0 |
| secret lines in any blob (old key, new key, old token, new token) | 21 | 0 |

View file

@ -199,7 +199,7 @@ print(f"{n_pass} pass, {n_fail} FAIL, {n_skip} skip; report {out}")
PY
# commit on night-battery, push to the mirror (never master)
cd "$IG" && git add docs/benchmarks/night && \
git -c user.name=igneum-labs -c user.email=337424239+[removed] commit -q -m "Night battery $DATE$( [ "$SUBSET" = 1 ] && echo ' (dry run)'): $(awk -F'\t' '$3 == "pass" { p++ } $3 == "FAIL" { f++ } END { printf "%d pass, %d FAIL", p, f }' "$ROWS") on master $REPO_SHA, fork $NODE_BRANCH $NODE_SHA
git -c user.name=igneum-labs -c user.email=337424239+igneum-labs@users.noreply.github.com commit -q -m "Night battery $DATE$( [ "$SUBSET" = 1 ] && echo ' (dry run)'): $(awk -F'\t' '$3 == "pass" { p++ } $3 == "FAIL" { f++ } END { printf "%d pass, %d FAIL", p, f }' "$ROWS") on master $REPO_SHA, fork $NODE_BRANCH $NODE_SHA
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>" && \
git push -q --force origin night-battery:refs/heads/night-battery && say "pushed night-battery to $REPO_MIRROR ($(git rev-parse --short HEAD)); on the Mac: git fetch build night-battery" || say "commit or push FAILED"

View file

@ -36,24 +36,25 @@ for v in BOX_HOSTNAME RUNNER_NAME RUNNER_LABELS RUNNER_CPUS RUNNER_JOBS; do
done
SSH=(ssh -i "$KEY" -o BatchMode=yes -o StrictHostKeyChecking=accept-new -o ConnectTimeout=15 "root@$IP")
gh_josh() {
gh_owner() {
local active
active=$(gh auth status 2>/dev/null | awk '/Logged in to github.com account/ { acct=$7 } /Active account: true/ { print acct; exit }')
if [ "$active" != igneum-labs ]; then
gh auth switch --user igneum-labs >/dev/null 2>&1 || { echo "gh: cannot switch to igneum-labs (gh auth status: ${active:-no active account})" >&2; exit 1; }
stored="$(cat "$HOME/.config/igneum/gh-user" 2>/dev/null | tr -d '[:space:]')"; stored="${stored:-igneum-labs}" # the keyring entry's name (the login's pre-rename spelling until a re-login)
if [ "$active" != "$stored" ]; then
gh auth switch --user "$stored" >/dev/null 2>&1 || { echo "gh: cannot switch to the stored login (gh auth status: ${active:-no active account}; the entry's name is in ~/.config/igneum/gh-user)" >&2; exit 1; }
fi
[ "$(gh api user --jq .login 2>/dev/null)" = igneum-labs ] || { echo "gh: the active token is not the igneum-labs login (stored as igneum-labs); refusing" >&2; exit 1; }
[ "$(gh api user --jq .login 2>/dev/null)" = igneum-labs ] || { echo "gh: the active token is not the igneum-labs login; refusing" >&2; exit 1; }
}
if [ "${1:-}" = --status ]; then
gh_josh
gh_owner
gh api "repos/$REPO_SLUG/actions/runners" --jq '.runners[] | "\(.name)\t\(.status)\tbusy=\(.busy)\t\(([.labels[].name]) | join(","))"' || echo "(no runners or no access)"
"${SSH[@]}" 'systemctl list-units --type=service --no-legend "actions.runner.*" ; ls -la /opt/actions-runner/.runner 2>/dev/null || echo "not registered on the box"'
exit 0
fi
gh_josh
echo "fetching a registration token for $REPO_SLUG as igneum-labs (igneum-labs) ..."
gh_owner
echo "fetching a registration token for $REPO_SLUG as igneum-labs ..."
TOKEN=$(gh api -X POST "repos/$REPO_SLUG/actions/runners/registration-token" --jq .token 2>/dev/null) || { echo "gh refused the registration token: the account needs admin on $REPO_SLUG (gh api repos/$REPO_SLUG --jq .permissions)" >&2; exit 1; }
[ -n "$TOKEN" ] || { echo "empty token from gh" >&2; exit 1; }
echo "token received (not shown); running provision.sh on root@$IP with it (first line of stdin, then the script)"

View file

@ -16,7 +16,7 @@
# workflow_dispatch), and that the runner's record names this run, this commit and this key. Any failure stops
# before the signature. OTA_NOTES= sets the changelog line (default: the version and the run id).
# Reads ~/.config/igneum/dl-token, ~/.config/igneum/dlsite-dir (IGNEUM_DLSITE overrides) and the gh login, which must
# be igneum-labs (gh auth switch --user igneum-labs).
# be the stored login (~/.config/igneum/gh-user, default igneum-labs; gh auth switch --user <it>).
set -euo pipefail
REPO="igneum-network/igneum"
HERE="$(cd "$(dirname "$0")" && pwd)"
@ -40,7 +40,8 @@ TOKEN="$(tr -d '[:space:]' < "$TOKEN_FILE")"
DEST="$DLSITE/dl/$TOKEN"
[ -n "$DLSITE" ] && [ -d "$DEST" ] || { echo "no downloads folder: set IGNEUM_DLSITE or ~/.config/igneum/dlsite-dir (must hold dl/<token>/)" >&2; exit 1; }
gh auth status 2>&1 | grep -q 'Active account: true' || { echo "gh is not logged in" >&2; exit 1; }
gh auth status 2>&1 | grep -B1 'Active account: true' | grep -q 'igneum-labs' || { echo "gh active account is not igneum-labs: run gh auth switch --user igneum-labs" >&2; exit 1; }
stored="$(cat "$HOME/.config/igneum/gh-user" 2>/dev/null | tr -d '[:space:]')"; stored="${stored:-igneum-labs}" # the keyring entry's name
gh auth status 2>&1 | grep -B1 'Active account: true' | grep -q -F "$stored" || { echo "gh active account is not the stored login $stored: run gh auth switch --user $stored" >&2; exit 1; }
if [ -z "$RUN_ID" ]; then
RUN_ID="$(gh run list --repo "$REPO" --workflow windows.yml --branch master --status success --limit 1 --json databaseId --jq '.[0].databaseId')"

View file

@ -7,8 +7,8 @@
# The patterns are not written in this tree in plain text: a plaintext list would be the hit it looks for. They live
# base64-encoded in tools/ci/founder-strings.b64 (one decoded line per pattern: perl regex, a tab, a sample the self-test plants;
# case-insensitive; # comments ignored)
# and are decoded into a private temporary file at run time. The standing commit login (igneum-labs) is not a founder
# term: the fresh-repository step renames it in the history (docs/plans/history-rewrite.md, tools/repo/fresh-repo.sh).
# and are decoded into a private temporary file at run time. The login's pre-rename spelling is in the list too (main's ruling,
# 7 October 2026: the public tree names igneum-labs only); the fresh-repository step rewrites it in the history (tools/repo/fresh-repo.sh).
#
# tools/ci/founder-strings-check.sh # exit 1 with file:line for every hit over the tracked text files
# tools/ci/founder-strings-check.sh --self-test # a fixture tree with one hit per pattern class fails and names the file; a clean

View file

@ -17,7 +17,7 @@ if [ ! -f "$G/igneum-gate-green/$SHA" ]; then
bash tools/ci/pre-push.sh || exit 1
[ -f "$G/igneum-gate-green/$SHA" ] || { echo "merge-to-master: the gate was green but no stamp was written (dirty tree?)" >&2; exit 1; }
fi
AUTHOR=(-c user.name=igneum-labs -c user.email=337424239+[removed])
AUTHOR=(-c user.name=igneum-labs -c user.email=337424239+igneum-labs@users.noreply.github.com)
for i in $(seq 1 "$TRIES"); do
git fetch -q origin master; TIP=$(git rev-parse origin/master)
if git merge-base --is-ancestor "$SHA" "$TIP"; then echo "merge-to-master: ${SHA:0:8} is already on origin/master $(git log -1 --format=%h origin/master)"; exit 0; fi

View file

@ -128,6 +128,7 @@ tree_checks() {
run "harness summaries never carry a raw 64-hex key (the writer's own redaction and check)" node infra/fast-time/lib/redact-keys.mjs --self-test
run "docs-only pushes skip the compile-or-compute CI jobs (the changes job's classifier)" bash tools/ci/docs-only-check.sh --self-test
run "no founder name, personal login, earlier business or personal address in any tracked text file (the pre-public scrub; self-test first, encoded list)" bash -c 'bash tools/ci/founder-strings-check.sh --self-test && bash tools/ci/founder-strings-check.sh'
run "the public ledger (docs/ledger-public.md) is what docs/fud-ledger.md generates: one row per item, no commit ids, times or team names (self-test first)" bash -c 'node tools/ledger/export-public.mjs --self-test && node tools/ledger/export-public.mjs --check'
}
gated_refs() {

View file

@ -222,7 +222,7 @@ async function selfTest() {
const file = path.join(dir, 'red.jsonl'); const stateFile = path.join(dir, 'posted.json'); const credFile = path.join(dir, 'discord');
const env = { GITHUB_RUN_ID: '424242', GITHUB_RUN_ATTEMPT: '1', GITHUB_REPOSITORY: 'igneum-network/igneum', GITHUB_REF_NAME: 'master',
GITHUB_SHA: '0f0abc6deadbeef', GITHUB_WORKFLOW: 'ci', GITHUB_TOKEN: 'x', RED_WATCH_TITLE: 'Merge box-work 2bd3bec: the repro script re-stamps its clones',
GITHUB_ACTOR: 'igneum-labs', RED_WATCH_AUTHOR: 'igneum-labs' };
GITHUB_ACTOR: 'igneum-labs', RED_WATCH_AUTHOR: 'igneum-ci' };
const jobs = { jobs: [
{ name: 'site build, link check, identity grep', conclusion: 'failure', steps: [{ name: 'site build', conclusion: 'success' }, { name: 'identity grep of the public export list', conclusion: 'failure' }] },
{ name: 'igneum-pow tests, igneum-census build', conclusion: 'success', steps: [] },
@ -240,7 +240,7 @@ async function selfTest() {
if (lines[0].failed[1].step !== '(job never started: runner or billing)') fails.push('record: a job with no steps was not named as never started');
const text = formatLine(lines[0]);
if (!/^CI red: ci on master @0f0abc6 "Merge box-work/.test(text) || !text.includes('actions/runs/424242')) fails.push(`format: ${text}`);
if (!text.includes('pushed by igneum-labs (commit by igneum-labs);') || !text.includes('site build at "identity grep of the public export list"')) fails.push(`format: the line does not name the pushing author and the red check: ${text}`);
if (!text.includes('pushed by igneum-labs (commit by igneum-ci);') || !text.includes('site build at "identity grep of the public export list"')) fails.push(`format: the line does not name the pushing author and the red check: ${text}`);
// a feature branch is recorded and formatted like master (every branch since 7 October 2026)
const envFeature = { ...env, GITHUB_RUN_ID: '424299', GITHUB_REF_NAME: 'ca3-v4-node', RED_WATCH_AUTHOR: 'igneum-labs' };
const fileFeature = path.join(dir, 'feature.jsonl');
@ -250,7 +250,7 @@ async function selfTest() {
// the workflow_run shape (ci-red.yml): GITHUB_* describe the watcher's own run, RED_WATCH_* the failed one; the line is the failed run's
const envRun = { GITHUB_RUN_ID: '999', GITHUB_RUN_ATTEMPT: '1', GITHUB_REPOSITORY: 'igneum-network/igneum', GITHUB_REF_NAME: 'master', GITHUB_SHA: 'ffffffffffff', GITHUB_WORKFLOW: 'ci-red', GITHUB_ACTOR: 'igneum-labs', GITHUB_TOKEN: 'x',
RED_WATCH_RUN_ID: '37620364667', RED_WATCH_ATTEMPT: '2', RED_WATCH_WORKFLOW: 'ci', RED_WATCH_BRANCH: 'ca3-v4-node', RED_WATCH_SHA: '26a4b0f1deadbeef', RED_WATCH_EVENT: 'push',
RED_WATCH_URL: 'https://github.com/igneum-network/igneum/actions/runs/37620364667', RED_WATCH_ACTOR: 'igneum-labs', RED_WATCH_TITLE: 'Counter ASIC 3.0 node plan 6.7', RED_WATCH_AUTHOR: 'igneum-labs' };
RED_WATCH_URL: 'https://github.com/igneum-network/igneum/actions/runs/37620364667', RED_WATCH_ACTOR: 'igneum-labs', RED_WATCH_TITLE: 'Counter ASIC 3.0 node plan 6.7', RED_WATCH_AUTHOR: 'igneum-ci' };
const fileRun = path.join(dir, 'workflow-run.jsonl'); const asked = [];
const askingFetch = async (url) => { asked.push(url); return { ok: true, status: 200, json: async () => jobs }; };
await record(fileRun, envRun, askingFetch);
@ -258,7 +258,7 @@ async function selfTest() {
if (lr.run_id !== '37620364667' || lr.attempt !== 2 || lr.branch !== 'ca3-v4-node' || lr.sha !== '26a4b0f' || lr.workflow !== 'ci') fails.push(`workflow_run shape: recorded ${JSON.stringify({ run_id: lr.run_id, attempt: lr.attempt, branch: lr.branch, sha: lr.sha, workflow: lr.workflow })}, expected the failed run, not the watcher's`);
if (!asked[0] || !asked[0].includes('/actions/runs/37620364667/jobs')) fails.push(`workflow_run shape: the jobs API was asked for ${asked[0]}, not the failed run`);
const textRun = formatLine(lr);
if (!/^CI red: ci on ca3-v4-node @26a4b0f "Counter ASIC 3.0 node plan 6.7": pushed by igneum-labs \(commit by igneum-labs\); site build at "identity grep of the public export list"; simulators at "\(job never started: runner or billing\)" https:\/\/github.com\/igneum-network\/igneum\/actions\/runs\/37620364667$/.test(textRun)) fails.push(`workflow_run line: ${textRun}`);
if (!/^CI red: ci on ca3-v4-node @26a4b0f "Counter ASIC 3.0 node plan 6.7": pushed by igneum-labs \(commit by igneum-ci\); site build at "identity grep of the public export list"; simulators at "\(job never started: runner or billing\)" https:\/\/github.com\/igneum-network\/igneum\/actions\/runs\/37620364667$/.test(textRun)) fails.push(`workflow_run line: ${textRun}`);
// post, dry run: prints, sends nothing, marks nothing
let printed = []; const log = (s) => printed.push(s);
const sends = []; const hookFetch = async (url, init) => { sends.push({ url, body: JSON.parse(init.body) }); return { ok: true, status: 204 }; };

View file

@ -0,0 +1,136 @@
#!/usr/bin/env node
// The public shape of the criticism ledger (main's ruling, 7 October 2026, 19:5x UK): docs/ledger-public.md, one row per item
// (id, the claim or criticism in one line, status, what was done in one line, the evidence link), generated from
// docs/fud-ledger.md so it never drifts. Nothing from the ledger's round sections or status-update sections; no internal commit
// ids (7 to 40 hex), no lane or agent names, no time of day (dates stay at the day). The founder check reads the output like
// every tracked file.
//
// node tools/ledger/export-public.mjs # rewrite docs/ledger-public.md from docs/fud-ledger.md
// node tools/ledger/export-public.mjs --check # exit 1 when docs/ledger-public.md differs from what the ledger generates (the gate)
// node tools/ledger/export-public.mjs --self-test # a fixture ledger with a commit id, a time, a lane name and a Fix line gives rows
// # with none of them and the right fields; --check fails on a drifted output
// Node 22, standard library only.
import fs from 'node:fs';
import os from 'node:os';
import path from 'node:path';
const ROOT = path.resolve(path.dirname(new URL(import.meta.url).pathname), '..', '..');
const LEDGER = path.join(ROOT, 'docs', 'fud-ledger.md');
const OUT = path.join(ROOT, 'docs', 'ledger-public.md');
const ITEM = /^### ([A-Z][A-Z0-9-]*?)\. (.+)$/;
export function parseItems(text) {
// an item runs from its heading to the next ### or ## heading; the round, status-update and count sections carry no items
// of their own shape except the headings they introduce, which are items like any other
const lines = text.split('\n'); const items = [];
let cur = null;
for (const line of lines) {
const m = line.match(ITEM);
if (m) { cur = { id: m[1], title: m[2].trim(), body: [] }; items.push(cur); continue; }
if (/^##? /.test(line) || /^### /.test(line)) { cur = null; continue; }
if (cur) cur.body.push(line);
}
return items;
}
const field = (body, name) => { // the LAST paragraph starting "<name>" (a later status line supersedes), joined to one line
let found = '';
for (let i = 0; i < body.length; i++) {
if (new RegExp(`^${name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}${name.endsWith(':') ? '' : '\\b'}`).test(body[i])) {
let j = i, para = [];
while (j < body.length && body[j].trim()) { para.push(body[j]); j++; }
found = para.join(' ');
}
}
return found;
};
const firstSentence = (s) => {
const t = s.replace(/\s+/g, ' ').trim();
const m = t.match(/^(.*?[.!?])(\s|$)(?![a-z0-9])/);
return (m ? m[1] : t).trim();
};
export function scrub(s) {
return s
.replace(/`?\b[0-9a-f]{7,40}\b`?/g, (x) => (/[a-f]/.test(x) && /[0-9]/.test(x) ? 'a commit' : x)) // a commit id has both letters and digits
.replace(/\b\d{1,2}:\d{2}(?::\d{2})?(?:\s?(?:UTC|UK|BST|GMT|Z))?\b/g, '')
.replace(/\b\d{2}:[0-9x]{2}(?:\s?(?:UTC|UK|BST|GMT|Z))?\b/g, '')
.replace(/,\s*(?:night|evening|afternoon|morning|midday|noon|late|early)(?=[,)\s.;:])/gi, '')
.replace(/\b(?:the\s+)?[a-z0-9-]+\s+lane(?:'s)?\b/gi, 'the team')
.replace(/\bmain's\b/g, "the team's").replace(/\bby main\b/g, 'by the team')
.replace(/\b(?:the\s+)?(?:ledger closer|shipper|reviewer|coordinator|orchestrator|steward)(?:'s)?\b/gi, 'the team')
.replace(/\b[Bb]ranch\s+`[^`]+`/g, 'a branch').replace(/\b[Ff]ork\s+`[^`]+`/g, 'a fork').replace(/\bbranches?\s+[a-z0-9][a-z0-9.-]*(?:\s+and\s+[a-z0-9][a-z0-9.-]*)?\b/g, 'a branch')
.replace(/,\s*;/g, ';').replace(/\(\s*[;,]\s*/g, '(').replace(/\(\s*\)/g, '').replace(/,\s*\)/g, ')').replace(/\s+([,.;:)])/g, '$1').replace(/\s{2,}/g, ' ').trim();
}
const cell = (s, max) => { s = s.replace(/\|/g, '\\|'); return s.length > max ? s.slice(0, max - 1).replace(/\s+\S*$/, '') + '…' : s; };
export function rowOf(item) {
const status = field(item.body, 'Status:').replace(/^Status:\s*/, '');
let statusShort = status.split(/[(:]/)[0].replace(/[.,;\s]+$/, '').trim() || 'unstated';
const fix = field(item.body, 'Fix'); const answer = field(item.body, 'Answer:'); const evidence = field(item.body, 'Evidence:');
// what was done, in order of worth: the Fix line; the status line's own remainder ("Decided (...): no standing bounty."); the Answer
let done = '';
const statusRest = status.replace(/^[^:(]*(?:\([^)]*\))?\s*:?\s*/, '');
if (fix) done = firstSentence(fix.replace(/^Fix(?:\s+needed)?\s*(?:\([^)]*\))?\s*[:,]?\s*/, ''));
else if (statusRest && statusRest !== status) done = firstSentence(statusRest);
else if (answer) done = firstSentence(answer.replace(/^Answer:\s*/, ''));
if (!/[A-Za-z0-9]/.test(done) && answer) done = firstSentence(answer.replace(/^Answer:\s*/, '')); // a status with no remainder
done = done.replace(/^(["'`]?)([a-z])/, (m, q, c) => q + c.toUpperCase());
// the evidence link: the first repository path in backticks, from Evidence:, then the fix, then the answer (a file, or a directory with its slash)
let link = '';
for (const src of [evidence, fix, answer]) {
const m = src && src.match(/`((?:[A-Za-z0-9_.-]+\/)+(?:[A-Za-z0-9_.-]+\.[A-Za-z0-9]+)?)`/);
if (m) { link = `[${m[1]}](../${m[1]})`; break; }
}
// no repository path: the evidence names a document section or a measurement in words, so the words stand (scrubbed, one line)
if (!link) { const words = firstSentence(evidence.replace(/^Evidence:\s*/, '').replace(/\s*Fix:.*$/, '')); link = words && /[A-Za-z]/.test(words) ? cell(scrub(words), 120) : 'none named'; }
return { id: item.id, claim: cell(scrub(item.title), 140), status: cell(scrub(statusShort), 60), done: cell(scrub(done), 220), evidence: link };
}
export function render(text) {
const items = parseItems(text); const rows = items.map(rowOf);
const byStatus = {}; for (const r of rows) byStatus[r.status] = (byStatus[r.status] || 0) + 1;
const out = [];
out.push('# Igneum criticism ledger, public shape');
out.push('');
out.push('Generated by `tools/ledger/export-public.mjs` from `docs/fud-ledger.md`; a gate check fails when the two drift. One row per item: the claim or criticism, its status, what was done, and the evidence. Internal identifiers, times of day and team-member names are left out on purpose; the full ledger is published with the repository.');
out.push('');
out.push(`${rows.length} items. By status: ${Object.entries(byStatus).sort((a, b) => b[1] - a[1]).map(([k, v]) => `${k} ${v}`).join('; ')}.`);
out.push('');
out.push('| Id | Claim or criticism | Status | What was done | Evidence |');
out.push('|---|---|---|---|---|');
for (const r of rows) out.push(`| ${r.id} | ${r.claim} | ${r.status} | ${r.done} | ${r.evidence} |`);
out.push('');
return out.join('\n');
}
function selfTest() {
const fx = `# ledger\n\n## 1. Section\n\n### M1. The program space is tiny\n"Eleven ops." Said on 3 October 2026.\n\nStatus: Decided (6 October 2026, 17:35 UTC, by the owner): no bounty. Second sentence.\n\nAnswer: Correct that the arithmetic is simple. More.\n\nEvidence: \`docs/bench-log.md\` (RTX 5090 sweep), commit 0e2d6b1c.\n\n### F1. Finality is attackable for the first month\nText.\n\nStatus: Fixed on a branch, pending merge (5 October 2026, night): fork branch \`ledger-fixes-0311\` fbb0082a.\n\nFix (5 October 2026, night), the harness text only: \`tools/finality-attacks/run.mjs\` names the floor (the hash lane, 14:44 UTC; main's ruling). Branch \`fin-fixes\` da1eb889 merged.\n\nEvidence: see the fix.\n\n## Round 3 entries\n\n### AP-F8-1. A load whose source was last written by \`or\` makes a hot set\nStatus: Fixed (7 October 2026, 13:31:10Z, the attack-pass lane).\n\n## Count by status\n\n| x | y |\n`;
const fails = [];
const items = parseItems(fx);
if (items.map((i) => i.id).join(',') !== 'M1,F1,AP-F8-1') fails.push(`items: ${items.map((i) => i.id).join(',')}`);
const rows = items.map(rowOf);
const text = render(fx);
if (rows[0].status !== 'Decided' || rows[0].done !== 'No bounty.' || rows[0].evidence !== '[docs/bench-log.md](../docs/bench-log.md)') fails.push(`M1 row: ${JSON.stringify(rows[0])}`);
if (rows[1].status !== 'Fixed on a branch, pending merge' || !/^The harness text only: `tools\/finality-attacks\/run\.mjs` names the floor/.test(rows[1].done)) fails.push(`F1 row: ${JSON.stringify(rows[1])}`);
if (rows[1].evidence !== '[tools/finality-attacks/run.mjs](../tools/finality-attacks/run.mjs)') fails.push(`F1 evidence: ${rows[1].evidence}`);
if (rows[2].evidence !== 'none named') fails.push(`AP-F8-1 evidence without an Evidence line: ${rows[2].evidence}`);
for (const bad of [/0e2d6b1c/, /fbb0082a/, /da1eb889/, /\d\d:\d\d/, /hash lane/, /attack-pass lane/, /main's/, /, night/, /fin-fixes/, /ledger-fixes-0311/]) if (bad.test(text)) fails.push(`scrub: ${bad} survived: ${text.match(bad)?.input?.slice(0, 0)}${(text.split('\n').find((l) => bad.test(l)) || '').slice(0, 160)}`);
if (!/\| AP-F8-1 \| A load whose source was last written by `or` makes a hot set \| Fixed \|/.test(text)) fails.push('AP-F8-1 row missing or wrong');
if (!/^3 items\. By status: /m.test(text)) fails.push('count line');
// --check: a drifted output fails, the generated one passes
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'ledger-public-')); const o = path.join(dir, 'out.md');
fs.writeFileSync(o, render(fx)); if (!check(fx, o)) fails.push('check: a fresh output was reported as drifted');
fs.appendFileSync(o, 'drift\n'); if (check(fx, o)) fails.push('check: a drifted output passed');
fs.rmSync(dir, { recursive: true, force: true });
if (fails.length) { for (const f of fails) console.error(`self-test failed: ${f}`); process.exit(1); }
console.log('self-test passed: one row per item with id, claim, status, what was done and the evidence link; commit ids, times of day, lane and agent names and branch names are gone; --check fails on drift and passes on the generated file');
}
export function check(text, outFile) { return fs.existsSync(outFile) && fs.readFileSync(outFile, 'utf8') === render(text); }
const arg = process.argv[2];
if (arg === '--self-test') selfTest();
else if (arg === '--check') {
const ok = check(fs.readFileSync(LEDGER, 'utf8'), OUT);
console.log(ok ? `ledger-public: docs/ledger-public.md matches docs/fud-ledger.md (${parseItems(fs.readFileSync(LEDGER, 'utf8')).length} items)` : 'ledger-public: docs/ledger-public.md differs from what docs/fud-ledger.md generates; run node tools/ledger/export-public.mjs and commit');
process.exit(ok ? 0 : 1);
} else {
const text = fs.readFileSync(LEDGER, 'utf8'); fs.writeFileSync(OUT, render(text));
console.log(`ledger-public: wrote docs/ledger-public.md, ${parseItems(text).length} items`);
}

View file

@ -27,7 +27,7 @@ set -euo pipefail
export TZ=UTC
HERE="$(cd "$(dirname "$0")" && pwd)"
ROOT="$(cd "$HERE/../.." && pwd)"
STANDING_LOGIN="${IGNEUM_STANDING_LOGIN:-igneum-labs}"
STANDING_LOGIN="${IGNEUM_STANDING_LOGIN:-$(base64 -d < "$(cd "$(dirname "$0")/../.." && pwd)/tools/ci/founder-strings.b64" | grep -vE '^#' | sed -n '10p' | cut -f2)}" # the login's pre-rename spelling, from the encoded list (no tracked file spells it)
ORG="igneum-network"
SOURCE="" WORK="" NEW_REPO="$ORG/igneum-core" NEW_LOGIN="" PUBLIC_CLAUDE="" CLEAN=0
while [ $# -gt 0 ]; do

View file

@ -39,7 +39,7 @@
//
// Secrets: ~/.config/igneum/dl-token, dlsite-dir, relay-token, relay-key, ota-signing-key, vercel/ are read by this
// tool or by the scripts it calls and never printed; every output line is scrubbed of the tokens. State that is not a
// secret (commit, run id, bump time) lives in ~/.cache/igneum/ship/<version>.json. gh auth switch --user igneum-labs runs
// secret (commit, run id, bump time) lives in ~/.cache/igneum/ship/<version>.json. gh auth switch --user <the stored login> runs
// before every gh call and before the push (the account drifted twice on 4 October). Zero dependencies.
import { readFileSync, writeFileSync, existsSync, statSync, mkdirSync, copyFileSync, rmSync, mkdtempSync } from 'node:fs';
import { spawn, spawnSync } from 'node:child_process';
@ -51,7 +51,7 @@ import { fileURLToPath } from 'node:url';
process.stdout.on('error', e => { if (e.code === 'EPIPE') process.exit(0); throw e; });
const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..');
const REPO = 'igneum-network/igneum';
const GH_USER = 'igneum-labs';
const GH_USER = (() => { try { return readFileSync(join(homedir(), '.config', 'igneum', 'gh-user'), 'utf8').trim() || 'igneum-labs'; } catch { return 'igneum-labs'; } })(); // the keyring entry's name
const WORKFLOW = 'windows.yml';
const CFG = join(homedir(), '.config', 'igneum');
const cfg = n => { try { return readFileSync(join(CFG, n), 'utf8').trim(); } catch { return ''; } };