From 409579e526730ba5b83b76145b1521948c6e3a1a Mon Sep 17 00:00:00 2001 From: Greg Soucy Date: Fri, 20 Mar 2026 19:06:52 -0400 Subject: [PATCH] [runtime] tighten verify warmup polling\n\nWhy: make the runtime chain schema verification test resilient to cached-only validator warmup while routing verify warmup through the shared helper.\nContract impact: none --- runtime/tests/runtime-signing.test.mjs | 46 ++++++++++++++++++-------- server.mjs | 3 +- 2 files changed, 33 insertions(+), 16 deletions(-) diff --git a/runtime/tests/runtime-signing.test.mjs b/runtime/tests/runtime-signing.test.mjs index 55e2ced..1d70a66 100644 --- a/runtime/tests/runtime-signing.test.mjs +++ b/runtime/tests/runtime-signing.test.mjs @@ -474,7 +474,7 @@ test("full chain clean -> summarize -> classify verifies with schema using parti async function verifyReceiptWithTimeout(receipt) { const controller = new AbortController(); - const timeout = setTimeout(() => controller.abort(), 5000); + const timeout = setTimeout(() => controller.abort(), 10000); try { const res = await fetch(`${srv.base}/verify?schema=1`, { @@ -492,10 +492,6 @@ test("full chain clean -> summarize -> classify verifies with schema using parti json = null; } - if (!res.ok && res.status !== 202) { - throw new Error(`HTTP ${res.status}: ${text}`); - } - return { res, text, json }; } catch (err) { const message = err?.name === "AbortError" ? "AbortError" : err?.message || String(err); @@ -528,16 +524,38 @@ test("full chain clean -> summarize -> classify verifies with schema using parti assert.equal(finalReceipt.x402.entry, "x402://classifyagent.eth/classify/v1.1.0"); - console.log("[chain] before verify request"); - let verifyAttempt = await verifyReceiptWithTimeout(finalReceipt); - console.log("[chain] after verify response", verifyAttempt.res.status, verifyAttempt.json ?? verifyAttempt.text); + let verifyAttempt = null; - if (verifyAttempt.res.status === 202) { - console.log("[chain] verify warmup 202 response", verifyAttempt.json ?? verifyAttempt.text); - await new Promise((resolve) => setTimeout(resolve, 1200)); - console.log("[chain] before verify request retry"); + for (let attempt = 1; attempt <= 3; attempt++) { + console.log(`[chain] before verify request attempt ${attempt}`); verifyAttempt = await verifyReceiptWithTimeout(finalReceipt); - console.log("[chain] after verify response retry", verifyAttempt.res.status, verifyAttempt.json ?? verifyAttempt.text); + console.log(`[chain] after verify response attempt ${attempt}`, verifyAttempt.res.status, verifyAttempt.json ?? verifyAttempt.text); + + const verifyRes = verifyAttempt.res; + const verifyJson = verifyAttempt.json; + + if (verifyRes.status === 200) break; + + if (verifyRes.status !== 202) { + throw new Error(`verify attempt ${attempt} returned unexpected status ${verifyRes.status}: ${verifyAttempt.text}`); + } + + const schemaErrors = Array.isArray(verifyJson?.errors?.schema_errors) ? verifyJson.errors.schema_errors : []; + const hasWarmupPending = schemaErrors.some((entry) => entry?.message === "validator_not_warmed_yet"); + + if (!hasWarmupPending) { + throw new Error(`verify attempt ${attempt} returned unexpected 202 payload: ${verifyAttempt.text}`); + } + + if (attempt === 3) { + throw new Error( + `verify warmup did not complete after 3 attempts; last status ${verifyRes.status}; last body: ${verifyAttempt.text}` + ); + } + + const retryAfterMs = Number(verifyJson?.retry_after_ms); + const delayMs = Number.isFinite(retryAfterMs) && retryAfterMs > 0 ? retryAfterMs : 1000; + await new Promise((resolve) => setTimeout(resolve, delayMs)); } const verifyRes = verifyAttempt.res; @@ -546,7 +564,7 @@ test("full chain clean -> summarize -> classify verifies with schema using parti assert.ok(verifyJson, "verify returned non-JSON response"); if (verifyRes.status !== 200) { - throw new Error(`verify retry failed with status ${verifyRes.status}: ${verifyAttempt.text}`); + throw new Error(`verify failed with status ${verifyRes.status}: ${verifyAttempt.text}`); } assert.equal(verifyJson.checks.signature_valid, true); diff --git a/server.mjs b/server.mjs index 4e7850b..26cd905 100644 --- a/server.mjs +++ b/server.mjs @@ -1880,8 +1880,7 @@ app.post("/verify", async (req, res) => { if (!verb) { schemaErrors = [{ message: "missing receipt.x402.verb" }]; } else if (VERIFY_SCHEMA_CACHED_ONLY && !hasValidatorCached(verb)) { - warmQueue.add(verb); - startWarmWorker(); + warmValidatorForVerb(verb); return res.status(202).json({ ok: false,