{"criteria_id":"payability/v1","criteria_revision":"1.0.0","family":"payability","op":"check","ops_not_offered":[],"corpus":{"id":"payability-corpus/v1","sha256":"3b2821f40815b77a85da6ac7c00cf2cc5d5c94a4aa166b40ccad1fd331c12427"},"corpus_pin_definition":"The corpus pin is the SHA-256 of the corpus's canonical serialization (the corpus object excluding its sha256 field), computed and verifiable by the published harness (harness.mjs). Expected outputs inside corpus cases are derived from the criteria text by an independent implementation in gen-corpus.mjs (never the engine's code path), and each case labels its provenance (constructed from on-disk fleet records vs synthetic).","price":{"usdc_units_per_call":10000,"label":"$0.01","basis":"per endpoint"},"free_tier":{"per_day":100,"min_interval_ms":5000,"on_exhaustion":"402"},"input_contract":{"body":"One JSON request body: { url, caller? (free pre-check only) }. The url is the single endpoint to check.","caps":{"body_bytes":262144},"over_cap":"A request body over 262,144 bytes is a free pre-gate refusal naming the cap.","validation":"The URL is validated FREE, before any payment: it must parse, use http/https, and carry no credentials. A malformed or policy-violating URL fails free and never consumes a payment. The target fetch itself runs only after payment verification."},"target_safety":"Target-URL policy (phase-1 SSRF discipline): the submitted URL must use http or https; must carry no embedded credentials (no userinfo); and is fetched once with a 5-second timeout, a response-body cap of 65,536 bytes, and redirects NOT followed to a different host (a redirect response is graded as received; a same-host redirect is likewise not followed in phase 1 — the 3xx response itself is the capture and grades NOT-A-402 unless it is a 402). Malformed URLs and policy violations are free refusals before any payment. An unreachable endpoint, a timeout, or an over-cap body is a paid verdict outcome (NOT-A-402 with the reason factor printed), never an error.","target_fetch":{"timeout_ms":5000,"body_cap_bytes":65536,"redirects":"not followed (phase 1)","method":"GET","auth":"none — exactly as an unauthenticated stranger"},"field_rule":"Field extraction (the fleet's x402 challenge shape, v1 body + v2 header): the body leg reads body.accepts[0] — recipient = payTo; token account = extra.usdc_token_account; memo = extra.memo (falling back to the body's top-level memo field); amounts = amount and maxAmountRequired; resource = resource; description = description. The header leg base64-decodes the PAYMENT-REQUIRED header as JSON and reads accepts[0] — memo = extra.memo, amount = amount, payTo = payTo, resource.url = resource.url. Amounts are mutually consistent when amount is present and (maxAmountRequired is absent or equal to amount) and (the header amount is absent or equal to the body amount). A field is present when it is a non-empty string (amounts: a string of digits).","state_rule":"Verdict states, decided in this exact order (first match wins): (1) NOT-A-402 — the fetch failed or timed out, the response status is not 402, or the response body exceeded the 65,536-byte cap. (2) RESOURCE-MISMATCH — a resource field is present (challenge body accepts[0].resource, or the decoded header's resource.url) and is not equal to the called URL. (3) HEADER-MISSING — the PAYMENT-REQUIRED header is absent or cannot be base64/JSON decoded. (4) AMOUNTS-ONLY — the amounts are present and mutually consistent, and recipient, token account, and memo are ALL absent. (5) UNCONFIGURED — the amount is absent or mutually inconsistent, or any core field (recipient, token account, memo, resource) is absent, or any header-to-body equality check (memo, amount, payTo) fails, or a 402 body cannot be JSON-decoded (with a decodable header present). (6) POPULATED — every field check passes. The description-length risk flag (description over 500 characters) is a factor only; it never changes the state.","states":["POPULATED","AMOUNTS-ONLY","UNCONFIGURED","HEADER-MISSING","RESOURCE-MISMATCH","NOT-A-402"],"description_flag":{"threshold_chars":500,"rule":"description_overlong is true when the challenge description is longer than 500 characters; it is a risk flag only and never changes the verdict state."},"verdict_grammar":{"line":"CHALLENGE PAYABILITY VERDICT — state: <STATE> — <check-end UTC>","vocabulary":"The line carries exactly one of the six published states. There is no composite score, grade, or band anywhere in this op."},"free_precheck":"The free pre-check (POST /precheck) validates the submitted URL against the published target-URL policy and returns assessability ONLY: the common signed fields, whether the URL is in-policy (or the free refusal naming the violation), and the disclosure/honesty/retention lines. It does NOT fetch the endpoint and returns no verdict, no state, and no factor. Free allowance: 100 per day per caller wallet, minimum interval 5,000 ms, 402 on exhaustion.","custody":{"construction":"In-memory processing within a single request lifetime; the fetched challenge persists nowhere, on any path including errors and timeouts. No hash of a fetched challenge appears anywhere.","ledger_closed_fields":["payer wallet","timestamp/day","price (USDC units) with the CAD fair-market-value block (rate, rate date, basis, cad_pending, refund)","payment tx id + Solana fee (lamports)","criteria version","verdict line","payability state","description_overlong flag","house flag"],"ledger_note":"The ledger list above is closed: adding a field is a criteria/handling version change. The ledger NEVER carries the called URL, any challenge field value, any challenge fragment, or any hash of a challenge.","errors":"Error handling is closed-form: static strings plus numeric facts only (lengths against caps, rule ids). No error path interpolates any part of a fetched challenge."},"forbidden":"Forbidden in every surface of this op (report, pre-check, errors, ledger, metrics): any composite score or grade; any judgement vocabulary beyond the six published states and the printed factors; any fetched challenge content beyond the presence/equality factors and the description length; any claim that a payment is guaranteed to settle.","boundary_statement":"Boundary vs Q-10 (F2 Listing-Presence Verdict): F2 returns coarse presence states for a submitted target (is something there, and does its challenge broadly match the listing claim). This service, A1, is the field-level decode underneath it: it fetches one endpoint's live 402 and grades the challenge's own fields one by one. F2 does not decode challenge fields; A1 does not grade listings, presence across venues, or listing claims. The fleet never sells the same check twice: presence is F2's ground, field-level payability is A1's.","disclosure_sentence":"Submitting an endpoint URL to any third party, this service included, discloses that you are checking that endpoint; the fetched challenge is processed in memory only and never stored, but the check does not undo the disclosure.","honesty_line":"The verdict grades the challenge exactly as served at check time to an unauthenticated stranger; a challenge can change between checks, and a POPULATED verdict states that the fields were present, consistent, and equal at that moment — it is not a guarantee that a payment will settle.","retention":"Target challenges are processed in memory only and are never stored — not in KV, not in logs, not in the payments ledger, not in metrics, and not in error records. No challenge body, fragment of it, or hash of it is recorded anywhere. Reports carry the verdict state, the field-check factors, and the called URL only. The payments ledger records only the closed field list published in the criteria. Because nothing is kept, a paid retry re-submits the URL.","payment_includes":"$0.01 per endpoint payability verdict. The fee is per endpoint: each endpoint URL you submit is charged at $0.01. The payment includes: one endpoint payability verdict — this service fetches that one endpoint's live 402 challenge exactly as an unauthenticated stranger would, decodes the challenge body and the PAYMENT-REQUIRED header, and returns one signed report giving the verdict state (POPULATED, AMOUNTS-ONLY, UNCONFIGURED, HEADER-MISSING, RESOURCE-MISMATCH, or NOT-A-402), every field-check factor (recipient present, token account present, memo present, amounts present and mutually consistent, resource.url equal to the called URL, header-to-body equality for memo, amount and payTo, and the description-length risk flag), and an as-of timestamp. No composite score is computed. A free pre-check validates the submitted URL against the published target-URL policy only — it does not fetch the endpoint and returns no verdict. The target endpoint's challenge is fetched once, at check time, and is never stored; the payments ledger records only the payer, the time, the price, the verdict state, and the verdict line.","kill_line":"Kill line (M-15 / A1, under the operator's 2026-11-03 build-bank-hold doctrine): build, bank, and hold; judged at the fleet's periodic reviews. There is NO demand kill line for this item. Day-0 = first outside paid settle (accounting only; house proofs never count). Tripwires, all stop-and-review: (1) refunds >5% in any 30-day window; (2) free use >10x paid use; (3) a wrong verdict from undisclosed stale or partial data (the error enters the corpus first as a regression case, corrected rules publish as a new criteria version, the corpus re-passes at 100% before serving resumes; issued reports are never amended); (4) custody: any surface retaining a fetched challenge body or a fragment of one; (5) any fetch outside the published target-URL policy.","never":"This op never follows a redirect; never sends credentials or any header beyond a plain unauthenticated GET; never stores a fetched challenge; never computes a composite score; never grades a listing or a venue (that is Q-10 F2's ground).","memo_op":{"op":"memo","route":"POST /memo (public: /toll/payability/memo)","price":{"usdc_units_per_call":10000,"label":"$0.01","basis":"per endpoint"},"fetches":"Two sequential GETs of the named endpoint, back-to-back, after payment verification (or on a verified-marker resume), under the same target-URL policy as the check op (http/https only, no URL credentials, 5,000 ms timeout per fetch, 65,536-byte body cap per fetch, redirects NOT followed).","states":["BOUND","MEMO-REUSED","LEG-MISMATCH","MEMO-ABSENT","NOT-A-402"],"state_rule":"Memo-binding verdict states, decided in this exact order (first match wins): (1) NOT-A-402 — either fetch failed or timed out, its response status is not 402, or its response body exceeded the 65,536-byte cap (the factors name the fetch). (2) MEMO-ABSENT — the body leg carries no memo in EITHER fetch. (3) LEG-MISMATCH — in either fetch, header-to-body memo equality is false (both legs carry a memo and they differ, or exactly one leg carries a memo). (4) MEMO-REUSED — both fetches carry body memos and they are identical. (5) BOUND — body memos are present in both fetches, unique across the pair, and header-to-body memo equality is true in both fetches. Completion rules for cases the five steps leave ungraded (published so the function is total): if the body memo is present in exactly one fetch and no earlier step matched, the state is MEMO-ABSENT with reason memo_absent_one_fetch (the pair cannot bind); if body memos are present in both, unique, and no earlier step matched but equality is not true in both fetches (a header leg carries no memo in a fetch, so equality is null there), the state is LEG-MISMATCH with reason memo_binding_not_established.","field_rule":"Memo field extraction (the same extraction as payability/v1 section 2, applied per fetch): the body leg memo is accepts[0].extra.memo, falling back to the body's top-level memo; the header leg memo is the decoded PAYMENT-REQUIRED header's accepts[0].extra.memo. Header-to-body memo equality per fetch follows the A1 semantics exactly: true when both legs carry a memo and they are equal; false when both carry it and differ, OR when exactly one leg carries it; null when neither leg carries it. Uniqueness across the pair is graded only when both fetches carry the memo on that leg, else null. The correlation-field census lists NAMES only (never values): per fetch and per leg, the sorted union of the accepts[0] top-level key names and the accepts[0].extra key names the challenge carries.","format_rule":"Memo freshness and format classes (deterministic, mechanical): freshness is graded on the body leg — regenerated when both fetches carry a body memo and they differ; static when both carry one and they are identical; not_gradable otherwise. The structural format class of one memo string: absent when no memo is carried; short when its length is under 8 characters; prefixed-opaque when it matches ^[A-Za-z][A-Za-z0-9]*[-_][A-Za-z0-9_-]+$ with a prefix of at least 2 characters before the first separator and a total length of at least 8; opaque otherwise.","factors":["per fetch: fetch_ok, status, is_402, body_over_cap, body_parseable, header_present, header_decodable, body_memo_present, header_memo_present","memo_equality_fetch1","memo_equality_fetch2","body_memos_unique","header_memos_unique","body_freshness_class","header_freshness_class","body_memo_format_fetch1","body_memo_format_fetch2","header_memo_format_fetch1","header_memo_format_fetch2","correlation_census (per fetch, per leg: sorted field NAMES only)"],"verdict_grammar":{"line":"MEMO BINDING VERDICT — state: <STATE> — <check-end UTC>","vocabulary":"The line carries exactly one of the five published memo-binding states. There is no composite score, grade, or band anywhere in this op."},"boundary_statement":"Boundary (A4): this op grades the CHALLENGE SIDE only. It observes the two challenges the endpoint issues back-to-back and grades the memos they carry. The seller's seen-set / replay store — whether the seller actually rejects a replayed memo — is internal to the seller, unobservable from outside, and is NEVER implied checked by any state this op returns, including BOUND. BOUND states only that the two observed challenges carried fresh, unique, leg-consistent memos.","payment_includes":"$0.01 per endpoint memo-binding check. The fee is per endpoint: each endpoint URL you submit is charged at $0.01. The payment includes: two back-to-back fetches of the named endpoint's live 402 challenge, memo presence grading per leg (body and PAYMENT-REQUIRED header) in each fetch, memo uniqueness grading across the pair, freshness-format grading of the memo (regenerated vs static, plus its structural format class), header-to-body memo equality in each fetch, and the correlation-field census (the NAMES only, never values, of the correlation-capable fields the challenge carries, per leg per fetch) — returned as one signed report giving the memo-binding verdict state (BOUND, MEMO-REUSED, LEG-MISMATCH, MEMO-ABSENT, or NOT-A-402), every factor, and an as-of timestamp. No composite score is computed. This op grades the CHALLENGE SIDE only: the seller's seen-set / replay store is internal and unobservable and is never implied checked. A free pre-check (op memo) validates the submitted URL against the published target-URL policy only — it does not fetch the endpoint and returns no verdict. The endpoint's challenges are fetched at check time and are never stored; the payments ledger records only the payer, the time, the price, the memo-binding state, and the verdict line — never any memo value.","ledger":{"kv_prefix":"pvm:ledger:","closed_fields":["payer wallet","timestamp/day","price (USDC units) with the CAD fair-market-value block (rate, rate date, basis, cad_pending, refund)","payment tx id + Solana fee (lamports)","criteria version","verdict line","memo_binding_state","house flag"],"note":"A closed list under its own KV prefix, distinct from the check op's ledger. The memo-op ledger NEVER carries the called URL, any memo value, any challenge field value, any challenge fragment, or any hash of a challenge."},"custody":"Challenge contents are processed in memory only and never stored on any surface (report, pre-check, errors, 402, ledger, KV, metrics). Reports carry factor booleans, format classes, and census field NAMES only — never a memo value.","free_precheck":"POST /precheck with { op: \"memo\" } returns assessability for the memo op only (no fetch, no verdict); its exhaustion 402 carries the /memo challenge (resource /toll/payability/memo). Omitting op, or op \"check\", returns the check op's pre-check unchanged."},"service":"payability-verdict","version":"1.0.0","endpoints":{"criteria":"GET /criteria (free)","precheck":"POST /precheck (free, URL-policy validation + assessability only: no fetch, no verdict; optional op field selects check (default) or memo)","check":"POST /check (paid, $0.01 per endpoint: signed challenge payability verdict)","memo":"POST /memo (paid, $0.01 per endpoint: signed memo-binding verdict over two back-to-back fetches)","metrics":"GET /metrics","not_offered":"Any other POST path answers NOT COVERED — this worker serves ops check and memo only."}}