Skip to content

Bazaar: seller-side discovery metadata helpers (and list Lens's own endpoints) - #154

Open
DevTobis wants to merge 1 commit into
Miracle656:mainfrom
DevTobis:feat/bazaar-seller-helpers
Open

Bazaar: seller-side discovery metadata helpers (and list Lens's own endpoints)#154
DevTobis wants to merge 1 commit into
Miracle656:mainfrom
DevTobis:feat/bazaar-seller-helpers

Conversation

@DevTobis

Copy link
Copy Markdown

closes #134

Summary

Seller-side helpers for declaring Bazaar discovery metadata, plus Lens's own gated routes declared with them.

The design decision that matters

The issue's core point is that per-parameter descriptions must be first-class, not an afterthought. I made that structural rather than aspirational:

  • description is the first positional argument of every param.* constructor. You cannot forget it by accident — the signature is the enforcement.
  • A parameter with no description, or one under 12 characters, fails validation. Not a warning, not a lint you can suppress. Since ranking in Bazaar: GET /discovery/search with real ranking and a quality evaluation #129 can only rank on what is declared, a listing with assetA: string and no prose caps search quality for everyone in the catalog, not just for its own seller.

What's here

src/bazaar/declare.ts

  • param.string / number / integer / boolean / enumOf, each taking description first and optional required (default true), example and default. An example is worth more to an agent than another sentence of prose, so it is a first-class option.
  • declareHttpResource and declareMcpTool — assemble the resource block, accepts, and the extensions.bazaar declaration with proper JSON Schema (additionalProperties: false, a required list built from the flags). The HTTP builder picks queryParams vs body + bodyType from the method, so you never have to remember which slot a POST uses. The CAIP-2 network on accepts is filled from the listing's network unless you set it explicitly.
  • validateDeclaration / assertDeclaration.

src/bazaar/lensListings.ts — the dogfood. /price/:assetA/:assetB, /candles/:assetA/:assetB, /pools, /price/twap/:assetA/:assetB (the routes src/middleware/x402.ts actually gates), plus the MCP face of the price feed. Each goes through assertDeclaration at module load.

docs/x402/bazaar-seller-guide.md, 23 tests, and a changeset.

Validation reuses the catalog's own validator

validateDeclaration calls validateListing from src/bazaar/validation.ts under the hood rather than reimplementing it. That matters: local and remote cannot drift apart, and the problems come back in the catalog's own { field, code, message } shape — a seller sees the same field path and code locally that the catalog would have soft-dropped them with. Then it adds the rules the catalog cannot enforce, because by the time a listing reaches the catalog the metadata is all it has:

Code Catches
missing_param_description A parameter with no description
param_description_too_short Under 12 chars — name the accepted values, not the field
weak_resource_description The description an agent ranks on is missing or too thin
undeclared_route_param routeTemplate names a :param absent from pathParams — an agent knows the URL shape but not what goes in the slot
missing_accepts No payment requirement, so not discoverable as a paid endpoint

assertDeclaration is the throwing form, listing every problem with its field path. Called at module load, a malformed listing fails the boot rather than quietly never appearing in the Bazaar — which is the failure mode worth designing against, because nothing tells you it happened.

Acceptance criteria

  • A resource server can declare a discoverable, priced endpoint in a few lines/pools is 7 lines; /price with two described path params is 15.
  • Per-parameter descriptions are first-class — first positional arg, and a hard validation failure when absent.
  • Local validation catches malformed metadata before it is sentvalidateDeclaration / assertDeclaration, reusing validateListing.
  • Both HTTP and MCP resource types supporteddeclareHttpResource, declareMcpTool.
  • Lens's own gated routes are declared using itsrc/bazaar/lensListings.ts.
  • …and appear in the catalog — see below.

On "appear in the catalog", and on the timing question

Two places where I want to be straight rather than tick a box.

The listings are built and validated, but nothing registers them yet. Automatic cataloging from the discovery extension is #130, and the registration path it will use (registerBazaarResource, and emitting the extension on the 402 payment path) is that issue's surface. I did not want to half-build #130 inside #134 and leave two partial implementations to reconcile — lensListings() is a pure function returning validated RegisterBazaarResourceInput[], which is exactly the input #130 needs, so it should be a short step. Say if you would rather I wire it here instead.

"Say in the PR how long it actually took someone who had not seen it before." I can't honestly answer that — I built the helpers, so I am the worst possible measurement. What I can report: declaring the four Lens routes against the finished API took a few minutes each, and the helpers caught two real mistakes in my own dogfooding that would otherwise have shipped — a routeTemplate naming :assetB before I had declared it, and a first-draft /pools description too thin to rank on. That is the mechanism working, but it is not the user study the criterion asks for. Worth handing to someone who hasn't seen it and recording the real number.

Verification

  • npx vitest run src/__tests__/bazaarDeclare.test.ts23 passed
  • Full suite: 324 passed, 1 skipped, 38 of 40 files green
  • npx tsc --noEmit — no errors from any file in this change

One pre-existing failure, not from this change: tests/mcp.test.ts fails with Cannot find package '@modelcontextprotocol/sdk/server/index.js', and src/mcp/server.ts produces 4 typecheck errors for the same reason. The package is declared in package.json but is not present in node_modules. I confirmed it by stashing this branch and re-running on clean main — identical failure. Left alone deliberately rather than bundling an unrelated dependency fix into this PR.

The buyer is software. An agent choosing between two price feeds cannot
open your docs - it has only what the listing declares, and ranking (Miracle656#129)
can only rank on what is declared. So description is the first positional
argument of every param constructor, and a declaration missing one does
not validate. It is not a warning you can ship past.

src/bazaar/declare.ts:
- param.string/number/integer/boolean/enumOf, with example and default,
  emitting JSON Schema fragments
- declareHttpResource and declareMcpTool, assembling the resource block,
  accepts (CAIP-2 network filled from the listing network) and the
  extensions.bazaar declaration, picking queryParams vs body/bodyType from
  the HTTP method
- validateDeclaration, which runs the catalog's own validateListing so
  local and remote cannot drift, then adds the seller-side rules the
  catalog cannot enforce: missing or too-short parameter descriptions, a
  weak resource description, a routeTemplate naming an undeclared param,
  and a listing with no price
- assertDeclaration, the throwing form, so a bad listing fails the boot
  instead of silently never appearing in the Bazaar

src/bazaar/lensListings.ts declares the routes middleware/x402.ts already
gates - /price, /candles, /pools, /price/twap - plus the MCP face of the
price feed, each through assertDeclaration at module load.

23 tests in src/__tests__/bazaarDeclare.test.ts, and a walkthrough in
docs/x402/bazaar-seller-guide.md.
@drips-wave

drips-wave Bot commented Aug 31, 2026

Copy link
Copy Markdown

@DevTobis Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bazaar: seller-side discovery metadata helpers (and list Lens's own endpoints)

1 participant