From 2a6151f1ccf1b030b67f98ca623241da38d4c6e3 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Thu, 8 Oct 2026 13:18:19 +0000 Subject: [PATCH] class v5 harness: the attempt-3 read's standalone path (--a3-only, --a3-known-failed) and the runner's stdout line; the check's live EQUAL on the rebuilt pair and the known-failed DIFFER on the page with the logs Co-Authored-By: Claude Fable 5.1 --- .../class-v5-harness/attempt3-check.json | 381 ++++++++++++++++++ .../class-v5-harness/attempt3-check.log | 30 ++ docs/design/class-v5-stored-state.md | 1 + infra/fast-time/class-v5-signal.mjs | 18 +- tools/class-v5/harness-remote.sh | 2 +- 5 files changed, 428 insertions(+), 4 deletions(-) create mode 100644 docs/design/class-v5-harness/attempt3-check.json create mode 100644 docs/design/class-v5-harness/attempt3-check.log diff --git a/docs/design/class-v5-harness/attempt3-check.json b/docs/design/class-v5-harness/attempt3-check.json new file mode 100644 index 000000000..3912cbee9 --- /dev/null +++ b/docs/design/class-v5-harness/attempt3-check.json @@ -0,0 +1,381 @@ +{ + "attempt_3_seed": { + "seed": "ec0a8cf9e1c6874f", + "expected": { + "class": "v5", + "attempt": 3, + "id": "1f1cf82877f46ee6", + "read_by": "igneum-pow at exactly 1c420786 and kaspa-pow program-id on class-v5-node f912e614, build-1, 14:07 UK" + }, + "cli": { + "attempt": 3, + "id": "1f1cf82877f46ee6" + }, + "engine": { + "attempt": 3, + "id": "1f1cf82877f46ee6", + "binary": "/srv/builds/igneum-wt-class-v5/vendor/igneum-node-class-v5/target/release/program-id" + }, + "engine_refusal": null, + "equal": true + }, + "pass": true, + "expect": "no-flip", + "signals": [ + 6, + 6, + 7 + ], + "checks": { + "zero_rejected_by_miners": true, + "zero_rejected_by_nodes": true, + "sinks_agree": true, + "block_counts_agree": true, + "miners_agree_on_every_program": true, + "window_line_on_every_node": true, + "every_node_signals_its_byte": true, + "chain_carries_the_bytes": true, + "state_roots_agree_across_nodes": true, + "template_never_v5": true, + "no_signal_line_on_any_node": true, + "ran_the_epochs": true, + "v4_programs_seen": true, + "signal_share_under_threshold_on_chain_or_the_object_off": true, + "attempt_3_seed_reads_equal": true + }, + "window": 60, + "windows": 7, + "floor": 100000, + "v4_floor": 120, + "v3_activation": 60, + "epoch_blocks": 60, + "lead": 10, + "first_full_window_epoch": 8, + "floor_epoch": 1667, + "stale_miner": null, + "stale_accepted_after_first_refresh": null, + "honest_accepted_after_flip": [ + 0, + 0, + 0 + ], + "stale_rejected": null, + "stateless_node": 3, + "stateless_accepted_after_flip": 0, + "stateless_refusal_lines": 0, + "state_roots_at_flip": [], + "streams": {}, + "days_seen": [ + 1244073 + ], + "day_boundary_crossed": false, + "node": "/srv/artefacts/0325-6ccaf9e9/node-lane/igneumd", + "miner": "/srv/artefacts/0325-6ccaf9e9/node-lane/igneum-miner", + "template_switch": null, + "run_ended_at_s": 195, + "final_daa": 180, + "max_epoch_seen": 3, + "epochs": { + "0": { + "class": 2, + "firstSeenDaa": 0, + "at": 5.9, + "eraSeed": "234e082d653dc69db36d875b256d0f5f4a123b353d6aa069c3c7aa9aa6c46062", + "bps": 0, + "bps5": 0, + "signal_epoch": null, + "day": 1244073 + }, + "1": { + "class": 3, + "firstSeenDaa": 60, + "at": 33.9, + "eraSeed": "234e082d653dc69db36d875b256d0f5f4a123b353d6aa069c3c7aa9aa6c46062", + "bps": 5111, + "bps5": 4888, + "signal_epoch": null, + "day": 1244073 + }, + "2": { + "class": 4, + "firstSeenDaa": 120, + "at": 141, + "eraSeed": "234e082d653dc69db36d875b256d0f5f4a123b353d6aa069c3c7aa9aa6c46062", + "bps": 4500, + "bps5": 5500, + "signal_epoch": null, + "day": 1244073 + }, + "3": { + "class": 4, + "firstSeenDaa": 180, + "at": 195, + "eraSeed": "234e082d653dc69db36d875b256d0f5f4a123b353d6aa069c3c7aa9aa6c46062", + "bps": 4500, + "bps5": 5500, + "signal_epoch": null, + "day": 1244073 + } + }, + "blocks": { + "total": 181, + "before_boundary": 181, + "after_boundary": 0, + "version_bytes": { + "0": 1, + "6": 95, + "7": 85 + }, + "signal_share_bps_on_chain": 5249 + }, + "programs": [ + { + "epoch": 0, + "class": "v2", + "program_id": "8f8806638d59850f", + "seed": "234e082d653dc69d", + "miners": 4, + "disagree": false + }, + { + "epoch": 1, + "class": "v3", + "program_id": "0387598d54486141", + "seed": "0ae69e83fe335830", + "miners": 4, + "disagree": false + }, + { + "epoch": 2, + "class": "v4", + "program_id": "b1a3de278844ed23", + "seed": "ce2f8891e7887337", + "miners": 4, + "disagree": false + } + ], + "program_id_rows": [], + "accepted_per_miner": [ + 45, + 50, + 51, + 34 + ], + "rejected_by_miners": [ + 0, + 0, + 0, + 0 + ], + "rejected_by_nodes": [ + 0, + 0, + 0 + ], + "sinks": [ + "5bb8ff5febfb6d68", + "5bb8ff5febfb6d68", + "5bb8ff5febfb6d68", + "5bb8ff5febfb6d68" + ], + "block_counts": [ + 180, + 180, + 180, + 180 + ], + "signal_lines": [ + null, + null, + null + ], + "floor_lines": [ + "Program class v5 from the override file: enabled, the floor at epoch 1667 (DAA score 100000 rounded up to the epoch boundary at 100020); the class v5 signal (byte 6, 9500 bps in each of 7 consecutive windows) can flip v4 to v5 before it; every item of the dataset is keyed by the execution state after the epoch's seed block", + "Program class v5 from the override file: enabled, the floor at epoch 1667 (DAA score 100000 rounded up to the epoch boundary at 100020); the class v5 signal (byte 6, 9500 bps in each of 7 consecutive windows) can flip v4 to v5 before it; every item of the dataset is keyed by the execution state after the epoch's seed block", + "Program class v5 from the override file: enabled, the floor at epoch 1667 (DAA score 100000 rounded up to the epoch boundary at 100020); the class v5 signal (byte 6, 9500 bps in each of 7 consecutive windows) can flip v4 to v5 before it; every item of the dataset is keyed by the execution state after the epoch's seed block" + ], + "samples": [ + { + "t": 5.9, + "daa": 0, + "epoch": 0, + "class": 2, + "bps": 0, + "bps5": 0, + "nodes": [ + "0/234e082d", + "0/234e082d", + "0/234e082d", + "0/234e082d" + ] + }, + { + "t": 20.9, + "daa": 31, + "epoch": 0, + "class": 2, + "bps": 5000, + "bps5": 5000, + "nodes": [ + "31/481eb180", + "31/481eb180", + "31/481eb180", + "31/481eb180" + ] + }, + { + "t": 35.9, + "daa": 61, + "epoch": 1, + "class": 3, + "bps": 5111, + "bps5": 4888, + "nodes": [ + "61/e14a1e5c", + "60/7b41a4a8", + "60/7b41a4a8", + "61/e14a1e5c" + ] + }, + { + "t": 50.9, + "daa": 63, + "epoch": 1, + "class": 3, + "bps": 5166, + "bps5": 4833, + "nodes": [ + "63/b476ae5b", + "63/b476ae5b", + "63/b476ae5b", + "63/b476ae5b" + ] + }, + { + "t": 65.9, + "daa": 66, + "epoch": 1, + "class": 3, + "bps": 5166, + "bps5": 4833, + "nodes": [ + "66/33e621e7", + "66/33e621e7", + "66/33e621e7", + "66/33e621e7" + ] + }, + { + "t": 81, + "daa": 69, + "epoch": 1, + "class": 3, + "bps": 5000, + "bps5": 5000, + "nodes": [ + "69/79ccfaa3", + "69/79ccfaa3", + "69/79ccfaa3", + "69/79ccfaa3" + ] + }, + { + "t": 96, + "daa": 73, + "epoch": 1, + "class": 3, + "bps": 5000, + "bps5": 5000, + "nodes": [ + "73/e5dab553", + "73/e5dab553", + "73/e5dab553", + "73/e5dab553" + ] + }, + { + "t": 111, + "daa": 78, + "epoch": 1, + "class": 3, + "bps": 5166, + "bps5": 4833, + "nodes": [ + "78/2e9fd6f8", + "78/2e9fd6f8", + "78/2e9fd6f8", + "78/2e9fd6f8" + ] + }, + { + "t": 126, + "daa": 98, + "epoch": 1, + "class": 3, + "bps": 4833, + "bps5": 5166, + "nodes": [ + "98/e1b2aa1f", + "98/e1b2aa1f", + "98/e1b2aa1f", + "98/e1b2aa1f" + ] + }, + { + "t": 141, + "daa": 120, + "epoch": 2, + "class": 4, + "bps": 4500, + "bps5": 5500, + "nodes": [ + "120/a4e0b591", + "120/a4e0b591", + "120/a4e0b591", + "120/a4e0b591" + ] + }, + { + "t": 156, + "daa": 136, + "epoch": 2, + "class": 4, + "bps": 4500, + "bps5": 5500, + "nodes": [ + "136/d00c2fca", + "136/d00c2fca", + "136/d00c2fca", + "136/d00c2fca" + ] + }, + { + "t": 171, + "daa": 151, + "epoch": 2, + "class": 4, + "bps": 4500, + "bps5": 5500, + "nodes": [ + "151/5e0379d8", + "151/5e0379d8", + "151/5e0379d8", + "151/5e0379d8" + ] + }, + { + "t": 186, + "daa": 171, + "epoch": 2, + "class": 4, + "bps": 4500, + "bps5": 5500, + "nodes": [ + "171/997b824e", + "171/997b824e", + "171/997b824e", + "171/997b824e" + ] + } + ] +} \ No newline at end of file diff --git a/docs/design/class-v5-harness/attempt3-check.log b/docs/design/class-v5-harness/attempt3-check.log new file mode 100644 index 000000000..b1f79fec8 --- /dev/null +++ b/docs/design/class-v5-harness/attempt3-check.log @@ -0,0 +1,30 @@ +13:12:41.745 signals 6/6/7, expect no-flip; v3 from 60 (epoch 1), v4 floor 120 (epoch 2), v5 floor 100000 (epoch 1667), window 60 DAA x 7 (the first epoch with seven full windows after v4 is 8); stale miner none; stateless node n3; 60 DAA per epoch, lead 10; run 200 s or 3 epochs +13:12:42.977 n0 up pid 3807653 json 31202 p2p 31201 exec 31203, signals 6 +13:12:44.184 n1 up pid 3808329 json 31212 p2p 31211 exec 31213, signals 6 +13:12:45.393 n2 up pid 3808893 json 31222 p2p 31221 exec 31223, signals 7 +13:12:46.600 n3 up pid 3809441 json 31232 p2p 31231 exec disabled, signals 7 +13:12:46.601 n0: Program class v4 signal window from the override file: 60 DAA ending at each epoch's seed block, threshold 9500 bps of blue blocks in each of 7 windows; the fixed height is the floor; this node signals object version 6 (class v4 sub-version 3: the amended draw with the distinct-values and most-repeated-value bounds; objects 4 and 5, the earlier v4 streams, do not count; 6 is class v5) | this node signals object version 6 +13:12:46.601 n1: Program class v4 signal window from the override file: 60 DAA ending at each epoch's seed block, threshold 9500 bps of blue blocks in each of 7 windows; the fixed height is the floor; this node signals object version 6 (class v4 sub-version 3: the amended draw with the distinct-values and most-repeated-value bounds; objects 4 and 5, the earlier v4 streams, do not count; 6 is class v5) | this node signals object version 6 +13:12:46.601 n2: Program class v4 signal window from the override file: 60 DAA ending at each epoch's seed block, threshold 9500 bps of blue blocks in each of 7 windows; the fixed height is the floor; this node signals object version 6 (class v4 sub-version 3: the amended draw with the distinct-values and most-repeated-value bounds; objects 4 and 5, the earlier v4 streams, do not count; 6 is class v5) | this node signals object version 7 +13:12:46.601 n3: Program class v4 signal window from the override file: 60 DAA ending at each epoch's seed block, threshold 9500 bps of blue blocks in each of 7 windows; the fixed height is the floor; this node signals object version 6 (class v4 sub-version 3: the amended draw with the distinct-values and most-repeated-value bounds; objects 4 and 5, the earlier v4 streams, do not count; 6 is class v5) | this node signals object version 7 +13:12:46.602 n0 digest: 1787ce0fd511a452 +13:12:47.614 epoch -1 -> 0 at daa 0, 5.9 s: template class 2, next 2, day 1244073, signal share at the sink v4 0 v5 0 bps (window 60, this node signals 6, v5 decided by signal at epoch none) +13:12:47.616 t=5.9 s daa 0 epoch 0 class 2 signal v4 0 v5 0 bps blocks/sink per node 0/234e082d 0/234e082d 0/234e082d 0/234e082d +13:13:02.635 t=20.9 s daa 31 epoch 0 class 2 signal v4 5000 v5 5000 bps blocks/sink per node 31/481eb180 31/481eb180 31/481eb180 31/481eb180 +13:13:15.645 epoch 0 -> 1 at daa 60, 33.9 s: template class 3, next 3, day 1244073, signal share at the sink v4 5111 v5 4888 bps (window 60, this node signals 6, v5 decided by signal at epoch none) +13:13:17.648 t=35.9 s daa 61 epoch 1 class 3 signal v4 5111 v5 4888 bps blocks/sink per node 61/e14a1e5c 60/7b41a4a8 60/7b41a4a8 61/e14a1e5c +13:13:32.663 t=50.9 s daa 63 epoch 1 class 3 signal v4 5166 v5 4833 bps blocks/sink per node 63/b476ae5b 63/b476ae5b 63/b476ae5b 63/b476ae5b +13:13:47.679 t=65.9 s daa 66 epoch 1 class 3 signal v4 5166 v5 4833 bps blocks/sink per node 66/33e621e7 66/33e621e7 66/33e621e7 66/33e621e7 +13:14:02.696 t=81.0 s daa 69 epoch 1 class 3 signal v4 5000 v5 5000 bps blocks/sink per node 69/79ccfaa3 69/79ccfaa3 69/79ccfaa3 69/79ccfaa3 +13:14:17.710 t=96.0 s daa 73 epoch 1 class 3 signal v4 5000 v5 5000 bps blocks/sink per node 73/e5dab553 73/e5dab553 73/e5dab553 73/e5dab553 +13:14:32.725 t=111.0 s daa 78 epoch 1 class 3 signal v4 5166 v5 4833 bps blocks/sink per node 78/2e9fd6f8 78/2e9fd6f8 78/2e9fd6f8 78/2e9fd6f8 +13:14:47.736 t=126.0 s daa 98 epoch 1 class 3 signal v4 4833 v5 5166 bps blocks/sink per node 98/e1b2aa1f 98/e1b2aa1f 98/e1b2aa1f 98/e1b2aa1f +13:15:02.743 epoch 1 -> 2 at daa 120, 141.0 s: template class 4, next 4, day 1244073, signal share at the sink v4 4500 v5 5500 bps (window 60, this node signals 6, v5 decided by signal at epoch none) +13:15:02.744 t=141.0 s daa 120 epoch 2 class 4 signal v4 4500 v5 5500 bps blocks/sink per node 120/a4e0b591 120/a4e0b591 120/a4e0b591 120/a4e0b591 +13:15:17.753 t=156.0 s daa 136 epoch 2 class 4 signal v4 4500 v5 5500 bps blocks/sink per node 136/d00c2fca 136/d00c2fca 136/d00c2fca 136/d00c2fca +13:15:32.768 t=171.0 s daa 151 epoch 2 class 4 signal v4 4500 v5 5500 bps blocks/sink per node 151/5e0379d8 151/5e0379d8 151/5e0379d8 151/5e0379d8 +13:15:47.781 t=186.0 s daa 171 epoch 2 class 4 signal v4 4500 v5 5500 bps blocks/sink per node 171/997b824e 171/997b824e 171/997b824e 171/997b824e +13:15:56.790 epoch 2 -> 3 at daa 180, 195.0 s: template class 4, next 4, day 1244073, signal share at the sink v4 4500 v5 5500 bps (window 60, this node signals 6, v5 decided by signal at epoch none) +13:16:09.441 ATTEMPT-3 SEED ec0a8cf9e1c6874f: cli attempt 3 id 1f1cf82877f46ee6 | engine attempt 3 id 1f1cf82877f46ee6 | expected attempt 3 id 1f1cf82877f46ee6 | EQUAL +13:16:09.442 SUMMARY PASS (expect no-flip, signals 6/6/7, stale none): no v5 epoch; epochs seen e0:2:0bps:d1244073 e1:3:4888bps:d1244073 e2:4:5500bps:d1244073 e3:4:5500bps:d1244073; chain bytes {"0":1,"6":95,"7":85} (5249 bps at byte 6); blocks 181 / 0; rejected miners 0/0/0/0 nodes 0/0/0; sinks 5bb8ff5febfb6d68 5bb8ff5febfb6d68 5bb8ff5febfb6d68 5bb8ff5febfb6d68 (agree); counts 180/180/180/180; signal lines 0/3 (epochs //, shares //); floor lines 3/3; state roots at the flip ; stateless node accepted after the flip 0 (refusal lines 0); stale miner accepted after the first refresh n/a rejected n/a; days 1244073 +13:16:09.442 summary: /tmp/igneum-fast-time-v5s-attempt3-check/summary.json diff --git a/docs/design/class-v5-stored-state.md b/docs/design/class-v5-stored-state.md index 9656c731c..f6f8ab79b 100644 --- a/docs/design/class-v5-stored-state.md +++ b/docs/design/class-v5-stored-state.md @@ -51,6 +51,7 @@ Clock rule for this page: every time is UK time (UK time tonight, UTC+1). The bu | 13:5x | The pairing read-back on the rebuilt pair 6ccaf9e9 (release-0.3.25-node, igneumd's IGNEUM_POW_FINGERPRINT=cbc5bd0a..., the same PoW code as the print-only c9ad753a): the flip case on build-1 (13:44 to 13:56 UK, `class-v5-harness/readback-0325.{log,json}`) with the CLI side igneum-pow built at exactly 1c420786 (/srv/builds/_scratch/v5-freeze-cli, sha256 7ba781db...): SUMMARY PASS; every v5 epoch id for id, miners 3 of 3 against the freeze CLI: epoch 8 13a54a0dd793ca79 (attempt 2), epoch 9 d35cd0e9cb186d00 (attempt 1), epoch 10 6104176723170d72 (attempt 2). The gap: the run's seeds are its block hashes and drew no attempt-3 seed, so the case that caught the pin d5b68fae is not exercised by this read; the seeded attempt-3 case (a fixed seed through the freeze CLI and the pair's miner pack path, one line per run) is the next harness item | | 14:1x | The pin's FAIL seed re-read (ec0a8cf9...8212, its era 234e082d...6062, day 1244071, the run's own epoch-9 stream from /tmp/igneum-fast-time-v5x-cross-0325-d5b68fae): igneum-pow at exactly 1c420786 draws attempt 3, program id 1f1cf82877f46ee6 (8f481459 the same). Neither id of the FAIL was the freeze's: the cross harness's "cli v5 ebf64b32e2d84c5b" came from the release worktree's pre-freeze igneum-pow copy and the pin miner's 65b57e3b847d362e from "igneum-pow-v5/src"; rule 19's fingerprint pairing catches both. The miner's side of a past seed cannot be re-read (igneum-miner reads ids from a node's template only), so the pin goes on the fingerprint equality and the record says the attempt-3 seed's miner id was not re-read; the seeded attempt-3 case (a miner `program-id` read on a given seed, era, day and stream, asked of the node lane by 15:00 UK, default a kaspa-pow test binary on class-v5-node) is the next harness item | | 14:1x | The seeded attempt-3 case closed EQUAL: kaspa-pow `program-id` (class-v5-node f912e614, consensus/pow/src/bin: the template prepare's own path on a given seed, era, day, genesis day and stream file; a stream-less v5 read refuses with the engine's line, exit 3) reads the pin's FAIL seed ec0a8cf9...8212 (era 234e082d...6062, day 1244071, genesis day 1243740, the run's epoch-9 stream) as attempt 3, id 1f1cf82877f46ee6, equal to igneum-pow at exactly 1c420786 (build-1, 14:07 UK); the class v4 control reads attempt 0, 17d03dc8ddfe865c. The harness now reads that seed on every run (`class-v5-harness/attempt-3-seed/{seed.json,state.igsd1}`, check `attempt_3_seed_reads_equal`: the engine path beside the run's CLI, attempt and id against the record's expectation; an unreadable side is a FAILED CHECK, never a skip); the node lane lifts the read into `igneum-miner program-id` on its next line | +| 14:2x | The harness's attempt-3 check read live: on the rebuilt pair 6ccaf9e9 with the CLI at exactly 1c420786 (build-1, a 3-epoch no-flip case, 14:16 UK, `class-v5-harness/attempt3-check.{log,json}`): "ATTEMPT-3 SEED ec0a8cf9e1c6874f: cli attempt 3 id 1f1cf82877f46ee6 | engine attempt 3 id 1f1cf82877f46ee6 | expected attempt 3 id 1f1cf82877f46ee6 | EQUAL", `attempt_3_seed_reads_equal` true; the standalone path (`--a3-only`, seconds, no nodes) reads the same, and its known-failed flag (`--a3-known-failed`, the record's id with one digit flipped) reads DIFFER. A first short run died at 14:10 UK from this lane's own fault: the runner script was edited while that run's bash was reading it (the mid-run edit class build-remote's comment names); the second run is the record | ## 1. The claim, in one paragraph diff --git a/infra/fast-time/class-v5-signal.mjs b/infra/fast-time/class-v5-signal.mjs index e6590f559..5ad4563ea 100644 --- a/infra/fast-time/class-v5-signal.mjs +++ b/infra/fast-time/class-v5-signal.mjs @@ -60,6 +60,7 @@ const V3_ACTIVATION = actflag('v3-activation', 60); const WINDOW = flag('window', 60); const STALE = sflag('stale') == null ? null : +sflag('stale'); const STATELESS_NODE = !args.includes('--no-stateless-node'); +const A3_DIR = `${ROOT}docs/design/class-v5-harness/attempt-3-seed`; const WINDOWS = 7; const SIGNAL = (sflag('signal') || '6,6,6').split(',').map(Number); // since the 0.3.23 node line the bytes are not ordered by class: 7 = class v4 sub-version 3, 6 = class v5 (counted exactly) @@ -75,6 +76,15 @@ for (const b of [IGNEUMD, CPU_MINER]) if (!existsSync(b)) { console.error(`missi // whose log says a port was in use fails the run at once const PIDS = `${TMP}/pids`; try { for (const pid of readFileSync(PIDS, 'utf8').split('\n').map(Number).filter(Boolean)) { try { process.kill(pid, 'SIGKILL'); console.log(`killed survivor pid ${pid} of the previous run`); } catch { } } } catch { } +// `--a3-only [--a3-known-failed]`: the attempt-3 seed read alone, no nodes, seconds (the check's own self-test and a pairing +// read between a pair and a CLI without a run); exit 0 on EQUAL, 1 on DIFFER or unread, and with --a3-known-failed the +// flipped expectation must read DIFFER (exit 0 then, 1 if it reads EQUAL). +if (args.includes('--a3-only')) { + const kf = args.includes('--a3-known-failed'); + const row = readAttempt3Seed(kf); + console.log(JSON.stringify(row)); + process.exit(kf ? (row.equal ? 1 : 0) : (row.equal ? 0 : 1)); +} rmSync(TMP, { recursive: true, force: true }); mkdirSync(TMP, { recursive: true }); const recordPid = (p) => { try { writeFileSync(PIDS, `${readFileSync(PIDS, 'utf8')}${p.pid}\n`); } catch { writeFileSync(PIDS, `${p.pid}\n`); } }; let baseText = readFileSync(FILE, 'utf8'); @@ -435,10 +445,11 @@ if (EXPECT === 'flip') { // through the run's CLI (igneum-pow show), attempt and id compared with each other and with the record's expectation. // A run's own seeds are its block hashes and rarely land at attempt 3, which is where two acceptance rules show; this // read does not wait for the chain to draw one. An unreadable side is a FAILED CHECK, never a skip. -const A3_DIR = `${ROOT}docs/design/class-v5-harness/attempt-3-seed`; -const a3 = (() => { +function readAttempt3Seed(knownFailed = false) { try { const j = JSON.parse(readFileSync(`${A3_DIR}/seed.json`, 'utf8')); + // the check's own known-failed shape (--a3-known-failed): the record's expected id with one hex digit flipped must read DIFFER + if (knownFailed) j.expected = { ...j.expected, id: j.expected.id.slice(0, 15) + (j.expected.id.endsWith('0') ? '1' : '0') }; const state = `${A3_DIR}/${j.state_file}`; const dayHex = Buffer.concat([Buffer.from('igneum-day/'), Buffer.from(BigInt(j.day).toString(16).padStart(16, '0'), 'hex').reverse()]).toString('hex'); const cli = IGNEUM_POW && existsSync(IGNEUM_POW) ? spawnSync(IGNEUM_POW, ['show', '--program-class', 'v5', '--epoch-hex', j.epoch_hex, '--era-hex', j.era_hex, '--day-hex', dayHex, '--state', state], { encoding: 'utf8' }).stdout || '' : ''; @@ -451,7 +462,8 @@ const a3 = (() => { log(`ATTEMPT-3 SEED ${row.seed}: cli ${cm ? `attempt ${cm[1]} id ${cm[2]}` : 'UNREAD'} | engine ${em ? `attempt ${em[1]} id ${em[2]}` : `UNREAD${row.engine_refusal ? ` (${row.engine_refusal})` : pidBin ? '' : ' (no program-id binary)'}`} | expected attempt ${j.expected.attempt} id ${j.expected.id} | ${row.equal ? 'EQUAL' : 'DIFFER'}`); return row; } catch (e) { log(`ATTEMPT-3 SEED: ${e.message}`); return { equal: false, error: e.message }; } -})(); +} +const a3 = readAttempt3Seed(); checks.attempt_3_seed_reads_equal = !!a3.equal; const pass = Object.values(checks).every(Boolean); const summary = { diff --git a/tools/class-v5/harness-remote.sh b/tools/class-v5/harness-remote.sh index fb0307eb7..fe6dd3c53 100755 --- a/tools/class-v5/harness-remote.sh +++ b/tools/class-v5/harness-remote.sh @@ -36,4 +36,4 @@ rsync -a -e "ssh -i $KEY" "$ROOT/docs/design/class-v5-harness/attempt-3-seed/" " # POW_BIN= points the harness's CLI id read at another crate build (the freeze CLI for a pairing read-back) ssh -i "$KEY" "$HOST" "IGNEUM_V5_BIN=${FORK_BIN:-} IGNEUM_POW_BIN=${POW_BIN:-} $REMOTE_ROOT/tools/class-v5/harness-box.sh" "$REMOTE_ROOT" "$REMOTE_LOG" "$CASE" "$BASE" $ARGS || true rsync -a -e "ssh -i $KEY" "$HOST:$REMOTE_LOG/$CASE.log" "$HOST:$REMOTE_LOG/$CASE.json" "$OUT/" 2>/dev/null || true -grep -E "SUMMARY|FAILED CHECK|PROGRAM ID|CLASS SWITCH" "$OUT/$CASE.log" || tail -20 "$OUT/$CASE.log" +grep -E "SUMMARY|FAILED CHECK|PROGRAM ID|CLASS SWITCH|ATTEMPT-3 SEED" "$OUT/$CASE.log" || tail -20 "$OUT/$CASE.log"