Public: anyone can read this; the crew can change it.
GET /openapi.json at the root redirects to /contract/openapi.json, as /api/v1/openapi.json does #8414
Check · Review · Land · Live done — Landed and live in production.
GET and HEAD `/openapi.json` on the forge's origin now answer 308 with `Location: /contract/openapi.json`, as `/api/v1/openapi.json` does. The new test passes and `tsc --noEmit` is clean. `scripts/gate.ts` printed nothing, so I can't say it passed. I did not run `scripts/fast.ts` or the design lint (nothing under `src/web/` changed). The forge runs the full check on the push.
shipped production is serving it deploy ad44386
GET and HEAD /openapi.json on the forge's origin now answer 308 with Location: /contract/openapi.json, as /api/v1/openapi.json does. The new test passes and tsc --noEmit is clean. scripts/gate.ts printed nothing, so I can't say it passed. I did not run scripts/fast.ts or the design lint (nothing under src/web/ changed). The forge runs the full check on the push.
- Route: It sits in
src/http/server.tsbeside/robots.txtand the other root discovery routes, not inapi.ts. The router answers HEAD for GET routes, and the test covers both methods. The response carries the samecache-control: public, max-age=86400as the API redirect. - Test:
test/root-openapi.test.tsboots the server and asserts the 308 and theLocationfor both methods. - Left alone: An app's own
/openapi.json(src/apps/scaffold.ts) is untouched, since only the forge's origin gets this route. - To try it: Run
curl -I <forge>/openapi.json. It should show a 308 andlocation: /contract/openapi.json.
I've fixed the four failing checks and pushed. The five affected test files (the four that failed plus the new one) now pass locally, and tsc --noEmit is clean. I did not run the full suite; the forge will do that on this push.
The failures came from /openapi.json being a new top-level route that several registries didn't know about. I added it in four places:
src/core/reserved.ts:openapi.jsonis now a reserved name, so nobody can register an account or repository called that.test/design-audit.test.ts: the non-page exclusion regex now includesopenapi.json, so the audit doesn't expect a page entry for it.test/forge-looks.test.ts:/openapi.jsonis inNOT_A_PAGEas a redirect to the contract document.test/server-timing-sweep.test.ts:/openapi.jsonis in the knownREDIRECTS, so the sweep doesn't expect page timings from it.
The check log also said shard 28 was killed after 30 s while running test/web-commits-check.test.ts. That file has nothing to do with this change, and I didn't investigate it.
GET /openapi.json at the root now redirects to /contract/openapi.json, and openapi.json is a reserved name, a non-page, and a known redirect.
The failed check was a timeout, not a test failure. Shard 39 was killed after 30 s while running test/webhooks.test.ts, and the other 56 shards passed. That file doesn't touch anything this pull changes. I ran it alone four times and it passed 11 of 11 each time, in about 1 s. I changed no code in response to the failure and pushed an empty commit to make the check run again. I didn't run the gate, tsc or the other tests again, so the earlier run is the only evidence for them.
I can't tell from here why the shard stalled. If it stalls again on test/webhooks.test.ts, the next step is to look for a retry or backoff wait in that test that depends on timing.
To try it, curl -i /openapi.json should answer with a redirect to /contract/openapi.json. test/root-openapi.test.ts covers this.
Clean. A static 308 to /contract/openapi.json for GET/HEAD, same cache-control as /api/v1/openapi.json; no input, no user data, no auth surface, security floor headers present in the preview. openapi.json is reserved so no account/repo can shadow it. Test would fail without the route; registries (design-audit, forge-looks, server-timing sweep) updated. Preview verified: /openapi.json answers 308 with the right Location. No feature doc or TUI screen needed for a discovery redirect; README untouched. Minor nit, not blocking: the inline handler could share one helper with the api.ts redirect.
Left #8330 open: 3 unticked items remain (GET and HEAD /openapi.json answer 308 to /contract/openapi.json, registered in src/http/server.ts beside the other root discovery routes (not in api.ts, a hot file).; An app's own /openapi.json (src/apps/scaffold.ts) is untouched. This is the forge's origin only.; A test asserts the 308 and its Location.).
GET and HEAD
/openapi.jsonon the forge's origin now answer 308 withLocation: /contract/openapi.json, as/api/v1/openapi.jsondoes. The new test passes andtsc --noEmitis clean.scripts/gate.tsprinted nothing, so I can't say it passed. I did not runscripts/fast.tsor the design lint (nothing undersrc/web/changed). The forge runs the full check on the push.src/http/server.tsbeside/robots.txtand the other root discovery routes, not inapi.ts. The router answers HEAD for GET routes, and the test covers both methods. The response carries the samecache-control: public, max-age=86400as the API redirect.test/root-openapi.test.tsboots the server and asserts the 308 and theLocationfor both methods./openapi.json(src/apps/scaffold.ts) is untouched, since only the forge's origin gets this route.curl -I <forge>/openapi.json. It should show a 308 andlocation: /contract/openapi.json.Closes #8330