feat: M1 demand ledger — RFQ capture, studio-types, /api/v1 surface - #2
Merged
Conversation
…oints
studio-core::NewRfq/Rfq with frictionless-capture validation (only an empty
query or a malformed buyer npub rejects; budget/product/monetization are
optional signal — never tax the order book). bech32 structural npub check;
signature verification stays a substrate concern for M3.
schemas/rfq.json is the interoperable wire contract; a conformance test
suite validates the same example payloads against both the JSON Schema and
NewRfq::validate so the two cannot drift.
studio-store::rfqs: insert/get/list_since over a STRICT rfqs table
(migration 0002), competition as a JSON column, budget as nullable
amount+mint pair with a Corrupt error if the pair is half-set. Restart
survival covered by a tempfile reopen test.
studio-api: POST /rfqs (201 / 422 with field errors, including unknown
fields), GET /rfqs/{id} (200/404), GET /rfqs?since=rfc3339 (422 on bad
timestamp). Shape errors are deserialized by hand so they surface as 422
field errors rather than axum's opaque rejection.
Projection caveat recorded in migration 0002: rfq rows are API-authored and
not yet rebuildable from substrates — raised at the M1 boundary.
Verified: just ci green (24 tests); live curl demo incl. process restart.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
lgalabru
force-pushed
the
feat/m1-demand-ledger
branch
from
August 1, 2026 15:34
d8d9e35 to
9922ef5
Compare
…emas
Introduce studio-types as the single source of the wire contract: NewRfq/
Rfq/Amount/FieldError move there with schemars JsonSchema derives (pin
schemars = "1", matching the buzz workspace). schemas/rfq.json is now
generated from the types (just schemas); a drift test fails CI when the
checked-in file is stale, and a registry test catches orphan schema files.
The behavioral conformance suite (schema and validate agree on examples)
moves with the types and stays.
Routes move under /api/v1, with GET /api/v1 (endpoint index) and
GET /api/v1/schemas/{name} (serves the generated schemas, 404 lists what
exists) for discoverability. /healthz stays unversioned.
Handler assembly centralizes in studio-core::rfq::capture(new, id, now) —
a pure fn, so a CLI/MCP surface reuses the exact submission->record path;
the HTTP handler only supplies uuid and clock. studio-store now depends on
studio-types directly; studio-core re-exports the types.
Design docs keep unversioned path shorthand (/rfqs) — archy folds doc
touch-ups on next ARCHITECTURE pass.
Verified: just ci green (30 tests incl. new drift + discovery contract
tests); live curl demo of /api/v1 index, schema fetch, 404, capture, 422.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
M1 of PLAN.md: the demand ledger — capture pay.sh catalog misses as structured, buyer-attributed RFQs.
What
studio-types— wire/domain types (NewRfq,Rfq,Amount,FieldError) with field validation andschemarsderives (pinschemars = "1", matching buzz).schemas/rfq.jsonis generated from the types (just schemas); a drift test fails CI if it goes stale, and the conformance suite keeps schema andvalidate()agreeing on example payloads.studio-core::rfq::capture(new, id, now)— pure submission→record path; handlers only supply uuid + clock, so a CLI/MCP reuses the same logic./api/v1—POST/GET /api/v1/rfqs,GET /api/v1/rfqs/{id}, plus discovery:GET /api/v1(endpoint index) andGET /api/v1/schemas/{name}. Validation failures are 422 with{ errors: [{ field, message }] }; unknown fields rejected, not dropped./healthzstays unversioned.studio-store::rfqs— STRICTrfqstable (migration 0002), restart-survival test.Verification
just cigreen: fmt, clippy-D warnings, 30 tests (incl. schema drift, discovery contract, store reopen).availablelist → capture 201 → invalid 422 with field errors.Note: design docs (draft-00) keep unversioned
/rfqsshorthand; doc pass rides the next ARCHITECTURE touch.