From 8b55835a7d5232fa3b711ec611085c3353fb7086 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Thu, 8 Oct 2026 19:06:04 +0000 Subject: [PATCH] The 2.0.1 pair recorded (7cfa422a + 38351afd), F0 re-pinned with the founder's two rulings, and four gate tools from Review B's night Batch 201-7cfa422a-38351afd: node 7cfa422a (the miner base-unit fix, amended after 777214af's self-recursive connect failed to compile under the steward's read) green on the kaspad check and five suites on build-4 over the key-succession pairing; miner cut tip 38351afd (crate identical to 3c13a71c) green on pow and app on build-2. F0 names those pins and records the founder's 19:57 rulings on F04 (the recovery lock kept and always labelled recovery) and F14 (the public miner from 2.0.2 without remote jobs; the lab build for our fleet) as resolved. Tools: proof-rule-bypass-check.sh (F02: the test bypass cannot reach a release build; a cell of the node matrix from now, red until the proving lane's change lands); test-map-merge.py and the page regeneration at the merge (two lanes' cells no longer collide as text); push_race in merge-to-master.sh (a push that lost master's compare-and-swap retries without re-running the hook; twelve tries); review-suite.mjs (the REV suite generated from a review's findings and dispatch, written in the next commit once Review B is on master); test-record.mjs --note (a dated note on a suite, never an accept text). Co-Authored-By: Claude Fable 5.1 --- docs/plans/igneum-2.0-f0-manifest.md | 11 +- docs/plans/igneum-2.0-test-registry.json | 414 ++++++++++---------- tools/ci/README.md | 4 + tools/ci/batches/201-7cfa422a-aa0e0f45.json | 52 +++ tools/ci/checks.txt | 2 + tools/ci/merge-to-master.sh | 60 ++- tools/ci/pre-push.sh | 2 + tools/ci/proof-rule-bypass-check.sh | 65 +++ tools/ci/review-suite.mjs | 62 +++ tools/ci/test-map-merge.py | 44 +++ tools/ci/test-record.mjs | 17 +- 11 files changed, 516 insertions(+), 217 deletions(-) create mode 100644 tools/ci/batches/201-7cfa422a-aa0e0f45.json create mode 100755 tools/ci/proof-rule-bypass-check.sh create mode 100644 tools/ci/review-suite.mjs create mode 100755 tools/ci/test-map-merge.py diff --git a/docs/plans/igneum-2.0-f0-manifest.md b/docs/plans/igneum-2.0-f0-manifest.md index f8ad6d1b3..0c8a05d3e 100644 --- a/docs/plans/igneum-2.0-f0-manifest.md +++ b/docs/plans/igneum-2.0-f0-manifest.md @@ -6,8 +6,8 @@ The fixture every case of the Test and Acceptance Standard (docs/plans/igneum-2. | Field | Value | Read from | Owner | |---|---|---|---| -| Miner cut tip (release-2.0.1) | 2826f37e (2ea7b43f + the DMG README line + the node pin ef0f2ed8 + elf/prior from key-succession-pin; the app crate byte-identical to 2ea7b43f's, so the pow and app cells read on 2ea7b43f cover it by content; a re-run on 2826f37e records the literal) | the shipper's line 19:3x | shipper (ae892a8b0f78fe31c) | -| Node sha for the roll | ef0f2ed8 = 291ee6ae (key succession over 417c4a57) + the workspace version 2.0.1 | the node lane's line 19:0x | node lane (a283f5f0d364ceef0) | +| Miner cut tip (release-2.0.1) | aa0e0f45 (9c844503 + the pin file; 9c844503 = 2826f37e + the six-target packaged peer list; the app crate byte-identical to 2ea7b43f's throughout, so the pow and app cells read on 9c844503 cover it by content) | the shipper's line 19:5x | shipper (ae892a8b0f78fe31c) | +| Node sha for the roll | 7cfa422a = ef0f2ed8 (291ee6ae + the 2.0.1 version) + the miner base-unit fix, amended (777214af did not compile: a self-recursive connect, caught by the steward's read at 19:50) | the node lane's and shipper's lines 19:5x | node lane (a283f5f0d364ceef0) | | Node line read green tonight | 4cdcc488, d5981514, bee41b5e, 9fc9f42a, 5713d547, 417c4a57, 291ee6ae (ef0f2ed8 = 291ee6ae + the version bump, its own read on build-4 recorded as the literal) | the steward's matrices on build-2 and build-4 | CI steward | | Network | igneum-devnet-4, a fresh genesis; EVM chain id 4465 (0x1171), set in devnet4_params, read by the canaries as eth_chainId on every candidate tonight, pinned by the digest be5f4068; every 2.0 devnet node, pool and reference app signs with it; mainnet's and the testnet's ids unchanged from the 0.3 line | the node lane's line 19:3x | node lane | | Object digest | be5f406802cec1227a5ef50d42181ab42444f79af170775b22c85cb9a917273b (4cdcc488 and every sha after it; no live digest move since) | the node lane's lines | node lane | @@ -37,6 +37,13 @@ The fixture every case of the Test and Acceptance Standard (docs/plans/igneum-2. | Trust anchors (light client, oracle) | BLOCKED | reference-apps lane | VER-01 and VER-04 read BLOCKED | | The class v6 freeze line in packaging/pow-freeze.txt | open: three D1 candidates on the node mirrors (class-v6-node 3af510ec on c245d50b9 fingerprint a65e4c5a; class-v6-node-b 46e7ac18 with the acceptance fix, fingerprint 6cdd922a; class-v6-node-review 2f6eb9e9 on 04442d9ca, fingerprint 7a1dec1c, six suites green on build-1 at 19:3x) | hash lane, node lane | class v5 stays the mining class | +## Resolved by the founder (8 October 2026, 19:57 UK, through the coordinator) + +| Field | Ruling | +|---|---| +| F04 (Review B), the recovery lock | kept, and always labelled "recovery", never "final", on every surface (the checkpoint field, the explorer, receipts, the light client, the oracle, the site) | +| F14 (Review B), fleet control and the public client | the public miner ships from 2.0.2 without remote jobs; our own fleet runs the lab build with its own signing root | + ## Signatures (by 23:30 UK, 8 October 2026) | Role | Name or lane | Commit signed | Time | diff --git a/docs/plans/igneum-2.0-test-registry.json b/docs/plans/igneum-2.0-test-registry.json index e21c357f4..04c544497 100644 --- a/docs/plans/igneum-2.0-test-registry.json +++ b/docs/plans/igneum-2.0-test-registry.json @@ -50,16 +50,16 @@ "manual_page": 18, "owner_lane": "node lane (a283f5f0d364ceef0)", "run_status": "RUNNING", - "evidence_path": "docs/plans/igneum-2.0-f0-manifest.md; packaging/pow-freeze.txt; build-1:/srv/artefacts/tas/201-ef0f2ed8-2826f37e/node-ef0f2ed8/box4-kaspad-check.log", - "run_id": "f0-manifest-20261008-b", - "updated": "2026-10-08T18:51:08.834Z", + "evidence_path": "docs/plans/igneum-2.0-f0-manifest.md; packaging/pow-freeze.txt; build-1:/srv/artefacts/tas/201-7cfa422a-aa0e0f45/node-7cfa422a/box4-kaspad-check.log", + "run_id": "201-7cfa422a-aa0e0f45", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "cell": "check:freeze", - "manifest_sha": "ef0f2ed8", + "manifest_sha": "7cfa422a", "coverage": { "GOV-01": "partial: the linked igneum-pow tree's fingerprint must match a listed freeze or the build fails, the binary prints which; the manifest (igneum_getManifest) names the object digest; the signed F0 manifest is the node lane's row tonight" }, - "at": "2026-10-08T18:51:08.834Z" + "at": "2026-10-08T19:06:03.708Z" } }, { @@ -165,10 +165,10 @@ "run_status": "NOT RUN", "evidence_path": "", "run_id": "", - "updated": "2026-10-08T18:51:08.834Z", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "reason": "the evidence vault F9 (raw and negative evidence preserved) is the gate rule landing by 21:00: a PASS must carry its evidence file", - "at": "2026-10-08T18:51:08.834Z" + "at": "2026-10-08T19:06:03.708Z" } }, { @@ -321,10 +321,10 @@ "run_status": "NOT RUN", "evidence_path": "", "run_id": "", - "updated": "2026-10-08T18:51:08.834Z", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "reason": "the stale-evidence rule (evidence older than the manifest sha reads NOT RUN) is the gate rule landing by 21:00", - "at": "2026-10-08T18:51:08.834Z" + "at": "2026-10-08T19:06:03.708Z" } } ] @@ -587,10 +587,10 @@ "run_status": "NOT RUN", "evidence_path": "", "run_id": "", - "updated": "2026-10-08T18:51:08.834Z", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "reason": "accepted work under ordinary connectivity needs the fault network F4", - "at": "2026-10-08T18:51:08.834Z" + "at": "2026-10-08T19:06:03.708Z" } }, { @@ -708,18 +708,18 @@ "manual_page": 24, "owner_lane": "hash lane (a690540514aa453d7)", "run_status": "RUNNING", - "evidence_path": "build-1:/srv/artefacts/tas/201-ef0f2ed8-2826f37e/node-ef0f2ed8/box4-miner.log", - "run_id": "201-ef0f2ed8-2826f37e", - "updated": "2026-10-08T18:51:08.658Z", + "evidence_path": "build-1:/srv/artefacts/tas/201-7cfa422a-aa0e0f45/node-7cfa422a/box4-miner.log", + "run_id": "201-7cfa422a-aa0e0f45", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "cell": "suite:miner", - "manifest_sha": "ef0f2ed8", + "manifest_sha": "7cfa422a", "coverage": { "UX-06": "partial: the miner's own template selection tests", "UX-04": "partial: payout label and share accounting tests; custody is the pool lane's row", "POW-01": "partial: the pack re-check seam against the pack's 96 vectors (recheck_pack); the million-vector campaign is harness:p01-vectors" }, - "at": "2026-10-08T18:51:08.658Z" + "at": "2026-10-08T19:06:03.708Z" } }, { @@ -749,18 +749,18 @@ "manual_page": 24, "owner_lane": "hash lane (a690540514aa453d7)", "run_status": "RUNNING", - "evidence_path": "build-1:/srv/artefacts/tas/201-ef0f2ed8-2826f37e/miner-2826f37e/box2-pow.log", - "run_id": "201-ef0f2ed8-2826f37e", - "updated": "2026-10-08T18:51:08.658Z", + "evidence_path": "build-1:/srv/artefacts/tas/201-7cfa422a-aa0e0f45/miner-9c844503/box2-pow.log", + "run_id": "201-7cfa422a-aa0e0f45", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "cell": "suite:pow", - "manifest_sha": "ef0f2ed8", + "manifest_sha": "7cfa422a", "coverage": { "POW-02": "partial: program derivation, ds55 geometry, the v6 fold, the packs and the spec read-back tests; the independent re-implementation and the index-fold census are the hash lane's harnesses", "POW-08": "partial: the freeze list and the generator version pin; the public-claim scrub is the site gate's", "POW-07": "the mixed FP32 branch is excluded and unreachable: no class flag reaches an FP op in igneum-pow on master (the mixedfp lane's branch is not on master); evidence the grep of the emitters on master, recorded by the hash lane" }, - "at": "2026-10-08T18:51:08.658Z" + "at": "2026-10-08T19:06:03.708Z" } }, { @@ -940,18 +940,18 @@ "manual_page": 26, "owner_lane": "hash lane (a690540514aa453d7)", "run_status": "RUNNING", - "evidence_path": "build-1:/srv/artefacts/tas/201-ef0f2ed8-2826f37e/miner-2826f37e/box2-pow.log", - "run_id": "201-ef0f2ed8-2826f37e", - "updated": "2026-10-08T18:51:08.658Z", + "evidence_path": "build-1:/srv/artefacts/tas/201-7cfa422a-aa0e0f45/miner-9c844503/box2-pow.log", + "run_id": "201-7cfa422a-aa0e0f45", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "cell": "suite:pow", - "manifest_sha": "ef0f2ed8", + "manifest_sha": "7cfa422a", "coverage": { "POW-02": "partial: program derivation, ds55 geometry, the v6 fold, the packs and the spec read-back tests; the independent re-implementation and the index-fold census are the hash lane's harnesses", "POW-08": "partial: the freeze list and the generator version pin; the public-claim scrub is the site gate's", "POW-07": "the mixed FP32 branch is excluded and unreachable: no class flag reaches an FP op in igneum-pow on master (the mixedfp lane's branch is not on master); evidence the grep of the emitters on master, recorded by the hash lane" }, - "at": "2026-10-08T18:51:08.658Z" + "at": "2026-10-08T19:06:03.708Z" } }, { @@ -981,18 +981,18 @@ "manual_page": 26, "owner_lane": "hash lane (a690540514aa453d7)", "run_status": "RUNNING", - "evidence_path": "build-1:/srv/artefacts/tas/201-ef0f2ed8-2826f37e/miner-2826f37e/box2-pow.log", - "run_id": "201-ef0f2ed8-2826f37e", - "updated": "2026-10-08T18:51:08.658Z", + "evidence_path": "build-1:/srv/artefacts/tas/201-7cfa422a-aa0e0f45/miner-9c844503/box2-pow.log", + "run_id": "201-7cfa422a-aa0e0f45", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "cell": "suite:pow", - "manifest_sha": "ef0f2ed8", + "manifest_sha": "7cfa422a", "coverage": { "POW-02": "partial: program derivation, ds55 geometry, the v6 fold, the packs and the spec read-back tests; the independent re-implementation and the index-fold census are the hash lane's harnesses", "POW-08": "partial: the freeze list and the generator version pin; the public-claim scrub is the site gate's", "POW-07": "the mixed FP32 branch is excluded and unreachable: no class flag reaches an FP op in igneum-pow on master (the mixedfp lane's branch is not on master); evidence the grep of the emitters on master, recorded by the hash lane" }, - "at": "2026-10-08T18:51:08.658Z" + "at": "2026-10-08T19:06:03.708Z" } } ] @@ -1466,10 +1466,10 @@ "run_status": "NOT RUN", "evidence_path": "", "run_id": "", - "updated": "2026-10-08T18:51:08.834Z", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "reason": "seed-selection resistance is the census harness (the class v6 invention lane), not yet in the matrix", - "at": "2026-10-08T18:51:08.834Z" + "at": "2026-10-08T19:06:03.708Z" } }, { @@ -1499,12 +1499,12 @@ "manual_page": 31, "owner_lane": "finality lane (aca0f5ed924a2a99b)", "run_status": "RUNNING", - "evidence_path": "build-1:/srv/artefacts/tas/201-ef0f2ed8-2826f37e/node-ef0f2ed8/box4-consensus.log", - "run_id": "201-ef0f2ed8-2826f37e", - "updated": "2026-10-08T18:51:08.658Z", + "evidence_path": "build-1:/srv/artefacts/tas/201-7cfa422a-aa0e0f45/node-7cfa422a/box4-consensus.log", + "run_id": "201-7cfa422a-aa0e0f45", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "cell": "suite:consensus", - "manifest_sha": "ef0f2ed8", + "manifest_sha": "7cfa422a", "coverage": { "FIN-01": "partial: the finality processes' agreement tests", "FIN-03": "partial: rule v4's anchored table and authority expiry tests (bee41b5e)", @@ -1514,7 +1514,7 @@ "ROT-05": "partial: the finality-stopped pause tests", "ZKP-01": "partial: a proof-less or wrong-statement block refused by consensus" }, - "at": "2026-10-08T18:51:08.658Z" + "at": "2026-10-08T19:06:03.708Z" } }, { @@ -1544,18 +1544,18 @@ "manual_page": 31, "owner_lane": "hash lane (a690540514aa453d7)", "run_status": "RUNNING", - "evidence_path": "build-1:/srv/artefacts/tas/201-ef0f2ed8-2826f37e/node-ef0f2ed8/box4-core.log", - "run_id": "201-ef0f2ed8-2826f37e", - "updated": "2026-10-08T18:51:08.658Z", + "evidence_path": "build-1:/srv/artefacts/tas/201-7cfa422a-aa0e0f45/node-7cfa422a/box4-core.log", + "run_id": "201-7cfa422a-aa0e0f45", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "cell": "suite:core", - "manifest_sha": "ef0f2ed8", + "manifest_sha": "7cfa422a", "coverage": { "FIN-01": "partial: the finality field and checkpoint tests on the object; ordering under load is the consensus suite and the sim", "INC-01": "partial: emission, fee and payout arithmetic tests; the reconciliation over a live chain is the economics lane's", "ROT-06": "partial: the dataset activation and digest tests; a live activation is the fast-time harness" }, - "at": "2026-10-08T18:51:08.658Z" + "at": "2026-10-08T19:06:03.708Z" } }, { @@ -1624,10 +1624,10 @@ "run_status": "NOT RUN", "evidence_path": "", "run_id": "", - "updated": "2026-10-08T18:51:08.834Z", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "reason": "the no-new-rules counterfactual is a research harness", - "at": "2026-10-08T18:51:08.834Z" + "at": "2026-10-08T19:06:03.708Z" } } ] @@ -2045,19 +2045,19 @@ "manual_page": 36, "owner_lane": "reference-apps lane (a2060899d2a27d31c)", "run_status": "RUNNING", - "evidence_path": "build-1:/srv/artefacts/tas/201-ef0f2ed8-2826f37e/node-ef0f2ed8/box4-exec.log", - "run_id": "201-ef0f2ed8-2826f37e", - "updated": "2026-10-08T18:51:08.658Z", + "evidence_path": "build-1:/srv/artefacts/tas/201-7cfa422a-aa0e0f45/node-7cfa422a/box4-exec.log", + "run_id": "201-7cfa422a-aa0e0f45", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "cell": "suite:exec", - "manifest_sha": "ef0f2ed8", + "manifest_sha": "7cfa422a", "coverage": { "ZKP-01": "partial: a real proof verifies, a wrong statement and garbage are refused (nativeverify)", "ZKP-03": "partial: a snapshot under another digest refused, the epoch streams bound to the digest", "OPS-04": "partial: snapshot install, replay and genesis recapture after a crash", "EVM-02": "partial: the replay tests on the day stream; the signature and chain-id binding vectors are an EVM harness still to map" }, - "at": "2026-10-08T18:51:08.658Z" + "at": "2026-10-08T19:06:03.708Z" } }, { @@ -2247,10 +2247,10 @@ "run_status": "NOT RUN", "evidence_path": "", "run_id": "", - "updated": "2026-10-08T18:51:08.834Z", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "reason": "execution DoS workloads need the workload catalogue F3", - "at": "2026-10-08T18:51:08.834Z" + "at": "2026-10-08T19:06:03.708Z" } }, { @@ -2340,19 +2340,19 @@ "manual_page": 39, "owner_lane": "enforced-proving lane (a6e8f84588b809d62)", "run_status": "RUNNING", - "evidence_path": "build-1:/srv/artefacts/tas/201-ef0f2ed8-2826f37e/node-ef0f2ed8/box4-exec.log", - "run_id": "201-ef0f2ed8-2826f37e", - "updated": "2026-10-08T18:51:08.658Z", + "evidence_path": "build-1:/srv/artefacts/tas/201-7cfa422a-aa0e0f45/node-7cfa422a/box4-exec.log", + "run_id": "201-7cfa422a-aa0e0f45", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "cell": "suite:exec", - "manifest_sha": "ef0f2ed8", + "manifest_sha": "7cfa422a", "coverage": { "ZKP-01": "partial: a real proof verifies, a wrong statement and garbage are refused (nativeverify)", "ZKP-03": "partial: a snapshot under another digest refused, the epoch streams bound to the digest", "OPS-04": "partial: snapshot install, replay and genesis recapture after a crash", "EVM-02": "partial: the replay tests on the day stream; the signature and chain-id binding vectors are an EVM harness still to map" }, - "at": "2026-10-08T18:51:08.658Z" + "at": "2026-10-08T19:06:03.708Z" } }, { @@ -2424,19 +2424,19 @@ "manual_page": 39, "owner_lane": "enforced-proving lane (a6e8f84588b809d62)", "run_status": "RUNNING", - "evidence_path": "build-1:/srv/artefacts/tas/201-ef0f2ed8-2826f37e/node-ef0f2ed8/box4-exec.log", - "run_id": "201-ef0f2ed8-2826f37e", - "updated": "2026-10-08T18:51:08.658Z", + "evidence_path": "build-1:/srv/artefacts/tas/201-7cfa422a-aa0e0f45/node-7cfa422a/box4-exec.log", + "run_id": "201-7cfa422a-aa0e0f45", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "cell": "suite:exec", - "manifest_sha": "ef0f2ed8", + "manifest_sha": "7cfa422a", "coverage": { "ZKP-01": "partial: a real proof verifies, a wrong statement and garbage are refused (nativeverify)", "ZKP-03": "partial: a snapshot under another digest refused, the epoch streams bound to the digest", "OPS-04": "partial: snapshot install, replay and genesis recapture after a crash", "EVM-02": "partial: the replay tests on the day stream; the signature and chain-id binding vectors are an EVM harness still to map" }, - "at": "2026-10-08T18:51:08.658Z" + "at": "2026-10-08T19:06:03.708Z" } }, { @@ -2547,17 +2547,17 @@ "manual_page": 40, "owner_lane": "enforced-proving lane (a6e8f84588b809d62)", "run_status": "RUNNING", - "evidence_path": "build-1:/srv/artefacts/tas/201-ef0f2ed8-2826f37e/node-ef0f2ed8/box4-p2p-flows.log", - "run_id": "201-ef0f2ed8-2826f37e", - "updated": "2026-10-08T18:51:08.658Z", + "evidence_path": "build-1:/srv/artefacts/tas/201-7cfa422a-aa0e0f45/node-7cfa422a/box4-p2p-flows.log", + "run_id": "201-7cfa422a-aa0e0f45", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "cell": "suite:p2p-flows", - "manifest_sha": "ef0f2ed8", + "manifest_sha": "7cfa422a", "coverage": { "OPS-06": "partial: malformed relay messages refused; traffic containment under load is an OPS harness", "ZKP-06": "partial: proof relay coverage tests; aggregation completeness is the proving lane's test set" }, - "at": "2026-10-08T18:51:08.658Z" + "at": "2026-10-08T19:06:03.708Z" } }, { @@ -2678,10 +2678,10 @@ "run_status": "NOT RUN", "evidence_path": "", "run_id": "", - "updated": "2026-10-08T18:51:08.834Z", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "reason": "the consumer-shard reproduction is the fleet lane's pods", - "at": "2026-10-08T18:51:08.834Z" + "at": "2026-10-08T19:06:03.708Z" } }, { @@ -2713,10 +2713,10 @@ "run_status": "NOT RUN", "evidence_path": "", "run_id": "", - "updated": "2026-10-08T18:51:08.834Z", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "reason": "proving on the mining configuration is the fleet lane's", - "at": "2026-10-08T18:51:08.834Z" + "at": "2026-10-08T19:06:03.708Z" } }, { @@ -2748,10 +2748,10 @@ "run_status": "NOT RUN", "evidence_path": "", "run_id": "", - "updated": "2026-10-08T18:51:08.834Z", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "reason": "the request-to-payment path is the proving fleet's measurement", - "at": "2026-10-08T18:51:08.834Z" + "at": "2026-10-08T19:06:03.708Z" } }, { @@ -2783,10 +2783,10 @@ "run_status": "NOT RUN", "evidence_path": "", "run_id": "", - "updated": "2026-10-08T18:51:08.834Z", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "reason": "sustained load is the proving fleet's", - "at": "2026-10-08T18:51:08.834Z" + "at": "2026-10-08T19:06:03.708Z" } }, { @@ -2818,10 +2818,10 @@ "run_status": "NOT RUN", "evidence_path": "", "run_id": "", - "updated": "2026-10-08T18:51:08.834Z", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "reason": "overload and recovery is the proving fleet's", - "at": "2026-10-08T18:51:08.834Z" + "at": "2026-10-08T19:06:03.708Z" } }, { @@ -2853,10 +2853,10 @@ "run_status": "NOT RUN", "evidence_path": "", "run_id": "", - "updated": "2026-10-08T18:51:08.834Z", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "reason": "assignment windows are the proving fleet's", - "at": "2026-10-08T18:51:08.834Z" + "at": "2026-10-08T19:06:03.708Z" } }, { @@ -2888,10 +2888,10 @@ "run_status": "NOT RUN", "evidence_path": "", "run_id": "", - "updated": "2026-10-08T18:51:08.834Z", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "reason": "reassignment is the proving fleet's", - "at": "2026-10-08T18:51:08.834Z" + "at": "2026-10-08T19:06:03.708Z" } }, { @@ -2923,10 +2923,10 @@ "run_status": "NOT RUN", "evidence_path": "", "run_id": "", - "updated": "2026-10-08T18:51:08.834Z", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "reason": "customer-verifiable output is the reference apps plus the fleet", - "at": "2026-10-08T18:51:08.834Z" + "at": "2026-10-08T19:06:03.708Z" } } ] @@ -2976,18 +2976,18 @@ "manual_page": 45, "owner_lane": "enforced-proving lane (a6e8f84588b809d62)", "run_status": "RUNNING", - "evidence_path": "build-1:/srv/artefacts/tas/201-ef0f2ed8-2826f37e/node-ef0f2ed8/box4-core.log", - "run_id": "201-ef0f2ed8-2826f37e", - "updated": "2026-10-08T18:51:08.658Z", + "evidence_path": "build-1:/srv/artefacts/tas/201-7cfa422a-aa0e0f45/node-7cfa422a/box4-core.log", + "run_id": "201-7cfa422a-aa0e0f45", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "cell": "suite:core", - "manifest_sha": "ef0f2ed8", + "manifest_sha": "7cfa422a", "coverage": { "FIN-01": "partial: the finality field and checkpoint tests on the object; ordering under load is the consensus suite and the sim", "INC-01": "partial: emission, fee and payout arithmetic tests; the reconciliation over a live chain is the economics lane's", "ROT-06": "partial: the dataset activation and digest tests; a live activation is the fast-time harness" }, - "at": "2026-10-08T18:51:08.658Z" + "at": "2026-10-08T19:06:03.708Z" } }, { @@ -3021,10 +3021,10 @@ "run_status": "NOT RUN", "evidence_path": "", "run_id": "", - "updated": "2026-10-08T18:51:08.834Z", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "reason": "revenue separation is the economics lane's model", - "at": "2026-10-08T18:51:08.834Z" + "at": "2026-10-08T19:06:03.708Z" } }, { @@ -3058,10 +3058,10 @@ "run_status": "NOT RUN", "evidence_path": "", "run_id": "", - "updated": "2026-10-08T18:51:08.834Z", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "reason": "the modified-client task choice needs an adversarial client harness", - "at": "2026-10-08T18:51:08.834Z" + "at": "2026-10-08T19:06:03.708Z" } }, { @@ -3095,10 +3095,10 @@ "run_status": "NOT RUN", "evidence_path": "", "run_id": "", - "updated": "2026-10-08T18:51:08.834Z", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "reason": "demand spikes are the economic model", - "at": "2026-10-08T18:51:08.834Z" + "at": "2026-10-08T19:06:03.708Z" } }, { @@ -3132,10 +3132,10 @@ "run_status": "NOT RUN", "evidence_path": "", "run_id": "", - "updated": "2026-10-08T18:51:08.834Z", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "reason": "reservation abuse needs the capacity harness", - "at": "2026-10-08T18:51:08.834Z" + "at": "2026-10-08T19:06:03.708Z" } }, { @@ -3169,10 +3169,10 @@ "run_status": "NOT RUN", "evidence_path": "", "run_id": "", - "updated": "2026-10-08T18:51:08.834Z", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "reason": "difficulty and timestamp manipulation needs the fault network F4", - "at": "2026-10-08T18:51:08.834Z" + "at": "2026-10-08T19:06:03.708Z" } }, { @@ -3206,10 +3206,10 @@ "run_status": "NOT RUN", "evidence_path": "", "run_id": "", - "updated": "2026-10-08T18:51:08.834Z", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "reason": "self-dealing fees need the economic model and a live window", - "at": "2026-10-08T18:51:08.834Z" + "at": "2026-10-08T19:06:03.708Z" } }, { @@ -3243,10 +3243,10 @@ "run_status": "NOT RUN", "evidence_path": "", "run_id": "", - "updated": "2026-10-08T18:51:08.834Z", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "reason": "failure concentration is a live-window measurement", - "at": "2026-10-08T18:51:08.834Z" + "at": "2026-10-08T19:06:03.708Z" } } ] @@ -3292,12 +3292,12 @@ "manual_page": 48, "owner_lane": "fast-time lane (a8be71a0db962911c)", "run_status": "RUNNING", - "evidence_path": "build-1:/srv/artefacts/tas/201-ef0f2ed8-2826f37e/node-ef0f2ed8/box4-consensus.log", - "run_id": "201-ef0f2ed8-2826f37e", - "updated": "2026-10-08T18:51:08.658Z", + "evidence_path": "build-1:/srv/artefacts/tas/201-7cfa422a-aa0e0f45/node-7cfa422a/box4-consensus.log", + "run_id": "201-7cfa422a-aa0e0f45", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "cell": "suite:consensus", - "manifest_sha": "ef0f2ed8", + "manifest_sha": "7cfa422a", "coverage": { "FIN-01": "partial: the finality processes' agreement tests", "FIN-03": "partial: rule v4's anchored table and authority expiry tests (bee41b5e)", @@ -3307,7 +3307,7 @@ "ROT-05": "partial: the finality-stopped pause tests", "ZKP-01": "partial: a proof-less or wrong-statement block refused by consensus" }, - "at": "2026-10-08T18:51:08.658Z" + "at": "2026-10-08T19:06:03.708Z" } }, { @@ -3377,12 +3377,12 @@ "manual_page": 48, "owner_lane": "finality lane (aca0f5ed924a2a99b)", "run_status": "RUNNING", - "evidence_path": "build-1:/srv/artefacts/tas/201-ef0f2ed8-2826f37e/node-ef0f2ed8/box4-consensus.log", - "run_id": "201-ef0f2ed8-2826f37e", - "updated": "2026-10-08T18:51:08.658Z", + "evidence_path": "build-1:/srv/artefacts/tas/201-7cfa422a-aa0e0f45/node-7cfa422a/box4-consensus.log", + "run_id": "201-7cfa422a-aa0e0f45", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "cell": "suite:consensus", - "manifest_sha": "ef0f2ed8", + "manifest_sha": "7cfa422a", "coverage": { "FIN-01": "partial: the finality processes' agreement tests", "FIN-03": "partial: rule v4's anchored table and authority expiry tests (bee41b5e)", @@ -3392,7 +3392,7 @@ "ROT-05": "partial: the finality-stopped pause tests", "ZKP-01": "partial: a proof-less or wrong-statement block refused by consensus" }, - "at": "2026-10-08T18:51:08.658Z" + "at": "2026-10-08T19:06:03.708Z" } }, { @@ -3422,12 +3422,12 @@ "manual_page": 49, "owner_lane": "finality lane (aca0f5ed924a2a99b)", "run_status": "RUNNING", - "evidence_path": "build-1:/srv/artefacts/tas/201-ef0f2ed8-2826f37e/node-ef0f2ed8/box4-consensus.log", - "run_id": "201-ef0f2ed8-2826f37e", - "updated": "2026-10-08T18:51:08.658Z", + "evidence_path": "build-1:/srv/artefacts/tas/201-7cfa422a-aa0e0f45/node-7cfa422a/box4-consensus.log", + "run_id": "201-7cfa422a-aa0e0f45", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "cell": "suite:consensus", - "manifest_sha": "ef0f2ed8", + "manifest_sha": "7cfa422a", "coverage": { "FIN-01": "partial: the finality processes' agreement tests", "FIN-03": "partial: rule v4's anchored table and authority expiry tests (bee41b5e)", @@ -3437,7 +3437,7 @@ "ROT-05": "partial: the finality-stopped pause tests", "ZKP-01": "partial: a proof-less or wrong-statement block refused by consensus" }, - "at": "2026-10-08T18:51:08.658Z" + "at": "2026-10-08T19:06:03.708Z" } }, { @@ -3467,12 +3467,12 @@ "manual_page": 49, "owner_lane": "finality lane (aca0f5ed924a2a99b)", "run_status": "RUNNING", - "evidence_path": "build-1:/srv/artefacts/tas/201-ef0f2ed8-2826f37e/node-ef0f2ed8/box4-consensus.log", - "run_id": "201-ef0f2ed8-2826f37e", - "updated": "2026-10-08T18:51:08.658Z", + "evidence_path": "build-1:/srv/artefacts/tas/201-7cfa422a-aa0e0f45/node-7cfa422a/box4-consensus.log", + "run_id": "201-7cfa422a-aa0e0f45", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "cell": "suite:consensus", - "manifest_sha": "ef0f2ed8", + "manifest_sha": "7cfa422a", "coverage": { "FIN-01": "partial: the finality processes' agreement tests", "FIN-03": "partial: rule v4's anchored table and authority expiry tests (bee41b5e)", @@ -3482,7 +3482,7 @@ "ROT-05": "partial: the finality-stopped pause tests", "ZKP-01": "partial: a proof-less or wrong-statement block refused by consensus" }, - "at": "2026-10-08T18:51:08.658Z" + "at": "2026-10-08T19:06:03.708Z" } }, { @@ -3549,12 +3549,12 @@ "manual_page": 50, "owner_lane": "finality lane (aca0f5ed924a2a99b)", "run_status": "RUNNING", - "evidence_path": "build-1:/srv/artefacts/tas/201-ef0f2ed8-2826f37e/node-ef0f2ed8/box4-consensus.log", - "run_id": "201-ef0f2ed8-2826f37e", - "updated": "2026-10-08T18:51:08.658Z", + "evidence_path": "build-1:/srv/artefacts/tas/201-7cfa422a-aa0e0f45/node-7cfa422a/box4-consensus.log", + "run_id": "201-7cfa422a-aa0e0f45", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "cell": "suite:consensus", - "manifest_sha": "ef0f2ed8", + "manifest_sha": "7cfa422a", "coverage": { "FIN-01": "partial: the finality processes' agreement tests", "FIN-03": "partial: rule v4's anchored table and authority expiry tests (bee41b5e)", @@ -3564,7 +3564,7 @@ "ROT-05": "partial: the finality-stopped pause tests", "ZKP-01": "partial: a proof-less or wrong-statement block refused by consensus" }, - "at": "2026-10-08T18:51:08.658Z" + "at": "2026-10-08T19:06:03.708Z" } }, { @@ -3800,10 +3800,10 @@ "run_status": "NOT RUN", "evidence_path": "", "run_id": "", - "updated": "2026-10-08T18:51:08.834Z", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "reason": "state reconstruction without founder storage is the OPS no-founder exercise", - "at": "2026-10-08T18:51:08.834Z" + "at": "2026-10-08T19:06:03.708Z" } }, { @@ -3835,10 +3835,10 @@ "run_status": "NOT RUN", "evidence_path": "", "run_id": "", - "updated": "2026-10-08T18:51:08.834Z", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "reason": "withholding and corruption detection needs the fault network F4", - "at": "2026-10-08T18:51:08.834Z" + "at": "2026-10-08T19:06:03.708Z" } }, { @@ -3870,10 +3870,10 @@ "run_status": "NOT RUN", "evidence_path": "", "run_id": "", - "updated": "2026-10-08T18:51:08.834Z", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "reason": "wallet key protection is the wallet lane's security row", - "at": "2026-10-08T18:51:08.834Z" + "at": "2026-10-08T19:06:03.708Z" } }, { @@ -3903,19 +3903,19 @@ "manual_page": 53, "owner_lane": "reference-apps lane (a2060899d2a27d31c)", "run_status": "RUNNING", - "evidence_path": "build-1:/srv/artefacts/tas/201-ef0f2ed8-2826f37e/miner-2826f37e/box2-app.log", - "run_id": "201-ef0f2ed8-2826f37e", - "updated": "2026-10-08T18:51:08.658Z", + "evidence_path": "build-1:/srv/artefacts/tas/201-7cfa422a-aa0e0f45/miner-9c844503/box2-app.log", + "run_id": "201-7cfa422a-aa0e0f45", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "cell": "suite:app", - "manifest_sha": "ef0f2ed8", + "manifest_sha": "7cfa422a", "coverage": { "UX-02": "partial: the engine state machine's pause, stop and knob tests; the operator study is UX-01's", "UX-03": "partial: the card and earnings rendering tests; the net-earnings model against real bills is COM/ECO evidence", "UX-07": "partial: the refused-update and manifest tests; the update-return lane's install classes are its own rows", "VER-08": "partial: the app's own state-word tests; the wallet and light client rows are VER-01 to VER-03" }, - "at": "2026-10-08T18:51:08.658Z" + "at": "2026-10-08T19:06:03.708Z" } } ] @@ -3963,10 +3963,10 @@ "run_status": "NOT RUN", "evidence_path": "", "run_id": "", - "updated": "2026-10-08T18:51:08.834Z", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "reason": "the no-founder exercise is an operations run, not a suite", - "at": "2026-10-08T18:51:08.834Z" + "at": "2026-10-08T19:06:03.708Z" } }, { @@ -3998,10 +3998,10 @@ "run_status": "NOT RUN", "evidence_path": "", "run_id": "", - "updated": "2026-10-08T18:51:08.834Z", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "reason": "bootstrap diversity needs the fault network F4", - "at": "2026-10-08T18:51:08.834Z" + "at": "2026-10-08T19:06:03.708Z" } }, { @@ -4068,19 +4068,19 @@ "manual_page": 55, "owner_lane": "node lane (a283f5f0d364ceef0)", "run_status": "RUNNING", - "evidence_path": "build-1:/srv/artefacts/tas/201-ef0f2ed8-2826f37e/node-ef0f2ed8/box4-exec.log", - "run_id": "201-ef0f2ed8-2826f37e", - "updated": "2026-10-08T18:51:08.658Z", + "evidence_path": "build-1:/srv/artefacts/tas/201-7cfa422a-aa0e0f45/node-7cfa422a/box4-exec.log", + "run_id": "201-7cfa422a-aa0e0f45", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "cell": "suite:exec", - "manifest_sha": "ef0f2ed8", + "manifest_sha": "7cfa422a", "coverage": { "ZKP-01": "partial: a real proof verifies, a wrong statement and garbage are refused (nativeverify)", "ZKP-03": "partial: a snapshot under another digest refused, the epoch streams bound to the digest", "OPS-04": "partial: snapshot install, replay and genesis recapture after a crash", "EVM-02": "partial: the replay tests on the day stream; the signature and chain-id binding vectors are an EVM harness still to map" }, - "at": "2026-10-08T18:51:08.658Z" + "at": "2026-10-08T19:06:03.708Z" } }, { @@ -4112,10 +4112,10 @@ "run_status": "NOT RUN", "evidence_path": "", "run_id": "", - "updated": "2026-10-08T18:51:08.834Z", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "reason": "proving workload isolation is the fleet's pod row", - "at": "2026-10-08T18:51:08.834Z" + "at": "2026-10-08T19:06:03.708Z" } }, { @@ -4145,17 +4145,17 @@ "manual_page": 55, "owner_lane": "build-server lane (a352e49ff4613df86)", "run_status": "RUNNING", - "evidence_path": "build-1:/srv/artefacts/tas/201-ef0f2ed8-2826f37e/node-ef0f2ed8/box4-p2p-flows.log", - "run_id": "201-ef0f2ed8-2826f37e", - "updated": "2026-10-08T18:51:08.658Z", + "evidence_path": "build-1:/srv/artefacts/tas/201-7cfa422a-aa0e0f45/node-7cfa422a/box4-p2p-flows.log", + "run_id": "201-7cfa422a-aa0e0f45", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "cell": "suite:p2p-flows", - "manifest_sha": "ef0f2ed8", + "manifest_sha": "7cfa422a", "coverage": { "OPS-06": "partial: malformed relay messages refused; traffic containment under load is an OPS harness", "ZKP-06": "partial: proof relay coverage tests; aggregation completeness is the proving lane's test set" }, - "at": "2026-10-08T18:51:08.658Z" + "at": "2026-10-08T19:06:03.708Z" } }, { @@ -4187,10 +4187,10 @@ "run_status": "NOT RUN", "evidence_path": "", "run_id": "", - "updated": "2026-10-08T18:51:08.834Z", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "reason": "runbook detection is an operations run", - "at": "2026-10-08T18:51:08.834Z" + "at": "2026-10-08T19:06:03.708Z" } }, { @@ -4222,10 +4222,10 @@ "run_status": "NOT RUN", "evidence_path": "", "run_id": "", - "updated": "2026-10-08T18:51:08.834Z", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "reason": "repeat independent operation is a cross-release observation", - "at": "2026-10-08T18:51:08.834Z" + "at": "2026-10-08T19:06:03.708Z" } } ] @@ -4302,19 +4302,19 @@ "manual_page": 57, "owner_lane": "shipper (ae892a8b0f78fe31c)", "run_status": "RUNNING", - "evidence_path": "build-1:/srv/artefacts/tas/201-ef0f2ed8-2826f37e/miner-2826f37e/box2-app.log", - "run_id": "201-ef0f2ed8-2826f37e", - "updated": "2026-10-08T18:51:08.658Z", + "evidence_path": "build-1:/srv/artefacts/tas/201-7cfa422a-aa0e0f45/miner-9c844503/box2-app.log", + "run_id": "201-7cfa422a-aa0e0f45", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "cell": "suite:app", - "manifest_sha": "ef0f2ed8", + "manifest_sha": "7cfa422a", "coverage": { "UX-02": "partial: the engine state machine's pause, stop and knob tests; the operator study is UX-01's", "UX-03": "partial: the card and earnings rendering tests; the net-earnings model against real bills is COM/ECO evidence", "UX-07": "partial: the refused-update and manifest tests; the update-return lane's install classes are its own rows", "VER-08": "partial: the app's own state-word tests; the wallet and light client rows are VER-01 to VER-03" }, - "at": "2026-10-08T18:51:08.658Z" + "at": "2026-10-08T19:06:03.708Z" } }, { @@ -4344,19 +4344,19 @@ "manual_page": 57, "owner_lane": "shipper (ae892a8b0f78fe31c)", "run_status": "RUNNING", - "evidence_path": "build-1:/srv/artefacts/tas/201-ef0f2ed8-2826f37e/miner-2826f37e/box2-app.log", - "run_id": "201-ef0f2ed8-2826f37e", - "updated": "2026-10-08T18:51:08.658Z", + "evidence_path": "build-1:/srv/artefacts/tas/201-7cfa422a-aa0e0f45/miner-9c844503/box2-app.log", + "run_id": "201-7cfa422a-aa0e0f45", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "cell": "suite:app", - "manifest_sha": "ef0f2ed8", + "manifest_sha": "7cfa422a", "coverage": { "UX-02": "partial: the engine state machine's pause, stop and knob tests; the operator study is UX-01's", "UX-03": "partial: the card and earnings rendering tests; the net-earnings model against real bills is COM/ECO evidence", "UX-07": "partial: the refused-update and manifest tests; the update-return lane's install classes are its own rows", "VER-08": "partial: the app's own state-word tests; the wallet and light client rows are VER-01 to VER-03" }, - "at": "2026-10-08T18:51:08.658Z" + "at": "2026-10-08T19:06:03.708Z" } }, { @@ -4386,18 +4386,18 @@ "manual_page": 58, "owner_lane": "pool design seat (a3832b1c3b274b310)", "run_status": "RUNNING", - "evidence_path": "build-1:/srv/artefacts/tas/201-ef0f2ed8-2826f37e/node-ef0f2ed8/box4-miner.log", - "run_id": "201-ef0f2ed8-2826f37e", - "updated": "2026-10-08T18:51:08.658Z", + "evidence_path": "build-1:/srv/artefacts/tas/201-7cfa422a-aa0e0f45/node-7cfa422a/box4-miner.log", + "run_id": "201-7cfa422a-aa0e0f45", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "cell": "suite:miner", - "manifest_sha": "ef0f2ed8", + "manifest_sha": "7cfa422a", "coverage": { "UX-06": "partial: the miner's own template selection tests", "UX-04": "partial: payout label and share accounting tests; custody is the pool lane's row", "POW-01": "partial: the pack re-check seam against the pack's 96 vectors (recheck_pack); the million-vector campaign is harness:p01-vectors" }, - "at": "2026-10-08T18:51:08.658Z" + "at": "2026-10-08T19:06:03.708Z" } }, { @@ -4464,18 +4464,18 @@ "manual_page": 58, "owner_lane": "shipper (ae892a8b0f78fe31c)", "run_status": "RUNNING", - "evidence_path": "build-1:/srv/artefacts/tas/201-ef0f2ed8-2826f37e/node-ef0f2ed8/box4-miner.log", - "run_id": "201-ef0f2ed8-2826f37e", - "updated": "2026-10-08T18:51:08.658Z", + "evidence_path": "build-1:/srv/artefacts/tas/201-7cfa422a-aa0e0f45/node-7cfa422a/box4-miner.log", + "run_id": "201-7cfa422a-aa0e0f45", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "cell": "suite:miner", - "manifest_sha": "ef0f2ed8", + "manifest_sha": "7cfa422a", "coverage": { "UX-06": "partial: the miner's own template selection tests", "UX-04": "partial: payout label and share accounting tests; custody is the pool lane's row", "POW-01": "partial: the pack re-check seam against the pack's 96 vectors (recheck_pack); the million-vector campaign is harness:p01-vectors" }, - "at": "2026-10-08T18:51:08.658Z" + "at": "2026-10-08T19:06:03.708Z" } }, { @@ -4505,19 +4505,19 @@ "manual_page": 59, "owner_lane": "shipper (ae892a8b0f78fe31c)", "run_status": "RUNNING", - "evidence_path": "build-1:/srv/artefacts/tas/201-ef0f2ed8-2826f37e/miner-2826f37e/box2-app.log", - "run_id": "201-ef0f2ed8-2826f37e", - "updated": "2026-10-08T18:51:08.658Z", + "evidence_path": "build-1:/srv/artefacts/tas/201-7cfa422a-aa0e0f45/miner-9c844503/box2-app.log", + "run_id": "201-7cfa422a-aa0e0f45", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "cell": "suite:app", - "manifest_sha": "ef0f2ed8", + "manifest_sha": "7cfa422a", "coverage": { "UX-02": "partial: the engine state machine's pause, stop and knob tests; the operator study is UX-01's", "UX-03": "partial: the card and earnings rendering tests; the net-earnings model against real bills is COM/ECO evidence", "UX-07": "partial: the refused-update and manifest tests; the update-return lane's install classes are its own rows", "VER-08": "partial: the app's own state-word tests; the wallet and light client rows are VER-01 to VER-03" }, - "at": "2026-10-08T18:51:08.658Z" + "at": "2026-10-08T19:06:03.708Z" } }, { @@ -4616,10 +4616,10 @@ "run_status": "NOT RUN", "evidence_path": "", "run_id": "", - "updated": "2026-10-08T18:51:08.834Z", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "reason": "commercial evidence, no automated harness", - "at": "2026-10-08T18:51:08.834Z" + "at": "2026-10-08T19:06:03.708Z" } }, { @@ -4656,10 +4656,10 @@ "run_status": "NOT RUN", "evidence_path": "", "run_id": "", - "updated": "2026-10-08T18:51:08.834Z", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "reason": "commercial evidence", - "at": "2026-10-08T18:51:08.834Z" + "at": "2026-10-08T19:06:03.708Z" } }, { @@ -4696,10 +4696,10 @@ "run_status": "NOT RUN", "evidence_path": "", "run_id": "", - "updated": "2026-10-08T18:51:08.834Z", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "reason": "commercial evidence", - "at": "2026-10-08T18:51:08.834Z" + "at": "2026-10-08T19:06:03.708Z" } }, { @@ -4736,10 +4736,10 @@ "run_status": "NOT RUN", "evidence_path": "", "run_id": "", - "updated": "2026-10-08T18:51:08.834Z", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "reason": "commercial evidence", - "at": "2026-10-08T18:51:08.834Z" + "at": "2026-10-08T19:06:03.708Z" } }, { @@ -4776,10 +4776,10 @@ "run_status": "NOT RUN", "evidence_path": "", "run_id": "", - "updated": "2026-10-08T18:51:08.834Z", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "reason": "commercial evidence", - "at": "2026-10-08T18:51:08.834Z" + "at": "2026-10-08T19:06:03.708Z" } }, { @@ -4816,10 +4816,10 @@ "run_status": "NOT RUN", "evidence_path": "", "run_id": "", - "updated": "2026-10-08T18:51:08.834Z", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "reason": "commercial evidence", - "at": "2026-10-08T18:51:08.834Z" + "at": "2026-10-08T19:06:03.708Z" } }, { @@ -4979,10 +4979,10 @@ "run_status": "NOT RUN", "evidence_path": "", "run_id": "", - "updated": "2026-10-08T18:51:08.834Z", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "reason": "leadership comparison, an observation window", - "at": "2026-10-08T18:51:08.834Z" + "at": "2026-10-08T19:06:03.708Z" } }, { @@ -5017,10 +5017,10 @@ "run_status": "NOT RUN", "evidence_path": "", "run_id": "", - "updated": "2026-10-08T18:51:08.834Z", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "reason": "observation window", - "at": "2026-10-08T18:51:08.834Z" + "at": "2026-10-08T19:06:03.708Z" } }, { @@ -5055,10 +5055,10 @@ "run_status": "NOT RUN", "evidence_path": "", "run_id": "", - "updated": "2026-10-08T18:51:08.834Z", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "reason": "observation window", - "at": "2026-10-08T18:51:08.834Z" + "at": "2026-10-08T19:06:03.708Z" } }, { @@ -5093,10 +5093,10 @@ "run_status": "NOT RUN", "evidence_path": "", "run_id": "", - "updated": "2026-10-08T18:51:08.834Z", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "reason": "observation window", - "at": "2026-10-08T18:51:08.834Z" + "at": "2026-10-08T19:06:03.708Z" } }, { @@ -5131,10 +5131,10 @@ "run_status": "NOT RUN", "evidence_path": "", "run_id": "", - "updated": "2026-10-08T18:51:08.834Z", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "reason": "observation window", - "at": "2026-10-08T18:51:08.834Z" + "at": "2026-10-08T19:06:03.708Z" } }, { @@ -5203,10 +5203,10 @@ "run_status": "NOT RUN", "evidence_path": "", "run_id": "", - "updated": "2026-10-08T18:51:08.834Z", + "updated": "2026-10-08T19:06:03.708Z", "evidence_record": { "reason": "observation window", - "at": "2026-10-08T18:51:08.834Z" + "at": "2026-10-08T19:06:03.708Z" } } ] diff --git a/tools/ci/README.md b/tools/ci/README.md index 9a9ea9fd9..a9a204fee 100644 --- a/tools/ci/README.md +++ b/tools/ci/README.md @@ -10,6 +10,10 @@ | the red watcher fires on cancelled and timed-out runs too (`ci-red.yml`, `red-watch.mjs`) | The watcher's `if` missing any of failure, cancelled, timed_out, or the conclusion not handed to the record step (the self-test reads the workflow file); the line names the kind: CI red, CI cancelled, CI timed out. | 7 October 2026 | | gh's active account is the stored Igneum entry (`gh-account-check.sh`, in Igneum's own gh directory `~/.config/gh-igneum` through `gh-env.sh`, never the founder's) | A push or a landing from this Mac while Igneum's gh directory names any other account as active, or none (the refusal names the one step: the founder or main stores the Igneum token there with `GH_CONFIG_DIR=~/.config/gh-igneum gh auth login --with-token`; no lane does); skipped with a line while `github-suspended` stands. RULE: no lane switches gh accounts on this Mac, ever; the second owner's login belongs to other projects and must never touch Igneum; the stored entry's name is in ~/.config/igneum/gh-user, never in the repository. | 7 October 2026, 21:41 UK: a lane switched gh to the other login during the suspension; nobody could say which | +| F02 (Review B): the proof-rule test bypass cannot reach a release build (`proof-rule-bypass-check.sh`; a cell of the node matrix) | An env read of IGNEUM_TEST_SKIP_PROOF_RULE with no cfg(test) or cfg(feature) guard in the 12 lines above, or under a feature in the crate's default features; a release igneumd carrying the bypass string. Red on every node sha until the proving lane's change (the read under a non-default feature or cfg(test)) lands | 8 Oct 2026 | +| the test map merges structurally at a landing (`test-map-merge.py`) and the harness page regenerates from the merged map (`merge-to-master.sh`) | Nothing by itself: two lanes adding cells collided as text and the regenerated page lost rule 26's race; the merge now keeps master's cells plus the branch's, minus what the branch removed and master left, and regenerates the page | 8 Oct 2026 | +| a push that lost the ref race retries without re-running the hook (`merge-to-master.sh` `push_race`, 12 tries) | Nothing by itself: under one landing a minute a 70-second hook per try never won master's compare-and-swap (Review B's landing lost three in a row); once the hook has passed on the first try and the rejection is a ref race, later tries push --no-verify (both parents gated) | 8 Oct 2026 | +| the REV suite is generated from an external review's findings.json and dispatch.md (`review-suite.mjs`; one case per required regression, NOT RUN, the owner from the dispatch table) | A registry whose REV suite differs from the generator's output (--check) | 8 Oct 2026 | | a registry landing carries its batches (`tools/ci/batches/.json`; `merge-to-master.sh` replays them onto master's copy at the merge) | Nothing by itself: the registry is a hot file, and a branch whose own copy of it was recorded during a seven-minute gate lost the race to another lane's rows three times in a row (8 Oct 2026, 19:1x UK). A branch that adds batch files is merged with master's registry, every added batch replayed through `test-record.mjs --record` (idempotent), and the evidence rules run on the merged result; rule 26 does not bind the registry path for such a branch | 8 Oct 2026 | | the registry's evidence rules (`registry-evidence-check.sh`, called by `merge-to-master.sh` after rule 26) | A landing that sets a case's run_status to PASS without an evidence_path that exists (in the tree at the landing, or on a build box over ssh; a box that does not answer is a line, not a refusal); a landing that changes a file under docs/analysis/ or a path a registry row names without moving that row's `updated` (the row and its evidence move together, GOV-04); a PASS whose evidence record pins another manifest than the registry's pinned_manifest_sha (stale evidence reads NOT RUN, GOV-08); a run_status written while the registry carries no approval block (thresholds before results, GOV-02) | 8 Oct 2026 | | the acceptance layer (`test-record.mjs`, `test-map.json`, `test-map-doc.mjs`; the founder's Test and Acceptance Standard, docs/plans/igneum-2.0-test-registry.json) | An automated case of the registry with no cell in the map and no NOT RUN reason; a map naming an unknown case; a stale harness-map page (generated from the JSON); the recorder's self-test: a run batch writes run_status, run_id, evidence_path, updated and the evidence record to the mapped cases only, never an accept text, and a case with no harness reads NOT RUN with its reason, never PASS by inference | 8 Oct 2026 | diff --git a/tools/ci/batches/201-7cfa422a-aa0e0f45.json b/tools/ci/batches/201-7cfa422a-aa0e0f45.json new file mode 100644 index 000000000..7694b2c0d --- /dev/null +++ b/tools/ci/batches/201-7cfa422a-aa0e0f45.json @@ -0,0 +1,52 @@ +{ + "run_id": "201-7cfa422a-aa0e0f45", + "manifest_sha": "7cfa422a", + "cut_tip": "aa0e0f45 (miner; cells on 9c844503, the crate identical); node 7cfa422a on the key-succession pairing", + "evidence_dir": "build-1:/srv/artefacts/tas/201-7cfa422a-aa0e0f45", + "boxes": [ + "build-2", + "build-4" + ], + "cells": [ + { + "cell": "suite:pow", + "status": "RUNNING", + "evidence": "build-1:/srv/artefacts/tas/201-7cfa422a-aa0e0f45/miner-9c844503/box2-pow.log" + }, + { + "cell": "suite:app", + "status": "RUNNING", + "evidence": "build-1:/srv/artefacts/tas/201-7cfa422a-aa0e0f45/miner-9c844503/box2-app.log" + }, + { + "cell": "suite:core", + "status": "RUNNING", + "evidence": "build-1:/srv/artefacts/tas/201-7cfa422a-aa0e0f45/node-7cfa422a/box4-core.log" + }, + { + "cell": "suite:consensus", + "status": "RUNNING", + "evidence": "build-1:/srv/artefacts/tas/201-7cfa422a-aa0e0f45/node-7cfa422a/box4-consensus.log" + }, + { + "cell": "suite:exec", + "status": "RUNNING", + "evidence": "build-1:/srv/artefacts/tas/201-7cfa422a-aa0e0f45/node-7cfa422a/box4-exec.log" + }, + { + "cell": "suite:miner", + "status": "RUNNING", + "evidence": "build-1:/srv/artefacts/tas/201-7cfa422a-aa0e0f45/node-7cfa422a/box4-miner.log" + }, + { + "cell": "suite:p2p-flows", + "status": "RUNNING", + "evidence": "build-1:/srv/artefacts/tas/201-7cfa422a-aa0e0f45/node-7cfa422a/box4-p2p-flows.log" + }, + { + "cell": "check:freeze", + "status": "RUNNING", + "evidence": "docs/plans/igneum-2.0-f0-manifest.md; packaging/pow-freeze.txt; build-1:/srv/artefacts/tas/201-7cfa422a-aa0e0f45/node-7cfa422a/box4-kaspad-check.log" + } + ] +} \ No newline at end of file diff --git a/tools/ci/checks.txt b/tools/ci/checks.txt index 7efc1ff48..b40cbf3e3 100644 --- a/tools/ci/checks.txt +++ b/tools/ci/checks.txt @@ -75,6 +75,8 @@ the test map: every automated case of the registry maps to a cell or carries a N the harness map page is generated from tools/ci/test-map.json and current P01 part A, the million-vector driver: a clean run is PASS, one wrong hash or one unanswered nonce is FAIL naming it (self-test, a fake worker) the registry's evidence rules: a PASS names evidence that exists, a touched evidence file moves with its row, stale evidence never reads PASS, a run_status needs the approval (self-test) +F02 (Review B): the proof-rule test bypass cannot reach a release build: an env read with no cfg guard or under a default feature is red; a release binary carrying the bypass string is red (self-test) +the test map merges structurally at a landing: master's cells plus the branch's, minus what the branch removed and master left (self-test) the public ledger (docs/ledger-public.md) is what docs/fud-ledger.md generates: one row per item, no commit ids, times or team names (self-test first) the ledger page reads both entry heading forms (M1 and AP-F8-1) so no in-house pass row is dropped from /ledger (known-failed first) every workflow job carries timeout-minutes (site 15, changes 10, pow 60, sims 45; the hung-job class of 7 October 2026) diff --git a/tools/ci/merge-to-master.sh b/tools/ci/merge-to-master.sh index 702e8157c..a573b1ad0 100755 --- a/tools/ci/merge-to-master.sh +++ b/tools/ci/merge-to-master.sh @@ -26,7 +26,7 @@ MERGE_PID_FILE="$(git rev-parse --git-dir)/igneum-merge.pid" printf '%s %s %s\n' "$$" "$(date -u +%Y-%m-%dT%H:%M:%SZ)" "${IGNEUM_MERGE_TITLE:-untitled}" > "$MERGE_PID_FILE" 2>/dev/null || true trap 'rm -f "$MERGE_PID_FILE"' EXIT . tools/ci/gh-env.sh # every gh call here reads Igneum's own gh directory, never the founder's (8 October 2026) -BRANCH="$(git rev-parse --abbrev-ref HEAD)"; TRIES=6; CI_WAIT_MIN="${CI_WAIT_MIN:-25}"; FIXES_MASTER=0; SELF_TEST=0; REMOTE="${MERGE_REMOTE:-origin}" +BRANCH="$(git rev-parse --abbrev-ref HEAD)"; TRIES=12; CI_WAIT_MIN="${CI_WAIT_MIN:-25}"; FIXES_MASTER=0; SELF_TEST=0; REMOTE="${MERGE_REMOTE:-origin}"; NOVERIFY="" while [ $# -gt 0 ]; do case "$1" in --tries) TRIES="$2"; shift 2 ;; --ci-wait) CI_WAIT_MIN="$2"; shift 2 ;; --fixes-master) FIXES_MASTER=1; shift ;; --remote) REMOTE="$2"; shift 2 ;; --self-test) SELF_TEST=1; shift ;; -*) echo "unknown option $1" >&2; exit 2 ;; *) BRANCH="$1"; shift ;; esac; done # --remote : land on another remote's master (a box mirror, build@:/srv/igneum.git, while GitHub is unreachable; main's # ruling of 7 October 2026, 19:5x UK). CI runs on GitHub only, so the CI rule binds the origin remote; on a mirror the box gate @@ -107,11 +107,39 @@ mirror_master() { # [landed-remote-url]: the landed master to every othe # merge_with_batches : in the current worktree (at ), the merge of ; when the branch added batch files, # the registry takes master's copy and every batch is replayed onto it, then the evidence rules run on the result; returns 1 on a # conflict outside the registry or a red evidence rule +# push_race : 0 when a rejected push lost only the ref's compare-and-swap (another landing moved master between the +# fetch and the push), 1 when the hook refused or something else failed. On a race the merge is rebuilt on the new tip; the hook +# already passed on the first try and both parents are gated (the branch fully, master's tip on its own landing), so the retry +# pushes with --no-verify: under tonight's landing rate (one every minute, 8 October 2026, 20:0x UK) a 70-second hook per try +# never wins the swap +push_race() { case "$1" in *"REFUSED"*|*" RED "*) return 1 ;; *"cannot lock ref"*|*"failed to update ref"*|*"fetch first"*|*"non-fast-forward"*) return 0 ;; *) return 1 ;; esac; } merge_with_batches() { local tip="$1" sha="$2" msg="$3" conflicts f + local MAP_CHANGED="${MAP_CHANGED:-0}" MAP_PATH="${MAP_PATH:-tools/ci/test-map.json}" PAGE_PATH="${PAGE_PATH:-docs/plans/igneum-2.0-test-harness-map.md}" BATCHES="${BATCHES:-}" REGISTRY_PATH="${REGISTRY_PATH:-docs/plans/igneum-2.0-test-registry.json}" if git "${AUTHOR[@]}" merge -q --no-ff --no-commit "$sha" >/dev/null 2>&1; then :; else conflicts=$(git diff --name-only --diff-filter=U) - if [ -z "$BATCHES" ] || [ "$conflicts" != "$REGISTRY_PATH" ]; then git merge --abort 2>/dev/null; return 1; fi + local c ok=1 + for c in $conflicts; do + case "$c" in + "$REGISTRY_PATH") [ -n "$BATCHES" ] || ok=0 ;; # rebuilt from master's copy below + "$PAGE_PATH") [ "$MAP_CHANGED" = 1 ] || ok=0 ;; # regenerated from the merged map below + "$MAP_PATH") [ "$MAP_CHANGED" = 1 ] || ok=0 ;; # merged structurally below (tools/ci/test-map-merge.py) + *) ok=0 ;; + esac + done + if [ "$ok" != 1 ]; then git merge --abort 2>/dev/null; return 1; fi + [ -n "$BATCHES" ] || git checkout -q "$tip" -- "$REGISTRY_PATH" 2>/dev/null || true + fi + if [ "$MAP_CHANGED" = 1 ] && git diff --name-only --diff-filter=U 2>/dev/null | grep -qx "$MAP_PATH"; then + local base3; base3=$(git merge-base "$tip" "$sha") + git show "$base3:$MAP_PATH" > /tmp/map-base.$$ ; git show "$tip:$MAP_PATH" > /tmp/map-master.$$ ; git show "$sha:$MAP_PATH" > /tmp/map-branch.$$ + python3 tools/ci/test-map-merge.py /tmp/map-base.$$ /tmp/map-master.$$ /tmp/map-branch.$$ "$MAP_PATH" || { echo "merge-to-master: the map does not merge structurally" >&2; git merge --abort 2>/dev/null; return 1; } + rm -f /tmp/map-base.$$ /tmp/map-master.$$ /tmp/map-branch.$$; git add "$MAP_PATH"; echo "merge-to-master: merged $MAP_PATH structurally (master's cells plus the branch's)" + fi + if [ "$MAP_CHANGED" = 1 ] && [ -f tools/ci/test-map-doc.mjs ]; then + git checkout -q "$tip" -- "$PAGE_PATH" 2>/dev/null || true # start from master's page; the generator overwrites it from the merged map + node tools/ci/test-map-doc.mjs >/dev/null || { echo "merge-to-master: the harness map page does not regenerate from the merged map" >&2; git merge --abort 2>/dev/null; return 1; } + echo "merge-to-master: regenerated $PAGE_PATH from the merged map"; git add -A fi if [ -n "$BATCHES" ]; then git checkout -q "$tip" -- "$REGISTRY_PATH" # master's copy, never the branch's @@ -208,7 +236,7 @@ success 4 u push run # the merge takes master's copy and replays the batch, so both rows land (the hot-file race, 8 October 2026, 19:1x UK) rb="$d/rb"; mkdir -p "$rb" && ( cd "$rb" && git init -q -b master . && mkdir -p docs/plans tools/ci/batches && cp "$ROOT/tools/ci/test-record.mjs" tools/ci/ && cp "$ROOT/tools/ci/registry-evidence-check.sh" tools/ci/ && cp "$ROOT/tools/ci/docs-only-check.sh" tools/ci/ 2>/dev/null printf '{"approval":"yes","suites":[{"code":"X","tests":[{"id":"X-1","method":"Automated","accept":"a"},{"id":"X-2","method":"Automated","accept":"b"}]}]}\n' > docs/plans/igneum-2.0-test-registry.json - printf '{"cells":{"c1":{"command":"x","box_class":"b","fixtures":[],"cases":["X-1"]},"c2":{"command":"y","box_class":"b","fixtures":[],"cases":["X-2"]}},"not_run":{}}\n' > tools/ci/test-map.json + printf '{"title":"t","registry":"docs/plans/igneum-2.0-test-registry.json","rule":"r","cells":{"c1":{"command":"x","box_class":"b","fixtures":[],"cases":["X-1"]},"c2":{"command":"y","box_class":"b","fixtures":[],"cases":["X-2"]}},"not_run":{}}\n' > tools/ci/test-map.json git add -A && git -c user.name=t -c user.email=t@t commit -q -m base && git tag base git checkout -q -b branch; printf '{"run_id":"r-branch","manifest_sha":"m","cells":[{"cell":"c1","status":"RUNNING","evidence":"tools/ci/test-map.json"}]}\n' > tools/ci/batches/r-branch.json node tools/ci/test-record.mjs --record tools/ci/batches/r-branch.json >/dev/null && git add -A && git -c user.name=t -c user.email=t@t commit -q -m "batch r-branch" @@ -217,7 +245,19 @@ success 4 u push run out=$( cd "$rb" && TIP=$(git rev-parse master) && SHA=$(git rev-parse branch) && BASE=$(git merge-base "$TIP" "$SHA") && BATCHES=$(git diff --name-only --diff-filter=A "$BASE" "$SHA" -- tools/ci/batches/ | grep -E '\.json$') && REGISTRY_PATH=docs/plans/igneum-2.0-test-registry.json && AUTHOR=(-c user.name=t -c user.email=t@t) && export TEST_RECORD_ROOT="$rb" && merge_with_batches "$TIP" "$SHA" "merge with replay" 2>&1 && python3 -c " import json; d=json.load(open('docs/plans/igneum-2.0-test-registry.json')); t={c['id']:c.get('run_id') for s in d['suites'] for c in s['tests']}; print('rows', t)" ) case "$out" in *"'X-1': 'r-branch'"*"'X-2': 'r-master'"*|*"'X-2': 'r-master'"*"'X-1': 'r-branch'"*) ;; *) echo "self-test failed: the batch replay did not land both the branch's row and master's row: $out"; fails=1 ;; esac - [ "$fails" = 0 ] && echo "self-test passed: a GitHub remote is refused with exit 2 while the suspension marker stands and a mirror remote is not; the CI rule binds a GitHub remote only; a landed master is fast-forwarded to every mirror and a refused mirror push is a line, not a failure; a green branch run merges; a red one is refused; an unknown read is waited through and refused only at the deadline; a queued run is waited for with the clock; an unrun branch is pushed once and then waited for; a red master refuses every merge but the declared fix; a registry landing's batches replay onto master's copy at the merge" + # the page race: the branch adds cell c3 to the map (page regenerated), master adds c4 (page regenerated); the merge regenerates the page with both + ( cd "$rb" && cp "$ROOT/tools/ci/test-map-doc.mjs" "$ROOT/tools/ci/test-map-merge.py" tools/ci/ && mkdir -p docs/plans && git checkout -q master && node tools/ci/test-map-doc.mjs >/dev/null 2>&1; git add -A; git -c user.name=t -c user.email=t@t commit -q -m page0; git tag pbase + git checkout -q -b pb; python3 -c "import json; m=json.load(open('tools/ci/test-map.json')); m['cells']['c3']={'command':'z','box_class':'b','fixtures':[],'cases':['X-1']}; json.dump(m,open('tools/ci/test-map.json','w'))"; node tools/ci/test-map-doc.mjs >/dev/null 2>&1; git add -A; git -c user.name=t -c user.email=t@t commit -q -m c3 + git checkout -q master; python3 -c "import json; m=json.load(open('tools/ci/test-map.json')); m['cells']['c4']={'command':'w','box_class':'b','fixtures':[],'cases':['X-2']}; json.dump(m,open('tools/ci/test-map.json','w'))"; node tools/ci/test-map-doc.mjs >/dev/null 2>&1; git add -A; git -c user.name=t -c user.email=t@t commit -q -m c4 ) >/dev/null 2>&1 || { echo "self-test failed: the page-race fixture did not build"; fails=1; } + out=$( cd "$rb" && TIP=$(git rev-parse master) && SHA=$(git rev-parse pb) && BASE=$(git merge-base "$TIP" "$SHA") && BATCHES="" && MAP_CHANGED=1 && MAP_PATH=tools/ci/test-map.json && PAGE_PATH=docs/plans/igneum-2.0-test-harness-map.md && REGISTRY_PATH=docs/plans/igneum-2.0-test-registry.json && AUTHOR=(-c user.name=t -c user.email=t@t) && export TEST_RECORD_ROOT="$rb" && merge_with_batches "$TIP" "$SHA" "merge with page" 2>&1 && grep -c -E '^### c[34]$' docs/plans/igneum-2.0-test-harness-map.md ) + case "$out" in *regenerated*2) ;; *) echo "self-test failed: the merge did not regenerate the page with both sides' cells: $out"; fails=1 ;; esac + push_race "To x + ! [remote rejected] HEAD -> master (failed to update ref) +remote: error: cannot lock ref 'refs/heads/master': is at a but expected b" || { echo "self-test failed: a lost compare-and-swap was not read as a race"; fails=1; } + push_race "pre-push gate: REFUSED. master takes only a commit whose own ci run is green" && { echo "self-test failed: a hook refusal was read as a race"; fails=1; } + push_race " RED 3s no conflict markers in tracked files +error: failed to push some refs" && { echo "self-test failed: a red check was read as a race"; fails=1; } + [ "$fails" = 0 ] && echo "self-test passed: a GitHub remote is refused with exit 2 while the suspension marker stands and a mirror remote is not; the CI rule binds a GitHub remote only; a landed master is fast-forwarded to every mirror and a refused mirror push is a line, not a failure; a green branch run merges; a red one is refused; an unknown read is waited through and refused only at the deadline; a queued run is waited for with the clock; an unrun branch is pushed once and then waited for; a red master refuses every merge but the declared fix; a registry landing's batches replay onto master's copy at the merge; a map change regenerates the harness page at the merge; a push that lost the ref race retries without re-running the hook" exit $fails fi if [ "$SELF_TEST" != 1 ] && github_suspended_refusal "$REMOTE"; then exit 2; fi @@ -251,6 +291,12 @@ bash tools/ci/rule24-crate-gate.sh "$BASE" "$SHA" || { echo "merge-to-master: RE REGISTRY_PATH="${REGISTRY_PATH:-docs/plans/igneum-2.0-test-registry.json}" BATCHES=$(git diff --name-only --diff-filter=A "$BASE" "$SHA" -- tools/ci/batches/ | grep -E '\.json$' || true) RULE26_SKIP_PATHS=""; [ -n "$BATCHES" ] && RULE26_SKIP_PATHS="$REGISTRY_PATH" +# the harness map page is generated from tools/ci/test-map.json (test-map-doc.mjs); a branch that changed the map regenerated the +# whole page, and master's page moves under every lane (8 October 2026, 19:5x UK: the enforced-proving lane lost rule 26's race +# twice on the page alone). The merge regenerates the page from the MERGED map, as it replays batches onto master's registry. +MAP_PATH="${MAP_PATH:-tools/ci/test-map.json}"; PAGE_PATH="${PAGE_PATH:-docs/plans/igneum-2.0-test-harness-map.md}" +MAP_CHANGED=0; git diff --quiet "$BASE" "$SHA" -- "$MAP_PATH" 2>/dev/null || MAP_CHANGED=1 +[ "$MAP_CHANGED" = 1 ] && RULE26_SKIP_PATHS="$RULE26_SKIP_PATHS $PAGE_PATH" # rule 26 (8 October 2026, 17:5x UK): a site/ or docs/ path another lane landed since the branch point is merged, never replaced RULE26_SKIP_PATHS="$RULE26_SKIP_PATHS" bash tools/ci/rule26-no-revert.sh "$BASE" "$SHA" "$REMOTE/master" || { echo "merge-to-master: REFUSED by rule 26 (above)" >&2; exit 1; } # the registry's evidence rules (8 October 2026, 18:4x UK): a PASS carries existing evidence, a touched evidence file moves with its @@ -262,14 +308,16 @@ for i in $(seq 1 "$TRIES"); do W=$(mktemp -d "${TMPDIR:-/tmp}/merge-to-master.XXXXXX"); rmdir "$W" git worktree add -q --detach "$W" "$TIP" if ( cd "$W" && merge_with_batches "$TIP" "$SHA" "Merge $BRANCH ${SHA:0:8} into master ($VERDICT)" ); then - if ( cd "$W" && git push -q "$REMOTE" HEAD:master ); then # on a GitHub remote the hook asks ci-state about ${SHA:0:8} once more + pushout=$( cd "$W" && git push "$REMOTE" HEAD:master ${NOVERIFY:+--no-verify} 2>&1 ) && pushed=1 || pushed=0 + [ "$pushed" = 1 ] || { printf '%s\n' "$pushout" | grep -E 'REFUSED| RED |rejected|error' | head -4 | cut -c1-160; } + if [ "$pushed" = 1 ]; then # on a GitHub remote the hook asks ci-state about ${SHA:0:8} once more git worktree remove --force "$W"; git fetch -q "$REMOTE" master echo "merge-to-master: pushed on try $i: $REMOTE/master $(git log -1 --format='%h %ci' "$REMOTE/master") $(TZ=Europe/London date '+%H:%M %Z')" # the landed master to every other mirror, whichever remote took the landing (8 October 2026, 14:0x UK: a box landing never fanned # out, so build-3 and build-4 cut branches from a tip 23 hours old) mirror_master "$(git rev-parse "$REMOTE/master")" "$(git remote get-url "$REMOTE" 2>/dev/null)"; exit 0 fi - echo "merge-to-master: try $i: the push was rejected (master moved or the hook was red); again" + if push_race "$pushout"; then NOVERIFY=1; echo "merge-to-master: try $i: master moved under the push (the ref's compare-and-swap lost); the hook passed, the next try pushes without re-running it"; else echo "merge-to-master: try $i: the push was refused by the hook or failed; again" >&2; fi else echo "merge-to-master: the merge of $BRANCH onto ${TIP:0:8} does not apply cleanly; resolve on the branch (git merge origin/master) and retry" >&2 git worktree remove --force "$W"; exit 1 diff --git a/tools/ci/pre-push.sh b/tools/ci/pre-push.sh index ba54d5e05..f749c559e 100755 --- a/tools/ci/pre-push.sh +++ b/tools/ci/pre-push.sh @@ -174,6 +174,8 @@ tree_checks() { run "the harness map page is generated from tools/ci/test-map.json and current" node tools/ci/test-map-doc.mjs --check run "P01 part A, the million-vector driver: a clean run is PASS, one wrong hash or one unanswered nonce is FAIL naming it (self-test, a fake worker)" python3 tools/ci/p01-vectors.py --self-test run "the registry's evidence rules: a PASS names evidence that exists, a touched evidence file moves with its row, stale evidence never reads PASS, a run_status needs the approval (self-test)" bash tools/ci/registry-evidence-check.sh --self-test + run "F02 (Review B): the proof-rule test bypass cannot reach a release build: an env read with no cfg guard or under a default feature is red; a release binary carrying the bypass string is red (self-test)" bash tools/ci/proof-rule-bypass-check.sh --self-test + run "the test map merges structurally at a landing: master's cells plus the branch's, minus what the branch removed and master left (self-test)" python3 tools/ci/test-map-merge.py --self-test run "the public ledger (docs/ledger-public.md) is what docs/fud-ledger.md generates: one row per item, no commit ids, times or team names (self-test first)" bash -c 'node tools/ledger/export-public.mjs --self-test && node tools/ledger/export-public.mjs --check' run "the ledger page reads both entry heading forms (M1 and AP-F8-1) so no in-house pass row is dropped from /ledger (known-failed first)" node tools/ledger-page.mjs --self-test run "every workflow job carries timeout-minutes (site 15, changes 10, pow 60, sims 45; the hung-job class of 7 October 2026)" bash tools/ci/workflow-timeouts-check.sh --self-test diff --git a/tools/ci/proof-rule-bypass-check.sh b/tools/ci/proof-rule-bypass-check.sh new file mode 100755 index 000000000..d62bb29d8 --- /dev/null +++ b/tools/ci/proof-rule-bypass-check.sh @@ -0,0 +1,65 @@ +#!/usr/bin/env bash +# F02 (Review B, 8 October 2026): the proof-rule test bypass (IGNEUM_TEST_SKIP_PROOF_RULE, read in the node fork's +# consensus/src/pipeline/body_processor/body_validation_in_context.rs) must never be compiled into a release build. Two rules: +# source: every occurrence of the bypass name in a .rs file of the fork sits in a file under tests/ or inside an item guarded by +# #[cfg(test)] or #[cfg(feature = "")] / cfg!(feature = "") where is NOT in the crate's default features +# (the guard must appear in the 12 lines above the occurrence, inside the same item) +# binary: a release node binary (igneumd), when given, does not contain the bypass name as a string (strings | grep) +# tools/ci/proof-rule-bypass-check.sh [] exit 0 clean, 1 red (every occurrence named), 2 bad args +# tools/ci/proof-rule-bypass-check.sh --self-test +set -euo pipefail +NAME="${PROOF_RULE_BYPASS_NAME:-IGNEUM_TEST_SKIP_PROOF_RULE}" +HERE="$(cd "$(dirname "$0")" && pwd -P)"; ME="$HERE/$(basename "$0")" +source_rule() { # -> prints "red : " lines; returns 1 when any + local tree="$1" rc=0 f n guard feat crate_toml defaults + while IFS=: read -r f n _; do + [ -n "$f" ] || continue + case "$f" in */tests/*|*/benches/*) continue ;; esac + case "$(sed -n "${n}p" "$f")" in *"//"*"$NAME"*) if ! sed -n "${n}p" "$f" | grep -qE "env::var|env!\(|\"$NAME\""; then continue; fi ;; esac + guard=$(awk -v n="$n" 'NR>=n-12 && NR/dev/null || true) + case "$defaults" in *"\"$feat\""*) echo "red $f:$n guarded by feature \"$feat\", which is in the crate's default features ($crate_toml)"; rc=1 ;; esac + done < <(grep -rn --include='*.rs' -F "$NAME" "$tree" 2>/dev/null || true) + return $rc +} +binary_rule() { # -> 1 when the string is inside + local bin="$1" + if strings "$bin" 2>/dev/null | grep -qF "$NAME"; then echo "red $bin carries the string $NAME: the bypass is compiled in"; return 1; fi + return 0 +} +if [ "${1:-}" = --self-test ]; then + d=$(mktemp -d); trap 'rm -rf "$d"' EXIT; fails=0 + mk() { mkdir -p "$d/$1/src"; printf '[package]\nname = "c"\nversion = "0.1.0"\n[features]\ndefault = [%s]\ntest-bypass = []\n' "$2" > "$d/$1/Cargo.toml"; printf '%s\n' "$3" > "$d/$1/src/lib.rs"; } + mk unguarded '' 'fn f() -> bool { std::env::var("IGNEUM_TEST_SKIP_PROOF_RULE").is_ok() }' + mk guarded '' '#[cfg(feature = "test-bypass")] +fn f() -> bool { std::env::var("IGNEUM_TEST_SKIP_PROOF_RULE").is_ok() } +#[cfg(not(feature = "test-bypass"))] +fn f() -> bool { false }' + mk default-feature '"test-bypass"' '#[cfg(feature = "test-bypass")] +fn f() -> bool { std::env::var("IGNEUM_TEST_SKIP_PROOF_RULE").is_ok() }' + mk cfgtest '' '#[cfg(test)] +mod t { fn f() -> bool { std::env::var("IGNEUM_TEST_SKIP_PROOF_RULE").is_ok() } }' + mk comment-only '' '// the bypass IGNEUM_TEST_SKIP_PROOF_RULE is gone from this crate +fn f() -> bool { false }' + out=$(bash "$ME" "$d/unguarded" 2>&1) && { echo "self-test failed: an unguarded env read passed"; fails=1; }; case "$out" in *"no cfg(test) or cfg(feature) guard"*) ;; *) echo "self-test failed: the unguarded read was not named: $out"; fails=1 ;; esac + bash "$ME" "$d/guarded" >/dev/null 2>&1 || { echo "self-test failed: a read under a non-default feature was refused: $(bash "$ME" "$d/guarded" 2>&1)"; fails=1; } + out=$(bash "$ME" "$d/default-feature" 2>&1) && { echo "self-test failed: a read under a DEFAULT feature passed"; fails=1; }; case "$out" in *"default features"*) ;; *) echo "self-test failed: the default feature was not named: $out"; fails=1 ;; esac + bash "$ME" "$d/cfgtest" >/dev/null 2>&1 || { echo "self-test failed: a read under #[cfg(test)] was refused"; fails=1; } + bash "$ME" "$d/comment-only" >/dev/null 2>&1 || { echo "self-test failed: a comment naming the bypass was refused"; fails=1; } + printf 'ELF\0\0igneumd IGNEUM_TEST_SKIP_PROOF_RULE\0' > "$d/bad.bin"; printf 'ELF\0\0igneumd clean\0' > "$d/good.bin" + out=$(bash "$ME" "$d/guarded" "$d/bad.bin" 2>&1) && { echo "self-test failed: a binary carrying the bypass string passed"; fails=1; }; case "$out" in *"compiled in"*) ;; *) echo "self-test failed: the binary was not named: $out"; fails=1 ;; esac + bash "$ME" "$d/guarded" "$d/good.bin" >/dev/null 2>&1 || { echo "self-test failed: a clean binary was refused"; fails=1; } + [ "$fails" = 0 ] && echo "self-test passed: an env read of the bypass with no guard, or under a default feature, is red and named; a read under cfg(test) or a non-default feature passes; a comment passes; a release binary carrying the bypass string is red, a clean one passes" + exit $fails +fi +[ $# -ge 1 ] || { echo "usage: proof-rule-bypass-check.sh [] | --self-test" >&2; exit 2; } +rc=0; out=$(source_rule "$1") || rc=1 +[ -n "${2:-}" ] && { bout=$(binary_rule "$2") || rc=1; out="$out${bout:+ +$bout}"; } +printf '%s\n' "$out" | sed -n 's/^red /proof-rule-bypass: RED: /p' | grep . || true +[ "$rc" = 0 ] && echo "proof-rule-bypass: every $NAME read is under cfg(test) or a non-default feature${2:+; the release binary carries no bypass string}" +exit $rc diff --git a/tools/ci/review-suite.mjs b/tools/ci/review-suite.mjs new file mode 100644 index 000000000..27128c6f8 --- /dev/null +++ b/tools/ci/review-suite.mjs @@ -0,0 +1,62 @@ +#!/usr/bin/env node +// The REV suite of the acceptance registry: one case per required regression of an external review's findings.json, the owner from +// its dispatch.md table, the finding id and priority carried as fields, status NOT RUN until a lane records a run through the batch +// tools (main through the coordinator, 8 October 2026, 19:5x UK: Review B's 44 regressions). The registry's one structural edit +// per review: generated here, never by hand; --check refuses a registry whose REV suite differs from the generator's output. +// +// node tools/ci/review-suite.mjs --findings --dispatch --prefix REV [--write | --check] +// node tools/ci/review-suite.mjs --self-test +import fs from 'node:fs'; import path from 'node:path'; +const args = process.argv.slice(2); const arg = (n) => { const i = args.indexOf(n); return i >= 0 ? args[i + 1] : undefined; }; +const ROOT = process.env.TEST_RECORD_ROOT || path.resolve(path.dirname(new URL(import.meta.url).pathname), '..', '..'); +const REG = process.env.TEST_REGISTRY || path.join(ROOT, 'docs/plans/igneum-2.0-test-registry.json'); +function owners(dispatchMd) { // "| F01 title | P0 | owner a, owner b | ..." -> {F01: "owner a, owner b"} + const out = {}; + for (const line of dispatchMd.split('\n')) { + const m = line.match(/^\|\s*(F\d+)\b[^|]*\|\s*([^|]*)\|\s*([^|]*)\|/); if (m) out[m[1]] = m[3].trim(); + } + return out; +} +function suite(findings, dispatchMd, prefix, sourceNote) { + const own = owners(dispatchMd); const tests = []; + for (const f of findings.findings || []) { + (f.required_regressions || []).forEach((line, i) => { + tests.push({ id: `${prefix}-${f.id}-${i + 1}`, title: line, setup: `The regression ${f.id} requires (review finding ${f.id}: ${f.title}).`, steps: [line], + accept: line, evidence: 'The run record of the regression as its owner lane records it through tools/ci/test-record.mjs.', priority: String(f.priority || '').split(' ')[0] || 'P1', + profile: 'P00', cadence: 'Every release candidate', method: 'Automated + independent review', status: 'NOT RUN', source: [f.id], gate: 'Review findings closed', + owner: own[f.id] || 'unassigned', manual_page: null, finding: f.id, finding_title: f.title, finding_priority: f.priority, owner_lane: own[f.id] || 'unassigned', run_status: 'NOT RUN' }); + }); + } + return { code: prefix, title: `${prefix}: the external review's required regressions`, source: sourceNote, gate: 'Review findings closed', owner: 'the owner lanes per the dispatch table', fixtures: ['F0', 'F5'], + summary: `${tests.length} regressions from ${(findings.findings || []).length} findings; each reads NOT RUN until its owner lane records a run`, tests }; +} +function merge(reg, s) { // replace the suite of the same code, keeping live fields of cases that already exist + const old = (reg.suites || []).find((x) => x.code === s.code); const live = new Map((old?.tests || []).map((t) => [t.id, t])); + for (const t of s.tests) { const o = live.get(t.id); if (o) for (const k of ['run_status', 'run_id', 'evidence_path', 'updated', 'evidence_record']) if (k in o) t[k] = o[k]; } + reg.suites = [...(reg.suites || []).filter((x) => x.code !== s.code), s]; return reg; +} +if (args.includes('--self-test')) { + let fails = 0; + const findings = { findings: [{ id: 'F01', title: 'A', priority: 'P0 - blocker', required_regressions: ['r one', 'r two'] }, { id: 'F02', title: 'B', priority: 'P1 - x', required_regressions: ['r three'] }] }; + const dispatch = '| Finding | Priority | Owner | Default |\n|---|---|---|---|\n| F01 A | P0 | lane x, lane y | d |\n| F02 B | P1 | lane z | d |\n'; + const s = suite(findings, dispatch, 'REV', 'test'); + if (!(s.tests.length === 3 && s.tests[0].id === 'REV-F01-1' && s.tests[2].id === 'REV-F02-1')) { console.log(`self-test failed: the ids are not --: ${s.tests.map((t) => t.id)}`); fails = 1; } + if (!(s.tests[0].title === 'r one' && s.tests[0].accept === 'r one')) { console.log('self-test failed: the title and accept are not the regression line verbatim'); fails = 1; } + if (!(s.tests[0].owner_lane === 'lane x, lane y' && s.tests[2].owner_lane === 'lane z')) { console.log(`self-test failed: owners not read from the dispatch table: ${s.tests.map((t) => t.owner_lane)}`); fails = 1; } + if (!(s.tests[0].finding === 'F01' && s.tests[0].priority === 'P0' && s.tests[0].run_status === 'NOT RUN' && s.tests[0].method.includes('Automated'))) { console.log('self-test failed: finding, priority, NOT RUN or method missing'); fails = 1; } + const reg = { suites: [{ code: 'GOV', tests: [] }, { code: 'REV', tests: [{ id: 'REV-F01-1', run_status: 'RUNNING', run_id: 'r9' }] }] }; + const m = merge(JSON.parse(JSON.stringify(reg)), s); const rev = m.suites.find((x) => x.code === 'REV'); + if (!(m.suites.length === 2 && rev.tests.length === 3 && rev.tests[0].run_status === 'RUNNING' && rev.tests[0].run_id === 'r9' && rev.tests[1].run_status === 'NOT RUN')) { console.log('self-test failed: a regenerated suite did not keep the existing case\'s live fields or dropped another suite'); fails = 1; } + if (!fails) console.log('self-test passed: one case per required regression with the id --, the line verbatim as title and accept, the owner from the dispatch table, finding and priority carried, NOT RUN; regenerating keeps live fields and the other suites'); + process.exit(fails); +} +const findings = JSON.parse(fs.readFileSync(arg('--findings'), 'utf8')); const dispatch = fs.readFileSync(arg('--dispatch'), 'utf8'); const prefix = arg('--prefix') || 'REV'; +const s = suite(findings, dispatch, prefix, `${path.relative(ROOT, arg('--findings'))} and ${path.relative(ROOT, arg('--dispatch'))}`); +const reg = JSON.parse(fs.readFileSync(REG, 'utf8')); +if (args.includes('--check')) { + const cur = (reg.suites || []).find((x) => x.code === prefix); const want = merge(JSON.parse(JSON.stringify(reg)), s).suites.find((x) => x.code === prefix); + if (JSON.stringify(cur) !== JSON.stringify(want)) { console.error(`review-suite: the registry's ${prefix} suite differs from the generator's output; run --write and commit`); process.exit(1); } + console.log(`review-suite: the ${prefix} suite matches its findings (${s.tests.length} cases)`); process.exit(0); +} +if (args.includes('--write')) { fs.writeFileSync(REG, JSON.stringify(merge(reg, s), null, 2) + '\n'); console.log(`review-suite: ${prefix} written, ${s.tests.length} cases from ${(findings.findings || []).length} findings`); process.exit(0); } +console.error('usage: review-suite.mjs --findings f --dispatch d [--prefix REV] --write|--check | --self-test'); process.exit(2); diff --git a/tools/ci/test-map-merge.py b/tools/ci/test-map-merge.py new file mode 100755 index 000000000..bfcd9551c --- /dev/null +++ b/tools/ci/test-map-merge.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python3 +"""A structural three-way merge of tools/ci/test-map.json (8 October 2026, 20:0x UK): two lanes adding cells on adjacent lines +collide as text; as objects they do not. Result = master's map, plus every cell (and not_run entry) the branch added or changed +against the base, minus the cells the branch removed that master left as the base had them. Everything else of the map (title, +registry, rule) is master's. Usage: test-map-merge.py ; --self-test.""" +import json, sys, tempfile, os + +def merge(base, master, branch): + out = json.loads(json.dumps(master)) + for key in ("cells", "not_run"): + b, m, r = base.get(key, {}), master.get(key, {}), branch.get(key, {}) + res = dict(m) + for k, v in r.items(): + if k not in b or b[k] != v: + res[k] = v + for k in b: + if k not in r and k in m and m[k] == b[k]: + del res[k] + out[key] = res + return out + +def self_test(): + fails = 0 + base = {"title": "t", "cells": {"c1": {"a": 1}, "c2": {"a": 2}, "c9": {"a": 9}}, "not_run": {"X-5": "none"}} + master = {"title": "t2", "cells": {"c1": {"a": 1}, "c2": {"a": 2}, "c9": {"a": 9}, "c4": {"a": 4}}, "not_run": {"X-5": "none", "X-6": "m"}} + branch = {"title": "t", "cells": {"c1": {"a": 1}, "c2": {"a": 22}, "c3": {"a": 3}}, "not_run": {}} # adds c3, changes c2, removes c9, clears X-5 + r = merge(base, master, branch) + want_cells = {"c1": {"a": 1}, "c2": {"a": 22}, "c4": {"a": 4}, "c3": {"a": 3}} + if r["cells"] != want_cells: print("self-test failed: cells:", r["cells"]); fails = 1 + if r["not_run"] != {"X-6": "m"}: print("self-test failed: not_run:", r["not_run"]); fails = 1 + if r["title"] != "t2": print("self-test failed: master's other fields not kept"); fails = 1 + # master changed c9 too: the branch's removal does not win + master2 = json.loads(json.dumps(master)); master2["cells"]["c9"] = {"a": 99} + if "c9" not in merge(base, master2, branch)["cells"]: print("self-test failed: a cell master changed was removed by the branch"); fails = 1 + if not fails: print("self-test passed: master's map plus the branch's added and changed cells and not_run entries, minus what the branch removed and master left alone; master's other fields kept") + return fails + +if __name__ == "__main__": + if "--self-test" in sys.argv: sys.exit(self_test()) + base, master, branch, out = (json.load(open(p)) for p in sys.argv[1:4]), None, None, None + b, m, r = base + res = merge(b, m, r) + with open(sys.argv[4], "w") as f: json.dump(res, f, indent=2); f.write("\n") + print(f"test-map-merge: {len(res.get('cells', {}))} cells, {len(res.get('not_run', {}))} NOT RUN reasons") diff --git a/tools/ci/test-record.mjs b/tools/ci/test-record.mjs index f75bd3728..cdaea54e4 100644 --- a/tools/ci/test-record.mjs +++ b/tools/ci/test-record.mjs @@ -10,8 +10,10 @@ // node tools/ci/test-record.mjs --record batch: {run_id, manifest_sha, evidence_dir, cells:[{cell, status, evidence}]} // each cell's case ids come from the map; the registry gains status/run/evidence/manifest // node tools/ci/test-record.mjs --cases the case ids a matrix cell answers (for the matrix scripts' column) +// node tools/ci/test-record.mjs --note "" append a dated note to a suite's notes (a ruling, a review finding's +// disposition); never a case's accept text // node tools/ci/test-record.mjs --self-test -import fs from 'node:fs'; import path from 'node:path'; +import fs from 'node:fs'; import path from 'node:path'; import child_process from 'node:child_process'; const args = process.argv.slice(2); const arg = (n) => { const i = args.indexOf(n); return i >= 0 ? args[i + 1] : undefined; }; const ROOT = process.env.TEST_RECORD_ROOT || path.resolve(path.dirname(new URL(import.meta.url).pathname), '..', '..'); const REG = process.env.TEST_REGISTRY || path.join(ROOT, 'docs/plans/igneum-2.0-test-registry.json'); @@ -65,15 +67,26 @@ if (args.includes('--self-test')) { if (!(reg.cases[1].run_status === 'NOT RUN' && /corpus/.test(reg.cases[1].evidence_record.reason))) { console.log('self-test failed: an unmapped Automated case did not read NOT RUN with its reason'); fails = 1; } if (reg.cases[2].run_status) { console.log('self-test failed: a manual case was given a run status'); fails = 1; } const regS = { suites: [{ code: 'X', tests: [{ id: 'X-1', method: 'Automated', accept: 'a' }] }] }; if (casesOf(regS).length !== 1) { console.log('self-test failed: the suites/tests registry shape was not read'); fails = 1; } + const regN = { suites: [{ code: 'FIN', tests: [{ id: 'F-1', method: 'Automated', accept: 'keep' }] }] }; fs.writeFileSync(`${d}/regn.json`, JSON.stringify(regN)); + const nr = child_process.spawnSync(process.execPath, [new URL(import.meta.url).pathname, '--note', 'FIN', 'the ruling'], { env: { ...process.env, TEST_REGISTRY: `${d}/regn.json`, TEST_MAP: `${d}/map.json` }, encoding: 'utf8' }); + const regN2 = JSON.parse(fs.readFileSync(`${d}/regn.json`, 'utf8')); + if (!(nr.status === 0 && regN2.suites[0].notes?.length === 1 && regN2.suites[0].notes[0].text === 'the ruling' && regN2.suites[0].tests[0].accept === 'keep')) { console.log(`self-test failed: --note did not append a dated note to the suite and keep the accept text: ${nr.stdout} ${nr.stderr}`); fails = 1; } let threw = false; try { record(reg, map, { run_id: 'r2', manifest_sha: 'x', cells: [{ cell: 'ghost', status: 'PASS' }] }); } catch { threw = true; } if (!threw) { console.log('self-test failed: a batch naming a cell not in the map was accepted'); fails = 1; } fs.rmSync(d, { recursive: true, force: true }); - if (!fails) console.log('self-test passed: a complete map checks; an unknown case id and an unmapped Automated case are refused; a run batch writes run_status, run_id, evidence_path, updated and the evidence record to the mapped cases only, leaves every accept text byte-identical, gives an unmapped Automated case NOT RUN with its reason and a manual case nothing; a batch naming an unknown cell is refused'); + if (!fails) console.log('self-test passed: a complete map checks; an unknown case id and an unmapped Automated case are refused; a run batch writes run_status, run_id, evidence_path, updated and the evidence record to the mapped cases only, leaves every accept text byte-identical, gives an unmapped Automated case NOT RUN with its reason and a manual case nothing; a batch naming an unknown cell is refused; --note appends a dated note to a suite and never touches an accept text'); process.exit(fails); } const reg = load(REG); const map = load(MAP); if (args.includes('--check')) { const r = check(reg, map); for (const l of r.lines) console.error(`test-record: ${l}`); console.log(`test-record: ${r.automated} Automated cases, ${r.mapped} mapped to cells, ${r.notRun} NOT RUN with a reason${r.bad ? `, ${r.bad} problems` : ''}`); process.exit(r.bad ? 1 : 0); } if (arg('--cases')) { console.log(((map.cells || {})[arg('--cases')]?.cases || []).join(',')); process.exit(0); } +if (arg('--note')) { + const code = arg('--note'); const text = args[args.indexOf('--note') + 2]; const suite = (reg.suites || []).find((s) => s.code === code); + if (!suite || !text) { console.error(`test-record: --note needs a suite code in the registry and a text (got ${code}, ${text ? 'text' : 'no text'})`); process.exit(2); } + const before = acceptSnapshot(reg); suite.notes = suite.notes || []; suite.notes.push({ at: new Date().toISOString(), text }); + if (acceptSnapshot(reg) !== before) { console.error('test-record: REFUSED: the note would change an accept text'); process.exit(1); } + fs.writeFileSync(REG, JSON.stringify(reg, null, 2) + '\n'); console.log(`test-record: note ${suite.notes.length} on ${code}: ${text.slice(0, 80)}`); process.exit(0); +} if (arg('--record')) { const batch = load(arg('--record')); const before = acceptSnapshot(reg); const touched = record(reg, map, batch); if (acceptSnapshot(reg) !== before) { console.error('test-record: REFUSED: the record would change an accept text'); process.exit(1); }