Merge master 5fbafe632 into ci-tv-d02 under the master-landing lock

This commit is contained in:
igneum-labs 2026-10-09 09:00:16 +00:00
commit 80a760ca47
24 changed files with 2166 additions and 220 deletions

View file

@ -0,0 +1,34 @@
# Igneum: evidence and experiment brief for the 1.5x target (9 October 2026)
The founder's brief, the standing order of 9 October: after the chain is one tip, every research lane and every idle box works on the 1.5x target. The brief sits beside the Complete Master Edition (`../igneum-2.0-complete-master.pdf`) as its experiment companion. It claims no pass, and neither does the team until X6.
The permanent rule: no X waits for another unless it consumes its output; one lane per experiment, one box or rented pod per variant, from minute one.
## What the brief holds
- The main recommendation: reconcile first whether the newest hybrid model still benefits from fixed per-load-site windows (the earlier source models half of the items serving 72 percent of reads and tests its census against that window-conditioned distribution); then compare the frozen control with a newly versioned candidate that removes the window restrictions, measuring total GPU energy, accepted throughput, the exact live-dataset access distributions, train and holdout cache policies and the complete re-optimised specialist energy.
- The arithmetic table (the brief's "Scope of the calculation"): with r0 the current GPU-to-specialist energy ratio, r_new = r0 x g / a; at r0 = 1.9, 2.0 and 2.1 the GPU-only reduction to 1.5x is 21.05, 25.00 and 28.57 percent, the specialist-only increase 26.67, 33.33 and 40.00 percent, and a 15 percent GPU reduction with a 20 percent specialist increase gives 1.3458, 1.4167 and 1.4875. The identity forecasts no obtainable engineering gain.
- The window hypothesis (the brief's "Conditional cache calculation"): against a fixed half-capacity store a uniform independent access stream yields 50 percent hits, so the relative miss-count increase over the reported 72 percent static hit fraction is 78.57 percent; this is not a chip-energy increase and not a demonstrated GPU advantage. An epoch permutation preserves the sorted static access probabilities and cannot by itself erase hot-set mass.
- The rejected candidates kept as controls, never described as unexplored fixes: the connected-state candidate and the masked-FP32 candidate.
- The research boundary: a new primitive, if needed, is investigated through the storage and recomputation cost function with memory-hardness specialists, never by adding bytes or reintroducing failed scratchpads; cheap verification, deterministic generation, binding, resource safety and commodity access stay required; a formal model is not a fabricated physical lower bound.
## The experiment matrix (the founder's 09:4x fan-out, the owners and clocks as the coordinator names them)
| ID | Experiment | Mandatory output | Owner | Clock |
|---|---|---|---|---|
| X0 | Reconcile the latest model and the exact frozen software | pack and commit identities; the wall-power boundary; node scaling; whether layer-8-off and compaction are included | the adversary lane (a1a9876a88f5a72fc) with the hash lane (a690540514aa453d7) | 10:15 UK |
| X1 | Fixed-window removal, a new consensus version (the class v7 shape) | live memory traces; cache-hit curves by capacity and policy; native correctness and generation availability; GPU performance | the X1 research lane (a6decc31f55cfbd00): the candidate cut by 10:15; the census, the live traces and the hit curves on three boxes in parallel, the GPU rows on rented 5090 and 4090 pods | 11:30 UK |
| X2 | Serving-mode result compaction | exact output equivalence including overflow and sentinels; wall joules and accepted throughput; no invented percentage | the X2 worker lane (a884c7bf29d150268) | 11:30 UK |
| X3 | Workload-specific Ember tuning | paired energy and rate data with stability and rejected-share checks; the same safe thermal policy | the X3 Ember lane (ae16e56dd365a2ea6) | 11:30 UK |
| X4 | Byte-identical reg64 implementation alternatives | direct, generated and prefix alternative performance; state, storage and port update costs on both sides | the X4 k lane (adf5683e5bcd9042b) | 11:30 UK |
| X5 | Co-optimised full opponent sweep | DRAM, several hybrid fractions, full SRAM and recomputation; complete power, area and throughput; the worst credible design retained | the adversary lane with the floor lanes: on the control now on six rented CPU hosts, the hybrid rows re-run on X1's traces | 12:30 UK |
| X6 | Blind confirmatory evaluation | held-out families and seeds, the required GPU cohort, same-node and one-node-ahead P04, P03 costs, P12 economics | the CI steward (a2ecfa95d3206016c) as the blind runner, the moment X1's and X5's rows exist | 14:00 UK |
## The landed copy
`igneum-1p5x-experiment-brief.md` is the brief as handed over, with one class of edit: inside its quoted source extracts the token "BST" occurred ten times and the machine name "PC 1" once; both trip the repository's identity gate on an exported path, so each "BST" reads "UK" and "PC 1" reads "the Windows desk host" in the landed copy. Nothing else changed.
| Copy | sha256 |
|---|---|
| the original as handed over | `74ee073286d4a6e211723163c39d1e5afc52eb74cbfa99108b926a5e61d2ad67` |
| the landed copy | `13e0caaa26a774035c8ee461fdc842ecf18afaee27167eceaef4973c22a681b4` |

View file

@ -0,0 +1,253 @@
# Igneum: evidence and experiment brief for the 1.5x target
Prepared 9 October 2026 from the previously supplied 8 October source archive. This is targeted document/source inspection plus arithmetic, not a new GPU benchmark, native Rust test, chip measurement, or verification of the newest reported 1.9-2.1x figures.
## Main recommendation
First reconcile whether the newest hybrid model still benefits from fixed per-load-site windows. The earlier source models half of the items serving 72% of reads, and its census tests against that window-conditioned distribution rather than demanding globally flat traffic. It also schedules a layer-8-off experiment; do not count this as an unperformed new idea if that experiment has since completed.
Compare the frozen control with a newly versioned candidate that removes those window restrictions, preserving the other experimental dimensions. Measure total GPU energy and accepted throughput, exact live-dataset access distributions, train/holdout cache policies, and complete re-optimised specialist energy. Uniform static accesses do not defeat a cache storing half the data, and do not hurt a full-SRAM store merely by being uniform.
The original connected-state and masked-FP32 candidates are recorded as rejected. They should remain controls, not be described as unexplored fixes.
## Exact source extracts
### `docs/design/class-v6-rotating-family.md:564-582`
File SHA-256: `1fa9d00f156de5cf1a1e0006811b185ff1c5fadf8196d5e5839fc606491c641c`
```text
564: #### 10.0q D4 landed: the coexistence model's second cut, the operator simulation, and the hybrid board scored (lane 3 at 4e9d51cc, 16:58 UK, three hours inside its clocks; both files in this landing; every row modelled; the scripts on build-4)
565:
566: **The pass line, met and stated:** `docs/analysis/class-v6/coexistence-model.md` (the second cut, the D4 checklist as its section list, section 13 marking every line in or owed) names seven credible conditions for sustained commodity participation (its section 12, each with its number) and names where it fails: a sunk SRAM-die fleet of USD 10 M or more at any price in the window, USD 1 M in a shrinking chain. The DRAM-board chip passes all seven at a one to three year life without a small network (it holds at 42 TH/s and IGN 1.00), without token appreciation (it holds on flat and shrinking paths) and without scheduled ASIC death (its life axis, not the rotation, is what it lives on). The SRAM die fails (a), (b), (c), (e) and (f) at every life, path and tariff once sunk; the only thing that holds it is that nobody pays to build it, carried as an investor's decision. New in the cut: the tariff advantage beside the hardware advantage with the review's 6.25x row first (on the measured rows the operating advantage is joules times tariff, 2.2x to 18.9x for the board and 3.7x to 32x for the die, the total a third to a half of it); break-even electricity for all 17 classes, owner and entrant (a GPU owner matches the three-year board up to 9 to 15 cents on Blackwell, 4 to 6 on Ada and Ampere, and the die at 0 to 5 cents; no entrant matches the three-year board or the die at any positive price); proving as a second income per class at zero, launch and spike demand on the proving-payment resolution's shape (a 16 GB or larger card earns USD 3 to 7 a day from internal proving at IGN 0.10 against 0.2 to 1.7 from mining; the 12 GB tier 0, the fleet lane's measured zero; any hash engine 0: condition (g)); the chip-side 1.5x generation at year 3 (moves the chip totals under 5 percent, its cost being hardware and the GPU's power); a per-class supply curve with the installed base as a cap (44.7 TH/s, approximate) and automatic re-entry (the growing path's year 4: 12.9 to 37.7 TH/s, 16 of 17 classes back); the supplier and operator dependence table (the chain's hash at IGN 0.03 to 1.00 is 12 to 95 percent of the installed base across three GPU vendors, or 17 to 128 N2 wafers from one supplier).
567:
568: **The operator simulation** (`docs/analysis/class-v6/operator-simulation.md`, the first run: mine, internal prove, external prove, off, per day at the marginal rate; four shocks, five runs; no parameter changed by hand): at launch-shape demand every shock restores in 0 periods because idle GPU capacity dwarfs the proving work. In a capacity-limited world (1 percent of the cards, the measured 5.5 percent proving efficiency) a lasting 1,000x proving spike is NOT restored in 150 periods when the internal pool is a fixed sum (provers go to the external fee market, the internal backlog grows without bound) and IS restored in 35 periods with the resolution's congestion-priced internal proving fee (peak 2x); the price fall, the six largest proving cohorts leaving, the mining entrant (1,500 of 9,177 cards move to proving) and the proving entrant restore in 0 periods in both worlds. **The one design finding: the fixed internal pool is a subsidy, not a price; internal proving needs the congestion-priced, user-funded fee too**, which is the proving payment of `docs/design/proving-payment.md` (90 percent of `pgas x f_p` to the block's proving pool), now carried there as the simulation's reason.
569:
570: **The third chip, the hybrid board (the adversary lane's D2(b) first row, 17:3x UK; modelled on its core's synthesised rows node-for-node, chip-model-v3's memory figures and adv-cache-2's measured window-layer hit rates; no chip measured):** the hottest half of the items in 1 GiB of SRAM beside the DRAM serves 72 percent of the reads, so the activate-bound board runs 3.6x the hashes on the same 16 devices: 2.69x per joule against the 5090 at its lock (2.20 to 3.03), USD 1.88 per MH/s (8.5x per dollar against the card's 16), for USD 250 of N2 SRAM a board (claimed); the uniform-store lower bound 2.30x and USD 3.34; the hottest three quarters 3.10x and USD 0.83; a node ahead 3.33x and 3.96x; the dataset floor raises the SRAM ticket (USD 690 at 5.5 GiB, USD 2.9 per MH/s) and not the ratio, the hit rate per fraction being scale-free. The record's partial-store curve (chip-model-v3 5.4) priced the un-stored items as recomputed, which loses (0.78x); stored in SRAM they win, so **the DRAM-board chip's cheapest form is the stored-half hybrid at USD 1.9 to 3.3 per MH/s**. Scored on the six conditions, a first reading by this lane on lane 3's rows (approximate; lane 3's own scoring owed by 21:00): (a) all-in within 1.5x of the best GPU owner: at 2.69x per joule the operating advantage alone is 2.7x at the GPU's tariff, so FAILS; (b) hardware per MH/s not under a quarter of the GPU entrant's: USD 1.88 against about 16, FAILS (8.5x); (c) a third of the chain costing more than a year's miner revenue: at IGN 0.10 a third of 8.8 TH/s is 2.9 TH/s, USD 5.5 M of hybrid boards against USD 77 M of revenue, FAILS; (d) GPUs keep resale and an outside use: holds (the GPU side is unchanged); (e) the per-joule gap at the knee under about 3x: 2.69x, holds at the central figure and fails at the top of its band; (f) a normal margin: at (b) and (c) the supplier's margin is the die's kind, FAILS. **So the success statement holds for the pure DRAM board, fails for the SRAM die, and on the first scoring fails for the hybrid board on (b) and (c), the dollar conditions, which is where the coordinator said to watch; what holds the hybrid is again the investment decision (the hybrid's development is the board's plus the SRAM's, USD 20 to 75 M plus the die's share), and the served form says so.** Lane 3's scoring with the sunk-development case replaces this reading by 21:00.
571:
572: #### 10.0r The placed energies, and the three chips scored at them (the adversary lane's placed row, 17:5x UK: the 8-lane genesis core placed and routed on ASAP7 with its SRAM macros, SPEF, a gate-level VCD; the full core's routed run 38 of 58 tags in; the SRAM term modelled; node factors claimed; the coordinator's order 18:0x UK: these are the energies the served form uses)
573:
574: Placement and the clock tree add 32 percent to the class v4 draw (7.78 pJ per lane-op routed against 5.91 synthesised at ASAP7; 5.44 against 4.13 at N5), inside the k lane's +20 to +40 expectation; node-for-node k 0.53 at the 5090's lock for the genesis core (0.38 a node ahead), the full 18-family core scaled 0.59 and 0.42 until its routed row lands; the 32-lane genesis core (synthesis) 3.70 pJ at N5, k 0.36, 10 percent under the 8-lane core. **Placement takes a tenth off every per-joule ratio and nothing off the per-dollar ones.** The served convention at the placed energy, the 5090 at its 1,300 MHz lock over the complete machine (controller, host share, PSU, VRM, cooling in):
575:
576: | Chip, as a complete machine | Per joule, node-for-node | Per joule, a node ahead | USD per MH/s (per dollar against the card's about 16) | Label |
577: |---|---|---|---|---|
578: | The GDDR7 board (the chip anyone can build) | **1.6x** (1.4x to 1.8x); 1.4x the 5080; 2.5x the cohort card | 1.9x (1.5x to 2.1x); 1.7x the 5080; 2.9x the cohort | 4.84 (3.3x) | placed core, modelled memory and machine, measured card |
579: | The stored-half hybrid board (1 GiB of SRAM beside the DRAM; 10.0q) | about 2.4x | about 2.9x | 1.88 (8.5x); the 5.5 GiB floor raises its SRAM ticket to USD 690 a board | modelled on the placed core |
580: | The N2 SRAM die | 2.4x | 3.3x | 0.8 (about 20x) | modelled on the placed core |
581:
582: Scored on lane 3's seven conditions at these energies (a first reading on lane 3's rows, approximate; its own scoring with the sunk-development case replaces it by 21:00): the board's verdicts stand (its per-joule ratio falls a tenth, its dollars do not move; it passes all seven at a one to three year life); the hybrid's stand (it fails (b) and (c), the dollar conditions, which placement does not touch; on (e) it sits on the 3x line a node ahead and under it node-for-node); the die's stand on (a), (b), (c) and (f) (its dollars are the die's) and on (e) it now holds node-for-node (2.4x) and fails a node ahead (3.3x). **So the success statement holds for the pure DRAM board, fails for the SRAM die once sunk, and fails for the hybrid on the dollar conditions; the placed energies change no verdict and tighten every per-joule figure by a tenth.** The served energy sentence (10.0h) reads from this table.
```
### `docs/analysis/class-v6/census-packs.md:18-22`
File SHA-256: `1aa41baecf0eb2683dbd7392fcc827dc69aa1cc72f1f751803081bf1c9b21885`
```text
18: What the sheet means. The index fold does what it was drawn for: the stride-bit bias is gone from every program it ships, the F8 tails of 1.22 to 1.50x come inside the gate (1.01 to 1.19x) and the bucket concentration at narrow-window sites falls from the control's 5 of 16 seeds to 0 of 16; p225's value-level class is untouched and p34 gains one bucket statistic. The k lane's table (rw1, `or` never drawn, `mul` at 4) reads clean and gives the lowest rejection rate measured on the family (0.117); the census lane's table (rw2, `or` 4, `mul` 6) keeps the lossy writers the tails come from and fails the F8 line, so the re-weight is sound in the rw1 form only. The window changes nothing the rule or the F8 form sees at 2^22 on the closed form and carries the fold's and the table's rows unchanged; its value is the chip-side cost the adversary lane prices.
19:
20: ## 1. The harness
21:
22: The class v5 crate of each pack's branch plus lane D's family-gate harness diff (`docs/analysis/class-v6/logs/harness-family-gate-v5-3dc3117c.diff`: `IGNEUM_FAMILY_GATE` widens the class v4 rules to the family's shapes, with every new class flag set aside in `is_family_shape`: state, fold, rw, wide8, reg64, reg64_chain), plus: a `sitestats` command (the whole rule with (c'''), then per site over 2^20 evaluations the distinct ratio against the window model, the largest 256-item bucket in sigma, the largest index-bit excess in sigma over the free bits); the `accept` walk at the class's own cap under the flag; the attack-pass lane's `attack-f8` with `--load-class <string>` (the program drawn from a class string with the spec's era laid over it) and `--dataset-words N` (the ds55 geometry through `load_index_geom`; not exercised: a state class refuses the non-power-of-two count); the uniform trace tool `tools/attack/v6-census/uniform` on `verify::Probe { trace_loads }` (every load's index per lane through the interpreter itself). Binaries pinned per crate under `/srv/builds/v6-census/bin/<tag>/` with sha256: fold-5b3486f0 (igneum-pow 50903d30, attack-f8 9ba2210b), reg64-1b676975 (v6census-uniform b2214265 after the fixes), all-d7d441be (igneum-pow 5a221e56, v6census-uniform 2ebd92c1).
```
### `docs/analysis/class-v6/census-packs.md:36-38`
File SHA-256: `1aa41baecf0eb2683dbd7392fcc827dc69aa1cc72f1f751803081bf1c9b21885`
```text
36: ## 3. The instrument's definition (the hot-set reconcile, for the record)
37:
38: Three reads. The acceptance's index-bit read: per program, per site, the one-count of each address bit over the 64 units' 16,384 addresses, judged inside the site's own era window and above the width's alignment, 6 sigma. The sitestats bucket: per program, per site, the largest 256-item bucket in sigma of its window expectation. attack-f8 census: per program, per item over the whole dataset, the cross-hash item histogram of all sites' reads against the WINDOW-MODEL control (the density the program's 16 drawn windows imply), the top-0.1-percent share ratio (1.2x), the 6-sigma largest 64-item bucket, the hot-set test; the flat-control ratio printed beside it and not used (1.1 to 1.7x on every pack: layer 8 by design, the adversary lane's 72 percent read against the other null).
```
### `docs/analysis/class-v6/family-gate.md:336-344`
File SHA-256: `59933bbd191f7f1674abc83447b7dd05b9f03d34a3a167d49b303ae9f52dc551`
```text
336: 1. DONE 13:2x UK: the lossy-share curve per shape (section 6.4) and the last-resort scan's verdicts on every exhausted era.
337: 2. DONE 14:4x UK: the pre-floor spread at width 4 against width 1 under the band and the floor decision (section 6.5: 0.995 kept at width 4 at its measured cost; the 0.990 to 0.995 band at width 4 read live before any floor moves).
338: 3. DONE 15:30 UK: the two ring-C live-dataset rows (section 6.6: 128 live epochs of the band, 2 hot sets at the 256 shape both refused by the floor, 0 at the 64 shape).
339: 4. DONE 15:1x UK: the x4, x8 and x16 verifier rows (section 6.7, build-3 one core: 3.73 / 4.12 / 7.13 ms per warp; x16 outside the band on the 10 ms gate by scaling to the proxies).
340: 5. DONE 14:4x UK: the width-4 plus shape-64 crossing (build-4, 3,000 eras: r = 0.654, 0 exhausted, (c''') 5.3 percent of candidates, the width's floor cost again) and section 6.8, the F8 label space's p2 to p65 and p212 to p225 through the sigma form at the shipped parameters (build-2, queued 14:0x UK), so the two F8-256 attributions the hash lane added to layer 4's bucket-bound row (p212, site 9 at 1.75x its window expectation; p225, a value-level concentration at a mad-written site with the bucket at expectation) and the morning's four tail seeds are read as known-failed cases of the bucket-sigma and bit-bias tests on one scale; and the bucket bound in sigma (from the bit-clean spread: p99 +6.8, p99.9 +16.5 to +20.1, max +35 over 9,409 eras; a band at +8 refuses 0.3 to 0.4 percent of bit-clean programs and 11 to 18 percent of all, which is the biased population, so the bucket bound and the bit read are one rule).
341: 6. The gate-record form: `logs/gate-records-lossy-base.jsonl` (3,000 records of the band stratum in the section 4.3 shape, one per line, 3.6 MB) and `logs/fg-records.py`, which derives every other stratum's records from its TSV rows in this directory.
342: 7. DONE 18:0x UK, section 6.9 (the Igneum 2.0 pause of 17:10 UK keeps this row as D1's op-mix acceptance and pauses the rest of the family gate; this report stands as the no-rescue test's control document): the research lane's best-mix genesis table (add 16, xor 14, mad 12, rotl 11, sub 10, rotr 10, shfl 4, mul 4, mulhi 2, or 0, sum 83; renormalised to 75 by largest remainder as 14, 13, 4, 11, 3, 10, 9, 2, 9, 0 in the generator's order) through the acceptance at the shipped parameters: the attempts census with the refused-ratio column at widths 4 and 1, the index-bit read, and attack-f8 at 2^20 on 64 seeds: PASS, the exact-table rows in at 18:20 UK. The harness is also ported onto class-v6 (13885e16f; the diff `logs/harness-v6-13885e16f.diff`, reproducing the class-v5 rows to the last digit) for the hash lane's layer-8-off acceptance due 12:00 UK on 9 October.
343: 8. Not in this report: the mixer ladder re-run at m = 4 and 16 (adv-mixer-3's harness rows; the per-family rows of section 4), the F8 census at D = 29 (the stand-in gap row), the 10^5-program verifier census at the top corner (F6 per family): each a named per-family row with its hours in section 4.1.
344:
```
### `docs/analysis/class-v6/connected-state.md:91-126`
File SHA-256: `f56e653aa2eab15bdfa9bee37555042a77bb4f9b2e3ea76f9fd2736ba803ba39`
```text
91: ## 5. The chip side
92:
93: The k lane (floor lane 2) priced the re-optimised core on the drawn program at 17:2x UK (synthesis only, a model and never a lower bound; its placed row is due 21:00 as an amendment). The core: 8 lanes, a 64 x 32-bit window per lane in clock-gated flops (a macro file reads within 5 percent), a 512-entry imem holding the 448-instruction text, one in-order op per cycle per lane (the spine's ILP is met by lane count, which is free), every class unit, the load's fold on the address path; gate-level random-input VCD, every pin annotated; 253,059 cells.
94:
95: | Row (the k lane's) | pJ per lane-op, ASAP7 | N5 (the card's node) | N3 | N2 | k at the 1,300 lock, N5 / N3 / N2 | k at stock, N5 / N3 |
96: |---|---|---|---|---|---|---|
97: | cs64s27x16, the re-optimised core (gated window, 512 imem) | 6.3 | 4.4 | 3.2 | 2.3 | 0.71 / 0.51 / 0.37 | 0.39 / 0.28 |
98: | the same window on the class v4 draw, 256 imem | 6.2 | 4.3 | 3.1 | 2.2 | 0.70 / 0.50 / 0.36 | 0.38 / 0.27 |
99: | the adversary's 32-register base, gated (the genesis window) | 4.5 | 3.2 | 2.3 | 1.6 | 0.51 / 0.37 / 0.26 | 0.28 / 0.20 |
100: | the GPU-shaped 64-register core, ungated (shadow-k.md, the earlier default) | 9.7 | 6.8 | 4.9 | 3.5 | 1.09 / 0.78 / 0.56 | 0.60 / 0.43 |
101:
102: What the adversary's re-optimisation did to each part of the structure: the gated file charges only the register written, so the whole-window liveness costs it nothing beyond the write it would make anyway and the hot-20 banking of section 2 is not even needed; the 16-pass loop and the 448 text cost the shared imem 0.1 pJ per lane-op; the narrow per-step chain sets the lane count, which is free. The window itself is worth +1.2 pJ per lane-op at N5 over the genesis window (+0.14 of k at the lock), the same knob as the design document's 64-register row; the connected organisation around it adds about 0.1 pJ. The placed ungated core came in 64 percent over its synthesis, so the placed figure is expected near 8 to 10 pJ at ASAP7 (k node-for-node near 0.9 to 1.1, approximate); both rows move together and the ratio below holds.
103:
104: ## 6. The score and the verdict
105:
106: E_GPU over E_adversary, absolute convention, GDDR7 board (E_mem 0.466 microjoules per hash), E_chip = E_mem + 55,296 x e_chip, E_GPU = the 5090 at the lock (2.33 microjoules per hash on class v5) x 1.016 for the window (the the Windows desk host lock row of section 4; the table was first written at x 1.006 from the stock rows and the amendment moved the ratios from 1.10x and 1.08x to 1.08x and 1.07x):
107:
108: | Core | Node-for-node (N5) | A node ahead (N3) | Two nodes (N2) |
109: |---|---|---|---|
110: | cs64s27x16, re-optimised | 2.367 / (0.466 + 0.243) = 3.3x | 2.367 / (0.466 + 0.177) = 3.7x | 2.367 / (0.466 + 0.127) = 4.0x |
111: | the genesis window (the control) | 2.33 / (0.466 + 0.177) = 3.6x | 2.33 / (0.466 + 0.127) = 3.9x | 2.33 / (0.466 + 0.088) = 4.2x |
112: | the window's effect on the chip's edge | 1.08x | 1.07x | 1.05x |
113:
114: On the placed figures (both rows 64 percent higher) the pair reads about 2.2x and 2.4x node-for-node and the ratio stays near 1.1x. The gate was 1.25x node-for-node for the 1.5x one-node-ahead ambition; the row reads 1.08x node-for-node and 1.07x a node ahead.
115:
116: **Verdict: KILL as a class.** The hypothesis was that a connected organisation of the same work, with the window independently necessary across the whole chain, would deny a specialist its separation of storage, arithmetic and scheduling. It does not: the liveness rows show the window is necessary (63 of 64 at every address) and the chip answers with a clock-gated file that pays per write, not per live register, so necessity costs it nothing; the only term that reaches the chip is the window's own width (+0.14 k at the lock), which the design document already holds as its one robust core knob, and the connected structure adds about 0.1 pJ around it. The GPU side passes its budget with room (+0.6 percent of energy per hash at stock on the 5090, -0.9 percent on the 4090, 80 to 87 registers per thread with no spill), and the census passes every instrument with fewer attempts than v5; neither moves the score. The founder's accepted review stands in a sharper form than before: a specialist's edge against this family is a per-op energy ratio on a known op mix, and reorganising the dependency graph of the same ops does not change what an op costs on either side.
117:
118: What is kept: the generator variant and the liveness tool (research class, behind the flag) for the v7 tests below; the measured fact that a 64-register window costs a card under 1 percent at stock, which fixes the design document's modelled "about 0 rate" row; the kit worker and nvcc harness agreement on two cards. What is withdrawn: the "connected state" line as a resistance mechanism.
119:
120: ## 7. What a v7 variant would test next
121:
122: - The index fold on the address (the layer-1 row) in this class, which removes the window-bit refusals on eras 0, 1, 4, 5 and 6 for the control and this class alike.
123: - A wider per-step chain: a spine of depth 8 to 16 so `dep` rises from about 11 toward the window, at the cost of ILP on the card (measure the rate first; the chain per step is what a two-level file exploits).
124: - The window at 32 and 16 (`cs32s27x16`, `cs16s27x16`) for the k curve, and the block at 16 x 27 (`cs64s16x27`, text 272) if the imem matters to the re-optimised core.
125: - The op-mix re-weight of the census lane at this structure (the two closing instructions already take the injecting table).
126: - A knob that reaches a gated file: not more live state but more WRITES per op the chip cannot skip (every op writing two registers, or a window write per load), priced against the card's own write cost first; the k lane's placed row at 21:00 says whether even that moves k.
```
### `igneum-pow/src/verify.rs:8-63`
File SHA-256: `033ae9f2ccd32e1170e7ff4f259b206b26e78ddc9ebf68d7b26933794aa1f345`
```text
8: /// The load address of an era program (`docs/plans/era-layout.md` section 1.3): `y = rotl(x * M, R)`, then the
9: /// window of the load site, `k = min(win, D - 26)` (0 when `D <= 26`), `idx = ((y & (MASK >> k)) | ((off &
10: /// (2^k - 1)) << (D - k))) & MASK`. For every other class `idx = x & MASK`, the lottery hash's address. `mask` is
11: /// `2^D - 1`. The acceptance mirror calls this at the rule's constant `D = 28`.
12: ///
13: /// Class v6 lane 1, the index fold (`docs/design/class-v6-rotating-family.md` section 2; `EraParams::fold`): the
14: /// product's low bits are folded before the rotation, `y = x * M; y ^= y >> 16; y = rotl(y, R)` ([`stride`]), so no
15: /// era's R lands a biased product bit (bit 0 of `x * M` for odd M is bit 0 of x; bit 1 is set at 3/8) on an address
16: /// bit. Every era of every other class keeps the plain product.
17: #[inline(always)]
18: pub fn load_index(era: Option<&EraParams>, ins: &Instr, x: u32, mask: u32, log2: u32) -> u32 {
19: match era {
20: None => x & mask,
21: Some(e) => {
22: let (wm, off) = window(ins, mask, log2);
23: let y = stride(e, x);
24: ((y & wm) | off) & mask
25: }
26: }
27: }
28:
29: /// The era's stride of a source value: `rotl(x * M, R)`, with the index fold of class v6 lane 1 between the product
30: /// and the rotation when the era carries it (`y ^= y >> 16`). The one place the form lives on the CPU side; the three
31: /// emitters write the same text ([`crate::emit`]).
32: #[inline(always)]
33: pub fn stride(e: &EraParams, x: u32) -> u32 {
34: let mut y = x.wrapping_mul(e.stride_mul);
35: if e.fold {
36: y ^= y >> 16;
37: }
38: y.rotate_left(e.stride_rot)
39: }
40:
41: /// The fold's shift (`y ^= y >> INDEX_FOLD_SHIFT`), named for the pack texts and the tests.
42: pub const INDEX_FOLD_SHIFT: u32 = 16;
43:
44: /// The window of a load site at a dataset of `2^log2` words: `(window mask, offset)` such that
45: /// `idx = (y & window mask) | offset` lies in the site's aligned window of `2^(log2 - k)` words.
46: #[inline(always)]
47: pub fn window(ins: &Instr, mask: u32, log2: u32) -> (u32, u32) {
48: let k = (ins.win as u32).min(log2.saturating_sub(26));
49: let wm = mask >> k;
50: let off = ((ins.off as u32) & ((1u32 << k) - 1)) << (log2 - k);
51: (wm, off)
52: }
53:
54: /// The window of a load site in the 32-bit SOURCE space (the multiply-shift mapping, research class ds55,
55: /// 8 October 2026): `k = min(win, log2 - 26)` as [`window`] with `log2 = floor(log2(N))`, and `(window mask,
56: /// offset)` such that `v = (y & window mask) | offset` lies in the site's aligned window of `2^(32 - k)` source
57: /// values; `idx = (v * N) >> 32` then lands in a contiguous run of about `N / 2^k` words, the site's window of the
58: /// dataset.
59: #[inline(always)]
60: pub fn window32(ins: &Instr, log2: u32) -> (u32, u32) {
61: let k = (ins.win as u32).min(log2.saturating_sub(26));
62: let wm = u32::MAX >> k;
63: let off = ((((ins.off as u32) & ((1u32 << k) - 1)) as u64) << (32 - k)) as u32;
```
### `igneum-pow/src/verify.rs:154-171`
File SHA-256: `033ae9f2ccd32e1170e7ff4f259b206b26e78ddc9ebf68d7b26933794aa1f345`
```text
154: /// `(x * N) >> 32` and the era form windows the source first ([`window32`]) then reduces.
155: #[inline(always)]
156: pub fn load_index_geom(era: Option<&EraParams>, ins: &Instr, x: u32, geom: DatasetGeom) -> u32 {
157: if !geom.mulshift {
158: return load_index(era, ins, x, geom.mask(), geom.log2);
159: }
160: match era {
161: None => geom.reduce(x),
162: Some(e) => {
163: let (wm, off) = window32(ins, geom.log2);
164: let y = stride(e, x);
165: geom.reduce((y & wm) | off)
166: }
167: }
168: }
169:
170: /// Read-width experiment (5 October 2026): a `load` of `W` words folds every word into `dst`:
171: /// `x = dst XOR w[0]; for j in 1..W: x = (rotl(x, FOLD_ROT) * FOLD_MUL) XOR w[j]; dst = x`. For `W = 1` this is the
```
### `docs/design/class-v6-rotating-family.md:540-551`
File SHA-256: `1fa9d00f156de5cf1a1e0006811b185ff1c5fadf8196d5e5839fc606491c641c`
```text
540: #### 10.0o Amendment (16:3x UK): the mixed FP32 candidate, KILLED on the GPU budget and the full-board score (`docs/analysis/class-v6/mixed-fp32.md` on class-v6-mixedfp at 255be026; all measured unless marked; for class v7)
541:
542: The candidate: the class v6 shape unchanged, four FP32 families (fadd, fmul, ffma, fcvt) drawn in the shadow block beside the ten integer families behind `IGNEUM_FG_FP32` (harness only), every result xor-injected, every operand a masked bitcast with the exponent field confined to 96..159 so no input or result is ever denormal, NaN or infinite; round to nearest even, no contraction, no fast-math, written in the emitter for CUDA, OpenCL and Metal; two weights, fp12 (18 percent of the shadow FP on the seed) and fp24 (30 percent).
543:
544: | Reading | The numbers | Label |
545: |---|---|---|
546: | Determinism | bit-identical CPU reference against CUDA on Ada and Blackwell: the pack self-test PASS on three rented cards for every pack, the 2^24 fingerprint equal on the CPU and all three cards for ctrl (5203e444a20bc754), fp12 (d9ddef1fa7a7895a) and fp24 (8fdedbb54ad3614f); Metal and the AMD OpenCL row owed | measured (PROVED on CUDA) |
547: | Census (sub-version 3, build-4, 256 seeds no era and 256 across eras 0 to 7) | both candidates 256 of 256 both ways, 0 exhausted, r 0.65 to 0.81 against the record's 0.67 to 0.83; the bias instruments fire 7x to 19x the record ((c'') 54 and 88 refusals against 8, (c''') 15 and 19 against 1, the era window-bit test 27 and 35 percent of candidates against 14.5); the F8-form read finds hot items (271 and 740 reads against the control's 29) on 1 of 16 and 2 of 16 seeds: an IEEE result's exponent byte carries 3 to 5 bits of entropy and the xor lands it on address bits 23 to 30 | measured |
548: | The verifier | the quiet core +5.6 percent (fp12), +8.2 (fp24); loaded, fp24 sits on the 10 ms line | measured |
549: | The card at stock (the class v5 kit worker, 250 x 2^24, nvidia-smi 1 Hz) | the 5090 3.553 microjoules per hash on ctrl, 4.078 on fp12 (+14.8 percent, 140.7 MH/s held, the card at its 575 W cap), 4.034 capped on fp24 (+13.5 with the clock down 108 MHz); the 4090 4.759, 5.664 (+19.0) and 6.022 (+26.5); v5-genesis +1 percent on both. 52 pJ per FP family op on the 5090, four fifths of it the determinism tax (the four integer ops per operand); the 10 percent budget allows about 11 percent of the shadow FP on the 5090, 9 on the 4090 | measured |
550: | The chip side (modelled on the k lane's method; its synthesised rows owed) | an FP32 FMA lane on its own is the family a chip undercuts least, k 0.4 to 0.5 at the lock against mad's synthesised 0.20 (the hypothesis's grain of truth), but the drawn op is the FMA plus its masking, which is ARX work on both sides, so the blended k of an ffma family op is 0.19 and an fadd's 0.18: the integer families' own | modelled |
551: | The full board, E_GPU over E_adversary at the 5090's lock | 3.0x on the record, 3.2x under fp12 (3.2x and 3.4x a node ahead): the candidate raises the chip's edge about 7 percent while costing every card 15 to 26 percent | modelled on measured card rows |
```
## Scope of the calculation
Let r0 be the current GPU/specialist energy ratio. Let g and a be the new-to-old GPU and specialist energies per equivalent accepted work. Then r_new = r0 * g / a. This identity does not forecast obtainable engineering gains.
| Current ratio | GPU-only energy reduction to 1.5x | Specialist-only increase to 1.5x | 15% GPU reduction plus 20% specialist increase |
|---|---:|---:|---:|
| 1.9 | 21.05% | 26.67% | 1.3458 |
| 2.0 | 25.00% | 33.33% | 1.4167 |
| 2.1 | 28.57% | 40.00% | 1.4875 |
## Conditional cache calculation
For the earlier reported static 72% hit fraction, misses = 28%. A truly uniform independent access distribution against a fixed half-capacity store yields a 50% hit fraction and 50% misses. The relative miss-count increase is 0.50 / 0.28 - 1 = 78.57%. This is NOT a 78.57% increase in chip energy or a demonstrated GPU advantage. It assumes equal-sized items, independent uniform requests, no extra compression, and the same fixed stored fraction. Dynamic replacement, predictable accesses, recomputation, overlap, bandwidth and power management must be evaluated separately.
An epoch permutation preserves the sorted static access probabilities. It cannot by itself erase hot-set mass. A cheaper on-chip copy may still serve 50% of a uniform stream, and an all-SRAM store may serve all of it.
## Proposed experiment matrix
| ID | Experiment | Mandatory output |
|---|---|---|
| X0 | Reconcile latest model and exact frozen software | Pack/commit identities; wall-power boundary; node scaling; whether layer-8-off and compaction are included |
| X1 | Fixed-window removal, new consensus version | Live memory traces; cache-hit curves by capacity and policy; native correctness and generation availability; GPU performance |
| X2 | Serving-mode result compaction | Exact output equivalence incl. overflow/sentinels; wall joules and accepted throughput; no invented percentage |
| X3 | Workload-specific Ember tuning | Paired energy/rate data with stability and rejected-share checks; same safe thermal policy |
| X4 | Byte-identical reg64 implementation alternatives | Direct/generated/prefix alternative performance; state/storage/port update costs on both sides |
| X5 | Co-optimised full opponent sweep | DRAM, multiple hybrid fractions, full SRAM and recomputation; complete power/area/throughput; worst credible design retained |
| X6 | Blind confirmatory evaluation | Held-out families/seeds, required GPU cohort, same/one-node-ahead P04, P03 costs, P12 economics |
## Research boundary
If a new primitive is needed, investigate the storage/recomputation cost function with memory-hardness specialists rather than increasing bytes or reintroducing failed scratchpads. Any new construction must also meet cheap-verification, deterministic generation, binding, resource-safety and commodity-access requirements. A formal model is not a fabricated physical lower bound.
No P04 pass, new performance result or release activation is claimed by this brief.

View file

@ -9,3 +9,5 @@ Files: igneum-2.0-complete-master.pdf (the light edition; the obsidian edition h
The claim the master makes: "A complete, independently substantiated technical/economic/operational/commercial pass supports a credible leadership-contender assessment, not a numerical rank certificate." Status: compilation only; no new technical tests were run for this edition. Missing or unrun evidence is not PASS; a defect reproduced by a probe is not a passed gate.
Companion volume: `token-value/` holds "Igneum 2.0, Token Value and Network Leadership" (1.0-proposed, snapshot 8 October 2026), the monetary companion to this master, status PROPOSED, every TV gate NOT RUN; see `token-value/README.md`.
Experiment companion: `1p5x/` holds the founder's "evidence and experiment brief for the 1.5x target" (9 October 2026), the standing order that every research lane and idle box works on the 1.5x target once the chain is one tip; it claims no pass; see `1p5x/README.md`.

View file

@ -2,7 +2,9 @@
A companion to the Complete Master Edition (`../igneum-2.0-complete-master.pdf`), not a replacement. The master stays THE reference; this volume is its monetary companion.
Status: PROPOSED. No gate has been executed; every TV gate reads NOT RUN. The six decisions D01 to D06 are the founder's and read "pending" in every public text until signed. The registry rows for the TV gates are recorded by the CI steward's batches, never by this landing.
Status: PROPOSED. No gate has been executed; every TV gate reads NOT RUN. The registry rows for the VR rules and the TV gates are recorded by the CI steward's batches, never by this landing.
The six decisions D01 to D06 were ratified by the founder on 9 October 2026 and are recorded in the registry's decisions block by the steward's batch at master d3686955 (ci-token-value 956fcb32, 09:14 UK): D01 capped issuance with no tail escape, subject to the pre-launch security-funding gate TV-04; D02 the same-cap emission comparison approved, the final schedule pending evidence; D03 separate accountable budgets, every payment counted once; D04 explicit auditable routing, the 80/20 split emission allocation only, the external-job rate not ratified; D05 a recovery certificate never shown as ordinary finality; D06 separate claims with the scoped public wording. Each is recorded against its specification, release and acceptance tests before activation.
The recommended public wording until a ranking is measured: "Designed to compete for leadership among GPU-first networks."

View file

@ -430,6 +430,14 @@ Rule: a case maps to a cell only where the cell's tests visibly answer it; cover
- CAP-02 Prove on the actual mining configuration: partial: proving alone (shard and the whole segment path) on the 8 GB and 12 GB tiers on the default job path, the time-share refusal beside the miner with the miner unharmed, memory headroom and proof latency; wall energy only on the 3060 (the 4060 host has no power sensor); induced GPU task failure and wallet control not run; 16 GB and 24 GB tiers not run
- UX-02 Make pause, stop and safe tuning reliable: partial: the prover's safe refusal under memory pressure (exit 78 in one line, the miner's worker unharmed, nothing leaked after the refusal); pause, stop, power limit and the UI's crash ownership are the suite:app cell's
### model:tv-04
- Command: `the TV-04 security-budget model: docs/plans/igneum-2.0-master/token-value/phase0/tv-04 (the generator and its tests on build-9; budget.csv, emission.csv, blocked.csv regenerate byte-identical), a reproducible cash-flow model of the ratified rules D01, D03, D04 (the external-job rate unratified), D05 and VR-05`
- Box class: build-9 (a model run, no GPU)
- Fixtures: F0
- Cases:
- TV-04 Security budget without price rescue: partial: the model computes each role's budget from the ratified rules; the verdict waits on the independent panel filling the role costs and declaring the viable and collapse cells; no price figure
### model:tv-d02-emission
- Command: `python3 tools/token-value/d02/test_d02.py && python3 tools/token-value/d02/d02_emission.py --check docs/plans/igneum-2.0-master/token-value/phase0/d02 (build-3, tools/token-value/d02/run_on_box.sh generate|crosscheck)`

File diff suppressed because one or more lines are too long

View file

@ -1,6 +1,6 @@
# The relay agent as a logon task (IgneumRelayService, registered by install-agent.ps1 from IgneumRelayService.xml).
# This loop keeps igneum-agent.ps1 running with no window: the Task Scheduler restarts this loop on failure (PT1M, 999
# times), and the loop restarts the agent 15 s after any exit, so the agent outlives the app, a crash of its own, and a
# times), and the loop restarts the agent 10 s after any exit, so the agent outlives the app, a crash of its own, and a
# reboot (the task fires at logon; the PC signs in by itself). MF-11, 7 October 2026: PC 2's agent had been dead since
# 6 October and its one-shot logon task exited at every boot, so neither a signed job nor a relay task could start the app.
# Output goes to %LOCALAPPDATA%\igneum-relay\logs\agent-service.log (5 MB, one rotation); the idle line is left out.
@ -19,7 +19,7 @@ while ($true) {
# one Add-Content per line, so the file is never held open: a reader (a job's Get-Content -Tail) is refused while a
# pipeline holds it (PC 2, 7 October 2026, 15:38 local: "being used by another process")
& powershell.exe -NoProfile -ExecutionPolicy Bypass -File $Agent 2>&1 | ForEach-Object { "$_" } | Where-Object { $_ -notmatch 'idle as ' } | ForEach-Object { Add-Content -Path $log -Value $_ }
Note ('agent exited with code ' + $LASTEXITCODE + '; again in 15 s')
} catch { Note ('agent failed to start: ' + $_.Exception.Message + '; again in 15 s') }
Start-Sleep -Seconds 15
Note ('agent exited with code ' + $LASTEXITCODE + '; again in 10 s')
} catch { Note ('agent failed to start: ' + $_.Exception.Message + '; again in 10 s') }
Start-Sleep -Seconds 10
}

View file

@ -6,8 +6,13 @@
# the task. Every IgneumRelayAgent* task (the one-shot reboot arms of X25) and the RunOnce key go first: on PC 2 a stale
# one pointed at a path that was not there and popped "Windows cannot find 'igneum-agent'" at every boot (7 October 2026).
# A failure here is a line on stdout and an exit code, never a dialog.
# powershell -ExecutionPolicy Bypass -File install-agent.ps1 [-Highest] [-Remove]
param([switch]$Highest, [switch]$Remove)
# The watchdog (watchdog.ps1 beside this file; 9 October 2026, the founder's rule that no machine needs a hand to
# recover): two more tasks, IgneumRelayWatchdog every 5 minutes and IgneumRelayWatchdogLogon a minute after logon, start
# the service task when the agent's pid is dead (the logon one as a loop checking every 10 s, so the agent is back within
# 15 s) and register it again when it is missing, so the agent outlives the
# engine's update, restart, quit and a reboot. -NoWatchdog skips them (the watchdog itself calls this script with it).
# powershell -ExecutionPolicy Bypass -File install-agent.ps1 [-Highest] [-Remove] [-NoWatchdog]
param([switch]$Highest, [switch]$Remove, [switch]$NoWatchdog)
$ErrorActionPreference = 'Continue'
$Here = Split-Path -Parent $MyInvocation.MyCommand.Path
$TaskName = 'IgneumRelayService'
@ -30,11 +35,19 @@ try {
if ((Test-Path $k) -and ((Get-ItemProperty -Path $k -ErrorAction SilentlyContinue).PSObject.Properties.Name -contains 'IgneumRelayAgent')) { Remove-ItemProperty -Path $k -Name 'IgneumRelayAgent' -ErrorAction SilentlyContinue; Write-Host 'removed the RunOnce key IgneumRelayAgent' }
} catch { }
if ($Remove) {
foreach ($w in @('IgneumRelayWatchdog', 'IgneumRelayWatchdogLogon')) { & schtasks.exe /Delete /F /TN $w 2>&1 | Out-Null }
& schtasks.exe /End /TN $TaskName 2>&1 | Out-Null
& schtasks.exe /Delete /F /TN $TaskName 2>&1 | Out-Null
Write-Host ('removed the ' + $TaskName + ' task (an agent window started by hand is not touched)')
exit 0
}
# A stale lock (9 October 2026, both PCs at 09:0x UK): an agent copy that holds the mutex but no longer polls (it sat waiting
# on an app a task had relaunched) made the bat refuse a second copy, and a hand was needed. Every shell running
# igneum-agent.ps1 or its service loop is ended here BY PID before the task is registered, so the install always starts
# clean; nothing of the Miner is touched (the engine and its workers are not powershell shells of ours).
$stale = @(Get-CimInstance Win32_Process | Where-Object { $_.Name -match '^(powershell|pwsh)\.exe$' -and $_.CommandLine -match 'igneum-agent(-service)?\.ps1' -and $_.ProcessId -ne $PID })
foreach ($p in $stale) { Stop-Process -Id $p.ProcessId -Force -ErrorAction SilentlyContinue; Write-Host ('ended the old agent shell pid ' + $p.ProcessId + ' (it held the lock)') }
if ($stale.Count -gt 0) { Start-Sleep -Seconds 2 }
foreach ($f in @('IgneumRelayService.xml', 'igneum-agent-service.ps1', 'igneum-agent.ps1', 'machine-secret.txt')) {
if (-not (Test-Path (Join-Path $Here $f))) { Write-Host ('missing ' + $f + ' beside this script (unzip the whole client zip from make-clients.sh --machine <name>)'); exit 2 }
}
@ -53,6 +66,16 @@ try {
Write-Host ('registered ' + $TaskName + ' for ' + $user + ' at ' + $level + ' from ' + $Here)
} finally { Remove-Item -Path $tmp -Force -ErrorAction SilentlyContinue }
& schtasks.exe /Run /TN $TaskName 2>&1 | ForEach-Object { "$_" } | Write-Host
if (-not $NoWatchdog) {
$wd = Join-Path $Here 'watchdog.ps1'
if (Test-Path $wd) {
$tr = 'powershell.exe -NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -File "' + $wd + '"'
$w1 = & schtasks.exe /Create /F /TN 'IgneumRelayWatchdog' /SC MINUTE /MO 5 /RL LIMITED /TR $tr 2>&1 | ForEach-Object { "$_" }
$w2 = & schtasks.exe /Create /F /TN 'IgneumRelayWatchdogLogon' /SC ONLOGON /DELAY 0001:00 /RL LIMITED /TR ($tr + ' -Loop') 2>&1 | ForEach-Object { "$_" }
Write-Host ('watchdog tasks: ' + (($w1 + $w2) -join ' | '))
& schtasks.exe /Run /TN 'IgneumRelayWatchdogLogon' 2>&1 | Out-Null
} else { Write-Host ('no watchdog.ps1 beside this script; the watchdog tasks are not registered') }
}
Start-Sleep -Seconds 3
& schtasks.exe /Query /TN $TaskName /V /FO LIST 2>&1 | ForEach-Object { "$_" } | Where-Object { $_ -match '^(TaskName|Status|Logon Mode|Last Run Time|Last Result|Task To Run|Run As User|Schedule Type):' } | Write-Host
Write-Host 'the agent now runs under the task; close any igneum-agent.bat window (the task copy exits while that one holds the mutex, and comes back 15 s after it closes)'

View file

@ -31,7 +31,7 @@ fi
mkdir -p "$OUT"
NAME="igneum-relay-clients${MACHINE:+-$MACHINE}"
STAGE="$(mktemp -d)/$NAME"; mkdir -p "$STAGE"; umask 077
for f in send.bat send.ps1 send.sh igneum-agent.bat igneum-agent.ps1 igneum-agent-service.ps1 install-agent.ps1 IgneumRelayService.xml agent.sh CLAUDE-PC.md; do
for f in send.bat send.ps1 send.sh igneum-agent.bat igneum-agent.ps1 igneum-agent-service.ps1 install-agent.ps1 watchdog.ps1 IgneumRelayService.xml agent.sh CLAUDE-PC.md; do
sed -e "s#__RELAY_URL__#$URL#g" -e "s#__RELAY_KEY__#$KEY#g" -e "s#__RELAY_TOKEN__#$TOKEN#g" -e "s#__DL_BASE__#$DL_BASE#g" "$HERE/$f" > "$STAGE/$f"
done
[ -n "$SECRET" ] && printf '%s\n' "$SECRET" > "$STAGE/machine-secret.txt"

View file

@ -0,0 +1,46 @@
# Relay agent watchdog (9 October 2026, the founder's standing rule: no machine needs a hand to recover). Registered by
# install-agent.ps1 as two scheduled tasks beside IgneumRelayService: IgneumRelayWatchdog every 5 minutes and
# IgneumRelayWatchdogLogon one minute after this user's logon. When the agent's pid file names no live process and no
# igneum-agent.ps1 shell runs, it starts the IgneumRelayService task; when that task is missing, it registers it again
# with install-agent.ps1 from this folder. The agent is only ever started by the task scheduler, never by a job of the
# engine (an agent started under a job died with the engine's update on PC 1, 9 October 09:08 UK). It ends nothing.
# watchdog.ps1 one check (the five-minute task): the agent, then the loop below when none runs
# watchdog.ps1 -Loop the loop (the logon task): one check every 10 s for 55 minutes, so a dead agent is back within
# 15 s (the founder's bar); it exits after 55 minutes and the five-minute task starts it again
param([switch]$Loop)
$ErrorActionPreference = 'Continue'
$Here = Split-Path -Parent $MyInvocation.MyCommand.Path
$state = Join-Path $env:LOCALAPPDATA 'igneum-relay'
New-Item -ItemType Directory -Force -Path $state | Out-Null
$log = Join-Path $state 'watchdog.log'
function L($s) { Add-Content -Path $log -Value ((Get-Date).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ') + ' ' + $s) }
$live = Join-Path $state 'agent.live'
function Agent-Alive {
if (Test-Path -LiteralPath $live) { try { $t = (Get-Content -LiteralPath $live -Raw).Trim(); if ($t -match '^\d+$' -and (Get-Process -Id ([int]$t) -ErrorAction SilentlyContinue)) { return $true } } catch { } }
return [bool](Get-CimInstance Win32_Process | Where-Object { $_.Name -match '^(powershell|pwsh)\.exe$' -and $_.CommandLine -match 'igneum-agent\.ps1' } | Select-Object -First 1)
}
function Check {
if (Agent-Alive) { return }
$q = & schtasks.exe /Query /TN 'IgneumRelayService' 2>&1 | Out-String
if ($q -match 'IgneumRelayService') {
& schtasks.exe /Run /TN 'IgneumRelayService' 2>&1 | Out-Null
L 'agent not running: IgneumRelayService task started'
} else {
$inst = Join-Path $Here 'install-agent.ps1'
if (Test-Path -LiteralPath $inst) { & powershell.exe -NoProfile -ExecutionPolicy Bypass -File $inst -NoWatchdog 2>&1 | Out-Null; L ('IgneumRelayService task missing: registered again from ' + $inst) } else { L ('IgneumRelayService task missing and no install-agent.ps1 beside ' + $Here + '; nothing done') }
}
}
if ($Loop) {
# one loop at a time: a second one exits
$mine = $PID
$other = Get-CimInstance Win32_Process | Where-Object { $_.ProcessId -ne $mine -and $_.Name -match '^(powershell|pwsh)\.exe$' -and $_.CommandLine -match 'watchdog\.ps1' -and $_.CommandLine -match '-Loop' } | Select-Object -First 1
if ($other) { exit 0 }
$until = (Get-Date).AddMinutes(55)
while ((Get-Date) -lt $until) { Check; Start-Sleep -Seconds 10 }
exit 0
}
Check
# the loop itself: started here when none runs (after a logon it is the logon task's; after 55 minutes it is this task's)
$loopUp = Get-CimInstance Win32_Process | Where-Object { $_.Name -match '^(powershell|pwsh)\.exe$' -and $_.CommandLine -match 'watchdog\.ps1' -and $_.CommandLine -match '-Loop' } | Select-Object -First 1
if (-not $loopUp) { & schtasks.exe /Run /TN 'IgneumRelayWatchdogLogon' 2>&1 | Out-Null; L 'watchdog loop not running: IgneumRelayWatchdogLogon task started' }
exit 0

View file

@ -15,7 +15,7 @@
"profile_hashes": ""
},
"claim_impact": "INT-07's clean-install half on kit 2 reads FAIL on the fleet canary (the walk bound at the fifth cut); the mac block PASS stands as the Mac entry's evidence; no fleet, hive or windows entry publishes until a record reads PASS on its own block",
"note": "Kit 2 (tip 1176efb9, node 5d53a591): the mac block PASS under tools/ci/canary-check.sh (the project's macOS machine: synced from empty in 2,016 s, 18 blocks in five minutes at 12.65 MH/s, 0 refusals, shard n/a on Apple silicon, the tip inside ten of the age-adjusted feed, quit in 4 s); the fleet block FAIL at sync (lp-4090-11, 04:04 UK: a fresh 2.0.2 node walls at the reference chain's fifth cut under fix 2's walk bound, 'passed 7200 blocks (2 x epoch_blocks) without meeting a block this executor holds a record of'; the kit ran clean; build-1:/srv/canary/1176efb9/lp-4090-11/fleet-block.json); the hive block reads about 05:30 UK, the windows block on the relay lane's clock. No fleet, hive or windows entry publishes on this record; the Mac entry published on its PASS block at 02:20 UK. Kit 1's 94e4c6ba FAIL (the wedge) stands as that sha's record. The recorder's rule: a measured FAIL on one block is a FAIL on the case. Re-recorded 9 October 2026 04:3x UK with the hive block (lp-4090-43, FAIL at sync on the lost-proof loop) and the re-shaped fleet block (no sync.feed object). Cell note brought up to the record's three blocks at 08:1x UK (the hive landing had re-recorded the batch note only). Re-recorded 9 October 2026 08:2x UK with hive-2, the lp-4090-43 kit-binary block and hive-3 (all FAIL at sync; the sync gate closed the hive run class). Re-recorded 08:3x UK: the record's own verdict FAIL. (The check now refuses a record whose own verdict reads PASS over a FAIL block, 09:0x UK.)",
"note": "Kit 2 (tip 1176efb9, node 5d53a591): the mac block PASS under tools/ci/canary-check.sh (the project's macOS machine: synced from empty in 2,016 s, 18 blocks in five minutes at 12.65 MH/s, 0 refusals, shard n/a on Apple silicon, the tip inside ten of the age-adjusted feed, quit in 4 s); the fleet block FAIL at sync (lp-4090-11, 04:04 UK: a fresh 2.0.2 node walls at the reference chain's fifth cut under fix 2's walk bound, 'passed 7200 blocks (2 x epoch_blocks) without meeting a block this executor holds a record of'; the kit ran clean; build-1:/srv/canary/1176efb9/lp-4090-11/fleet-block.json); the hive block reads about 05:30 UK, the windows block on the relay lane's clock. No fleet, hive or windows entry publishes on this record; the Mac entry published on its PASS block at 02:20 UK. Kit 1's 94e4c6ba FAIL (the wedge) stands as that sha's record. The recorder's rule: a measured FAIL on one block is a FAIL on the case. Re-recorded 9 October 2026 04:3x UK with the hive block (lp-4090-43, FAIL at sync on the lost-proof loop) and the re-shaped fleet block (no sync.feed object). Cell note brought up to the record's three blocks at 08:1x UK (the hive landing had re-recorded the batch note only). Re-recorded 9 October 2026 08:2x UK with hive-2, the lp-4090-43 kit-binary block and hive-3 (all FAIL at sync; the sync gate closed the hive run class). Re-recorded 08:3x UK: the record's own verdict FAIL. (The check now refuses a record whose own verdict reads PASS over a FAIL block, 09:0x UK.) Re-recorded 09:3x UK with the mini's recovery legs on the mac block. Re-recorded 09:5x UK: the reboot leg PASS.",
"cells": [
{
"cell": "canary:fresh-install",

View file

@ -24,5 +24,5 @@
"evidence": "build-1:/srv/artefacts/p01/p01-20261008-01/cuda-5090-hl-v5-win.json; build-1:/srv/artefacts/p01/p01-20261008-01/cuda-4090-hl-v5-win.json; build-1:/srv/artefacts/p01/p01-20261008-01/cuda-3090-hl-v5-win.json; build-1:/srv/artefacts/p01/p01-20261008-01/cuda-5090-hl-v6-all.json; build-1:/srv/artefacts/p01/p01-20261008-01/cuda-4090-hl-v6-all.json; build-1:/srv/artefacts/p01/p01-20261008-01/cuda-3090-hl-v6-all.json; build-1:/srv/artefacts/p01/p01-20261008-01/cuda-5090-hl-v6-foldrw.json; build-1:/srv/artefacts/p01/p01-20261008-01/cuda-4090-hl-v6-foldrw.json; build-1:/srv/artefacts/p01/p01-20261008-01/cuda-3090-hl-v6-foldrw.json; build-1:/srv/artefacts/p01/p01-20261008-01/cuda-5090-hl-v6-all-nowin.json; build-1:/srv/artefacts/p01/p01-20261008-01/cuda-4090-hl-v6-all-nowin.json; build-1:/srv/artefacts/p01/p01-20261008-01/cuda-3090-hl-v6-all-nowin.json"
}
],
"note": "P01 part A, the CUDA half, complete at 20:41 UK: four packs (hl-v5-win e3da3669 id 0x6554474f410f36f3 gen 5; hl-v6-all 6df3d430 id 0x4de7b836cc40a4ea gen 6; hl-v6-foldrw f0dc3428 id 0xd7eba30115d26dd4; hl-v6-all-nowin 67ceec05 id 0xbe1d6f48928cef4a) on three CUDA cards (RTX 5090 sm_120, 4090 sm_89, 3090 sm_86), twelve runs, every one driver exit 0, answered 1,000,000, agree 1,000,000, disagree 0, missing 0, 41 to 50 s per million; the kit worker 9bfcf728 for gen 5, the generator-6 worker 804a6f7f for gen 6; the twelve JSONs parsed on build-1 with their sha256s. Remaining for PASS: OpenCL (the project's first rig's RX 7600, the hash lane; no rented AMD card exists tonight) and Metal (the mini, the morning); the case stays NOT RUN in progress until then. (rig names scrubbed for the served registry at 22:2x UK, the steward's identity landing.)"
"note": "P01 part A, the CUDA half, complete at 20:41 UK: four packs (hl-v5-win e3da3669 id 0x6554474f410f36f3 gen 5; hl-v6-all 6df3d430 id 0x4de7b836cc40a4ea gen 6; hl-v6-foldrw f0dc3428 id 0xd7eba30115d26dd4; hl-v6-all-nowin 67ceec05 id 0xbe1d6f48928cef4a) on three CUDA cards (RTX 5090 sm_120, 4090 sm_89, 3090 sm_86), twelve runs, every one driver exit 0, answered 1,000,000, agree 1,000,000, disagree 0, missing 0, 41 to 50 s per million; the kit worker 9bfcf728 for gen 5, the generator-6 worker 804a6f7f for gen 6; the twelve JSONs parsed on build-1 with their sha256s. Remaining for PASS: OpenCL (the project's first rig's RX 7600, the hash lane; no rented AMD card exists tonight) and Metal (the mini, the morning); the case stays NOT RUN in progress until then. (rig names scrubbed for the served registry at 22:2x UK, the steward's identity landing.) Re-recorded at 09:5x UK once the recorder kept records per run: the twelve CUDA evidence files return to POW-01's evidence_path beside the same-work run's record."
}

View file

@ -19,7 +19,7 @@
},
"claim_impact": "POW-01's CUDA half across a dataset-day switch on the frozen object: CUDA against the CPU reference bit for bit on three ranges with the day switch at nonce 1572864. NOT same-work evidence: the node engine refuses this seed/stream pair (IgneumEngine::epoch_for's class v5 check wants the stream's block af89be5d... to equal the epoch seed edc4fa84...), so the node and pool readers cannot read it; the coordinator's ruling 22:0x UK keeps it as the CUDA and CPU-only row",
"network_label": "on an island, not a network",
"note": "Context 01 at build-1:/srv/artefacts/tas/same-work-20261008-01/job-context.json (sha256 d2540e02...). CPU reference: igneum-pow hash-bound (class-v6 1a938abe4, binary 0d3f3fca...) on build-4, 21:46 to 21:55 UK, ref-D c49fed11... over [0, 1572864), ref-D1 5ae1220d... over [1572864, 3145728); ref-D's first million lines equal the hash lane's P01 reference /srv/artefacts/packs/p01-vectors/hl-v6-all.txt byte for byte. The node1 state stream (block af89be5d...) was written on build-4 at 15:34 UK, before the 20:00 UK split; the cell carries the island label by main's 22:2x UK rule. CUDA: the 5090 PASS on all three phases (the gen 6 worker 804a6f7f, the driver at c8b65a26 or later; 23:16 to 23:20 UK: cuda-5090-1.json 1b36fb8a..., cuda-5090-2.json 70200bff... with the day switch at 1572864 driven through the worker's prepare and both boundary hashes equal to the reference (69abfadf816e767e before, 5b3fb17ad84744fd after), cuda-5090-3.json f2ecf5c7...; 1,048,576 agree each, 0 disagree, 0 missing); the 4090 PASS on all three phases (23:22 to 23:25 UK: cuda-4090-1.json cd0f5aee..., cuda-4090-2.json f864f950... with the day switch at 1572864, cuda-4090-3.json 126bd552...; 1,048,576 agree each, 0 disagree, 0 missing); The 3090 PASS on all three phases (05:07 to 05:10 UK; cuda-3090-{1,2,3}.json afa3d4a4..., 167875f9..., cc956dee...; 1,048,576 agree each, 0 disagree, 0 missing; the day switch at 1572864 with the same boundary hashes as every other reader): the fleet lane's first run on that pod at 00:35 UK never ran a phase (its verify rule demanded two reference files where a context carries one, then its put failed on the pod's flapping ssh; a runner fault, reported once), the rerun from 04:57 UK ran detached on the pod under a pid file with a collector pulling each JSON. So the CUDA cell reads three cards on this context. Metal and OpenCL are the morning's reads (08:30 UK). The case stays NOT RUN in progress until every reader has read (the coordinator's ruling 23:1x UK: a PASS by inference is forbidden). OPENCL on the first rig's RX 7600: take 1 (05:54 UK, opencl-rx7600-take1.report.txt 7fb1ee95...) was a job fault on the rig, not a reader result (the script matched an older gen-5-stamped pack of the same name in the rig's jobs tree; the worker refused it as class v5 against a class v6 job); take 2 (run-ca3-pc1-samework01-opencl-7600-20261009-b, the packs by exact path, 06:03 to 06:05 UK) reads PASS on all three phases: p1 digest 1517d572..., p2 91d63d8b... across the day switch 20730 to 20731 at 1572864 (the D+1 pack prepared in 486 ms, the boundary block 8,192 of 8,192 lines), p3 e483e82a..., each 1,048,576 of 1,048,576 equal to ref-D's and ref-D1's slices, both pack ids 0x4de7b836cc40a4ea generator 6 in the RESULT lines; 'RESULT verdict all PASS context=same-work-20261008-01 reader=opencl card=rx7600'; the report opencl-rx7600.report.txt (sha256 84683b16..., read back on build-1 at 06:09 UK). So the OpenCL reader on the RX 7600 reads all three contexts equal to the CPU reference across their day switches; Metal is the sixth reader on every context, 08:30 UK.",
"note": "Context 01 at build-1:/srv/artefacts/tas/same-work-20261008-01/job-context.json (sha256 d2540e02...). CPU reference: igneum-pow hash-bound (class-v6 1a938abe4, binary 0d3f3fca...) on build-4, 21:46 to 21:55 UK, ref-D c49fed11... over [0, 1572864), ref-D1 5ae1220d... over [1572864, 3145728); ref-D's first million lines equal the hash lane's P01 reference /srv/artefacts/packs/p01-vectors/hl-v6-all.txt byte for byte. The node1 state stream (block af89be5d...) was written on build-4 at 15:34 UK, before the 20:00 UK split; the cell carries the island label by main's 22:2x UK rule. CUDA: the 5090 PASS on all three phases (the gen 6 worker 804a6f7f, the driver at c8b65a26 or later; 23:16 to 23:20 UK: cuda-5090-1.json 1b36fb8a..., cuda-5090-2.json 70200bff... with the day switch at 1572864 driven through the worker's prepare and both boundary hashes equal to the reference (69abfadf816e767e before, 5b3fb17ad84744fd after), cuda-5090-3.json f2ecf5c7...; 1,048,576 agree each, 0 disagree, 0 missing); the 4090 PASS on all three phases (23:22 to 23:25 UK: cuda-4090-1.json cd0f5aee..., cuda-4090-2.json f864f950... with the day switch at 1572864, cuda-4090-3.json 126bd552...; 1,048,576 agree each, 0 disagree, 0 missing); The 3090 PASS on all three phases (05:07 to 05:10 UK; cuda-3090-{1,2,3}.json afa3d4a4..., 167875f9..., cc956dee...; 1,048,576 agree each, 0 disagree, 0 missing; the day switch at 1572864 with the same boundary hashes as every other reader): the fleet lane's first run on that pod at 00:35 UK never ran a phase (its verify rule demanded two reference files where a context carries one, then its put failed on the pod's flapping ssh; a runner fault, reported once), the rerun from 04:57 UK ran detached on the pod under a pid file with a collector pulling each JSON. So the CUDA cell reads three cards on this context. Metal and OpenCL are the morning's reads (08:30 UK). The case stays NOT RUN in progress until every reader has read (the coordinator's ruling 23:1x UK: a PASS by inference is forbidden). OPENCL on the first rig's RX 7600: take 1 (05:54 UK, opencl-rx7600-take1.report.txt 7fb1ee95...) was a job fault on the rig, not a reader result (the script matched an older gen-5-stamped pack of the same name in the rig's jobs tree; the worker refused it as class v5 against a class v6 job); take 2 (run-ca3-pc1-samework01-opencl-7600-20261009-b, the packs by exact path, 06:03 to 06:05 UK) reads PASS on all three phases: p1 digest 1517d572..., p2 91d63d8b... across the day switch 20730 to 20731 at 1572864 (the D+1 pack prepared in 486 ms, the boundary block 8,192 of 8,192 lines), p3 e483e82a..., each 1,048,576 of 1,048,576 equal to ref-D's and ref-D1's slices, both pack ids 0x4de7b836cc40a4ea generator 6 in the RESULT lines; 'RESULT verdict all PASS context=same-work-20261008-01 reader=opencl card=rx7600'; the report opencl-rx7600.report.txt (sha256 84683b16..., read back on build-1 at 06:09 UK). So the OpenCL reader on the RX 7600 reads all three contexts equal to the CPU reference across their day switches; Metal is the sixth reader on every context, 08:30 UK. METAL, the project's macOS machine (Apple M6) on the serve worker igneum-worker-metal 5aeddcba... (built from class-v6 755c2dbcf by the hash lane), the driver on master with --prepare-first, 08:30 to 08:31 UK: PASS on all three phases, metal-{1,2,3}.json a7ab9fac..., 9be3101a..., b3df42ef... (read back on build-1 at 09:41 UK), 1,048,576 agree each, 0 disagree, 0 missing, the day switch at 1572864 with the boundary hashes 69abfadf816e767e before and 5b3fb17ad84744fd after, equal to every other reader's. So the frozen object reads equal on the CPU reference, CUDA (three cards), OpenCL and Metal across the day switch. This row does not decide POW-01 (its accept covers the full P01 corpus across families, boundary seeds and backends with an independent review: the hash lane's); the record stays NOT RUN for POW-01 and carries the hash lane's P01 campaign evidence (p01-20261008-01) beside this row's, because the recorder keeps one record per cell and this run's record had displaced that batch's on harness:p01-vectors since 22:27 UK.",
"cells": [
{
"cell": "harness:p01-vectors",
@ -28,10 +28,9 @@
],
"status": "NOT RUN",
"method": "GPU",
"evidence": "build-1:/srv/artefacts/tas/same-work-20261008-01/job-context.json; build-1:/srv/artefacts/tas/same-work-20261008-01/references/ref-D.txt; build-1:/srv/artefacts/tas/same-work-20261008-01/references/ref-D1.txt; build-1:/srv/artefacts/tas/same-work-20261008-01/cuda-5090-1.json; build-1:/srv/artefacts/tas/same-work-20261008-01/cuda-5090-2.json; build-1:/srv/artefacts/tas/same-work-20261008-01/cuda-5090-3.json; build-1:/srv/artefacts/tas/same-work-20261008-01/cuda-4090-1.json; build-1:/srv/artefacts/tas/same-work-20261008-01/cuda-4090-2.json; build-1:/srv/artefacts/tas/same-work-20261008-01/cuda-4090-3.json; build-1:/srv/artefacts/tas/same-work-20261008-01/cuda-3090-1.json; build-1:/srv/artefacts/tas/same-work-20261008-01/cuda-3090-2.json; build-1:/srv/artefacts/tas/same-work-20261008-01/cuda-3090-3.json; build-1:/srv/artefacts/tas/same-work-20261008-01/opencl-rx7600-take1.report.txt; build-1:/srv/artefacts/tas/same-work-20261008-01/opencl-rx7600.report.txt",
"note": "the 5090, the 4090 and the 3090 PASS on all three phases of the frozen object across the day switch; OpenCL PASS x3 on the first rig's RX 7600 (the day switch seen; take 1 a job fault); Metal 08:30 UK, the last reader; CPU reference cross-checked against the hash lane's P01 file; in progress",
"network_label": "on an island, not a network",
"in_progress": true
"evidence": "build-1:/srv/artefacts/tas/same-work-20261008-01/job-context.json; build-1:/srv/artefacts/tas/same-work-20261008-01/references/ref-D.txt; build-1:/srv/artefacts/tas/same-work-20261008-01/references/ref-D1.txt; build-1:/srv/artefacts/tas/same-work-20261008-01/cuda-5090-1.json; build-1:/srv/artefacts/tas/same-work-20261008-01/cuda-5090-2.json; build-1:/srv/artefacts/tas/same-work-20261008-01/cuda-5090-3.json; build-1:/srv/artefacts/tas/same-work-20261008-01/cuda-4090-1.json; build-1:/srv/artefacts/tas/same-work-20261008-01/cuda-4090-2.json; build-1:/srv/artefacts/tas/same-work-20261008-01/cuda-4090-3.json; build-1:/srv/artefacts/tas/same-work-20261008-01/cuda-3090-1.json; build-1:/srv/artefacts/tas/same-work-20261008-01/cuda-3090-2.json; build-1:/srv/artefacts/tas/same-work-20261008-01/cuda-3090-3.json; build-1:/srv/artefacts/tas/same-work-20261008-01/opencl-rx7600-take1.report.txt; build-1:/srv/artefacts/tas/same-work-20261008-01/opencl-rx7600.report.txt; build-1:/srv/artefacts/tas/same-work-20261008-01/metal-1.json; build-1:/srv/artefacts/tas/same-work-20261008-01/metal-2.json; build-1:/srv/artefacts/tas/same-work-20261008-01/metal-3.json; build-1:/srv/artefacts/p01/p01-20261008-01/cuda-5090-hl-v5-win.json; build-1:/srv/artefacts/p01/p01-20261008-01/cuda-4090-hl-v5-win.json; build-1:/srv/artefacts/p01/p01-20261008-01/cuda-3090-hl-v5-win.json; build-1:/srv/artefacts/p01/p01-20261008-01/cuda-5090-hl-v6-all.json; build-1:/srv/artefacts/p01/p01-20261008-01/cuda-4090-hl-v6-all.json; build-1:/srv/artefacts/p01/p01-20261008-01/cuda-3090-hl-v6-all.json; build-1:/srv/artefacts/p01/p01-20261008-01/cuda-5090-hl-v6-foldrw.json; build-1:/srv/artefacts/p01/p01-20261008-01/cuda-4090-hl-v6-foldrw.json; build-1:/srv/artefacts/p01/p01-20261008-01/cuda-3090-hl-v6-foldrw.json; build-1:/srv/artefacts/p01/p01-20261008-01/cuda-5090-hl-v6-all-nowin.json; build-1:/srv/artefacts/p01/p01-20261008-01/cuda-4090-hl-v6-all-nowin.json; build-1:/srv/artefacts/p01/p01-20261008-01/cuda-3090-hl-v6-all-nowin.json",
"note": "the same-work row on the frozen object is complete: CPU reference, CUDA 5090/4090/3090 x3, OpenCL x3, Metal x3, every nonce equal across the day switch; POW-01 itself is decided by the hash lane's P01 corpus and review, not by this row; the P01 CUDA campaign's evidence is carried here so it stays on the case",
"network_label": "on an island, not a network"
}
]
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,30 @@
{
"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). Recorded by the CI steward at 09:4x UK from docs/plans/igneum-2.0-master/token-value/phase0/tv-04/registry-batch-tv-04.json (master 95027a4f, sha256 003f3653...), with the cell model:tv-04 added to the map; in progress until the panel's cells are filled.",
"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",
"in_progress": true
}
]
}

View file

@ -85,7 +85,35 @@
"verdict": "PASS",
"recorded_at": "2026-10-09T00:11:54Z",
"recorded_by": "shipper",
"run": "the mini, 02:14 UK"
"run": "the mini, 02:14 UK",
"recovery": {
"rule": "the founder's standing rule, 9 October 2026 (relayed 09:0x UK): no machine needs his hand to recover, update or mine",
"supervision": {
"miner": "LaunchAgent network.igneum.miner-supervisor (~/Library/LaunchAgents/network.igneum.miner-supervisor.plist sha256 3cc755b680cb37e1\u2026, ~/igneum-supervisor/mini-supervise.sh sha256 600d8dba7bce52b5\u2026, KeepAlive, RunAtLoad; reopens the app through LaunchServices after 90 s without api/state, waits out the app's updater by update-pending.json, never a second instance; outside the app's process tree)",
"relay_agent": "LaunchAgent network.igneum.relay-agent (sha256 cc43ce954f790aa1\u2026, KeepAlive, RunAtLoad; the relay lane's install 09:29 UK; the app's updater never ends it)",
"feeds": "LaunchAgents network.igneum.mini-tip and network.igneum.mini-collector (KeepAlive, RunAtLoad), the mini's tip feed and workers-page report"
},
"legs": [
{
"leg": "the app's update path",
"verdict": "PASS",
"read_back": "igneum-mini ~/Library/Logs/Igneum/supervisor.log",
"detail": "api/quit 09:26:55 UK as the updater's helper does, the engine gone in 3 s, the host ended by its pid, 0 app processes 09:26:59, no hand; the supervisor opened the app 09:28:28 (91 s down), the engine answered 09:28:30, the node at its kept tip (DAA 46,800) 09:28:45; one instance"
},
{
"leg": "the relay agent killed",
"verdict": "PASS",
"read_back": "igneum-mini ~/Library/Logs/Igneum/relay-agent.log",
"detail": "the agent's process ended by its recorded id at 09:31:03 UK; launchd's process 10967 at 09:31:04 (1 s), 'registered as igneum-mini' 09:31:04, idle lines after; the miner app untouched (4 processes, the supervisor process 9720)"
},
{
"leg": "a reboot",
"verdict": "PASS",
"detail": "the restart issued by the mini's own command (osascript System Events restart) at 09:45:02 UK; ssh back at 09:46:14 (71 s, uptime 51 s); the igneum console session logged in by itself at 09:45 (the founder's FileVault setup carries the pre-boot; no hand); the app relaunched by the login session 09:45:59; the miner supervisor under launchd running 09:46:04; the relay agent registered 09:46:16 (its first try failed on the network not yet up; launchd respawned it); the node at its kept tip and syncing by 09:46:30, synced on the moving reference chain at 09:47:20 (DAA 49,960, 6 peers, seed 284fb765), mining, a block accepted 09:47:16. The tip feed and the workers-page collector moved under launchd on the way (network.igneum.mini-tip f881eb2a\u2026, network.igneum.mini-collector 1e9db456\u2026)",
"read_back": "igneum-mini ~/Library/Logs/Igneum/supervisor.log, relay-agent.log; the app log"
}
]
}
},
{
"artefact": {
@ -556,6 +584,6 @@
"verdict": "FAIL",
"recorded_at": "2026-10-09T01:15:45Z",
"recorded_by": "shipper (the mini's rule-33 canary)",
"note": "Six blocks: the mac block PASS (the Mac entry published 02:20 UK on it); five FAIL at sync, 9 October 2026: lp-4090-11 fleet (the fifth cut under fix 2's walk bound), hive-1 and hive-2 (the first class v5 cut on the lost-proof loop: h-run.sh mined from the node's first grpc answer and islanded on its own records; closed by the sync gate in release-2.0.2 9998913f), lp-4090-43 kit-binary and hive-3 (against the standing reference: lp-04's chain stood at its epoch-13 cut from 05:45 UK; hive-3 climbed to 16,535 with 0 blocks mined, the gate holding the miners). Every kit and package ran clean; no fleet, hive or windows entry publishes on this record; a fresh node cannot join devnet-4 as it stands (the fifth cut, three state roots for the epoch-13 seed block across 2.0.0, 2.0.1 and 2.0.2).",
"note": "Six blocks: the mac block PASS (the Mac entry published 02:20 UK on it); five FAIL at sync, 9 October 2026: lp-4090-11 fleet (the fifth cut under fix 2's walk bound), hive-1 and hive-2 (the first class v5 cut on the lost-proof loop: h-run.sh mined from the node's first grpc answer and islanded on its own records; closed by the sync gate in release-2.0.2 9998913f), lp-4090-43 kit-binary and hive-3 (against the standing reference: lp-04's chain stood at its epoch-13 cut from 05:45 UK; hive-3 climbed to 16,535 with 0 blocks mined, the gate holding the miners). Every kit and package ran clean; no fleet, hive or windows entry publishes on this record; a fresh node cannot join devnet-4 as it stands (the fifth cut, three state roots for the epoch-13 seed block across 2.0.0, 2.0.1 and 2.0.2). Recovery (9 October 2026 09:3x UK): the miner supervisor and the relay agent under launchd on the mini; the update-path and agent-kill legs PASS; the reboot leg PASS at 09:45 UK (the mini back by itself in 71 s, mining on the moving reference chain at 09:47).",
"verdict_note": "the record's own verdict is FAIL (five of six blocks FAIL at sync; the independent review owner's read at the F0 signing, 9 October 2026); the mac block's PASS stays as its row and --artefact mac reads PASS for the Mac entry published 02:20 UK"
}

View file

@ -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 box-form hashed identity list hashes a path entry's login only, never a generic path word (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)

View file

@ -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 box-form hashed identity list hashes a path entry's login only, never a generic path word (self-test)" bash tools/ci/served-identity-hashes.sh --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 .'

View file

@ -5,7 +5,19 @@
# 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; }
if [ "${1:-}" = --self-test ]; then
d=$(mktemp -d); trap 'rm -rf "$d"' EXIT; printf '# t\n/Users/ownerlogin/Desktop/fleet\nOwner Name\n10\\.0\\.0\\.77\nDESKTOP-[A-Z0-9]{7}\n' > "$d/l"; printf 'saltsaltsaltsaltsaltsaltsaltsalt' > "$d/s"
out="$(bash "$0" "$d/l" "$d/s" 2>/dev/null)"; fails=0
python3 - "$d/s" "$out" <<'PY2' || fails=1
import sys, hmac, hashlib; salt=open(sys.argv[1],'rb').read(); digs={l for l in sys.argv[2].splitlines() if l and not l.startswith('#')}
h=lambda t: hmac.new(salt, t.encode(), hashlib.sha256).hexdigest()
bad=[t for t in ('desktop','users','fleet') if h(t) in digs]; good=[t for t in ('ownerlogin','owner','name','10.0.0.77') if h(t) in digs]
if bad or len(good) != 4: print(f"self-test failed: generic words hashed {bad}; distinctive tokens hashed {good}"); sys.exit(1)
PY2
[ "$fails" = 0 ] && echo "self-test passed: a path entry hashes its login only (desktop, users and fleet never become digests); a name, its parts and the home IP do; a regex entry is skipped"
exit $fails
fi
[ $# -eq 2 ] || { echo "usage: $0 <identity.local> <salt file> | --self-test" >&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'
@ -17,9 +29,16 @@ for raw in open(lst):
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):
# a PATH entry (the owner's home path, a folder under it) names the owner only in its distinctive segment (the login); the generic
# path words (users, home, desktop, projects, ...) are ordinary words any served page may carry (9 October 2026, 09:36 UK: the build
# page's "at desktop width" was refused), so only the segments outside the generic set are hashed
GENERIC = {'users', 'home', 'desktop', 'projects', 'library', 'application', 'support', 'config', 'tmp', 'var', 'srv', 'root', 'fleet',
'downloads', 'documents', 'private', 'opt', 'usr', 'local', 'bin', 'etc', 'mnt', 'volumes', 'data', 'builds', 'logs', 'out', 'run'}
toks = re.findall(r"[A-Za-z0-9][A-Za-z0-9._-]*", lit)
if '/' in lit or lit.startswith('~'): toks = [t for t in toks if t.lower() not in GENERIC]
for tok in toks:
t = tok.lower().strip('.-')
if t: out.add(hmac.new(salt, t.encode(), hashlib.sha256).hexdigest()); n += 1
if t and t not in GENERIC: 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)

View file

@ -740,6 +740,19 @@
},
"island": "none: every row proved a fixture on a rented pod; no row read a devnet"
},
"model:tv-04": {
"command": "the TV-04 security-budget model: docs/plans/igneum-2.0-master/token-value/phase0/tv-04 (the generator and its tests on build-9; budget.csv, emission.csv, blocked.csv regenerate byte-identical), a reproducible cash-flow model of the ratified rules D01, D03, D04 (the external-job rate unratified), D05 and VR-05",
"box_class": "build-9 (a model run, no GPU)",
"fixtures": [
"F0"
],
"cases": [
"TV-04"
],
"coverage": {
"TV-04": "partial: the model computes each role's budget from the ratified rules; the verdict waits on the independent panel filling the role costs and declaring the viable and collapse cells; no price figure"
}
},
"model:tv-d02-emission": {
"command": "python3 tools/token-value/d02/test_d02.py && python3 tools/token-value/d02/d02_emission.py --check docs/plans/igneum-2.0-master/token-value/phase0/d02 (build-3, tools/token-value/d02/run_on_box.sh generate|crosscheck)",
"box_class": "build box, CPU only (build-3)",

View file

@ -127,15 +127,31 @@ function record(reg, map, batch) {
...(missing.length ? { blocked_on: missing, reason: `INT-17: missing ${missing.join(', ')}; never PASS without them` } : {}) };
if (cell.network_label) c.evidence_record.network_label = cell.network_label;
if (!c.evidence_record.network_label && (status === 'PASS' || status === 'FAIL') && method !== 'static' && ISLAND_RE.test(JSON.stringify([c.evidence_record.release_identity?.network_object, c.evidence_record.evidence, c.evidence_record.note]))) c.evidence_record.network_label = ISLAND_LABEL;
// one record per (case, cell, run) (9 October 2026, 09:4x UK, the same-work hand's class: a second run on the same cell had replaced
// the first run's record and dropped its evidence from evidence_path). The latest run sits under the cell's own key; an older run's
// record moves to "<cell>@<run_id>" and keeps counting; the same run_id replayed overwrites its own record; "supersedes": [run_id, ...]
// on the cell or the batch drops the named older records on that cell (a rerun after a fix, a FAIL replaced by its retest), so an
// older FAIL stands until a batch supersedes it by name.
const supersedes = new Set([...(Array.isArray(cell.supersedes) ? cell.supersedes : cell.supersedes ? [cell.supersedes] : []), ...(Array.isArray(batch.supersedes) ? batch.supersedes : batch.supersedes ? [batch.supersedes] : [])].map(String));
for (const [k, r] of Object.entries(c.evidence_records)) {
const onCell = k === cell.cell || k.startsWith(`${cell.cell}@`);
if (onCell && r && supersedes.has(String(r.run_id))) delete c.evidence_records[k];
}
const prior = c.evidence_records[cell.cell];
if (prior && prior.run_id && String(prior.run_id) !== String(batch.run_id)) c.evidence_records[`${cell.cell}@${prior.run_id}`] = prior;
for (const [k, r] of Object.entries(c.evidence_records)) if (k.startsWith(`${cell.cell}@`) && String(r.run_id) === String(batch.run_id)) delete c.evidence_records[k]; // the run's own older copy under an @ key
c.evidence_records[cell.cell] = c.evidence_record;
// a lifted legacy 'record' entry that carries only a no-harness reason (no run) is not a run: it never counts in the combined
// decision and is dropped once a real cell lands (8 October 2026, 21:5x UK: R2-F03-R01 read NOT RUN on master beside its PASS cell)
for (const [k, r] of Object.entries(c.evidence_records)) if (k !== cell.cell && !r.run_id && !r.evidence && r.reason) delete c.evidence_records[k];
const decs = Object.values(c.evidence_records).filter((r) => r.run_id || r.evidence || r.decision === 'BLOCKED').map((r) => r.decision);
// the latest run on each cell is that cell's word; an older run's record (the "<cell>@<run_id>" keys) stays as evidence and votes only
// when it is a FAIL, which stands until a batch supersedes it by name
const voters = Object.entries(c.evidence_records).filter(([k, r]) => !k.includes('@') || r.decision === 'FAIL').map(([, r]) => r);
const decs = voters.filter((r) => r.run_id || r.evidence || r.decision === 'BLOCKED').map((r) => r.decision);
const combined = decs.includes('FAIL') ? 'FAIL' : decs.includes('BLOCKED') ? 'BLOCKED' : decs.every((d) => d === 'PASS') ? 'PASS' : 'NOT RUN';
c.run_status = combined; c.run_id = batch.run_id; c.updated = now;
c.evidence_path = [...new Set(Object.values(c.evidence_records).map((r) => r.evidence).filter(Boolean))].join('; ');
if (combined !== 'NOT RUN') delete c.in_progress_since; else if (decs.some(() => true) && Object.values(c.evidence_records).some((r) => r.in_progress)) c.in_progress_since = c.in_progress_since || now;
if (combined !== 'NOT RUN') delete c.in_progress_since; else if (decs.some(() => true) && voters.some((r) => r.in_progress)) c.in_progress_since = c.in_progress_since || now;
const ap = cell.approvals || batch.approvals || {}; c.approvals = { scope_approved: ap.scope_approved ?? c.approvals?.scope_approved ?? null, implementation_complete: ap.implementation_complete ?? c.approvals?.implementation_complete ?? null, evidence_reproduced: ap.evidence_reproduced ?? c.approvals?.evidence_reproduced ?? null, claim_authorised: ap.claim_authorised ?? c.approvals?.claim_authorised ?? null };
touched.push(id);
}
@ -172,7 +188,7 @@ if (args.includes('--self-test')) {
fs.mkdirSync(`${d}/dir`); const relDir = path.relative(ROOT, `${d}/dir`); let badDir = '';
try { record(reg, map, { run_id: 'x', manifest_sha: 'abc', method: 'native', cells: [{ cell: 'pow', status: 'FAIL', evidence: relDir }] }); } catch (e) { badDir = String(e.message); }
if (!/is a directory/.test(badDir)) { console.log(`self-test failed: a directory cited as evidence was accepted: ${badDir}`); fails = 1; }
fs.writeFileSync(`${d}/dir/f.log`, 'x'); let okFile = true; try { record(reg, map, { run_id: 'x', manifest_sha: 'abc', method: 'native', cells: [{ cell: 'pow', status: 'FAIL', evidence: `${relDir}/f.log` }] }); } catch { okFile = false; }
fs.writeFileSync(`${d}/dir/f.log`, 'x'); let okFile = true; try { record(reg, map, { run_id: 'x', manifest_sha: 'abc', method: 'native', cells: [{ cell: 'pow', status: 'NOT RUN', evidence: `${relDir}/f.log` }] }); } catch { okFile = false; }
if (!okFile) { console.log('self-test failed: a tree file that exists was refused as evidence'); fails = 1; }
process.env.TEST_RECORD_NO_TREE = '1';
if (!badStatus) { console.log('self-test failed: a status outside the vocabulary was accepted'); fails = 1; }
@ -180,6 +196,17 @@ if (args.includes('--self-test')) {
if (!badMethod) { console.log('self-test failed: a batch with no method was accepted (methods are never conflated)'); fails = 1; }
const regO = { cases: [{ id: 'O1', method: 'Automated', accept: 'a', run_status: 'RUNNING', updated: 't', evidence_record: { cell: 'suite:x' } }, { id: 'O2', method: 'Automated', accept: 'b', run_status: 'DEFERRED' }] }; normalize(regO);
if (!(regO.cases[0].run_status === 'NOT RUN' && regO.cases[0].in_progress_since === 't' && regO.cases[0].evidence_record.method === 'native' && regO.cases[1].run_status === 'NOT RUN' && /deferred/.test(regO.cases[1].deferral_note))) { console.log(`self-test failed: normalize: ${JSON.stringify(regO)}`); fails = 1; }
// records per run: two runs on one cell both count; the same run replayed overwrites its own; supersedes drops a named older run
const regR = { cases: [{ id: 'R1', method: 'Automated', accept: 'a' }] }; const mapR = { cells: { rc: { command: 'x', box_class: 'b', fixtures: [], cases: ['R1'] } }, not_run: {} };
record(regR, mapR, { run_id: 'run-a', manifest_sha: 'm', method: 'native', cells: [{ cell: 'rc', status: 'FAIL', evidence: '/e/a.log' }] });
record(regR, mapR, { run_id: 'run-b', manifest_sha: 'm', method: 'native', cells: [{ cell: 'rc', status: 'PASS', evidence: '/e/b.log' }] });
const kR = Object.keys(regR.cases[0].evidence_records).sort().join();
if (!(kR === 'rc,rc@run-a' && regR.cases[0].run_status === 'FAIL' && /a\.log/.test(regR.cases[0].evidence_path) && /b\.log/.test(regR.cases[0].evidence_path))) { console.log(`self-test failed: a second run on a cell dropped the first: ${kR} ${regR.cases[0].run_status} ${regR.cases[0].evidence_path}`); fails = 1; }
record(regR, mapR, { run_id: 'run-b', manifest_sha: 'm', method: 'native', cells: [{ cell: 'rc', status: 'PASS', evidence: '/e/b2.log' }] });
if (!(Object.keys(regR.cases[0].evidence_records).length === 2 && regR.cases[0].evidence_records.rc.evidence === '/e/b2.log')) { console.log('self-test failed: the same run replayed did not overwrite its own record'); fails = 1; }
record(regR, mapR, { run_id: 'run-c', manifest_sha: 'm', method: 'native', supersedes: ['run-a'], cells: [{ cell: 'rc', status: 'PASS', evidence: '/e/c.log' }] });
const kR2 = Object.keys(regR.cases[0].evidence_records).sort().join();
if (!(kR2 === 'rc,rc@run-b' && regR.cases[0].run_status === 'PASS' && !/a\.log/.test(regR.cases[0].evidence_path))) { console.log(`self-test failed: supersedes did not drop the named FAIL run: ${kR2} ${regR.cases[0].run_status}`); fails = 1; }
// the island label: a record on the 2.0 devnet after the cut takes the label; one before it, or off the devnet, does not; a cell may carry it
const regI = { cases: [
{ id: 'I1', method: 'Automated', accept: 'a', run_status: 'PASS', evidence_records: { x: { decision: 'PASS', at: '2026-10-08T21:00:00Z', release_identity: { network_object: 'igneum-devnet-4, chain id 4465' }, evidence: '/e' } } },
@ -199,7 +226,7 @@ if (args.includes('--self-test')) {
if (!(regL.cases[0].run_status === 'PASS' && !('record' in regL.cases[0].evidence_records))) { console.log(`self-test failed: a lifted reason-only record kept a PASS cell at NOT RUN or survived beside it: ${JSON.stringify(regL.cases[0].evidence_records)}`); fails = 1; }
record(reg, map, { run_id: 'r1p', manifest_sha: 'abc', method: 'native', cells: [{ cell: 'pow', status: 'PASS', evidence: '/e/pow.log' }] });
if (acceptSnapshot(reg) !== before) { console.log('self-test failed: a record changed an accept text'); fails = 1; }
if (!(touched.length === 1 && reg.cases[0].run_status === 'PASS' && reg.cases[0].run_id === 'r1p' && reg.cases[0].evidence_record.manifest_sha === 'abc' && reg.cases[0].evidence_path === '/e/pow.log' && reg.cases[0].updated)) { console.log(`self-test failed: the run was not written to the mapped case's live fields: ${JSON.stringify(reg.cases[0])}`); fails = 1; }
if (!(touched.length === 1 && reg.cases[0].run_status === 'PASS' && reg.cases[0].run_id === 'r1p' && reg.cases[0].evidence_record.manifest_sha === 'abc' && reg.cases[0].evidence_path.split('; ').includes('/e/pow.log') && reg.cases[0].updated)) { console.log(`self-test failed: the run was not written to the mapped case's live fields: ${JSON.stringify(reg.cases[0])}`); fails = 1; }
if (!(reg.cases[1].run_status === 'NOT RUN' && /corpus/.test(reg.cases[1].evidence_record.reason))) { console.log('self-test failed: an unmapped Automated case did not read NOT RUN with its reason'); fails = 1; }
if (reg.cases[0].run_status !== 'PASS') { console.log('self-test failed: the PASS after the RUNNING pass did not land'); fails = 1; }
const stamp1 = reg.cases[1].updated; record(reg, map, { run_id: 'r1b', manifest_sha: 'abc', evidence_dir: '/e', method: 'native', cells: [{ cell: 'pow', status: 'PASS', evidence: '/e/pow.log' }] });
@ -243,7 +270,7 @@ if (args.includes('--self-test')) {
let threw = false; try { record(reg, map, { run_id: 'r2', manifest_sha: 'x', method: 'native', cells: [{ cell: 'ghost', status: 'PASS' }] }); } catch { threw = true; }
if (!threw) { console.log('self-test failed: a batch naming a cell not in the map was accepted'); fails = 1; }
fs.rmSync(d, { recursive: true, force: true });
if (!fails) console.log('self-test passed: a complete map checks; an unknown case id and an unmapped Automated case are refused; a run batch writes run_status, run_id, evidence_path, updated and the evidence record to the mapped cases only, leaves every accept text byte-identical, gives an unmapped Automated case NOT RUN with its reason and a manual case nothing; a batch naming an unknown cell is refused; --note appends a dated note to a suite and never touches an accept text; an unchanged NOT RUN row is not re-stamped; a cell with a missing prerequisite is BLOCKED, never PASS (INT-17); a cut batch needs the binary on a box, the commit string read back and the kit ISA clean line; a cell may narrow its write to named cases; the decision vocabulary is exactly NOT RUN, BLOCKED, FAIL, PASS with RUNNING read as in progress; every record carries the p.139 fields and the four approvals, never inferred; several cells on one case keep every record and combine the decision');
if (!fails) console.log('self-test passed: records are kept per (case, cell, run): the latest run is the word of its cell, an older run stays as evidence and an older FAIL stands until superseded by name, the same run replayed overwrites itself; a complete map checks; an unknown case id and an unmapped Automated case are refused; a run batch writes run_status, run_id, evidence_path, updated and the evidence record to the mapped cases only, leaves every accept text byte-identical, gives an unmapped Automated case NOT RUN with its reason and a manual case nothing; a batch naming an unknown cell is refused; --note appends a dated note to a suite and never touches an accept text; an unchanged NOT RUN row is not re-stamped; a cell with a missing prerequisite is BLOCKED, never PASS (INT-17); a cut batch needs the binary on a box, the commit string read back and the kit ISA clean line; a cell may narrow its write to named cases; the decision vocabulary is exactly NOT RUN, BLOCKED, FAIL, PASS with RUNNING read as in progress; every record carries the p.139 fields and the four approvals, never inferred; several cells on one case keep every record and combine the decision');
process.exit(fails);
}
const reg = load(REG); const map = load(MAP);

View file

@ -92,7 +92,7 @@ if (args.includes('--check')) {
if (args.includes('--write')) {
merge(reg, vr); merge(reg, tv); mergeDecisions(reg, decisions); const n = mapReasons(map, tv);
fs.writeFileSync(REG, JSON.stringify(reg, null, 2) + '\n'); fs.writeFileSync(MAP, JSON.stringify(map, null, 2) + '\n');
console.log(`token-value-suite: VR written (${vr.tests.length} rules), TV written (${tv.tests.length} gates), decisions ${decisions.length} (UNAPPROVED); ${n} NOT RUN reasons in the map`);
console.log(`token-value-suite: VR written (${vr.tests.length} rules), TV written (${tv.tests.length} gates), decisions ${decisions.length} (${(reg.decisions || []).map((x) => x.status).filter((v, i, a) => a.indexOf(v) === i).join(', ')}); ${n} NOT RUN reasons in the map`);
process.exit(0);
}
console.error('usage: token-value-suite.mjs --file <rules-and-gates.json> [--write | --check] | --self-test'); process.exit(2);

View file

@ -62,7 +62,7 @@
.cores i.hot::after { animation: flicker 1.3s ease-in-out infinite alternate; }
@keyframes flicker { from { filter: brightness(.85); } to { filter: brightness(1.15); } }
.corelabel { display: flex; justify-content: space-between; flex-wrap: wrap; gap: 2px 12px; font-family: var(--mono); font-size: 10px; color: var(--muted); padding: 6px 18px 0; letter-spacing: 0.08em; text-transform: uppercase; }
/* the five gauges on one row at desktop width and a clean stack on a phone: flex with growth, so a wrapped tile fills its
/* the five gauges on one row at full width and a clean stack on a phone: flex with growth, so a wrapped tile fills its
row and no empty cell is ever drawn (8 October 2026: BUILD SLOTS sat alone beside a grey strip at widths between the grid's breakpoints) */
.gauges { display: flex; flex-wrap: wrap; gap: 1px; background: var(--line); border-top: 1px solid var(--line); margin-top: 14px; position: relative; z-index: 1; }
.gauges .g { flex: 1 1 150px; min-width: 0; }
@ -191,7 +191,7 @@
<h2>Recently done <span>click a row for the closing lines</span></h2>
<div class="tl" id="done"></div>
<h2>Headline timings <span>what the box does against the Mac and PC 1 on the same tree</span></h2>
<h2>Headline timings <span>what the box does against the Mac and the first rig on the same tree</span></h2>
<div class="head3" id="headline"></div>
<h2>Analytics <span id="an-sub"></span></h2>
@ -218,7 +218,7 @@ const tone = (pct, warn = 70, bad = 90) => pct >= bad ? 'bad' : pct >= warn ? 'w
// one card per entry of boxes[] in the merged workers.json (merge-workers.mjs on build-1, every 20 s); no per-box feed map (8 October 2026:
// the old three-entry map drew build-1 to build-3 only while the merge carried nine boxes)
const STALE_S = 120;
const BOX_NOTES = { 'igneum-build-3': 'down since 16:40 UK, Hetzner switch fault' };
const BOX_NOTES = { 'igneum-build-3': 'down since 16:40 UK, a switch fault at the host' };
const PROVISIONING = 'provisioning, first build logged when the sources land';
function boxState(b) { // live | down | provisioning, with the line the cards print
const age = b && b.collected_at ? (Date.now() - Date.parse(b.collected_at)) / 1000 : null;
@ -309,14 +309,14 @@ function renderCrew() {
const st = boxState(bx);
if (st.kind === 'down') { cards.push(`<div class="w"><div class="top"><div><div class="card">${esc(bx.name)}</div><div class="meta">build server</div></div>${pill('down', 'error')}</div><div class="doing">${esc(st.note)}</div></div>`); continue; }
if (st.kind === 'provisioning' && !st.live) { cards.push(`<div class="w"><div class="top"><div><div class="card">${esc(bx && bx.name || 'build server')}</div><div class="meta">build server</div></div>${pill('provisioning', 'queued')}</div><div class="doing">${esc(st.note)}</div></div>`); continue; }
if (bx && bx.cores) cards.push(`<div class="w"><div class="top"><div><div class="card">${esc(bx.name)}</div><div class="meta">Hetzner, ${bx.cores} threads, ${esc(fmtBytes((bx.mem && bx.mem.total_kb || 0) * 1024))}, RAID 1 NVMe</div></div>${pill(bx.running && bx.running.length ? 'building' : jobsSummary(bx) ? 'busy' : 'idle', bx.running && bx.running.length ? 'running' : '')}</div><div class="doing">${bx.running && bx.running.length ? bx.running.map(r => esc(`${r.worktree || '?'}: ${kindLabel(r.kind)}`)).join('<br>') : (st.kind === 'provisioning' ? esc(st.note) : 'Slot free. The next build-remote.sh or cross-remote.sh routed here takes it.')}</div>${slotBar(bx.slots, bx.slots ? bx.slots.count : 1)}<div class="foot"><span>${bx.recent ? bx.recent.length : 0} builds logged</span><span>${esc(ago(bx.collected_at))}</span></div></div>`);
if (bx && bx.cores) cards.push(`<div class="w"><div class="top"><div><div class="card">${esc(bx.name)}</div><div class="meta">dedicated box, ${bx.cores} threads, ${esc(fmtBytes((bx.mem && bx.mem.total_kb || 0) * 1024))}, RAID 1 NVMe</div></div>${pill(bx.running && bx.running.length ? 'building' : jobsSummary(bx) ? 'busy' : 'idle', bx.running && bx.running.length ? 'running' : '')}</div><div class="doing">${bx.running && bx.running.length ? bx.running.map(r => esc(`${r.worktree || '?'}: ${kindLabel(r.kind)}`)).join('<br>') : (st.kind === 'provisioning' ? esc(st.note) : 'Slot free. The next build-remote.sh or cross-remote.sh routed here takes it.')}</div>${slotBar(bx.slots, bx.slots ? bx.slots.count : 1)}<div class="foot"><span>${bx.recent ? bx.recent.length : 0} builds logged</span><span>${esc(ago(bx.collected_at))}</span></div></div>`);
else cards.push(`<div class="w"><div class="top"><div><div class="card">${esc(bx && bx.name || 'build server')}</div><div class="meta">build server</div></div>${pill('unreachable', 'error')}</div><div class="doing">${esc(bx && bx.source && bx.source.error || 'no facts from this box')}</div></div>`);
}
if (mac) {
const held = mac.slots.held || [], runs = held.filter(h => /^run-/.test(h.slot)), builds = held.filter(h => /^build-/.test(h.slot)), meas = held.filter(h => h.slot === 'measure');
const doing = held.length ? held.map(h => `${esc(h.slot)}: ${esc((h.worktree ? h.worktree + ' ' : '') + (h.command || h.label || ''))}`.slice(0, 140)).join('<br>') : MAC_COPY;
cards.push(`<div class="w"><div class="top"><div><div class="card">${esc(mac.name)}</div><div class="meta">this MacBook, ${mac.build_slots} build slot${mac.build_slots === 1 ? '' : 's'}, 3 run slots</div></div>${pill(meas.length ? 'measuring' : builds.length ? 'building' : runs.length ? 'running' : 'idle', held.length ? 'running' : '')}</div><div class="doing">${doing}</div><div class="slots">${['build-0', 'build-1', 'build-2', 'run-0', 'run-1', 'run-2', 'measure'].map(nm => { const h = held.find(x => x.slot === nm); return `<i class="${h ? (nm === 'measure' ? 'measure' : nm.startsWith('run') ? 'run' : 'held') : ''}" title="${esc(nm)}${h ? ': ' + esc(h.label) : ': free'}"></i>`; }).join('')}</div><div class="foot"><span>${mac.queue.length ? mac.queue.length + ' waiting for a slot' : 'nobody waiting'}</span><span>${esc(ago(mac.collected_at))}</span></div></div>`);
} else cards.push(`<div class="w"><div class="top"><div><div class="card">MacBook-Pro</div><div class="meta">this MacBook</div></div>${pill('no push', 'error')}</div><div class="doing">${MAC_COPY}</div></div>`);
cards.push(`<div class="w"><div class="top"><div><div class="card">${esc(mac.name)}</div><div class="meta">this Mac, ${mac.build_slots} build slot${mac.build_slots === 1 ? '' : 's'}, 3 run slots</div></div>${pill(meas.length ? 'measuring' : builds.length ? 'building' : runs.length ? 'running' : 'idle', held.length ? 'running' : '')}</div><div class="doing">${doing}</div><div class="slots">${['build-0', 'build-1', 'build-2', 'run-0', 'run-1', 'run-2', 'measure'].map(nm => { const h = held.find(x => x.slot === nm); return `<i class="${h ? (nm === 'measure' ? 'measure' : nm.startsWith('run') ? 'run' : 'held') : ''}" title="${esc(nm)}${h ? ': ' + esc(h.label) : ': free'}"></i>`; }).join('')}</div><div class="foot"><span>${mac.queue.length ? mac.queue.length + ' waiting for a slot' : 'nobody waiting'}</span><span>${esc(ago(mac.collected_at))}</span></div></div>`);
} else cards.push(`<div class="w"><div class="top"><div><div class="card">the macOS build host</div><div class="meta">this Mac</div></div>${pill('no push', 'error')}</div><div class="doing">${MAC_COPY}</div></div>`);
{ const m = miniLive(); const held = m && m.slots && m.slots.held || [];
cards.push(`<div class="w"><div class="top"><div><div class="card">${MINI.name}</div><div class="meta">${MINI.label}</div></div>${pill(!m ? 'no report' : held.length ? 'building' : 'idle', !m ? 'queued' : held.length ? 'running' : '')}</div><div class="doing">${!m ? 'no report yet' : (esc(miniMinerLine(m)) + '<br>') + (held.length ? held.map(h => esc(`${h.slot}: ${h.worktree || h.label || ''}`)).join('<br>') : 'macOS binaries build here from tonight; slot free.')}</div>${m && m.slots ? slotBar(m.slots, m.slots.count || 1) : ''}<div class="foot"><span>${m ? `${(m.recent || []).length} builds logged` : 'its collector pushes to build-1'}</span><span>${m ? esc(ago(m.collected_at)) : ''}</span></div></div>`); }
const pcsAt = D.pcs && D.pcs.collected_at ? Date.parse(D.pcs.collected_at) : null; const pcsAge = pcsAt ? Math.round((Date.now() - pcsAt) / 1000) : null;
@ -335,7 +335,7 @@ function renderCrew() {
const pcAgeText = pcAge === null ? 'report age unknown' : `report ${fmtDurShort(pcAge)} old${pcAge > 600 ? ', STALE' : ''}${pc.source === 'intake' ? ', from the PC' : ''}`;
cards.push(`<div class="w"><div class="top"><div><div class="card">${esc(pc.name)}</div><div class="meta">${esc(pc.machine || pc.id)} · ${esc(pc.role)} · <span ${pcAge !== null && pcAge > 600 ? 'style="color:var(--warn)"' : ''}>${esc(pcAgeText)}</span></div></div>${pill(r ? 'running' : pc.queue.length ? 'queued' : 'idle', r ? 'running' : pc.queue.length ? 'queued' : '')}</div><div class="doing">${pcReportLine(pc) ? pcReportLine(pc) + '<br>' : ''}${r ? `${esc(r.kind)} ${esc(r.job)}${r.title ? '<br>' + esc(r.title) : ''}${r.stage ? `<br><span class="pill">stage ${esc(r.stage)}</span>` : ''}` : pc.queue.length ? `Next: ${esc(pc.queue[0].kind)} ${esc(pc.queue[0].job)}${pc.queue[0].title ? ', ' + esc(pc.queue[0].title) : ''}` : esc(pc.note || 'idle on jobs; the relay polls every 10 min')}</div><div class="foot"><span>${pc.recent.length} reports kept</span><span>${pc.last_report_at ? 'last report ' + esc(ago(pc.last_report_at)) : 'no report in 7 days'}</span></div></div>`);
}
if (!pcs.length) cards.push(`<div class="w"><div class="top"><div><div class="card">PC 1 and PC 2</div><div class="meta">relay jobs</div></div>${pill('no data', 'error')}</div><div class="doing">${esc(D.sources && D.sources.pcs && D.sources.pcs.error || 'the Mac pusher reads the relay intake; nothing has arrived')}</div></div>`);
if (!pcs.length) cards.push(`<div class="w"><div class="top"><div><div class="card">rig 1 and rig 2</div><div class="meta">relay jobs</div></div>${pill('no data', 'error')}</div><div class="doing">${esc(D.sources && D.sources.pcs && D.sources.pcs.error || 'the Mac pusher reads the relay intake; nothing has arrived')}</div></div>`);
$('crew').innerHTML = cards.join('');
}
@ -416,7 +416,7 @@ function renderHeadline() {
const bx = boxesOf(D).filter(b => b.headline); const rows = bx.length ? bx.flatMap(b => headline(b.headline).map(r => ({ ...r, label: bx.length > 1 ? `${r.label} · ${b.name}` : r.label }))) : headline(D.headline);
$('headline').innerHTML = rows.map(r => {
const max = Math.max(r.box_s || 0, r.mac_s || 0, r.pc_s || 0, 1);
return `<div class="h3"><div class="l">${esc(r.label)}</div><div class="v">${r.box_s === null ? '<span style="color:var(--muted);font-size:14px">not measured yet</span>' : esc(fmtDur(r.box_s)) + '<small>box</small>'}</div><div class="cmp">${r.mac_s !== null ? `Mac <b>${esc(fmtDur(r.mac_s))}</b>${r.speedup ? ` (${r.speedup}× slower)` : ''}` : 'Mac <b>not measured on this tree</b>'}${r.pc_s !== null ? ` · PC 1 <b>${esc(fmtDur(r.pc_s))}</b>` : ''}</div>${r.box_s !== null ? `<div class="meter"><i style="width:${(r.box_s / max * 100).toFixed(1)}%"></i>${r.mac_s !== null ? `<em style="left:${(r.mac_s / max * 100).toFixed(1)}%" title="Mac"></em>` : ''}${r.pc_s !== null ? `<em style="left:${(r.pc_s / max * 100).toFixed(1)}%;background:var(--cool)" title="PC 1"></em>` : ''}</div>` : ''}<div class="s">${esc(r.note || r.what)}${r.measured_at ? ` · measured ${t(r.measured_at, true)}` : ''}</div></div>`;
return `<div class="h3"><div class="l">${esc(r.label)}</div><div class="v">${r.box_s === null ? '<span style="color:var(--muted);font-size:14px">not measured yet</span>' : esc(fmtDur(r.box_s)) + '<small>box</small>'}</div><div class="cmp">${r.mac_s !== null ? `Mac <b>${esc(fmtDur(r.mac_s))}</b>${r.speedup ? ` (${r.speedup}× slower)` : ''}` : 'Mac <b>not measured on this tree</b>'}${r.pc_s !== null ? ` · rig 1 <b>${esc(fmtDur(r.pc_s))}</b>` : ''}</div>${r.box_s !== null ? `<div class="meter"><i style="width:${(r.box_s / max * 100).toFixed(1)}%"></i>${r.mac_s !== null ? `<em style="left:${(r.mac_s / max * 100).toFixed(1)}%" title="Mac"></em>` : ''}${r.pc_s !== null ? `<em style="left:${(r.pc_s / max * 100).toFixed(1)}%;background:var(--cool)" title="rig 1"></em>` : ''}</div>` : ''}<div class="s">${esc(r.note || r.what)}${r.measured_at ? ` · measured ${t(r.measured_at, true)}` : ''}</div></div>`;
}).join('');
}