diff --git a/infra/fast-time/proving-cache-history.mjs b/infra/fast-time/proving-cache-history.mjs
index 2934bd5d6..1a82e4a10 100644
--- a/infra/fast-time/proving-cache-history.mjs
+++ b/infra/fast-time/proving-cache-history.mjs
@@ -15,10 +15,10 @@
// node infra/fast-time/proving-cache-history.mjs --prove-bin
// [--before 90] [--after 120] [--slot 0] [--out ]
//
-// Verdict: (1) block n shard 0 paid exactly once, to PAYOUT; (2) H1's verifies.run grew by exactly 2 over the run (the
-// real proof once, the invalid bytes once) and verifies.cacheAnswers by at least 2; (3) the context refusal of phase 1
-// and the invalid refusal of phase 3 both read in H1's log; (4) the second use of the invalid bytes produced a refusal
-// with no new verify.
+// Verdict: (1) block n shard 0 paid exactly once, to PAYOUT; (2) H1 ran the SP1 verifier exactly twice over the run (the real
+// proof once, the invalid bytes once): the context refusal of phase 1 is a pre-check (the statement differs) that runs no
+// verifier and is never cached, re-read at every carrier; (3) the context refusal and the invalid refusal both read in H1's
+// log; (4) the second use of the invalid bytes is answered from the cache with no new verify (cacheAnswers at least 1).
import { spawn, spawnSync } from 'node:child_process';
import { mkdirSync, rmSync, writeFileSync, readFileSync, openSync, existsSync, appendFileSync } from 'node:fs';
import { createHash, randomBytes } from 'node:crypto';
@@ -136,7 +136,7 @@ async function rejoin(label) {
for (let k = 0; k < 120; k++) { if (await sameTip(A, H1)) { log(`${label}: A is on H1's tip (${k * 5} s)`); return true; } await sleep(5000); }
log(`${label}: A did not rejoin H1's tip in 600 s`); return false;
}
-async function verifies(node) { const s = await node.exec('igneum_getProvingStatus', []); return s.verifies || { run: 0, cacheAnswers: 0 }; }
+async function verifies(node) { const s = await node.exec('igneum_getProvingStatus', []); return s.verifies || { calls: 0, sp1: 0, contextRefusals: 0, cacheAnswers: 0 }; }
const refusals = (node) => (node.logText().match(/a carried proof record's proof does not verify: [^\n]*/g) || []);
async function submitVia(node, name, record, proof) {
let out;
@@ -233,15 +233,16 @@ try {
log(`phase 3: H1 verifies after 3a ${JSON.stringify(v3a)}, after 3b ${JSON.stringify(v3b)}; refusals ${ref3a} then ${ref3b}`);
// the verdict
const paidOnce = (o2.paid || []).length === 1 && (o1.paid || []).length === 0;
- const runs = Number(v3b.run) - Number(v0.run);
+ const runs = Number(v3b.sp1) - Number(v0.sp1); // SP1 verifies: the real proof once (phase 2), the invalid bytes once (3a); the context refusal of phase 1 runs no verifier
const cache = Number(v3b.cacheAnswers) - Number(v0.cacheAnswers);
+ const contextCheap = Number(v1.contextRefusals) - Number(v0.contextRefusals) >= 1 && Number(v1.sp1) === Number(v0.sp1);
const contextRefused = result.phases.context.refusals.length >= 1;
- const invalidRefusedTwiceNoVerify = ref3b > ref3a && Number(v3b.run) === Number(v3a.run);
- const pass = paidOnce && runs === 2 && cache >= 2 && contextRefused && invalidRefusedTwiceNoVerify;
- result.verdict = { paidOnce, verifiesRun: runs, cacheAnswers: cache, contextRefused, invalidRefusedTwiceNoVerify, pass };
+ const invalidRefusedTwiceNoVerify = ref3b > ref3a && Number(v3b.sp1) === Number(v3a.sp1);
+ const pass = paidOnce && runs === 2 && cache >= 1 && contextRefused && contextCheap && invalidRefusedTwiceNoVerify;
+ result.verdict = { paidOnce, sp1Verifies: runs, cacheAnswers: cache, contextRefused, contextCheap, invalidRefusedTwiceNoVerify, pass };
result.endedAt = new Date().toISOString();
writeFileSync(OUT, JSON.stringify(result, null, 2));
- log(`RESULT ${pass ? 'PASS' : 'FAIL'}: paid once=${paidOnce}; SP1 verifies run=${runs} (expect 2); cache answers=${cache} (expect >= 2); context refusal read=${contextRefused}; invalid refused again without a verify=${invalidRefusedTwiceNoVerify}; ${OUT}`);
+ log(`RESULT ${pass ? 'PASS' : 'FAIL'}: paid once=${paidOnce}; SP1 verifies=${runs} (expect 2: the real proof once, the invalid bytes once); context refusal read=${contextRefused} and cheap (no verifier)=${contextCheap}; cache answers=${cache} (expect >= 1); invalid refused again without a verify=${invalidRefusedTwiceNoVerify}; ${OUT}`);
await stopAll();
process.exit(pass ? 0 : 1);
} catch (e) {