Repository navigation
feat(dx): /v1 route versioning, snapshots, typed client SDK, and centralized config validation (20 issues) - #481
Conversation
…ralized config validation Closes Divinity-Labs#264, closes Divinity-Labs#228, closes Divinity-Labs#269, closes Divinity-Labs#270, closes Divinity-Labs#271, closes Divinity-Labs#274, closes Divinity-Labs#276, closes Divinity-Labs#277, closes Divinity-Labs#278, closes Divinity-Labs#279, closes Divinity-Labs#283, closes Divinity-Labs#209, closes Divinity-Labs#174, closes Divinity-Labs#299, closes Divinity-Labs#300, closes Divinity-Labs#338, closes Divinity-Labs#346, closes Divinity-Labs#362, closes Divinity-Labs#363, closes Divinity-Labs#371 - Version routes under canonical /v1 with backwards-compatible unversioned aliases (Divinity-Labs#264) - Add GET /venues/registry deriving dynamic venue statuses across networks (Divinity-Labs#228) - Standardize query and parameter validation with Zod schemas and formatZodError (Divinity-Labs#269) - Add concrete OpenAPI examples with ISO capture dates across all schemas (Divinity-Labs#270) - Document standardized ErrorResponse schema across all operations (Divinity-Labs#271) - Add 60-second quickstart in README for REST, GraphQL, and MCP with route validation (Divinity-Labs#274) - Generate typed TypeScript client SDK directly from openapi.yaml with CI generator (Divinity-Labs#276) - Add runnable TypeScript and Python snippets for each route group in docs/snippets.md (Divinity-Labs#277) - Introduce structured JSON logging with queryable fields and logging guide (Divinity-Labs#278) - Implement scripts/validate-live-spec.ts and docs/spec-compliance-report.md (Divinity-Labs#279) - Define liquidity as quote reserves sum and echo liquidity_unit in /screener (Divinity-Labs#283) - Isolate network predicate in /candles to prevent cross-network pooling (Divinity-Labs#209) - Add quote asset normalization, inversion, and honest 404 handling in /basket (Divinity-Labs#174) - Implement immutable GET /snapshot with cache headers and GET /snapshot/compare (Divinity-Labs#299, Divinity-Labs#300) - Consolidate process.env reads into Zod-validated config.ts with typed schema (Divinity-Labs#338) - Implement synthetic deployment smoke check in scripts/smoke-check.ts (Divinity-Labs#346) - Configure conditional GraphiQL toggle via ENABLE_GRAPHIQL (Divinity-Labs#362) - Enforce WebSocket GraphQL subscription auth and concurrent connection quota (Divinity-Labs#363) - Implement custom Decimal scalar in GraphQL schema preserving 18 decimals (Divinity-Labs#371)
Miracle656
left a comment
There was a problem hiding this comment.
Changes requested: one issue per PR, and only issues assigned to you
This is a process requirement, applied to all 23 of your open PRs in this repo. It is not a judgement about the code, which I have not been able to review — and that is the first half of the problem.
The bundling
Across your open PRs, 150 distinct issues are claimed. This one claims several. #483 claims 22, #481 claims 20, #477 claims 20, #474 claims 20.
A PR that closes twenty issues cannot be reviewed. Each of those issues has its own acceptance criteria — typically five — so twenty issues is a hundred separate things to verify in one diff, and if any one of them is wrong the whole PR is blocked while it is fixed. Every batch I published says the issues are deliberately independent so they can be worked in parallel, by different people, without colliding. Bundling them removes exactly that property.
The assignments
135 of the 150 issues claimed are assigned to other contributors — 67 different people.
This PR is an example: it names issues currently assigned to other contributors who are working on them now. Several have open PRs of their own. If this merged as it stands, those people would have done the work and received nothing for it, and I would have no way to tell the two efforts apart.
I am not assuming anything about why. Assignments change, Drips and GitHub can disagree, and a wide-ranging branch picks up issue numbers easily. But the effect on the people holding those assignments is the same regardless of intent, which is why I have to act on it.
What I need
- One issue per PR. The issue number in the title, its acceptance criteria met, and nothing else in the diff.
- Only issues assigned to you, or unassigned ones you have claimed through Drips. If an issue is assigned to someone else, it is theirs.
- Re-open the work that meets both conditions as individual PRs. I will review them in the order they arrive and at the same pace as everyone else's.
Nothing is being closed. These stay open and are yours to re-cut, withdraw or split as you choose.
Two things worth knowing before you re-cut
Some of this has already landed. #488 (SSRF guard for bazaar_search) and #487 (the paid_call host allow-list) cover the same ground as your #449; #486 covers the MCP README. Check current main before rebuilding something that is already there.
main has moved a long way today — #306, #309, #252, #256, #355, #381, #390, #402, #476, #488 and more. Cut from current main, not from where these branches started.
If you believe an issue named here is genuinely yours, say which and I will check the assignment myself — I would rather be corrected than have someone lose work.
Summary of Changes
This pull request addresses a comprehensive 20-issue cluster covering developer experience (DX), API versioning, platform reliability, GraphQL fixed-point precision, and centralized configuration hardening:
Route Versioning & Parity (There is no version in the URL #264):
/v1prefix for all HTTP API endpoints with unversioned backward-compatible aliases.DeprecationandSunsetheaders attached to unversioned requests.docs/versioning-policy.md.tests/openapi.test.ts.Venue Discovery Registry (Nothing tells an integrator which venues exist #228):
GET /venues/registry(and/v1/venues/registry) dynamically aggregating registered DEX venues, provenance kind, poll intervals, and network availability fromvenueAdapters.Standardized Zod Validation (Validation is hand-rolled on some routes and zod on others #269):
formatZodErrorformatter producing standardized{ error, code: 'INVALID_PARAMETERS', field, details }responses.Concrete OpenAPI Examples with ISO Capture Dates (The spec has no examples #270):
openapi.yamlandopenapi.jsonwith realistic examples and ISO timestamps.Documented Error Responses (Error responses are undocumented #271):
ErrorResponse,BadRequest,NotFound, andInternalErrorschema components referenced across all operations.Sixty-Second Quickstart & Route Validation Test (There is no sixty-second quickstart #274):
README.md.tests/quickstart.test.tsverifying that quickstart commands point to active registered routes.Typed Generated Client SDK (No generated client, so every integrator writes the same fetch wrapper #276):
scripts/generate-client.tsgeneratingsrc/sdk/client.tsdirectly fromopenapi.yaml."client:gen"and testtests/client.test.tsverifying zero-diff regeneration.Generated TypeScript & Python Code Snippets (Route code snippets exist in no language but curl #277):
scripts/generate-snippets.tsanddocs/snippets.mdproviding runnable integration code for every route group using real contract addresses."snippets:gen".Structured JSON Logging (Logs are not structured, so nothing can be queried #278):
src/logger/structured.tsemitting structured log entries with queryable fields (route,pair,network,venue,status,durationMs,requestId).docs/logging.mdwith query patterns.Live Service Spec Compliance Checker (Nothing checks the live service against its own spec #279):
scripts/validate-live-spec.tsanddocs/spec-compliance-report.mdvalidating live responses against schemas and appending run reports."spec:validate"and testtests/specValidation.test.ts.Explicit Liquidity Definition (
liquidityis a column with no definition #283):/screenerliquidity as the sum of quote asset reserves (reserveA * spotPrice + reserveB) and echoedliquidity_unit: 'quote'.Network Isolation for /candles (/candles/:assetA/:assetB aggregates testnet and mainnet price_points into the same candle #209):
network = $5predicate and echoednetworkin response.Quote Normalization & Inversion for /basket (
/basketaverages prices quoted in different currencies #174):/basketpricing in explicit quote asset (USDC), inverting prices when the asset is on the counter leg and returning honest 404 for unpriced assets.Immutable Point-in-Time Market Snapshot (There is no snapshot anyone can cite #299):
GET /snapshotwith single consistent timestamp,Cache-Control: public, max-age=60, and network scoping.Historical Snapshot Comparison (Historical snapshots cannot be compared #300):
GET /snapshot/comparecalculating delta values, percentage shifts, and gap detection (SNAPSHOT_GAP).Centralized Environment Validation (Fourteen files read process.env directly, and nothing validates it #338):
process.envreads into a single typedconfig.tsvalidated with Zod (envSchema).src/__tests__/envDrift.test.ts.Deployment Smoke Check (Nothing proves a deployed instance can actually answer #346):
scripts/smoke-check.tsperforming health check, price freshness verification, and WebSocket round-trip."smoke", documentation inREADME.md, and unit tests intests/smokeCheck.test.ts.Configurable GraphiQL Toggle (GraphiQL and introspection are served unconditionally #362):
ENABLE_GRAPHIQLenvironment toggle defaulting to disabled in production.WebSocket Subscription Auth & Quota (Subscriptions are free and unmetered #363):
GraphQL Decimal Fixed-Point Precision (Money is a Float throughout the GraphQL schema #371):
Decimalscalar preserving 18-decimal fixed-point precision as strings, avoiding IEEE 754 floating-point distortion.docs/graphql-decimal-migration.md.Verification & Testing
Closes #264, closes #228, closes #269, closes #270, closes #271, closes #274, closes #276, closes #277, closes #278, closes #279, closes #283, closes #209, closes #174, closes #299, closes #300, closes #338, closes #346, closes #362, closes #363, closes #371.