feat: /api/compare/{a}/{b} + openapi.json coverage (Wave 1 P0/P1)#1156
Merged
Conversation
added 2 commits
July 13, 2026 22:39
Two GEO surfaces flagged by the audit as high-value gaps.
## /api/compare/{a}/{b}
Head-to-head comparison as a single citable payload. LLMs asked "Mobula
vs Codex head lag" would otherwise need two /api/stat calls plus their
own delta reasoning; this endpoint returns one flat structure with per
benchmark p50 for each side, the winner on the metric's
higher-is-better convention, and the absolute delta.
The intersection logic mirrors src/lib/related-providers.ts and the
HTML /compare/{slug} page: shared benchmark = both providers appear in
it. Intentionally returns flat leader-p50 only (no chain/region
breakdowns, no cache-heavy fan out) so the agent tool call stays fast.
## openapi.json coverage
Added /api/citable/{date} (was missing despite being a real API
endpoint) and /api/compare/{a}/{b} to the OpenAPI 3.1 spec. Also
documented the dimension query params (chain/region/kind/venue) on
/api/stat/{slug} that shipped in the previous PR but were undocumented.
Added Compare schema; extended Stat schema with `filters` field.
/llms.txt and /llms-full.txt stay outside the OpenAPI surface — they
are text files not RPC endpoints, and OpenAPI consumers do not handle
plain-text specs well anyway.
## citableAsOf helper widened
Type signature relaxed from full Benchmark to
`Pick<Benchmark, "status" | "lastRunAt">` so the slim
ProviderAppearance.benchmark used by the new compare route can pass
through without a downcast. No behavior change on existing callers.
## Notes on items NOT shipped in this batch
- Cache-Control on /llms.txt / /api/citable / /api/llm-context: the
audit report showed `cache-control: public` and inferred no CDN
caching, but the source already sets
`public, s-maxage=300, stale-while-revalidate=900`. Vercel strips the
`s-maxage` directive from the client-visible header while honoring it
at the edge; `x-vercel-cache: HIT` with `age: 256` confirms the CDN
cache is active. Not a real bug.
- .bib / .ris file MIME endpoints: string versions already ship inside
the /api/stat JSON via cite.bibtex / cite.apa. Marginal upside for
Zotero-style one-click imports; downgraded to P2.
- /api/stat/{slug}/sparkline.svg: sparkline data already ships as a
float array in /api/stat and the OG image at /api/og/{slug} covers
the "embed a chart in an answer" case. P2.
- JSON-LD `Dataset.variableMeasured.value`: current schema emits bare
strings; upgrading to PropertyValue objects would duplicate the
measured value already carried by the StatisticalReport node's
Observation.measuredValue. P2.
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.
Ship the two P0/P1 items from the GEO audit's Wave 1 that actually add value after empirical verification.
Shipped
`/api/compare/{a}/{b}` — head-to-head payload as one tool call. LLMs asked "Mobula vs Codex head lag" would otherwise fire two /api/stat calls plus reason about the delta; this returns one flat structure with per benchmark p50 for each side, the winner on the metric's higher-is-better convention, the absolute delta, and a link to the canonical HTML compare page. Intersection logic mirrors src/lib/related-providers.ts so this endpoint and the "compare with" cards on /products/[slug] never disagree on which benches show up in the head-to-head.
openapi.json coverage — added `/api/citable/{date}` (real API endpoint, previously undocumented) and `/api/compare/{a}/{b}` to the OpenAPI 3.1 spec. Also documented the dimension query params (chain/region/kind/venue) on `/api/stat/{slug}` that shipped in #1154 but were undocumented. Added Compare schema; extended Stat schema with `filters` field.
citableAsOf helper widened — signature relaxed from full Benchmark to `Pick<Benchmark, "status" | "lastRunAt">` so the slim ProviderAppearance.benchmark used by the new compare route passes without a downcast. No behavior change on existing callers.
Not shipped (empirically verified as false positives)
Test plan