FACTS.md — walras (Stellar x402 facilitator + Bazaar)
Single source of truth. Rules:
- No protocol/library/API fact is asserted in code, docs, or the SCF submission unless it has a row here with status VERIFIED, a date, and a source.
- Web-sourced rows are re-verified against the pinned spec commit in Session 0 where applicable.
- On conflict between this file and anyone's memory: this file wins. On conflict between this file and the pinned spec: re-verify, update the row, log in DECISIONS.md.
Pinned spec commit: x402-foundation/x402 @ 17fc9890ade45a570a019352a3573391ad5d1e1f
(main, committed 2026-08-01T14:16:23+02:00; cloned to /workspaces/x402 on 2026-08-02.
All specs/… and typescript/… paths below are at that SHA.)
RFP source text: docs/rfp.md (verbatim, captured 2026-08-02).
Evidence transcripts: docs/EVIDENCE.md. Divergence log: docs/DECISIONS.md.
Verified — carried forward from 2026-07-31 (web-sourced)
| ID | Claim | Status | Date | Source |
|---|---|---|---|---|
| F-001 | @x402/stellar exists on npm; Apache-2.0. Version superseded — see F-040. |
VERIFIED | 2026-07-31 | npmjs.com/package/@x402/stellar |
| F-002 | Protocol repo is github.com/x402-foundation/x402 (migrated from coinbase/x402) |
VERIFIED | 2026-07-31 | repo README; npm package links |
| F-003 | Package provides Client / Facilitator / Server components; ExactStellarScheme; createEd25519Signer implements SEP-43 SignAuthEntry + SignTransaction |
VERIFIED | 2026-07-31 | npm README; re-confirmed at SHA (F-030) |
| F-004 | Networks: stellar:testnet (default RPC https://soroban-testnet.stellar.org), stellar:pubnet (custom RPC URL required), stellar:* wildcard; CAIP-2; x402 v2 |
VERIFIED | 2026-07-31 | npm README; re-confirmed at SHA (F-041) |
| F-005 | @x402/stellar implements the exact scheme only today → the upto Stellar gap in the RFP is real |
VERIFIED | 2026-07-31 | npm README; re-confirmed: only specs/schemes/upto/scheme_upto_{evm,svm}.md exist at SHA — no Stellar variant |
| F-006 | Facilitators currently always sponsor fees; areFeesSponsored: true |
VERIFIED | 2026-07-31 | npm README; re-confirmed live (F-025) and in source (F-031) |
| F-007 | Validity is ledger-based, ~12 ledgers ≈ 60 s. Derivation now pinned — see F-028. | VERIFIED | 2026-07-31 | npm README |
| F-008 | Any SEP-41 token supported; USDC default, 7 decimals; amounts in base units | VERIFIED | 2026-07-31 | npm README; confirmed on-chain (F-036, F-038) |
| F-009 | Bazaar is codified as an official v2 extension in the reference SDK | VERIFIED | 2026-07-31 | docs.cdp.coinbase.com/x402/bazaar; spec at SHA |
| F-010 | Cataloging is automatic after successful settle; no separate registration step. CDP behavior — NOT spec-mandated. See F-023. | VERIFIED (CDP only) | 2026-07-31 | docs.cdp.coinbase.com/x402/bazaar |
| F-011 | Cataloging outcomes reported via EXTENSION-RESPONSES header |
VERIFIED | 2026-07-31 | spec at SHA (F-024); SDK source (F-039) |
| F-012 | CDP prunes resources with no settlements for 30 days | VERIFIED (CDP behavior, not spec) | 2026-07-31 | docs.cdp.coinbase.com/x402/bazaar |
| F-013 | CDP's /discovery/search has no pagination. Confirmed as ecosystem-wide — the reference SDK impl also returns pagination: null unconditionally (F-027). |
VERIFIED | 2026-07-31 | docs.cdp.coinbase.com; e2e/facilitators/typescript/bazaar.ts |
| F-014 | CDP exposes the Bazaar to agents via MCP with tools shaped like search_resources / proxy_tool_call |
VERIFIED | 2026-07-31 | docs.cdp.coinbase.com/x402/bazaar |
| F-015 | OpenZeppelin Relayer is AGPL-3.0; @openzeppelin/relayer-sdk AGPL-3.0-or-later → excluded per RFP 3.6 |
VERIFIED | 2026-07-31 | github.com/OpenZeppelin/openzeppelin-relayer; npm |
| F-016 | SDF is a Premier member of the x402 Foundation with a Governing Board seat; Foundation launch 2026-07-14 | VERIFIED | 2026-07-31 | stellar.org/x402; RFP §2 corroborates |
| F-017 | x402.org facilitator supports stellar:testnet with sponsored fees |
VERIFIED | 2026-07-31 | confirmed live (F-025) |
| F-018 | stellar/x402-stellar repo carries SDF tools, examples, reference facilitator example |
VERIFIED | 2026-07-31 | developers.stellar.org; RFP appendix |
| F-019 | Freighter browser extension supports x402; Freighter Mobile does not yet | VERIFIED | 2026-07-31 | developers.stellar.org x402 docs |
| F-020 | SDK family includes @x402/extensions and @x402/mcp |
VERIFIED | 2026-07-31 | confirmed on npm (F-040) |
| F-021 | @x402/extensions provides bazaarResourceServerExtension and withBazaar |
VERIFIED | 2026-07-31 | source at SHA (F-032) |
| F-022 | Built on Stellar facilitator is built on OZ Relayer + x402 plugin (AGPL-excluded) | VERIFIED | 2026-07-31 | developers.stellar.org |
Context facts (submission, not build)
| ID | Claim | Status | Date | Source |
|---|---|---|---|---|
| C-001 | SCF FAQ: generally one project at a time per submitter | VERIFIED | 2026-07-31 | SCF Handbook FAQ |
| C-002 | Repeat Build applicants must show significant progress on prior project; reviewers assess only submission content | VERIFIED | 2026-07-31 | SCF Handbook |
| C-003 | Round deadline arrives in the SCF invitation email | VERIFIED (imprecise) | 2026-07-31 | SCF Handbook |
| C-004 | RFP Track: submissions reviewed by 2 reviewers from the quarter's Category Delegate Panel; third breaks ties. Scope may be limited if reasoning is articulated. Q3 RFPs opened 2026-07-23 for SCF #45. | VERIFIED | 2026-08-02 | docs/rfp.md Part A |
Verified — Session 0, from pinned spec / source / live measurement
Bazaar extension (Q-001) — specs/extensions/bazaar.md @ SHA
| ID | Claim | Status | Date | Source |
|---|---|---|---|---|
| F-023 | The spec does not require cataloging to be gated on settlement. Facilitator Behavior says only: (1) validate info against schema, (2) extract. "How a facilitator stores, indexes, and exposes discovered resources is an implementation detail." Settle-gating is our deliberate choice, not conformance. |
VERIFIED | 2026-08-02 | specs/extensions/bazaar.md §Facilitator Behavior |
| F-024 | EXTENSION-RESPONSES is base64-encoded JSON keyed by extension name. bazaar.status ∈ "success" | "processing" | "rejected" (required); bazaar.rejectedReason (optional string, human-readable, only when rejected). Facilitator MAY append it — it is not mandatory. |
VERIFIED | 2026-08-02 | specs/extensions/bazaar.md §Verify and Settlement Response Header |
| F-025 | /discovery/resources filters are seven, not six: type, payTo, scheme, network, extensions, limit, offset. RFP 3.2 omits scheme. Defaults from v2 spec §8.1: limit = 20 (range 1–100), offset = 0. |
VERIFIED | 2026-08-02 | specs/extensions/bazaar.md; specs/x402-specification-v2.md §8.1 |
| F-026 | /discovery/search query parameter is named query, not q. Required. Other params: type, payTo, scheme, network, extensions, limit, cursor. limit and cursor are explicitly advisory — "facilitator may return fewer or ignore". |
VERIFIED | 2026-08-02 | specs/extensions/bazaar.md; extensions/src/bazaar/facilitatorClient.ts L282-304 |
| F-027 | List and search return different array field names. List → items; search → resources. Confirmed in three places: TS types DiscoveryResourcesResponse.items vs SearchDiscoveryResourcesResponse.resources; the reference e2e catalog; v2 spec §8.1 example. bazaar.md's prose "mirrors the list endpoint with a resources array" is loose wording, not a third shape. |
VERIFIED | 2026-08-02 | extensions/src/bazaar/facilitatorClient.ts L126-159; e2e/facilitators/typescript/bazaar.ts L25-67 |
| F-028 | Search response fields: partialResults?: boolean ("true when additional matches were truncated"); pagination?: {limit: number, cursor: string | null} | null. Note search pagination has no offset/total — unlike list pagination {limit, offset, total}. |
VERIFIED | 2026-08-02 | specs/extensions/bazaar.md; facilitatorClient.ts L145-159 |
| F-029 | MCP resources are keyed on the tuple (resource.url, input.toolName) — facilitators MUST use both because MCP multiplexes tools over one endpoint. |
VERIFIED | 2026-08-02 | specs/extensions/bazaar.md §MCP Tools note |
| F-030 | routeTemplate validation: non-empty; starts /; matches ^/[a-zA-Z0-9_/:.\-~%]+$; no ..; no ://. Percent-decoding MUST precede the .. and :// checks. Failure = discard field and fall back to concrete URL path (soft-drop, not rejection). Shipped as isValidRouteTemplate. |
VERIFIED | 2026-08-02 | specs/extensions/bazaar.md §routeTemplate Validation Rules; extensions/src/bazaar/facilitator.ts L31-66 |
| F-031 | Soft-drop service metadata rules apply to resource.serviceName / tags / iconUrl (not to the discovery info block). serviceName: printable ASCII U+0020–U+007E, ≤32 chars. tags: ≤5 entries, each ≤32 printable-ASCII chars, deduped case-insensitively, first occurrence wins. iconUrl: ≤2048 chars, absolute http(s) only, no userinfo, IDN-normalized (UTS #46), rejects IP literals / loopback set / all-digit / hex hostnames. Percent-decode the host before IP and loopback checks. |
VERIFIED | 2026-08-02 | specs/extensions/bazaar.md §Validation Rules; extensions/src/bazaar/facilitator.ts L83-283 |
| F-032 | Clients echo the bazaar extension from PaymentRequired into PaymentPayload. If omitted, no cataloging occurs — the seller cannot force a listing. |
VERIFIED | 2026-08-02 | specs/extensions/bazaar.md §Client Behavior |
Exact-Stellar scheme (Q-002) — specs/schemes/exact/scheme_exact_stellar.md @ SHA
| ID | Claim | Status | Date | Source |
|---|---|---|---|---|
| F-033 | payload is exactly {"transaction": "<base64 XDR>"} — a Stellar transaction with a single invokeHostFunction op calling transfer(from, to, amount) plus signed auth entries. Scope is SEP-41 Soroban tokens only; classic Stellar assets are not supported. |
VERIFIED | 2026-08-02 | spec §PaymentPayload payload Field, §Summary NOTE |
| F-034 | Auth-entry expiry derivation: ledgerTimeout = ceil(maxTimeoutSeconds / estimatedLedgerSeconds), using the live network estimate where available, fallback 5 s. With the default maxTimeoutSeconds: 60 this yields 12 ledgers — the origin of the "~12 ledgers ≈ 60 s" figure in F-007. |
VERIFIED | 2026-08-02 | spec §Protocol Flow step 4, §Authorization Entries |
| F-035 | Facilitator verification MUST list has five groups: protocol (version/scheme/network), transaction structure (1 op, contract == asset, fn transfer w/ 3 args, arg1 == payTo, arg2 == amount as i128), auth entries (sorobanCredentialsAddress only, no subInvocations, all required signers signed, expiry bound), facilitator safety (facilitator must not be tx source, op source, from, or appear in any auth entry; simulation must show only the expected balance changes), and simulation (must succeed and emit events confirming the exact amount). |
VERIFIED | 2026-08-02 | spec §Facilitator Verification Rules (MUST) |
| F-036 | /settle MUST perform full verification independently and MUST NOT assume prior verification. The package already honours this — settle() calls _verify() as its Step 1. Our wrapper must therefore NOT re-verify. |
VERIFIED | 2026-08-02 | spec §Protocol Flow step 10 NOTE; mechanisms/stellar/src/exact/facilitator/scheme.ts L208 |
| F-037 | Fee rules: facilitator MUST derive the settlement fee from a fresh settle-time simulation (simulationResourceFee + inclusionBuffer, buffer ≥ 100 stroops), refresh Soroban footprint/resourceFee from that simulation, and fully override the client's fee bid. Optional maxTransactionFeeStroops ceiling, default 50 000 stroops, rejects with invalid_exact_stellar_payload_fee_exceeds_maximum. |
VERIFIED | 2026-08-02 | spec §Transaction Fees |
| F-038 | SettlementResponse = {success, transaction, network, payer} where transaction is the 64-char hex tx hash and payer is the client's address (never the facilitator's). |
VERIFIED | 2026-08-02 | spec §Phase 3 |
| F-039 | The spec's MUST list contains no explicit replay check. Replay resistance is structural: a reused Soroban auth-entry nonce makes re-simulation fail, and simulation success is itself a MUST. The package likewise has no explicit replay branch. RFP 3.1 demands "not replayed", so this must be stated as structural and demonstrated empirically, not claimed as a coded check. | VERIFIED | 2026-08-02 | spec §Facilitator Verification Rules; scheme.ts L493-504 (no replay branch) |
Facilitator surface & /supported (Q-003, Q-005)
| ID | Claim | Status | Date | Source |
|---|---|---|---|---|
| F-040 | /supported returns {kinds[], extensions[], signers{}} — all three required. Each kind: {x402Version, scheme, network, extra?}. signers maps CAIP-2 patterns (stellar:*) to public addresses. |
VERIFIED | 2026-08-02 | specs/x402-specification-v2.md §7.3, §7.3.1 |
| F-041 | Live capture of https://x402.org/facilitator/supported returns for Stellar: {"x402Version":2,"scheme":"exact","network":"stellar:testnet","extra":{"areFeesSponsored":true}}, and signers["stellar:*"] = ["GC6CSXBV4C6RL3HEDTW57KXYXSSXKAWKGYDEOSATXM3XNKXSR2VRYN3K","GC5OLUZ4WANPN6VT7YGTK2SRMZG762KOVKJXHWIO4K57UBASO2FMNRET"] (two signers). No stellar:pubnet kind is advertised. |
VERIFIED | 2026-08-02 | evidence §S0-2 |
| F-042 | The x402.org facilitator advertises extensions: ["builder-code","eip2612GasSponsoring","erc20ApprovalGasSponsoring"] — bazaar is absent. The public conformance baseline does not advertise Bazaar support at all. |
VERIFIED | 2026-08-02 | evidence §S0-2 |
| F-043 | areFeesSponsored is not Stellar-only: x402.org advertises xrpl:1 with extra.areFeesSponsored: false, confirming it as a cross-chain field with a meaningful false case. |
VERIFIED | 2026-08-02 | evidence §S0-2 |
| F-044 | Wrap target: class ExactStellarScheme implements SchemeNetworkFacilitator, imported from @x402/stellar/exact/facilitator. Constructor (signers: FacilitatorStellarSigner[], {rpcConfig?, areFeesSponsored=true, maxTransactionFeeStroops=50_000, selectSigner=roundRobin, feeBumpSigner?}). Methods: verify(), settle(), getExtra(network) → {areFeesSponsored}, getSigners(network). Package exports: ., ./exact/client, ./exact/server, ./exact/facilitator. |
VERIFIED | 2026-08-02 | mechanisms/stellar/src/exact/facilitator/scheme.ts L85-174; package.json exports |
| F-045 | The package performs all of the spec's verification MUSTs itself, emitting 37 distinct machine-readable reason codes (30 on the verify path, 7 on the settle path; enumerated in DECISIONS D-007). Our wrapper adds zero payment validation — its jobs are HTTP surface, config, caller auth, and the discovery hook. | VERIFIED | 2026-08-02 | scheme.ts L379-556, L610-804 |
| F-046 | The package tolerates auth-entry expiry 2 ledgers beyond the spec's strict bound (SIGNATURE_EXPIRATION_LEDGER_TOLERANCE = 2, for RPC skew). The spec says MUST NOT exceed currentLedger + ceil(...). This is an implementation deviation we inherit by wrapping. |
VERIFIED | 2026-08-02 | scheme.ts L37, L769 |
| F-047 | Settle supports an optional feeBumpSigner that wraps the inner transaction in a FeeBumpTransaction, decoupling fee payment from sequence-number management — i.e. the throughput answer to RFP 3.5 is already in the package. |
VERIFIED | 2026-08-02 | scheme.ts L106-108, L287-323 |
Bazaar facilitator-side helpers (Q-006)
| ID | Claim | Status | Date | Source |
|---|---|---|---|---|
| F-048 | @x402/extensions DOES ship facilitator-side cataloging helpers — contradicting the pre-build plan's expectation (Q-006 "Expected: our build"). Exported from @x402/extensions/bazaar: extractDiscoveryInfo, extractDiscoveryInfoFromExtension, validateAndExtract, validateDiscoveryExtension (Ajv 2020-12 against the supplied schema), validateDiscoveryExtensionSpec (protocol invariants), isValidRouteTemplate, isValidServiceName, sanitizeTags, isValidIconUrl, sanitizeResourceServiceMetadata. |
VERIFIED | 2026-08-02 | extensions/src/bazaar/index.ts L108-127 |
| F-049 | What remains our build: persistence, indexing, the two discovery HTTP endpoints, ranking, retention, and the DiscoveredResource → DiscoveryResource wire mapping. The package stops at extraction; it never stores or serves. |
VERIFIED | 2026-08-02 | extensions/src/bazaar/facilitator.ts (no storage); spec §Facilitator Behavior |
| F-050 | Two distinct types with confusingly similar names. DiscoveredResource (extraction output) = {resourceUrl, description?, mimeType?, serviceName?, tags?, iconUrl?, method?|toolName, routeTemplate?, x402Version, discoveryInfo, extensions?}. DiscoveryResource (catalog wire shape) = {resource, type, x402Version, accepts[], lastUpdated, description?, mimeType?, serviceName?, tags?, iconUrl?, extensions?}. The mapping between them is unimplemented in the package and is ours. |
VERIFIED | 2026-08-02 | bazaar/http/types.ts, bazaar/mcp/types.ts, bazaar/facilitatorClient.ts L98-121 |
| F-051 | extractDiscoveryInfo canonicalizes the catalog URL as ${origin}${routeTemplate} when a valid routeTemplate is present, else ${origin}${pathname} — query string and fragment are stripped. On schema-validation failure it console.warns and returns null (soft-drop, never throws). |
VERIFIED | 2026-08-02 | extensions/src/bazaar/facilitator.ts L504-538 |
Toolchain, assets, fees (Q-004, Q-007, Q-008, Q-010, Q-012, Q-013)
| ID | Claim | Status | Date | Source |
|---|---|---|---|---|
| F-052 | Testnet USDC SAC contract ID is CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA, wrapping classic asset USDC:GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5, decimals() == 7. Verified four independent ways: spec example, package constant USDC_TESTNET_ADDRESS, on-chain ledger entry (executable == contractExecutableStellarAsset, METADATA storage), and cryptographic re-derivation Asset("USDC", issuer).contractId(TESTNET) round-tripping to the same ID. |
VERIFIED | 2026-08-02 | evidence §S0-3 |
| F-053 | Mainnet USDC SAC constant is CCW67TSZV3SSS2HXMBQ5JFGCKJNXKZM7UQUWUZPUTHXSTZLEO7SJMI75 (package constant; not independently verified on pubnet — out of pre-build scope). |
VERIFIED (source only) | 2026-08-02 | mechanisms/stellar/src/constants.ts L29 |
| F-054 | Measured settlement fee on stellar:testnet: 23 073 stroops = 0.0023073 XLM, observed repeatedly across the x402.org facilitator's settlements (a second cluster at 20 654 stroops = 0.0020654 XLM). The RFP's "about 0.0023 XLM" (§2) is confirmed to two significant figures by live measurement. Observed max_fee 33 253 — only ~1.5× headroom under the 50 000-stroop default ceiling (F-037). |
VERIFIED | 2026-08-02 | evidence §S0-4 |
| F-055 | The x402.org Stellar facilitator settles using a fee-bump transaction with a separate fee account (source_account = GC6CSXBV…, fee_account = GC5OLUZ4…), i.e. it uses the package's feeBumpSigner path in production. |
VERIFIED | 2026-08-02 | evidence §S0-4 |
| F-056 | e2e suite lives at e2e/, run with pnpm install:all then pnpm test (interactive selector) or pnpm test --min. Stellar env vars: SERVER_STELLAR_ADDRESS, CLIENT_STELLAR_PRIVATE_KEY, FACILITATOR_STELLAR_PRIVATE_KEY; facilitator process also reads STELLAR_PRIVATE_KEY, STELLAR_NETWORK (default stellar:testnet), STELLAR_RPC_URL. Requires Node ≥ 22. Setup path: Stellar Lab keypair + Friendbot → USDC trustline via lab.stellar.org/account/fund → Circle faucet (faucet.circle.com, select Stellar) for testnet USDC. |
VERIFIED | 2026-08-02 | e2e/README.md L120-226; e2e/package.json |
| F-057 | X-PAYMENT; payment response X-PAYMENT-RESPONSEx402Version and Session 0 read the v1 branch. EXTENSION-RESPONSES (facilitator→server) remains correct. |
SUPERSEDED | 2026-08-02 | D-018; F-065 |
| F-058 | Toolchain pinned: Node v24.14.0 (local) — but @x402/stellar and the e2e suite both declare engines.node >= 22; pnpm 10.32.1; npm 11.9.0; git 2.53.0. All @x402/* packages at 2.20.0, Apache-2.0. |
VERIFIED | 2026-08-02 | G0.1 capture; npm view; evidence §S0-1 |
| F-059 | @x402/stellar@2.20.0 requires @stellar/stellar-sdk: ^16.0.1 and @x402/core: ~2.20.0. Pinning @stellar/stellar-sdk at ^14 produces a duplicate SDK in the tree (14.6.1 + 16.2.0) and the settle path's fee arithmetic is written against v16 semantics. We must pin ^16. |
VERIFIED | 2026-08-02 | node_modules/@x402/stellar/package.json; evidence §S0-5; scheme.ts L253 comment |
| F-060 | Q-010 license scan PASS. 294 distinct packages across the full planned dependency set: 249 MIT, 17 Apache-2.0, 14 ISC, 8 BSD-3-Clause, 2 BSD-2-Clause, 3 permissive dual/multi, 1 Unlicense. Zero AGPL/SSPL/OSL/EUPL/CPAL/RPL. Zero GPL/LGPL/MPL/CDDL/EPL. Zero undeclared. | VERIFIED | 2026-08-02 | evidence §S0-5 |
| F-061 | Package version drift is fast and real: @x402/* moved 2.17.0 → 2.20.0 in the two days between the 2026-07-31 fact-check and 2026-08-02. The pinned spec SHA is dated 2026-08-01, one day before this session. The RFP's "drift, not inability, is the failure mode" (§4) is empirically supported. |
VERIFIED | 2026-08-02 | F-001 vs F-058 |
Session 1 — from package source and the published artifact
| ID | Claim | Status | Date | Source |
|---|---|---|---|---|
| F-062 | gatherAuthEntrySignatureStatus classifies an auth entry as signed purely by testing that its signature ScVal is not scvVoid — it performs no cryptographic verification. A forged or corrupted signature is therefore invisible to every check @x402/stellar makes on its own, and is caught only by the Soroban host during simulation. This is why "simulation MUST succeed" (F-035) is load-bearing rather than defence-in-depth: it is the sole control against a forged authorization. |
VERIFIED | 2026-08-02 | mechanisms/stellar/src/shared.ts L117-126 @ SHA; demonstrated S1-4 |
| F-063 | The 37 reason codes of F-045 are present in the published npm artifact of @x402/stellar@2.20.0 (dist/esm/exact/facilitator/index.mjs), not only in the source tree S0-6 read. The enumeration is asserted against the installed bundle by packages/facilitator/test/errors.test.ts, so an upstream rename breaks the build rather than degrading a rejection reason silently. |
VERIFIED | 2026-08-02 | S1-5 |
| F-064 | The verification step ordering in ExactStellarScheme._verify places auth-entry checks (expiry bound, credential type, sub-invocations, signature status) and transfer-event checks after simulateTransaction. Consequently, on a network where simulation cannot succeed, those codes are unreachable and every payload collapses to invalid_exact_stellar_payload_simulation_failed. Structural checks (version, scheme, network, operation shape, asset, function name, recipient, amount, facilitator safety) all precede simulation and remain reachable. Confirmed live in S2: expired and replayed payloads both surface as …_simulation_failed; wrong_amount fires pre-simulation. |
VERIFIED | 2026-08-02 | scheme.ts L385-551 @ SHA; S1-3, S1-4, S2-6 |
Session 2 — live conformance on stellar:testnet
| ID | Claim | Status | Date | Source |
|---|---|---|---|---|
| F-065 | v2 canonical wire headers are PAYMENT-REQUIRED (402), PAYMENT-SIGNATURE (paid request), PAYMENT-RESPONSE (receipt) — named canonical in specs/transports-v2/http.md §Header Reference and emitted by x402HTTPClient.encodePaymentSignatureHeader when x402Version === 2. X-PAYMENT/X-PAYMENT-RESPONSE are the v1 names (v1 emit branch; v1 fallback read). Observed live, casing as-sent, on the S2 transcript. Supersedes F-057. |
VERIFIED | 2026-08-02 | spec @ SHA; x402HTTPClient.ts L90-156; S2-2 |
| F-066 | An unmodified stock client completed a payment end-to-end through the walras facilitator on stellar:testnet: @x402/fetch buyer + @x402/express seller (both stock, zero custom protocol code), settled tx ac50c0910b3484ae6f2b070f35a95d1062dd3269cd4f877434dbcf2d7d3cc155 (ledger 3935588, successful, verified on Horizon and stellar.expert), 0.01 USDC buyer→seller, payer = buyer address. Full wire transcript captured by transparent taps. Q-011 closed. Note: the @x402/express middleware defaults maxTimeoutSeconds to 300, not the scheme spec's illustrative 60 (F-034 derivation unchanged). |
VERIFIED | 2026-08-02 | S2-2, S2-3 |
| F-067 | The repo e2e suite passes against walras: --facilitators=walras --families=stellar --testnet with servers {express, hono} × clients {fetch, axios} = 4/4 pass, each with a real on-chain settlement (hashes in S2-4, all verified on Horizon). walras ran as an external-proxy facilitator exec'ing the unmodified built dist. 11 e2e settlements total this session; every one charged exactly 22 973 stroops. |
VERIFIED | 2026-08-02 | S2-4; e2e/logs/walras-stellar-s2-final.* |
| F-068 | Two e2e-harness defects at the pinned SHA, both invisible when the bundled all-family reference facilitator runs: (a) the mock facilitator omits batch-settlement from evmSchemes despite its stated claim-everything contract, killing every TS server's route validation under a non-EVM external facilitator; (b) servers/fastify never reads MOCK_FACILITATOR_URL, so it cannot start against any single-family facilitator at all. (a) fixed locally in scaffolding (one line); (b) excluded from the matrix. Both upstream-reportable. |
VERIFIED | 2026-08-02 | e2e/mock-facilitator/index.ts L28; grep MOCK_FACILITATOR_URL e2e/servers/*/index.ts; S2-4 |
| F-069 | Measured walras settlement fee: 22 973 stroops = 0.0022973 XLM, uniform across all 12 S2 settlements (max_fee 33 153). Exactly 100 stroops below the x402.org baseline's dominant cluster (23 073, F-054) — the delta is the baseline's fee-bump operation's own base fee (a fee bump pays for inner ops + 1). Q-008 cross-check closed: the RFP's "about 0.0023 XLM" holds for walras. Balance accounting exact: buyer −0.021 USDC, seller +0.021 USDC, facilitator −0.0275676 XLM = 12 × 22 973 stroops, and the facilitator held USDC at no point. | VERIFIED | 2026-08-02 | S2-3; Horizon |
Session 3 — discovery layer verification
| ID | Claim | Status | Date | Source |
|---|---|---|---|---|
| F-070 | node:sqlite (DatabaseSync) works on the pinned Node v24.14.0: file-backed DBs accept PRAGMA journal_mode=WAL (returns wal; :memory: DBs report memory, as SQLite defines), positional binding, transactions, and ON CONFLICT DO UPDATE all function. The module emits ExperimentalWarning — accepted as a pre-build risk in D-023. |
VERIFIED | 2026-08-02 | live probe; S3-1; test suite S3-2 |
| F-071 | @x402/extensions@2.20.0 is Apache-2.0; its transitive dependencies (@noble/curves, @scure/base, ajv, jose, @signinwithethereum/siwe, tweetnacl, viem, zod, @x402/core) are MIT / Apache-2.0 / Unlicense. Full-tree license scan re-run after install: PASS, zero copyleft. |
VERIFIED | 2026-08-02 | npm view; scripts/license-scan.mjs; S3-1 |
| F-072 | The SDK's one-shot extractDiscoveryInfo is not a trust boundary: it validates info only against the CLIENT-supplied schema (a trivial schema validates anything), never calls the exported validateDiscoveryExtensionSpec protocol-invariant check, discards rejection reasons into console.warn, and calls new URL(resource.url) unguarded (throws on a missing/malformed URL). A hardened facilitator must compose the low-level helpers itself. |
VERIFIED | 2026-08-02 | extensions/src/bazaar/facilitator.ts L475-579 @ SHA; demonstrated by the trivial-schema test, S3-2, and live S3-4 |
| F-073 | The stock @x402/core facilitator client parses EXTENSION-RESPONSES on verify/settle responses and console.logs fields from the allowlist ["status","rejectedReason","reason","code"] — so D-014's additive machine code is visible to unmodified consumers. Observed live: the stock seller middleware logged {"bazaar":{"status":"success"}} from walras's header. |
VERIFIED | 2026-08-02 | core/src/http/httpFacilitatorClient.ts L253-286 @ SHA; S3-3 |
| F-074 | @x402/express auto-registers bazaarResourceServerExtension when route configs declare bazaar extensions (checkIfBazaarNeeded → dynamic import → registerExtension), and x402HTTPResourceServer route config carries serviceName/tags/iconUrl through to the 402 resource block. A seller needs only declareDiscoveryExtension in route config — no explicit extension registration. |
VERIFIED | 2026-08-02 | http/express/src/index.ts L122-139 @ SHA; live 402 capture, S3-3 |
| F-075 | The full RFP 3.2 automatic-cataloging loop works live on stellar:testnet: stock buyer pays stock bazaar-declaring seller through walras (tx 81c4baac…9b3f, ledger 3936498, fee 22 973 stroops = F-069 exactly) → listing appears in GET /discovery/resources with zero registration steps → stock middleware logs the success header. Hostile payloads: a trivial-schema extension and a real settled wrong-payee payment (tx 66da7395…42d4) were both soft-dropped with machine codes (bazaar_spec_validation_failed, bazaar_listing_owned_by_other_payee) while their settlements succeeded on-chain. |
VERIFIED | 2026-08-02 | S3-3, S3-4; Horizon |
Session 4 — search verification
| ID | Claim | Status | Date | Source |
|---|---|---|---|---|
| F-076 | node:sqlite on the pinned Node v24.14.0 bundles SQLite 3.51.2 compiled with SQLITE_ENABLE_FTS5: FTS5 virtual tables and bm25() work. bm25() returns negative scores, smaller = more relevant (ascending order = best first). Raw user text in MATCH throws (fts5: syntax error) on operator characters (", (, :, *, -, …), so untrusted queries must be compiled to quoted-token expressions before reaching the engine. |
VERIFIED | 2026-08-03 | live probe, PRAGMA compile_options; S4-2 |
| F-077 | Search pagination.limit is "Number of results in this page" — the returned count, per both the spec table and the SDK type comment — NOT the requested maximum, unlike the list endpoint's pagination.limit. pagination.cursor is "Cursor for the next page, or null if unavailable". |
VERIFIED | 2026-08-03 | specs/extensions/bazaar.md §GET /discovery/search @ SHA; facilitatorClient.ts L145-159 |
Docs session — documentation toolchain (gate GD.3)
| ID | Claim | Status | Date | Source |
|---|---|---|---|---|
| F-084 | Docs tooling licenses checked on the npm registry before install (gate GD.3): @mermaid-js/mermaid-cli@11.16.0 MIT, @redocly/cli@2.44.2 MIT, markdown-link-check@3.15.0 ISC, yaml@2.9.0 ISC. Zero copyleft at top level. The mermaid-cli transitive tree carries three dev-only findings (elkjs EPL-2.0, dompurify MPL-2.0-OR-Apache-2.0, khroma undeclared-but-MIT-on-disk) — none in any workspace project's production dependency closure (pnpm ls -r --prod). G-LIC re-run PASS under the two-tier policy of D-031. Extends the Q-012 toolchain pin (F-058). |
VERIFIED | 2026-08-05 | npm view (pre-install); pnpm why; on-disk license files; DECISIONS D-031; evidence §Docs |
| F-085 | Stellar account reserves: one base reserve is 0.5 XLM, and every subentry — a trustline is one subentry — raises the account's minimum balance by one base reserve. Onboarding consequence: an account needs spare XLM above its current minimum before it can add the USDC trustline. Invisible on testnet (Friendbot funds 10 000 XLM); real on pubnet. | VERIFIED | 2026-08-05 | developers.stellar.org — Fundamentals → Stellar data structures → Accounts (fetched 2026-08-05) |
| F-086 | walras fee-bump settlement measured live: with FEE_BUMP_SECRET set, every settlement is a fee-bump envelope — Horizon shows fee_account ≠ source_account, fee_charged 23 073 stroops, max_fee 33 253, receipt carrying the outer (fee-bump) hash with the inner hash resolvable. Exactly +100 stroops over the single-submitter posture (F-069), confirming D-021's arithmetic, and byte-identical to the x402.org baseline's dominant fee anatomy (F-054, F-055). |
VERIFIED | 2026-08-05 | S7-1; Horizon tx 7519b950…9875 |
Session 6 — @x402/mcp and the MCP transport (gate G6.1)
| ID | Claim | Status | Date | Source |
|---|---|---|---|---|
| F-078 | @x402/mcp@2.20.0 is Apache-2.0. Runtime deps: @modelcontextprotocol/sdk ^1.12.1 (MIT), zod ^3.24.2 (MIT), @x402/core ~2.20.0 (Apache-2.0). Exports (from src/index.ts @ SHA): client x402MCPClient + factories createx402MCPClient / wrapMCPClientWithPayment(FromConfig); server createPaymentWrapper; constants MCP_PAYMENT_META_KEY = "x402/payment", MCP_PAYMENT_RESPONSE_META_KEY = "x402/payment-response", MCP_PAYMENT_REQUIRED_CODE = 402; meta attach/extract utils; createToolResourceUrl → mcp://tool/{name}. |
VERIFIED | 2026-08-05 | npm view; typescript/packages/mcp/src/index.ts, types/mcp.ts @ SHA |
| F-079 | MCP transport spec exists at the pinned SHA: specs/transports-v2/mcp.md. 402 signaling = tool result with isError: true carrying PaymentRequired in both structuredContent (REQUIRED) and content[0].text (REQUIRED, the JSON-stringified same object). Payment rides _meta["x402/payment"] (PaymentPayload); receipt rides _meta["x402/payment-response"] (SettlementResponse). Settlement failure after execution = same 402-shaped result, and the server should not return the tool's content — only the payment error. |
VERIFIED | 2026-08-05 | specs/transports-v2/mcp.md @ SHA |
| F-080 | Division of labor: @x402/mcp provides the payment-aware MCP client (transparent 19-method passthrough; callTool detects 402-in-result and McpError -32042/SEP-1036, auto-pays, retries once on a corrective 402) and the server-side tool wrapper (createPaymentWrapper: verify → execute → settle via x402ResourceServer; on settle failure withholds tool content per spec). It provides no MCP server surface, no discovery/search tools, no MCP→HTTP bridge, and no catalog resolution — the walras packages/mcp-server (search_resources, paid_call) is entirely our build. Caveat: getToolPaymentRequirements probes by actually calling the tool — a free tool executes as a side effect. |
VERIFIED | 2026-08-05 | mcp/src/client/x402MCPClient.ts, mcp/src/server/paymentWrapper.ts @ SHA |
| F-081 | Client-side spend-cap seam: x402Client.registerPolicy((x402Version, reqs) => reqs) filters PaymentRequirements[] before scheme selection and binds every transport sharing that client (HTTP wrapFetchWithPayment, MCP x402MCPClient). If policies filter everything out, payload creation throws "All payment requirements were filtered out by policies for x402 version: …". A 402 can also be inspected pre-payment: x402HTTPClient.getPaymentRequiredResponse(getHeader, body?) decodes the v2 PAYMENT-REQUIRED header (v1 body fallback), throwing "Invalid payment required response" otherwise. |
VERIFIED | 2026-08-05 | core/src/client/x402Client.ts L583-627; core/src/http/x402HTTPClient.ts L114-135 @ SHA |
| F-082 | Where a listing's machine-readable calling convention lives differs by type. HTTP: extensions.bazaar.info.input = {type:"http", method, queryParams:<example values>} (query variant) or {type:"http", method, bodyType, body:<example values>} (body variant), while the JSON Schema for those params sits at extensions.bazaar.schema.properties.input.properties.queryParams (resp. .body). MCP: extensions.bazaar.info.input = {type:"mcp", toolName, inputSchema:<the actual JSON Schema>, description?, transport?, example?} — schema inline, not in the outer schema object. |
VERIFIED | 2026-08-05 | extensions/src/bazaar/http/resourceService.ts L24-153; mcp/resourceService.ts L19-45 @ SHA |
| F-083 | x402ResourceServer.buildPaymentRequirements requires await resourceServer.initialize() first — it refuses kinds no facilitator has advertised, throwing "Facilitator does not support exact on stellar:testnet. Make sure to call initialize() …". The express middleware path hides this; a standalone createPaymentWrapper seller must call it explicitly, which also means the facilitator must be up before the seller boots. Hit live building demo/mcp-seller.ts. |
VERIFIED | 2026-08-05 | core/src/server/x402ResourceServer.ts L683-711 @ SHA; live boot failure + fix, S6-3 |
Adversarial audit — shipped-code security findings (gate hardening)
| ID | Claim | Status | Date | Source |
|---|---|---|---|---|
| F-087 | @x402/extensions validateDiscoveryExtension is ReDoS-exposed. It runs new Ajv({strict:false,allErrors:true}).compile(extension.schema) on the CLIENT's schema, compiling any pattern to a native RegExp with no safety policy, then validates the CLIENT's info. Measured against the installed @x402/extensions@2.20.0 dist: schema {pattern:"^(a+)+$"} + info "a"×n+"!" → n=28 2.3 s, n=30 9.2 s, n=32 36 s, ~4× per +2 chars; all payloads under 140 bytes = ~0.21 % of the 64 KiB indexer cap. Runs INLINE on the settle response path and Node is single-threaded, so it stalls concurrent requests after the transfer commits — falsifying "the byte cap bounds Ajv cost" (D-025). walras neutralizes it by stripping regex keywords + bounding node count before compile (D-033). |
VERIFIED | 2026-08-14 | dist read dist/cjs/bazaar/index.js L700-703; measured repro this session; D-033 |
| F-088 | The SDK's isValidRouteTemplate percent-decodes exactly once, so double-encoded traversal (%252e%252e), protocol-relative authorities (//host), and percent-encoded null bytes (%00) all return true. Measured against the installed dist. RFP task 3.B requires the facilitator to reject double-encoding, null bytes, and absolute/protocol-relative forms; delegating wholly to the SDK does not. walras adds hardenRouteTemplate (bounded repeated decode + null/backslash/protocol-relative rejection) ahead of the SDK check (D-033). |
VERIFIED | 2026-08-14 | dist read dist/cjs/bazaar/index.js L600-611; measured repro this session; D-033 |
| F-089 | The §7.1/§7.2 request envelope carries a top-level x402Version (integer) alongside paymentPayload and paymentRequirements; walras parses and echoes it (server.ts parseEnvelope, X402_VERSION = 2). The stock @x402/core facilitator client sends it and the reference facilitator requires it. |
VERIFIED | 2026-08-14 | specs/x402-specification-v2.md §7.1–7.2 @ SHA; packages/facilitator/src/server.ts; packages/facilitator/src/routeSchemas.ts |
Session 0 follow-up — the second baseline and the docs deployment (2026-08-14)
| ID | Claim | Status | Date | Source |
|---|---|---|---|---|
| F-090 | A second live Stellar x402 facilitator exists and its stellar:testnet kind is byte-identical to x402.org's. periplo-testnet.fly.dev (periplo-facilitator, repo github.com/Eras256/Periplo) serves /supported 200 with exactly one kind — {"x402Version":2,"scheme":"exact","network":"stellar:testnet","extra":{"areFeesSponsored":true}} — field-for-field identical to the x402.org Stellar kind (F-041, S0-2). F-041 is therefore confirmed on two independent operators. Differences: one advertised Stellar signer (GDXULEKC…FLE) vs x402.org's two; no stellar:pubnet kind on either. |
VERIFIED | 2026-08-14 | evidence §S0-7 (live capture 2026-08-14T15:48:42Z) |
| F-091 | periplo advertises extensions: ["bazaar"] and serves no discovery endpoint — the "advertised vs reachable" gap, live and in the direction that breaks clients. Both canonical bazaar endpoints 404 (/discovery/resources, F-025; /discovery/search, F-026), as do six near-miss spellings. Not a probe artifact: POST /verify on the same host returns 400 with {"isValid":false,"invalidReason":"invalid_request_shape",…}, so routing is live, and the facilitator's own service index lists only /health, /supported, /verify, /settle — it does not itself claim a discovery surface. Inverse of x402.org, which advertises no bazaar and serves none (F-042). Vindicates D-016 (advertise only what is reachable) with a live counterexample. |
VERIFIED | 2026-08-14 | evidence §S0-7; /supported + service index + 10 route probes, 2026-08-14 |
| F-092 | docs.walras.space is serving ce3d9ca while branch HEAD is c302fac — one commit stale. The deployed commit is read from the site's own footer stamp, the only deploy marker that exists (scripts/docs/build-site.mjs L33/L346 stamps git rev-parse --short HEAD at build time). ce3d9ca is a clean ancestor of c302fac (missed redeploy, not divergence); the undeployed delta is README.md + a 119-line rewrite of build-site.mjs, so the live site is rendered by the previous generation of its own builder. The site is deployed manually and out-of-band: the repository contains no deploy configuration and ci.yml has no pages or deploy job. |
VERIFIED | 2026-08-14 | evidence §Ops-1; curl https://docs.walras.space/; git merge-base --is-ancestor; scripts/check-site.sh |
Policywright integration — a real production tool, paid by an agent with zero prior integration (2026-08-14)
| ID | Claim | Status | Date | Source |
|---|---|---|---|---|
| F-093 | The stock @x402/mcp createPaymentWrapper IS the server-side payment gate for an MCP tool — no walras-authored gate is needed (Q-019 answered). Proven end to end with a REAL production tool: Policywright (SCF #44), whose pure synthesize capability (recordedTx → least-privilege OpenZeppelin smart-account spec; no I/O, no clock reads, deterministic) is served as a paid MCP tool behind walras, priced $0.05 testnet USDC, payTo a fresh Policywright-owned testnet account GCC5HEDS…BLTOM (Friendbot-funded, USDC trustline), facilitator = walras. The tool declares its calling convention and discovery metadata via stock declareDiscoveryExtension({toolName:"synthesize", inputSchema, …}) — the F-082 mcp shape (info.input = {type:"mcp", toolName, inputSchema} + outer schema), attached through stock createPaymentWrapper after resourceServer.initialize() (F-083). A generic MCP agent with zero prior integration searched (empty → pay-to-list, D-004), paid the tool by (url, toolName) — that settlement cataloged it — then re-discovered it and paid it again by minted id. Two settled stellar:testnet txs: 3ff7309b…bf04 (ledger 4140963) and 980c3c59…8cc4 (ledger 4140965), fee 22 973 stroops each = F-069; identical recordedTx ⇒ byte-identical synthesized spec. Provenance: the integration lives in the Policywright repo (branch walras-x402-integration, integrations/walras-x402); walras imports nothing from Policywright, and Policywright's MCP-server tranche (T2) remains not-started — this is one early, deliberately minimal tool, not that deliverable. |
VERIFIED | 2026-08-14 | evidence §S6-4; Horizon txs; demo/policywright-session.ts; policywright@walras-x402-integration |
| F-094 | The settle-gated ownership binding (D-024) holds on the MCP tuple, not only on HTTP URLs. Live poison-mcp attack: an attacker settles a real self-payment (structurally valid, on-chain) while echoing the Policywright tool's exact (resource.url, toolName) tuple with the attacker's own payTo and a well-formed mcp extension (passes schema validation, so the only possible rejection is the ownership check). Settlement succeeds on-chain; EXTENSION-RESPONSES reports bazaar.status:"rejected", code:bazaar_listing_owned_by_other_payee; the catalog entry is byte-identical and still owned by the Policywright payTo. The INVARIANT is preserved — indexing never throws and cannot change the settlement outcome. |
VERIFIED | 2026-08-14 | evidence §S6-4; demo/hostile-client.ts HOSTILE_MODE=poison-mcp; scripts/policywright-negative.sh |
Multi-submitter round-robin — the last D-012 half, observed live (2026-08-15)
| ID | Claim | Status | Date | Source |
|---|---|---|---|---|
| F-095 | Round-robin across multiple submitter seeds observed live. With SUBMITTER_SECRET set to two comma-separated seeds and FEE_BUMP_SECRET unset, ./scripts/demo.sh settled five payments on stellar:testnet whose Horizon source_account strictly alternates between the two submitters — SUB1 GDM7S4RB…BIXC, SUB2 GADH5EHI…RP22 — ledgers 4152764/66/68/70/72, every fee_charged 22 973 stroops (= F-069), fee_account = source_account on all five (no fee bump, as configured). Settle latency measured at the facilitator: 3.44–7.21 s, median 5.18 s, 5/5 settled. One demo-side fix recorded in §S7-2: demo.sh's preflight rejected the comma-separated form config.ts documents and parses; the facilitator itself needed zero changes. |
VERIFIED | 2026-08-15 | evidence §S7-2; Horizon txs cccd8d5a…131a 515174c5…b854 3cf99b6b…69cc eba8ab92…dae7 f98f360f…5048 |
Q-009 traced — contract-account (__check_auth) payers (2026-08-15)
| ID | Claim | Status | Date | Source |
|---|---|---|---|---|
| F-096 | A contract account (C-address with custom __check_auth) can be the payer in exact-stellar, and the walras facilitator path supports it as-built (Q-009 traced). The pinned spec's auth-entry-signing pattern "Supports both C-accounts and G-accounts" and mandates sorobanCredentialsAddress credentials — the exact Soroban type that routes C-address auth through __check_auth; it imposes no signature-format rule (the strings __check_auth/"nonce"/"ed25519" never appear). The installed @x402/stellar@2.20.0 verify/settle path is address-type-agnostic by inspection: credential TYPE is checked, address type never; "signed" = signature ScVal ≠ scvVoid; zero package-side cryptography — validity is delegated to enforcing-mode simulation of the client-signed tx (which executes __check_auth) plus on-chain submission; settle copies auth entries verbatim into a facilitator-sourced envelope the legacy credential preimage does not bind. Binding constraints: V1 address credentials only (CAP-71 V2/delegates rejected), no extra subInvocations, no facilitator address in any auth entry, exact balance-change footprint, expiration cap, SEP-41 only. The blocker is client-side payload creation: the package's client scheme never plumbs the SDK's {signatureScVal} smart-wallet hatch, so its Ed25519 branch throws on C-addresses — external tooling must build the payload. Caveat stated plainly: traced from source and docs (36/36 claims adversarially re-verified), not an executed C-payer round-trip. |
VERIFIED (source trace) | 2026-08-15 | evidence §S0-8; spec @ 17fc9890 (sha256 34438214…7975); @x402/stellar@2.20.0 dist; @stellar/stellar-sdk@16.2.0 base/auth.js; developers.stellar.org authorization + simulation docs |
Verification queue — status after Session 0
Gate G-FACTS: implementation does not start while any P0 row is OPEN.
| ID | Question | Status | Closed by |
|---|---|---|---|
| Q-001 | bazaar.md shapes, filters, search, MCP keying, soft-drop, routeTemplate | CLOSED | F-023 … F-032 |
| Q-002 | scheme_exact_stellar payload format + validation requirements | CLOSED | F-033 … F-039 |
| Q-003 | /supported response incl. extra.areFeesSponsored |
CLOSED | F-040 … F-043 (spec + live) |
| Q-004 | e2e suite location, stellar:testnet invocation, env vars | CLOSED | F-056 (docs); F-067 (local run, 4/4 pass against walras). |
| Q-005 | @x402/stellar facilitator surface; package vs wrapper validation split |
CLOSED | F-044 … F-047 |
| Q-006 | facilitator-side cataloging helpers in @x402/extensions |
CLOSED — expectation was wrong | F-048 … F-051 |
| Q-007 | Testnet USDC issuer + SAC contract ID, on-chain | CLOSED | F-052 (4 independent checks) |
| Q-008 | Actual settlement fee on testnet | CLOSED | F-054 (live measurement, 0.0023073 XLM) |
| Q-009 | Custom __check_auth account support (P1) |
CLOSED — traced (source analysis, not a live C-payer run) | F-096: spec supports C-account payers by design; the installed facilitator path is address-type-agnostic and needs zero changes (signature validity rides on enforcing-mode simulation, which executes __check_auth); the blocker is client-side payload creation (the package never plumbs the SDK's {signatureScVal} hatch). Constraints enumerated in evidence §S0-8. |
| Q-010 | Dependency license scan | CLOSED — PASS | F-060 |
| Q-011 | Live stock-client 402 → payment → settle transcript | CLOSED | F-066 (full transcript, settled tx, on-chain verification). |
| Q-012 | Pin toolchain + @x402/* versions |
CLOSED | F-058, F-059 |
| Q-013 | Wire header names/casing | CLOSED | F-057 (from SDK source, stronger than a transcript for casing) |
| Q-019 | How a SERVER-side MCP tool declares payment requirements + discovery metadata per spec @ SHA, and whether @x402/mcp (or any official package) provides server-side gating |
CLOSED — an official gate exists; no walras helper needed | F-080 (@x402/mcp createPaymentWrapper verifies → executes → settles server-side, withholding content on settle failure), F-082 (mcp discovery-metadata location), F-083 (initialize() ordering), and F-093 (the whole path proven live with a real external tool). The session-prompt fallback "if none exists, implement a walras gate" did not apply. |
Q-011 — closed in Session 2
The blocker resolved exactly as predicted: the buyer account was funded with 20 testnet
USDC via the captcha-gated Circle faucet (received 2026-08-02T09:23:00Z on-chain), and both
Q-011 and the Q-004 local run closed in the same session. The round-trip evidence is
S2-2/S2-3 (stock client, full transcript, settled tx ac50c091…cc155); the e2e
run is S2-4. One Session 0 fact did not survive contact with the live wire: the header
names in F-057 were the v1 branch — corrected by F-065 / D-018.
Update log
| Date | Change | By |
|---|---|---|
| 2026-07-31 | Initial population from RFP fact-check (web-verified) + verification queue | Kunal / Claude session |
| 2026-08-02 | Materialized into repo. Pinned spec SHA 17fc9890… written into header (G0.2). RFP captured verbatim to docs/rfp.md (G0.3). |
Claude session S0 |
| 2026-08-02 | Session 0 verification: added F-023 … F-061 from pinned spec, package source, live capture, and on-chain measurement. Closed Q-001 … Q-008, Q-010, Q-012, Q-013. Q-011 blocked on captcha-gated USDC faucet; Q-009 partial (P1). | Claude session S0 |
| 2026-08-02 | Session 1 build: monorepo scaffold + packages/facilitator. Added F-062 … F-064 from package source and the published artifact. Added DECISIONS D-016 (do not advertise bazaar before it is reachable) and D-017 (test against a Soroban RPC double; label its results as modelled). Evidence S1-1 … S1-5. Q-011 unchanged — still OPEN and still the only blocker on a live round-trip. |
Claude session S1 |
| 2026-08-02 | Session 2 conformance: buyer funded (Circle faucet) → Q-011 and Q-004 CLOSED. Stock @x402/fetch buyer paid a stock @x402/express seller through walras; tx ac50c091…cc155 verified on Horizon + stellar.expert. Repo e2e suite 4/4 against walras (express, hono × fetch, axios). Negative live tests (replay, amount mismatch, expired auth) each rejected with non-null reasons. Added F-065 … F-069; F-057 superseded (v1 headers). DECISIONS D-018 … D-021. Two upstream e2e-harness defects recorded (F-068). Evidence S2-1 … S2-6. |
Claude session S2 |
| 2026-08-02 | Session 3 discovery: packages/bazaar (SQLite/WAL store on node:sqlite, hostile-input indexer, wire mapping) + facilitator settle hook, EXTENSION-RESPONSES, and GET /discovery/resources (seven filters, D-005). /supported now advertises bazaar (D-016 satisfied). 132/132 tests incl. poisoning suite. Live: automatic cataloging + two hostile soft-drops proven on stellar:testnet (F-075). Added F-070 … F-075; DECISIONS D-022 … D-025. Evidence S3-1 … S3-4. |
Claude session S3 |
| 2026-08-03 | Session 4 search: gate G4.1 seeded the live catalog with 11 settle-gated listings (11 real settlements on stellar:testnet, S4-1). GET /discovery/search shipped spec-shaped (F-026 … F-028, F-077): query param, five filters, resources array, truthful partialResults, real keyset cursor pagination (D-003 honored; D-027). BASELINE retriever = FTS5/BM25 in node:sqlite (F-076, D-026) behind a Retriever seam. Eval harness pnpm eval:search: 28 labeled queries → recall@1 0.84, recall@3/5 0.93, MRR@10 0.91, nDCG@10 0.91 (S4-3). 157/157 tests. Live probes incl. hostile-syntax query and exactly-once cursor walk (S4-4). Added F-076, F-077; DECISIONS D-026, D-027. |
Claude session S4 |
| 2026-08-03 | Session 5 demo + final assembly: gate G5.1 PASS (S2–S4 evidence present; clean-clone install/build/test exit 0; eval numbers reproduced in the clone). scripts/demo.sh one-command demo proven live: fresh empty catalog → first settlement auto-lists (EXTENSION-RESPONSES success) → agent searches /discovery/search, pays top hit via stock client (tx f2857a0b…3914, fee 22 973 = F-069) → catalog lastUpdated bumped. Negative flags --tampered/--expired/--poison-catalog each rejected live with machine reasons (S5-3), consistent with F-064/S2-6/S3-4. G-LIC re-run PASS. README quickstart timed from a real fresh clone: ≈100 s machine time incl. five settlements (S5-5); self-validation clone → README → demo exit 0. No new protocol facts — the session composed only verified components. Evidence S5-1 … S5-5. |
Claude session S5 |
| 2026-08-05 | Docs session: gates GD.1–GD.4 PASS. Docs tooling license-checked pre-install (F-084); G-LIC rewritten two-tier (D-031) after mermaid's transitive tree surfaced three dev-only findings — shipped path stays zero-tolerance, PASS. R3 stop-condition fixed in code first: Fastify route schemas single-sourced (routeSchemas.ts, no-op compilers, wire behavior pinned by the suite), CONFIG_REFERENCE tables + drift-guard tests in both configs, SCHEMA_SQL exported; 213/213 tests. Generators shipped (pnpm docs:gen: OpenAPI 6 routes redocly-valid, config 8+4 vars, errors 64 codes/4 taxonomies, ERD 4 tables, 9 hash-marked SVGs) + pnpm docs:check gate (drift, OpenAPI, stale-SVG, links, claims audit) + CI workflow. Written: as-built ARCHITECTURE rewrite, MODELS, THREAT-MODEL, 7 diagrams, 3 role guides, quickstart, runbook, glossary, faq, SECURITY, CONTRIBUTING, litepaper (13 sections + LIMITATIONS) + ABSTRACT, 6 SCF snippets (docs/scf/*.md). docs:check PASS across 27 files; 10/10 spot-checked citations trace; post-refactor ./scripts/demo.sh re-run live: exit 0, agent tx b3fa66a2…7a054, fee 22 973 = F-069. Added F-084, F-085. Evidence §Docs. Git history rewritten on user request (Co-Authored-By trailers removed, all 16 commit dates byte-identical, force-pushed). |
Claude session Docs |
| 2026-08-05 | S7 fee-bump capture: the last "Not yet captured" row closed on user request — fee account created + funded, FEE_BUMP_SECRET set, ./scripts/demo.sh exit 0 with all five settlements through the fee-bump path; agent tx 7519b950…9875 Horizon-verified: fee_account ≠ source_account, fee 23 073 / max_fee 33 253 = the F-054 baseline anatomy byte-for-byte, delta over F-069 exactly the 100 stroops D-021 predicted. Added F-086; D-021 S7 follow-up; S7-1; stale "not yet captured" wording updated in ARCHITECTURE §5, runbook §4, operate.md §6, litepaper LIMITATIONS. Remaining unobserved: multi-submitter round-robin. |
Claude session Docs |
| 2026-08-05 | Session 6 MCP: gate G6.1 PASS (@x402/mcp@2.20.0 Apache-2.0, surface mapped from pinned source + installed artifact; MCP transport spec read at SHA; G-LIC re-run PASS with @modelcontextprotocol/sdk@1.30.0 MIT). packages/mcp-server shipped: search_resources + paid_call over stdio, dual-format deterministic results, facilitator error-enum passthrough (D-028), self-describing resource ids (D-029), double-enforced spend cap (D-030). 47 new tests (204 workspace total) — real MCP protocol over in-memory transports; chain seams doubled, labeled. Live S6-3: generic MCP client (zero walras imports) completed discover→pay using ONLY the two tools — paid an http listing by id (tx 79b541be…), paid a live MCP tool by (url, toolName) (tx d57ccaea…) whose settlement auto-cataloged it (F-029 tuple, closing the last "Not yet captured" row), re-discovered and re-paid it by minted id (tx 641f3e35…); all fees 22 973 stroops = F-069. Negative paths in-session: walras_mcp_unknown_resource_id, walras_invalid_search_cursor passthrough. Added F-078 … F-083; DECISIONS D-028 … D-030. Evidence S6-1 … S6-3. |
Claude session S6 |
| 2026-08-14 | Policywright integration (S6 acceptance case): Q-019 CLOSED — the stock @x402/mcp createPaymentWrapper is the server-side payment gate (F-080), so no walras gate was written. Policywright's pure synthesize capability (SCF #44) served as a paid MCP tool behind walras from the Policywright repo (branch walras-x402-integration), priced $0.05 testnet USDC to a fresh Policywright-owned payTo. A zero-integration MCP agent searched (empty → pay-to-list), paid by (url, toolName) — cataloging the tool — then re-discovered and re-paid it by minted id: two settled txs 3ff7309b…/980c3c59…, fee 22 973 = F-069, deterministic synthesis (F-093). Live poison-mcp negative path: attacker echoing the tool's tuple with its own payTo settles on-chain but is bazaar_listing_owned_by_other_payee, catalog untouched (F-094 — D-024 holds on the MCP tuple). walras-side additions are generic and reusable: scripts/testnet-usdc.mjs (DEX USDC funding, no captcha), demo/hostile-client.ts poison-mcp mode, demo/policywright-session.ts + scripts/policywright-demo.sh/policywright-negative.sh, scripts/gate-s6.sh. Added F-093, F-094; DECISIONS D-037. Evidence §S6-4. |
Claude session (Policywright integration) |
| 2026-08-14 | Adversarial-audit hardening (parallel review session's findings, all reproduced against the installed dist before acting): (1) ReDoS — the SDK's validateDiscoveryExtension compiles the client schema's pattern to native RegExp; a ~140-byte evil-pattern payload measured 36 s of synchronous compute on the inline settle path (F-087). Fixed: boundSchemaForValidation strips regex keywords + caps node count before Ajv; new bazaar_schema_too_complex code (D-033). (2) routeTemplate under-decode — the SDK decodes once, so %252e%252e / //host / %00 pass (F-088); added hardenRouteTemplate (bounded repeated decode + null/backslash/protocol-relative rejection) per RFP 3.B (D-033). (3) soft_drops audit table (RFP 3.A) + per-field drop logging. (4) same-owner update now merges, closing a same-owner metadata-blanking vector (D-033). (5) URL squatting made honest: attacker-FIRST regression test pins real behavior, THREAT-MODEL row 52 reframed, S3-4 scoped, D-032 records it as a disclosed limitation (grant-scope fix = proof-of-origin-control). Bazaar suite 64→76. Added F-087 … F-089; DECISIONS D-032, D-033. Hygiene: fee overclaims re-scoped to F-069 (single-submitter) vs F-086 (fee-bump) across README + 8 docs; real clone URL; .env.example DB_PATH; demo/ typechecked; gate scripts materialized. INVARIANT preserved: the indexer still never throws and cannot change a settlement outcome. |
Claude session (audit follow-up) |
| 2026-08-14 | Ledger-gap closure — two untracked gaps and one false claim, all recorded rather than quietly fixed. (1) Second baseline (S0 DoD), 12 days late: periplo-testnet.fly.dev captured live — stellar:testnet kind byte-identical to x402.org's, confirming F-041 on two independent operators (F-090); it advertises extensions:["bazaar"] yet 404s both canonical discovery endpoints and its own service index claims no discovery surface (F-091) — the RFP's "advertised vs reachable" caution observed in the wild, vindicating D-016. D-010 amended: no discovery baseline still, but now because the one operator claiming Bazaar does not implement it. The process failure — the gap was never tracked as outstanding — recorded as D-034, not backdated. (2) docs.walras.space: measured for the first time — deployed ce3d9ca vs HEAD c302fac, one commit stale, rendered by the previous generation of its own builder (F-092); scripts/check-site.sh + pnpm check:site now read the footer stamp back off the live site, deliberately outside CI (D-035). (3) Upstream findings: D-002, D-009, D-019, D-020 were marked UPSTREAM since 2026-08-02 but never filed — zero issues opened. Statuses changed to FOUND, NOT FILED (D-036); the litepaper's "queued upstream" and maintenance.md's "upstream divergences are reported" corrected, the latter having read as a track record for an empty backlog. Added F-090 … F-092; DECISIONS D-034 … D-036; S0-7, Ops-1; four "Not yet captured" rows added incl. multi-submitter round-robin. |
Claude session (ledger gaps) |
| 2026-08-15 | Round-robin capture: the last technical "Not yet captured" row closed — a second Friendbot-funded submitter added to SUBMITTER_SECRET (comma-separated), ./scripts/demo.sh exit 0 with five settlements whose Horizon source_account strictly alternates SUB1/SUB2/SUB1/SUB2/SUB1, all fees 22 973 = F-069, median settle 5.18 s, 5/5 settled. One demo-side fix: demo.sh preflight now validates each seed of the comma-separated form (it rejected the format config.ts documents; facilitator untouched). Added F-095; D-021 S7-2 follow-up; S7-2. Q-009 CLOSED by source trace (F-096, S0-8): C-account payers are spec-supported and the installed facilitator path needs zero changes — enforcing-mode simulation executes __check_auth; the blocker is client-side payload creation; 36/36 claims adversarially re-verified against cited lines; explicitly NOT a live C-payer run. Also added .github/workflows/live-settle.yml — a stock-client settlement on every push with Friendbot-created run-time accounts and DEX-bought USDC, so the repo holds no secrets and any fork reproduces the settlement — and clean URLs for docs.walras.space (build-site.mjs emits extensionless links + vercel.json cleanUrls; old .html deep links 308-redirect; takes effect on the next manual deploy, D-035). |
Claude session (leftovers) |