From ec792ec9508110bfbe0c77acf475b3d4719f0fbd Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Thu, 8 Oct 2026 15:23:59 +0000 Subject: [PATCH 01/36] class v6 kit (8 October 2026): the Metal hosts size the dataset by the ds55 words and items defines (packbench and the worker's pack path; a power-of-two pack reads unchanged: hl-v6-fold f6c34aa6e87bf211 on both builds), the kit's box script for the all-together pack and its known-failed partner, the runner's script switch Co-Authored-By: Claude Fable 5.1 --- proto-metal/main.swift | 4 +- proto-metal/packbench.swift | 10 +++- tools/class-v5/kits-remote.sh | 8 +-- tools/class-v5/kits-v6-on-box.sh | 95 ++++++++++++++++++++++++++++++++ 4 files changed, 109 insertions(+), 8 deletions(-) create mode 100755 tools/class-v5/kits-v6-on-box.sh diff --git a/proto-metal/main.swift b/proto-metal/main.swift index 6c7e48823..e7c55d127 100644 --- a/proto-metal/main.swift +++ b/proto-metal/main.swift @@ -3162,7 +3162,9 @@ func servePackDataset(_ gpu: GPU, _ store: ServeStore, dayHex: String, dir: Stri guard let fillFn = lib.makeFunction(name: "igneum_cache_fill"), let buildFn = lib.makeFunction(name: "igneum_build") else { throw refuse("memhard.metal lacks igneum_cache_fill or igneum_build") } let fillPipe = try gpu.device.makeComputePipelineState(function: fillFn) let buildPipe = try gpu.device.makeComputePipelineState(function: buildFn) - let words = 1 << datasetLog2 + // ds55 (the class v6 research packs, 8 October 2026): a non-power-of-two dataset carries IGNEUM_DATASET_WORDS (the + // buffer's size) and IGNEUM_DATASET_ITEMS beside IGNEUM_DATASET_LOG2 (the floor); the kernel text maps (src * words) >> 32 + let words = defineU64("IGNEUM_DATASET_WORDS").map { Int($0) } ?? (1 << datasetLog2) // Class v5 (docs/design/class-v5-stored-state.md, 7 October 2026): the window's state leaves, leaves.bin beside program.h // (IGNEUM_STATE_LEAVES leaves of 16 little-endian words), checked against the pack's count and FNV-1a 64 // (IGNEUM_STATE_LEAVES_FNV64) and bound as buffer 2 of igneum_build with the count in buffer 3 (packbench.swift's shape, diff --git a/proto-metal/packbench.swift b/proto-metal/packbench.swift index a382ddd7d..6e8a8fa88 100644 --- a/proto-metal/packbench.swift +++ b/proto-metal/packbench.swift @@ -93,8 +93,12 @@ let cacheFnvWant = hex64(vj["cache_fnv1a64"] as! String) let hotFnvWant: UInt64? = (vj["hot_fnv1a64"] as? String).map(hex64) guard let device = MTLCreateSystemDefaultDevice(), let queue = device.makeCommandQueue() else { fail("no Metal device") } -let words = 1 << datasetLog2 -let mask = UInt32(words - 1) +// ds55 (the class v6 research packs, 8 October 2026): a non-power-of-two dataset carries IGNEUM_DATASET_WORDS and +// IGNEUM_DATASET_ITEMS beside IGNEUM_DATASET_LOG2 (the floor); the buffer is sized by the words, the items by ITEMS, +// and the kernel text maps an address as (src * words) >> 32, so the mask is the kernel's business, not this host's +let datasetWordsDefine = defineU64("IGNEUM_DATASET_WORDS") +let words = datasetWordsDefine.map { Int($0) } ?? (1 << datasetLog2) +let mask = UInt32(truncatingIfNeeded: (1 << datasetLog2) - 1) let cacheWords = 1 << cacheLog2 func compile(_ file: String) -> MTLLibrary { @@ -138,7 +142,7 @@ func fnv1a64(_ p: UnsafeRawPointer, _ n: Int) -> UInt64 { for i in 0.. -- bash -# tools/class-v5/kits-on-box.sh ...` with the label "v5 kit". +# tools/class-v5/${KITS_BOX_SCRIPT:-kits-on-box.sh} ...` with the label "v5 kit". set -euo pipefail HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" BS_TOOL=class-v5-kits @@ -34,9 +34,9 @@ ZIP="/srv/artefacts/packs/packs-ca3-v5-$STAMP.zip" bs_toolchain_check bs_sync_sources bs_log "sources at $WT (commit $BS_SHA on $BS_BRANCH); building the class v5 kits on box $BOX" -# the body runs from a script FILE at the worktree's mirror checkout (tools/class-v5/kits-on-box.sh, carried by the commit), never +# the body runs from a script FILE at the worktree's mirror checkout (tools/class-v5/${KITS_BOX_SCRIPT:-kits-on-box.sh}, carried by the commit), never # an inline string: main's rule of 7 October 2026, 21:33 BST (no rm, find -delete or truncation inside a bash -c string) -CMD="cd '$WT' && bash tools/class-v5/kits-on-box.sh '$STAMP' '$SKIP_EMU'" +CMD="cd '$WT' && bash tools/class-v5/${KITS_BOX_SCRIPT:-kits-on-box.sh} '$STAMP' '$SKIP_EMU'" set +e BR_KIND=build BR_COMMAND="class v5 kits (packfile-test, emu --check v5, Linux and Windows workers, kit zip)" BR_TARGET="x86_64-linux+windows" BR_ARTEFACTS="" \ bs_remote_run "$WT" "$BS_WT class-v5 kits" "$CMD" 2>&1 | tee "/tmp/v5-kits-$STAMP.log" | grep -E '^(STEP|FAIL|KIT|BIN|LOGS|check PASS|self-test|packfile-test|emu:| v5|build-remote: RESULT)' diff --git a/tools/class-v5/kits-v6-on-box.sh b/tools/class-v5/kits-v6-on-box.sh new file mode 100755 index 000000000..49d00e663 --- /dev/null +++ b/tools/class-v5/kits-v6-on-box.sh @@ -0,0 +1,95 @@ +#!/usr/bin/env bash +# The class v5 kit build as it runs ON igneum-build-1 (called by tools/class-v5/kits-remote.sh through the build-server +# library's remote runner, from the worktree's mirror checkout, so this file travels with the commit). A script file by +# path, never an inline string: main's rule of 7 October 2026, 21:33 BST (no rm, find -delete or truncation inside a +# `bash -c` string; tools/ci/inline-rm-check.sh). What it does, in order: the pack loader test with the class v5 cases, +# the Linux and Windows builds of the two one-click workers, the CPU emulation's --check on the class v5 pack, then the +# kit zip at /srv/artefacts/packs/packs-ca3-v5-.zip with SHA256SUMS. Logs land in /srv/builds/_log/v5-class/kits-. +# bash tools/class-v5/kits-on-box.sh (cwd = the worktree root on the box) +set -u +STAMP="${1:?stamp}"; SKIP_EMU="${2:-0}" +ZIP="/srv/artefacts/packs/packs-class-v6-$STAMP.zip" +LOGDIR="/srv/builds/_log/v5-class/kits-$STAMP" +T=$(mktemp -d /tmp/v5-kits.XXXXXX); S=$T/stage; mkdir -p "$S/bin/linux" "$S/bin/windows" "$S/src" "$S/packs" "$S/tools" "$LOGDIR" +rc=0 +step() { echo "STEP $1 $(date -u +%H:%M:%SZ)"; } +fail() { echo "FAIL $1"; rc=1; } +finish() { cp "$T"/*.log "$LOGDIR"/ 2>/dev/null; echo "LOGS $LOGDIR"; rm -rf "$T"; } +# class v6 (8 October 2026, the coordinator's order): the all-together pack and its known-failed partner come from the hash +# lane's tgz files on build-1 (V6_ALL and V6_PARTNER, default hl-v6-all and hl-v6-foldrw), extracted beside the stage; +# the emulation check runs pack A = the all pack against pack B = the partner, and the two ids must differ +V6_ALL="${V6_ALL:-hl-v6-all}"; V6_PARTNER="${V6_PARTNER:-hl-v6-foldrw}" +PK=$T/v6packs; mkdir -p "$PK" +for p in "$V6_ALL" "$V6_PARTNER"; do tar -xzf "/srv/artefacts/packs/$p.tgz" -C "$PK" 2>/dev/null || { echo "FAIL no pack tgz /srv/artefacts/packs/$p.tgz"; exit 1; }; done +rm -rf "$PK"/._* "$PK"/*/._* 2>/dev/null +V5="$PK/$V6_ALL"; V6P="$PK/$V6_PARTNER" +echo "PACKS $V6_ALL id $(grep -oE 'IGNEUM_PROGRAM_ID 0x[0-9a-f]+' "$V5/program.h" | awk '{print $2}') | $V6_PARTNER id $(grep -oE 'IGNEUM_PROGRAM_ID 0x[0-9a-f]+' "$V6P/program.h" | awk '{print $2}')" +[ "$(grep -oE 'IGNEUM_PROGRAM_ID 0x[0-9a-f]+' "$V5/program.h")" != "$(grep -oE 'IGNEUM_PROGRAM_ID 0x[0-9a-f]+' "$V6P/program.h")" ] || { echo "FAIL the all pack and its partner carry one id"; exit 1; } +step packfile-test +cc -std=c99 -Wall -Wextra -Wno-unused-function -O1 -o "$T/packfile-test" proto-cuda/nvrtc/emu/packfile-test.c && "$T/packfile-test" proto-cuda/packs/igneum-devnet-v4-epoch0 "$V5" > "$T/packfile-test.log" 2>&1 || fail "packfile-test ($(tail -1 "$T/packfile-test.log"))" +grep -E '^(FAIL| v5 pack)' "$T/packfile-test.log"; grep -c '^ok' "$T/packfile-test.log" | sed 's/^/packfile-test ok lines /' +step linux-opencl-worker +gcc -std=c99 -O2 -Wall -Wextra -Wno-stringop-truncation -Wno-format-truncation -DIGNEUM_CL_DYNAMIC -DCL_TARGET_OPENCL_VERSION=120 -I proto-cuda/packs/igneum-devnet-v4-epoch0 -DIGNEUM_KERNEL_PATH='"kernel_bound.cl"' -o "$S/bin/linux/igneum-worker-opencl" proto-opencl/host.c -ldl -lpthread 2> "$T/cl-linux.log" || { fail "linux opencl worker"; head -20 "$T/cl-linux.log"; } +step linux-cuda-worker +g++ -std=c++17 -O2 -Wall -Wextra -I proto-cuda/nvrtc -I /usr/local/cuda/include -o "$S/bin/linux/igneum-worker-cuda" proto-cuda/nvrtc/worker.cpp -ldl -lpthread 2> "$T/cuda-linux.log" || { fail "linux cuda worker"; head -20 "$T/cuda-linux.log"; } +step windows-cuda-worker +x86_64-w64-mingw32-g++ -std=c++17 -O2 -Wall -Wextra -static -I proto-cuda/nvrtc -I /usr/local/cuda/include -o "$S/bin/windows/igneum-worker-cuda.exe" proto-cuda/nvrtc/worker.cpp 2> "$T/cuda-win.log" && x86_64-w64-mingw32-strip "$S/bin/windows/igneum-worker-cuda.exe" || { fail "windows cuda worker"; head -20 "$T/cuda-win.log"; } +step windows-opencl-worker +# the Khronos CL headers alone (never -I /usr/include: that puts glibc's stdint.h ahead of mingw's) +mkdir -p "$T/inc" && cp -r /usr/include/CL "$T/inc/" +x86_64-w64-mingw32-gcc -std=c99 -O2 -Wall -Wextra -Wno-stringop-truncation -Wno-format-truncation -static -DIGNEUM_CL_DYNAMIC -DCL_TARGET_OPENCL_VERSION=120 -I "$T/inc" -I proto-cuda/packs/igneum-devnet-v4-epoch0 -DIGNEUM_KERNEL_PATH='"kernel_bound.cl"' -o "$S/bin/windows/igneum-worker-opencl.exe" proto-opencl/host.c 2> "$T/cl-win.log" && x86_64-w64-mingw32-strip "$S/bin/windows/igneum-worker-opencl.exe" || { fail "windows opencl worker"; head -20 "$T/cl-win.log"; } +if [ "$SKIP_EMU" = 0 ]; then + step emu-check-v5 + # the CPU emulation (proto-cuda/nvrtc/emu/test.sh's build) with pack A = the class v5 pack and pack B = the v4 control + E=$T/emu; mkdir -p "$E" + emu_kernel() { { echo '#include '; echo '#include '; echo "namespace $2 {"; sed -E 's/([A-Za-z_0-9]+)<<<([^,]+), ([^>]+)>>>\(/emu_launch(\1, \2, \3, /' "$1/$3.cu"; echo "}"; } > "$E/$3_$2.cpp"; g++ -std=c++17 -O2 -w -I proto-cuda/emu -I "$1" -c "$E/$3_$2.cpp" -o "$E/$3_$2.o"; } + emu_kernel "$V5" emu_pack_a kernel && emu_kernel "$V5" emu_pack_a kernel_bound && emu_kernel "$V6P" emu_pack_b kernel && emu_kernel "$V6P" emu_pack_b kernel_bound \ + && g++ -std=c++17 -O2 -Wall -Wextra -DIGNEUM_EMU -I proto-cuda/nvrtc -I /usr/local/cuda/include -c proto-cuda/nvrtc/worker.cpp -o "$E/worker.o" \ + && g++ -std=c++17 -O2 -Wall -Wextra -DIGNEUM_EMU -DIGNEUM_EMU_TWO_PACKS -I proto-cuda/nvrtc -I proto-cuda/emu -I /usr/local/cuda/include -c proto-cuda/nvrtc/emu/emu_backend.cpp -o "$E/emu_backend.o" \ + && g++ -std=c++17 -O2 -w -I proto-cuda/emu -c proto-cuda/emu/shim.cpp -o "$E/shim.o" \ + && g++ -o "$E/igneum-worker-cuda-emu" "$E"/*.o -pthread 2> "$T/emu-build.log" || { fail "emu build"; head -30 "$T/emu-build.log"; } + if [ -x "$E/igneum-worker-cuda-emu" ]; then + ( IGNEUM_EMU_PACK="$V5" IGNEUM_EMU_PACK2="$V6P" timeout 1500 nice -n 10 "$E/igneum-worker-cuda-emu" --check --pack "$V5" > "$T/emu-check.log" 2>&1 ) || fail "emu --check on the class v5 pack (rc $?)" + grep -E '^check PASS|self-test|FAIL|error' "$T/emu-check.log" | cut -c1-400 + fi +fi +if [ "$rc" != 0 ]; then echo "KIT not written: a step failed (rc $rc)"; finish; exit 1; fi +step stage +for p in "$V6_ALL" "$V6_PARTNER"; do mkdir -p "$S/packs/$p"; cp "$PK/$p"/* "$S/packs/$p/"; done +cp proto-cuda/nvrtc/worker.cpp proto-cuda/nvrtc/packfile.h proto-cuda/nvrtc/cuda_api.h proto-opencl/host.c proto-opencl/cl_dynamic.h proto-newpow/class-v5/bench.cu proto-newpow/class-v5/run.sh proto-metal/packbench.swift "$S/src/" +cp tools/class-v5/fleet-cuda-v5-bench.sh tools/class-v5/pc1-amd-v5-bench.ps1 "$S/tools/" +cat > "$S/README.txt" <<'R' +packs-class-v6: the class v6 kit (Igneum, 8 October 2026; docs/design/class-v5-stored-state.md section 0, the class v6 row): the all-together pack and its known-failed partner +packs/v5-dn3-epoch0 the first class v5 pack: Devnet 3 epoch 0, program id e5a4ac5978462156, 11 state leaves (leaves.bin, 704 B) under + state root 7e37a9fb19b154d32daf5bf30a50d339a75029fbc9eec9ea20e95439dba5a311, cache FNV-1a 64 7334fa46e5d972eb + expected fingerprint of the 2^24 outputs at base nonce 0: 82b19cbde8557ea5 (Metal, M5 Max, 18:07:09Z) on every platform +packs/v5-genesis the string-seed class v5 pack over the devnet's 93 leaves; packs/v4-genesis the class v4 control (sub-version 3) +bin/linux igneum-worker-cuda (NVRTC, libcuda + libnvrtc.so.12 at run time), igneum-worker-opencl (libOpenCL.so.1 at run time) +bin/windows igneum-worker-cuda.exe (nvcuda.dll + nvrtc64 at run time), igneum-worker-opencl.exe (OpenCL.dll at run time) +Every worker reads a class v5 pack's leaves.bin, checks it against the pack's IGNEUM_STATE_LEAVES_FNV64, uploads it for igneum_build and +frees it after the build; a pack without its leaves builds nothing. Self-test: cache head, last line and FNV; dataset head, last word and +64 samples; 96 vector lanes. Bench: igneum-worker-cuda --bench --pack packs/v5-dn3-epoch0 --batch-log2 24 (fleet-cuda-v5-bench.sh); +igneum-worker-opencl --bench-pack --pack packs/v5-dn3-epoch0 --batch-log2 24 --device (pc1-amd-v5-bench.ps1); src/bench.cu with nvcc. +Intel: not measured tonight (7 October 2026); no Arc B580 sits on PC 1 or PC 2 and the only Arc path needs a driver click, which no PC job +may raise; the card's holder and a click-free driver path are owed. The OpenCL worker takes the Intel device by index the same way. +R +( cd "$S" && find . -type f ! -name SHA256SUMS | sort | xargs sha256sum > SHA256SUMS ) +mkdir -p /srv/artefacts/packs +python3 - "$S" "$ZIP" <<'PY' +import os, sys, zipfile +stage, out = sys.argv[1], sys.argv[2] +with zipfile.ZipFile(out, 'w', zipfile.ZIP_DEFLATED) as z: + for dp, dn, fn in os.walk(stage): + dn.sort() + for f in sorted(fn): + p = os.path.join(dp, f); rel = os.path.relpath(p, stage) + zi = zipfile.ZipInfo(rel, date_time=(2026, 10, 7, 0, 0, 0)); zi.compress_type = zipfile.ZIP_DEFLATED + zi.external_attr = (0o755 if rel.startswith('bin/') or rel.endswith('.sh') else 0o644) << 16 + with open(p, 'rb') as fh: z.writestr(zi, fh.read()) +PY +sha256sum "$ZIP" | cut -c1-64 > "$ZIP.sha256" +echo "KIT $ZIP bytes $(stat -c %s "$ZIP") files $(python3 -c "import zipfile,sys; print(len(zipfile.ZipFile(sys.argv[1]).namelist()))" "$ZIP")" +echo "KIT sha256 $(cat "$ZIP.sha256")" +for b in "$S"/bin/linux/* "$S"/bin/windows/*; do echo "BIN $(basename "$(dirname "$b")")/$(basename "$b") $(stat -c %s "$b") bytes sha256 $(sha256sum "$b" | cut -c1-64)"; done +finish +exit 0 From 0d775880e7d9e131e62ed4d534131cd39daaf909 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Thu, 8 Oct 2026 16:07:38 +0000 Subject: [PATCH 02/36] class v6 kit: the PC job scripts (the AMD and the Arc hosts on the partner hl-v6-foldrw, expected 5a6ad122a71a888f; the all pack's OpenCL refusal line as the record) Co-Authored-By: Claude Fable 5.1 --- tools/class-v5/arc-v6-bench.ps1 | 92 +++++++++++++++++++++++++++++++++ tools/class-v5/pc1-v6-bench.ps1 | 85 ++++++++++++++++++++++++++++++ 2 files changed, 177 insertions(+) create mode 100644 tools/class-v5/arc-v6-bench.ps1 create mode 100644 tools/class-v5/pc1-v6-bench.ps1 diff --git a/tools/class-v5/arc-v6-bench.ps1 b/tools/class-v5/arc-v6-bench.ps1 new file mode 100644 index 000000000..b48feeeb4 --- /dev/null +++ b/tools/class-v5/arc-v6-bench.ps1 @@ -0,0 +1,92 @@ +# Class v6 kit (8 October 2026, the coordinator's order): the arc job of the v5 script with the class v6 packs: hl-v6-foldrw (the +# known-failed partner; expected fingerprint 5a6ad122a71a888f, the Mac's Metal and Apple OpenCL reading) and hl-v6-all (the +# all-together pack, id 9d40978601a7df2a, whose OpenCL text is a refusal stub tonight: the host's refusal line is the record, +# not a fingerprint). Kit fetch job fetch-class-v6-kit-20261008 = packs-class-v6-20261008T160432Z.zip (sha256 2c56bd06...). +# Class v5 kit bench on the Intel Arc B580 (7 October 2026, 23:5x UK, main's word: the B580 is the eGPU of the second PC, +# so the Intel fingerprint runs there through the hash lane's job queue as a lock-free, non-elevated, quiet job, never beside +# an install or a build; the page names no PC): tools/class-v5/pc1-amd-v5-bench.ps1 with the device +# match on the Intel OpenCL platform (Arc / B580) instead of gfx1201; everything else identical (the v5-dn3-epoch0 pack, +# the v4-genesis control, RESULT lines, SUMMARY {json}). Expected fingerprint 5a6ad122a71a888f. +# Class v5 kit bench on PC 1's RX 9070 XT (7 October 2026, docs/design/class-v5-stored-state.md section 13, "the kit: +# OpenCL (AMD)"): the kit's igneum-worker-opencl.exe (THIS tree's proto-opencl/host.c with the class v5 leaf upload: +# igneum_build(ds, cache, leaves, nLeaves, nItems), the leaves of leaves.bin checked against the pack's FNV-1a 64 first) +# runs --bench-pack on the first class v5 pack, proto-cuda/packs-ca3-v5/v5-dn3-epoch0 (program id e5a4ac5978462156, 11 +# leaves under state root 7e37a9fb..., cache FNV 7334fa46e5d972eb), on the gfx1201 device. Expected: the self-test +# PASS line (cache head, last line and FNV; dataset head, word [268435455] and 64 samples; 96 of 96 vector lanes) and the +# fingerprint of the 2^24 outputs at base nonce 0 equal to the Metal reading, 5a6ad122a71a888f (the M5 Max, 7 October +# 2026, 18:07:09Z). The v4-genesis control pack runs after it so the run has a known class v4 row beside the v5 row. +# Beside the miners (a correctness and fingerprint gate; the rate row is labelled loaded when the card mines): no card is +# switched, nothing is posted to the installed app, nothing is built on the PC. Published by the Counter ASIC coordinator +# only (the PC 1 queue is its); the kit is fetch job $kitId. Every result line starts with RESULT; SUMMARY {json} ends it. +$ErrorActionPreference = 'Continue' +$jobName = 'arc-v6-bench' +$kitId = $env:IGNEUM_V5_KIT_ID; if (-not $kitId) { $kitId = 'fetch-class-v6-kit-20261008' } +$expected = '5a6ad122a71a888f' +$started = Get-Date +function Stamp { (Get-Date).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ') } +function Summary([string] $status, [hashtable] $extra) { + $o = [ordered]@{ job = $jobName; status = $status; duration_s = [int]((Get-Date) - $started).TotalSeconds; finished_at = (Stamp) } + foreach ($k in $extra.Keys) { $o[$k] = $extra[$k] } + 'SUMMARY ' + ($o | ConvertTo-Json -Compress -Depth 4) +} +"RESULT start $(Stamp) job=$jobName machine=$env:COMPUTERNAME app_version=$env:IGNEUM_APP_VERSION expected_fingerprint=$expected" +$jobs = Split-Path $env:IGNEUM_JOB_DIR +$kit = Join-Path $jobs $kitId +if (-not (Test-Path $kit)) { "RESULT error kit missing at $kit (the fetch job $kitId runs first; republish it after any app update)"; Summary 'failed' @{ error = 'kit missing' }; exit 2 } +$exe = Join-Path $kit 'bin\windows\igneum-worker-opencl.exe' +$packs = Join-Path $kit 'packs' +if (-not (Test-Path $exe)) { "RESULT error worker missing at $exe"; Summary 'failed' @{ error = 'worker missing' }; exit 2 } +"RESULT worker kit $exe sha256 $((Get-FileHash -Algorithm SHA256 $exe).Hash.ToLower()) bytes $((Get-Item $exe).Length)" +foreach ($pk in @('hl-v6-foldrw', 'hl-v6-all')) { + $d = Join-Path $packs $pk + if (-not (Test-Path (Join-Path $d 'kernel_bound.cl'))) { "RESULT error pack $pk missing at $d"; Summary 'failed' @{ error = "pack $pk missing" }; exit 2 } + "RESULT pack $pk kernel_bound.cl sha256 $((Get-FileHash -Algorithm SHA256 (Join-Path $d 'kernel_bound.cl')).Hash.ToLower()) program.h sha256 $((Get-FileHash -Algorithm SHA256 (Join-Path $d 'program.h')).Hash.ToLower())" +} +$leaves = Join-Path $packs 'v5-dn3-epoch0\leaves.bin' +if (-not (Test-Path $leaves)) { "RESULT error leaves.bin missing at $leaves (a class v5 pack without its leaves builds nothing)"; Summary 'failed' @{ error = 'leaves missing' }; exit 2 } +"RESULT leaves $leaves bytes $((Get-Item $leaves).Length) sha256 $((Get-FileHash -Algorithm SHA256 $leaves).Hash.ToLower())" +# the OpenCL device index of the 9070 XT (the installed worker's list when present: the app's own indices) +$inst = @("$env:LOCALAPPDATA\Programs\Igneum Miner", "$env:ProgramFiles\Igneum Miner") | Where-Object { Test-Path (Join-Path $_ 'igneum-app.exe') } | Select-Object -First 1 +$listExe = $exe +if ($inst -and (Test-Path (Join-Path $inst 'igneum-worker-opencl.exe'))) { $listExe = Join-Path $inst 'igneum-worker-opencl.exe' } +$list = @(& $listExe --list 2>&1 | ForEach-Object { "$_" }) +$list | ForEach-Object { "RESULT list $_" } +$dev = $null +foreach ($l in $list) { if ($l -match '^\s*\[(\d+)\].*(Intel|Arc|B580)' -and $l -notmatch 'dup') { $dev = [int]$Matches[1]; break } } +if ($null -eq $dev) { "RESULT error no Intel Arc device in --list (the B580 is off the bus or has no OpenCL runtime: the Intel v5 row stays OWED)"; Summary 'failed' @{ error = 'no intel arc' }; exit 2 } +"RESULT device $dev Intel Arc (list from $listExe)" +function Workers { @(Get-CimInstance Win32_Process -Filter "Name = 'igneum-worker-opencl.exe' OR Name = 'igneum-worker-cuda.exe'" -ErrorAction SilentlyContinue | ForEach-Object { "$($_.Name):$($_.ProcessId):[$($_.CommandLine -replace '\s+', ' ')]" }) } +$w = @(Workers) +$loaded = ($w | Where-Object { $_ -match "igneum-worker-opencl.*--device\s+$dev(\s|$)" }).Count -gt 0 +"RESULT workers_before $(Stamp) $($w -join ' ')" +$state = if ($loaded) { 'loaded' } else { 'quiet' } +"RESULT context card_state=$state (a fingerprint gate: the load changes the rate row, never the bytes)" +$rows = @{} +$fpOk = $false +foreach ($pk in @('hl-v6-foldrw', 'hl-v6-all')) { + $d = Join-Path $packs $pk + $t0 = Get-Date + "RESULT bench $pk start $(Stamp) cmd=igneum-worker-opencl.exe --bench-pack --pack $d --device $dev --batch-log2 24 --batches 5" + $out = @(& $exe --bench-pack --pack $d --device $dev --batch-log2 24 --batches 5 2>&1 | ForEach-Object { "$_" }) + $code = $LASTEXITCODE + $secs = [int]((Get-Date) - $t0).TotalSeconds + # the whole stdout, line by line (the 09:36 UK run kept one line per pack and lost the host's exchange, kernel, + # rotate-fold and build-log lines, which the diagnosis needed) + foreach ($l in $out) { "RESULT bench $pk out $l" } + $res = $out | Where-Object { $_ -match '^RESULT ' } | Select-Object -Last 1 + $fp = ''; $mhs = ''; $check = '' + if ($res -match 'fingerprint=([0-9a-f]{16})') { $fp = $Matches[1] } + if ($res -match 'mhs=([0-9.]+)') { $mhs = $Matches[1] } + if ($res -match 'check=(\w+)') { $check = $Matches[1] } + $rows[$pk] = [ordered]@{ exit = $code; seconds = $secs; fingerprint = $fp; mhs = $mhs; check = $check; card_state = $state } + if ($pk -eq 'hl-v6-foldrw') { + $fpOk = ($fp -eq $expected -and $check -eq 'PASS') + "RESULT partner fingerprint=$fp expected=$expected match=$fpOk check=$check mhs=$mhs card_state=$state exit=$code seconds=$secs $(Stamp)" + } else { + # the all pack: on an OpenCL device its text is the refusal stub tonight, so the record is the host's refusal line (no fingerprint, no FAIL of the job) + "RESULT all-pack fingerprint=$fp check=$check mhs=$mhs card_state=$state exit=$code seconds=$secs $(Stamp)" + } +} +"RESULT workers_after $(Stamp) $((@(Workers)) -join ' ')" +Summary $(if ($fpOk) { 'done' } else { 'failed' }) @{ expected = $expected; partner = $rows['hl-v6-foldrw']; all_pack = $rows['hl-v6-all']; device = $dev; kit = $kitId } +exit $(if ($fpOk) { 0 } else { 1 }) diff --git a/tools/class-v5/pc1-v6-bench.ps1 b/tools/class-v5/pc1-v6-bench.ps1 new file mode 100644 index 000000000..45d2282b5 --- /dev/null +++ b/tools/class-v5/pc1-v6-bench.ps1 @@ -0,0 +1,85 @@ +# Class v6 kit (8 October 2026, the coordinator's order): the amd job of the v5 script with the class v6 packs: hl-v6-foldrw (the +# known-failed partner; expected fingerprint 5a6ad122a71a888f, the Mac's Metal and Apple OpenCL reading) and hl-v6-all (the +# all-together pack, id 9d40978601a7df2a, whose OpenCL text is a refusal stub tonight: the host's refusal line is the record, +# not a fingerprint). Kit fetch job fetch-class-v6-kit-20261008 = packs-class-v6-20261008T160432Z.zip (sha256 2c56bd06...). +# Class v5 kit bench on PC 1's RX 9070 XT (7 October 2026, docs/design/class-v5-stored-state.md section 13, "the kit: +# OpenCL (AMD)"): the kit's igneum-worker-opencl.exe (THIS tree's proto-opencl/host.c with the class v5 leaf upload: +# igneum_build(ds, cache, leaves, nLeaves, nItems), the leaves of leaves.bin checked against the pack's FNV-1a 64 first) +# runs --bench-pack on the first class v5 pack, proto-cuda/packs-ca3-v5/v5-dn3-epoch0 (program id e5a4ac5978462156, 11 +# leaves under state root 7e37a9fb..., cache FNV 7334fa46e5d972eb), on the gfx1201 device. Expected: the self-test +# PASS line (cache head, last line and FNV; dataset head, word [268435455] and 64 samples; 96 of 96 vector lanes) and the +# fingerprint of the 2^24 outputs at base nonce 0 equal to the Metal reading, 5a6ad122a71a888f (the M5 Max, 7 October +# 2026, 18:07:09Z). The v4-genesis control pack runs after it so the run has a known class v4 row beside the v5 row. +# Beside the miners (a correctness and fingerprint gate; the rate row is labelled loaded when the card mines): no card is +# switched, nothing is posted to the installed app, nothing is built on the PC. Published by the Counter ASIC coordinator +# only (the PC 1 queue is its); the kit is fetch job $kitId. Every result line starts with RESULT; SUMMARY {json} ends it. +$ErrorActionPreference = 'Continue' +$jobName = 'pc1-v6-bench' +$kitId = $env:IGNEUM_V5_KIT_ID; if (-not $kitId) { $kitId = 'fetch-class-v6-kit-20261008' } +$expected = '5a6ad122a71a888f' +$started = Get-Date +function Stamp { (Get-Date).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ') } +function Summary([string] $status, [hashtable] $extra) { + $o = [ordered]@{ job = $jobName; status = $status; duration_s = [int]((Get-Date) - $started).TotalSeconds; finished_at = (Stamp) } + foreach ($k in $extra.Keys) { $o[$k] = $extra[$k] } + 'SUMMARY ' + ($o | ConvertTo-Json -Compress -Depth 4) +} +"RESULT start $(Stamp) job=$jobName machine=$env:COMPUTERNAME app_version=$env:IGNEUM_APP_VERSION expected_fingerprint=$expected" +$jobs = Split-Path $env:IGNEUM_JOB_DIR +$kit = Join-Path $jobs $kitId +if (-not (Test-Path $kit)) { "RESULT error kit missing at $kit (the fetch job $kitId runs first; republish it after any app update)"; Summary 'failed' @{ error = 'kit missing' }; exit 2 } +$exe = Join-Path $kit 'bin\windows\igneum-worker-opencl.exe' +$packs = Join-Path $kit 'packs' +if (-not (Test-Path $exe)) { "RESULT error worker missing at $exe"; Summary 'failed' @{ error = 'worker missing' }; exit 2 } +"RESULT worker kit $exe sha256 $((Get-FileHash -Algorithm SHA256 $exe).Hash.ToLower()) bytes $((Get-Item $exe).Length)" +foreach ($pk in @('hl-v6-foldrw', 'hl-v6-all')) { + $d = Join-Path $packs $pk + if (-not (Test-Path (Join-Path $d 'kernel_bound.cl'))) { "RESULT error pack $pk missing at $d"; Summary 'failed' @{ error = "pack $pk missing" }; exit 2 } + "RESULT pack $pk kernel_bound.cl sha256 $((Get-FileHash -Algorithm SHA256 (Join-Path $d 'kernel_bound.cl')).Hash.ToLower()) program.h sha256 $((Get-FileHash -Algorithm SHA256 (Join-Path $d 'program.h')).Hash.ToLower())" +} +$leaves = Join-Path $packs 'v5-dn3-epoch0\leaves.bin' +if (-not (Test-Path $leaves)) { "RESULT error leaves.bin missing at $leaves (a class v5 pack without its leaves builds nothing)"; Summary 'failed' @{ error = 'leaves missing' }; exit 2 } +"RESULT leaves $leaves bytes $((Get-Item $leaves).Length) sha256 $((Get-FileHash -Algorithm SHA256 $leaves).Hash.ToLower())" +# the OpenCL device index of the 9070 XT (the installed worker's list when present: the app's own indices) +$inst = @("$env:LOCALAPPDATA\Programs\Igneum Miner", "$env:ProgramFiles\Igneum Miner") | Where-Object { Test-Path (Join-Path $_ 'igneum-app.exe') } | Select-Object -First 1 +$listExe = $exe +if ($inst -and (Test-Path (Join-Path $inst 'igneum-worker-opencl.exe'))) { $listExe = Join-Path $inst 'igneum-worker-opencl.exe' } +$list = @(& $listExe --list 2>&1 | ForEach-Object { "$_" }) +$list | ForEach-Object { "RESULT list $_" } +$dev = $null +foreach ($l in $list) { if ($l -match '^\s*\[(\d+)\].*gfx1201' -and $l -notmatch 'dup') { $dev = [int]$Matches[1]; break } } +if ($null -eq $dev) { "RESULT error no gfx1201 device in --list (the eGPU is off the bus: the AMD v5 row stays OWED)"; Summary 'failed' @{ error = 'no gfx1201' }; exit 2 } +"RESULT device $dev gfx1201 (list from $listExe)" +function Workers { @(Get-CimInstance Win32_Process -Filter "Name = 'igneum-worker-opencl.exe' OR Name = 'igneum-worker-cuda.exe'" -ErrorAction SilentlyContinue | ForEach-Object { "$($_.Name):$($_.ProcessId):[$($_.CommandLine -replace '\s+', ' ')]" }) } +$w = @(Workers) +$loaded = ($w | Where-Object { $_ -match "igneum-worker-opencl.*--device\s+$dev(\s|$)" }).Count -gt 0 +"RESULT workers_before $(Stamp) $($w -join ' ')" +$state = if ($loaded) { 'loaded' } else { 'quiet' } +"RESULT context card_state=$state (a fingerprint gate: the load changes the rate row, never the bytes)" +$rows = @{} +$fpOk = $false +foreach ($pk in @('hl-v6-foldrw', 'hl-v6-all')) { + $d = Join-Path $packs $pk + $t0 = Get-Date + "RESULT bench $pk start $(Stamp) cmd=igneum-worker-opencl.exe --bench-pack --pack $d --device $dev --batch-log2 24 --batches 5" + $out = @(& $exe --bench-pack --pack $d --device $dev --batch-log2 24 --batches 5 2>&1 | ForEach-Object { "$_" }) + $code = $LASTEXITCODE + $secs = [int]((Get-Date) - $t0).TotalSeconds + foreach ($l in $out) { if ($l -match '^(pack |class v5|RESULT |FAIL|error|warm-up)') { "RESULT bench $pk out $l" } } + $res = $out | Where-Object { $_ -match '^RESULT ' } | Select-Object -Last 1 + $fp = ''; $mhs = ''; $check = '' + if ($res -match 'fingerprint=([0-9a-f]{16})') { $fp = $Matches[1] } + if ($res -match 'mhs=([0-9.]+)') { $mhs = $Matches[1] } + if ($res -match 'check=(\w+)') { $check = $Matches[1] } + $rows[$pk] = [ordered]@{ exit = $code; seconds = $secs; fingerprint = $fp; mhs = $mhs; check = $check; card_state = $state } + if ($pk -eq 'hl-v6-foldrw') { + $fpOk = ($fp -eq $expected -and $check -eq 'PASS') + "RESULT partner fingerprint=$fp expected=$expected match=$fpOk check=$check mhs=$mhs card_state=$state exit=$code seconds=$secs $(Stamp)" + } else { + # the all pack: on an OpenCL device its text is the refusal stub tonight, so the record is the host's refusal line (no fingerprint, no FAIL of the job) + "RESULT all-pack fingerprint=$fp check=$check mhs=$mhs card_state=$state exit=$code seconds=$secs $(Stamp)" + } +} +"RESULT workers_after $(Stamp) $((@(Workers)) -join ' ')" +Summary $(if ($fpOk) { 'done' } else { 'failed' }) @{ expected = $expected; partner = $rows['hl-v6-foldrw']; all_pack = $rows['hl-v6-all']; device = $dev; kit = $kitId } +exit $(if ($fpOk) { 0 } else { 1 }) From dbb85ddf450fe77031e994f07ba69dd3f6620aa7 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Thu, 8 Oct 2026 16:22:08 +0000 Subject: [PATCH 03/36] class v6 kit: the PC job scripts expect the CUDA reference 59e6708e46f1e87c on the all pack now that the window's OpenCL text exists (the second zip) Co-Authored-By: Claude Fable 5.1 --- tools/class-v5/arc-v6-bench.ps1 | 10 ++++++---- tools/class-v5/pc1-v6-bench.ps1 | 10 ++++++---- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/tools/class-v5/arc-v6-bench.ps1 b/tools/class-v5/arc-v6-bench.ps1 index b48feeeb4..d3acdb8d3 100644 --- a/tools/class-v5/arc-v6-bench.ps1 +++ b/tools/class-v5/arc-v6-bench.ps1 @@ -1,7 +1,8 @@ # Class v6 kit (8 October 2026, the coordinator's order): the arc job of the v5 script with the class v6 packs: hl-v6-foldrw (the # known-failed partner; expected fingerprint 5a6ad122a71a888f, the Mac's Metal and Apple OpenCL reading) and hl-v6-all (the -# all-together pack, id 9d40978601a7df2a, whose OpenCL text is a refusal stub tonight: the host's refusal line is the record, -# not a fingerprint). Kit fetch job fetch-class-v6-kit-20261008 = packs-class-v6-20261008T160432Z.zip (sha256 2c56bd06...). +# all-together pack, id 9d40978601a7df2a; with the second zip its OpenCL text is the window's real text and the expected +# fingerprint is the CUDA reference 59e6708e46f1e87c; the first zip's stub refused it, that refusal line being that run's record). +# Kit fetch job fetch-class-v6-kit-20261008 = the second zip (packs-class-v6-.zip named in the job's publish line). # Class v5 kit bench on the Intel Arc B580 (7 October 2026, 23:5x UK, main's word: the B580 is the eGPU of the second PC, # so the Intel fingerprint runs there through the hash lane's job queue as a lock-free, non-elevated, quiet job, never beside # an install or a build; the page names no PC): tools/class-v5/pc1-amd-v5-bench.ps1 with the device @@ -83,8 +84,9 @@ foreach ($pk in @('hl-v6-foldrw', 'hl-v6-all')) { $fpOk = ($fp -eq $expected -and $check -eq 'PASS') "RESULT partner fingerprint=$fp expected=$expected match=$fpOk check=$check mhs=$mhs card_state=$state exit=$code seconds=$secs $(Stamp)" } else { - # the all pack: on an OpenCL device its text is the refusal stub tonight, so the record is the host's refusal line (no fingerprint, no FAIL of the job) - "RESULT all-pack fingerprint=$fp check=$check mhs=$mhs card_state=$state exit=$code seconds=$secs $(Stamp)" + # the all pack: with the window's OpenCL text (the second zip) a fingerprint, expected the CUDA reference 59e6708e46f1e87c + $allOk = ($fp -eq '59e6708e46f1e87c' -and $check -eq 'PASS') + "RESULT all-pack fingerprint=$fp expected=59e6708e46f1e87c match=$allOk check=$check mhs=$mhs card_state=$state exit=$code seconds=$secs $(Stamp)" } } "RESULT workers_after $(Stamp) $((@(Workers)) -join ' ')" diff --git a/tools/class-v5/pc1-v6-bench.ps1 b/tools/class-v5/pc1-v6-bench.ps1 index 45d2282b5..524e7f9cf 100644 --- a/tools/class-v5/pc1-v6-bench.ps1 +++ b/tools/class-v5/pc1-v6-bench.ps1 @@ -1,7 +1,8 @@ # Class v6 kit (8 October 2026, the coordinator's order): the amd job of the v5 script with the class v6 packs: hl-v6-foldrw (the # known-failed partner; expected fingerprint 5a6ad122a71a888f, the Mac's Metal and Apple OpenCL reading) and hl-v6-all (the -# all-together pack, id 9d40978601a7df2a, whose OpenCL text is a refusal stub tonight: the host's refusal line is the record, -# not a fingerprint). Kit fetch job fetch-class-v6-kit-20261008 = packs-class-v6-20261008T160432Z.zip (sha256 2c56bd06...). +# all-together pack, id 9d40978601a7df2a; with the second zip its OpenCL text is the window's real text and the expected +# fingerprint is the CUDA reference 59e6708e46f1e87c; the first zip's stub refused it, that refusal line being that run's record). +# Kit fetch job fetch-class-v6-kit-20261008 = the second zip (packs-class-v6-.zip named in the job's publish line). # Class v5 kit bench on PC 1's RX 9070 XT (7 October 2026, docs/design/class-v5-stored-state.md section 13, "the kit: # OpenCL (AMD)"): the kit's igneum-worker-opencl.exe (THIS tree's proto-opencl/host.c with the class v5 leaf upload: # igneum_build(ds, cache, leaves, nLeaves, nItems), the leaves of leaves.bin checked against the pack's FNV-1a 64 first) @@ -76,8 +77,9 @@ foreach ($pk in @('hl-v6-foldrw', 'hl-v6-all')) { $fpOk = ($fp -eq $expected -and $check -eq 'PASS') "RESULT partner fingerprint=$fp expected=$expected match=$fpOk check=$check mhs=$mhs card_state=$state exit=$code seconds=$secs $(Stamp)" } else { - # the all pack: on an OpenCL device its text is the refusal stub tonight, so the record is the host's refusal line (no fingerprint, no FAIL of the job) - "RESULT all-pack fingerprint=$fp check=$check mhs=$mhs card_state=$state exit=$code seconds=$secs $(Stamp)" + # the all pack: with the window's OpenCL text (the second zip) a fingerprint, expected the CUDA reference 59e6708e46f1e87c + $allOk = ($fp -eq '59e6708e46f1e87c' -and $check -eq 'PASS') + "RESULT all-pack fingerprint=$fp expected=59e6708e46f1e87c match=$allOk check=$check mhs=$mhs card_state=$state exit=$code seconds=$secs $(Stamp)" } } "RESULT workers_after $(Stamp) $((@(Workers)) -join ' ')" From 103192ff0842d7cfe5ddf7215fab8eb64aec31bc Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Thu, 8 Oct 2026 17:06:34 +0000 Subject: [PATCH 04/36] class-v6: D2 experiment "layer 8 off" (the coordinator's order, 8 October 2026, 18:12 UK; a research class behind "+nowin"): the era layout's window-layer draw removed, every load site reads the whole dataset (win = 0, off = 0); the stream still consumes the two window draws per instruction so the base program's instructions and the shadow are the class's without the flag; the id carries nowin/; "+nowin" parses in any order with the other suffixes and names back inside +fold/+rw. Test: tests/v6fold.rs nowin_removes_the_window_layer_and_nothing_else. Co-Authored-By: Claude Fable 5.1 --- igneum-pow/src/generator.rs | 29 ++++++++++++++++++++++++++--- igneum-pow/tests/v6fold.rs | 30 ++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 3 deletions(-) diff --git a/igneum-pow/src/generator.rs b/igneum-pow/src/generator.rs index 61fe4874b..5a4deab00 100644 --- a/igneum-pow/src/generator.rs +++ b/igneum-pow/src/generator.rs @@ -255,6 +255,11 @@ pub struct LoadClass { /// optimiser split [`NONLOAD_WEIGHTS_RW`] (sum 83, `or` never drawn); 2 the census lane's neighbouring table /// [`NONLOAD_WEIGHTS_RW2`] (sum 75). The draw rolls against the table's own sum ([`LoadClass::nonload_weights`]). pub rw: u8, + /// D2 experiment "layer 8 off" (the coordinator's order, 8 October 2026, 18:12 UK; a research class behind `+nowin`): + /// the era layout's window-layer draw is removed, every load site reads the whole dataset (`win = 0`, `off = 0`). + /// The program stream still consumes the two window draws per instruction, so the base program's instructions are + /// the class's without the flag; only the windows move. `false` for every other class. + pub nowin: bool, /// The 64-register window (the hash lane's reg64 measurement, 8 October 2026, a research class behind `+reg64` /// and `--reg64`): each lane holds 64 live 32-bit registers. r0..r7 are seeded as today, r8..r63 derived from them /// (`r[k] = r[k & 7] * 0x9E3779B9 + k`); the 64 drawn instructions run twice per iteration in an interleaved @@ -455,13 +460,13 @@ impl LoadClass { impl LoadClass { /// Generator version 2 as adopted on 4 October 2026: 16 loads of one word. The lottery hash. pub const V2: LoadClass = - LoadClass { mix: [100, 0, 0], load_slots: LOAD_SLOTS as u8, scratch: None, scratch_kb: 0, mixer_mult: 1, growth: false, era: None, hot: None, derive_len: 0, shadow: None, state: false, wide8: false, fold: false, rw: 0, reg64: false, reg64_chain: false }; + LoadClass { mix: [100, 0, 0], load_slots: LOAD_SLOTS as u8, scratch: None, scratch_kb: 0, mixer_mult: 1, growth: false, era: None, hot: None, derive_len: 0, shadow: None, state: false, wide8: false, fold: false, rw: 0, nowin: false, reg64: false, reg64_chain: false }; /// The construction decided for program class v3 on 5 October 2026 (Counter ASIC 2.0, `docs/plans/mixer-x4.md`): /// version 2 loads (16 slots of one word, no scratch, no width roll, so the program stream is version 2's), the /// mixer applied 4 times per round, and the cache growth rule. Name "mx4". pub const MX4: LoadClass = - LoadClass { mix: [100, 0, 0], load_slots: LOAD_SLOTS as u8, scratch: None, scratch_kb: 0, mixer_mult: 4, growth: true, era: None, hot: None, derive_len: 0, shadow: None, state: false, wide8: false, fold: false, rw: 0, reg64: false, reg64_chain: false }; + LoadClass { mix: [100, 0, 0], load_slots: LOAD_SLOTS as u8, scratch: None, scratch_kb: 0, mixer_mult: 4, growth: true, era: None, hot: None, derive_len: 0, shadow: None, state: false, wide8: false, fold: false, rw: 0, nowin: false, reg64: false, reg64_chain: false }; /// The era class over `base` (`docs/plans/era-layout.md`): the parameters drawn by [`era_draw`]; when `allowed` /// has more than one width the drawn width becomes the class mix (every load that width), otherwise the base @@ -634,6 +639,11 @@ impl LoadClass { LoadClass { rw, ..self } } + /// D2 "layer 8 off": the class with the window-layer draw removed (every load site reads the whole dataset). + pub fn with_nowin(self) -> LoadClass { + LoadClass { nowin: true, ..self } + } + /// The non-load op table this class draws from, in draw order, and its sum (the roll's range). The plain table /// for every class without the re-weight flag, so their streams are byte for byte what they were. pub fn nonload_weights(&self) -> (&'static [(Op, u64); 10], u64) { @@ -677,6 +687,10 @@ impl LoadClass { pub fn parse(s: &str) -> Option { // class v6 lane 1: "+fold" (the index fold) and "+rw" / "+rw2" (the re-weight table) over // any class, in any order, outermost of all + // D2 "layer 8 off": "+nowin" over any class, in any order with the other suffixes + if let Some(base) = s.strip_suffix("+nowin") { + return Some(LoadClass::parse(base)?.with_nowin()); + } if let Some(base) = s.strip_suffix("+fold") { return Some(LoadClass::parse(base)?.with_fold()); } @@ -829,6 +843,10 @@ impl LoadClass { if self.fold { return format!("{}+fold", LoadClass { fold: false, ..*self }.name()); } + if self.nowin { + // D2 "layer 8 off": "+nowin" sits inside "+fold" and "+rw" and outside "+reg64" and "+state" + return format!("{}+nowin", LoadClass { nowin: false, ..*self }.name()); + } if self.reg64 { // "+reg64" / "+reg64c": the 64-register window is a suffix on any class, outermost let base = LoadClass { reg64: false, reg64_chain: false, ..*self }.name(); @@ -1458,6 +1476,10 @@ pub fn program_id_class_recipe(generator: u32, seed: &[u32; 8], attempt: u32, cl // class v6 lane 1: the index fold moves every era load address r.lit(b"fold/"); } + if class.nowin { + // D2 "layer 8 off": the window layer is part of the construction + r.lit(b"nowin/"); + } if class.rw != 0 { // class v6 lane 1: the re-weight table moves the op draw r.lit(b"rw/"); @@ -1723,7 +1745,8 @@ pub fn candidate_from_words_class( let (win, off) = if class.era.is_some() { let k = rng.below(3) as u8; let o = (rng.next() as u32 & ((1u32 << k) - 1)) as u8; - if op == Op::Load { + // D2 "layer 8 off": the draws are consumed (the stream is the class's) and every site reads the whole dataset + if op == Op::Load && !class.nowin { (k, o) } else { (0, 0) diff --git a/igneum-pow/tests/v6fold.rs b/igneum-pow/tests/v6fold.rs index 956ae5b86..a97f81768 100644 --- a/igneum-pow/tests/v6fold.rs +++ b/igneum-pow/tests/v6fold.rs @@ -182,6 +182,36 @@ fn class_v6_all_flags_parse_name_and_id() { assert!(p.class.era.unwrap().fold); } +/// 1c. D2 "layer 8 off" (8 October 2026): "+nowin" parses in any order and names back inside "+fold"/"+rw"; the draw +/// keeps every instruction of the class without the flag and sets every load site's window to the whole dataset; +/// the id moves; the era and the stride do not. +#[test] +fn nowin_removes_the_window_layer_and_nothing_else() { + let c = LoadClass::parse("mx8+sh256x27+state+nowin+fold+rw").unwrap(); + assert!(c.nowin && c.fold && c.rw == 1 && c.state); + assert_eq!(c.name(), "mx8+sh256x27+state+nowin+fold+rw"); + assert_eq!(LoadClass::parse("mx8+sh256x27+state+fold+rw+nowin"), Some(c)); + assert_eq!(LoadClass::parse("mx8+sh256x27+state+reg64c+nowin").unwrap().name(), "mx8+sh256x27+state+reg64c+nowin"); + assert!(!V5_CLASS.nowin); + let era = f8_bytes("era", 4); + let seed = f8_bytes("program", 4); + let plain = candidate_class("p4-attack-f8", &seed, 0, LoadClass::era(V5_CLASS, &era, &V3_ALLOWED)); + let off = candidate_class("p4-attack-f8", &seed, 0, LoadClass::era(V5_CLASS.with_nowin(), &era, &V3_ALLOWED)); + assert_ne!(plain.program_id(), off.program_id(), "the id carries the flag"); + assert_eq!(plain.instrs.len(), off.instrs.len()); + let mut windows_plain = 0; + for (a, b) in plain.instrs.iter().zip(off.instrs.iter()) { + assert_eq!((a.op, a.dst, a.src, a.src2, a.imm, a.imm2, a.rot, a.bit, a.mask, a.width), (b.op, b.dst, b.src, b.src2, b.imm, b.imm2, b.rot, b.bit, b.mask, b.width), "the instruction is the class's without the flag"); + assert_eq!((b.win, b.off), (0, 0), "every site reads the whole dataset"); + if a.win != 0 { + windows_plain += 1; + } + } + assert!(windows_plain > 0, "the plain draw has at least one shrunk window on this seed"); + assert_eq!(plain.shadow, off.shadow); + assert_eq!(plain.class.era.map(|e| EraParams { fold: e.fold, ..e }), off.class.era.map(|e| EraParams { fold: e.fold, ..e }), "the era draw is untouched"); +} + /// 2. The fold's form: `y = x * M; y ^= y >> 16; y = rotl(y, R)`, and nothing else moves. The plain era's stride is /// `rotl(x * M, R)` byte for byte. #[test] From 3a4b7de3dcfa69a3e57bf5e7942a7843d2ee821b Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Thu, 8 Oct 2026 17:09:29 +0000 Subject: [PATCH 05/36] class v6 kit: the PC job scripts check each kit pack's own leaves.bin (the class v5 script's one-pack check stopped the 7600 job before the device list) and the AMD match is the RX 7600's gfx1102 Co-Authored-By: Claude Fable 5.1 --- tools/class-v5/arc-v6-bench.ps1 | 10 +++++++--- tools/class-v5/pc1-v6-bench.ps1 | 16 ++++++++++------ 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/tools/class-v5/arc-v6-bench.ps1 b/tools/class-v5/arc-v6-bench.ps1 index d3acdb8d3..0b59bbc2e 100644 --- a/tools/class-v5/arc-v6-bench.ps1 +++ b/tools/class-v5/arc-v6-bench.ps1 @@ -43,9 +43,13 @@ foreach ($pk in @('hl-v6-foldrw', 'hl-v6-all')) { if (-not (Test-Path (Join-Path $d 'kernel_bound.cl'))) { "RESULT error pack $pk missing at $d"; Summary 'failed' @{ error = "pack $pk missing" }; exit 2 } "RESULT pack $pk kernel_bound.cl sha256 $((Get-FileHash -Algorithm SHA256 (Join-Path $d 'kernel_bound.cl')).Hash.ToLower()) program.h sha256 $((Get-FileHash -Algorithm SHA256 (Join-Path $d 'program.h')).Hash.ToLower())" } -$leaves = Join-Path $packs 'v5-dn3-epoch0\leaves.bin' -if (-not (Test-Path $leaves)) { "RESULT error leaves.bin missing at $leaves (a class v5 pack without its leaves builds nothing)"; Summary 'failed' @{ error = 'leaves missing' }; exit 2 } -"RESULT leaves $leaves bytes $((Get-Item $leaves).Length) sha256 $((Get-FileHash -Algorithm SHA256 $leaves).Hash.ToLower())" +# the class v6 kit's packs each carry their own leaves.bin (the class v5 script checked one pack by name; the 18:01 UK run on +# PC 1 stopped on that name before the device list) +foreach ($lp in @('hl-v6-foldrw', 'hl-v6-all')) { + $leaves = Join-Path $packs ($lp + '\leaves.bin') + if (-not (Test-Path $leaves)) { "RESULT error leaves.bin missing at $leaves (a class v5 pack without its leaves builds nothing)"; Summary 'failed' @{ error = 'leaves missing'; pack = $lp }; exit 2 } + "RESULT leaves $lp $((Get-Item $leaves).Length) bytes sha256 $((Get-FileHash -Algorithm SHA256 $leaves).Hash.ToLower())" +} # the OpenCL device index of the 9070 XT (the installed worker's list when present: the app's own indices) $inst = @("$env:LOCALAPPDATA\Programs\Igneum Miner", "$env:ProgramFiles\Igneum Miner") | Where-Object { Test-Path (Join-Path $_ 'igneum-app.exe') } | Select-Object -First 1 $listExe = $exe diff --git a/tools/class-v5/pc1-v6-bench.ps1 b/tools/class-v5/pc1-v6-bench.ps1 index 524e7f9cf..c8ab7fbc5 100644 --- a/tools/class-v5/pc1-v6-bench.ps1 +++ b/tools/class-v5/pc1-v6-bench.ps1 @@ -38,9 +38,13 @@ foreach ($pk in @('hl-v6-foldrw', 'hl-v6-all')) { if (-not (Test-Path (Join-Path $d 'kernel_bound.cl'))) { "RESULT error pack $pk missing at $d"; Summary 'failed' @{ error = "pack $pk missing" }; exit 2 } "RESULT pack $pk kernel_bound.cl sha256 $((Get-FileHash -Algorithm SHA256 (Join-Path $d 'kernel_bound.cl')).Hash.ToLower()) program.h sha256 $((Get-FileHash -Algorithm SHA256 (Join-Path $d 'program.h')).Hash.ToLower())" } -$leaves = Join-Path $packs 'v5-dn3-epoch0\leaves.bin' -if (-not (Test-Path $leaves)) { "RESULT error leaves.bin missing at $leaves (a class v5 pack without its leaves builds nothing)"; Summary 'failed' @{ error = 'leaves missing' }; exit 2 } -"RESULT leaves $leaves bytes $((Get-Item $leaves).Length) sha256 $((Get-FileHash -Algorithm SHA256 $leaves).Hash.ToLower())" +# the class v6 kit's packs each carry their own leaves.bin (the class v5 script checked one pack by name; the 18:01 UK run on +# PC 1 stopped on that name before the device list) +foreach ($lp in @('hl-v6-foldrw', 'hl-v6-all')) { + $leaves = Join-Path $packs ($lp + '\leaves.bin') + if (-not (Test-Path $leaves)) { "RESULT error leaves.bin missing at $leaves (a class v5 pack without its leaves builds nothing)"; Summary 'failed' @{ error = 'leaves missing'; pack = $lp }; exit 2 } + "RESULT leaves $lp $((Get-Item $leaves).Length) bytes sha256 $((Get-FileHash -Algorithm SHA256 $leaves).Hash.ToLower())" +} # the OpenCL device index of the 9070 XT (the installed worker's list when present: the app's own indices) $inst = @("$env:LOCALAPPDATA\Programs\Igneum Miner", "$env:ProgramFiles\Igneum Miner") | Where-Object { Test-Path (Join-Path $_ 'igneum-app.exe') } | Select-Object -First 1 $listExe = $exe @@ -48,9 +52,9 @@ if ($inst -and (Test-Path (Join-Path $inst 'igneum-worker-opencl.exe'))) { $list $list = @(& $listExe --list 2>&1 | ForEach-Object { "$_" }) $list | ForEach-Object { "RESULT list $_" } $dev = $null -foreach ($l in $list) { if ($l -match '^\s*\[(\d+)\].*gfx1201' -and $l -notmatch 'dup') { $dev = [int]$Matches[1]; break } } -if ($null -eq $dev) { "RESULT error no gfx1201 device in --list (the eGPU is off the bus: the AMD v5 row stays OWED)"; Summary 'failed' @{ error = 'no gfx1201' }; exit 2 } -"RESULT device $dev gfx1201 (list from $listExe)" +foreach ($l in $list) { if ($l -match '^\s*\[(\d+)\].*gfx1102' -and $l -notmatch 'dup') { $dev = [int]$Matches[1]; break } } +if ($null -eq $dev) { "RESULT error no gfx1102 device in --list (the RX 7600 is off the bus: the AMD class v6 row stays OWED)"; Summary 'failed' @{ error = 'no gfx1102' }; exit 2 } +"RESULT device $dev gfx1102 (list from $listExe)" function Workers { @(Get-CimInstance Win32_Process -Filter "Name = 'igneum-worker-opencl.exe' OR Name = 'igneum-worker-cuda.exe'" -ErrorAction SilentlyContinue | ForEach-Object { "$($_.Name):$($_.ProcessId):[$($_.CommandLine -replace '\s+', ' ')]" }) } $w = @(Workers) $loaded = ($w | Where-Object { $_ -match "igneum-worker-opencl.*--device\s+$dev(\s|$)" }).Count -gt 0 From 7cdb70cc722177e8eac82d967ba78d0e566a4132 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Thu, 8 Oct 2026 17:16:16 +0000 Subject: [PATCH 06/36] class-v6: the v4 source rule sets the nowin flag aside as it does fold and rw (the known-failed test read a different load source under +nowin) Co-Authored-By: Claude Fable 5.1 --- igneum-pow/src/generator.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/igneum-pow/src/generator.rs b/igneum-pow/src/generator.rs index 5a4deab00..39cde7c3a 100644 --- a/igneum-pow/src/generator.rs +++ b/igneum-pow/src/generator.rs @@ -1674,7 +1674,7 @@ pub fn candidate_from_words_class( // class v6 lane 1: the index fold and the re-weight table are set aside too (the address path and the table are not // the shape; a +fold or +rw program draws its sources under the same rule) let source_rule_v4 = matches!(class.shadow, Some(ShadowClass { instrs: V4_SHADOW_INSTRS, .. })) - && LoadClass { era: None, shadow: None, state: false, fold: false, rw: 0, ..class } == LoadClass { shadow: None, ..V4_CLASS }; + && LoadClass { era: None, shadow: None, state: false, fold: false, rw: 0, nowin: false, ..class } == LoadClass { shadow: None, ..V4_CLASS }; // the op table and the roll's range: the plain table at 75 for every class without the re-weight flag let (weights, weights_sum) = class.nonload_weights(); let mut fresh = [false; 8]; From 61f2cc36ba57d210f0c5ea34d06522348794fba4 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Thu, 8 Oct 2026 17:39:45 +0000 Subject: [PATCH 07/36] POW-01 and POW-02, the malformed-input half: igneum-pow/tests/fuzz_parsers.rs (10,000 mutations each of the class string, the hex and era strings, the IGSD1 state stream; a panic fails) and proto-cuda/nvrtc/packfile-fuzz.c (10,000 mutated pack files through pf_load, never a crash) Co-Authored-By: Claude Fable 5.1 --- igneum-pow/tests/fuzz_parsers.rs | 132 +++++++++++++++++++++++++++++++ proto-cuda/nvrtc/packfile-fuzz.c | 56 +++++++++++++ 2 files changed, 188 insertions(+) create mode 100644 igneum-pow/tests/fuzz_parsers.rs create mode 100644 proto-cuda/nvrtc/packfile-fuzz.c diff --git a/igneum-pow/tests/fuzz_parsers.rs b/igneum-pow/tests/fuzz_parsers.rs new file mode 100644 index 000000000..a52ac6ea3 --- /dev/null +++ b/igneum-pow/tests/fuzz_parsers.rs @@ -0,0 +1,132 @@ +//! POW-01 and POW-02's malformed-input half (the Test and Acceptance Standard, 8 October 2026): 10,000 mutated inputs +//! per parser, every one refused cleanly or accepted, never a panic. The parsers: the class string (`LoadClass::parse`, +//! `ProgramClass::parse`), the hex reader (`bind::unhex`), the IGSD1 state stream (`StateStream::decode`), the era +//! string form (`":<64 hex>"`, the exporter's `parse_era` re-stated here since main.rs keeps it private). The +//! mutations: byte flips, truncation, insertion, duplication and random bytes over a valid seed input, drawn from a +//! fixed SplitMix64 so the run is reproducible; a panic in any parser fails the test (the harness catches none). +use igneum_pow::bind::unhex; +use igneum_pow::generator::{LoadClass, ProgramClass}; +use igneum_pow::state::StateStream; + +struct Rng(u64); +impl Rng { + fn next(&mut self) -> u64 { + self.0 = self.0.wrapping_add(0x9e3779b97f4a7c15); + let mut z = self.0; + z = (z ^ (z >> 30)).wrapping_mul(0xbf58476d1ce4e5b9); + z = (z ^ (z >> 27)).wrapping_mul(0x94d049bb133111eb); + z ^ (z >> 31) + } + fn below(&mut self, n: usize) -> usize { + (self.next() % (n.max(1) as u64)) as usize + } +} + +/// One mutation of `seed`: a flipped byte, a truncation, an insertion, a doubled slice, or random bytes of a random length. +fn mutate(rng: &mut Rng, seed: &[u8]) -> Vec { + let mut v = seed.to_vec(); + match rng.below(6) { + 0 => { + if !v.is_empty() { + let i = rng.below(v.len()); + v[i] ^= 1 << rng.below(8); + } + } + 1 => { + let n = rng.below(v.len() + 1); + v.truncate(n); + } + 2 => { + let i = rng.below(v.len() + 1); + v.insert(i, rng.next() as u8); + } + 3 => { + if v.len() > 1 { + let a = rng.below(v.len()); + let b = a + rng.below(v.len() - a); + let slice = v[a..b].to_vec(); + v.splice(a..a, slice); + } + } + 4 => { + let n = rng.below(300); + v = (0..n).map(|_| rng.next() as u8).collect(); + } + _ => { + if !v.is_empty() { + let i = rng.below(v.len()); + v[i] = rng.next() as u8; + } + } + } + v +} + +const N: usize = 10_000; + +#[test] +fn class_strings_never_panic() { + let seeds = ["mx8+sh256x27+state+reg64c+fold+rw", "mx8+sh256x27+state+nowin", "w32m8g-erad810f22d+sh256x27+state", "v2", "mix50-35-15", "scr4k32+hot64k4a", "mx4", "p4,p16,p64", "w64x4", "mx8+rw2"]; + let mut rng = Rng(1); + let (mut some, mut none) = (0, 0); + for k in 0..N { + let s = mutate(&mut rng, seeds[k % seeds.len()].as_bytes()); + let text = String::from_utf8_lossy(&s); + match LoadClass::parse(&text) { + Some(c) => { + // an accepted string names back to something the parser accepts again + assert!(LoadClass::parse(&c.name()).is_some(), "{text:?} -> {} does not re-parse", c.name()); + some += 1; + } + None => none += 1, + } + let _ = ProgramClass::parse(&text); + } + println!("class strings: {some} accepted, {none} refused of {N}"); + assert!(none > N / 2, "the mutations refuse at least half"); +} + +#[test] +fn hex_and_era_strings_never_panic() { + let hex = "edc4fa844da9dc98d37e965176f6558a31560e40502ab3ae5491b21aaaabfb07"; + let mut rng = Rng(2); + let mut refused = 0; + for _ in 0..N { + let s = mutate(&mut rng, hex.as_bytes()); + let text = String::from_utf8_lossy(&s); + if unhex(&text).is_none() { + refused += 1; + } + // the era string ":<64 hex>" as the exporter reads it + let era = format!("{}:{}", rng.below(1000), text); + let parsed = era.split_once(':').and_then(|(n, h)| n.parse::().ok().zip(unhex(h))).filter(|(_, b)| b.len() == 32); + if let Some((_, b)) = parsed { + assert_eq!(b.len(), 32); + } + } + println!("hex strings: {refused} refused of {N}"); + assert!(refused > 0); +} + +#[test] +fn state_streams_never_panic() { + // a small valid stream: three records under a fixed root and block + let stream = StateStream { number: 159357, block: [7u8; 32], root: [9u8; 32], records: vec![vec![1, 2, 3], vec![], (0..200u8).collect()] }; + let valid = stream.encode(); + assert_eq!(StateStream::decode(&valid).map(|s| s.records.len()), Ok(3)); + let mut rng = Rng(3); + let (mut ok, mut err) = (0, 0); + for _ in 0..N { + let bytes = mutate(&mut rng, &valid); + match StateStream::decode(&bytes) { + Ok(s) => { + // an accepted stream re-encodes to the bytes it was read from + assert_eq!(s.encode(), bytes, "an accepted stream must round-trip"); + ok += 1; + } + Err(_) => err += 1, + } + } + println!("state streams: {ok} accepted, {err} refused of {N}"); + assert!(err > N / 2); +} diff --git a/proto-cuda/nvrtc/packfile-fuzz.c b/proto-cuda/nvrtc/packfile-fuzz.c new file mode 100644 index 000000000..76c6858ed --- /dev/null +++ b/proto-cuda/nvrtc/packfile-fuzz.c @@ -0,0 +1,56 @@ +/* packfile-fuzz.c: POW-01's malformed-input half for the pack reader (8 October 2026). Copies a pack directory, mutates + * one of its files N times (a flipped byte, a truncation, an inserted byte, a doubled slice, random bytes) and calls + * pf_load on the copy each time; the run passes when every call returns 0 (refused with a message) or 1 (accepted), + * and the process never crashes. One line per 1,000 rounds, a RESULT line at the end. + * cc -O2 -o packfile-fuzz packfile-fuzz.c && ./packfile-fuzz + */ +#include "packfile.h" +#include + +static uint64_t rs = 0x1234567; +static uint64_t rnext(void) { rs += 0x9e3779b97f4a7c15ull; uint64_t z = rs; z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ull; z = (z ^ (z >> 27)) * 0x94d049bb133111ebull; return z ^ (z >> 31); } +static size_t below(size_t n) { return n ? (size_t)(rnext() % n) : 0; } + +static int copy_file(const char* from, const char* to) { + size_t n; char* b = pf_read_file(from, &n); if (!b) return 0; + FILE* f = fopen(to, "wb"); if (!f) { free(b); return 0; } + fwrite(b, 1, n, f); fclose(f); free(b); return 1; +} + +static void write_mutated(const char* src, const char* dst) { + size_t n; char* b = pf_read_file(src, &n); + size_t cap = n + 400; char* v = (char*)malloc(cap ? cap : 1); size_t len = n; if (n) memcpy(v, b, n); + switch (below(6)) { + case 0: if (len) v[below(len)] ^= (char)(1 << below(8)); break; + case 1: len = below(len + 1); break; + case 2: { size_t i = below(len + 1); memmove(v + i + 1, v + i, len - i); v[i] = (char)rnext(); len++; } break; + case 3: if (len > 1) { size_t a = below(len), bl = below(len - a); if (bl > 300) bl = 300; memmove(v + a + bl, v + a, len - a); memcpy(v + a, b + a, bl); len += bl; } break; + case 4: len = below(300); for (size_t i = 0; i < len; i++) v[i] = (char)rnext(); break; + default: if (len) v[below(len)] = (char)rnext(); break; + } + FILE* f = fopen(dst, "wb"); if (f) { fwrite(v, 1, len, f); fclose(f); } + free(v); free(b); +} + +int main(int argc, char** argv) { + if (argc < 4) { fprintf(stderr, "usage: packfile-fuzz \n"); return 2; } + const char* pack = argv[1]; long rounds = atol(argv[2]); const char* scratch = argv[3]; + const char* files[] = { "program.h", "vectors.h", "seeds.txt", "memhard.h" }; + mkdir(scratch, 0755); + char from[1024], to[1024]; + for (int i = 0; i < 4; i++) { snprintf(from, sizeof from, "%s/%s", pack, files[i]); snprintf(to, sizeof to, "%s/%s", scratch, files[i]); copy_file(from, to); } + PfPack pk; char err[512]; + int base = pf_load(pack, &pk, err, sizeof err); + printf("base pack %s: %s%s\n", pack, base ? "accepted" : "refused: ", base ? "" : err); + long accepted = 0, refused = 0; + for (long r = 0; r < rounds; r++) { + int which = (int)below(4); + for (int i = 0; i < 4; i++) { snprintf(from, sizeof from, "%s/%s", pack, files[i]); snprintf(to, sizeof to, "%s/%s", scratch, files[i]); if (i == which) write_mutated(from, to); else copy_file(from, to); } + memset(&pk, 0, sizeof pk); err[0] = 0; + int ok = pf_load(scratch, &pk, err, sizeof err); + if (ok) accepted++; else refused++; + if ((r + 1) % 1000 == 0) printf("round %ld: accepted %ld refused %ld\n", r + 1, accepted, refused); + } + printf("RESULT packfile-fuzz pack=%s rounds=%ld accepted=%ld refused=%ld crashes=0 verdict=PASS\n", pack, rounds, accepted, refused); + return 0; +} From f34da5f57cc6f0ab7e6a5300f4dced57c2fe483e Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Thu, 8 Oct 2026 17:41:05 +0000 Subject: [PATCH 08/36] class-v6: the window's liveness rule is wired into the acceptance behind the reg64 flag (the arithmetic-only window refused at its first dead register, the full chain and every other class unchanged); the test reads it through accept::check Co-Authored-By: Claude Fable 5.1 --- igneum-pow/src/accept.rs | 6 ++++++ igneum-pow/tests/packs.rs | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/igneum-pow/src/accept.rs b/igneum-pow/src/accept.rs index e02c92efe..daa8186ca 100644 --- a/igneum-pow/src/accept.rs +++ b/igneum-pow/src/accept.rs @@ -849,6 +849,12 @@ pub fn check_dynamic(p: &Program) -> Result { check_distinct_indices_v4(p)?; } } + // the reg64 window's liveness rule (the window's acceptance tool, wired 8 October 2026, 19:5x UK): keyed on the + // window flag so no other class's verdict moves; the arithmetic-only window is refused at its first dead register, + // the full chain passes (129 one-warp interpretations on the closed form, under a second) + if p.class.reg64 { + check_window_liveness(p)?; + } let half = (ACCEPT_HASHES / 2) as u32; let mut bias_max = 0u32; for (bit, &ones) in acc.bit_ones.iter().enumerate() { diff --git a/igneum-pow/tests/packs.rs b/igneum-pow/tests/packs.rs index 9b3aecf48..a03549113 100644 --- a/igneum-pow/tests/packs.rs +++ b/igneum-pow/tests/packs.rs @@ -1222,4 +1222,10 @@ fn reg64_liveness_rule_refuses_the_subset_fold_and_passes_the_full_chain() { let mut chain = epoch_reg64_of_devnet(); chain.program.class = chain.program.class.with_reg64_chain(); assert_eq!(check_window_liveness(&chain.program), Ok(()), "the full chain keeps all 64 registers live across the chain"); + // wired into the acceptance (8 October 2026): `accept::check` refuses the arithmetic-only window as a dead register + // and never refuses the chain program for liveness; the plain pack's verdict does not move + use igneum_pow::accept::check; + assert!(matches!(check(&window.program), Err(Reject::DeadWindowRegister { .. })), "the acceptance refuses the arithmetic-only window"); + assert!(!matches!(check(&chain.program), Err(Reject::DeadWindowRegister { .. }) | Err(Reject::NotAWindow)), "the chain program is never refused for liveness"); + assert!(check(&plain.program).is_ok(), "the pinned devnet program's verdict does not move"); } From 7d8171e8a3bbdbb5327a6b57b7adc2de530b7c7b Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Thu, 8 Oct 2026 18:03:38 +0000 Subject: [PATCH 09/36] class-v6: the external review's findings (docs/analysis/review-2026-10-08, 8 October 2026), fixed by construction where they apply: A02 every class carrying a v6 flag reserves five non-load slots as shuffles over the five lane dimensions in a drawn order (LoadClass::is_v6; the id carries v6draw/); A08 a v6 mad never names its destination as its second source; A06 program.json carries the BLAKE2b-256 of every kernel text (kernel_blake2b256); A07 the verifier's group alignment, tails and low-32 rollover under test; A04 a zeroing shadow fails acceptance under test (the acceptance executes the shadow since sub-version 3); and the fuzz's finding: bind::unhex panicked on a multi-byte character inside the text, now a refusal on bytes. Co-Authored-By: Claude Fable 5.1 --- igneum-pow/src/bind.rs | 15 +++++++++-- igneum-pow/src/emit.rs | 21 +++++++++++---- igneum-pow/src/generator.rs | 47 ++++++++++++++++++++++++++++++++-- igneum-pow/tests/packs.rs | 51 +++++++++++++++++++++++++++++++++++++ igneum-pow/tests/v6fold.rs | 37 ++++++++++++++++++++++++++- 5 files changed, 161 insertions(+), 10 deletions(-) diff --git a/igneum-pow/src/bind.rs b/igneum-pow/src/bind.rs index 94edea2bd..dd18b3069 100644 --- a/igneum-pow/src/bind.rs +++ b/igneum-pow/src/bind.rs @@ -91,10 +91,21 @@ pub fn hex(bytes: &[u8]) -> String { /// Bytes from hex (either case). `None` on odd length or a bad digit. pub fn unhex(s: &str) -> Option> { - if s.len() % 2 != 0 { + // on bytes, never on char boundaries (the fuzz of 8 October 2026 found a multi-byte character inside the text + // panicked the slice; a non-ASCII byte is a bad digit) + let b = s.as_bytes(); + if b.len() % 2 != 0 { return None; } - (0..s.len()).step_by(2).map(|i| u8::from_str_radix(&s[i..i + 2], 16).ok()).collect() + let digit = |c: u8| -> Option { + match c { + b'0'..=b'9' => Some(c - b'0'), + b'a'..=b'f' => Some(c - b'a' + 10), + b'A'..=b'F' => Some(c - b'A' + 10), + _ => None, + } + }; + b.chunks(2).map(|c| Some(digit(c[0])? << 4 | digit(c[1])?)).collect() } impl Epoch { diff --git a/igneum-pow/src/emit.rs b/igneum-pow/src/emit.rs index 25f14e983..f122e2d35 100644 --- a/igneum-pow/src/emit.rs +++ b/igneum-pow/src/emit.rs @@ -2610,19 +2610,30 @@ pub fn export_pack(epoch: &Epoch, day: &str, source: &str) -> Pack { v.hot_fnv = h.fnv1a64(); } let is_mh = memhard.is_some(); - let mut files = vec![ - ("program.json".to_string(), program_json(p, day, ds)), - ("vectors.json".to_string(), vectors_json_geom(p, day, geom, &bases, &outs, &v, source, is_mh)), + let texts: Vec<(String, String)> = vec![ ("kernel.cu".to_string(), cuda_kernel_geom(p, memhard, geom)), ("kernel.cl".to_string(), opencl_kernel_geom(p, memhard, geom)), - ("program.h".to_string(), program_header(p, day, ds)), - ("vectors.h".to_string(), vectors_header(p, &bases, &outs, &v, mask, source, is_mh)), ("program.metal".to_string(), metal_program_geom(p, geom, LoadSource::Stored)), // Header-bound kernels (3 October 2026, bind.rs): new files, the seven above are unchanged. ("program_bound.metal".to_string(), metal_program_bound_geom(p, geom)), ("kernel_bound.cu".to_string(), cuda_kernel_bound_geom(p, memhard, geom)), ("kernel_bound.cl".to_string(), opencl_kernel_bound_geom(p, memhard, geom)), ]; + // A06 (the external review of 8 October 2026): program.json authenticates the kernel texts by hash, not by + // metadata: the BLAKE2b-256 of every kernel file the pack carries, beside the program, dataset and era identities + let mut pj = program_json(p, day, ds); + let hashes: Vec = texts.iter().map(|(n, t)| format!(" {}: \"{}\"", jstr(n), hex_bytes(&crate::state::blake2b_256(&[t.as_bytes()])))).collect(); + let tail = pj.trim_end().strip_suffix('}').map(|t| t.len()).unwrap_or(pj.len()); + pj.truncate(tail); + pj = pj.trim_end().to_string(); + pj.push_str(&format!(",\n \"kernel_blake2b256\": {{\n{}\n }}\n}}\n", hashes.join(",\n"))); + let mut files = vec![ + ("program.json".to_string(), pj), + ("vectors.json".to_string(), vectors_json_geom(p, day, geom, &bases, &outs, &v, source, is_mh)), + ("program.h".to_string(), program_header(p, day, ds)), + ("vectors.h".to_string(), vectors_header(p, &bases, &outs, &v, mask, source, is_mh)), + ]; + files.extend(texts); if let Some(mp) = memhard { files.push(("memhard.h".to_string(), cuda_memhard_header(p, mp))); files.push(("memhard.metal".to_string(), metal_memhard_for(p, mp))); diff --git a/igneum-pow/src/generator.rs b/igneum-pow/src/generator.rs index 39cde7c3a..6a822bbd9 100644 --- a/igneum-pow/src/generator.rs +++ b/igneum-pow/src/generator.rs @@ -644,6 +644,16 @@ impl LoadClass { LoadClass { nowin: true, ..self } } + /// The class v6 object's draw rules (the external review of 8 October 2026, A02 and A08, fixed by construction for + /// every class carrying a v6 flag: the index fold, a re-weight table, the register window or layer 8 off): five + /// of the non-load slots are shuffles whose masks are the five lane dimensions 1, 2, 4, 8, 16 in a drawn order, so + /// every accepted program mixes all 32 lanes by construction; and a `mad` never names its destination as its + /// second source (`d = a * d + d` is `d * (a + 1)`, not a bijection in `d` when `a` is odd). Every other class + /// draws as before. + pub fn is_v6(&self) -> bool { + self.fold || self.rw != 0 || self.reg64 || self.nowin + } + /// The non-load op table this class draws from, in draw order, and its sum (the roll's range). The plain table /// for every class without the re-weight flag, so their streams are byte for byte what they were. pub fn nonload_weights(&self) -> (&'static [(Op, u64); 10], u64) { @@ -1480,6 +1490,10 @@ pub fn program_id_class_recipe(generator: u32, seed: &[u32; 8], attempt: u32, cl // D2 "layer 8 off": the window layer is part of the construction r.lit(b"nowin/"); } + if class.is_v6() { + // the v6 draw rules (A02 five shuffle dimensions, A08 the mad operand rule) are part of the construction + r.lit(b"v6draw/"); + } if class.rw != 0 { // class v6 lane 1: the re-weight table moves the op draw r.lit(b"rw/"); @@ -1648,6 +1662,23 @@ pub fn candidate_from_words_class( for &slot in &p[..slots] { is_load[slot as usize] = true; } + // class v6 (A02, by construction): five of the non-load slots are shuffles over the five lane dimensions in a + // drawn order; drawn from the stream after the load slots, so no other class's stream moves + let mut is_shfl = [false; INSTR_COUNT]; + let mut shfl_masks = [1u8, 2, 4, 8, 16]; + if class.is_v6() { + let rest = &mut p[slots..]; + for i in 0..5 { + let j = i + rng.below((rest.len() - i) as u64) as usize; + rest.swap(i, j); + is_shfl[rest[i] as usize] = true; + } + for i in 0..5 { + let j = i + rng.below((5 - i) as u64) as usize; + shfl_masks.swap(i, j); + } + } + let mut shfl_next = 0usize; // Variant 5: the first k drawn load slots (a uniform k-subset, the draw order is random) are scratch ops. let mut is_scratch = [false; INSTR_COUNT]; for &slot in &p[..class.scratch_slots()] { @@ -1704,6 +1735,9 @@ pub fn candidate_from_words_class( Op::Load }; } + if is_shfl[k] { + op = Op::Shfl; + } let dst = rng.below(8); let src = if op.is_load() { let mut eligible = [0u64; 8]; @@ -1732,12 +1766,21 @@ pub fn candidate_from_words_class( a } }; - let b = rng.below(8); + let mut b = rng.below(8); + // class v6 (A08, by construction): a mad's second source is never its destination + if class.is_v6() && op == Op::Mad && b == dst { + b = (b + 1) & 7; + } let imm = rng.next() as u32; let imm2 = rng.next() as u32; let rot = 1 + rng.below(31) as u32; let bit = rng.below(32); - let mask = 1u8 << rng.below(5); + let mut mask = 1u8 << rng.below(5); + // class v6 (A02): the reserved shuffle slots take the five dimensions in the drawn order + if is_shfl[k] { + mask = shfl_masks[shfl_next]; + shfl_next += 1; + } // Version 2 loads take no width roll, so a mixer class with version 2 loads draws the version 2 program let width = if class.takes_width_roll() { class.width_for_roll(rng.below(100)) } else { 1 }; let width = if op == Op::Load { width } else { 1 }; diff --git a/igneum-pow/tests/packs.rs b/igneum-pow/tests/packs.rs index a03549113..4301e0e5c 100644 --- a/igneum-pow/tests/packs.rs +++ b/igneum-pow/tests/packs.rs @@ -1229,3 +1229,54 @@ fn reg64_liveness_rule_refuses_the_subset_fold_and_passes_the_full_chain() { assert!(!matches!(check(&chain.program), Err(Reject::DeadWindowRegister { .. }) | Err(Reject::NotAWindow)), "the chain program is never refused for liveness"); assert!(check(&plain.program).is_ok(), "the pinned devnet program's verdict does not move"); } + +/// The external review's A07 (8 October 2026): the bound hash of a nonce is the lane of the aligned 32-nonce group that +/// contains it, in the verifier by construction (`Epoch::hash_bound`), across the group's tail and the low-32 rollover; +/// the high 32 bits of the nonce enter the init words, so two nonces 2^32 apart never share a hash. The launchers +/// refuse a job whose nonce_start is not 32-aligned or whose count is not a multiple of 32 (worker.cpp's job line). +#[test] +fn a07_bound_hash_is_group_aligned_across_tails_and_rollover() { + use igneum_pow::bind::block_init_words; + let e = epoch("mx8-devnet-epoch0"); + let prehash = [0x5au8; 32]; + for &n in &[0u64, 1, 2, 31, 32, 33, 63, (1u64 << 32) - 1, 1u64 << 32, (1u64 << 32) + 1, u64::MAX - 1, u64::MAX] { + let base = n & !31; + let warp = e.hash_warp_bound(&prehash, base); + assert_eq!(e.hash_bound(&prehash, n), warp[(n & 31) as usize], "nonce {n}: the lane of its aligned group"); + assert_eq!(e.hash_warp_bound(&prehash, n), warp, "nonce {n}: the group is the same from any of its nonces"); + let distinct: std::collections::HashSet = warp.iter().copied().collect(); + assert!(distinct.len() >= 31, "nonce {n}: the lanes of a group are distinct hashes"); + } + assert_ne!(e.hash_bound(&prehash, 2), e.hash_bound(&prehash, 2 + (1u64 << 32)), "the high 32 bits reach the hash"); + assert_ne!(block_init_words(&prehash, 2), block_init_words(&prehash, 2 + (1u64 << 32))); +} + +/// The external review's A04 (8 October 2026): the acceptance executes the shadow block as the hash does (class v4 +/// sub-version 3), so a shadow that zeroes the registers fails acceptance; the pinned program with its own shadow passes. +#[test] +fn a04_a_zeroing_shadow_fails_acceptance() { + use igneum_pow::accept::check; + let e = epoch("mx8-devnet-epoch0"); + assert!(check(&e.program).is_ok()); + let mut z = e.program.clone(); + assert!(!z.shadow.is_empty(), "the pinned class has a shadow block"); + for ins in z.shadow.iter_mut() { + ins.op = Op::Xor; + ins.src = ins.dst; + } + assert!(check(&z).is_err(), "a shadow of xor d, d zeroes every register it touches and must fail"); +} + +/// The external review's A06 (8 October 2026): the pack's program.json authenticates every kernel text by BLAKE2b-256. +#[test] +fn a06_program_json_hashes_every_kernel_text() { + let e = epoch("mx8-devnet-epoch0"); + let out = export_pack(&e, &day_label("mx8-devnet-epoch0"), "test"); + let file = |n: &str| out.files.iter().find(|(f, _)| f == n).map(|(_, t)| t.clone()).unwrap(); + let j: Value = serde_json::from_str(&file("program.json")).unwrap(); + let h = j["kernel_blake2b256"].as_object().expect("kernel_blake2b256"); + for n in ["kernel.cu", "kernel.cl", "program.metal", "program_bound.metal", "kernel_bound.cu", "kernel_bound.cl"] { + let want: String = igneum_pow::state::blake2b_256(&[file(n).as_bytes()]).iter().map(|x| format!("{x:02x}")).collect(); + assert_eq!(h[n].as_str().unwrap(), want, "{n}"); + } +} diff --git a/igneum-pow/tests/v6fold.rs b/igneum-pow/tests/v6fold.rs index a97f81768..b3c62ff37 100644 --- a/igneum-pow/tests/v6fold.rs +++ b/igneum-pow/tests/v6fold.rs @@ -8,7 +8,7 @@ use igneum_pow::accept::{index_bit_sigma, index_bit_sigma_max, ACCEPT_UNITS_DIST use igneum_pow::emit::export_pack; use igneum_pow::generator::{ candidate_class, generate_era_generator, LoadClass, Op, Program, ProgramClass, EraParams, INSTR_COUNT, NONLOAD_WEIGHTS, - NONLOAD_WEIGHTS_RW, NONLOAD_WEIGHTS_RW2, NONLOAD_WEIGHTS_RW2_SUM, NONLOAD_WEIGHTS_RW_SUM, V3_ALLOWED, V4_CLASS, V5_CLASS, + NONLOAD_WEIGHTS_RW, NONLOAD_WEIGHTS_RW2, NONLOAD_WEIGHTS_RW2_SUM, NONLOAD_WEIGHTS_RW_SUM, V3_ALLOWED, V3_CLASS, V4_CLASS, V5_CLASS, }; use igneum_pow::seed::seed_words_from_bytes; use igneum_pow::verify::{load_index, stride, DatasetGeom, Epoch, INDEX_FOLD_SHIFT}; @@ -212,6 +212,41 @@ fn nowin_removes_the_window_layer_and_nothing_else() { assert_eq!(plain.class.era.map(|e| EraParams { fold: e.fold, ..e }), off.class.era.map(|e| EraParams { fold: e.fold, ..e }), "the era draw is untouched"); } +/// The external review's A02 and A08 (8 October 2026), fixed by construction for every class carrying a v6 flag: +/// every candidate of 64 seeds (attempt 0, no acceptance pass) carries shuffles over all five lane dimensions, and no +/// `mad` names its destination as its second source; the plain class v5 draw is untouched (the pinned pack test +/// reads that); the v6 draw's id carries the rule. +#[test] +fn v6_draw_connects_all_lanes_and_keeps_mad_bijective_by_construction() { + let era = f8_bytes("era", 4); + let classes = [V5_CLASS.with_fold(), V5_CLASS.with_rw(1), V5_CLASS.with_nowin(), LoadClass::parse("mx8+sh256x27+state+reg64c+fold+rw").unwrap()]; + for c in classes { + assert!(c.is_v6()); + for k in 0..64u32 { + let seed = f8_bytes("program", k); + let p = candidate_class("p-a02", &seed, 0, LoadClass::era(c, &era, &V3_ALLOWED)); + let mut dims = [false; 5]; + for ins in &p.instrs { + if ins.op == Op::Shfl { + dims[ins.mask.trailing_zeros() as usize] = true; + } + if ins.op == Op::Mad { + assert_ne!(ins.src2, ins.dst, "seed {k} class {}: a mad with src2 == dst", c.name()); + } + } + assert!(dims.iter().all(|&d| d), "seed {k} class {}: shuffle dimensions {:?}", c.name(), dims); + assert_eq!(p.instrs.len(), 64); + assert_eq!(p.instrs.iter().filter(|i| i.op.is_load()).count(), 16, "the load slots are the class's"); + } + } + assert!(!V5_CLASS.is_v6() && !V3_CLASS.is_v6()); + // a plain class v5 candidate of the same seed can lack a dimension: the rule is the v6 construction's, not a filter + let seed = f8_bytes("program", 4); + let a = candidate_class("p-a02", &seed, 0, LoadClass::era(V5_CLASS, &era, &V3_ALLOWED)); + let b = candidate_class("p-a02", &seed, 0, LoadClass::era(V5_CLASS.with_fold(), &era, &V3_ALLOWED)); + assert_ne!(a.program_id(), b.program_id()); +} + /// 2. The fold's form: `y = x * M; y ^= y >> 16; y = rotl(y, R)`, and nothing else moves. The plain era's stride is /// `rotl(x * M, R)` byte for byte. #[test] From ab4c36c5c02b4be2780afa7aefc7208c174f5ce9 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Thu, 8 Oct 2026 18:06:01 +0000 Subject: [PATCH 10/36] class-v6: blake2b_256 reached through its own module; the pack-reader fuzz skips a file the pack does not carry Co-Authored-By: Claude Fable 5.1 --- igneum-pow/src/emit.rs | 2 +- igneum-pow/tests/packs.rs | 2 +- proto-cuda/nvrtc/packfile-fuzz.c | 5 +++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/igneum-pow/src/emit.rs b/igneum-pow/src/emit.rs index f122e2d35..876ba88cd 100644 --- a/igneum-pow/src/emit.rs +++ b/igneum-pow/src/emit.rs @@ -2622,7 +2622,7 @@ pub fn export_pack(epoch: &Epoch, day: &str, source: &str) -> Pack { // A06 (the external review of 8 October 2026): program.json authenticates the kernel texts by hash, not by // metadata: the BLAKE2b-256 of every kernel file the pack carries, beside the program, dataset and era identities let mut pj = program_json(p, day, ds); - let hashes: Vec = texts.iter().map(|(n, t)| format!(" {}: \"{}\"", jstr(n), hex_bytes(&crate::state::blake2b_256(&[t.as_bytes()])))).collect(); + let hashes: Vec = texts.iter().map(|(n, t)| format!(" {}: \"{}\"", jstr(n), hex_bytes(&crate::blake2b::blake2b_256(&[t.as_bytes()])))).collect(); let tail = pj.trim_end().strip_suffix('}').map(|t| t.len()).unwrap_or(pj.len()); pj.truncate(tail); pj = pj.trim_end().to_string(); diff --git a/igneum-pow/tests/packs.rs b/igneum-pow/tests/packs.rs index 4301e0e5c..80fdbc1ec 100644 --- a/igneum-pow/tests/packs.rs +++ b/igneum-pow/tests/packs.rs @@ -1276,7 +1276,7 @@ fn a06_program_json_hashes_every_kernel_text() { let j: Value = serde_json::from_str(&file("program.json")).unwrap(); let h = j["kernel_blake2b256"].as_object().expect("kernel_blake2b256"); for n in ["kernel.cu", "kernel.cl", "program.metal", "program_bound.metal", "kernel_bound.cu", "kernel_bound.cl"] { - let want: String = igneum_pow::state::blake2b_256(&[file(n).as_bytes()]).iter().map(|x| format!("{x:02x}")).collect(); + let want: String = igneum_pow::blake2b::blake2b_256(&[file(n).as_bytes()]).iter().map(|x| format!("{x:02x}")).collect(); assert_eq!(h[n].as_str().unwrap(), want, "{n}"); } } diff --git a/proto-cuda/nvrtc/packfile-fuzz.c b/proto-cuda/nvrtc/packfile-fuzz.c index 76c6858ed..9cafb5519 100644 --- a/proto-cuda/nvrtc/packfile-fuzz.c +++ b/proto-cuda/nvrtc/packfile-fuzz.c @@ -12,13 +12,14 @@ static uint64_t rnext(void) { rs += 0x9e3779b97f4a7c15ull; uint64_t z = rs; z = static size_t below(size_t n) { return n ? (size_t)(rnext() % n) : 0; } static int copy_file(const char* from, const char* to) { - size_t n; char* b = pf_read_file(from, &n); if (!b) return 0; + size_t n = 0; char* b = pf_read_file(from, &n); if (!b) { remove(to); return 0; } FILE* f = fopen(to, "wb"); if (!f) { free(b); return 0; } fwrite(b, 1, n, f); fclose(f); free(b); return 1; } static void write_mutated(const char* src, const char* dst) { - size_t n; char* b = pf_read_file(src, &n); + size_t n = 0; char* b = pf_read_file(src, &n); + if (!b) { remove(dst); return; } /* a pack without this file: the mutation is its absence */ size_t cap = n + 400; char* v = (char*)malloc(cap ? cap : 1); size_t len = n; if (n) memcpy(v, b, n); switch (below(6)) { case 0: if (len) v[below(len)] ^= (char)(1 << below(8)); break; From a326de8eab6ebd2bbe6b9778677a41d0164b322f Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Thu, 8 Oct 2026 18:18:54 +0000 Subject: [PATCH 11/36] class-v6: the acceptance's class v4 shape predicate and the draw's source rule set the window and layer 8 off aside (lane D's finding: a +nowin or +reg64c program was judged by the class v2 parts on the chain's path); test: every v6 flag keeps the shape and the attempt cap Co-Authored-By: Claude Fable 5.1 --- igneum-pow/src/accept.rs | 4 +++- igneum-pow/src/generator.rs | 2 +- igneum-pow/tests/v6fold.rs | 17 +++++++++++++++++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/igneum-pow/src/accept.rs b/igneum-pow/src/accept.rs index daa8186ca..51ef435f3 100644 --- a/igneum-pow/src/accept.rs +++ b/igneum-pow/src/accept.rs @@ -489,7 +489,9 @@ pub fn is_class_v4_shape(class: &LoadClass) -> bool { // class v5 (docs/design/class-v5-stored-state.md) is judged under the same rules: its state flag is set aside; // class v6 lane 1's index fold and re-weight table are set aside too (the address path and the op table are // not the shape) - && LoadClass { era: None, shadow: None, state: false, fold: false, rw: 0, ..*class } == LoadClass { shadow: None, ..V4_CLASS } + // the window and layer 8 off are set aside too (lane D's finding of 8 October 2026, 19:1x UK: a +nowin or +reg64c + // program was judged by the class v2 parts alone on the chain's path; the harness's own predicate hid it) + && LoadClass { era: None, shadow: None, state: false, fold: false, rw: 0, nowin: false, reg64: false, reg64_chain: false, ..*class } == LoadClass { shadow: None, ..V4_CLASS } } /// One pass of the dataflow freshness over the base program then the shadow block (the order of one iteration), diff --git a/igneum-pow/src/generator.rs b/igneum-pow/src/generator.rs index 6a822bbd9..8f30ee48b 100644 --- a/igneum-pow/src/generator.rs +++ b/igneum-pow/src/generator.rs @@ -1705,7 +1705,7 @@ pub fn candidate_from_words_class( // class v6 lane 1: the index fold and the re-weight table are set aside too (the address path and the table are not // the shape; a +fold or +rw program draws its sources under the same rule) let source_rule_v4 = matches!(class.shadow, Some(ShadowClass { instrs: V4_SHADOW_INSTRS, .. })) - && LoadClass { era: None, shadow: None, state: false, fold: false, rw: 0, nowin: false, ..class } == LoadClass { shadow: None, ..V4_CLASS }; + && LoadClass { era: None, shadow: None, state: false, fold: false, rw: 0, nowin: false, reg64: false, reg64_chain: false, ..class } == LoadClass { shadow: None, ..V4_CLASS }; // the op table and the roll's range: the plain table at 75 for every class without the re-weight flag let (weights, weights_sum) = class.nonload_weights(); let mut fresh = [false; 8]; diff --git a/igneum-pow/tests/v6fold.rs b/igneum-pow/tests/v6fold.rs index b3c62ff37..b67eb9756 100644 --- a/igneum-pow/tests/v6fold.rs +++ b/igneum-pow/tests/v6fold.rs @@ -247,6 +247,23 @@ fn v6_draw_connects_all_lanes_and_keeps_mad_bijective_by_construction() { assert_ne!(a.program_id(), b.program_id()); } +/// Lane D's finding (8 October 2026): every class v6 flag is set aside by the acceptance's class v4 shape predicate, +/// so a +nowin, +reg64 or +reg64c program is judged by the full rule (the fresh-source rule, the saturated-source +/// check, the index floors and the attempt cap with the last resort), not by the class v2 parts; the draw's source +/// rule reads the same shape. +#[test] +fn every_v6_flag_keeps_the_class_v4_acceptance_shape() { + use igneum_pow::accept::is_class_v4_shape; + use igneum_pow::generator::max_attempts_for; + let all = LoadClass::parse("mx8+sh256x27+state+reg64c+nowin+fold+rw").unwrap(); + for c in [V5_CLASS, V5_CLASS.with_nowin(), V5_CLASS.with_reg64(), V5_CLASS.with_reg64().with_reg64_chain(), V5_CLASS.with_fold(), all] { + assert!(is_class_v4_shape(&c), "{}", c.name()); + assert!(is_class_v4_shape(&LoadClass::era(c, &f8_bytes("era", 4), &V3_ALLOWED)), "{} under an era", c.name()); + assert_eq!(max_attempts_for(&c), max_attempts_for(&V5_CLASS), "{}: the same attempt cap and last resort", c.name()); + } + assert!(!is_class_v4_shape(&V3_CLASS) && !is_class_v4_shape(&LoadClass::V2)); +} + /// 2. The fold's form: `y = x * M; y ^= y >> 16; y = rotl(y, R)`, and nothing else moves. The plain era's stride is /// `rotl(x * M, R)` byte for byte. #[test] From 86ce68b2e7e1f3e8c1963476f533f7d9cad4a6e7 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Thu, 8 Oct 2026 18:32:44 +0000 Subject: [PATCH 12/36] igneum-pow hash-bound --count: one warp per 32 nonces (the P01 campaign's million-vector files in minutes; the per-nonce form hashed the whole group per nonce) Co-Authored-By: Claude Fable 5.1 --- igneum-pow/src/main.rs | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/igneum-pow/src/main.rs b/igneum-pow/src/main.rs index 393b1eb81..4e3ddb224 100644 --- a/igneum-pow/src/main.rs +++ b/igneum-pow/src/main.rs @@ -229,10 +229,29 @@ fn main() { // gate G2 (5 October 2026, ported from branch ca2-era for the class v4 gate run): `--count N` prints // "nonce hash" for N consecutive 64-bit nonces from --nonce, one epoch build, to re-hash a worker's // found lines (the same prehash, target ff..ff) - for k in 0..a.count { - let n = a.nonce.wrapping_add(k); - println!("{n} {:016x}", e.hash_bound(&prehash, n)); + // one warp per 32 nonces (the P01 campaign, 8 October 2026: a million nonces per pack in minutes, not + // hours; the per-nonce form hashed the whole aligned group for every nonce) + let end = a.nonce.wrapping_add(a.count); + let mut n = a.nonce; + let mut out = String::with_capacity(1 << 16); + use std::io::Write; + let stdout = std::io::stdout(); + let mut lock = stdout.lock(); + while n != end { + let base = n & !31; + let warp = e.hash_warp_bound(&prehash, base); + let mut m = n; + while m != end && (m & !31) == base { + out.push_str(&format!("{m} {:016x}\n", warp[(m & 31) as usize])); + m = m.wrapping_add(1); + } + n = m; + if out.len() > (1 << 15) { + lock.write_all(out.as_bytes()).unwrap(); + out.clear(); + } } + lock.write_all(out.as_bytes()).unwrap(); return; } let init = igneum_pow::bind::block_init_words(&prehash, a.nonce); From f3c3ff59eb5c10d4dd3683cc5d1828391fe66430 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Thu, 8 Oct 2026 18:56:10 +0000 Subject: [PATCH 13/36] class-v6: A06's kernel hashes move to identity.json (a thirteenth pack file: program id, class, generator, day, dataset bytes, the BLAKE2b-256 of every kernel text) so every pinned pack's twelve files stay byte for byte; the tests skip it in the pinned comparison and count thirteen Co-Authored-By: Claude Fable 5.1 --- igneum-pow/src/emit.rs | 22 ++++++++++++++-------- igneum-pow/tests/ds55.rs | 7 +++++-- igneum-pow/tests/packs.rs | 9 +++++---- igneum-pow/tests/v6fold.rs | 5 ++++- 4 files changed, 28 insertions(+), 15 deletions(-) diff --git a/igneum-pow/src/emit.rs b/igneum-pow/src/emit.rs index 876ba88cd..367b668a5 100644 --- a/igneum-pow/src/emit.rs +++ b/igneum-pow/src/emit.rs @@ -2619,16 +2619,22 @@ pub fn export_pack(epoch: &Epoch, day: &str, source: &str) -> Pack { ("kernel_bound.cu".to_string(), cuda_kernel_bound_geom(p, memhard, geom)), ("kernel_bound.cl".to_string(), opencl_kernel_bound_geom(p, memhard, geom)), ]; - // A06 (the external review of 8 October 2026): program.json authenticates the kernel texts by hash, not by - // metadata: the BLAKE2b-256 of every kernel file the pack carries, beside the program, dataset and era identities - let mut pj = program_json(p, day, ds); + // A06 (the external review of 8 October 2026): the pack authenticates its kernel texts by hash, not by metadata: + // identity.json carries the program id, the dataset and era identities and the BLAKE2b-256 of every kernel file. + // A file of its own, so every pinned pack's twelve files stay byte for byte (the readers ignore it). let hashes: Vec = texts.iter().map(|(n, t)| format!(" {}: \"{}\"", jstr(n), hex_bytes(&crate::blake2b::blake2b_256(&[t.as_bytes()])))).collect(); - let tail = pj.trim_end().strip_suffix('}').map(|t| t.len()).unwrap_or(pj.len()); - pj.truncate(tail); - pj = pj.trim_end().to_string(); - pj.push_str(&format!(",\n \"kernel_blake2b256\": {{\n{}\n }}\n}}\n", hashes.join(",\n"))); + let identity = format!( + "{{\n \"program_id\": \"{:#018x}\",\n \"load_class\": {},\n \"generator\": {},\n \"day\": {},\n \"dataset_bytes\": {},\n \"kernel_blake2b256\": {{\n{}\n }},\n \"rule\": \"the external review's A06 (8 October 2026): a pack's program, dataset and work identities are distinct, and its kernel texts are authenticated by the hash of their bytes, never by the metadata beside them\"\n}}\n", + p.program_id(), + jstr(&p.class.name()), + p.generator, + jstr(day), + (ds.geom.words as u128) * 4, + hashes.join(",\n") + ); let mut files = vec![ - ("program.json".to_string(), pj), + ("program.json".to_string(), program_json(p, day, ds)), + ("identity.json".to_string(), identity), ("vectors.json".to_string(), vectors_json_geom(p, day, geom, &bases, &outs, &v, source, is_mh)), ("program.h".to_string(), program_header(p, day, ds)), ("vectors.h".to_string(), vectors_header(p, &bases, &outs, &v, mask, source, is_mh)), diff --git a/igneum-pow/tests/ds55.rs b/igneum-pow/tests/ds55.rs index 821cd76cf..4bff40706 100644 --- a/igneum-pow/tests/ds55.rs +++ b/igneum-pow/tests/ds55.rs @@ -68,8 +68,11 @@ fn power_of_two_path_is_byte_identical_to_the_pinned_pack() { assert!(!e.dataset.geom.mulshift); assert_eq!(e.dataset.geom, DatasetGeom::pow2(28)); let out = export_pack(e, &day_label(), SOURCE); - assert_eq!(out.files.len(), 12, "the pack's twelve files"); + assert_eq!(out.files.len(), 13, "the pack's thirteen files"); for (name, text) in &out.files { + if name == "identity.json" { + continue; // A06's identity file is new beside the pinned twelve + } let want = pinned(name); assert!(text == &want, "mx8-devnet-epoch0/{name} differs from the default path's export"); } @@ -219,7 +222,7 @@ fn ds55_pack_fields_and_vectors() { assert_eq!(e.program.seed[0], 0x667d_0fbd); assert_eq!(e.program.seed[1], 0x7b8e_5963); let out = export_pack(e, &day_label(), SOURCE); - assert_eq!(out.files.len(), 12); + assert_eq!(out.files.len(), 13); let pj = &out.files.iter().find(|(n, _)| n == "program.json").unwrap().1; let j: Value = serde_json::from_str(pj).expect("program.json is valid JSON"); assert_eq!(j["program_id"].as_str().unwrap(), "0x73bcbfe8ccf988f1"); diff --git a/igneum-pow/tests/packs.rs b/igneum-pow/tests/packs.rs index 80fdbc1ec..8cae778ba 100644 --- a/igneum-pow/tests/packs.rs +++ b/igneum-pow/tests/packs.rs @@ -869,7 +869,7 @@ fn hot_packs_emitted_sources_and_load_forms() { let file = |name: &str| -> &str { &out.files.iter().find(|(n, _)| n == name).unwrap().1 }; hassert_same_text(pack, "vectors.json", file("vectors.json")); hassert_same_text(pack, "vectors.h", file("vectors.h")); - assert_eq!(out.files.len(), 12); + assert_eq!(out.files.len(), 13); // One form per dialect, exactly 16 - k masked dataset loads and k hot loads in every hash kernel; the fill // kernel is present once per source that builds the table. for (file, load, masked, hot) in [ @@ -1032,7 +1032,7 @@ fn reg64_plain_path_reexports_the_pinned_devnet_pack_unchanged() { assert_eq!(e.program.registers(), 8); assert_eq!(e.program.scheduled(), e.program.instrs, "without the flag the schedule is the drawn program"); let out = export_pack(e, &day_label(pack), PINNED_SOURCE); - assert_eq!(out.files.len(), 12); + assert_eq!(out.files.len(), 13); for (name, text) in &out.files { assert_same_text(pack, name, text); } @@ -1267,14 +1267,15 @@ fn a04_a_zeroing_shadow_fails_acceptance() { assert!(check(&z).is_err(), "a shadow of xor d, d zeroes every register it touches and must fail"); } -/// The external review's A06 (8 October 2026): the pack's program.json authenticates every kernel text by BLAKE2b-256. +/// The external review's A06 (8 October 2026): the pack's identity.json authenticates every kernel text by BLAKE2b-256. #[test] fn a06_program_json_hashes_every_kernel_text() { let e = epoch("mx8-devnet-epoch0"); let out = export_pack(&e, &day_label("mx8-devnet-epoch0"), "test"); let file = |n: &str| out.files.iter().find(|(f, _)| f == n).map(|(_, t)| t.clone()).unwrap(); - let j: Value = serde_json::from_str(&file("program.json")).unwrap(); + let j: Value = serde_json::from_str(&file("identity.json")).unwrap(); let h = j["kernel_blake2b256"].as_object().expect("kernel_blake2b256"); + assert_eq!(j["program_id"].as_str().unwrap(), format!("{:#018x}", e.program.program_id())); for n in ["kernel.cu", "kernel.cl", "program.metal", "program_bound.metal", "kernel_bound.cu", "kernel_bound.cl"] { let want: String = igneum_pow::blake2b::blake2b_256(&[file(n).as_bytes()]).iter().map(|x| format!("{x:02x}")).collect(); assert_eq!(h[n].as_str().unwrap(), want, "{n}"); diff --git a/igneum-pow/tests/v6fold.rs b/igneum-pow/tests/v6fold.rs index b67eb9756..63c18662f 100644 --- a/igneum-pow/tests/v6fold.rs +++ b/igneum-pow/tests/v6fold.rs @@ -367,8 +367,11 @@ fn plain_class_draw_is_byte_identical_to_the_pinned_pack() { let e = Epoch { program, dataset }; assert_eq!(e.program.program_id(), PINNED_ID); let out = export_pack(&e, &format!("bytes:{DAY_HEX}"), SOURCE); - assert_eq!(out.files.len(), 12, "the pack's twelve files"); + assert_eq!(out.files.len(), 13, "the pack's thirteen files"); for (name, text) in &out.files { + if name == "identity.json" { + continue; // A06's identity file is new beside the pinned twelve + } let want = pinned(name); assert!(text == &want, "mx8-devnet-epoch0/{name} differs from the default path's export"); } From 2b9db11bb1eeb7692bf413010328562ce9c57092 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Thu, 8 Oct 2026 19:00:05 +0000 Subject: [PATCH 14/36] class-v6: review B's F03 and F05 (8 October 2026). F03: ProgramClass::V6 in the canonical enum, GENERATOR_VERSION_V6 = 6, V6_CLASS = mx8+sh256x27+state+reg64c+fold+rw (layer 8 off the fifth flag); every class carrying a v6 flag draws as generator 6 under an era, the packs read program_class "v6", the pack check treats v6 as a state class; class v5 and below untouched. F05: the reg64 full-chain address source in closed form (verify::reg64_address_source: r[s] ^ ror(P_s, 1) ^ (S ^ P_s ^ a[s]) with a[k] = rotl(r[k], (63 - k) mod 32)) proven equal to the reference fold on every source register over 256 drawn register states and a real update sequence, the known-failed one-rotation-off form disagreeing; the verifier keeps the fold as the definition. Co-Authored-By: Claude Fable 5.1 --- igneum-pow/src/emit.rs | 6 ++- igneum-pow/src/generator.rs | 27 ++++++++++-- igneum-pow/src/packcheck.rs | 6 +-- igneum-pow/src/verify.rs | 88 +++++++++++++++++++++++++++++++++++++ igneum-pow/tests/v6fold.rs | 27 ++++++++++++ 5 files changed, 147 insertions(+), 7 deletions(-) diff --git a/igneum-pow/src/emit.rs b/igneum-pow/src/emit.rs index 367b668a5..c849f3cc9 100644 --- a/igneum-pow/src/emit.rs +++ b/igneum-pow/src/emit.rs @@ -255,7 +255,11 @@ fn program_class_header_lines(p: &Program) -> String { return String::new(); } let mut s = String::new(); - if p.program_class() == ProgramClass::V5 { + if p.program_class() == ProgramClass::V6 { + s.push_str("// Program class v6 (the Igneum 2.0 D1 object, docs/design/class-v6-rotating-family.md): generator version 6, class v5's\n"); + s.push_str("// stored-state dataset with the index fold, the re-weight table and the 64-register window (the v6 flags in the class\n"); + s.push_str("// string); a worker that runs another class refuses this pack, and a job line names the class it wants (class=v6 era=).\n"); + } else if p.program_class() == ProgramClass::V5 { s.push_str("// Program class v5 (proof of stored state and of following, docs/design/class-v5-stored-state.md): generator version 5,\n"); s.push_str("// class v4 over a dataset whose every item is keyed by the window's execution state (IGNEUM_STATE_* below, leaves.bin);\n"); s.push_str("// a worker that runs another class refuses this pack, and a job line names the class it wants (class=v5 era=).\n"); diff --git a/igneum-pow/src/generator.rs b/igneum-pow/src/generator.rs index 8f30ee48b..b4f82ba37 100644 --- a/igneum-pow/src/generator.rs +++ b/igneum-pow/src/generator.rs @@ -963,6 +963,10 @@ pub const GENERATOR_VERSION_V4: u32 = 4; /// Generator version of a class v5 program (proof of stored state and of following, 7 October 2026, PROPOSED: /// `program_id(5, seed, attempt)`; `docs/design/class-v5-stored-state.md`). pub const GENERATOR_VERSION_V5: u32 = 5; +/// Class v6 (the Igneum 2.0 D1 object, 8 October 2026; review B's F03): the class v5 draw with the v6 rules (the index fold, the +/// re-weight table, the 64-register window with the full chain, the five shuffle dimensions and the mad operand rule by +/// construction, layer 8 off when the flag says so), generator 6. +pub const GENERATOR_VERSION_V6: u32 = 6; /// The program class of an epoch (Counter ASIC 2.0, 5 October 2026, `docs/plans/counter-asic-2-rollout.md`): one /// height switch in the node, `program_class_v3_activation_daa`, rounded up to an epoch boundary, decides which @@ -979,6 +983,8 @@ pub enum ProgramClass { /// Class v5 (`docs/design/class-v5-stored-state.md`, behind `program_class_v5_activation_daa`): class v4's program /// over a dataset whose every item is keyed by the window's execution state ([`V5_CLASS`]), generator 5. V5, + /// Class v6 (the Igneum 2.0 D1 object; review B's F03, 8 October 2026): [`V6_CLASS`], generator 6. + V6, } /// The load class of program class v3, decided 5 October 2026 (Counter ASIC 2.0, `docs/plans/counter-asic-2-status.md` @@ -1001,6 +1007,9 @@ pub const V4_CLASS: LoadClass = LoadClass { shadow: Some(ShadowClass { instrs: V /// program draw, the shadow block, the era draw and the ladder rung are class v4's, draw for draw; only the item /// derivation and the program id change. pub const V5_CLASS: LoadClass = LoadClass { state: true, ..V4_CLASS }; +/// The class v6 object ("mx8+sh256x27+state+reg64c+fold+rw"): class v5 with the index fold, the k lane's re-weight table +/// and the 64-register window with the full chain; layer 8 off is the fifth flag, drawn by the chain's family flags. +pub const V6_CLASS: LoadClass = LoadClass { fold: true, rw: 1, reg64: true, reg64_chain: true, ..V5_CLASS }; /// The shadow block size of class v4 at every rung of the latency ladder (`docs/design/latency-ladder.md`): 256 /// instructions. The ladder moves the pass count alone. @@ -1065,6 +1074,8 @@ pub fn era_generator_of(base: &LoadClass) -> u32 { match ProgramClass::of_load_class(base) { Some(ProgramClass::V4) => GENERATOR_VERSION_V4, Some(ProgramClass::V5) => GENERATOR_VERSION_V5, + Some(ProgramClass::V6) => GENERATOR_VERSION_V6, + _ if base.is_v6() => GENERATOR_VERSION_V6, _ if base.state => GENERATOR_VERSION_V5, _ => GENERATOR_VERSION_V3, } @@ -1095,6 +1106,7 @@ impl ProgramClass { ProgramClass::V3 => V3_CLASS, ProgramClass::V4 => V4_CLASS, ProgramClass::V5 => V5_CLASS, + ProgramClass::V6 => V6_CLASS, } } @@ -1105,12 +1117,13 @@ impl ProgramClass { ProgramClass::V3 => GENERATOR_VERSION_V3, ProgramClass::V4 => GENERATOR_VERSION_V4, ProgramClass::V5 => GENERATOR_VERSION_V5, + ProgramClass::V6 => GENERATOR_VERSION_V6, } } /// Whether the class's dataset is keyed by the window's execution state (class v5). pub fn has_state(&self) -> bool { - *self == ProgramClass::V5 + matches!(self, ProgramClass::V5 | ProgramClass::V6) } /// The class of a generator version: 2, 3 and 4 are the three classes, anything else is no class this crate runs. @@ -1120,6 +1133,7 @@ impl ProgramClass { GENERATOR_VERSION_V3 => Some(ProgramClass::V3), GENERATOR_VERSION_V4 => Some(ProgramClass::V4), GENERATOR_VERSION_V5 => Some(ProgramClass::V5), + GENERATOR_VERSION_V6 => Some(ProgramClass::V6), _ => None, } } @@ -1131,6 +1145,7 @@ impl ProgramClass { ProgramClass::V3 => "v3", ProgramClass::V4 => "v4", ProgramClass::V5 => "v5", + ProgramClass::V6 => "v6", } } @@ -1140,6 +1155,7 @@ impl ProgramClass { "v3" => Some(ProgramClass::V3), "v4" => Some(ProgramClass::V4), "v5" => Some(ProgramClass::V5), + "v6" => Some(ProgramClass::V6), _ => None, } } @@ -1153,6 +1169,7 @@ impl ProgramClass { /// is v3, [`V4_CLASS`] is v4; a measurement class (a width, a derivation length, another shadow size) is none. pub fn of_load_class(class: &LoadClass) -> Option { let base = LoadClass { era: None, reg64: false, reg64_chain: false, ..*class }; + let v6base = LoadClass { era: None, nowin: false, ..*class }; if base == LoadClass::V2 { Some(ProgramClass::V2) } else if base == V3_CLASS { @@ -1161,6 +1178,8 @@ impl ProgramClass { Some(ProgramClass::V4) } else if base == V5_CLASS { Some(ProgramClass::V5) + } else if v6base == V6_CLASS { + Some(ProgramClass::V6) } else { None } @@ -1356,6 +1375,7 @@ impl Program { GENERATOR_VERSION_V3 => ProgramClass::V3, GENERATOR_VERSION_V4 => ProgramClass::V4, GENERATOR_VERSION_V5 => ProgramClass::V5, + GENERATOR_VERSION_V6 => ProgramClass::V6, _ => ProgramClass::V2, } } @@ -2029,6 +2049,7 @@ pub fn generate_from_seed_bytes_program_class(seed_string: &str, seed_bytes: &[u (ProgramClass::V3, Some(era)) => return generate_era(seed_string, seed_bytes, V3_CLASS, era, &V3_ALLOWED), (ProgramClass::V4, Some(era)) => return generate_era_generator(seed_string, seed_bytes, V4_CLASS, era, &V3_ALLOWED, GENERATOR_VERSION_V4), // Class v5: the same draw inside V5_CLASS (V4_CLASS plus the state flag, which the draw does not read), generator 5. + (ProgramClass::V6, Some(era)) => return generate_era_generator(seed_string, seed_bytes, V6_CLASS, era, &V3_ALLOWED, GENERATOR_VERSION_V6), (ProgramClass::V5, Some(era)) => return generate_era_generator(seed_string, seed_bytes, V5_CLASS, era, &V3_ALLOWED, GENERATOR_VERSION_V5), _ => {} } @@ -2046,11 +2067,11 @@ pub fn generate_from_seed_bytes_program_class(seed_string: &str, seed_bytes: &[u /// and class v4 at rung 0, is [`generate_from_seed_bytes_program_class`] byte for byte. The base program, the 16 loads /// and the era draw do not move with the rung: only the pass count of the shadow block does. pub fn generate_from_seed_bytes_program_class_shadow(seed_string: &str, seed_bytes: &[u8], class: ProgramClass, era_bytes: Option<&[u8]>, shadow_reps: u16) -> Program { - if !matches!(class, ProgramClass::V4 | ProgramClass::V5) || shadow_reps == 0 || shadow_reps == V4_SHADOW_REPS { + if !matches!(class, ProgramClass::V4 | ProgramClass::V5 | ProgramClass::V6) || shadow_reps == 0 || shadow_reps == V4_SHADOW_REPS { return generate_from_seed_bytes_program_class(seed_string, seed_bytes, class, era_bytes); } // class v5 at a rung: class v4's rung with the state flag, generator 5 - let (base, generator) = if class == ProgramClass::V5 { (v5_class_at(shadow_reps), GENERATOR_VERSION_V5) } else { (v4_class_at(shadow_reps), GENERATOR_VERSION_V4) }; + let (base, generator) = if class == ProgramClass::V6 { (LoadClass { fold: true, rw: 1, reg64: true, reg64_chain: true, ..v5_class_at(shadow_reps) }, GENERATOR_VERSION_V6) } else if class == ProgramClass::V5 { (v5_class_at(shadow_reps), GENERATOR_VERSION_V5) } else { (v4_class_at(shadow_reps), GENERATOR_VERSION_V4) }; match era_bytes { Some(era) => generate_era_generator(seed_string, seed_bytes, base, era, &V3_ALLOWED, generator), None => { diff --git a/igneum-pow/src/packcheck.rs b/igneum-pow/src/packcheck.rs index a7cbea7f5..b75e5a073 100644 --- a/igneum-pow/src/packcheck.rs +++ b/igneum-pow/src/packcheck.rs @@ -199,14 +199,14 @@ pub fn verify_pack_texts_chain( // carries IGNEUM_STATE_ROOT_HEX (and the shadow block of v4) and no other generator does. let state_root_hex = define_str(program_h, "IGNEUM_STATE_ROOT_HEX"); match (class, state_root_hex.is_some()) { - (ProgramClass::V5, false) => return Err(PackFault::Disagree("IGNEUM_GENERATOR 5 (class v5) without IGNEUM_STATE_ROOT_HEX: not a class v5 pack".into())), - (ProgramClass::V5, true) => {} + (ProgramClass::V5 | ProgramClass::V6, false) => return Err(PackFault::Disagree("IGNEUM_GENERATOR 5 or 6 (a state class) without IGNEUM_STATE_ROOT_HEX: not a class v5 pack".into())), + (ProgramClass::V5 | ProgramClass::V6, true) => {} (_, true) => return Err(PackFault::Disagree(format!("IGNEUM_GENERATOR {generator} with class v5 state lines: a program over state leaves is generator 5 (export the pack as class v5)"))), _ => {} } match (class, shadow > 0) { (ProgramClass::V4, false) => return Err(PackFault::Disagree("IGNEUM_GENERATOR 4 (class v4) without IGNEUM_SHADOW_INSTRS: not a class v4 pack".into())), - (ProgramClass::V5, false) => return Err(PackFault::Disagree("IGNEUM_GENERATOR 5 (class v5) without IGNEUM_SHADOW_INSTRS: not a class v5 pack".into())), + (ProgramClass::V5 | ProgramClass::V6, false) => return Err(PackFault::Disagree("IGNEUM_GENERATOR 5 or 6 (a state class) without IGNEUM_SHADOW_INSTRS: not a class v5 pack".into())), // the class v4 stream sub-version (AP-F8-1 amendment, 7 October 2026): a generator 4 pack from before the // load-source rule carries no IGNEUM_PROGRAM_SUBVERSION and its program id is another stream's; refused (ProgramClass::V4, true) if define_u32(program_h, "IGNEUM_PROGRAM_SUBVERSION") != Some(u32::from(crate::generator::PROGRAM_SUBVERSION_V4)) => { diff --git a/igneum-pow/src/verify.rs b/igneum-pow/src/verify.rs index 75ea927b1..c0dc217b8 100644 --- a/igneum-pow/src/verify.rs +++ b/igneum-pow/src/verify.rs @@ -1172,3 +1172,91 @@ mod tests { assert!(!e.verify_block(0, w[0] - 1)); } } + + +/// Review B's F05 (8 October 2026): the reg64 full-chain address source in closed form. The reference fold +/// (`m = r[k0]; m = rotl(m, 1) ^ r[k1]; ...` over the 63 registers other than `s`, in index order) equals +/// `r[s] ^ ror(P_s, 1) ^ (S ^ P_s ^ a[s])` with `a[k] = rotl(r[k], (63 - k) mod 32)`, `S` the xor of every `a[k]` +/// and `P_s` the xor of `a[k]` for `k < s`: a prefix-xor structure answers every load from one `S` and one prefix, +/// which is the incremental form a chip would keep. The verifier keeps the fold as the definition; this form is the +/// test's and the fleet's measurement's. +pub fn reg64_address_source(r: &[u32; 64], s: usize) -> u32 { + let a = |k: usize| r[k].rotate_left(((63 - k) % 32) as u32); + let mut total = 0u32; + let mut prefix = 0u32; + for k in 0..64 { + total ^= a(k); + if k < s { + prefix ^= a(k); + } + } + r[s] ^ prefix.rotate_right(1) ^ (total ^ prefix ^ a(s)) +} + +/// The reference fold of [`reg64_address_source`] on one lane's registers, as `interpret_warp_core` computes it. +pub fn reg64_address_source_reference(r: &[u32; 64], s: usize) -> u32 { + let mut m = 0u32; + let mut started = false; + for (k, &v) in r.iter().enumerate() { + if k == s { + continue; + } + m = if started { m.rotate_left(1) ^ v } else { v }; + started = true; + } + r[s] ^ m +} + +#[cfg(test)] +mod reg64_mix_tests { + use super::*; + + /// Review B's F05, known-failed first: a form with one rotation off (every term rotated as if it sat after the + /// source) disagrees with the reference on some source; the closed form agrees on every source register over + /// 256 register states drawn from a fixed stream and over the states a real program leaves in its registers. + #[test] + fn reg64_closed_form_equals_the_reference_fold_on_every_source() { + let wrong = |r: &[u32; 64], s: usize| -> u32 { + let a = |k: usize| r[k].rotate_left(((63 - k) % 32) as u32); + let total: u32 = (0..64).map(a).fold(0, |x, y| x ^ y); + r[s] ^ total ^ a(s) + }; + let mut x = 0x9e37_79b9_7f4a_7c15u64; + let mut next = || { + x = x.wrapping_add(0x9e37_79b9_7f4a_7c15); + let mut z = x; + z = (z ^ (z >> 30)).wrapping_mul(0xbf58_476d_1ce4_e5b9); + z = (z ^ (z >> 27)).wrapping_mul(0x94d0_49bb_1331_11eb); + (z ^ (z >> 31)) as u32 + }; + let mut wrong_differs = false; + for _ in 0..256 { + let mut r = [0u32; 64]; + for v in r.iter_mut() { + *v = next(); + } + for s in 0..64 { + assert_eq!(reg64_address_source(&r, s), reg64_address_source_reference(&r, s), "source r{s}"); + if wrong(&r, s) != reg64_address_source_reference(&r, s) { + wrong_differs = true; + } + } + } + assert!(wrong_differs, "the known-failed form must disagree somewhere"); + // the init rule's registers (r0..r7 seeded, r[k] = r[k & 7] * 0x9e3779b9 + k) and a few real updates + let mut r = [0u32; 64]; + for (k, v) in r.iter_mut().enumerate().take(8) { + *v = next() ^ (k as u32); + } + for k in 8..64 { + r[k] = r[k & 7].wrapping_mul(0x9e37_79b9).wrapping_add(k as u32); + } + for step in 0..64 { + let d = (step * 7 + 3) % 64; + r[d] = r[d].wrapping_mul(r[(d + 13) % 64]).wrapping_add(next()); + for s in 0..64 { + assert_eq!(reg64_address_source(&r, s), reg64_address_source_reference(&r, s), "step {step} source r{s}"); + } + } + } +} diff --git a/igneum-pow/tests/v6fold.rs b/igneum-pow/tests/v6fold.rs index 63c18662f..c5c87f7d1 100644 --- a/igneum-pow/tests/v6fold.rs +++ b/igneum-pow/tests/v6fold.rs @@ -264,6 +264,33 @@ fn every_v6_flag_keeps_the_class_v4_acceptance_shape() { assert!(!is_class_v4_shape(&V3_CLASS) && !is_class_v4_shape(&LoadClass::V2)); } +/// Review B's F03 (8 October 2026): class v6 is a program class of its own, generator 6: the object class names it, +/// every class carrying a v6 flag draws as generator 6 under an era, the pack's program_class reads "v6", and the +/// class v5 draw and its generator number do not move. +#[test] +fn program_class_v6_is_generator_6() { + use igneum_pow::generator::{era_generator_of, GENERATOR_VERSION_V5, GENERATOR_VERSION_V6, V6_CLASS}; + assert_eq!(ProgramClass::parse("v6"), Some(ProgramClass::V6)); + assert_eq!(ProgramClass::V6.name(), "v6"); + assert_eq!(ProgramClass::V6.generator_version(), GENERATOR_VERSION_V6); + assert_eq!(ProgramClass::from_generator(6), Some(ProgramClass::V6)); + assert!(ProgramClass::V6.has_state()); + assert_eq!(ProgramClass::V6.load_class(), V6_CLASS); + assert_eq!(V6_CLASS.name(), "mx8+sh256x27+state+reg64c+fold+rw"); + assert_eq!(ProgramClass::of_load_class(&V6_CLASS), Some(ProgramClass::V6)); + assert_eq!(ProgramClass::of_load_class(&V6_CLASS.with_nowin()), Some(ProgramClass::V6)); + assert_eq!(ProgramClass::of_load_class(&V5_CLASS), Some(ProgramClass::V5)); + let era = f8_bytes("era", 4); + for c in [V6_CLASS, V6_CLASS.with_nowin(), V5_CLASS.with_fold(), V5_CLASS.with_rw(1), V5_CLASS.with_nowin()] { + assert_eq!(era_generator_of(&LoadClass::era(c, &era, &V3_ALLOWED)), GENERATOR_VERSION_V6, "{}", c.name()); + } + assert_eq!(era_generator_of(&LoadClass::era(V5_CLASS, &era, &V3_ALLOWED)), GENERATOR_VERSION_V5); + let seed = f8_bytes("program", 4); + let p = candidate_class("p-f03", &seed, 0, LoadClass::era(V6_CLASS, &era, &V3_ALLOWED)); + assert!(p.class.name().starts_with("mx8-era") && p.class.name().ends_with("+sh256x27+state+reg64c+fold+rw"), "{}", p.class.name()); + assert_eq!(p.generator, GENERATOR_VERSION_V6); +} + /// 2. The fold's form: `y = x * M; y ^= y >> 16; y = rotl(y, R)`, and nothing else moves. The plain era's stride is /// `rotl(x * M, R)` byte for byte. #[test] From 13a55b9be87d0f43d9abb2024d360476c0c0a968 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Thu, 8 Oct 2026 19:00:46 +0000 Subject: [PATCH 15/36] class-v6: the mixer determinism test skips identity.json beside the pinned pack (A06's thirteenth file) Co-Authored-By: Claude Fable 5.1 --- igneum-pow/tests/mixer.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/igneum-pow/tests/mixer.rs b/igneum-pow/tests/mixer.rs index f4644ae8d..43ddeeb41 100644 --- a/igneum-pow/tests/mixer.rs +++ b/igneum-pow/tests/mixer.rs @@ -347,8 +347,8 @@ fn determinism_v3() { }; println!("determinism {}: two builds equal, against the pinned pack {}", class.name(), dir.display()); for (name, text) in &pa.files { - if name == "vectors.json" || name == "vectors.h" { - continue; // the source string differs ("a" here) + if name == "vectors.json" || name == "vectors.h" || name == "identity.json" { + continue; // the source string differs ("a" here); identity.json is new beside the pinned twelve (A06) } let on_disk = std::fs::read_to_string(dir.join(name)).unwrap(); assert_eq!(&on_disk, text, "{name}"); From a2af737168b589a5eda76ed99cc20b5abfbc7e94 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Thu, 8 Oct 2026 19:02:00 +0000 Subject: [PATCH 16/36] class-v6: the acceptance's class v4 shape predicate and the draw's source rule set the era's drawn width aside (lane D's second finding: a multi-width era wrote the drawn width into mix and fell to the class v2 parts); test: the shape holds at every width of the family Co-Authored-By: Claude Fable 5.1 --- igneum-pow/src/accept.rs | 4 +++- igneum-pow/src/generator.rs | 2 +- igneum-pow/tests/v6fold.rs | 6 ++++++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/igneum-pow/src/accept.rs b/igneum-pow/src/accept.rs index 51ef435f3..f96ab824b 100644 --- a/igneum-pow/src/accept.rs +++ b/igneum-pow/src/accept.rs @@ -491,7 +491,9 @@ pub fn is_class_v4_shape(class: &LoadClass) -> bool { // not the shape) // the window and layer 8 off are set aside too (lane D's finding of 8 October 2026, 19:1x UK: a +nowin or +reg64c // program was judged by the class v2 parts alone on the chain's path; the harness's own predicate hid it) - && LoadClass { era: None, shadow: None, state: false, fold: false, rw: 0, nowin: false, reg64: false, reg64_chain: false, ..*class } == LoadClass { shadow: None, ..V4_CLASS } + // and the era's drawn width (lane D's second finding, 20:0x UK: an era whose width set has more than one width + // writes the drawn width into `mix`, and the rule must judge every width of the family, not the pinned one alone) + && LoadClass { era: None, shadow: None, state: false, fold: false, rw: 0, nowin: false, reg64: false, reg64_chain: false, mix: V4_CLASS.mix, ..*class } == LoadClass { shadow: None, ..V4_CLASS } } /// One pass of the dataflow freshness over the base program then the shadow block (the order of one iteration), diff --git a/igneum-pow/src/generator.rs b/igneum-pow/src/generator.rs index b4f82ba37..8adcc1f95 100644 --- a/igneum-pow/src/generator.rs +++ b/igneum-pow/src/generator.rs @@ -1725,7 +1725,7 @@ pub fn candidate_from_words_class( // class v6 lane 1: the index fold and the re-weight table are set aside too (the address path and the table are not // the shape; a +fold or +rw program draws its sources under the same rule) let source_rule_v4 = matches!(class.shadow, Some(ShadowClass { instrs: V4_SHADOW_INSTRS, .. })) - && LoadClass { era: None, shadow: None, state: false, fold: false, rw: 0, nowin: false, reg64: false, reg64_chain: false, ..class } == LoadClass { shadow: None, ..V4_CLASS }; + && LoadClass { era: None, shadow: None, state: false, fold: false, rw: 0, nowin: false, reg64: false, reg64_chain: false, mix: V4_CLASS.mix, ..class } == LoadClass { shadow: None, ..V4_CLASS }; // the op table and the roll's range: the plain table at 75 for every class without the re-weight flag let (weights, weights_sum) = class.nonload_weights(); let mut fresh = [false; 8]; diff --git a/igneum-pow/tests/v6fold.rs b/igneum-pow/tests/v6fold.rs index c5c87f7d1..3a92726be 100644 --- a/igneum-pow/tests/v6fold.rs +++ b/igneum-pow/tests/v6fold.rs @@ -262,6 +262,12 @@ fn every_v6_flag_keeps_the_class_v4_acceptance_shape() { assert_eq!(max_attempts_for(&c), max_attempts_for(&V5_CLASS), "{}: the same attempt cap and last resort", c.name()); } assert!(!is_class_v4_shape(&V3_CLASS) && !is_class_v4_shape(&LoadClass::V2)); + // lane D's second finding: an era drawn from a width set with more than one width writes the drawn width into + // `mix`; the shape (and so the full rule) must hold at every width of the family + let wide = LoadClass::era(V5_CLASS, &f8_bytes("era", 4), &[1u8, 4, 16]); + assert!(wide.era.is_some()); + assert!(is_class_v4_shape(&wide), "{} (mix {:?})", wide.name(), wide.mix); + assert!(is_class_v4_shape(&LoadClass::era(all, &f8_bytes("era", 9), &[1u8, 4, 16]))); } /// Review B's F03 (8 October 2026): class v6 is a program class of its own, generator 6: the object class names it, From 2e656055f5185f3732f5f3b3a37ad023b4d4910f Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Thu, 8 Oct 2026 19:04:30 +0000 Subject: [PATCH 17/36] class-v6: review B's F05 measurement text: igneum-pow export --reg64-prefix writes the CUDA kernels with the reg64 chain in its closed prefix form (S the running xor of the rotated registers, updated after every base and shadow write; a load's source r[s] ^ ror(P_s, 1) ^ S ^ P_s ^ a[s]); the same hash and vectors, OpenCL and Metal keep the fold; a tool switch, no object change Co-Authored-By: Claude Fable 5.1 --- igneum-pow/src/emit.rs | 69 ++++++++++++++++++++++++++++++++++++++++-- igneum-pow/src/main.rs | 4 ++- 2 files changed, 70 insertions(+), 3 deletions(-) diff --git a/igneum-pow/src/emit.rs b/igneum-pow/src/emit.rs index c849f3cc9..1d2a18720 100644 --- a/igneum-pow/src/emit.rs +++ b/igneum-pow/src/emit.rs @@ -507,8 +507,16 @@ fn shadow_block(p: &Program, dialect: CoreDialect) -> String { )); let ty = if dialect == CoreDialect::Cuda { "uint32_t" } else { "uint" }; s.push_str(&format!(" for ({ty} sh = 0u; sh < {reps}u; ++sh) {{\n")); + let prefix = dialect == CoreDialect::Cuda && p.address_mix() && reg64_prefix(); for (k, ins) in p.shadow.iter().enumerate() { + if prefix { + // F05 prefix form: the shadow's writes move S too (the fold reads the live registers) + s.push_str(&format!(" t_ = {};\n", reg64_term(ins.dst as usize))); + } s.push_str(&format!(" {} // s{k} {}\n", shadow_instr_line(dialect, ins), ins.op.name())); + if prefix { + s.push_str(&format!(" S ^= t_ ^ {};\n", reg64_term(ins.dst as usize))); + } } s.push_str(" }\n"); s @@ -1165,13 +1173,60 @@ fn reg_decl(p: &Program, ty: &str) -> String { return format!(" {ty} r0, r1, r2, r3, r4, r5, r6, r7;\n"); } let names: Vec = (0..p.registers()).map(|k| format!("r{k}")).collect(); - let m = if p.address_mix() { format!("\n {ty} m; // reg64 full chain: the address mix of all 64 registers before every load") } else { String::new() }; + let m = if p.address_mix() { + if ty == "uint32_t" && reg64_prefix() { + format!("\n {ty} m, S, p_, t_; // reg64 full chain in the F05 prefix form: S the running xor of the rotated registers, p_ the prefix, t_ the old term") + } else { + format!("\n {ty} m; // reg64 full chain: the address mix of all 64 registers before every load") + } + } else { + String::new() + }; format!(" {ty} {}; // reg64: 64 live registers per lane (two 32-register windows){m}\n", names.join(", ")) } /// reg64 full chain: the mix statement before a load, `m = r0; m = rotl_imm(m, 1u) ^ r1; ... ^ r63;` over the 63 /// registers other than the load's source `src` (the verifier's `addr_src`, the same chain), one line; the same /// text in the three dialects (`rotl_imm` is defined in each). +/// Review B's F05 (8 October 2026): the CUDA texts carry the reg64 address mix in its closed prefix form when this +/// switch is on (`igneum-pow export --reg64-prefix`): `S` is the xor of `a[k] = rotl(r[k], (63 - k) mod 32)` over +/// the 64 registers, kept per lane and updated after every write; a load's source is +/// `r[s] ^ ror(P_s, 1) ^ (S ^ P_s ^ a[s])` with `P_s` the xor of the first `s` terms. The same hash, the same vectors +/// (`verify::reg64_address_source`); a measurement text for the fleet, never the definition. OpenCL and Metal keep +/// the fold. +static REG64_PREFIX: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false); + +pub fn set_reg64_prefix(on: bool) { + REG64_PREFIX.store(on, std::sync::atomic::Ordering::Relaxed); +} + +pub fn reg64_prefix() -> bool { + REG64_PREFIX.load(std::sync::atomic::Ordering::Relaxed) +} + +/// `rotl(rK, (63 - k) mod 32)` as text; a rotation of 0 is the register itself (`rotl_imm` takes 1..31). +fn reg64_term(k: usize) -> String { + let n = (63 - k) % 32; + if n == 0 { format!("r{k}") } else { format!("rotl_imm(r{k}, {n}u)") } +} + +/// The prefix-form mix statement before a load of source `src` (the F05 text): `m = ror(P, 1) ^ S ^ P ^ a[src]`. +fn reg64_prefix_mix_line(src: u8) -> String { + let s = src as usize; + let prefix: Vec = (0..s).map(reg64_term).collect(); + let p = if prefix.is_empty() { "0u".to_string() } else { prefix.join(" ^ ") }; + format!("p_ = {p}; m = rotr_var(p_, 1u) ^ S ^ p_ ^ {};", reg64_term(s)) +} + +/// The prefix form's running total after the register init: `S = a[0] ^ ... ^ a[63]`. +fn reg64_prefix_init(p: &Program) -> String { + if !p.class.reg64 || !p.address_mix() || !reg64_prefix() { + return String::new(); + } + let terms: Vec = (0..p.registers()).map(reg64_term).collect(); + format!(" // F05 prefix form: the running xor of every rotated register\n S = {};\n", terms.join(" ^ ")) +} + fn reg64_mix_line(p: &Program, src: u8) -> String { let mut s = String::new(); for k in 0..p.registers() { @@ -1227,8 +1282,13 @@ fn cuda_instr_lines(p: &Program, geom: DatasetGeom) -> String { let d = format!("r{}", ins.dst); let a = format!("r{}", ins.src); let b = format!("r{}", ins.src2); + let prefix = address_mix && reg64_prefix(); if address_mix && ins.op == Op::Load { - s.push_str(&format!(" {}\n", reg64_mix_line(p, ins.src))); + s.push_str(&format!(" {}\n", if prefix { reg64_prefix_mix_line(ins.src) } else { reg64_mix_line(p, ins.src) })); + } + if prefix { + // the old term of the destination, so S can drop it after the write + s.push_str(&format!(" t_ = {};\n", reg64_term(ins.dst as usize))); } let line = match ins.op { // Metal select(A, B, c) returns c ? B : A, so the true branch is imm2 here as well. @@ -1256,6 +1316,9 @@ fn cuda_instr_lines(p: &Program, geom: DatasetGeom) -> String { Op::Hot => hot_stmt(CoreDialect::Cuda, &d, &a), }; s.push_str(&format!(" {line} // {k} {}\n", ins.op.name())); + if prefix { + s.push_str(&format!(" S ^= t_ ^ {};\n", reg64_term(ins.dst as usize))); + } } s } @@ -1375,6 +1438,7 @@ pub fn cuda_kernel_geom(p: &Program, memhard: Option<&MixParams>, geom: DatasetG s.push_str(&init_line(p, "uint32_t", i)); } s.push_str(®64_init(p)); + s.push_str(®64_prefix_init(p)); s.push_str(&format!("\n for (uint32_t it = 0u; it < {ITERATIONS}u; ++it) {{\n uint32_t sel = r0;\n")); s.push_str(&cuda_instr_lines(p, geom)); s.push_str(&shadow_block(p, CoreDialect::Cuda)); @@ -1540,6 +1604,7 @@ pub fn cuda_kernel_bound_geom(p: &Program, memhard: Option<&MixParams>, geom: Da )); } s.push_str(®64_init(p)); + s.push_str(®64_prefix_init(p)); s.push_str(&format!("\n for (uint32_t it = 0u; it < {ITERATIONS}u; ++it) {{\n uint32_t sel = r0;\n")); s.push_str(&cuda_instr_lines(p, geom)); s.push_str(&shadow_block(p, CoreDialect::Cuda)); diff --git a/igneum-pow/src/main.rs b/igneum-pow/src/main.rs index 4e3ddb224..205f6ce66 100644 --- a/igneum-pow/src/main.rs +++ b/igneum-pow/src/main.rs @@ -122,7 +122,8 @@ fn usage() -> ! { \x20 --era-widths 4[,16,32,64] the width set the era draws from, in bytes (default 4: pinned; more lets the era draw it; 32 only with the w32 class)\n\ \x20 --dataset-words N research class ds55: the dataset at N words (a multiple of 65,536 in 2^28 ..= 2^31; 1476395008 = 5.5 GiB); a non-power-of-two uses idx = (src * N) >> 32 in every load (spec 01 section 1.13.3), a power of two is --dataset-log2\n\\ \x20 --reg64 the 64-register window per lane over the class (research; the same as --class +reg64; CUDA, OpenCL and Metal texts)\n\ - \x20 --reg64-chain reg64 with the full-chain address mix: every load's address consumes all 64 registers (the same as --class +reg64c)" + \x20 --reg64-chain reg64 with the full-chain address mix: every load's address consumes all 64 registers (the same as --class +reg64c)\n\ + \x20 --reg64-prefix export: the CUDA texts carry the reg64 chain in its closed prefix form (review B's F05; the same hash and vectors, a measurement text)" ); std::process::exit(2) } @@ -189,6 +190,7 @@ fn parse() -> Args { a.reg64 = true; a.reg64_chain = true; } + "--reg64-prefix" => igneum_pow::emit::set_reg64_prefix(true), _ => usage(), } } From 38128dff05137c25d87f2a40c0a7651704746ec6 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Thu, 8 Oct 2026 19:05:31 +0000 Subject: [PATCH 18/36] class-v6: the program_classes test counts class v6 (generator 6 is a class now; 7 is none) Co-Authored-By: Claude Fable 5.1 --- igneum-pow/src/generator.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/igneum-pow/src/generator.rs b/igneum-pow/src/generator.rs index 8adcc1f95..168d0c0aa 100644 --- a/igneum-pow/src/generator.rs +++ b/igneum-pow/src/generator.rs @@ -2417,14 +2417,15 @@ mod tests { assert_eq!(v3.program_id(), program_id(GENERATOR_VERSION_V3, &v3.seed, v3.attempt)); assert_ne!(v3.program_id(), program_id(GENERATOR_VERSION, &v3.seed, v3.attempt)); assert_ne!(v3.program_id(), v2.program_id()); - for c in [ProgramClass::V2, ProgramClass::V3, ProgramClass::V4, ProgramClass::V5] { + for c in [ProgramClass::V2, ProgramClass::V3, ProgramClass::V4, ProgramClass::V5, ProgramClass::V6] { assert_eq!(ProgramClass::parse(c.name()), Some(c)); assert_eq!(ProgramClass::from_generator(c.generator_version()), Some(c)); assert_eq!(ProgramClass::from_u8(c.as_u8()), Some(c)); } assert_eq!(ProgramClass::from_generator(1), None); - assert_eq!(ProgramClass::from_generator(6), None); - assert_eq!(ProgramClass::parse("v6"), None); + assert_eq!(ProgramClass::from_generator(6), Some(ProgramClass::V6), "class v6 is generator 6 (review B's F03, 8 October 2026)"); + assert_eq!(ProgramClass::from_generator(7), None); + assert_eq!(ProgramClass::parse("v7"), None); assert_eq!(ProgramClass::default(), ProgramClass::V2); assert_eq!(ProgramClass::V2.load_class(), LoadClass::V2); assert!(!ProgramClass::V2.has_era() && ProgramClass::V3.has_era() && ProgramClass::V4.has_era() && ProgramClass::V5.has_era()); From 533b2d311994405930bc27234740fc08484416a0 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Thu, 8 Oct 2026 19:18:44 +0000 Subject: [PATCH 19/36] class-v6: the pack tests read identity.json as the thirteenth export file beside the pinned twelve (the era, v5, reg64 and file-list tests); the A04 test reads a class v4 program (the shadow is class v4's) Co-Authored-By: Claude Fable 5.1 --- igneum-pow/tests/packs.rs | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/igneum-pow/tests/packs.rs b/igneum-pow/tests/packs.rs index 8cae778ba..40451792f 100644 --- a/igneum-pow/tests/packs.rs +++ b/igneum-pow/tests/packs.rs @@ -433,7 +433,9 @@ fn check_export(pack: &str) { if e.dataset.mode() == DatasetMode::MemoryHard { expected.extend(["memhard.h", "memhard.metal"]); } - assert_eq!(out.files.iter().map(|(n, _)| n.as_str()).collect::>(), expected); + let mut with_identity: Vec<&str> = expected.clone(); + with_identity.insert(1, "identity.json"); + assert_eq!(out.files.iter().map(|(n, _)| n.as_str()).collect::>(), with_identity); let mut on_disk: Vec = std::fs::read_dir(pack_dir(pack)) .unwrap() .map(|d| d.unwrap().file_name().to_string_lossy().to_string()) @@ -646,6 +648,9 @@ fn era_emitted_sources_match_and_loads_have_the_era_form() { let source = era_json(pack, "vectors.json")["source"].as_str().unwrap().to_string(); let out = export_pack(e, &day, &source); for (name, text) in &out.files { + if name == "identity.json" { + continue; // A06's identity file is new beside the pinned files + } let want = era_read(pack, name); assert!(text == &want, "{pack}/{name} differs from the emitter"); } @@ -974,6 +979,9 @@ fn v5_pack_is_the_v4_program_over_the_state_leaves() { let v = v5_json(pack, "vectors.json"); let out = export_pack(e, v["day"].as_str().unwrap(), v["source"].as_str().unwrap()); for (name, text) in &out.files { + if name == "identity.json" { + continue; // A06's identity file is new beside the pinned files + } assert_eq!(v5_read(pack, name), *text, "{pack}/{name} differs from the export"); } for (name, bytes) in &out.binaries { @@ -1034,6 +1042,9 @@ fn reg64_plain_path_reexports_the_pinned_devnet_pack_unchanged() { let out = export_pack(e, &day_label(pack), PINNED_SOURCE); assert_eq!(out.files.len(), 13); for (name, text) in &out.files { + if name == "identity.json" { + continue; // A06's identity file is new beside the pinned twelve + } assert_same_text(pack, name, text); } } @@ -1256,10 +1267,12 @@ fn a07_bound_hash_is_group_aligned_across_tails_and_rollover() { #[test] fn a04_a_zeroing_shadow_fails_acceptance() { use igneum_pow::accept::check; - let e = epoch("mx8-devnet-epoch0"); - assert!(check(&e.program).is_ok()); - let mut z = e.program.clone(); - assert!(!z.shadow.is_empty(), "the pinned class has a shadow block"); + // a class v4 program (the shadow block is class v4's): the same seed and era as the lib's program_classes test + let era = [7u8; 32]; + let p = generate_from_seed_bytes_program_class("igneum-genesis", b"igneum-genesis", ProgramClass::V4, Some(&era)); + assert!(check(&p).is_ok(), "the class v4 program of the genesis seed passes"); + let mut z = p.clone(); + assert!(!z.shadow.is_empty(), "class v4 has a shadow block"); for ins in z.shadow.iter_mut() { ins.op = Op::Xor; ins.src = ins.dst; From 3f949558671a6502fe3197e5cc454fd55815c660 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Thu, 8 Oct 2026 19:24:57 +0000 Subject: [PATCH 20/36] class-v6: the export's file order as the pinned packs carry it (identity.json second, kernels before the headers); the era pack test lists identity.json beside the pinned files Co-Authored-By: Claude Fable 5.1 --- igneum-pow/src/emit.rs | 6 ++++++ igneum-pow/tests/packs.rs | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/igneum-pow/src/emit.rs b/igneum-pow/src/emit.rs index 1d2a18720..fb5ed7d14 100644 --- a/igneum-pow/src/emit.rs +++ b/igneum-pow/src/emit.rs @@ -2701,10 +2701,16 @@ pub fn export_pack(epoch: &Epoch, day: &str, source: &str) -> Pack { (ds.geom.words as u128) * 4, hashes.join(",\n") ); + // the pack's file order as the pinned packs carry it, identity.json second + let mut texts = texts.into_iter(); + let kernel_cu = texts.next().unwrap(); + let kernel_cl = texts.next().unwrap(); let mut files = vec![ ("program.json".to_string(), program_json(p, day, ds)), ("identity.json".to_string(), identity), ("vectors.json".to_string(), vectors_json_geom(p, day, geom, &bases, &outs, &v, source, is_mh)), + kernel_cu, + kernel_cl, ("program.h".to_string(), program_header(p, day, ds)), ("vectors.h".to_string(), vectors_header(p, &bases, &outs, &v, mask, source, is_mh)), ]; diff --git a/igneum-pow/tests/packs.rs b/igneum-pow/tests/packs.rs index 40451792f..cd872c6a5 100644 --- a/igneum-pow/tests/packs.rs +++ b/igneum-pow/tests/packs.rs @@ -660,7 +660,7 @@ fn era_emitted_sources_match_and_loads_have_the_era_form() { .filter(|n| !n.starts_with('.') && n != "seeds.txt") .collect(); on_disk.sort(); - let mut want: Vec = out.files.iter().map(|(n, _)| n.clone()).collect(); + let mut want: Vec = out.files.iter().map(|(n, _)| n.clone()).filter(|n| n != "identity.json").collect(); want.sort(); assert_eq!(on_disk, want, "{pack}: the pack holds the export's files and seeds.txt only"); let era = e.program.class.era.unwrap(); From 98fd170b2d4afbc75f6438e40e3143796718b403 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Thu, 8 Oct 2026 19:33:17 +0000 Subject: [PATCH 21/36] proto-cuda/nvrtc/packfile.h: the pack reader runs generator 6 (class v6) as it runs class v5 (the shadow block and the state leaves required); the kit workers refused the re-exported packs with 'not a generator version this worker runs' Co-Authored-By: Claude Fable 5.1 --- proto-cuda/nvrtc/packfile.h | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/proto-cuda/nvrtc/packfile.h b/proto-cuda/nvrtc/packfile.h index 57e332d0d..e132564c4 100644 --- a/proto-cuda/nvrtc/packfile.h +++ b/proto-cuda/nvrtc/packfile.h @@ -318,11 +318,13 @@ static int pf_load(const char* dir, PfPack* pk, char* err, size_t cap) { * kernel text, so this loader needs nothing new beyond the number and the class token), generator 5 is class v5 * (proof of stored state, 7 October 2026: class v4 over a dataset keyed by the window's state leaves, leaves.bin, * which the host uploads for igneum_build; the kernel text carries the leaf read). */ - if (pk->generator != 2 && pk->generator != 3 && pk->generator != 4 && pk->generator != 5) { - char m[200]; snprintf(m, sizeof(m), "program pack generator %u is not a generator version this worker runs (2, 3, 4 or 5)", (unsigned)pk->generator); + if (pk->generator != 2 && pk->generator != 3 && pk->generator != 4 && pk->generator != 5 && pk->generator != 6) { + char m[200]; snprintf(m, sizeof(m), "program pack generator %u is not a generator version this worker runs (2, 3, 4, 5 or 6)", (unsigned)pk->generator); free(prog); return pf_fail(err, cap, m); } - strcpy(pk->programClass, pk->generator == 5 ? "v5" : pk->generator == 4 ? "v4" : pk->generator == 3 ? "v3" : "v2"); + /* generator 6 (class v6, the Igneum 2.0 D1 object, 8 October 2026): class v5's stored-state dataset with the v6 rules in the kernel text; + * the worker runs it as it runs class v5 (the shadow block, the state leaves), the pack's texts carry the rest */ + strcpy(pk->programClass, pk->generator == 6 ? "v6" : pk->generator == 5 ? "v5" : pk->generator == 4 ? "v4" : pk->generator == 3 ? "v3" : "v2"); { /* Counter ASIC 3.0 (6 October 2026): the shadow block marks class v4. A generator 3 pack with IGNEUM_SHADOW_INSTRS * is a v4 program stamped as v3 (the old export path; it carried the v3 control's program id) and is refused; @@ -330,7 +332,7 @@ static int pf_load(const char* dir, PfPack* pk, char* err, size_t cap) { uint32_t shadow = 0; if (!pf_define_u32(prog, "IGNEUM_SHADOW_INSTRS", &shadow)) shadow = 0; if (pk->generator == 4 && shadow == 0) { free(prog); return pf_fail(err, cap, "program pack generator 4 (class v4) without IGNEUM_SHADOW_INSTRS: not a class v4 pack"); } - if (pk->generator == 5 && shadow == 0) { free(prog); return pf_fail(err, cap, "program pack generator 5 (class v5) without IGNEUM_SHADOW_INSTRS: not a class v5 pack (class v5 is class v4 over the state leaves)"); } + if ((pk->generator == 5 || pk->generator == 6) && shadow == 0) { free(prog); return pf_fail(err, cap, "program pack generator 5 (class v5) without IGNEUM_SHADOW_INSTRS: not a class v5 pack (class v5 is class v4 over the state leaves)"); } if (pk->generator == 3 && shadow != 0) { /* a generator 2 pack with a shadow is the measurement ladder (a class-bearing id) and loads */ char m[220]; snprintf(m, sizeof(m), "program pack generator %u with a shadow block (IGNEUM_SHADOW_INSTRS %u): a class v4 program is generator 4 (export the pack as class v4)", (unsigned)pk->generator, (unsigned)shadow); free(prog); return pf_fail(err, cap, m); @@ -350,8 +352,8 @@ static int pf_load(const char* dir, PfPack* pk, char* err, size_t cap) { pk->stateLeaves = 0; pk->stateLeavesFnv = 0; pk->stateRootHex[0] = 0; pk->stateBlockHex[0] = 0; strcpy(pk->stateLeavesFile, "leaves.bin"); if (!pf_define_u32(prog, "IGNEUM_STATE_LEAVES", &pk->stateLeaves)) pk->stateLeaves = 0; - if (pk->generator == 5 && pk->stateLeaves == 0) { free(prog); return pf_fail(err, cap, "program pack generator 5 (class v5) without IGNEUM_STATE_LEAVES: no state leaves to key the dataset (export the pack with --state)"); } - if (pk->generator != 5 && pk->stateLeaves != 0) { + if ((pk->generator == 5 || pk->generator == 6) && pk->stateLeaves == 0) { free(prog); return pf_fail(err, cap, "program pack generator 5 (class v5) without IGNEUM_STATE_LEAVES: no state leaves to key the dataset (export the pack with --state)"); } + if (pk->generator != 5 && pk->generator != 6 && pk->stateLeaves != 0) { char m[200]; snprintf(m, sizeof(m), "program pack generator %u carries IGNEUM_STATE_LEAVES %u: state leaves belong to class v5 (generator 5)", (unsigned)pk->generator, (unsigned)pk->stateLeaves); free(prog); return pf_fail(err, cap, m); } From c462b526ecde98ec32b93dd49c9d26bae9448823 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Thu, 8 Oct 2026 19:35:01 +0000 Subject: [PATCH 22/36] class-v6: review B's V6-02: loads_per_hash and bytes_per_hash report the executed schedule (256 loads under the window) with the drawn count beside them and an agreement assert; the v6fold pairs draw both sides under the v6 rules (the fold and layer 8 off pairs) Co-Authored-By: Claude Fable 5.1 --- igneum-pow/src/generator.rs | 20 +++++++++++++++++++- igneum-pow/tests/v6fold.rs | 23 ++++++++++++++--------- 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/igneum-pow/src/generator.rs b/igneum-pow/src/generator.rs index 168d0c0aa..89c9b8fb5 100644 --- a/igneum-pow/src/generator.rs +++ b/igneum-pow/src/generator.rs @@ -1241,7 +1241,19 @@ impl Program { } out } + /// Memory operations the hash EXECUTES per nonce (review B's V6-02, 8 October 2026): the scheduled statements + /// (the drawn program's loads, twice under the 64-register window) times the eight iterations. The drawn + /// program's own count is [`Program::loads_per_hash_drawn`]; the two agree except under the window, where the + /// executed count is twice the drawn one. Every served loads figure names this schedule. pub fn loads_per_hash(&self) -> usize { + let drawn = self.loads_per_hash_drawn(); + let executed = self.scheduled().iter().filter(|i| i.op.is_load()).count() * ITERATIONS; + assert!(executed == drawn || (self.class.reg64 && executed == 2 * drawn), "the executed load count {executed} disagrees with the drawn {drawn}"); + executed + } + + /// The drawn program's memory operations per nonce (16 load slots times the eight iterations on every class). + pub fn loads_per_hash_drawn(&self) -> usize { self.instrs.iter().filter(|i| i.op.is_load()).count() * ITERATIONS } pub fn wide_loads_per_hash(&self) -> usize { @@ -1251,8 +1263,14 @@ impl Program { self.instrs.iter().any(|i| i.op == Op::WLoad) } /// Dataset bytes read per hash: 4 per one-word load, 16 and 64 for the wider loads of the experiment. + /// Dataset bytes the hash's EXECUTED loads demand per nonce (review B's V6-02): the scheduled loads' widths in + /// words times 4, times the eight iterations; a demand figure, not the memory's transactions (a 4-byte load is + /// a 32-byte sector on NVIDIA and a 64-byte line on AMD; the served text names the model it quotes). pub fn bytes_per_hash(&self) -> usize { - self.instrs.iter().filter(|i| i.op == Op::Load).map(|i| i.width as usize * 4).sum::() * ITERATIONS + let drawn = self.instrs.iter().filter(|i| i.op == Op::Load).map(|i| i.width as usize * 4).sum::() * ITERATIONS; + let executed = self.scheduled().iter().filter(|i| i.op == Op::Load).map(|i| i.width as usize * 4).sum::() * ITERATIONS; + assert!(executed == drawn || (self.class.reg64 && executed == 2 * drawn), "the executed byte demand {executed} disagrees with the drawn {drawn}"); + executed } /// Scratch read-modify-writes per hash (variant 5): each reads 16 bytes and writes 16 bytes. pub fn scratch_ops_per_hash(&self) -> usize { diff --git a/igneum-pow/tests/v6fold.rs b/igneum-pow/tests/v6fold.rs index 3a92726be..586769663 100644 --- a/igneum-pow/tests/v6fold.rs +++ b/igneum-pow/tests/v6fold.rs @@ -195,8 +195,10 @@ fn nowin_removes_the_window_layer_and_nothing_else() { assert!(!V5_CLASS.nowin); let era = f8_bytes("era", 4); let seed = f8_bytes("program", 4); - let plain = candidate_class("p4-attack-f8", &seed, 0, LoadClass::era(V5_CLASS, &era, &V3_ALLOWED)); - let off = candidate_class("p4-attack-f8", &seed, 0, LoadClass::era(V5_CLASS.with_nowin(), &era, &V3_ALLOWED)); + // both sides of the pair draw under the v6 rules (the five shuffle slots and the mad operand rule enter the + // stream for every class with a v6 flag), so the pair is the fold class with and without layer 8 off + let plain = candidate_class("p4-attack-f8", &seed, 0, LoadClass::era(V5_CLASS.with_fold(), &era, &V3_ALLOWED)); + let off = candidate_class("p4-attack-f8", &seed, 0, LoadClass::era(V5_CLASS.with_fold().with_nowin(), &era, &V3_ALLOWED)); assert_ne!(plain.program_id(), off.program_id(), "the id carries the flag"); assert_eq!(plain.instrs.len(), off.instrs.len()); let mut windows_plain = 0; @@ -294,7 +296,7 @@ fn program_class_v6_is_generator_6() { let seed = f8_bytes("program", 4); let p = candidate_class("p-f03", &seed, 0, LoadClass::era(V6_CLASS, &era, &V3_ALLOWED)); assert!(p.class.name().starts_with("mx8-era") && p.class.name().ends_with("+sh256x27+state+reg64c+fold+rw"), "{}", p.class.name()); - assert_eq!(p.generator, GENERATOR_VERSION_V6); + // candidate_class draws without stamping the generator; the era path stamps 6 (era_generator_of above) } /// 2. The fold's form: `y = x * M; y ^= y >> 16; y = rotl(y, R)`, and nothing else moves. The plain era's stride is @@ -316,12 +318,15 @@ fn fold_form_and_the_plain_stride_unchanged() { assert!(differ > 9_000, "the fold moved {differ} of 10,000 addresses"); // the program of a fold class is the program of the plain class: the same instructions when the same attempt // is accepted (the fold does not enter the draw; the indices it moves can move (c'') and (c''') verdicts) - let p = f8_program(4, ProgramClass::V4, false); - let f = f8_program(4, ProgramClass::V4, true); - if p.attempt == f.attempt { - assert_eq!(p.instrs, f.instrs); - assert_eq!(p.shadow, f.shadow); - } + // since the review's draw rules (8 October 2026) a fold class draws under the v6 rules, so the pair is the v6 + // re-weight class with and without the fold: the same instructions, the fold moving the addresses alone + let era = f8_bytes("era", 4); + let seed = f8_bytes("program", 4); + let p = candidate_class("p4-attack-f8", &seed, 0, LoadClass::era(V5_CLASS.with_rw(1), &era, &V3_ALLOWED)); + let f = candidate_class("p4-attack-f8", &seed, 0, LoadClass::era(V5_CLASS.with_rw(1).with_fold(), &era, &V3_ALLOWED)); + assert_eq!(p.instrs, f.instrs); + assert_eq!(p.shadow, f.shadow); + assert_ne!(p.program_id(), f.program_id()); assert_eq!(f.class.name(), format!("{}+fold", p.class.name())); assert_ne!(p.program_id(), f.program_id()); // and load_index reads the fold through the era From 2e43b0af99e174dc07d1e7f3aa431fe114358723 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Thu, 8 Oct 2026 19:39:22 +0000 Subject: [PATCH 23/36] class v6 kit: the Metal worker runs generator 6 as it runs class v5 (packClassOf 6 = v6, the state-leaf rules on both classes, as packfile.h 98fd170b2); the kit's packfile-test names the checked-in class v5 pack as its known-good (the generator 6 all pack failed that check by construction in the third build) Co-Authored-By: Claude Fable 5.1 --- proto-metal/main.swift | 15 ++++++++------- tools/class-v5/kits-v6-on-box.sh | 5 ++++- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/proto-metal/main.swift b/proto-metal/main.swift index e7c55d127..87cda6f40 100644 --- a/proto-metal/main.swift +++ b/proto-metal/main.swift @@ -2992,9 +2992,10 @@ final class ServeDataset { /// Counter ASIC 2.0 and 3.0: the classes this worker runs from a prepared pack only (never from the Swift version 2 /// generator): class v3 (generator 3) and class v4 (generator 4, class v3 plus the latency-shadow block, which is in /// the pack's own program_bound.metal). Each carries an era seed. -func isPackClass(_ cls: String) -> Bool { cls == "v3" || cls == "v4" || cls == "v5" } // class v5 (7 October 2026): class v4 over the state leaves, from a pack +func isPackClass(_ cls: String) -> Bool { cls == "v3" || cls == "v4" || cls == "v5" || cls == "v6" } // class v5 (7 October 2026): class v4 over the state leaves, from a pack; class v6 (8 October 2026): class v5's stored-state dataset with the v6 rules in the kernel text (packfile.h db63e1e36: run as class v5) /// The class name of a pack's IGNEUM_GENERATOR (packfile.h's rule). -func packClassOf(generator: UInt32) -> String { generator == 5 ? "v5" : generator == 4 ? "v4" : generator == 3 ? "v3" : "v2" } +func packClassOf(generator: UInt32) -> String { generator == 6 ? "v6" : generator == 5 ? "v5" : generator == 4 ? "v4" : generator == 3 ? "v3" : "v2" } +func isStateClass(_ cls: String) -> Bool { cls == "v5" || cls == "v6" } // the classes keyed by the state leaves // The resident programs and datasets, shared by the job loop (main thread) and the prepare queue (background). final class ServeStore { @@ -3085,7 +3086,7 @@ func servePackProgram(_ gpu: GPU, _ store: ServeStore, seedHex: String, seed: [U } func refuse(_ why: String) -> NSError { NSError(domain: "pack", code: 2, userInfo: [NSLocalizedDescriptionKey: "pack \(dir): \(why)"]) } let generator = defineU32("IGNEUM_GENERATOR") ?? 1 - guard generator == 2 || generator == 3 || generator == 4 || generator == 5 else { throw refuse("program pack generator \(generator) is not a generator version this worker runs (2, 3, 4 or 5)") } + guard generator == 2 || generator == 3 || generator == 4 || generator == 5 || generator == 6 else { throw refuse("program pack generator \(generator) is not a generator version this worker runs (2, 3, 4, 5 or 6)") } let packClass = packClassOf(generator: generator) if let named = defineStr("IGNEUM_PROGRAM_CLASS"), named != packClass { throw refuse("program pack IGNEUM_PROGRAM_CLASS \"\(named)\" does not match IGNEUM_GENERATOR \(generator)") } // Counter ASIC 3.0 (6 October 2026): the shadow block marks class v4 (packfile.h's rule): a generator 3 pack with @@ -3093,9 +3094,9 @@ func servePackProgram(_ gpu: GPU, _ store: ServeStore, seedHex: String, seed: [U let shadow = defineU32("IGNEUM_SHADOW_INSTRS") ?? 0 if generator == 4 && shadow == 0 { throw refuse("program pack generator 4 (class v4) without IGNEUM_SHADOW_INSTRS: not a class v4 pack") } // class v5 (7 October 2026) is class v4 over the state leaves: the shadow block and IGNEUM_STATE_LEAVES both mark it - if generator == 5 && shadow == 0 { throw refuse("program pack generator 5 (class v5) without IGNEUM_SHADOW_INSTRS: not a class v5 pack") } - if generator == 5 && (defineU32("IGNEUM_STATE_LEAVES") ?? 0) == 0 { throw refuse("program pack generator 5 (class v5) without IGNEUM_STATE_LEAVES: no state leaves to key the dataset (export the pack with --state)") } - if generator != 5 && (defineU32("IGNEUM_STATE_LEAVES") ?? 0) != 0 { throw refuse("program pack generator \(generator) carries IGNEUM_STATE_LEAVES: state leaves belong to class v5 (generator 5)") } + if (generator == 5 || generator == 6) && shadow == 0 { throw refuse("program pack generator 5 (class v5) without IGNEUM_SHADOW_INSTRS: not a class v5 pack") } + if (generator == 5 || generator == 6) && (defineU32("IGNEUM_STATE_LEAVES") ?? 0) == 0 { throw refuse("program pack generator 5 (class v5) without IGNEUM_STATE_LEAVES: no state leaves to key the dataset (export the pack with --state)") } + if generator != 5 && generator != 6 && (defineU32("IGNEUM_STATE_LEAVES") ?? 0) != 0 { throw refuse("program pack generator \(generator) carries IGNEUM_STATE_LEAVES: state leaves belong to class v5 (generator 5)") } if generator == 3 && shadow != 0 { throw refuse("program pack generator \(generator) with a shadow block (IGNEUM_SHADOW_INSTRS \(shadow)): a class v4 program is generator 4 (export the pack as class v4)") } let eraHex = defineStr("IGNEUM_ERA_SEED_HEX") ?? "" if wantClass != "" && wantClass != packClass { throw refuse("program class mismatch: this pack is class \(packClass), the line names class \(wantClass) (export the pack again)") } @@ -3175,7 +3176,7 @@ func servePackDataset(_ gpu: GPU, _ store: ServeStore, dayHex: String, dir: Stri return UInt64(programH[Range(m.range(at: 1), in: programH)!], radix: 16) } let stateLeaves = defineU32("IGNEUM_STATE_LEAVES") ?? 0 - if (packClass == "v5") != (stateLeaves > 0) { throw refuse(packClass == "v5" ? "class v5 pack without IGNEUM_STATE_LEAVES" : "a class \(packClass) pack carries IGNEUM_STATE_LEAVES \(stateLeaves): state leaves belong to class v5") } + if isStateClass(packClass) != (stateLeaves > 0) { throw refuse(isStateClass(packClass) ? "class v5 pack without IGNEUM_STATE_LEAVES" : "a class \(packClass) pack carries IGNEUM_STATE_LEAVES \(stateLeaves): state leaves belong to class v5") } var leavesBuf: MTLBuffer? = nil var nLeaves: UInt32 = 0 if stateLeaves > 0 { diff --git a/tools/class-v5/kits-v6-on-box.sh b/tools/class-v5/kits-v6-on-box.sh index 49d00e663..845cdbd5c 100755 --- a/tools/class-v5/kits-v6-on-box.sh +++ b/tools/class-v5/kits-v6-on-box.sh @@ -25,8 +25,11 @@ rm -rf "$PK"/._* "$PK"/*/._* 2>/dev/null V5="$PK/$V6_ALL"; V6P="$PK/$V6_PARTNER" echo "PACKS $V6_ALL id $(grep -oE 'IGNEUM_PROGRAM_ID 0x[0-9a-f]+' "$V5/program.h" | awk '{print $2}') | $V6_PARTNER id $(grep -oE 'IGNEUM_PROGRAM_ID 0x[0-9a-f]+' "$V6P/program.h" | awk '{print $2}')" [ "$(grep -oE 'IGNEUM_PROGRAM_ID 0x[0-9a-f]+' "$V5/program.h")" != "$(grep -oE 'IGNEUM_PROGRAM_ID 0x[0-9a-f]+' "$V6P/program.h")" ] || { echo "FAIL the all pack and its partner carry one id"; exit 1; } +# the test's third argument is its class v5 known-good (the checked-in Devnet 3 epoch 0 pack, generator 5, 11 leaves); the kit's all +# pack is generator 6 since the post-review export (class v6, 93 leaves) and fails that check by construction (the third kit build, +# 20:38 UK), so the checked-in pack is named and the v6 packs are read by the emulation check below step packfile-test -cc -std=c99 -Wall -Wextra -Wno-unused-function -O1 -o "$T/packfile-test" proto-cuda/nvrtc/emu/packfile-test.c && "$T/packfile-test" proto-cuda/packs/igneum-devnet-v4-epoch0 "$V5" > "$T/packfile-test.log" 2>&1 || fail "packfile-test ($(tail -1 "$T/packfile-test.log"))" +cc -std=c99 -Wall -Wextra -Wno-unused-function -O1 -o "$T/packfile-test" proto-cuda/nvrtc/emu/packfile-test.c && "$T/packfile-test" proto-cuda/packs/igneum-devnet-v4-epoch0 proto-cuda/packs-ca3-v5/v5-dn3-epoch0 > "$T/packfile-test.log" 2>&1 || fail "packfile-test ($(tail -1 "$T/packfile-test.log"))" grep -E '^(FAIL| v5 pack)' "$T/packfile-test.log"; grep -c '^ok' "$T/packfile-test.log" | sed 's/^/packfile-test ok lines /' step linux-opencl-worker gcc -std=c99 -O2 -Wall -Wextra -Wno-stringop-truncation -Wno-format-truncation -DIGNEUM_CL_DYNAMIC -DCL_TARGET_OPENCL_VERSION=120 -I proto-cuda/packs/igneum-devnet-v4-epoch0 -DIGNEUM_KERNEL_PATH='"kernel_bound.cl"' -o "$S/bin/linux/igneum-worker-opencl" proto-opencl/host.c -ldl -lpthread 2> "$T/cl-linux.log" || { fail "linux opencl worker"; head -20 "$T/cl-linux.log"; } From 0d3508baa86541215aeb0d11b5a5ce5fcd8ffd74 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Thu, 8 Oct 2026 19:40:56 +0000 Subject: [PATCH 24/36] class-v6: the fold test reads the class name's suffix order (fold inside rw) and parses both spellings Co-Authored-By: Claude Fable 5.1 --- igneum-pow/tests/v6fold.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/igneum-pow/tests/v6fold.rs b/igneum-pow/tests/v6fold.rs index 586769663..ed10c319e 100644 --- a/igneum-pow/tests/v6fold.rs +++ b/igneum-pow/tests/v6fold.rs @@ -327,8 +327,9 @@ fn fold_form_and_the_plain_stride_unchanged() { assert_eq!(p.instrs, f.instrs); assert_eq!(p.shadow, f.shadow); assert_ne!(p.program_id(), f.program_id()); - assert_eq!(f.class.name(), format!("{}+fold", p.class.name())); - assert_ne!(p.program_id(), f.program_id()); + // the name orders the fold inside the re-weight suffix ("...+state+fold+rw"); both spellings parse to the class + assert!(f.class.name().ends_with("+sh256x27+state+fold+rw"), "{}", f.class.name()); + assert_eq!(LoadClass::parse(&format!("{}+fold", p.class.name())), Some(f.class)); // and load_index reads the fold through the era let ins = p.instrs.iter().find(|i| i.op == Op::Load).unwrap(); let (pe, fe) = (p.class.era.unwrap(), f.class.era.unwrap()); From 414f105a5183b20965c9031e5a110d35d5068cb5 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Thu, 8 Oct 2026 19:43:45 +0000 Subject: [PATCH 25/36] class v6 kit: the PC job scripts expect the post-review (generator 6) packs' fingerprints, the Mac's Metal and Apple OpenCL reading (all pack e8f4f3289c6ee1fc, partner 6ce3dc344a613500); the third zip packs-class-v6-20261008T194045Z.zip Co-Authored-By: Claude Fable 5.1 --- tools/class-v5/arc-v6-bench.ps1 | 20 ++++++++++++-------- tools/class-v5/pc1-v6-bench.ps1 | 18 +++++++++++------- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/tools/class-v5/arc-v6-bench.ps1 b/tools/class-v5/arc-v6-bench.ps1 index 0b59bbc2e..4ff6e5916 100644 --- a/tools/class-v5/arc-v6-bench.ps1 +++ b/tools/class-v5/arc-v6-bench.ps1 @@ -1,28 +1,32 @@ # Class v6 kit (8 October 2026, the coordinator's order): the arc job of the v5 script with the class v6 packs: hl-v6-foldrw (the -# known-failed partner; expected fingerprint 5a6ad122a71a888f, the Mac's Metal and Apple OpenCL reading) and hl-v6-all (the +# known-failed partner; expected fingerprint 6ce3dc344a613500, the Mac's Metal and Apple OpenCL reading) and hl-v6-all (the # all-together pack, id 9d40978601a7df2a; with the second zip its OpenCL text is the window's real text and the expected -# fingerprint is the CUDA reference 59e6708e46f1e87c; the first zip's stub refused it, that refusal line being that run's record). +# fingerprint is the CUDA reference e8f4f3289c6ee1fc; the first zip's stub refused it, that refusal line being that run's record). # Kit fetch job fetch-class-v6-kit-20261008 = the second zip (packs-class-v6-.zip named in the job's publish line). # Class v5 kit bench on the Intel Arc B580 (7 October 2026, 23:5x UK, main's word: the B580 is the eGPU of the second PC, # so the Intel fingerprint runs there through the hash lane's job queue as a lock-free, non-elevated, quiet job, never beside # an install or a build; the page names no PC): tools/class-v5/pc1-amd-v5-bench.ps1 with the device # match on the Intel OpenCL platform (Arc / B580) instead of gfx1201; everything else identical (the v5-dn3-epoch0 pack, -# the v4-genesis control, RESULT lines, SUMMARY {json}). Expected fingerprint 5a6ad122a71a888f. +# the v4-genesis control, RESULT lines, SUMMARY {json}). Expected fingerprint 6ce3dc344a613500. # Class v5 kit bench on PC 1's RX 9070 XT (7 October 2026, docs/design/class-v5-stored-state.md section 13, "the kit: # OpenCL (AMD)"): the kit's igneum-worker-opencl.exe (THIS tree's proto-opencl/host.c with the class v5 leaf upload: # igneum_build(ds, cache, leaves, nLeaves, nItems), the leaves of leaves.bin checked against the pack's FNV-1a 64 first) # runs --bench-pack on the first class v5 pack, proto-cuda/packs-ca3-v5/v5-dn3-epoch0 (program id e5a4ac5978462156, 11 # leaves under state root 7e37a9fb..., cache FNV 7334fa46e5d972eb), on the gfx1201 device. Expected: the self-test # PASS line (cache head, last line and FNV; dataset head, word [268435455] and 64 samples; 96 of 96 vector lanes) and the -# fingerprint of the 2^24 outputs at base nonce 0 equal to the Metal reading, 5a6ad122a71a888f (the M5 Max, 7 October +# fingerprint of the 2^24 outputs at base nonce 0 equal to the Metal reading, 6ce3dc344a613500 (the M5 Max, 7 October # 2026, 18:07:09Z). The v4-genesis control pack runs after it so the run has a known class v4 row beside the v5 row. # Beside the miners (a correctness and fingerprint gate; the rate row is labelled loaded when the card mines): no card is # switched, nothing is posted to the installed app, nothing is built on the PC. Published by the Counter ASIC coordinator # only (the PC 1 queue is its); the kit is fetch job $kitId. Every result line starts with RESULT; SUMMARY {json} ends it. +# Post-review packs (8 October 2026, 20:4x UK, the third kit zip packs-class-v6-20261008T194045Z.zip, sha256 735e1411...): the packs are +# generator 6 (class v6; ids hl-v6-all 4de7b836cc40a4ea, hl-v6-foldrw d7eba30115d26dd4) and the expected fingerprints are the +# Mac's Metal and Apple OpenCL reading of them (all pack e8f4f3289c6ee1fc, partner 6ce3dc344a613500); the generator 5 zips' values +# (59e6708e46f1e87c and 5a6ad122a71a888f) belong to the superseded packs and no longer match by construction. $ErrorActionPreference = 'Continue' $jobName = 'arc-v6-bench' $kitId = $env:IGNEUM_V5_KIT_ID; if (-not $kitId) { $kitId = 'fetch-class-v6-kit-20261008' } -$expected = '5a6ad122a71a888f' +$expected = '6ce3dc344a613500' $started = Get-Date function Stamp { (Get-Date).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ') } function Summary([string] $status, [hashtable] $extra) { @@ -88,9 +92,9 @@ foreach ($pk in @('hl-v6-foldrw', 'hl-v6-all')) { $fpOk = ($fp -eq $expected -and $check -eq 'PASS') "RESULT partner fingerprint=$fp expected=$expected match=$fpOk check=$check mhs=$mhs card_state=$state exit=$code seconds=$secs $(Stamp)" } else { - # the all pack: with the window's OpenCL text (the second zip) a fingerprint, expected the CUDA reference 59e6708e46f1e87c - $allOk = ($fp -eq '59e6708e46f1e87c' -and $check -eq 'PASS') - "RESULT all-pack fingerprint=$fp expected=59e6708e46f1e87c match=$allOk check=$check mhs=$mhs card_state=$state exit=$code seconds=$secs $(Stamp)" + # the all pack: with the window's OpenCL text (the second zip) a fingerprint, expected the CUDA reference e8f4f3289c6ee1fc + $allOk = ($fp -eq 'e8f4f3289c6ee1fc' -and $check -eq 'PASS') + "RESULT all-pack fingerprint=$fp expected=e8f4f3289c6ee1fc match=$allOk check=$check mhs=$mhs card_state=$state exit=$code seconds=$secs $(Stamp)" } } "RESULT workers_after $(Stamp) $((@(Workers)) -join ' ')" diff --git a/tools/class-v5/pc1-v6-bench.ps1 b/tools/class-v5/pc1-v6-bench.ps1 index c8ab7fbc5..84f8349cd 100644 --- a/tools/class-v5/pc1-v6-bench.ps1 +++ b/tools/class-v5/pc1-v6-bench.ps1 @@ -1,7 +1,7 @@ # Class v6 kit (8 October 2026, the coordinator's order): the amd job of the v5 script with the class v6 packs: hl-v6-foldrw (the -# known-failed partner; expected fingerprint 5a6ad122a71a888f, the Mac's Metal and Apple OpenCL reading) and hl-v6-all (the +# known-failed partner; expected fingerprint 6ce3dc344a613500, the Mac's Metal and Apple OpenCL reading) and hl-v6-all (the # all-together pack, id 9d40978601a7df2a; with the second zip its OpenCL text is the window's real text and the expected -# fingerprint is the CUDA reference 59e6708e46f1e87c; the first zip's stub refused it, that refusal line being that run's record). +# fingerprint is the CUDA reference e8f4f3289c6ee1fc; the first zip's stub refused it, that refusal line being that run's record). # Kit fetch job fetch-class-v6-kit-20261008 = the second zip (packs-class-v6-.zip named in the job's publish line). # Class v5 kit bench on PC 1's RX 9070 XT (7 October 2026, docs/design/class-v5-stored-state.md section 13, "the kit: # OpenCL (AMD)"): the kit's igneum-worker-opencl.exe (THIS tree's proto-opencl/host.c with the class v5 leaf upload: @@ -9,15 +9,19 @@ # runs --bench-pack on the first class v5 pack, proto-cuda/packs-ca3-v5/v5-dn3-epoch0 (program id e5a4ac5978462156, 11 # leaves under state root 7e37a9fb..., cache FNV 7334fa46e5d972eb), on the gfx1201 device. Expected: the self-test # PASS line (cache head, last line and FNV; dataset head, word [268435455] and 64 samples; 96 of 96 vector lanes) and the -# fingerprint of the 2^24 outputs at base nonce 0 equal to the Metal reading, 5a6ad122a71a888f (the M5 Max, 7 October +# fingerprint of the 2^24 outputs at base nonce 0 equal to the Metal reading, 6ce3dc344a613500 (the M5 Max, 7 October # 2026, 18:07:09Z). The v4-genesis control pack runs after it so the run has a known class v4 row beside the v5 row. # Beside the miners (a correctness and fingerprint gate; the rate row is labelled loaded when the card mines): no card is # switched, nothing is posted to the installed app, nothing is built on the PC. Published by the Counter ASIC coordinator # only (the PC 1 queue is its); the kit is fetch job $kitId. Every result line starts with RESULT; SUMMARY {json} ends it. +# Post-review packs (8 October 2026, 20:4x UK, the third kit zip packs-class-v6-20261008T194045Z.zip, sha256 735e1411...): the packs are +# generator 6 (class v6; ids hl-v6-all 4de7b836cc40a4ea, hl-v6-foldrw d7eba30115d26dd4) and the expected fingerprints are the +# Mac's Metal and Apple OpenCL reading of them (all pack e8f4f3289c6ee1fc, partner 6ce3dc344a613500); the generator 5 zips' values +# (59e6708e46f1e87c and 5a6ad122a71a888f) belong to the superseded packs and no longer match by construction. $ErrorActionPreference = 'Continue' $jobName = 'pc1-v6-bench' $kitId = $env:IGNEUM_V5_KIT_ID; if (-not $kitId) { $kitId = 'fetch-class-v6-kit-20261008' } -$expected = '5a6ad122a71a888f' +$expected = '6ce3dc344a613500' $started = Get-Date function Stamp { (Get-Date).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ') } function Summary([string] $status, [hashtable] $extra) { @@ -81,9 +85,9 @@ foreach ($pk in @('hl-v6-foldrw', 'hl-v6-all')) { $fpOk = ($fp -eq $expected -and $check -eq 'PASS') "RESULT partner fingerprint=$fp expected=$expected match=$fpOk check=$check mhs=$mhs card_state=$state exit=$code seconds=$secs $(Stamp)" } else { - # the all pack: with the window's OpenCL text (the second zip) a fingerprint, expected the CUDA reference 59e6708e46f1e87c - $allOk = ($fp -eq '59e6708e46f1e87c' -and $check -eq 'PASS') - "RESULT all-pack fingerprint=$fp expected=59e6708e46f1e87c match=$allOk check=$check mhs=$mhs card_state=$state exit=$code seconds=$secs $(Stamp)" + # the all pack: with the window's OpenCL text (the second zip) a fingerprint, expected the CUDA reference e8f4f3289c6ee1fc + $allOk = ($fp -eq 'e8f4f3289c6ee1fc' -and $check -eq 'PASS') + "RESULT all-pack fingerprint=$fp expected=e8f4f3289c6ee1fc match=$allOk check=$check mhs=$mhs card_state=$state exit=$code seconds=$secs $(Stamp)" } } "RESULT workers_after $(Stamp) $((@(Workers)) -join ' ')" From d47d66a58ee59380fed0627abac51178ad734ca6 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Thu, 8 Oct 2026 19:50:17 +0000 Subject: [PATCH 26/36] class-v6: the fold test parses the plain class string (an era class's name is not a parse form) Co-Authored-By: Claude Fable 5.1 --- igneum-pow/tests/v6fold.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/igneum-pow/tests/v6fold.rs b/igneum-pow/tests/v6fold.rs index ed10c319e..c66c73d65 100644 --- a/igneum-pow/tests/v6fold.rs +++ b/igneum-pow/tests/v6fold.rs @@ -329,7 +329,7 @@ fn fold_form_and_the_plain_stride_unchanged() { assert_ne!(p.program_id(), f.program_id()); // the name orders the fold inside the re-weight suffix ("...+state+fold+rw"); both spellings parse to the class assert!(f.class.name().ends_with("+sh256x27+state+fold+rw"), "{}", f.class.name()); - assert_eq!(LoadClass::parse(&format!("{}+fold", p.class.name())), Some(f.class)); + assert_eq!(LoadClass::parse("mx8+sh256x27+state+rw+fold"), Some(V5_CLASS.with_rw(1).with_fold())); // and load_index reads the fold through the era let ins = p.instrs.iter().find(|i| i.op == Op::Load).unwrap(); let (pe, fe) = (p.class.era.unwrap(), f.class.era.unwrap()); From 49dae98bc130f1403a3609acd73945e516b8e842 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Thu, 8 Oct 2026 19:54:31 +0000 Subject: [PATCH 27/36] class v6 kit: gate-remote.sh runs the full gate over the kit tree on a build box (the class-v5 script) Co-Authored-By: Claude Fable 5.1 --- tools/class-v5/gate-remote.sh | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100755 tools/class-v5/gate-remote.sh diff --git a/tools/class-v5/gate-remote.sh b/tools/class-v5/gate-remote.sh new file mode 100755 index 000000000..2c13ca3c3 --- /dev/null +++ b/tools/class-v5/gate-remote.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +# The FULL gate (tools/ci/pre-push.sh with no arguments) over this worktree's tree, run on a build box, never on the Mac (the +# no-Mac-builds rule of 7 October 2026). Shape as kits-remote.sh: the sources sync to the worktree's mirror checkout on the box +# and the gate runs there from the script FILE the commit carries (no inline string). Usage: tools/class-v5/gate-remote.sh [--box N] +# Exit: the gate's own status; the log at /tmp/v5-gate-.log on the Mac. +set -euo pipefail +HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +. "$HERE/../../infra/build-server/lib.sh" +BOX=1 +while [ $# -gt 0 ]; do case "$1" in --box) BOX="$2"; shift 2 ;; *) echo "unknown argument $1" >&2; exit 2 ;; esac; done +export IGNEUM_AGENT="${IGNEUM_AGENT:-v5-gate}" +bs_host "$BOX" +pushd "$HERE/../../igneum-pow" > /dev/null; bs_context; popd > /dev/null +WT="$BS_REMOTE_WT" +STAMP=$(date -u +%Y%m%dT%H%M%SZ) +bs_toolchain_check +bs_sync_sources +bs_log "sources at $WT (commit $BS_SHA on $BS_BRANCH); the full gate on box $BOX" +CMD="cd '$WT' && IGNEUM_GATE_NO_TITLE=1 bash tools/ci/pre-push.sh" +set +e +BR_KIND=gate BR_COMMAND="the full gate (tools/ci/pre-push.sh) over the class-v6-kits tree" BR_TARGET="x86_64-linux" BR_ARTEFACTS="" \ + bs_remote_run "$WT" "$BS_WT class-v6-kits full gate" "$CMD" 2>&1 | tee "/tmp/v5-gate-$STAMP.log" | grep -E '^( (ok|FAIL|RED)|pre-push gate|FAIL|build-remote: RESULT)' +rc=${PIPESTATUS[0]} +set -e +bs_wt_unlock +[ "$rc" = 0 ] && bs_log "full gate GREEN at $BS_SHA" || bs_die "full gate RED (rc $rc); full log /tmp/v5-gate-$STAMP.log" From 8f0980829c2c3793f36499148a6b35155ff453d7 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Thu, 8 Oct 2026 19:57:49 +0000 Subject: [PATCH 28/36] gate-remote.sh: ci mode on box 2 (the box carries the overlap browser; local mode on a box reads two environment reds) Co-Authored-By: Claude Fable 5.1 --- tools/class-v5/gate-remote.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/class-v5/gate-remote.sh b/tools/class-v5/gate-remote.sh index 2c13ca3c3..0339330f3 100755 --- a/tools/class-v5/gate-remote.sh +++ b/tools/class-v5/gate-remote.sh @@ -6,7 +6,7 @@ set -euo pipefail HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" . "$HERE/../../infra/build-server/lib.sh" -BOX=1 +BOX=2 # box 2 carries the overlap browser (/srv/builds/_bin/overlap); box 1 does not (the 20:56 UK red) while [ $# -gt 0 ]; do case "$1" in --box) BOX="$2"; shift 2 ;; *) echo "unknown argument $1" >&2; exit 2 ;; esac; done export IGNEUM_AGENT="${IGNEUM_AGENT:-v5-gate}" bs_host "$BOX" @@ -16,7 +16,9 @@ STAMP=$(date -u +%Y%m%dT%H%M%SZ) bs_toolchain_check bs_sync_sources bs_log "sources at $WT (commit $BS_SHA on $BS_BRANCH); the full gate on box $BOX" -CMD="cd '$WT' && IGNEUM_GATE_NO_TITLE=1 bash tools/ci/pre-push.sh" +# ci mode: the box runs the gate as the box runners do (box-locks reads ok with no host file; a browser is found at +# /srv/builds/_bin/overlap); local mode on a box reads two environment reds that are not the tree's (20:56 UK) +CMD="cd '$WT' && IGNEUM_GATE_NO_TITLE=1 bash tools/ci/pre-push.sh ci" set +e BR_KIND=gate BR_COMMAND="the full gate (tools/ci/pre-push.sh) over the class-v6-kits tree" BR_TARGET="x86_64-linux" BR_ARTEFACTS="" \ bs_remote_run "$WT" "$BS_WT class-v6-kits full gate" "$CMD" 2>&1 | tee "/tmp/v5-gate-$STAMP.log" | grep -E '^( (ok|FAIL|RED)|pre-push gate|FAIL|build-remote: RESULT)' From efe06c9dbce3daec60062b31e18843d700f04fe6 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Thu, 8 Oct 2026 19:59:06 +0000 Subject: [PATCH 29/36] class-v6: V6-02 re-done: the executed load and byte counters (loads_per_hash_executed, bytes_per_hash_executed) are read by the emitters alone; the acceptance and the draw read the drawn count as before (the first form, c462b526e, routed the executed count into the acceptance and moved every reg64 verdict: hl-v6-all drew 0x1626c5853aa84261 instead of 0x4de7b836cc40a4ea, found by the re-export's read-back) Co-Authored-By: Claude Fable 5.1 --- igneum-pow/src/emit.rs | 10 +++++----- igneum-pow/src/generator.rs | 36 +++++++++++++++++++++++------------- 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/igneum-pow/src/emit.rs b/igneum-pow/src/emit.rs index fb5ed7d14..4c92715b5 100644 --- a/igneum-pow/src/emit.rs +++ b/igneum-pow/src/emit.rs @@ -355,8 +355,8 @@ fn class_header_lines(p: &Program) -> String { let c = p.width_counts(); s.push_str(&format!("#define IGNEUM_LOAD_WIDTH_COUNTS {{ {}, {}, {} }} // loads of 4, 16, 64 bytes per program ", c[0], c[1], c[2])); - s.push_str(&format!("#define IGNEUM_BYTES_PER_HASH {} -", p.bytes_per_hash())); + s.push_str(&format!("#define IGNEUM_BYTES_PER_HASH {} // demand of the executed loads per nonce (loads x width); the memory moves sectors or lines +", p.bytes_per_hash_executed())); s.push_str(&format!("#define IGNEUM_FOLD_ROT {FOLD_ROT} ")); s.push_str(&format!("#define IGNEUM_FOLD_MUL {} @@ -2016,7 +2016,7 @@ pub fn program_header(p: &Program, day: &str, ds: &DatasetSource) -> String { s.push_str("#define IGNEUM_LANES 32\n"); s.push_str(&format!("#define IGNEUM_ITERATIONS {ITERATIONS}\n")); s.push_str(&format!("#define IGNEUM_INSTR_COUNT {INSTR_COUNT}\n")); - s.push_str(&format!("#define IGNEUM_LOADS_PER_HASH {}\n", p.loads_per_hash())); + s.push_str(&format!("#define IGNEUM_LOADS_PER_HASH {} // executed per nonce (twice the drawn program's under the 64-register window)\n", p.loads_per_hash_executed())); s.push_str(&format!("#define IGNEUM_WIDE_LOADS_PER_HASH {}\n", p.wide_loads_per_hash())); s.push_str(&format!("#define IGNEUM_OP_MIX {}\n", jstr(&p.op_mix()))); s.push_str(&program_class_header_lines(p)); @@ -2258,7 +2258,7 @@ pub fn program_json(p: &Program, day: &str, ds: &DatasetSource) -> String { s.push_str(" \"registers\": 8,\n"); s.push_str(&format!(" \"iterations\": {ITERATIONS},\n")); s.push_str(&format!(" \"instruction_count\": {INSTR_COUNT},\n")); - s.push_str(&format!(" \"loads_per_hash\": {},\n", p.loads_per_hash())); + s.push_str(&format!(" \"loads_per_hash\": {},\n", p.loads_per_hash_executed())); if p.program_class() != ProgramClass::V2 { s.push_str(&format!(" \"program_class\": {},\n", jstr(p.program_class().name()))); if p.program_class() == ProgramClass::V4 { @@ -2308,7 +2308,7 @@ pub fn program_json(p: &Program, day: &str, ds: &DatasetSource) -> String { s.push_str(&format!(" \"load_slots\": {},\n", p.class.load_slots)); s.push_str(&format!(" \"load_mix_percent_4_16_64\": [{}, {}, {}],\n", p.class.mix[0], p.class.mix[1], p.class.mix[2])); s.push_str(&format!(" \"load_width_counts_4_16_64\": [{}, {}, {}],\n", c[0], c[1], c[2])); - s.push_str(&format!(" \"bytes_per_hash\": {},\n", p.bytes_per_hash())); + s.push_str(&format!(" \"bytes_per_hash\": {},\n", p.bytes_per_hash_executed())); if p.has_scratch() { s.push_str(&format!(" \"scratch_ops_per_hash\": {},\n", p.scratch_ops_per_hash())); s.push_str(&format!(" \"scratch_kib_per_warp\": {},\n", p.class.scratch_kb)); diff --git a/igneum-pow/src/generator.rs b/igneum-pow/src/generator.rs index 89c9b8fb5..ce0084681 100644 --- a/igneum-pow/src/generator.rs +++ b/igneum-pow/src/generator.rs @@ -1241,21 +1241,25 @@ impl Program { } out } - /// Memory operations the hash EXECUTES per nonce (review B's V6-02, 8 October 2026): the scheduled statements - /// (the drawn program's loads, twice under the 64-register window) times the eight iterations. The drawn - /// program's own count is [`Program::loads_per_hash_drawn`]; the two agree except under the window, where the - /// executed count is twice the drawn one. Every served loads figure names this schedule. + /// The drawn program's memory operations per nonce (16 load slots times the eight iterations on every class): + /// the count the acceptance rule and the draw's bookkeeping read (the acceptance judges the drawn program's + /// sites). The hash EXECUTES [`Program::loads_per_hash_executed`] of them, twice this under the 64-register + /// window; the served figures and the pack's headers name the executed count (review B's V6-02). pub fn loads_per_hash(&self) -> usize { - let drawn = self.loads_per_hash_drawn(); + self.instrs.iter().filter(|i| i.op.is_load()).count() * ITERATIONS + } + + /// Memory operations the hash EXECUTES per nonce (review B's V6-02, 8 October 2026): the scheduled statements + /// (the drawn program's loads, twice under the 64-register window) times the eight iterations; asserted to + /// agree with the drawn count except by the window's factor of two. The emitters alone read it (program.h, + /// program.json): the acceptance reads the drawn count, so no verdict moves with the served figure (the first + /// form of this change, 0266c9ec0, routed the executed count into the acceptance and moved every reg64 verdict). + pub fn loads_per_hash_executed(&self) -> usize { + let drawn = self.loads_per_hash(); let executed = self.scheduled().iter().filter(|i| i.op.is_load()).count() * ITERATIONS; assert!(executed == drawn || (self.class.reg64 && executed == 2 * drawn), "the executed load count {executed} disagrees with the drawn {drawn}"); executed } - - /// The drawn program's memory operations per nonce (16 load slots times the eight iterations on every class). - pub fn loads_per_hash_drawn(&self) -> usize { - self.instrs.iter().filter(|i| i.op.is_load()).count() * ITERATIONS - } pub fn wide_loads_per_hash(&self) -> usize { self.instrs.iter().filter(|i| i.op == Op::WLoad).count() * ITERATIONS } @@ -1263,11 +1267,17 @@ impl Program { self.instrs.iter().any(|i| i.op == Op::WLoad) } /// Dataset bytes read per hash: 4 per one-word load, 16 and 64 for the wider loads of the experiment. + /// Dataset bytes the drawn program's loads demand per nonce (the acceptance's and the draw's figure). + pub fn bytes_per_hash(&self) -> usize { + self.instrs.iter().filter(|i| i.op == Op::Load).map(|i| i.width as usize * 4).sum::() * ITERATIONS + } + /// Dataset bytes the hash's EXECUTED loads demand per nonce (review B's V6-02): the scheduled loads' widths in /// words times 4, times the eight iterations; a demand figure, not the memory's transactions (a 4-byte load is - /// a 32-byte sector on NVIDIA and a 64-byte line on AMD; the served text names the model it quotes). - pub fn bytes_per_hash(&self) -> usize { - let drawn = self.instrs.iter().filter(|i| i.op == Op::Load).map(|i| i.width as usize * 4).sum::() * ITERATIONS; + /// a 32-byte sector on NVIDIA and a 64-byte line on AMD; the served text names the model it quotes). The + /// emitters alone read it. + pub fn bytes_per_hash_executed(&self) -> usize { + let drawn = self.bytes_per_hash(); let executed = self.scheduled().iter().filter(|i| i.op == Op::Load).map(|i| i.width as usize * 4).sum::() * ITERATIONS; assert!(executed == drawn || (self.class.reg64 && executed == 2 * drawn), "the executed byte demand {executed} disagrees with the drawn {drawn}"); executed From d7693908e96576019b678a7d3bada5d0a76a04d7 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Thu, 8 Oct 2026 20:11:52 +0000 Subject: [PATCH 30/36] registry: the class v6 kit's cross-platform fingerprint cell (kit:class-v6-fingerprints) answers REV-F03-2's worker half; batch kit-class-v6-20261008-01 writes RUNNING (CPU, CUDA 4090, Metal, Apple OpenCL equal on the generator 6 packs; the PC rows and the node and pool halves open) Co-Authored-By: Claude Fable 5.1 --- docs/plans/igneum-2.0-test-registry.json | 16 +++++++++++----- tools/ci/batches/kit-class-v6-20261008-01.json | 15 +++++++++++++++ tools/ci/test-map.json | 14 ++++++++++++++ 3 files changed, 40 insertions(+), 5 deletions(-) create mode 100644 tools/ci/batches/kit-class-v6-20261008-01.json diff --git a/docs/plans/igneum-2.0-test-registry.json b/docs/plans/igneum-2.0-test-registry.json index 0a3e8f917..2631fc66e 100644 --- a/docs/plans/igneum-2.0-test-registry.json +++ b/docs/plans/igneum-2.0-test-registry.json @@ -5601,12 +5601,18 @@ "finding_title": "The bundle contains a v6 candidate, not a demonstrated integrated v6 release", "finding_priority": "P0 - freeze/integration blocker", "owner_lane": "CI steward, hash lane (ProgramClass::V6 on freeze), pool lane", - "run_status": "NOT RUN", - "updated": "2026-10-08T19:32:50.856Z", + "run_status": "RUNNING", + "updated": "2026-10-08T20:11:46.500Z", "evidence_record": { - "reason": "F03 (P0, the external review): the regression's harness is the owner lane's (CI steward, hash lane (ProgramClass::V6 on freeze), pool lane); not yet named in the map", - "at": "2026-10-08T19:32:50.856Z" - } + "cell": "kit:class-v6-fingerprints", + "manifest_sha": "ef0f2ed8", + "coverage": { + "REV-F03-2": "partial: the worker half (CPU reference, CUDA, Metal, OpenCL) on the same program packs; the node's and the pool's accepted work on the same job context are the CI steward's and the pool lane's cells; PASS only when every listed platform reads one fingerprint and the node and pool halves are green" + }, + "at": "2026-10-08T20:11:46.500Z" + }, + "run_id": "kit-class-v6-20261008-01", + "evidence_path": "docs/design/class-v5-stored-state.md (section 0, the class v6 kit row: the generator 6 packs hl-v6-all 4de7b836cc40a4ea and hl-v6-foldrw d7eba30115d26dd4 read e8f4f3289c6ee1fc and 6ce3dc344a613500 on the CPU emulation check, the CUDA 4090, Metal and Apple OpenCL, 20:41 to 20:52 UK; the RTX 5090, RX 7600 and Arc rows the morning's); build-1:/srv/artefacts/packs/packs-class-v6-20261008T194045Z.zip (sha256 735e1411...); build-1:/srv/builds/_log/v5-class/kits-20261008T194045Z/emu-check.log" }, { "id": "REV-F03-3", diff --git a/tools/ci/batches/kit-class-v6-20261008-01.json b/tools/ci/batches/kit-class-v6-20261008-01.json new file mode 100644 index 000000000..62cbd8ce1 --- /dev/null +++ b/tools/ci/batches/kit-class-v6-20261008-01.json @@ -0,0 +1,15 @@ +{ + "run_id": "kit-class-v6-20261008-01", + "manifest_sha": "ef0f2ed8", + "evidence_dir": "docs/design/class-v5-stored-state.md", + "boxes": [ + "build-1" + ], + "cells": [ + { + "cell": "kit:class-v6-fingerprints", + "status": "RUNNING", + "evidence": "docs/design/class-v5-stored-state.md (section 0, the class v6 kit row: the generator 6 packs hl-v6-all 4de7b836cc40a4ea and hl-v6-foldrw d7eba30115d26dd4 read e8f4f3289c6ee1fc and 6ce3dc344a613500 on the CPU emulation check, the CUDA 4090, Metal and Apple OpenCL, 20:41 to 20:52 UK; the RTX 5090, RX 7600 and Arc rows the morning's); build-1:/srv/artefacts/packs/packs-class-v6-20261008T194045Z.zip (sha256 735e1411...); build-1:/srv/builds/_log/v5-class/kits-20261008T194045Z/emu-check.log" + } + ] +} diff --git a/tools/ci/test-map.json b/tools/ci/test-map.json index 9ef25d249..c3e601b7e 100644 --- a/tools/ci/test-map.json +++ b/tools/ci/test-map.json @@ -468,6 +468,20 @@ "coverage": { "VER-05": "partial: the public read node must report startedFrom genesis (no snapshot) and the reference reader on build-1 executed the 2.0 devnet from genesis with no snapshot; the pages fetch headers, certificates, coinbase bodies and account proofs from the public read RPC only; the archive and availability model beyond the 2,048-block state ring is the OPS no-founder exercise. Run ra-20261008T1915-ver: FAIL, the public node reports startedFrom snapshot (restarted from a snapshot after 17:46 UK); the reader on build-1 still from genesis" } + }, + "kit:class-v6-fingerprints": { + "command": "KITS_BOX_SCRIPT=kits-v6-on-box.sh tools/class-v5/kits-remote.sh --box 1 (the kit zip with its emulation check), then the kit's workers on every platform: the box's CPU emulation (--check, 96 of 96 vector lanes), the fleet's CUDA 4090 (--check and --bench at 2^24, base nonce 0), the Mac's Metal (proto-metal/packbench.swift --pack) and Apple OpenCL (proto-opencl/host.c --pack --bench-pack), PC 1's RTX 5090 and RX 7600 (tools/class-v5/pc1-v6-bench.ps1), PC 2's Arc B580 (tools/class-v5/arc-v6-bench.ps1); the fingerprint of the 2^24 outputs at base nonce 0 equal on every platform for the all pack and for its known-failed partner, the two distinct", + "box_class": "build box + pods + Mac + PC 1 + PC 2", + "fixtures": [ + "F0", + "F2" + ], + "cases": [ + "REV-F03-2" + ], + "coverage": { + "REV-F03-2": "partial: the worker half (CPU reference, CUDA, Metal, OpenCL) on the same program packs; the node's and the pool's accepted work on the same job context are the CI steward's and the pool lane's cells; PASS only when every listed platform reads one fingerprint and the node and pool halves are green" + } } }, "not_run": { From 21edd23c9480aa69f6a3fda53bcd5751362bc30b Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Thu, 8 Oct 2026 20:18:49 +0000 Subject: [PATCH 31/36] class-v6: program.h's load and byte defines keep their exact text (the pinned packs byte for byte); the executed-count note is a line of its own on the window packs Co-Authored-By: Claude Fable 5.1 --- igneum-pow/src/emit.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/igneum-pow/src/emit.rs b/igneum-pow/src/emit.rs index 4c92715b5..13ffe7d88 100644 --- a/igneum-pow/src/emit.rs +++ b/igneum-pow/src/emit.rs @@ -355,7 +355,7 @@ fn class_header_lines(p: &Program) -> String { let c = p.width_counts(); s.push_str(&format!("#define IGNEUM_LOAD_WIDTH_COUNTS {{ {}, {}, {} }} // loads of 4, 16, 64 bytes per program ", c[0], c[1], c[2])); - s.push_str(&format!("#define IGNEUM_BYTES_PER_HASH {} // demand of the executed loads per nonce (loads x width); the memory moves sectors or lines + s.push_str(&format!("#define IGNEUM_BYTES_PER_HASH {} ", p.bytes_per_hash_executed())); s.push_str(&format!("#define IGNEUM_FOLD_ROT {FOLD_ROT} ")); @@ -2016,7 +2016,10 @@ pub fn program_header(p: &Program, day: &str, ds: &DatasetSource) -> String { s.push_str("#define IGNEUM_LANES 32\n"); s.push_str(&format!("#define IGNEUM_ITERATIONS {ITERATIONS}\n")); s.push_str(&format!("#define IGNEUM_INSTR_COUNT {INSTR_COUNT}\n")); - s.push_str(&format!("#define IGNEUM_LOADS_PER_HASH {} // executed per nonce (twice the drawn program's under the 64-register window)\n", p.loads_per_hash_executed())); + if p.class.reg64 { + s.push_str("// the executed counts per nonce (review B's V6-02): twice the drawn program's under the 64-register window\n"); + } + s.push_str(&format!("#define IGNEUM_LOADS_PER_HASH {}\n", p.loads_per_hash_executed())); s.push_str(&format!("#define IGNEUM_WIDE_LOADS_PER_HASH {}\n", p.wide_loads_per_hash())); s.push_str(&format!("#define IGNEUM_OP_MIX {}\n", jstr(&p.op_mix()))); s.push_str(&program_class_header_lines(p)); From c6fcb102e9f4a8f405cff5cb113ffee2ab5980be Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Thu, 8 Oct 2026 20:25:47 +0000 Subject: [PATCH 32/36] class v6 kit: the harness map page regenerated for the kit's cell (the merge gate's red); arc-v6-bench.ps1 reads the generator 6 kit from the fresh dir fetch-class-v6-kit-20261008-g6 (a fetch into the old dir left zip 2's files on PC 2) Co-Authored-By: Claude Fable 5.1 --- docs/plans/igneum-2.0-test-harness-map.md | 10 +++++++++- tools/class-v5/arc-v6-bench.ps1 | 5 +++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/docs/plans/igneum-2.0-test-harness-map.md b/docs/plans/igneum-2.0-test-harness-map.md index 263caa79e..1025a44dd 100644 --- a/docs/plans/igneum-2.0-test-harness-map.md +++ b/docs/plans/igneum-2.0-test-harness-map.md @@ -275,6 +275,14 @@ Rule: a case maps to a cell only where the cell's tests visibly answer it; cover - Cases: - VER-05 Reconstruct required state without founder storage: partial: the public read node must report startedFrom genesis (no snapshot) and the reference reader on build-1 executed the 2.0 devnet from genesis with no snapshot; the pages fetch headers, certificates, coinbase bodies and account proofs from the public read RPC only; the archive and availability model beyond the 2,048-block state ring is the OPS no-founder exercise. Run ra-20261008T1915-ver: FAIL, the public node reports startedFrom snapshot (restarted from a snapshot after 17:46 UK); the reader on build-1 still from genesis +### kit:class-v6-fingerprints + +- Command: `KITS_BOX_SCRIPT=kits-v6-on-box.sh tools/class-v5/kits-remote.sh --box 1 (the kit zip with its emulation check), then the kit's workers on every platform: the box's CPU emulation (--check, 96 of 96 vector lanes), the fleet's CUDA 4090 (--check and --bench at 2^24, base nonce 0), the Mac's Metal (proto-metal/packbench.swift --pack) and Apple OpenCL (proto-opencl/host.c --pack --bench-pack), PC 1's RTX 5090 and RX 7600 (tools/class-v5/pc1-v6-bench.ps1), PC 2's Arc B580 (tools/class-v5/arc-v6-bench.ps1); the fingerprint of the 2^24 outputs at base nonce 0 equal on every platform for the all pack and for its known-failed partner, the two distinct` +- Box class: build box + pods + Mac + PC 1 + PC 2 +- Fixtures: F0, F2 +- Cases: + - REV-F03-2 Same job context produces identical accepted work in node, CPU reference, CUDA, Metal, OpenCL and pool.: partial: the worker half (CPU reference, CUDA, Metal, OpenCL) on the same program packs; the node's and the pool's accepted work on the same job context are the CI steward's and the pool lane's cells; PASS only when every listed platform reads one fingerprint and the node and pool halves are green + ## Automated cases with no harness in the matrix (NOT RUN, the reason) - GOV-02 Approve thresholds before results: the approval is recorded in the registry's approval field; the automated half (thresholds frozen before any run_status) is the gate rule landing by 21:00 @@ -382,4 +390,4 @@ Rule: a case maps to a cell only where the cell's tests visibly answer it; cover ## Count -153 automated cases: 56 mapped to a cell, 102 NOT RUN with a reason. +153 automated cases: 57 mapped to a cell, 102 NOT RUN with a reason. diff --git a/tools/class-v5/arc-v6-bench.ps1 b/tools/class-v5/arc-v6-bench.ps1 index 4ff6e5916..a7d67b375 100644 --- a/tools/class-v5/arc-v6-bench.ps1 +++ b/tools/class-v5/arc-v6-bench.ps1 @@ -2,7 +2,8 @@ # known-failed partner; expected fingerprint 6ce3dc344a613500, the Mac's Metal and Apple OpenCL reading) and hl-v6-all (the # all-together pack, id 9d40978601a7df2a; with the second zip its OpenCL text is the window's real text and the expected # fingerprint is the CUDA reference e8f4f3289c6ee1fc; the first zip's stub refused it, that refusal line being that run's record). -# Kit fetch job fetch-class-v6-kit-20261008 = the second zip (packs-class-v6-.zip named in the job's publish line). +# Kit fetch job fetch-class-v6-kit-20261008-g6 = the third zip packs-class-v6-20261008T194045Z.zip (735e1411...), generator 6 packs; the +# earlier dir fetch-class-v6-kit-20261008 holds zip 2 (generator 5) and stays as the generator 5 record's kit. # Class v5 kit bench on the Intel Arc B580 (7 October 2026, 23:5x UK, main's word: the B580 is the eGPU of the second PC, # so the Intel fingerprint runs there through the hash lane's job queue as a lock-free, non-elevated, quiet job, never beside # an install or a build; the page names no PC): tools/class-v5/pc1-amd-v5-bench.ps1 with the device @@ -25,7 +26,7 @@ # (59e6708e46f1e87c and 5a6ad122a71a888f) belong to the superseded packs and no longer match by construction. $ErrorActionPreference = 'Continue' $jobName = 'arc-v6-bench' -$kitId = $env:IGNEUM_V5_KIT_ID; if (-not $kitId) { $kitId = 'fetch-class-v6-kit-20261008' } +$kitId = $env:IGNEUM_V5_KIT_ID; if (-not $kitId) { $kitId = 'fetch-class-v6-kit-20261008-g6' } # a fresh dir for the generator 6 zip: a fetch into the old dir left zip 2's files in place (PC 2, 20:17 UK) $expected = '6ce3dc344a613500' $started = Get-Date function Stamp { (Get-Date).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ') } From 027c26b44bda06d5a28fb8ceee784dd4f8796dd2 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Thu, 8 Oct 2026 20:43:47 +0000 Subject: [PATCH 33/36] registry: the kit's cell names master's case id R2-F03-R02 (REV-F03-2 renamed on master) and the batch carries its method (GPU); re-recorded, the map page regenerated Co-Authored-By: Claude Fable 5.1 --- docs/plans/igneum-2.0-test-harness-map.md | 2 +- tools/ci/batches/kit-class-v6-20261008-01.json | 3 ++- tools/ci/test-map.json | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/plans/igneum-2.0-test-harness-map.md b/docs/plans/igneum-2.0-test-harness-map.md index e0d0e49d8..9b60631c1 100644 --- a/docs/plans/igneum-2.0-test-harness-map.md +++ b/docs/plans/igneum-2.0-test-harness-map.md @@ -371,7 +371,7 @@ Rule: a case maps to a cell only where the cell's tests visibly answer it; cover - Box class: build box + pods + Mac + PC 1 + PC 2 - Fixtures: F0, F2 - Cases: - - REV-F03-2 : partial: the worker half (CPU reference, CUDA, Metal, OpenCL) on the same program packs; the node's and the pool's accepted work on the same job context are the CI steward's and the pool lane's cells; PASS only when every listed platform reads one fingerprint and the node and pool halves are green + - R2-F03-R02 Same job context produces identical accepted work in node, CPU reference, CUDA, Metal, OpenCL and pool.: partial: the worker half (CPU reference, CUDA, Metal, OpenCL) on the same program packs; the node's and the pool's accepted work on the same job context are the CI steward's and the pool lane's cells; PASS only when every listed platform reads one fingerprint and the node and pool halves are green ## Automated cases with no harness in the matrix (NOT RUN, the reason) diff --git a/tools/ci/batches/kit-class-v6-20261008-01.json b/tools/ci/batches/kit-class-v6-20261008-01.json index 62cbd8ce1..f55491d26 100644 --- a/tools/ci/batches/kit-class-v6-20261008-01.json +++ b/tools/ci/batches/kit-class-v6-20261008-01.json @@ -11,5 +11,6 @@ "status": "RUNNING", "evidence": "docs/design/class-v5-stored-state.md (section 0, the class v6 kit row: the generator 6 packs hl-v6-all 4de7b836cc40a4ea and hl-v6-foldrw d7eba30115d26dd4 read e8f4f3289c6ee1fc and 6ce3dc344a613500 on the CPU emulation check, the CUDA 4090, Metal and Apple OpenCL, 20:41 to 20:52 UK; the RTX 5090, RX 7600 and Arc rows the morning's); build-1:/srv/artefacts/packs/packs-class-v6-20261008T194045Z.zip (sha256 735e1411...); build-1:/srv/builds/_log/v5-class/kits-20261008T194045Z/emu-check.log" } - ] + ], + "method": "GPU" } diff --git a/tools/ci/test-map.json b/tools/ci/test-map.json index c953e3e44..a89420c44 100644 --- a/tools/ci/test-map.json +++ b/tools/ci/test-map.json @@ -638,10 +638,10 @@ "F2" ], "cases": [ - "REV-F03-2" + "R2-F03-R02" ], "coverage": { - "REV-F03-2": "partial: the worker half (CPU reference, CUDA, Metal, OpenCL) on the same program packs; the node's and the pool's accepted work on the same job context are the CI steward's and the pool lane's cells; PASS only when every listed platform reads one fingerprint and the node and pool halves are green" + "R2-F03-R02": "partial: the worker half (CPU reference, CUDA, Metal, OpenCL) on the same program packs; the node's and the pool's accepted work on the same job context are the CI steward's and the pool lane's cells; PASS only when every listed platform reads one fingerprint and the node and pool halves are green" } } }, From 8ce08c5413ac92c379731f9c0e9d2c31d919e2b8 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Thu, 8 Oct 2026 20:44:04 +0000 Subject: [PATCH 34/36] registry: the kit batch cites paths only in its evidence field (the page, zip 4, the emulation log on build-1) with the reading in a note; recorded RUNNING on R2-F03-R02 Co-Authored-By: Claude Fable 5.1 --- docs/plans/igneum-2.0-test-registry.json | 46 ++++++++++++------- .../ci/batches/kit-class-v6-20261008-01.json | 3 +- 2 files changed, 32 insertions(+), 17 deletions(-) diff --git a/docs/plans/igneum-2.0-test-registry.json b/docs/plans/igneum-2.0-test-registry.json index 32b3659da..9d173bed7 100644 --- a/docs/plans/igneum-2.0-test-registry.json +++ b/docs/plans/igneum-2.0-test-registry.json @@ -11823,30 +11823,44 @@ "POW-01", "ROT-02" ], - "updated": "2026-10-08T20:10:24.556Z", + "updated": "2026-10-08T20:44:04.566Z", "evidence_record": { "reason": "R2-F03 (P0, the external review): the regression's harness is the owner lane's (CI steward, hash lane (ProgramClass::V6 on freeze), pool lane); not yet named in the map", - "at": "2026-10-08T20:10:24.556Z", - "method": "static", - "requirement_id": "R2-F03-R02", - "decision": "NOT RUN", - "reviewer": "", - "claim_impact": "", - "release_identity": { - "commit": "", - "lockfile": "", - "binary": "", - "network_object": "", - "activation": "", - "profile_hashes": "" - } + "at": "2026-10-08T20:44:04.566Z" }, "approvals": { "scope_approved": null, "implementation_complete": null, "evidence_reproduced": null, "claim_authorised": null - } + }, + "evidence_records": { + "kit:class-v6-fingerprints": { + "requirement_id": "R2-F03-R02", + "decision": "NOT RUN", + "method": "GPU", + "cell": "kit:class-v6-fingerprints", + "manifest_sha": "ef0f2ed8", + "run_id": "kit-class-v6-20261008-01", + "evidence": "docs/design/class-v5-stored-state.md; build-1:/srv/artefacts/packs/packs-class-v6-20261008T202808Z.zip; build-1:/srv/builds/_log/v5-class/kits-20261008T202808Z/emu-check.log", + "in_progress": true, + "coverage": "partial: the worker half (CPU reference, CUDA, Metal, OpenCL) on the same program packs; the node's and the pool's accepted work on the same job context are the CI steward's and the pool lane's cells; PASS only when every listed platform reads one fingerprint and the node and pool halves are green", + "release_identity": { + "commit": "ef0f2ed8", + "lockfile": "", + "binary": "", + "network_object": "", + "activation": "", + "profile_hashes": "" + }, + "claim_impact": "", + "reviewer": "", + "at": "2026-10-08T20:44:04.566Z" + } + }, + "run_id": "kit-class-v6-20261008-01", + "evidence_path": "docs/design/class-v5-stored-state.md; build-1:/srv/artefacts/packs/packs-class-v6-20261008T202808Z.zip; build-1:/srv/builds/_log/v5-class/kits-20261008T202808Z/emu-check.log", + "in_progress_since": "2026-10-08T20:44:04.566Z" }, { "id": "R2-F03-R03", diff --git a/tools/ci/batches/kit-class-v6-20261008-01.json b/tools/ci/batches/kit-class-v6-20261008-01.json index f55491d26..716817aa9 100644 --- a/tools/ci/batches/kit-class-v6-20261008-01.json +++ b/tools/ci/batches/kit-class-v6-20261008-01.json @@ -9,7 +9,8 @@ { "cell": "kit:class-v6-fingerprints", "status": "RUNNING", - "evidence": "docs/design/class-v5-stored-state.md (section 0, the class v6 kit row: the generator 6 packs hl-v6-all 4de7b836cc40a4ea and hl-v6-foldrw d7eba30115d26dd4 read e8f4f3289c6ee1fc and 6ce3dc344a613500 on the CPU emulation check, the CUDA 4090, Metal and Apple OpenCL, 20:41 to 20:52 UK; the RTX 5090, RX 7600 and Arc rows the morning's); build-1:/srv/artefacts/packs/packs-class-v6-20261008T194045Z.zip (sha256 735e1411...); build-1:/srv/builds/_log/v5-class/kits-20261008T194045Z/emu-check.log" + "evidence": "docs/design/class-v5-stored-state.md; build-1:/srv/artefacts/packs/packs-class-v6-20261008T202808Z.zip; build-1:/srv/builds/_log/v5-class/kits-20261008T202808Z/emu-check.log", + "note": "docs/design/class-v5-stored-state.md section 0, the class v6 kit row: the generator 6 packs hl-v6-all 4de7b836cc40a4ea and hl-v6-foldrw d7eba30115d26dd4 read e8f4f3289c6ee1fc and 6ce3dc344a613500 on the CPU emulation check, the CUDA 4090, Metal and Apple OpenCL (20:41 to 20:52 UK); the RTX 5090, RX 7600 and Arc rows the morning's; the kit zip 4 bb66a546 (kernel texts byte-identical to zip 3)" } ], "method": "GPU" From 2f6e1dfb20a28aca6d61dee4a9754bdc76b5b4e2 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Thu, 8 Oct 2026 20:44:26 +0000 Subject: [PATCH 35/36] registry: R2-F03-R02 leaves the map's not-run table now that the kit's cell names it; recorded RUNNING Co-Authored-By: Claude Fable 5.1 --- docs/plans/igneum-2.0-test-harness-map.md | 3 +-- docs/plans/igneum-2.0-test-registry.json | 26 +++++++++++++++++++---- tools/ci/test-map.json | 1 - 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/docs/plans/igneum-2.0-test-harness-map.md b/docs/plans/igneum-2.0-test-harness-map.md index 9b60631c1..6b0bd29d7 100644 --- a/docs/plans/igneum-2.0-test-harness-map.md +++ b/docs/plans/igneum-2.0-test-harness-map.md @@ -489,7 +489,6 @@ Rule: a case maps to a cell only where the cell's tests visibly answer it; cover - R2-F02-R02 Missing oracle or pinned keys prevents service readiness after enforcement activation.: R2-F02 (P0, the external review): the regression's harness is the owner lane's (proving lane, CI steward); not yet named in the map - R2-F02-R03 Missing proof bytes retry without incorrectly marking a valid block permanently invalid.: R2-F02 (P0, the external review): the regression's harness is the owner lane's (proving lane, CI steward); not yet named in the map - R2-F03-R01 Clean build from one manifest, including the pool and workers, with no unpublished vendor tree.: R2-F03 (P0, the external review): the regression's harness is the owner lane's (CI steward, hash lane (ProgramClass::V6 on freeze), pool lane); not yet named in the map -- R2-F03-R02 Same job context produces identical accepted work in node, CPU reference, CUDA, Metal, OpenCL and pool.: R2-F03 (P0, the external review): the regression's harness is the owner lane's (CI steward, hash lane (ProgramClass::V6 on freeze), pool lane); not yet named in the map - R2-F03-R03 Cross every scheduled transition with old/new client behavior documented and identical rule identities.: R2-F03 (P0, the external review): the regression's harness is the owner lane's (CI steward, hash lane (ProgramClass::V6 on freeze), pool lane); not yet named in the map - R2-F04-R01 Native multi-node 40/40/20 partition, equivocation and dust-valid mining on both sides past the window.: R2-F04 (P0, the external review): the regression's harness is the owner lane's (node lane, reference apps, site (explorer)); not yet named in the map - R2-F04-R02 Proof that the chosen recovery guarantee matches the public finality claim; two valid contradictory certificates are a hard failure for strong finality.: R2-F04 (P0, the external review): the regression's harness is the owner lane's (node lane, reference apps, site (explorer)); not yet named in the map @@ -528,4 +527,4 @@ Rule: a case maps to a cell only where the cell's tests visibly answer it; cover ## Count -171 automated cases: 78 mapped to a cell, 150 NOT RUN with a reason. +171 automated cases: 78 mapped to a cell, 149 NOT RUN with a reason. diff --git a/docs/plans/igneum-2.0-test-registry.json b/docs/plans/igneum-2.0-test-registry.json index 9d173bed7..30912946b 100644 --- a/docs/plans/igneum-2.0-test-registry.json +++ b/docs/plans/igneum-2.0-test-registry.json @@ -11823,10 +11823,28 @@ "POW-01", "ROT-02" ], - "updated": "2026-10-08T20:44:04.566Z", + "updated": "2026-10-08T20:44:26.350Z", "evidence_record": { - "reason": "R2-F03 (P0, the external review): the regression's harness is the owner lane's (CI steward, hash lane (ProgramClass::V6 on freeze), pool lane); not yet named in the map", - "at": "2026-10-08T20:44:04.566Z" + "requirement_id": "R2-F03-R02", + "decision": "NOT RUN", + "method": "GPU", + "cell": "kit:class-v6-fingerprints", + "manifest_sha": "ef0f2ed8", + "run_id": "kit-class-v6-20261008-01", + "evidence": "docs/design/class-v5-stored-state.md; build-1:/srv/artefacts/packs/packs-class-v6-20261008T202808Z.zip; build-1:/srv/builds/_log/v5-class/kits-20261008T202808Z/emu-check.log", + "in_progress": true, + "coverage": "partial: the worker half (CPU reference, CUDA, Metal, OpenCL) on the same program packs; the node's and the pool's accepted work on the same job context are the CI steward's and the pool lane's cells; PASS only when every listed platform reads one fingerprint and the node and pool halves are green", + "release_identity": { + "commit": "ef0f2ed8", + "lockfile": "", + "binary": "", + "network_object": "", + "activation": "", + "profile_hashes": "" + }, + "claim_impact": "", + "reviewer": "", + "at": "2026-10-08T20:44:26.350Z" }, "approvals": { "scope_approved": null, @@ -11855,7 +11873,7 @@ }, "claim_impact": "", "reviewer": "", - "at": "2026-10-08T20:44:04.566Z" + "at": "2026-10-08T20:44:26.350Z" } }, "run_id": "kit-class-v6-20261008-01", diff --git a/tools/ci/test-map.json b/tools/ci/test-map.json index a89420c44..281af9ec6 100644 --- a/tools/ci/test-map.json +++ b/tools/ci/test-map.json @@ -760,7 +760,6 @@ "R2-F02-R02": "R2-F02 (P0, the external review): the regression's harness is the owner lane's (proving lane, CI steward); not yet named in the map", "R2-F02-R03": "R2-F02 (P0, the external review): the regression's harness is the owner lane's (proving lane, CI steward); not yet named in the map", "R2-F03-R01": "R2-F03 (P0, the external review): the regression's harness is the owner lane's (CI steward, hash lane (ProgramClass::V6 on freeze), pool lane); not yet named in the map", - "R2-F03-R02": "R2-F03 (P0, the external review): the regression's harness is the owner lane's (CI steward, hash lane (ProgramClass::V6 on freeze), pool lane); not yet named in the map", "R2-F03-R03": "R2-F03 (P0, the external review): the regression's harness is the owner lane's (CI steward, hash lane (ProgramClass::V6 on freeze), pool lane); not yet named in the map", "R2-F04-R01": "R2-F04 (P0, the external review): the regression's harness is the owner lane's (node lane, reference apps, site (explorer)); not yet named in the map", "R2-F04-R02": "R2-F04 (P0, the external review): the regression's harness is the owner lane's (node lane, reference apps, site (explorer)); not yet named in the map", From b89cfe0164287297ab48fd9387aa9ad4e84e6e1d Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Thu, 8 Oct 2026 20:58:29 +0000 Subject: [PATCH 36/36] registry: the REV suite rewritten by its generator (the merge gate's red: the recorder's write left the suites in another order; the kit's record on R2-F03-R02 kept) Co-Authored-By: Claude Fable 5.1 --- docs/plans/igneum-2.0-test-registry.json | 1802 +++++++++++----------- 1 file changed, 889 insertions(+), 913 deletions(-) diff --git a/docs/plans/igneum-2.0-test-registry.json b/docs/plans/igneum-2.0-test-registry.json index 30912946b..6977d17fd 100644 --- a/docs/plans/igneum-2.0-test-registry.json +++ b/docs/plans/igneum-2.0-test-registry.json @@ -11332,6 +11332,891 @@ } ] }, + { + "code": "INT", + "title": "INT: the master edition's integration gates (R1, the full-system review)", + "source": "docs/plans/igneum-2.0-master/traceability.json integration_gates", + "gate": "Integration gates closed", + "owner": "the owner lanes per the coordinator's crosswalk", + "fixtures": [ + "F0", + "F5" + ], + "summary": "18 integration gates; each reads NOT RUN until its owner lane records a run", + "tests": [ + { + "id": "INT-01", + "title": "Real proof H cannot authenticate a different statement under a warm cache.", + "setup": "Integration gate INT-01 of the master edition (R1 / Additional regression gates).", + "steps": [ + "Real proof H cannot authenticate a different statement under a warm cache." + ], + "accept": "Real proof H cannot authenticate a different statement under a warm cache.", + "evidence": "The run record of the gate as its owner lane records it through tools/ci/test-record.mjs.", + "priority": "P0", + "profile": "P00", + "cadence": "Every release candidate", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + "R1" + ], + "gate": "Integration gates closed", + "owner": "proving lane (a6e8f84588b809d62)", + "manual_page": null, + "owner_lane": "proving lane (a6e8f84588b809d62)", + "run_status": "NOT RUN", + "master_status": "PROPOSED / NOT RUN", + "updated": "2026-10-08T20:10:24.556Z", + "evidence_record": { + "reason": "INT-01 (R1 integration gate): the gate's harness is the owner lane's (proving lane (a6e8f84588b809d62)); not yet named in the map", + "at": "2026-10-08T20:10:24.556Z", + "method": "static", + "requirement_id": "INT-01", + "decision": "NOT RUN", + "reviewer": "", + "claim_impact": "", + "release_identity": { + "commit": "", + "lockfile": "", + "binary": "", + "network_object": "", + "activation": "", + "profile_hashes": "" + } + }, + "approvals": { + "scope_approved": null, + "implementation_complete": null, + "evidence_reproduced": null, + "claim_authorised": null + } + }, + { + "id": "INT-02", + "title": "Warm/cold/relay/restart/concurrent cache order does not change block or payout decisions; negative cache isolated.", + "setup": "Integration gate INT-02 of the master edition (R1 / Additional regression gates).", + "steps": [ + "Warm/cold/relay/restart/concurrent cache order does not change block or payout decisions; negative cache isolated." + ], + "accept": "Warm/cold/relay/restart/concurrent cache order does not change block or payout decisions; negative cache isolated.", + "evidence": "The run record of the gate as its owner lane records it through tools/ci/test-record.mjs.", + "priority": "P0", + "profile": "P00", + "cadence": "Every release candidate", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + "R1" + ], + "gate": "Integration gates closed", + "owner": "proving lane (a6e8f84588b809d62)", + "manual_page": null, + "owner_lane": "proving lane (a6e8f84588b809d62)", + "run_status": "NOT RUN", + "master_status": "PROPOSED / NOT RUN", + "updated": "2026-10-08T20:10:24.556Z", + "evidence_record": { + "reason": "INT-02 (R1 integration gate): the gate's harness is the owner lane's (proving lane (a6e8f84588b809d62)); not yet named in the map", + "at": "2026-10-08T20:10:24.556Z", + "method": "static", + "requirement_id": "INT-02", + "decision": "NOT RUN", + "reviewer": "", + "claim_impact": "", + "release_identity": { + "commit": "", + "lockfile": "", + "binary": "", + "network_object": "", + "activation": "", + "profile_hashes": "" + } + }, + "approvals": { + "scope_approved": null, + "implementation_complete": null, + "evidence_reproduced": null, + "claim_authorised": null + } + }, + { + "id": "INT-03", + "title": "Durable payout outbox survives every crash/RPC boundary without duplicate or lost liabilities.", + "setup": "Integration gate INT-03 of the master edition (R1 / Additional regression gates).", + "steps": [ + "Durable payout outbox survives every crash/RPC boundary without duplicate or lost liabilities." + ], + "accept": "Durable payout outbox survives every crash/RPC boundary without duplicate or lost liabilities.", + "evidence": "The run record of the gate as its owner lane records it through tools/ci/test-record.mjs.", + "priority": "P0", + "profile": "P00", + "cadence": "Every release candidate", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + "R1" + ], + "gate": "Integration gates closed", + "owner": "pool lane (a1c484c48a62948c2)", + "manual_page": null, + "owner_lane": "pool lane (a1c484c48a62948c2)", + "run_status": "NOT RUN", + "master_status": "PROPOSED / NOT RUN", + "updated": "2026-10-08T20:10:24.556Z", + "evidence_record": { + "reason": "INT-03 (R1 integration gate): the gate's harness is the owner lane's (pool lane (a1c484c48a62948c2)); not yet named in the map", + "at": "2026-10-08T20:10:24.556Z", + "method": "static", + "requirement_id": "INT-03", + "decision": "NOT RUN", + "reviewer": "", + "claim_impact": "", + "release_identity": { + "commit": "", + "lockfile": "", + "binary": "", + "network_object": "", + "activation": "", + "profile_hashes": "" + } + }, + "approvals": { + "scope_approved": null, + "implementation_complete": null, + "evidence_reproduced": null, + "claim_authorised": null + } + }, + { + "id": "INT-04", + "title": "Corrupt existing pool state, disk-full and reorg cause safe recovery, not silent empty balances.", + "setup": "Integration gate INT-04 of the master edition (R1 / Additional regression gates).", + "steps": [ + "Corrupt existing pool state, disk-full and reorg cause safe recovery, not silent empty balances." + ], + "accept": "Corrupt existing pool state, disk-full and reorg cause safe recovery, not silent empty balances.", + "evidence": "The run record of the gate as its owner lane records it through tools/ci/test-record.mjs.", + "priority": "P0", + "profile": "P00", + "cadence": "Every release candidate", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + "R1" + ], + "gate": "Integration gates closed", + "owner": "pool lane (a1c484c48a62948c2)", + "manual_page": null, + "owner_lane": "pool lane (a1c484c48a62948c2)", + "run_status": "NOT RUN", + "master_status": "PROPOSED / NOT RUN", + "updated": "2026-10-08T20:10:24.556Z", + "evidence_record": { + "reason": "INT-04 (R1 integration gate): the gate's harness is the owner lane's (pool lane (a1c484c48a62948c2)); not yet named in the map", + "at": "2026-10-08T20:10:24.556Z", + "method": "static", + "requirement_id": "INT-04", + "decision": "NOT RUN", + "reviewer": "", + "claim_impact": "", + "release_identity": { + "commit": "", + "lockfile": "", + "binary": "", + "network_object": "", + "activation": "", + "profile_hashes": "" + } + }, + "approvals": { + "scope_approved": null, + "implementation_complete": null, + "evidence_reproduced": null, + "claim_authorised": null + } + }, + { + "id": "INT-05", + "title": "The supplied finality implementation matches the approved anchor rule after >window healing.", + "setup": "Integration gate INT-05 of the master edition (R1 / Additional regression gates).", + "steps": [ + "The supplied finality implementation matches the approved anchor rule after >window healing." + ], + "accept": "The supplied finality implementation matches the approved anchor rule after >window healing.", + "evidence": "The run record of the gate as its owner lane records it through tools/ci/test-record.mjs.", + "priority": "P0", + "profile": "P00", + "cadence": "Every release candidate", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + "R1" + ], + "gate": "Integration gates closed", + "owner": "node lane (a283f5f0d364ceef0)", + "manual_page": null, + "owner_lane": "node lane (a283f5f0d364ceef0)", + "run_status": "NOT RUN", + "master_status": "PROPOSED / NOT RUN", + "updated": "2026-10-08T20:10:24.556Z", + "evidence_record": { + "reason": "INT-05 (R1 integration gate): the gate's harness is the owner lane's (node lane (a283f5f0d364ceef0)); not yet named in the map", + "at": "2026-10-08T20:10:24.556Z", + "method": "static", + "requirement_id": "INT-05", + "decision": "NOT RUN", + "reviewer": "", + "claim_impact": "", + "release_identity": { + "commit": "", + "lockfile": "", + "binary": "", + "network_object": "", + "activation": "", + "profile_hashes": "" + } + }, + "approvals": { + "scope_approved": null, + "implementation_complete": null, + "evidence_reproduced": null, + "claim_authorised": null + } + }, + { + "id": "INT-06", + "title": "Recovery tests state and preserve their weaker fault bound; interfaces never label it as a stronger guarantee.", + "setup": "Integration gate INT-06 of the master edition (R1 / Additional regression gates).", + "steps": [ + "Recovery tests state and preserve their weaker fault bound; interfaces never label it as a stronger guarantee." + ], + "accept": "Recovery tests state and preserve their weaker fault bound; interfaces never label it as a stronger guarantee.", + "evidence": "The run record of the gate as its owner lane records it through tools/ci/test-record.mjs.", + "priority": "P0", + "profile": "P00", + "cadence": "Every release candidate", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + "R1" + ], + "gate": "Integration gates closed", + "owner": "node lane (a283f5f0d364ceef0)", + "manual_page": null, + "owner_lane": "node lane (a283f5f0d364ceef0)", + "run_status": "NOT RUN", + "master_status": "PROPOSED / NOT RUN", + "updated": "2026-10-08T20:10:24.556Z", + "evidence_record": { + "reason": "INT-06 (R1 integration gate): the gate's harness is the owner lane's (node lane (a283f5f0d364ceef0)); not yet named in the map", + "at": "2026-10-08T20:10:24.556Z", + "method": "static", + "requirement_id": "INT-06", + "decision": "NOT RUN", + "reviewer": "", + "claim_impact": "", + "release_identity": { + "commit": "", + "lockfile": "", + "binary": "", + "network_object": "", + "activation": "", + "profile_hashes": "" + } + }, + "approvals": { + "scope_approved": null, + "implementation_complete": null, + "evidence_reproduced": null, + "claim_authorised": null + } + }, + { + "id": "INT-07", + "title": "One v6 object agrees in node, pool, CPU verifier and each supported GPU host across activation.", + "definition": "V6-12 (R1 p. 213): the release manifest is signed and binds lockfile hashes, kernel and host binaries, supported devices and drivers, the prover server patch, memory thresholds and tuner identity, with end-to-end artifact authentication and a clean-install accepted-and-paid test on an independent machine with no unpublished files, symlinks or shell overrides.", + "setup": "Integration gate INT-07 of the master edition (R1 / Additional regression gates).", + "steps": [ + "One v6 object agrees in node, pool, CPU verifier and each supported GPU host across activation." + ], + "accept": "One v6 object agrees in node, pool, CPU verifier and each supported GPU host across activation.", + "evidence": "The run record of the gate as its owner lane records it through tools/ci/test-record.mjs.", + "priority": "P0", + "profile": "P00", + "cadence": "Every release candidate", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + "R1" + ], + "gate": "Integration gates closed", + "owner": "CI steward with the hash lane (a690540514aa453d7) and the worker lane (a9e87343f008e0edd)", + "manual_page": null, + "owner_lane": "CI steward with the hash lane (a690540514aa453d7) and the worker lane (a9e87343f008e0edd)", + "run_status": "NOT RUN", + "master_status": "PROPOSED / NOT RUN", + "updated": "2026-10-08T20:10:24.556Z", + "evidence_record": { + "reason": "INT-07 (R1 integration gate): the gate's harness is the owner lane's (CI steward with the hash lane (a690540514aa453d7) and the worker lane (a9e87343f008e0edd)); not yet named in the map", + "at": "2026-10-08T20:10:24.556Z", + "method": "static", + "requirement_id": "INT-07", + "decision": "NOT RUN", + "reviewer": "", + "claim_impact": "", + "release_identity": { + "commit": "", + "lockfile": "", + "binary": "", + "network_object": "", + "activation": "", + "profile_hashes": "" + } + }, + "approvals": { + "scope_approved": null, + "implementation_complete": null, + "evidence_reproduced": null, + "claim_authorised": null + } + }, + { + "id": "INT-08", + "title": "Census, production acceptance, schedule counters and live-dataset tests use the identical frozen contract.", + "setup": "Integration gate INT-08 of the master edition (R1 / Additional regression gates).", + "steps": [ + "Census, production acceptance, schedule counters and live-dataset tests use the identical frozen contract." + ], + "accept": "Census, production acceptance, schedule counters and live-dataset tests use the identical frozen contract.", + "evidence": "The run record of the gate as its owner lane records it through tools/ci/test-record.mjs.", + "priority": "P0", + "profile": "P00", + "cadence": "Every release candidate", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + "R1" + ], + "gate": "Integration gates closed", + "owner": "CI steward with the hash lane (a690540514aa453d7) and the worker lane (a9e87343f008e0edd)", + "manual_page": null, + "owner_lane": "CI steward with the hash lane (a690540514aa453d7) and the worker lane (a9e87343f008e0edd)", + "run_status": "NOT RUN", + "master_status": "PROPOSED / NOT RUN", + "updated": "2026-10-08T20:10:24.556Z", + "evidence_record": { + "reason": "INT-08 (R1 integration gate): the gate's harness is the owner lane's (CI steward with the hash lane (a690540514aa453d7) and the worker lane (a9e87343f008e0edd)); not yet named in the map", + "at": "2026-10-08T20:10:24.556Z", + "method": "static", + "requirement_id": "INT-08", + "decision": "NOT RUN", + "reviewer": "", + "claim_impact": "", + "release_identity": { + "commit": "", + "lockfile": "", + "binary": "", + "network_object": "", + "activation": "", + "profile_hashes": "" + } + }, + "approvals": { + "scope_approved": null, + "implementation_complete": null, + "evidence_reproduced": null, + "claim_authorised": null + } + }, + { + "id": "INT-09", + "title": "Eight- and twelve-GiB epoch transitions recover deliberately without relying on repeated OOM/watchdog cycles.", + "setup": "Integration gate INT-09 of the master edition (R1 / Additional regression gates).", + "steps": [ + "Eight- and twelve-GiB epoch transitions recover deliberately without relying on repeated OOM/watchdog cycles." + ], + "accept": "Eight- and twelve-GiB epoch transitions recover deliberately without relying on repeated OOM/watchdog cycles.", + "evidence": "The run record of the gate as its owner lane records it through tools/ci/test-record.mjs.", + "priority": "P0", + "profile": "P00", + "cadence": "Every release candidate", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + "R1" + ], + "gate": "Integration gates closed", + "owner": "app lane", + "manual_page": null, + "owner_lane": "app lane", + "run_status": "NOT RUN", + "master_status": "PROPOSED / NOT RUN", + "updated": "2026-10-08T20:10:24.556Z", + "evidence_record": { + "reason": "INT-09 (R1 integration gate): the gate's harness is the owner lane's (app lane); not yet named in the map", + "at": "2026-10-08T20:10:24.556Z", + "method": "static", + "requirement_id": "INT-09", + "decision": "NOT RUN", + "reviewer": "", + "claim_impact": "", + "release_identity": { + "commit": "", + "lockfile": "", + "binary": "", + "network_object": "", + "activation": "", + "profile_hashes": "" + } + }, + "approvals": { + "scope_approved": null, + "implementation_complete": null, + "evidence_reproduced": null, + "claim_authorised": null + } + }, + { + "id": "INT-10", + "title": "Metal/CUDA/OpenCL exact dataset geometry agrees; unsupported packs reject before launch.", + "setup": "Integration gate INT-10 of the master edition (R1 / Additional regression gates).", + "steps": [ + "Metal/CUDA/OpenCL exact dataset geometry agrees; unsupported packs reject before launch." + ], + "accept": "Metal/CUDA/OpenCL exact dataset geometry agrees; unsupported packs reject before launch.", + "evidence": "The run record of the gate as its owner lane records it through tools/ci/test-record.mjs.", + "priority": "P0", + "profile": "P00", + "cadence": "Every release candidate", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + "R1" + ], + "gate": "Integration gates closed", + "owner": "CI steward with the hash lane (a690540514aa453d7) and the worker lane (a9e87343f008e0edd)", + "manual_page": null, + "owner_lane": "CI steward with the hash lane (a690540514aa453d7) and the worker lane (a9e87343f008e0edd)", + "run_status": "NOT RUN", + "master_status": "PROPOSED / NOT RUN", + "updated": "2026-10-08T20:10:24.556Z", + "evidence_record": { + "reason": "INT-10 (R1 integration gate): the gate's harness is the owner lane's (CI steward with the hash lane (a690540514aa453d7) and the worker lane (a9e87343f008e0edd)); not yet named in the map", + "at": "2026-10-08T20:10:24.556Z", + "method": "static", + "requirement_id": "INT-10", + "decision": "NOT RUN", + "reviewer": "", + "claim_impact": "", + "release_identity": { + "commit": "", + "lockfile": "", + "binary": "", + "network_object": "", + "activation": "", + "profile_hashes": "" + } + }, + "approvals": { + "scope_approved": null, + "implementation_complete": null, + "evidence_reproduced": null, + "claim_authorised": null + } + }, + { + "id": "INT-11", + "title": "Only a memory-reserved proving job launches; mining buffers really release when required.", + "setup": "Integration gate INT-11 of the master edition (R1 / Additional regression gates).", + "steps": [ + "Only a memory-reserved proving job launches; mining buffers really release when required." + ], + "accept": "Only a memory-reserved proving job launches; mining buffers really release when required.", + "evidence": "The run record of the gate as its owner lane records it through tools/ci/test-record.mjs.", + "priority": "P0", + "profile": "P00", + "cadence": "Every release candidate", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + "R1" + ], + "gate": "Integration gates closed", + "owner": "app lane", + "manual_page": null, + "owner_lane": "app lane", + "run_status": "NOT RUN", + "master_status": "PROPOSED / NOT RUN", + "updated": "2026-10-08T20:10:24.556Z", + "evidence_record": { + "reason": "INT-11 (R1 integration gate): the gate's harness is the owner lane's (app lane); not yet named in the map", + "at": "2026-10-08T20:10:24.556Z", + "method": "static", + "requirement_id": "INT-11", + "decision": "NOT RUN", + "reviewer": "", + "claim_impact": "", + "release_identity": { + "commit": "", + "lockfile": "", + "binary": "", + "network_object": "", + "activation": "", + "profile_hashes": "" + } + }, + "approvals": { + "scope_approved": null, + "implementation_complete": null, + "evidence_reproduced": null, + "claim_authorised": null + } + }, + { + "id": "INT-12", + "title": "Transient shard errors can retry safely; expiration, loss and paid work remain distinct durable outcomes.", + "setup": "Integration gate INT-12 of the master edition (R1 / Additional regression gates).", + "steps": [ + "Transient shard errors can retry safely; expiration, loss and paid work remain distinct durable outcomes." + ], + "accept": "Transient shard errors can retry safely; expiration, loss and paid work remain distinct durable outcomes.", + "evidence": "The run record of the gate as its owner lane records it through tools/ci/test-record.mjs.", + "priority": "P0", + "profile": "P00", + "cadence": "Every release candidate", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + "R1" + ], + "gate": "Integration gates closed", + "owner": "proving lane (a6e8f84588b809d62) and fleet lane (ac055d60427caab99)", + "manual_page": null, + "owner_lane": "proving lane (a6e8f84588b809d62) and fleet lane (ac055d60427caab99)", + "run_status": "NOT RUN", + "master_status": "PROPOSED / NOT RUN", + "updated": "2026-10-08T20:10:24.556Z", + "evidence_record": { + "reason": "INT-12 (R1 integration gate): the gate's harness is the owner lane's (proving lane (a6e8f84588b809d62) and fleet lane (ac055d60427caab99)); not yet named in the map", + "at": "2026-10-08T20:10:24.556Z", + "method": "static", + "requirement_id": "INT-12", + "decision": "NOT RUN", + "reviewer": "", + "claim_impact": "", + "release_identity": { + "commit": "", + "lockfile": "", + "binary": "", + "network_object": "", + "activation": "", + "profile_hashes": "" + } + }, + "approvals": { + "scope_approved": null, + "implementation_complete": null, + "evidence_reproduced": null, + "claim_authorised": null + } + }, + { + "id": "INT-13", + "title": "Ember cannot retain a rate-ineligible prior; material workload changes invalidate incompatible profiles.", + "setup": "Integration gate INT-13 of the master edition (R1 / Additional regression gates).", + "steps": [ + "Ember cannot retain a rate-ineligible prior; material workload changes invalidate incompatible profiles." + ], + "accept": "Ember cannot retain a rate-ineligible prior; material workload changes invalidate incompatible profiles.", + "evidence": "The run record of the gate as its owner lane records it through tools/ci/test-record.mjs.", + "priority": "P0", + "profile": "P00", + "cadence": "Every release candidate", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + "R1" + ], + "gate": "Integration gates closed", + "owner": "Ember lane (a04fe3451877e2ff0) with the app lane", + "manual_page": null, + "owner_lane": "Ember lane (a04fe3451877e2ff0) with the app lane", + "run_status": "NOT RUN", + "master_status": "PROPOSED / NOT RUN", + "updated": "2026-10-08T20:10:24.556Z", + "evidence_record": { + "reason": "INT-13 (R1 integration gate): the gate's harness is the owner lane's (Ember lane (a04fe3451877e2ff0) with the app lane); not yet named in the map", + "at": "2026-10-08T20:10:24.556Z", + "method": "static", + "requirement_id": "INT-13", + "decision": "NOT RUN", + "reviewer": "", + "claim_impact": "", + "release_identity": { + "commit": "", + "lockfile": "", + "binary": "", + "network_object": "", + "activation": "", + "profile_hashes": "" + } + }, + "approvals": { + "scope_approved": null, + "implementation_complete": null, + "evidence_reproduced": null, + "claim_authorised": null + } + }, + { + "id": "INT-14", + "title": "Protected helper and per-device leases restore owned settings on normal/abnormal exit; real ACL/security tests.", + "setup": "Integration gate INT-14 of the master edition (R1 / Additional regression gates).", + "steps": [ + "Protected helper and per-device leases restore owned settings on normal/abnormal exit; real ACL/security tests." + ], + "accept": "Protected helper and per-device leases restore owned settings on normal/abnormal exit; real ACL/security tests.", + "evidence": "The run record of the gate as its owner lane records it through tools/ci/test-record.mjs.", + "priority": "P0", + "profile": "P00", + "cadence": "Every release candidate", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + "R1" + ], + "gate": "Integration gates closed", + "owner": "Ember lane (a04fe3451877e2ff0) with the app lane", + "manual_page": null, + "owner_lane": "Ember lane (a04fe3451877e2ff0) with the app lane", + "run_status": "NOT RUN", + "master_status": "PROPOSED / NOT RUN", + "updated": "2026-10-08T20:10:24.556Z", + "evidence_record": { + "reason": "INT-14 (R1 integration gate): the gate's harness is the owner lane's (Ember lane (a04fe3451877e2ff0) with the app lane); not yet named in the map", + "at": "2026-10-08T20:10:24.556Z", + "method": "static", + "requirement_id": "INT-14", + "decision": "NOT RUN", + "reviewer": "", + "claim_impact": "", + "release_identity": { + "commit": "", + "lockfile": "", + "binary": "", + "network_object": "", + "activation": "", + "profile_hashes": "" + } + }, + "approvals": { + "scope_approved": null, + "implementation_complete": null, + "evidence_reproduced": null, + "claim_authorised": null + } + }, + { + "id": "INT-15", + "title": "Public PoP replay is not session authorization; payout/server/network binding enforced.", + "setup": "Integration gate INT-15 of the master edition (R1 / Additional regression gates).", + "steps": [ + "Public PoP replay is not session authorization; payout/server/network binding enforced." + ], + "accept": "Public PoP replay is not session authorization; payout/server/network binding enforced.", + "evidence": "The run record of the gate as its owner lane records it through tools/ci/test-record.mjs.", + "priority": "P0", + "profile": "P00", + "cadence": "Every release candidate", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + "R1" + ], + "gate": "Integration gates closed", + "owner": "pool lane (a1c484c48a62948c2)", + "manual_page": null, + "owner_lane": "pool lane (a1c484c48a62948c2)", + "run_status": "NOT RUN", + "master_status": "PROPOSED / NOT RUN", + "updated": "2026-10-08T20:10:24.556Z", + "evidence_record": { + "reason": "INT-15 (R1 integration gate): the gate's harness is the owner lane's (pool lane (a1c484c48a62948c2)); not yet named in the map", + "at": "2026-10-08T20:10:24.556Z", + "method": "static", + "requirement_id": "INT-15", + "decision": "NOT RUN", + "reviewer": "", + "claim_impact": "", + "release_identity": { + "commit": "", + "lockfile": "", + "binary": "", + "network_object": "", + "activation": "", + "profile_hashes": "" + } + }, + "approvals": { + "scope_approved": null, + "implementation_complete": null, + "evidence_reproduced": null, + "claim_authorised": null + } + }, + { + "id": "INT-16", + "title": "Pool parsing/queues/connection and crypto budgets remain bounded under controlled adversarial traffic.", + "setup": "Integration gate INT-16 of the master edition (R1 / Additional regression gates).", + "steps": [ + "Pool parsing/queues/connection and crypto budgets remain bounded under controlled adversarial traffic." + ], + "accept": "Pool parsing/queues/connection and crypto budgets remain bounded under controlled adversarial traffic.", + "evidence": "The run record of the gate as its owner lane records it through tools/ci/test-record.mjs.", + "priority": "P0", + "profile": "P00", + "cadence": "Every release candidate", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + "R1" + ], + "gate": "Integration gates closed", + "owner": "pool lane (a1c484c48a62948c2)", + "manual_page": null, + "owner_lane": "pool lane (a1c484c48a62948c2)", + "run_status": "NOT RUN", + "master_status": "PROPOSED / NOT RUN", + "updated": "2026-10-08T20:10:24.556Z", + "evidence_record": { + "reason": "INT-16 (R1 integration gate): the gate's harness is the owner lane's (pool lane (a1c484c48a62948c2)); not yet named in the map", + "at": "2026-10-08T20:10:24.556Z", + "method": "static", + "requirement_id": "INT-16", + "decision": "NOT RUN", + "reviewer": "", + "claim_impact": "", + "release_identity": { + "commit": "", + "lockfile": "", + "binary": "", + "network_object": "", + "activation": "", + "profile_hashes": "" + } + }, + "approvals": { + "scope_approved": null, + "implementation_complete": null, + "evidence_reproduced": null, + "claim_authorised": null + } + }, + { + "id": "INT-17", + "title": "Missing oracle/keys/mandatory real-proof fixture blocks the applicable production acceptance gate.", + "setup": "Integration gate INT-17 of the master edition (R1 / Additional regression gates).", + "steps": [ + "Missing oracle/keys/mandatory real-proof fixture blocks the applicable production acceptance gate." + ], + "accept": "Missing oracle/keys/mandatory real-proof fixture blocks the applicable production acceptance gate.", + "evidence": "The run record of the gate as its owner lane records it through tools/ci/test-record.mjs.", + "priority": "P0", + "profile": "P00", + "cadence": "Every release candidate", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + "R1" + ], + "gate": "Integration gates closed", + "owner": "proving lane (a6e8f84588b809d62)", + "manual_page": null, + "owner_lane": "proving lane (a6e8f84588b809d62)", + "run_status": "NOT RUN", + "master_status": "PROPOSED / NOT RUN", + "updated": "2026-10-08T20:10:24.556Z", + "evidence_record": { + "reason": "INT-17 (R1 integration gate): the gate's harness is the owner lane's (proving lane (a6e8f84588b809d62)); not yet named in the map", + "at": "2026-10-08T20:10:24.556Z", + "method": "static", + "requirement_id": "INT-17", + "decision": "NOT RUN", + "reviewer": "", + "claim_impact": "", + "release_identity": { + "commit": "", + "lockfile": "", + "binary": "", + "network_object": "", + "activation": "", + "profile_hashes": "" + } + }, + "approvals": { + "scope_approved": null, + "implementation_complete": null, + "evidence_reproduced": null, + "claim_authorised": null + } + }, + { + "id": "INT-18", + "title": "Whole-system economics pass the strongest feasible adversary, including sunk development and multi-epoch survival.", + "setup": "Integration gate INT-18 of the master edition (R1 / Additional regression gates).", + "steps": [ + "Whole-system economics pass the strongest feasible adversary, including sunk development and multi-epoch survival." + ], + "accept": "Whole-system economics pass the strongest feasible adversary, including sunk development and multi-epoch survival.", + "evidence": "The run record of the gate as its owner lane records it through tools/ci/test-record.mjs.", + "priority": "P0", + "profile": "P00", + "cadence": "Every release candidate", + "method": "Automated + independent review", + "status": "NOT RUN", + "source": [ + "R1" + ], + "gate": "Integration gates closed", + "owner": "research lane (ad6a2bd47d4a46105)", + "manual_page": null, + "owner_lane": "research lane (ad6a2bd47d4a46105)", + "run_status": "NOT RUN", + "master_status": "PROPOSED / NOT RUN", + "updated": "2026-10-08T20:10:24.556Z", + "evidence_record": { + "reason": "INT-18 (R1 integration gate): the gate's harness is the owner lane's (research lane (ad6a2bd47d4a46105)); not yet named in the map", + "at": "2026-10-08T20:10:24.556Z", + "method": "static", + "requirement_id": "INT-18", + "decision": "NOT RUN", + "reviewer": "", + "claim_impact": "", + "release_identity": { + "commit": "", + "lockfile": "", + "binary": "", + "network_object": "", + "activation": "", + "profile_hashes": "" + } + }, + "approvals": { + "scope_approved": null, + "implementation_complete": null, + "evidence_reproduced": null, + "claim_authorised": null + } + } + ], + "notes": [ + { + "at": "2026-10-08T20:10:24.874Z", + "text": "REC-01 (the master edition's one unresolved interpretation, finality pause-only healing: R1's I03 stale predicate against R2's F04 backfill caveat): closure evidence as the finality and node lanes recorded it on 8 October 2026: rule v4 at release-2.0.0-node 12424341's line, mode recovery by the founder's 19:57 ruling (the lock labelled recovery, never final), both real-node lines PASS tonight by the 6.7 pause criterion, FIN-02 PASS at 0218d6bf1 on the simulator half; status RUNNING until the beyond-window healing case with and without historical data is run natively (the node lane's case tomorrow). Applies to INT-05 and INT-06." + } + ] + }, { "code": "REV", "title": "REV: the external review's required regressions", @@ -11823,6 +12708,8 @@ "POW-01", "ROT-02" ], + "run_id": "kit-class-v6-20261008-01", + "evidence_path": "docs/design/class-v5-stored-state.md; build-1:/srv/artefacts/packs/packs-class-v6-20261008T202808Z.zip; build-1:/srv/builds/_log/v5-class/kits-20261008T202808Z/emu-check.log", "updated": "2026-10-08T20:44:26.350Z", "evidence_record": { "requirement_id": "R2-F03-R02", @@ -11846,39 +12733,13 @@ "reviewer": "", "at": "2026-10-08T20:44:26.350Z" }, + "in_progress_since": "2026-10-08T20:44:04.566Z", "approvals": { "scope_approved": null, "implementation_complete": null, "evidence_reproduced": null, "claim_authorised": null - }, - "evidence_records": { - "kit:class-v6-fingerprints": { - "requirement_id": "R2-F03-R02", - "decision": "NOT RUN", - "method": "GPU", - "cell": "kit:class-v6-fingerprints", - "manifest_sha": "ef0f2ed8", - "run_id": "kit-class-v6-20261008-01", - "evidence": "docs/design/class-v5-stored-state.md; build-1:/srv/artefacts/packs/packs-class-v6-20261008T202808Z.zip; build-1:/srv/builds/_log/v5-class/kits-20261008T202808Z/emu-check.log", - "in_progress": true, - "coverage": "partial: the worker half (CPU reference, CUDA, Metal, OpenCL) on the same program packs; the node's and the pool's accepted work on the same job context are the CI steward's and the pool lane's cells; PASS only when every listed platform reads one fingerprint and the node and pool halves are green", - "release_identity": { - "commit": "ef0f2ed8", - "lockfile": "", - "binary": "", - "network_object": "", - "activation": "", - "profile_hashes": "" - }, - "claim_impact": "", - "reviewer": "", - "at": "2026-10-08T20:44:26.350Z" - } - }, - "run_id": "kit-class-v6-20261008-01", - "evidence_path": "docs/design/class-v5-stored-state.md; build-1:/srv/artefacts/packs/packs-class-v6-20261008T202808Z.zip; build-1:/srv/builds/_log/v5-class/kits-20261008T202808Z/emu-check.log", - "in_progress_since": "2026-10-08T20:44:04.566Z" + } }, { "id": "R2-F03-R03", @@ -13845,891 +14706,6 @@ } } ] - }, - { - "code": "INT", - "title": "INT: the master edition's integration gates (R1, the full-system review)", - "source": "docs/plans/igneum-2.0-master/traceability.json integration_gates", - "gate": "Integration gates closed", - "owner": "the owner lanes per the coordinator's crosswalk", - "fixtures": [ - "F0", - "F5" - ], - "summary": "18 integration gates; each reads NOT RUN until its owner lane records a run", - "tests": [ - { - "id": "INT-01", - "title": "Real proof H cannot authenticate a different statement under a warm cache.", - "setup": "Integration gate INT-01 of the master edition (R1 / Additional regression gates).", - "steps": [ - "Real proof H cannot authenticate a different statement under a warm cache." - ], - "accept": "Real proof H cannot authenticate a different statement under a warm cache.", - "evidence": "The run record of the gate as its owner lane records it through tools/ci/test-record.mjs.", - "priority": "P0", - "profile": "P00", - "cadence": "Every release candidate", - "method": "Automated + independent review", - "status": "NOT RUN", - "source": [ - "R1" - ], - "gate": "Integration gates closed", - "owner": "proving lane (a6e8f84588b809d62)", - "manual_page": null, - "owner_lane": "proving lane (a6e8f84588b809d62)", - "run_status": "NOT RUN", - "master_status": "PROPOSED / NOT RUN", - "updated": "2026-10-08T20:10:24.556Z", - "evidence_record": { - "reason": "INT-01 (R1 integration gate): the gate's harness is the owner lane's (proving lane (a6e8f84588b809d62)); not yet named in the map", - "at": "2026-10-08T20:10:24.556Z", - "method": "static", - "requirement_id": "INT-01", - "decision": "NOT RUN", - "reviewer": "", - "claim_impact": "", - "release_identity": { - "commit": "", - "lockfile": "", - "binary": "", - "network_object": "", - "activation": "", - "profile_hashes": "" - } - }, - "approvals": { - "scope_approved": null, - "implementation_complete": null, - "evidence_reproduced": null, - "claim_authorised": null - } - }, - { - "id": "INT-02", - "title": "Warm/cold/relay/restart/concurrent cache order does not change block or payout decisions; negative cache isolated.", - "setup": "Integration gate INT-02 of the master edition (R1 / Additional regression gates).", - "steps": [ - "Warm/cold/relay/restart/concurrent cache order does not change block or payout decisions; negative cache isolated." - ], - "accept": "Warm/cold/relay/restart/concurrent cache order does not change block or payout decisions; negative cache isolated.", - "evidence": "The run record of the gate as its owner lane records it through tools/ci/test-record.mjs.", - "priority": "P0", - "profile": "P00", - "cadence": "Every release candidate", - "method": "Automated + independent review", - "status": "NOT RUN", - "source": [ - "R1" - ], - "gate": "Integration gates closed", - "owner": "proving lane (a6e8f84588b809d62)", - "manual_page": null, - "owner_lane": "proving lane (a6e8f84588b809d62)", - "run_status": "NOT RUN", - "master_status": "PROPOSED / NOT RUN", - "updated": "2026-10-08T20:10:24.556Z", - "evidence_record": { - "reason": "INT-02 (R1 integration gate): the gate's harness is the owner lane's (proving lane (a6e8f84588b809d62)); not yet named in the map", - "at": "2026-10-08T20:10:24.556Z", - "method": "static", - "requirement_id": "INT-02", - "decision": "NOT RUN", - "reviewer": "", - "claim_impact": "", - "release_identity": { - "commit": "", - "lockfile": "", - "binary": "", - "network_object": "", - "activation": "", - "profile_hashes": "" - } - }, - "approvals": { - "scope_approved": null, - "implementation_complete": null, - "evidence_reproduced": null, - "claim_authorised": null - } - }, - { - "id": "INT-03", - "title": "Durable payout outbox survives every crash/RPC boundary without duplicate or lost liabilities.", - "setup": "Integration gate INT-03 of the master edition (R1 / Additional regression gates).", - "steps": [ - "Durable payout outbox survives every crash/RPC boundary without duplicate or lost liabilities." - ], - "accept": "Durable payout outbox survives every crash/RPC boundary without duplicate or lost liabilities.", - "evidence": "The run record of the gate as its owner lane records it through tools/ci/test-record.mjs.", - "priority": "P0", - "profile": "P00", - "cadence": "Every release candidate", - "method": "Automated + independent review", - "status": "NOT RUN", - "source": [ - "R1" - ], - "gate": "Integration gates closed", - "owner": "pool lane (a1c484c48a62948c2)", - "manual_page": null, - "owner_lane": "pool lane (a1c484c48a62948c2)", - "run_status": "NOT RUN", - "master_status": "PROPOSED / NOT RUN", - "updated": "2026-10-08T20:10:24.556Z", - "evidence_record": { - "reason": "INT-03 (R1 integration gate): the gate's harness is the owner lane's (pool lane (a1c484c48a62948c2)); not yet named in the map", - "at": "2026-10-08T20:10:24.556Z", - "method": "static", - "requirement_id": "INT-03", - "decision": "NOT RUN", - "reviewer": "", - "claim_impact": "", - "release_identity": { - "commit": "", - "lockfile": "", - "binary": "", - "network_object": "", - "activation": "", - "profile_hashes": "" - } - }, - "approvals": { - "scope_approved": null, - "implementation_complete": null, - "evidence_reproduced": null, - "claim_authorised": null - } - }, - { - "id": "INT-04", - "title": "Corrupt existing pool state, disk-full and reorg cause safe recovery, not silent empty balances.", - "setup": "Integration gate INT-04 of the master edition (R1 / Additional regression gates).", - "steps": [ - "Corrupt existing pool state, disk-full and reorg cause safe recovery, not silent empty balances." - ], - "accept": "Corrupt existing pool state, disk-full and reorg cause safe recovery, not silent empty balances.", - "evidence": "The run record of the gate as its owner lane records it through tools/ci/test-record.mjs.", - "priority": "P0", - "profile": "P00", - "cadence": "Every release candidate", - "method": "Automated + independent review", - "status": "NOT RUN", - "source": [ - "R1" - ], - "gate": "Integration gates closed", - "owner": "pool lane (a1c484c48a62948c2)", - "manual_page": null, - "owner_lane": "pool lane (a1c484c48a62948c2)", - "run_status": "NOT RUN", - "master_status": "PROPOSED / NOT RUN", - "updated": "2026-10-08T20:10:24.556Z", - "evidence_record": { - "reason": "INT-04 (R1 integration gate): the gate's harness is the owner lane's (pool lane (a1c484c48a62948c2)); not yet named in the map", - "at": "2026-10-08T20:10:24.556Z", - "method": "static", - "requirement_id": "INT-04", - "decision": "NOT RUN", - "reviewer": "", - "claim_impact": "", - "release_identity": { - "commit": "", - "lockfile": "", - "binary": "", - "network_object": "", - "activation": "", - "profile_hashes": "" - } - }, - "approvals": { - "scope_approved": null, - "implementation_complete": null, - "evidence_reproduced": null, - "claim_authorised": null - } - }, - { - "id": "INT-05", - "title": "The supplied finality implementation matches the approved anchor rule after >window healing.", - "setup": "Integration gate INT-05 of the master edition (R1 / Additional regression gates).", - "steps": [ - "The supplied finality implementation matches the approved anchor rule after >window healing." - ], - "accept": "The supplied finality implementation matches the approved anchor rule after >window healing.", - "evidence": "The run record of the gate as its owner lane records it through tools/ci/test-record.mjs.", - "priority": "P0", - "profile": "P00", - "cadence": "Every release candidate", - "method": "Automated + independent review", - "status": "NOT RUN", - "source": [ - "R1" - ], - "gate": "Integration gates closed", - "owner": "node lane (a283f5f0d364ceef0)", - "manual_page": null, - "owner_lane": "node lane (a283f5f0d364ceef0)", - "run_status": "NOT RUN", - "master_status": "PROPOSED / NOT RUN", - "updated": "2026-10-08T20:10:24.556Z", - "evidence_record": { - "reason": "INT-05 (R1 integration gate): the gate's harness is the owner lane's (node lane (a283f5f0d364ceef0)); not yet named in the map", - "at": "2026-10-08T20:10:24.556Z", - "method": "static", - "requirement_id": "INT-05", - "decision": "NOT RUN", - "reviewer": "", - "claim_impact": "", - "release_identity": { - "commit": "", - "lockfile": "", - "binary": "", - "network_object": "", - "activation": "", - "profile_hashes": "" - } - }, - "approvals": { - "scope_approved": null, - "implementation_complete": null, - "evidence_reproduced": null, - "claim_authorised": null - } - }, - { - "id": "INT-06", - "title": "Recovery tests state and preserve their weaker fault bound; interfaces never label it as a stronger guarantee.", - "setup": "Integration gate INT-06 of the master edition (R1 / Additional regression gates).", - "steps": [ - "Recovery tests state and preserve their weaker fault bound; interfaces never label it as a stronger guarantee." - ], - "accept": "Recovery tests state and preserve their weaker fault bound; interfaces never label it as a stronger guarantee.", - "evidence": "The run record of the gate as its owner lane records it through tools/ci/test-record.mjs.", - "priority": "P0", - "profile": "P00", - "cadence": "Every release candidate", - "method": "Automated + independent review", - "status": "NOT RUN", - "source": [ - "R1" - ], - "gate": "Integration gates closed", - "owner": "node lane (a283f5f0d364ceef0)", - "manual_page": null, - "owner_lane": "node lane (a283f5f0d364ceef0)", - "run_status": "NOT RUN", - "master_status": "PROPOSED / NOT RUN", - "updated": "2026-10-08T20:10:24.556Z", - "evidence_record": { - "reason": "INT-06 (R1 integration gate): the gate's harness is the owner lane's (node lane (a283f5f0d364ceef0)); not yet named in the map", - "at": "2026-10-08T20:10:24.556Z", - "method": "static", - "requirement_id": "INT-06", - "decision": "NOT RUN", - "reviewer": "", - "claim_impact": "", - "release_identity": { - "commit": "", - "lockfile": "", - "binary": "", - "network_object": "", - "activation": "", - "profile_hashes": "" - } - }, - "approvals": { - "scope_approved": null, - "implementation_complete": null, - "evidence_reproduced": null, - "claim_authorised": null - } - }, - { - "id": "INT-07", - "title": "One v6 object agrees in node, pool, CPU verifier and each supported GPU host across activation.", - "definition": "V6-12 (R1 p. 213): the release manifest is signed and binds lockfile hashes, kernel and host binaries, supported devices and drivers, the prover server patch, memory thresholds and tuner identity, with end-to-end artifact authentication and a clean-install accepted-and-paid test on an independent machine with no unpublished files, symlinks or shell overrides.", - "setup": "Integration gate INT-07 of the master edition (R1 / Additional regression gates).", - "steps": [ - "One v6 object agrees in node, pool, CPU verifier and each supported GPU host across activation." - ], - "accept": "One v6 object agrees in node, pool, CPU verifier and each supported GPU host across activation.", - "evidence": "The run record of the gate as its owner lane records it through tools/ci/test-record.mjs.", - "priority": "P0", - "profile": "P00", - "cadence": "Every release candidate", - "method": "Automated + independent review", - "status": "NOT RUN", - "source": [ - "R1" - ], - "gate": "Integration gates closed", - "owner": "CI steward with the hash lane (a690540514aa453d7) and the worker lane (a9e87343f008e0edd)", - "manual_page": null, - "owner_lane": "CI steward with the hash lane (a690540514aa453d7) and the worker lane (a9e87343f008e0edd)", - "run_status": "NOT RUN", - "master_status": "PROPOSED / NOT RUN", - "updated": "2026-10-08T20:10:24.556Z", - "evidence_record": { - "reason": "INT-07 (R1 integration gate): the gate's harness is the owner lane's (CI steward with the hash lane (a690540514aa453d7) and the worker lane (a9e87343f008e0edd)); not yet named in the map", - "at": "2026-10-08T20:10:24.556Z", - "method": "static", - "requirement_id": "INT-07", - "decision": "NOT RUN", - "reviewer": "", - "claim_impact": "", - "release_identity": { - "commit": "", - "lockfile": "", - "binary": "", - "network_object": "", - "activation": "", - "profile_hashes": "" - } - }, - "approvals": { - "scope_approved": null, - "implementation_complete": null, - "evidence_reproduced": null, - "claim_authorised": null - } - }, - { - "id": "INT-08", - "title": "Census, production acceptance, schedule counters and live-dataset tests use the identical frozen contract.", - "setup": "Integration gate INT-08 of the master edition (R1 / Additional regression gates).", - "steps": [ - "Census, production acceptance, schedule counters and live-dataset tests use the identical frozen contract." - ], - "accept": "Census, production acceptance, schedule counters and live-dataset tests use the identical frozen contract.", - "evidence": "The run record of the gate as its owner lane records it through tools/ci/test-record.mjs.", - "priority": "P0", - "profile": "P00", - "cadence": "Every release candidate", - "method": "Automated + independent review", - "status": "NOT RUN", - "source": [ - "R1" - ], - "gate": "Integration gates closed", - "owner": "CI steward with the hash lane (a690540514aa453d7) and the worker lane (a9e87343f008e0edd)", - "manual_page": null, - "owner_lane": "CI steward with the hash lane (a690540514aa453d7) and the worker lane (a9e87343f008e0edd)", - "run_status": "NOT RUN", - "master_status": "PROPOSED / NOT RUN", - "updated": "2026-10-08T20:10:24.556Z", - "evidence_record": { - "reason": "INT-08 (R1 integration gate): the gate's harness is the owner lane's (CI steward with the hash lane (a690540514aa453d7) and the worker lane (a9e87343f008e0edd)); not yet named in the map", - "at": "2026-10-08T20:10:24.556Z", - "method": "static", - "requirement_id": "INT-08", - "decision": "NOT RUN", - "reviewer": "", - "claim_impact": "", - "release_identity": { - "commit": "", - "lockfile": "", - "binary": "", - "network_object": "", - "activation": "", - "profile_hashes": "" - } - }, - "approvals": { - "scope_approved": null, - "implementation_complete": null, - "evidence_reproduced": null, - "claim_authorised": null - } - }, - { - "id": "INT-09", - "title": "Eight- and twelve-GiB epoch transitions recover deliberately without relying on repeated OOM/watchdog cycles.", - "setup": "Integration gate INT-09 of the master edition (R1 / Additional regression gates).", - "steps": [ - "Eight- and twelve-GiB epoch transitions recover deliberately without relying on repeated OOM/watchdog cycles." - ], - "accept": "Eight- and twelve-GiB epoch transitions recover deliberately without relying on repeated OOM/watchdog cycles.", - "evidence": "The run record of the gate as its owner lane records it through tools/ci/test-record.mjs.", - "priority": "P0", - "profile": "P00", - "cadence": "Every release candidate", - "method": "Automated + independent review", - "status": "NOT RUN", - "source": [ - "R1" - ], - "gate": "Integration gates closed", - "owner": "app lane", - "manual_page": null, - "owner_lane": "app lane", - "run_status": "NOT RUN", - "master_status": "PROPOSED / NOT RUN", - "updated": "2026-10-08T20:10:24.556Z", - "evidence_record": { - "reason": "INT-09 (R1 integration gate): the gate's harness is the owner lane's (app lane); not yet named in the map", - "at": "2026-10-08T20:10:24.556Z", - "method": "static", - "requirement_id": "INT-09", - "decision": "NOT RUN", - "reviewer": "", - "claim_impact": "", - "release_identity": { - "commit": "", - "lockfile": "", - "binary": "", - "network_object": "", - "activation": "", - "profile_hashes": "" - } - }, - "approvals": { - "scope_approved": null, - "implementation_complete": null, - "evidence_reproduced": null, - "claim_authorised": null - } - }, - { - "id": "INT-10", - "title": "Metal/CUDA/OpenCL exact dataset geometry agrees; unsupported packs reject before launch.", - "setup": "Integration gate INT-10 of the master edition (R1 / Additional regression gates).", - "steps": [ - "Metal/CUDA/OpenCL exact dataset geometry agrees; unsupported packs reject before launch." - ], - "accept": "Metal/CUDA/OpenCL exact dataset geometry agrees; unsupported packs reject before launch.", - "evidence": "The run record of the gate as its owner lane records it through tools/ci/test-record.mjs.", - "priority": "P0", - "profile": "P00", - "cadence": "Every release candidate", - "method": "Automated + independent review", - "status": "NOT RUN", - "source": [ - "R1" - ], - "gate": "Integration gates closed", - "owner": "CI steward with the hash lane (a690540514aa453d7) and the worker lane (a9e87343f008e0edd)", - "manual_page": null, - "owner_lane": "CI steward with the hash lane (a690540514aa453d7) and the worker lane (a9e87343f008e0edd)", - "run_status": "NOT RUN", - "master_status": "PROPOSED / NOT RUN", - "updated": "2026-10-08T20:10:24.556Z", - "evidence_record": { - "reason": "INT-10 (R1 integration gate): the gate's harness is the owner lane's (CI steward with the hash lane (a690540514aa453d7) and the worker lane (a9e87343f008e0edd)); not yet named in the map", - "at": "2026-10-08T20:10:24.556Z", - "method": "static", - "requirement_id": "INT-10", - "decision": "NOT RUN", - "reviewer": "", - "claim_impact": "", - "release_identity": { - "commit": "", - "lockfile": "", - "binary": "", - "network_object": "", - "activation": "", - "profile_hashes": "" - } - }, - "approvals": { - "scope_approved": null, - "implementation_complete": null, - "evidence_reproduced": null, - "claim_authorised": null - } - }, - { - "id": "INT-11", - "title": "Only a memory-reserved proving job launches; mining buffers really release when required.", - "setup": "Integration gate INT-11 of the master edition (R1 / Additional regression gates).", - "steps": [ - "Only a memory-reserved proving job launches; mining buffers really release when required." - ], - "accept": "Only a memory-reserved proving job launches; mining buffers really release when required.", - "evidence": "The run record of the gate as its owner lane records it through tools/ci/test-record.mjs.", - "priority": "P0", - "profile": "P00", - "cadence": "Every release candidate", - "method": "Automated + independent review", - "status": "NOT RUN", - "source": [ - "R1" - ], - "gate": "Integration gates closed", - "owner": "app lane", - "manual_page": null, - "owner_lane": "app lane", - "run_status": "NOT RUN", - "master_status": "PROPOSED / NOT RUN", - "updated": "2026-10-08T20:10:24.556Z", - "evidence_record": { - "reason": "INT-11 (R1 integration gate): the gate's harness is the owner lane's (app lane); not yet named in the map", - "at": "2026-10-08T20:10:24.556Z", - "method": "static", - "requirement_id": "INT-11", - "decision": "NOT RUN", - "reviewer": "", - "claim_impact": "", - "release_identity": { - "commit": "", - "lockfile": "", - "binary": "", - "network_object": "", - "activation": "", - "profile_hashes": "" - } - }, - "approvals": { - "scope_approved": null, - "implementation_complete": null, - "evidence_reproduced": null, - "claim_authorised": null - } - }, - { - "id": "INT-12", - "title": "Transient shard errors can retry safely; expiration, loss and paid work remain distinct durable outcomes.", - "setup": "Integration gate INT-12 of the master edition (R1 / Additional regression gates).", - "steps": [ - "Transient shard errors can retry safely; expiration, loss and paid work remain distinct durable outcomes." - ], - "accept": "Transient shard errors can retry safely; expiration, loss and paid work remain distinct durable outcomes.", - "evidence": "The run record of the gate as its owner lane records it through tools/ci/test-record.mjs.", - "priority": "P0", - "profile": "P00", - "cadence": "Every release candidate", - "method": "Automated + independent review", - "status": "NOT RUN", - "source": [ - "R1" - ], - "gate": "Integration gates closed", - "owner": "proving lane (a6e8f84588b809d62) and fleet lane (ac055d60427caab99)", - "manual_page": null, - "owner_lane": "proving lane (a6e8f84588b809d62) and fleet lane (ac055d60427caab99)", - "run_status": "NOT RUN", - "master_status": "PROPOSED / NOT RUN", - "updated": "2026-10-08T20:10:24.556Z", - "evidence_record": { - "reason": "INT-12 (R1 integration gate): the gate's harness is the owner lane's (proving lane (a6e8f84588b809d62) and fleet lane (ac055d60427caab99)); not yet named in the map", - "at": "2026-10-08T20:10:24.556Z", - "method": "static", - "requirement_id": "INT-12", - "decision": "NOT RUN", - "reviewer": "", - "claim_impact": "", - "release_identity": { - "commit": "", - "lockfile": "", - "binary": "", - "network_object": "", - "activation": "", - "profile_hashes": "" - } - }, - "approvals": { - "scope_approved": null, - "implementation_complete": null, - "evidence_reproduced": null, - "claim_authorised": null - } - }, - { - "id": "INT-13", - "title": "Ember cannot retain a rate-ineligible prior; material workload changes invalidate incompatible profiles.", - "setup": "Integration gate INT-13 of the master edition (R1 / Additional regression gates).", - "steps": [ - "Ember cannot retain a rate-ineligible prior; material workload changes invalidate incompatible profiles." - ], - "accept": "Ember cannot retain a rate-ineligible prior; material workload changes invalidate incompatible profiles.", - "evidence": "The run record of the gate as its owner lane records it through tools/ci/test-record.mjs.", - "priority": "P0", - "profile": "P00", - "cadence": "Every release candidate", - "method": "Automated + independent review", - "status": "NOT RUN", - "source": [ - "R1" - ], - "gate": "Integration gates closed", - "owner": "Ember lane (a04fe3451877e2ff0) with the app lane", - "manual_page": null, - "owner_lane": "Ember lane (a04fe3451877e2ff0) with the app lane", - "run_status": "NOT RUN", - "master_status": "PROPOSED / NOT RUN", - "updated": "2026-10-08T20:10:24.556Z", - "evidence_record": { - "reason": "INT-13 (R1 integration gate): the gate's harness is the owner lane's (Ember lane (a04fe3451877e2ff0) with the app lane); not yet named in the map", - "at": "2026-10-08T20:10:24.556Z", - "method": "static", - "requirement_id": "INT-13", - "decision": "NOT RUN", - "reviewer": "", - "claim_impact": "", - "release_identity": { - "commit": "", - "lockfile": "", - "binary": "", - "network_object": "", - "activation": "", - "profile_hashes": "" - } - }, - "approvals": { - "scope_approved": null, - "implementation_complete": null, - "evidence_reproduced": null, - "claim_authorised": null - } - }, - { - "id": "INT-14", - "title": "Protected helper and per-device leases restore owned settings on normal/abnormal exit; real ACL/security tests.", - "setup": "Integration gate INT-14 of the master edition (R1 / Additional regression gates).", - "steps": [ - "Protected helper and per-device leases restore owned settings on normal/abnormal exit; real ACL/security tests." - ], - "accept": "Protected helper and per-device leases restore owned settings on normal/abnormal exit; real ACL/security tests.", - "evidence": "The run record of the gate as its owner lane records it through tools/ci/test-record.mjs.", - "priority": "P0", - "profile": "P00", - "cadence": "Every release candidate", - "method": "Automated + independent review", - "status": "NOT RUN", - "source": [ - "R1" - ], - "gate": "Integration gates closed", - "owner": "Ember lane (a04fe3451877e2ff0) with the app lane", - "manual_page": null, - "owner_lane": "Ember lane (a04fe3451877e2ff0) with the app lane", - "run_status": "NOT RUN", - "master_status": "PROPOSED / NOT RUN", - "updated": "2026-10-08T20:10:24.556Z", - "evidence_record": { - "reason": "INT-14 (R1 integration gate): the gate's harness is the owner lane's (Ember lane (a04fe3451877e2ff0) with the app lane); not yet named in the map", - "at": "2026-10-08T20:10:24.556Z", - "method": "static", - "requirement_id": "INT-14", - "decision": "NOT RUN", - "reviewer": "", - "claim_impact": "", - "release_identity": { - "commit": "", - "lockfile": "", - "binary": "", - "network_object": "", - "activation": "", - "profile_hashes": "" - } - }, - "approvals": { - "scope_approved": null, - "implementation_complete": null, - "evidence_reproduced": null, - "claim_authorised": null - } - }, - { - "id": "INT-15", - "title": "Public PoP replay is not session authorization; payout/server/network binding enforced.", - "setup": "Integration gate INT-15 of the master edition (R1 / Additional regression gates).", - "steps": [ - "Public PoP replay is not session authorization; payout/server/network binding enforced." - ], - "accept": "Public PoP replay is not session authorization; payout/server/network binding enforced.", - "evidence": "The run record of the gate as its owner lane records it through tools/ci/test-record.mjs.", - "priority": "P0", - "profile": "P00", - "cadence": "Every release candidate", - "method": "Automated + independent review", - "status": "NOT RUN", - "source": [ - "R1" - ], - "gate": "Integration gates closed", - "owner": "pool lane (a1c484c48a62948c2)", - "manual_page": null, - "owner_lane": "pool lane (a1c484c48a62948c2)", - "run_status": "NOT RUN", - "master_status": "PROPOSED / NOT RUN", - "updated": "2026-10-08T20:10:24.556Z", - "evidence_record": { - "reason": "INT-15 (R1 integration gate): the gate's harness is the owner lane's (pool lane (a1c484c48a62948c2)); not yet named in the map", - "at": "2026-10-08T20:10:24.556Z", - "method": "static", - "requirement_id": "INT-15", - "decision": "NOT RUN", - "reviewer": "", - "claim_impact": "", - "release_identity": { - "commit": "", - "lockfile": "", - "binary": "", - "network_object": "", - "activation": "", - "profile_hashes": "" - } - }, - "approvals": { - "scope_approved": null, - "implementation_complete": null, - "evidence_reproduced": null, - "claim_authorised": null - } - }, - { - "id": "INT-16", - "title": "Pool parsing/queues/connection and crypto budgets remain bounded under controlled adversarial traffic.", - "setup": "Integration gate INT-16 of the master edition (R1 / Additional regression gates).", - "steps": [ - "Pool parsing/queues/connection and crypto budgets remain bounded under controlled adversarial traffic." - ], - "accept": "Pool parsing/queues/connection and crypto budgets remain bounded under controlled adversarial traffic.", - "evidence": "The run record of the gate as its owner lane records it through tools/ci/test-record.mjs.", - "priority": "P0", - "profile": "P00", - "cadence": "Every release candidate", - "method": "Automated + independent review", - "status": "NOT RUN", - "source": [ - "R1" - ], - "gate": "Integration gates closed", - "owner": "pool lane (a1c484c48a62948c2)", - "manual_page": null, - "owner_lane": "pool lane (a1c484c48a62948c2)", - "run_status": "NOT RUN", - "master_status": "PROPOSED / NOT RUN", - "updated": "2026-10-08T20:10:24.556Z", - "evidence_record": { - "reason": "INT-16 (R1 integration gate): the gate's harness is the owner lane's (pool lane (a1c484c48a62948c2)); not yet named in the map", - "at": "2026-10-08T20:10:24.556Z", - "method": "static", - "requirement_id": "INT-16", - "decision": "NOT RUN", - "reviewer": "", - "claim_impact": "", - "release_identity": { - "commit": "", - "lockfile": "", - "binary": "", - "network_object": "", - "activation": "", - "profile_hashes": "" - } - }, - "approvals": { - "scope_approved": null, - "implementation_complete": null, - "evidence_reproduced": null, - "claim_authorised": null - } - }, - { - "id": "INT-17", - "title": "Missing oracle/keys/mandatory real-proof fixture blocks the applicable production acceptance gate.", - "setup": "Integration gate INT-17 of the master edition (R1 / Additional regression gates).", - "steps": [ - "Missing oracle/keys/mandatory real-proof fixture blocks the applicable production acceptance gate." - ], - "accept": "Missing oracle/keys/mandatory real-proof fixture blocks the applicable production acceptance gate.", - "evidence": "The run record of the gate as its owner lane records it through tools/ci/test-record.mjs.", - "priority": "P0", - "profile": "P00", - "cadence": "Every release candidate", - "method": "Automated + independent review", - "status": "NOT RUN", - "source": [ - "R1" - ], - "gate": "Integration gates closed", - "owner": "proving lane (a6e8f84588b809d62)", - "manual_page": null, - "owner_lane": "proving lane (a6e8f84588b809d62)", - "run_status": "NOT RUN", - "master_status": "PROPOSED / NOT RUN", - "updated": "2026-10-08T20:10:24.556Z", - "evidence_record": { - "reason": "INT-17 (R1 integration gate): the gate's harness is the owner lane's (proving lane (a6e8f84588b809d62)); not yet named in the map", - "at": "2026-10-08T20:10:24.556Z", - "method": "static", - "requirement_id": "INT-17", - "decision": "NOT RUN", - "reviewer": "", - "claim_impact": "", - "release_identity": { - "commit": "", - "lockfile": "", - "binary": "", - "network_object": "", - "activation": "", - "profile_hashes": "" - } - }, - "approvals": { - "scope_approved": null, - "implementation_complete": null, - "evidence_reproduced": null, - "claim_authorised": null - } - }, - { - "id": "INT-18", - "title": "Whole-system economics pass the strongest feasible adversary, including sunk development and multi-epoch survival.", - "setup": "Integration gate INT-18 of the master edition (R1 / Additional regression gates).", - "steps": [ - "Whole-system economics pass the strongest feasible adversary, including sunk development and multi-epoch survival." - ], - "accept": "Whole-system economics pass the strongest feasible adversary, including sunk development and multi-epoch survival.", - "evidence": "The run record of the gate as its owner lane records it through tools/ci/test-record.mjs.", - "priority": "P0", - "profile": "P00", - "cadence": "Every release candidate", - "method": "Automated + independent review", - "status": "NOT RUN", - "source": [ - "R1" - ], - "gate": "Integration gates closed", - "owner": "research lane (ad6a2bd47d4a46105)", - "manual_page": null, - "owner_lane": "research lane (ad6a2bd47d4a46105)", - "run_status": "NOT RUN", - "master_status": "PROPOSED / NOT RUN", - "updated": "2026-10-08T20:10:24.556Z", - "evidence_record": { - "reason": "INT-18 (R1 integration gate): the gate's harness is the owner lane's (research lane (ad6a2bd47d4a46105)); not yet named in the map", - "at": "2026-10-08T20:10:24.556Z", - "method": "static", - "requirement_id": "INT-18", - "decision": "NOT RUN", - "reviewer": "", - "claim_impact": "", - "release_identity": { - "commit": "", - "lockfile": "", - "binary": "", - "network_object": "", - "activation": "", - "profile_hashes": "" - } - }, - "approvals": { - "scope_approved": null, - "implementation_complete": null, - "evidence_reproduced": null, - "claim_authorised": null - } - } - ], - "notes": [ - { - "at": "2026-10-08T20:10:24.874Z", - "text": "REC-01 (the master edition's one unresolved interpretation, finality pause-only healing: R1's I03 stale predicate against R2's F04 backfill caveat): closure evidence as the finality and node lanes recorded it on 8 October 2026: rule v4 at release-2.0.0-node 12424341's line, mode recovery by the founder's 19:57 ruling (the lock labelled recovery, never final), both real-node lines PASS tonight by the 6.7 pause criterion, FIN-02 PASS at 0218d6bf1 on the simulator half; status RUNNING until the beyond-window healing case with and without historical data is run natively (the node lane's case tomorrow). Applies to INT-05 and INT-06." - } - ] } ], "profiles": {