Releases: fardinvahdat/x402trace
Release list
v0.3.4
[0.3.4] — 2026-05-30
v0.3.4 cycle complete: four committed items shipped across L + K + G + I. bazaar-check grows from 5 checks to 8: host-pollution (L, #101), payment-payload echo gap rule pair with new upstream_stuck.cause discriminator (K, #102), facilitator-fitness per-rail probe with declared-identity-first attribution (G, #103), and the first top-level new verdict since v0.3.2 — service_unreachable with multi-probe consensus + per-cause windows + the first stateful event discriminant in x402trace (I, #104 + determinism fix #105). ADRs 005 / 006 / 007 / 008 record the architectural decisions. JSON API X402-44 contract preserved across all four additions — every shape change is strictly additive. Cohort: 4 named external contributors credited (@hypeprinter007-stack / Ferj 🙏, @RipperMercs 🙏, @TKCollective 🙏, @AsaiShota 🙏) plus 5 additional named voices behind the design refinements (@Cryptor, @TomSmart_ai, @Cinderwright, @evanatpizzarobot, @poteshniy).
Added (I — X402-52)
reachabilitycheck (X402-52, per ADR-006). 8th and final v0.3.4 diagnose-rule. Probes the service URL at the network layer (DNS / TCP / TLS / HTTP) with bounded timeout + bounded retry. Classifies failures into a 5-state axis:dns_failure | tcp_refused | tls_error | timeout | persistent_5xx. Voices: divigent probe (2026-05-23 DNS-fail real example) + @TomSmart_ai (mapper.db cohort + 2026-05-28 traceroute anti-evidence + per-cause-window endorsement 2026-05-29). @AsaiShota's test-echo-cdp as false-positive sentinel pattern (carried from K).- NEW top-level verdict
service_unreachable— first new top-level discriminator since v0.3.2'supstream_stuck. Exit 3 (same bucket as upstream_issue / upstream_stuck — exit-code contract per ADR-004 Pillar 2 preserved). Pre-empts all other verdict paths via the precedence ruleservice_unreachable > upstream_stuck.cause (K) > upstream_issue > facilitator_fitness facet (G) > host_pollution facet (L) > looks_correct— a DNS-failing service doesn't reach the surfaces those diagnose. Documented insrc/bazaar/diagnose-rules.md. bazaar.probe_attemptJSONL event discriminant (src/decoder/schema.md) — first stateful event added bybazaar-check. Records every reachability probe (success or fail) to enable cross-invocation multi-probe consensus.- First stateful verdict in x402trace —
service_unreachablerequires N consecutive matching probes within the per-cause window. Probe history is read from the JSONL log supplied via--probe-history-log <file>, current probe appended back. Preserves local-first stateless property: no external state directory; probe history lives in the same JSONL log operators already manage. - Per-cause consensus windows table (locked 2026-05-29 with @TomSmart_ai endorsement). DNS 5min / TCP 15min / TLS 30min / timeout 15min / persistent_5xx out-of-band. Operators scale uniformly via
--unreachable-interval-multiplier <n>. Per-cause individual flags deferred to v0.4+. persistent_5xxis intentionally out-of-band — server-malfunction signal, NOT unreachability. Classified via in-probe bounded retry (3 attempts × 500ms); rolls up to existingupstream_issue, NOTservice_unreachable. Per ADR-006 explicit design.- 3 new CLI flags on
bazaar-check:--probe-history-log <path>— JSONL log for cross-invocation probe history. Without it, single-probe-only mode (top-levelservice_unreachablenever fires).--unreachable-consensus-count <n>— consecutive matching probes required for top-level promotion (default 3).--unreachable-interval-multiplier <n>— uniform scalar over the per-cause windows table (default 1).
Clockabstraction (src/bazaar/clock.ts) — injectable for deterministic probe-history timestamps + window computations in tests. Production usesrealClock; tests usecreateMockClock().- Anti-pattern documented: "don't key verdicts on third-party single-snapshot status fields" — per @TomSmart_ai's 2026-05-28 traceroute analysis (13/15 mapper.db-labeled-unreachable endpoints were HTTP-reachable on re-probe; status field is stale by design). x402trace always uses its own multi-probe consensus.
Changed (I — X402-52)
bazaar-checkJSON output: results[] now contains 8 entries (was 7 after G). New 8th entry"reachability". No existing field renamed, removed, or reordered — X402-44 contract preserved.BazaarVerdictdiscriminated union now includes theservice_unreachablevariant alongsidelooks_correct | implementation_issue | upstream_issue | upstream_stuck. New required fields on theservice_unreachablevariant:unreachableCause,consensusThreshold,probeCount. Strictly additive — existing variants unchanged.verdict.tsUPSTREAM_CHECKS set extended to include"reachability"— info-status from I rolls to upstream signal when consensus not met. Verdict synthesizer checks reachability consensus FIRST and pre-empts the entire downstream verdict chain when fired.src/bazaar/json-api.mddocuments the new check + facet + verdict shape + the precedence rule.src/bazaar/diagnose-rules.mdreplaces the "pending implementation" placeholder with the full reachability spec.src/decoder/schema.mddocuments the newbazaar.probe_attemptevent discriminant.
Internal (I — X402-52)
src/bazaar/reachability.ts— new check module. Public surface:checkReachability,classifyFetchError. Single-probe + history-read + consensus-compute + facet emission + optional log append in one orchestration.src/bazaar/probe-history.ts— new module. Public surface:readProbeHistory,consensusReached,nextAttemptSeq,PER_CAUSE_INTERVAL_MS. Pure functions; no I/O beyondreadFileSyncon the JSONL log.src/bazaar/clock.ts— new module.Clockinterface,realClock,createMockClock.src/bazaar/types.ts—ReachabilityState,UnreachableCause,ReachabilityFacet,ProbeAttemptRecordtypes added.- Test count: G cycle shipped 598 → 646 passed + 4 skipped (650 total) in this I cycle. +48 from 37 new reachability/probe-history/clock unit tests + 11 integration assertions.
- Publish-surface cap raised 540 KB → 600 KB + file count 110 → 120 in
scripts/check-publish-surface.mjs. I added ~52 KB across 3 new source modules + their .d.ts companions in dist/.
JSON API (I — X402-52)
- Additive: new 8th check
"reachability"appended toresults[](was 7 in G cycle). New optionalreachability.detail.{state, unreachable_cause, probe_count, consensus_threshold, consensus_met, consensus_window_ms, diagnostic}shape. Newservice_unreachablevariant onBazaarVerdictdiscriminated union with required fieldsunreachableCause,consensusThreshold,probeCount. No existing field renamed, removed, reordered, or retyped. X402-44 contract preserved (additive change, minor-version-eligible per ADR-004 Pillar 2). Snapshot fixture regenerated.
Added (G — X402-51)
facilitator-fitnesscheck (X402-51, per ADR-005). New diagnose-rule that probes the merchant's declaredextensions.bazaar.facilitatoragainst a built-in registry (CDP, PayAI, x402.org/facilitator) and emits a per-rail fitness facet. Closes the v0.3.2 gap:indexing.indexer_state: not_applicable_non_cdpcorrectly avoided misattribution but offered no positive signal for non-CDP services. G fills the silence with a per-rail health probe. Voices: @Cryptor (CDP-only-by-design correction) + @TomSmart_ai (mapper-integration consumer) + @Cinderwright 3rd-touch (#1065 PayAI alternative). Canonical multi-rail fixture from Ferj/@hypeprinter007-stack's anchor-x402 (3 rails: Base USDC CDP + Solana USDC CDP + JPY Coin Polygon).src/bazaar/facilitator-registry.json— built-in registry of 3 facilitators (CDP, PayAI, x402.org/facilitator) with declared URLs, name aliases, probe endpoints. Per ADR-005 § Risks #1: registry is data, not code; new facilitators land as PRs adding entries. Operator override via--facilitator-registry <path>deferred to v0.4+.- New
facilitator_fitnessfacet onfacilitator-fitnesscheck — per-rail array ({ rail, network, facilitator, identity_source, fitness, diagnostic? }) + summary counts. Strictly additive per X402-44. Verdict synthesizer treats info-statusfacilitator-fitnessas upstream signal — any unreachable rail rolls up toupstream_issue(exit 3);degradedrails surface in facet without flipping the verdict. - Identity-source attribution — declared / inferred-from-tx / unknown. v0.3.4 MVP supports
declaredonly (read frommanifest.extensions.bazaar.facilitator); tx-from inference reserved as a v0.4+ slot. Per ADR-005: declared-identity-first is load-bearing for gasless rails (SKALE+PayAI per TKCollective's fixture offer) where buyer-side txfromis the gasless relayer, not the facilitator. - Bounded retry + backoff on
/verifyprobe — 3 attempts at 500ms / 1s / 2s per the @mkmkkkkk #1065 pattern. 4xx responses read asok(facilitator is responsive; probe-payload rejection is expected). Cached per facilitator URL for the duration of a singlebazaar-checkrun. anchor-x402-facilitator-fitness-ok-multi-rail.jsonnew fixture — Ferj/@hypeprinter007-stack's 3-rail capture adapted to G acceptance. Tests per-rail emission + summary aggregation across Base/Solana/Polygon when CDP is declared and the facilitator probe returns 2xx.
Changed (G — X402-51)
bazaar-checkJSON output: results[] now contains 7 entries (was 6 after L). New 7t...
v0.3.3
[0.3.3] — 2026-05-27
Fast-follow on v0.3.2. Documentation polish, a body-discovery remediation copy fix from a first-time contributor, a hybrid D.3+D.5 captured-response fixture from @TKCollective, paid-audits + funding-rail surface additions on README, and ADR-007 recording v0.3.4 K (payment-payload echo gap rule pair) ahead of implementation. No code-level behaviour changes to verdict outputs; the bazaar-check JSON API contract (X402-44) is preserved verbatim. Cohort: three external contributors credited (@TateLyman across two PRs + @TKCollective fixture).
Added
- AgentOracle captured-response fixture (hybrid D.3 + D.5) (#87, thanks @TKCollective 🙏). New
tests/fixtures/bazaar/captured-responses/agentoracle-upstream-stuck-body-discovery.json— operator-contributed live capture fromagentoracle.co/researchshowing the canonical 2026-05-09 → 2026-05-11 stuck-listing pattern:extensions.bazaarvalidates clean (BodyDiscoveryExtension variant, D.5 path), CDP discovery returns empty resources (D.3 indexer-stateprocessing), composite verdictupstream_stuck. Captured under the #2207 cluster as TKCollective's bucket-2/3 reference case. Fourth fixture under the v0.3.2 captured-responses harness (alongside the three hand-rolled D.x captures from X402-47); first operator-contributed live capture from the named v0.3.2 cohort. Picked up automatically bytests/integration/bazaar-check-captured-responses.test.ts— no harness changes. - ADR-007 drafted in DECISIONS.md — v0.3.4 K (payment-payload echo gap diagnose rules +
detail.upstream_stuck_causediscriminator). Records the design ahead of X402-50 implementation per ADR convention (same pattern as ADR-003 → X402-31 v0.3.0 and ADR-004 → X402-41 v0.3.2). ADR-005 (G facilitator-fitness, X402-51) + ADR-006 (Iservice_unreachable, X402-52) slots reserved for v0.3.4 implementation cycle. Two-voice promotion: @RipperMercs (TensorFeed canonical writeup, 1→29 indexed in <1hr) + @TKCollective (44-line patch, 16+d stuck → 22min indexed). @AsaiShota's contrast case (payload-correct, still stuck) baked into AC as false-positive sentinel. - Giveth project rail in
.github/FUNDING.yml+ README "Donate" section (#93). Giveth project page athttps://giveth.io/project/x402tracejoins the direct-wallet Basescan link as the second supported donation rail. Multichain support (Base, Ethereum, Optimism, Polygon) with optional GIVbacks rewards for donors. Donations through either rail land in the same wallet. Drips Network registration remains deferred per [[iran-residency-payment-rails]] constraints (platform-side ETH fee gate);FUNDING.jsonclaim file from v0.3.2 stays in place for whenever the fee is payable.
Fixed
bazaar-checkbody-discovery remediation copy alignment (#80, thanks @TateLyman 🙏 — first-time contributor). Remediation message in the body-discovery sub-check refactor referenced the legacy MCP-discovery field names; aligned the copy to the variant-aware shape introduced in v0.3.2 D.5 (X402-43). Surgical copy fix only — no verdict-logic change, no JSON API impact. Audit-pass-first-time pattern for an external contribution.
Documentation
- Bazaar contributor handbook in
CONTRIBUTING.md(#86, thanks @TateLyman 🙏 — second contribution within 27h of accepting his handbook offer). New section covering captured-response fixture conventions (tests/fixtures/bazaar/captured-responses/schema, self-describing JSON shape, automatic harness pickup), discovery-variant triage (BodyDiscoveryExtension vs McpDiscoveryExtension shape detection), and the no-payment-required testing discipline (fixture replay over live HTTP, deterministic verdicts in CI). Onboards the body-discovery + captured-response work shipped through v0.3.2 D.3/D.4/D.5/X402-47 for future external contributors. - Paid audits section in
README.md(#89). Maintainer-side review offering for teams shipping x402-paid services at scale — bazaar-readiness gap audits, multi-rail integration checks, supply-chain hygiene review. Hourly + flat-rate options; payment via direct wallet or x402 itself. Companion surface to the funding rails (Basescan + Giveth + FUNDING.json) — donations support open-source maintenance; paid audits are commercial work.
Internal
- Publish-surface cap raised 420 KB → 440 KB in
scripts/check-publish-surface.mjs. Necessary for v0.3.3 to pass CI (CI-measured tarball at 430,475 bytes exceeds the 430,080-byte cap by 395 bytes — locally 429,993 bytes due to a ~482-byte pnpm-pack discrepancy between macOS and the GitHub Actions Linux runner). Same step size as v0.3.2's 400 → 420 cycle. Gives ~20 KB headroom for v0.3.4's K/G/I diagnose-rule additions and their newdetail.*facets (upstream_stuck_cause,facilitator_fitness,reachability). .gitignoreforgraphify-output/artifacts (#90). Session-local knowledge-graph outputs from the/graphifyworkflow shouldn't ship in the repo or pack into the npm tarball. Clean separation from the publisheddist/surface.- Canonicalize donate wallet to
0xe922Cc1D44C69bDEc8581Cc9Fd28bab8f59478CC(#91). Updated all in-repo references (README, FUNDING.yml, FUNDING.json) to the single canonical maintainer EOA. Same address resolves on Base + Ethereum mainnet. FUNDING.jsonclaim file for Drips Network (#92). Drips protocol expects aFUNDING.jsonat repo root with claim-signature fields; file is ready for the Drips registration whenever the platform-side ETH fee is payable. Defers the actual on-chain registration but lands the spec-correct claim shape.
Changed
src/cli/index.tsVERSIONconstant bumped 0.3.2 → 0.3.3.CLAUDE.mdStatus line updated to reflect v0.3.2 SHIPPED to npm + external adoption evidence (@0xdespot, @poteshniy, @RipperMercs, @TKCollective publicnpx x402trace@0.3.2runs in the #2207 closure loop) + v0.3.4 scope pointer (X402-50/51/52 filed 2026-05-27) + deagentic.ai forward-direction reference.
Notes
- Test count: v0.3.2 shipped 511 passed + 4 skipped (515 total) → v0.3.3 runs 514 passed + 4 skipped (518 total), +3 tests from the captured-responses harness iterating over the new agentoracle fixture (top-level verdict assertion + per-check sub-verdict assertions). No new test files; the harness picks up the fixture automatically.
- Tarball size: v0.3.2's 102 files / 416,867 bytes (~407 KB) unpacked → v0.3.3: 102 files / 430,475 bytes (~420 KB) unpacked in CI / 429,993 bytes locally on macOS (+13–14 KB from the new captured-response fixture + CHANGELOG entry + DECISIONS.md ADR-007 + README/FUNDING additions). pnpm-pack output is reproducibly ~482 bytes larger in the GitHub Actions Linux runner than on macOS (line-ending or pack-order details — not in scope to fix). The CI measurement is the source of truth. Publish-surface cap raised in this release:
MAX_UNPACKED_BYTESinscripts/check-publish-surface.mjsbumped 420 KB → 440 KB — same step size as v0.3.2's 400 → 420 raise. v0.3.4's three diagnose-rule additions (K + G + I) and their newdetail.*facets (upstream_stuck_cause,facilitator_fitness,reachability) get ~20 KB of headroom. Revisit again in v0.3.4 alongside the deferred legacydetail.statusfield cleanup on indexing per ADR-004's follow-up. - Runtime
dependenciescount unchanged from v0.3.2 (4:commander,dotenv,viem,x402). No supply-chain expansion. Zero devDep imports fromdist/. - JSON API stability preserved. No additive or breaking changes to
bazaar-check --log jsonenvelope, facets, or verdict discriminator. Snapshot test passes against v0.3.2's frozen exemplar attests/fixtures/bazaar/json-api-snapshot.jsonwithout regeneration. TomSmart_ai's mapper-integration + @poteshniy'sagenttrust.uk/v1/reputationAPI (the named JSON API consumers per X402-44) require no changes. - No breaking changes. v0.3.2 → v0.3.3 is strictly additive (one new captured-response fixture + ADR-007 + docs + funding rail). v0.3.0/0.3.1/0.3.2 callers see identical behaviour.
- External adoption signals captured during the v0.3.2 → v0.3.3 window: @0xdespot ran
npx -y x402trace@0.3.2 bazaar-checkagainst hyperD 2026-05-23 (D.4--endpointmode, returnedupstream_stuckverdict on the variant-aware body-discovery path — exactly the AC for X402-42 + X402-43). @poteshniy (AgentTrust) shippedagenttrust.uk/v1/reputation2026-05-26 — a free public compliance API that consumes the x402trace v0.3.2 JSON shape directly, validating the X402-44 stability commitment externally. @TomSmart_ai's mapper-mcp parser audit on 2026-05-27 (anchored to a maintainer reference tosrc/decoder/parse.ts:113-125) re-classified 401 previously-failed v2 endpoints as valid, a measurable ecosystem-cleanup outcome attributable to the v0.3.2 + Discord exchange chain. Five operators in the #2207 closure loop: RipperMercs / TKCollective / AsaiShota / 0xdespot / poteshniy. - v0.3.4 scope locked 2026-05-27: three diagnose-rule additions filed during this fast-follow window — X402-50 K (payment-payload echo gap, ADR-007 in this relea...
v0.3.2
[0.3.2] — 2026-05-23
The metadata-propagation release. v0.3.0 + v0.3.1 answered "is my Bazaar / agentic.market integration shaped correctly?"; v0.3.2 sharpens the upstream-attribution side of the same question — "if my manifest looks right, why isn't my listing rendering?" — with four new verdict pathways, a per-route probe mode, variant-aware extension validation, a published JSON API contract, and end-to-end fixture infrastructure. Seven Jira tickets (X402-41 → X402-47) ran through the strict 6-stage audit gate; all merged to main 2026-05-21 → 2026-05-23. ADR-004 codifies the three pillars (verdict semantics + JSON API stability + facilitator-aware attribution). No breaking changes to v0.3.0/0.3.1 surface — --log json additions are strictly additive per the new versioning rule.
Added
- End-to-end fixture consumption for D.x verdict-synthesis paths (X402-47). New
tests/fixtures/bazaar/captured-responses/directory with three hand-rolled, self-describing fixtures — each capturing the well-known + challenge + discovery responses needed to exercise one v0.3.2 D.x failure mode throughrunBazaarCheckend-to-end without live HTTP. Initial set:d2-missing-propagation.json(manifest correct, indexer surfaces blank resource →metadata_propagation: missing→upstream_issue; the @zev / TheRoosters / GM pattern),d3-processing-stuck.json(facilitator settled but CDP discovery returns 0 resources →indexer_state: processing→upstream_stuck; Max's polyodds.bet pattern, canonical #2207),d5-body-discovery.json(extensions.bazaar uses BodyDiscoveryExtension shape — was false-positiveimplementation_issuepre-v0.3.2, now passes cleanly withlooks_correct; AsaiShota's test-echo-cdp + 0xdespot's hyperD pattern). Self-describing JSON schema ({scenario, input, mocks, expected}); new integration testtests/integration/bazaar-check-captured-responses.test.tsiterates over every fixture, builds a mock fetcher dispatching by URL pattern, runs the full pipeline, asserts verdict + per-checkdetailfacets match via dotted-path extraction. Adding a new fixture is one JSON file — the harness picks it up automatically. Scope cut vs original ticket: the original X402-47 AC called for consuming 6 named contributor fixtures (TomSmart cdp-mature, AsaiShota test-echo-cdp, evanatpizzarobot tensorfeed, 0xdespot hyperd, hypeprinter007 anchor-x402 multi-rail). Only TomSmart's first fixture is in the repo today; the other 5 are pre-committed but not delivered. This PR ships the fixture-consumption infrastructure with synthetic captures so the v0.3.2 audit gate has D.x coverage NOW; real contributor fixtures wire in as they arrive (TomSmart Sunday drop next). - D.3 indexer-state probe +
upstream_stuckcomposite verdict (X402-46, ADR-004 Pillar 1 + Pillar 3). The existingindexingcheck now emits adetail.indexer_statefacet with four values:indexed(≥1 resource in CDP discovery),processing(404 or empty resources — Max's polyodds.bet case + the canonical #2207 indexer-state-stuck cluster),unknown(HTTP error / non-JSON / network failure), andnot_applicable_non_cdp(operator declared a non-CDP facilitator in their well-known manifest; CDP discovery is not the canonical indexer for this service per ADR-004 Pillar 3). Whenindexer_state: processingfires the verdict synthesizer returns a new composite verdictupstream_stuck— distinct from genericupstream_issuebecause the root cause is known (facilitator settled, indexer queue stalled).upstream_stuckrolls up to exit code 3 (preserves CI contract per ADR-004); verdict prose + JSON facets carry the granularity. New sharedsrc/bazaar/facilitator-detect.tshelper — manifest-claim-based detection (extensions.bazaar.facilitatorvalue), used by both D.2 (propagation) and D.3 (indexing). When facilitator is non-CDP, both D.2 and D.3 short-circuit tonot_applicable_non_cdpBEFORE the network probe — fast, no HTTP cost, no false-positive. v0.3.3+ deferred:processing_freshvsprocessing_staledistinction (requires settle-timestamp data we don't collect without driving live settles; future work via operator-supplied evidence flag). - D.2 metadata propagation diff (X402-45). New 5th check in
bazaar-checkresults:propagation. Queries CDP discovery for the service'spayToand diffs the rendered fields (name,description) against what the operator declared in/.well-known/x402. Surfaces the @zev / TheRoosters / GM pain pattern: manifest is correctly shaped, indexer dropped fields, listing renders blank — your implementation is fine, the gating step is upstream. Emitsdetail.metadata_propagationwith one of four states:ok(all diffed fields match — status pass),partial(some drift — status info + diff array showing per-field mismatches),missing(indexer surfaces none of the manifest's declared fields, matching the canonical #2207 indexer-state cluster — status info),unknown(defensive default when no manifest is available via--endpointmode, nopayTois extractable, or the discovery query failed — status pass). New modulesrc/bazaar/propagation.ts; pure-functioncomputePropagationStatus()helper exported for downstream re-use. Diff scope intentionally narrow (name,description) — extends when new pain shapes surface. Facilitator-aware semantics layered separately: D.3 (X402-46) will add the explicitnot_applicable_non_cdpstate per ADR-004 Pillar 3; D.2 stays narrow and returnsunknownfor non-CDP services rather than asserting attribution it can't yet determine. bazaar-check --log jsonis now a documented public API contract (X402-44, ADR-004 Pillar 2). Three deliverables landed together: the contract doc atsrc/bazaar/json-api.md(envelope shape + per-checkdetailkeys + verdict discriminator + stability rules + regeneration workflow), a frozen exemplar attests/fixtures/bazaar/json-api-snapshot.json, and a snapshot test attests/integration/bazaar-check-json-api.test.ts(6 tests catch field renames, removals, additions, and reordering against the exemplar). Versioning rule committed: additive changes (new optional fields, new check names, newverdict.kindvalues, newdetail.*keys) ship in MINOR versions with a### JSON APICHANGELOG entry; shape-breaking changes (renames, removals, type changes, fixed-position reordering) require a MAJOR version + integrator notice. Exit-code contract preserved across all minor versions (D.3'supstream_stuckwill roll up to exit code 3, not a new code). README "JSON API" section added under thebazaar-checkdocumentation;CONTRIBUTING.md"JSON API discipline" section added with a PR self-check. TomSmart_ai's mapper-integration is the named consumer this contract is committed to.bazaar-check --endpoint <paid-url>per-route 402 probe mode (X402-42, D.4). For services that publish per-route instead of at root/.well-known/x402— the #2207 pattern documented by @AsaiShota (test-echo-cdp), @evanatpizzarobot (TensorFeed), and @0xdespot (hyperD.ai). When--endpointis supplied, the bazaar-check pipeline skips the root well-known probe entirely and fetches the 402 challenge directly from the given paid URL; manifest-shape validations run against the 402 body instead of the root manifest. Self-payment guard + CDP indexing query continue to run unchanged (they consume the challenge body'spayToregardless of how the challenge was obtained). UX: a one-line info note prints when--endpointis used (ℹ skipping root /.well-known/x402 probe per --endpoint. Note: services that DO publish at root signal extra discoverability hygiene; consider both.); routes to stdout in--log humanand stderr in--log jsonso stdout stays JSON-parseable. Newendpoint?: stringfield onBazaarCheckOptions(programmatic API); newendpoint?: stringfield onBazaarCheckCommandOptions. URL-validated at command entry; non-URL values exit 1 with a clear error.
Fixed
bazaar-checkfalse-positiveimplementation_issueon body-discovery services (#72 → X402-43, thanks @AsaiShota 🙏 for the diagnosis with@x402/extensions@2.11.0package-source citation, and @0xdespot 🙏 for the second-voice corroboration on x402-foundation/x402#2207). v0.3.0/0.3.1'ssrc/bazaar/challenge.tsandsrc/bazaar/well-known.tsboth validatedextensions.bazaarassuming the MCP-discovery shape (top-levelname+description). Real-world v2 services using the Body-discovery shape (info.input+info.output+schemaperdeclareDiscoveryExtension(...)) failed the envelope check despite being correctly implemented — verdict overrode the substantive indexing-probe signal. Newsrc/bazaar/extensions-bazaar.tshelper detects the variant by shape (body-discovery indicators win; else assume mcp-discovery per ADR-004) and validates the variant-appropriate required-field set. Default-deny third branch for future@x402/extensionsvariants we don't recognise yet — skips shape validation with an informational pass rather than false-positive. Tests cover ≥4 cases per affected file (challenge.ts + well-known.ts) plus 13 helper unit tests.
Changed
- **
indexingcheck'sdetail.statusfield gai...
v0.3.1
[0.3.1] — 2026-05-20
Hotfix release covering two bazaar-check bugs surfaced by external contributors within 72 hours of v0.3.0 ship, plus an npm-metadata fix from the v0.3.0 post-publish audit. No breaking changes — strictly additive.
Fixed
parseChallengeBodyfalse-fails on canonical x402 v2 challenge bodies (#65 → #66, thanks @hypeprinter007-stack 🙏 — first external contributor). v0.3.0'ssrc/decoder/parse.tsdetectedx402Versioncorrectly but enforced v1 field names regardless, so v2-compliant bodies using the renamedamountfield (instead of v1'smaxAmountRequired) and lacking the v1 per-acceptresourcefield failed withchallenge accepts[0].maxAmountRequired missing or wrong type. v2 bodies are now normalized at parse time (amount → maxAmountRequiredwhen onlyamountis present) and the per-acceptresourcerequirement is dropped under v2 (resource lives top-level in v2). Error messages under v2 include the hint(v2 field name: "amount")so operators don't have to spec-dive. Surfaced against the real v2 serviceapi.anchor-x402.com; e2e-verified to flipbazaar-checkexit code from2(false-fail) to0(looks_correct).bazaar-checkhung indefinitely on stalled HTTP probes (#67, thanks @peterxing 🙏). When a checked endpoint accepted the connection but never resolved — or sent headers but then stalled the body — the CLI hung until killed manually, breaking CI / automation use. Now wrapped with a 10s default per-probe timeout viaAbortController; configurable with--timeout-msfor CI / smoke runs / known-flaky endpoints. Body-read path keeps the timer active acrossarrayBuffer/blob/formData/json/textso headers-arrived-but-body-stalls is caught too. Upper bound validated against Node'ssetTimeoutcap (2_147_483_647).
Changed
package.jsondescriptionnow reflects the v0.3 headline subcommands (was v0.2-era:"x402 payment debugger for Base. Detects reconciliation failures, pre-flights wallets, explains 402s."). Closes the audit gap discovered post-v0.3.0 publish where the npm-displayed package description didn't mentionbazaar-check,validate --diff, or mainnet support. New audit-gate checklist item carried forward to v0.3.2+: "package.json description and README headline list both reflect this version's user-facing features."src/cli/index.tsVERSIONconstant bumped 0.3.0 → 0.3.1.
Removed
- Stale
--rpc-urlexample forbazaar-checkin the README.bazaar-checkis HTTP-only and doesn't need an RPC URL (it uses the CDP discovery API for the indexing query); the example was misleading.
Notes
- Adoption signal. Two distinct external contributors in 72 hours after v0.3.0 ship (@hypeprinter007-stack and @peterxing); both PRs merged within 12 hours of opening. Strongest "v0.3.0 found its audience" signal so far. Third independent positive signal in the same window: @TomSmart_ai (mapper operator) ran
bazaar-checkagainst 19 endpoints from his production catalog, 19/19 returnedimplementation_issue— first production-scale validation of the verdict taxonomy. - Pitch-language update. TomSmart_ai's framing — "catches the listing-readiness gap" vs "speaks x402 at all" (his strict-v2 sweep showed 88% protocol-valid on the same catalog) — is sharper than the prior README copy. Forward to v0.3.2+ surfaces.
- No breaking changes. v0.3.0 → v0.3.1 is backward-compatible. v1 challenge bodies parse unchanged. Callers that don't pass
--timeout-msget the new 10s default; callers that need the old "wait forever" behaviour can pass--timeout-ms 2147483647(Node's timer max, the documented upper bound). - Test count: 410 in v0.3.0 → 415 in v0.3.1 (+2 from #66 v2 parse coverage, +3 from #67 timeout coverage). All existing tests pass unchanged.
v0.3.0
[0.3.0] — 2026-05-17
The v0.3 release. Operator-side debugging cut: x402trace can now answer the question Discord operators are asking each other in real time — "is my Bazaar / agentic.market integration correct, or is the bug upstream of me?" — in a 30-second command-line check. Same shipped binary contract as v0.2.x (no breaking changes to existing subcommands); two new subcommands; five new facilitator-aware diagnose rules; Base mainnet support behind an opt-in --chain flag; cross-facilitator drift detection on validate. Strict 6-stage audit gate ran on every ticket (X402-31..36).
Added
x402trace bazaar-check <service-url>(X402-32, headline). Pre-ship Bazaar / agentic.market implementation validator. Four read-only checks compose into a single bottom-line verdict:/.well-known/x402manifest, 402 challenge structure (extensions.bazaar.{name, description}), self-payment guard (--payer-hint), and CDP indexing query (/v2/x402/discovery/resources). Exit codes:0looks_correct,2implementation_issue,3upstream_issue (the #2207 Bazaar-indexing pattern; named explicitly in the verdict prose). Maps the dominant Discord pain — ≥10 named voices on the #2207 cluster.x402trace validate --diff <facilitators>(X402-35). Cross-facilitator drift detection. Comma-separated aliases (cdp,xpay,payai,x402.org) OR full URLs. Runs the synthesised payload through each facilitator's/verifyendpoint in parallel viaPromise.all, captures per-facilitator HTTP into aFacilitatorInteraction, and runs the X402-33 facilitator-aware rules per-facilitator. Exit codes:0any_accepts,2all_reject,3all_timeout. Closes TerraDeed's CDP → xpay manual workaround (Discord transcript) and #2184 (PayAI + Python SDK 2.9.0).x402trace versions <service-url>(X402-36, stretch). SDK skew audit. Walks up from cwd forpackage.jsonand extracts@x402/*/x402-*/x402versions; fetches the service URL's 402 forx402Version+Serverheader hints; matches both against a bundled known-skew dataset (@x402/fetch@2.10.0extension echo bug,@x402/honosyncFacilitatorOnStartdefault, pre-v2 Python SDK bazaar emission). Exit0no skew /2skew detected. Closes Myceliaman14 + Poteshniy's Discord chases.- Five new facilitator-aware diagnose rules (X402-33).
cdpMinAmountRule,selfPaymentRule,facilitatorThrottlingRule,extensionResponsesMissingRule,gasEstimationFailureRule. Each backed by named Discord/GitHub voices per ADR-003. NewFacilitatorInteractiontype +DiagnosticContext.facilitator+DiagnosticContext.expectsBazaarExtensionsfields. Rules skip cleanly when their context fields are absent. - Base mainnet support (X402-34). New
--chain <base-sepolia|base>flag onproxy,inspect,validate,bazaar-check,versions. Default staysbase-sepolia(no surprise change).--chain baseswitches to Base mainnet (chain ID 8453) with the canonical mainnet USDC address (0x833589fCD…). Mainnet RPC URL must be supplied via--rpc-urlorBASE_RPC_URLenv; no default mainnet endpoint is shipped (CLAUDE.md hard rule #2). NewBASE_CHAIN_IDenv (accepts"base"/"base-sepolia"OR numeric"8453"/"84532", case-insensitive). Mainnet startup banner emits to stdout (human) or stderr (JSON). NewChainKeyexported type,BASE_USDCconstant,usdcAddressFor()helper. EXIT_UPSTREAM = 3exit code constant insrc/cli/exit-codes.ts. Distinguishes "upstream issue detected" (bazaar-check, validate --diff all-timeout) from "implementation issue" (EXIT_RUNTIME = 2) and "usage error" (EXIT_USAGE = 1).- ADR-003 in DECISIONS.md (X402-31). v0.3 feature pick + autonomous-mode strict 6-stage audit gate codification. The gate substitutes for user review during autonomous execution; every PR in v0.3 ran through Pre-work → Implementation → Correctness audit → Edge-case enumeration → Re-audit → Ship.
- CLAUDE.md hard rule #8 + "Strict audit gate" section. Codifies the gate so future sessions follow it.
- Cross-platform evidence base. Plan and ADR-003 cite Discord transcript (10+ named voices on Bazaar indexing failures), GitHub issues (#2207 cluster, #1065, #2294), Dev.to article, and agentic.market directory.
Changed
- CLAUDE.md hard rule #2 updated from "Testnet only until v0.1 ships" to "No committed mainnet RPC URLs" (v0.3 enables mainnet code; CI never uses mainnet).
src/cli/index.tsVERSIONconstant bumped 0.2.3 → 0.3.0 (kept in sync withpackage.json).
Deferred to v0.3.1+
- Paid-pass mode (
--with-wallet) inbazaar-check— requires signing infrastructure (changes ADR-001 read-only contract) or pre-signed payload pipeline. Static-analysis-only bazaar-check ships now; real-settlement EXTENSION-RESPONSES surfacing is detectable via X402-33'sextensionResponsesMissingRulefor callers that drive their own facilitator HTTP. - SLA-breach observation event (X402-37) — single Discord voice + schema-change risk failed the strict-bar; deferred until a 2nd named operator surfaces independently. Hikari is shipping Recourse as the enforcement product.
- ERC-6492 Smart Wallet support, reconciliation webhook/auto-retry,
extensions.diagnosticdecoder (gated on PR #1875),tokenNameMismatchRule,repeatedNonceRule, daemon mode, audit export, multi-chain (non-Base), hosted SaaS — all listed in ADR-003 with documented deferral reasons.
Fixed (X402-38 pre-publish audit, 2026-05-17)
validate --diff: AbortController signal was never passed to fetch — the timeout firedcontroller.abort()but the fetch call didn't receive the signal, so real-world timeouts would not actually cancel the request. Tests passed because the mock fetcher threwAbortErrordirectly. Fix:DiffFetchertype extended withsignal?: AbortSignal; signal now plumbed through. Two new regression tests assert the signal is received by the fetcher and reportsaborted=trueafter the timeout window.- Pre-existing flake at
tests/integration/demo-timeout-reconciliation.test.ts:114(50ms fixed sleep racing the engine event bus under parallel-test load). Hit CI twice in this session; would have intermittently broken the publish workflow'sprepublishOnlystep. Fix: replaced fixed sleep with apollForhelper that retries up to 2s in 25ms steps. 5/5 consecutive runs pass post-fix.
Notes
- 278 → 410 tests (+132 new across X402-31..36 + audit). The pre-existing flake noted above is now deterministic.
- Tarball size: 74 files / 222 KB unpacked at v0.2.3 → 96 files / ~337 KB unpacked at v0.3.0. Well under the 400 KB CI guard cap.
- Runtime
dependenciescount unchanged from v0.2.3 (4:commander,dotenv,viem,x402). No supply-chain expansion. - Audit findings documented but NOT fixed in v0.3.0 (all low severity, none block release):
cdpMinAmountRuleapplies the same minimum across chains; the $0.001 was Discord-confirmed for Sepolia only. Mainnet minimum may differ. Rule fails-soft (suggests a higher amount); documented inline in src/diagnose/rules.ts.validate --diffsilently overrides--strict. Documented in src/cli/validate-command.ts.parseFacilitatorListallows duplicate aliases (e.g.--diff cdp,cdp). Harmless but wasteful; documented.extractX402Versions(theversionssubcommand) accepts non-semver values (workspace:*,github:foo/bar).match: "any"known-skew entries can fire false-positives for monorepo users. Edge case; promote to a fix when a real user reports it.
v0.2.3
[0.2.3] — 2026-05-13
Supply-chain hardening patch. No functional changes from 0.2.2 — same CLI behaviour, same diagnostic rules, same chain client, same shipped binary (dist/). The bump exists to publish a cleaner install graph and to ship two community files that supply-chain scanners reward.
Changed
hono,x402-fetch,x402-honoreclassified fromdependenciestodevDependencies(X402-26). These three packages are imported only bysrc/dogfood/,scripts/, andtests/— paths excluded fromtsconfig.build.jsonand therefore from the publisheddist/. The shipped tarball is byte-for-byte equivalent to 0.2.2's; the only thing that changes is whatnpm i x402tracepulls into a consumer'snode_modules/. End-user install graph drops the entire WalletConnect / MetaMask SDK / safe-global transitive tree (the source of the 4 high + 10 medium CVE alerts on the Socket report for 0.2.2).src/cli/index.tsVERSIONconstant bumped 0.2.2 → 0.2.3 (kept in sync withpackage.json).
Added
CODE_OF_CONDUCT.md— Contributor Covenant v2.1 verbatim, contact pointed at the repo's private vulnerability reporting + maintainer email (X402-26).SECURITY.md— vulnerability reporting channels, response targets, scope, and an explicit "what x402trace does/doesn't do" section so reporters know what's in-bounds (X402-26).- README supply-chain FAQ — one new Q&A pair pre-empting "my scanner shows transitive alerts on x402trace deps" by naming the runtime tree (
commander+dotenv+viem+x402) and pointing wallet-SDK transitives to their actual source (X402-26). - CI publish-surface guard (X402-27) — new
scripts/check-publish-surface.mjsruns afterpnpm buildin CI + locally viapnpm check:publish-surface+ as part ofprepublishOnly. Caps the bundle at 100 files / 400 KB unpacked and forbids any file indist/from importing a package listed indevDependencies. Locks in the X402-26 fix so dep classification can't quietly drift back. - Dependabot config (X402-28) — weekly grouped npm updates (Mondays; dev-deps + production-patches bundled, semver-majors ignored) plus monthly ungrouped GitHub Actions updates. Gives us a weekly heads-up when an upstream ships a CVE patch instead of waiting for an external scanner.
- CLAUDE.md hard rule #8 (X402-29) — "The published bundle defines the runtime dependency set." Codifies the X402-26 lesson so future sessions don't recreate the misclassification.
Security
- Eliminates the wallet-SDK transitive tree (
@walletconnect/*,@metamask/sdk,@safe-global/*) from end-user installs ofx402trace. The CVE alerts those packages carry are still real — they're just no longer dragged intonode_modules/for a CLI that doesn't use them. Anyone running the dogfood rig or contributing locally still gets them viadevDependencies.
Notes
- The
dist/is byte-for-byte the same shape as 0.2.2: 74 files, ~222 KB unpacked. Verified locally + enforced by the publish-surface CI guard going forward. - Socket score recalibration takes a few hours after publish; Snyk a day. Predicted lift: Socket Supply Chain Security 77 → 90+, Snyk Health 27 → 35-45.
- Five tickets in the v0.2.3 batch: X402-26, X402-27, X402-28, X402-29, X402-30 (this release cut).
v0.2.2
[0.2.2] — 2026-05-13
Docs-only patch: ships the three animated GIF demos to the npm package page (npmjs.com only re-renders the README on publish). No functional changes from 0.2.1.
Changed
- README hero is now a live animated GIF — the X402-15 reconciliation demo, generated from the committed asciinema cast via
agg. Renders inline on github.com, npmjs.com, and any markdown viewer (256 KB, under X / Twitter's 15 MB cap). validateandexplainexample sections each now include their own demo GIF (27 KB + 36 KB) above the existing text-output blocks. Text blocks remain for AI-agent quoting andgrep-friendly inspection.- Three new committed asciinema source casts under
examples/cast/(e2e-timeout-reconciliation.cast,validate-demo.cast,explain-demo.cast) — replayable withasciinema play.
v0.2.1
[0.2.1] — 2026-05-13
Documentation + discoverability patch. No functional changes from 0.2.0 — same CLI behaviour, same diagnostic rules, same chain client. The bump exists so npm refreshes its search index with the new description + keywords (npm only re-indexes on publish).
Changed
package.jsondescription— was "Local CLI for debugging x402 payment flows on Base — catches timeout reconciliation failures"; now "x402 payment debugger for Base. Detects reconciliation failures, pre-flights wallets, explains 402s." Surfaces all three product capabilities in npm search instead of just reconciliation.package.jsonkeywords(9 → 14) — addedhttp-402,base-sepolia,payment-debugging,timeout-reconciliation,eip-3009,facilitator,coinbase-x402,agentic-payments; removed redundantdebugging/ vagueobservability/ misleadingethereum(Base is an L2).- README — added four discoverability blocks for human + AI-agent readers:
- "When to use x402trace" — 4 problem-statement bullets, each pattern-matching an AI agent's reasoning loop ("wallet debited but server says failed" →
proxy --reconcile, etc.) - "The four subcommands at a glance" — ASCII lifecycle visual keying
validate/proxy/inspect/explainto the BEFORE / DURING / POST / FAILURE phases of a payment - Concrete terminal output blocks for
validateandexplainso devs + AI agents can verify-before-install - Comparison table vs
xpay/x402scan/x402lint(replaces the previous prose paragraph) - 4-question FAQ in the Q&A pattern AI tool-cards quote into recommendation snippets
- "When to use x402trace" — 4 problem-statement bullets, each pattern-matching an AI agent's reasoning loop ("wallet debited but server says failed" →
VERSIONconstant insrc/cli/index.tsbumped 0.2.0 → 0.2.1 (kept in sync withpackage.json).
Notes
- The live tx hash
0x116ccf73…ba52is now above the fold in the README so crawlers / GEO snippets have a verifiable on-chain anchor. - Release workflow's
contents: writepermission (fixed for v0.1.0) means this tag-push self-creates the GitHub Release without manual intervention.
v0.2.0
[0.2.0] — 2026-05-12
The v0.2 pre/post-payment debugger. v0.1 owned mid-flight (proxy) + post-settlement (reconcile); v0.2 adds pre-flight (validate) and offline failure diagnosis (explain), sharing a new pure rule engine in src/diagnose/. Closes pain ranks #3 (generic 402 with no error reason) and #4 (wallet-state pre-flight gap) from the X402-6 ranking. 278 tests, same Base Sepolia / exact EVM scope as v0.1 per ADR-002. Apache-2.0.
Added
x402trace validate <wallet> <service-url>(X402-21) — read-only pre-flight before signing. Fetches the 402 challenge, queries on-chain USDC balance + EIP-3009 nonce status + wallet kind (EOA vs Smart Wallet viagetCode), synthesises a hypotheticalPaymentPayload, runs the diagnose engine, renders a plain-English report. Exits0forwould-succeed,2forwould-fail,0foruncertain(or2with--strict).x402trace explain <jsonl-log-file>(X402-21) — read a JSONL log produced byproxy --reconcile, find every exchange wherereconcile.result.kind != 'settled_on_chain'plus everydecoder.error, run the same rule engine against captured state, print per-failure prose with actionable fixes. CI-friendly: exits2if any failures rendered,0if log was clean.src/diagnose/(X402-21) — pure rule engine (no I/O, noDate.now). 10 rules covering network match, scheme match, recipient match, value sufficiency,validBefore/validAfterwindow, payer USDC balance, EIP-3009 nonce freshness, wallet kind (EOA + Smart Wallet; ERC-6492 deferred to v0.3 per ADR-002), and Base Sepolia USDC asset address. Each rule returnspass/fail/skip;skipmeans the context lacked the data (e.g.explaindoesn't have live wallet state). Top-level status iswould-succeed/would-fail/uncertain(the latter when the two critical chain-state rules are skipped).- Chain client extensions (X402-21) —
getUsdcBalance(wallet),isNonceConsumed(authorizer, nonce),detectWalletKind(wallet)read-only methods onChainClient, plus a narrowUSDC_READ_ABI(justbalanceOf+authorizationState). Used byvalidate; reusable by future v0.3 features. - v0.2 feature pick (X402-20) — ADR-002 records the decision + 4 rejected alternatives. SPEC.md § 5 flipped from "v0.2 stretch (deferred)" to "v0.2 scope" with a new v0.3 stretch list catching the deferrals. CLAUDE.md current-focus flipped to v0.2.
- CI release workflow
contents: writefix — release.yml'sCreate GitHub Releasestep had failed on the v0.1.0 cut with HTTP 403 because the job hadcontents: read. Promoted towriteso v0.2.0+ tag-pushes self-create the GitHub Release without manual intervention.
Tests
- 278 total (+63 from v0.1.0's 215). New: 36 unit tests for
diagnose-rules, 14 forvalidate-command, 9 forexplain-command, +4 forcli-dispatchercovering the new subcommands.
Notes
package.jsonbin layout unchanged from v0.1.0 —x402traceresolves to four subcommands (proxy,inspect,validate,explain).tsconfig.build.jsonis still the published-bundle config; tarball stays ~62 files / ~156 KB.
v0.1.0 — v0.1 wedge
[0.1.0] — 2026-05-12
The v0.1 wedge: a local proxy + timeout-reconciliation engine that catches the canonical coinbase/x402#1062 symptom — buyer is debited on-chain but the facilitator/server thinks the payment failed. Verified end-to-end on real Base Sepolia + the live x402.org/facilitator (tx 0x116ccf73…ba52). 215 tests, GitHub Actions CI on Node 20 + 22, Apache-2.0.
Added
- Initial project scaffold (X402-2)
CLAUDE.mdoperating manual for Claude Code sessionsTESTING.mddefining test requirements per change typeSPEC.md,ARCHITECTURE.md,DECISIONS.mdskeletonsCONTRIBUTING.md,dogfood-notes.mdskeletons.env.exampleconfiguration template.github/PULL_REQUEST_TEMPLATE.mdenforcing test checklist- Apache 2.0 license
- Dogfood rig on Base Sepolia (X402-3): Hono +
x402-hono@1.2.0server (src/dogfood/app.ts,api/[...all].tsfor Vercel,scripts/dev-server.tsfor local), paying client viax402-fetch@1.2.0(scripts/dogfood-client.ts), env validation with mainnet-RPC guard (src/dogfood/config.ts), and 20 unit tests covering config validation and 402 challenge generation. Verified end-to-end against the realx402.org/facilitatoron Base Sepolia — paid GET returned 200 with on-chain settlement tx0x8b53a04d…b3428. - Public Vercel production deploy (X402-3) on the
v1branch alias atx402trace-dogfood-git-v1-fardinvahdats-projects.vercel.appserving/(static landing) and/api/weather(x402-gated). Second on-chain settlement against the realx402.org/facilitatorfrom this production endpoint: tx0xc5758bf2…6cbf. - Five-failure-mode reproduction harness for X402-4 (
scripts/failure-modes.ts,pnpm dogfood:failure-modes <n>). Captures verbatim server/client/facilitator error strings for: wrong chain ID, expiredvalidBefore, insufficient USDC, malformed signature, facilitator unavailable. Full transcripts + diagnoses indogfood-notes.md§ Failure modes. - Week-1 pain synthesis (X402-6) in
dogfood-notes.md§ Top painful moments: 9 ranked pains + 5 wedge candidates (A reconciliation, B inspect+doctor, C bazaar-check, D cross-facilitator, E proxy substrate) — pulls from X402-3 dogfood capture, X402-4 failure modes, X402-5 GitHub catalogue, and the Notion Validation evidence page. CLAUDE.md updated to point future sessions at the table for feature-scope work. - v0.1 wedge accepted (X402-7) — ADR-001 in
DECISIONS.md: local HTTP proxy substrate + timeout-reconciliation engine on top. Scope tightened for the 5-week timeline: Base Sepolia only, single facilitator profile (x402.org/facilitator),exactEVM scheme only, detect-and-notify (no auto-refund in v0.1). CLAUDE.md status updated from "tentative" to "accepted." Bazaar diagnostics, cross-facilitator drift, inspect/doctor/versions deferred to v0.2+. - v0.1 implementation spec (X402-8) filled in at
SPEC.md: problem, solution, user flow (x402trace proxy --upstream <url> --reconcile+ sampleRECONCILED ⚠ settled-but-server-thinks-notoutput), v0.1 scope/v0.2 stretch lists, 5 success-criteria checkboxes, explicit out-of-scope non-goals, and per-competitor differentiation against xpay / x402scan / x402lint / x402-watch / zauth / PaySentry. Linked from CLAUDE.md. - v0.1 architecture (X402-9) finalized in
ARCHITECTURE.md: 5-component decomposition (Proxysrc/proxy/, Decodersrc/decoder/, Chainsrc/chain/, Reconciliationsrc/reconciliation/, CLIsrc/cli/) with one-example data flow traced through every component for happy / rejected / timeout outcomes; TypeScript interface stubs ready to become source code (PaymentRequirements, PaymentPayload, FacilitatorResponse, PaymentExchange, ExchangeOutcome, ChainTransfer, ReconciliationResult); canonical JSONL record format (the file is the API); full configuration precedence table; v0.2 extension points named per feature so no v0.1 component is rewritten for v0.2. - Proxy core (X402-10) in
src/proxy/: forward HTTP proxy that captures every exchange to a JSONL log + in-process event bus. Five modules —proxy.ts(server + forwarding via fetch),types.ts(ProxyEvent/CapturedRequest/CapturedResponse/ExchangeOutcomediscriminated union +isLikelyX402Exchangeheuristic),event-bus.ts(subscribe-with-queue-and-drop-counter pub-sub),jsonl-sink.ts(append-only writer),id.ts(per-exchange UUIDs). Hop-by-hop headers stripped per RFC; non-UTF8 bodies base64-encoded; upstream timeout returns 502 +proxy.errorevent. Deliberately dumb — no x402 parsing here (that's X402-11). 18 new unit tests + a 4-test integration that pipes the dogfood client through the proxy at the X402-3 dogfood rig (mock-facilitator-backed) and asserts both the 402 and the paid 200 are captured to JSONL with the right discriminants.pnpm proxy --upstream <url>runs it; fullnpx x402trace proxyplumbing arrives in X402-14. - x402 message decoder (X402-11) in
src/decoder/: pure-function parsers that turn rawProxyEvents into typedDecodedEvents. Six modules —types.ts(PaymentRequirements,PaymentAuthorization,PaymentPayload,FacilitatorResponse,DecodedEventdiscriminated union),parse.ts(parseChallengeBody,parsePaymentHeader,parseSettlementHeader, version detection — usesx402/schemes'sexact.evm.decodePaymentfor the v1 fast path, hand-rolled fallback for v2),redact.ts(signature redaction by default,--log-secretsopt-in),format.ts(formatHumanandformatJson),decoder.ts(createDecoder()stream consumer),index.ts. Includessrc/decoder/schema.mddocumenting the JSONL contract. Handles both v1 (X-PAYMENT/X-PAYMENT-RESPONSE) and v2 (PAYMENT-SIGNATURE/PAYMENT-RESPONSE) header surfaces. 22 new unit tests covering v1 + v2 parsers, redaction, formatting + a 4-test integration that asserts the proxy→decoder→PaymentExchange pipeline produces the right structured events from a paid flow. Stdout sample of the readable output is captured indogfood-notes.md§ "Decoder readable-output sample" per acceptance criterion;pnpm decoder:demoreproduces it. - Base RPC client (X402-12) in
src/chain/: thin viem wrapper over Base Sepolia. Five modules —types.ts(ChainTransfer+VerifyTransferResult7-variant discriminated union:confirmed/pending/reverted/not_found/wrong_recipient/wrong_amount/wrong_token),abi.ts(Base Sepolia USDC address0x036CbD…CF7e+ Transfer + EIP-3009 AuthorizationUsed event ABIs),retry.ts(exponential backoff, 3 attempts default per ARCHITECTURE.md),client.ts(createChainClientwithverifyTransfer,getTransferByTxHash,subscribeUsdcTransfersAsyncIterable,getBlockNumber),index.ts. Read-only — never holds private keys, never broadcasts.subscribeUsdcTransfersenriches eachTransferevent with the matchingAuthorizationUsed.noncefrom the same tx so the reconciliation engine can match by EIP-3009 nonce. 16 unit tests with mocked transport covering all 7 verify variants + the retry helper + 4 e2e tests against live Base Sepolia (gated byX402_E2E=1; verified against the two real X402-3 settlement txs0x8b53a04d…b3428and0xc5758bf2…6cbf). - GitHub Actions CI (X402-18) —
.github/workflows/ci.ymlrunspnpm typecheck,pnpm lint,pnpm test,pnpm buildon every PR + push tov1/staging/main. Node 20 + 22 matrix, pnpm-store cached viaactions/setup-node@v4, 10-min job timeout, in-progress runs cancelled when a fresher commit lands on the same ref.pnpm testauto-skipstests/e2e/chain-live.test.ts(gated onX402_E2E=1), so the live-Base-Sepolia suite never burns testnet funds in CI. Companion.github/workflows/release.ymlis the X402-19 substrate: tag-triggered (v*.*.*), runs the same quality bar, builds, and has the npm-publish step commented out until X402-19 wires theNPM_TOKENsecret. The CI badge inREADME.md(placeholder since X402-16) lights up on the first run. - Unit-test coverage hardening (X402-17) — Week-4 risk-reduction pass on the decoder, reconciliation, and CLI. Per the ticket spec ("chase risk reduction, not coverage targets"), targeted the gaps that break silently: (a) the streaming decoder's dispatch logic (
createDecoder().decode()) had zero direct tests — newtests/unit/decoder-decoder.test.ts(11 tests) covers settlement-header parse errors, theoutcome.rawPaymentResponseHeaderfallback path, andproxy.errorpassthrough; (b) base64 + unicode edge cases onparsePaymentHeader/parseChallengeBody/parseSettlementHeadermirroring the coinbase/x402#865 surface area — CJK + emoji indescriptionandextra.nameround-trip, padding-stripped base64 tolerated, JSON primitives rejected, URL-safe base64 contract documented; (c) reconciliationextractErrorReasonpaths (non-JSON rawBody, JSON withouterror, missing rawBody), theunknownproxy outcome branch the X402-15 demo relies on, chain-transfer race conditions (arrival before pending join, duplicate transfers after match); (d)x402trace proxyenv-var-vs-flag precedence — extractedresolveProxyConfig(opts, env)as a pure function fromproxy-command.ts(small refactor for testability), then pinned the contract from ARCHITECTURE.md § Configuration with 28 unit tests acrossX402TRACE_UPSTREAM, `X402TRACE_PORT...