feat(agent-readiness): RFC 9727 API catalog + native openapi.yaml serve#3343
Conversation
Closes #3309, part of epic #3306. - Serves the sebuf-bundled OpenAPI spec natively at https://www.worldmonitor.app/openapi.yaml with correct application/yaml content-type (no Mintlify proxy hop). Build-time copy from docs/api/worldmonitor.openapi.yaml. - Publishes RFC 9727 API catalog at /.well-known/api-catalog with service-desc pointing at the native URL, status rel pointing at /api/health, and a separate anchor for the MCP endpoint referencing its SEP-1649 card (#3311). Refs PR #3341 (sebuf v0.11.1 bundle landed).
The deploy-config guardrail hard-codes the SPA catch-all regex string and asserts its Cache-Control is no-cache. The prior commit added openapi.yaml to the exclusion list; this updates the test to match so the guardrail continues to protect HTML entry caching.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Greptile SummaryThis PR implements RFC 9727 API catalog discovery by serving Confidence Score: 5/5Safe to merge — all remaining findings are P2 style/DX suggestions that do not affect production behaviour. No P0 or P1 issues found. The two P2 comments cover: (1) the prebuild hook not firing for non-default build scripts (production Vercel uses npm run build, so no deployment impact), and (2) a more precise MIME type hint in the linkset JSON. Both are minor and non-blocking. No files require special attention for merging. Important Files Changed
Sequence DiagramsequenceDiagram
participant Scanner as Agent Scanner
participant Vercel as Vercel Edge
participant Public as public/ static files
participant DocsAPI as docs/api/ source
Note over DocsAPI,Public: npm run build (prebuild hook)
DocsAPI->>Public: "cp worldmonitor.openapi.yaml to public/openapi.yaml"
Scanner->>Vercel: "GET /.well-known/api-catalog"
Vercel->>Public: "serve api-catalog (extensionless JSON)"
Vercel-->>Scanner: "200 Content-Type: application/linkset+json"
Scanner->>Vercel: "GET /openapi.yaml (service-desc href)"
Vercel->>Public: "serve openapi.yaml (build artifact)"
Vercel-->>Scanner: "200 Content-Type: application/yaml"
Scanner->>Vercel: "GET /docs/documentation (service-doc href)"
Vercel-->>Scanner: "302 to Mintlify proxy"
Reviews (1): Last reviewed commit: "test(deploy-config): update SPA catch-al..." | Re-trigger Greptile |
- Extract openapi.yaml copy into named script `build:openapi` and prefix every web-variant build (build:full/tech/finance/happy/ commodity). prebuild delegates to the same script so the default `npm run build` path is unchanged. Swap shell `cp` for Node's cpSync for cross-platform safety. - Bump service-desc MIME type in /.well-known/api-catalog from application/yaml to application/vnd.oai.openapi (IANA-registered OpenAPI media type). Endpoint Content-Type stays application/yaml for browser/tool compatibility.
- status.href in /.well-known/api-catalog was pointing at https://api.worldmonitor.app/health (which serves the SPA HTML, not a health response). Corrected to /api/health, which returns the real {"status":"HEALTHY",...} JSON from api/health.js. - Extend tests/deploy-config.test.mjs with assertions that would have caught this regression: linkset structure, status/service- desc href shapes, and presence of build:openapi across every web-variant build script.
|
Round-2 review feedback addressed in e94af87 (plus one item from the previous commit): P1 — status href was pointing at the SPA, not the health endpoint P2 — P2 — guardrail test coverage
Confirmed the P1 assertion would have caught the regression: temporarily reverted the fix locally → red ( |
Summary
worldmonitor.openapi.yamlnatively from Vercel athttps://www.worldmonitor.app/openapi.yaml(build-time copy fromdocs/api/) — correctContent-Type: application/yaml, no Mintlify proxy hop./.well-known/api-catalog(RFC 9727 linkset) with:service-desc→/openapi.yaml(the sebuf-bundled 190-operation spec)service-doc→/docs/documentation(Mintlify landing)status→/api/health/mcpreferencing its SEP-1649 cardWhy native serve instead of the Mintlify-proxied URL
Today
worldmonitor.openapi.yamlserves via the/docs/:match*→ Mintlify rewrite, returningContent-Type: application/octet-stream, text/yaml(doubled). For a publicservice-desctarget referenced by agent scanners, we want a first-party URL with a clean content-type and no proxy dependency. The file is still committed indocs/api/(unchanged) for Mintlify docs consumption; we just also copy it topublic/at build time.Changes
.gitignore: add/public/openapi.yaml(build output, derived fromdocs/api/worldmonitor.openapi.yaml).package.json:prebuildhook copies the bundle intopublic/before anynpm run buildinvocation.vercel.json:openapi.yamlfrom the SPA catch-all rewrite (two occurrences:rewrites+ no-cacheheaders).Content-Type: application/yaml; charset=utf-8on/openapi.yaml.Content-Type: application/linkset+jsonon/.well-known/api-catalog(required by RFC 9727; the generic/.well-known/(.*)catch-all sets CORS + cache but not Content-Type).public/.well-known/api-catalog: new linkset JSON (extensionless per RFC 9727).tests/deploy-config.test.mjs: update the hard-coded SPA catch-all regex assertion to match the new exclusion list — guardrail still validates HTML entry caching.Test plan
curl -sI <preview>/openapi.yamlreturns200,Content-Type: application/yaml; charset=utf-8.curl -s <preview>/openapi.yaml | head -3shows valid OpenAPI YAML (openapi: 3.1.0...).curl -sI <preview>/.well-known/api-catalogreturns200,Content-Type: application/linkset+json.curl -s <preview>/.well-known/api-catalog | jq .valid JSON, matches RFC 9264 linkset shape.https://worldmonitor.appandhttps://www.worldmonitor.app.Refs PR #3341 (sebuf v0.11.1 bundle landed), epic #3306.