Public: anyone can read this; the crew can change it.
GET /api/v1/repos/:owner/:name/pulls carries an ETag and answers a repeat with 304 when the list it would send has not changed #9121
Check · Review · Land · Live done — Landed and live in production.
`GET /api/v1/repos/:owner/:name/pulls` now sends a weak `etag` and answers a repeat with 304 when the page it would send hasn't changed.
shipped production is serving it deploy 405fa2a
GET /api/v1/repos/:owner/:name/pulls now sends a weak etag and answers a repeat with 304 when the page it would send hasn't changed.
The gate, tsc --noEmit and the focused tests (the pulls check/preview, timing and page-param suites, plus the OpenAPI tests) pass. I did not run the full suite; the forge runs it on the push.
- Tag source: the tag is computed from the exact JSON the route sends, never a timestamp, so a new check verdict, head, state or merge changes it.
state,limit,cursorandfieldseach change the page, so each tags its own. - Headers: the 200 carries
cache-control: private, no-cacheandvary: authorization, cookie. The server appendsAccept-Encodingto thatvary, so the header actually sent isauthorization, cookie, Accept-Encoding. - 304: a matching
If-None-Matchgets a 304 with no body and the sameetag. - OpenAPI: the route's summary names the
etagand the 304, and the route declares 304 as an additional status. - Test: I added one test to
test/api-pulls-check-preview.test.ts. It asks twice for 200 then 304, records a new check run on a pull, and gets 200 with a different tag.
The route stays in src/http/api.ts; I did not move it to src/http/api/pulls.ts. I did not tag the single-pull read or any other list.
GET /api/v1/repos/:owner/:name/pulls now sends a weak etag of the exact page body and answers a repeat If-None-Match with an empty 304. The etag changes when any pull in the page is opened, pushed to, checked, merged or closed.
The earlier push failed the gate's "say how to try it on the preview" rule, which wants a Try: line in a commit message. I added an empty commit carrying that line, so no history was rewritten. I have not re-run the gate or the tests since. Last time the gate, tsc --noEmit and the focused tests passed, and the forge runs the full check on this push.
- Headers: the 200 carries
cache-control: private, no-cacheandvary: authorization, cookie. The server appendsAccept-Encodingto thatvary. - 304: it carries the same
etag. - Tag source: the tag is computed from the JSON actually sent, never a timestamp, so a new check verdict can't hide behind a 304. Each
state,limit,cursorandfieldsvalue gets its own tag because each changes the page. - OpenAPI: the route's summary names the
etagand the 304, and the route declares 304 as an additional status. - Test:
test/api-pulls-check-preview.test.tsasks twice for 200 then 304, records a new check run on a pull, and gets 200 with a different tag. - Not done: the route stays in
src/http/api.tsrather than moving tosrc/http/api/pulls.ts, and I tagged no other list.
Try: call GET /api/v1/repos/<owner>/<name>/pulls on the preview and note the etag. Repeat the call with that value as If-None-Match and expect 304 with no body.
Clean. The tag is a weak hash of the exact JSON sent, so verdict, head, state, limit, cursor and fields each tag their own page. 304 carries the same etag and no body. Headers are correct (private, no-cache; vary authorization, cookie), no new dependency, and the response is built the same way as json(). The test covers 200, 304, then 200 with a new tag after a check run. Nit, not blocking: no test varies limit or cursor.
GET /api/v1/repos/:owner/:name/pullsnow sends a weaketagand answers a repeat with 304 when the page it would send hasn't changed.The gate,
tsc --noEmitand the focused tests (the pulls check/preview, timing and page-param suites, plus the OpenAPI tests) pass. I did not run the full suite; the forge runs it on the push.state,limit,cursorandfieldseach change the page, so each tags its own.cache-control: private, no-cacheandvary: authorization, cookie. The server appendsAccept-Encodingto thatvary, so the header actually sent isauthorization, cookie, Accept-Encoding.If-None-Matchgets a 304 with no body and the sameetag.etagand the 304, and the route declares 304 as an additional status.test/api-pulls-check-preview.test.ts. It asks twice for 200 then 304, records a new check run on a pull, and gets 200 with a different tag.The route stays in
src/http/api.ts; I did not move it tosrc/http/api/pulls.ts. I did not tag the single-pull read or any other list.Closes #9118