From e490db485d139d5b1e22fc2b6360daff6a2fa63a Mon Sep 17 00:00:00 2001 From: Greg Soucy Date: Fri, 20 Mar 2026 12:19:02 -0400 Subject: [PATCH] [runtime] align defaults and schema validators to v1.1.0 Why: keep fabricated x402 payloads and runtime-local schema validation aligned with the v1.1.0 protocol surface. Contract impact: none --- runtime/tests/runtime-signing.test.mjs | 31 ++++++++++++++++++++++++++ server.mjs | 12 +++++----- 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/runtime/tests/runtime-signing.test.mjs b/runtime/tests/runtime-signing.test.mjs index 107794d..0c82f27 100644 --- a/runtime/tests/runtime-signing.test.mjs +++ b/runtime/tests/runtime-signing.test.mjs @@ -54,6 +54,8 @@ function unwrapReceiptResponse(payload) { return { receipt: payload?.receipt || payload, runtimeMetadata: payload?.runtime_metadata || null }; } + + async function stop(proc) { if (proc.exitCode !== null) return; proc.kill("SIGTERM"); @@ -170,3 +172,32 @@ test("/verify?ens=1 passes with mocked ENS TXT response", async () => { await stop(srv.proc); } }); + + +test("fabricated x402 defaults use v1.1.0", async () => { + const keys = makeKeys(); + const srv = await startServer({ + API_VERSION: "1.1.0", + RECEIPT_SIGNING_PRIVATE_KEY_PEM_B64: keys.privatePemB64, + RECEIPT_SIGNING_PUBLIC_KEY_B64: keys.publicRaw32B64, + RECEIPT_SIGNER_ID: "runtime.commandlayer.eth", + }); + + try { + const receiptResp = await fetch(`${srv.base}/describe/v1.1.0`, { + method: "POST", + headers: { "content-type": "application/json" }, + body: JSON.stringify({ input: { subject: "t", detail_level: "short" }, trace: { provider: "test" } }), + }); + assert.equal(receiptResp.status, 200); + const response = await receiptResp.json(); + const { receipt } = unwrapReceiptResponse(response); + assert.deepEqual(receipt.x402, { + verb: "describe", + version: "1.1.0", + entry: "x402://describeagent.eth/describe/v1.1.0", + }); + } finally { + await stop(srv.proc); + } +}); diff --git a/server.mjs b/server.mjs index a6830e0..45c509e 100644 --- a/server.mjs +++ b/server.mjs @@ -772,7 +772,7 @@ function makeAjv() { } function receiptSchemaUrlForVerb(verb) { - return `${SCHEMA_HOST}/schemas/v1.0.0/commons/${verb}/receipts/${verb}.receipt.schema.json`; + return `${SCHEMA_HOST}/schemas/v1.1.0/commons/${verb}/receipts/${verb}.receipt.schema.json`; } async function getValidatorForVerb(verb) { @@ -793,9 +793,9 @@ async function getValidatorForVerb(verb) { // Preload shared refs (best effort) try { const shared = [ - `${SCHEMA_HOST}/schemas/v1.0.0/_shared/receipt.base.schema.json`, - `${SCHEMA_HOST}/schemas/v1.0.0/_shared/x402.schema.json`, - `${SCHEMA_HOST}/schemas/v1.0.0/_shared/identity.schema.json`, + `${SCHEMA_HOST}/schemas/v1.1.0/_shared/receipt.base.schema.json`, + `${SCHEMA_HOST}/schemas/v1.1.0/_shared/x402.schema.json`, + `${SCHEMA_HOST}/schemas/v1.1.0/_shared/identity.schema.json`, ]; await Promise.all(shared.map((u) => fetchJsonWithTimeout(u, SCHEMA_FETCH_TIMEOUT_MS).catch(() => null))); } catch { @@ -1349,7 +1349,7 @@ async function handleVerb(verb, req, res) { }; try { - const x402 = req.body?.x402 || { verb, version: "1.0.0", entry: `x402://${verb}agent.eth/${verb}/v1.0.0` }; + const x402 = req.body?.x402 || { verb, version: "1.1.0", entry: `x402://${verb}agent.eth/${verb}/v1.1.0` }; const callerTimeout = Number(req.body?.limits?.timeout_ms || req.body?.limits?.max_latency_ms || 0); const timeoutMs = Math.min(SERVER_MAX_HANDLER_MS, callerTimeout && callerTimeout > 0 ? callerTimeout : SERVER_MAX_HANDLER_MS); @@ -1374,7 +1374,7 @@ async function handleVerb(verb, req, res) { } } catch (e) { - const x402 = req.body?.x402 || { verb, version: "1.0.0", entry: `x402://${verb}agent.eth/${verb}/v1.0.0` }; + const x402 = req.body?.x402 || { verb, version: "1.1.0", entry: `x402://${verb}agent.eth/${verb}/v1.1.0` }; const actor = req.body?.actor ? { id: String(req.body.actor), role: "user" }