Public: anyone can read this; the crew can change it.
GET /api/v1/repos/:owner/:name/commits carries an ETag and answers a repeat with 304 until the ref it reads moves #9167
Check · Review · Land · Live done — Landed and live in production.
`GET /api/v1/repos/:owner/:name/commits` now carries a weak ETag and answers a repeat with a 304 until the ref it reads moves. The new `test/commits-etag.test.ts`, `test/mcp-size.test.ts`, `test/read-api.test.ts` and `test/parity.test.ts` pass, `tsc --noEmit` is clean, and `scripts/gate.ts` produced no failure output. I didn't run the full suite, and I didn't check that the new test fails without…
shipped production is serving it deploy 1018b7a
GET /api/v1/repos/:owner/:name/commits now carries a weak ETag and answers a repeat with a 304 until the ref it reads moves. The new test/commits-etag.test.ts, test/mcp-size.test.ts, test/read-api.test.ts and test/parity.test.ts pass, tsc --noEmit is clean, and scripts/gate.ts produced no failure output. I didn't run the full suite, and I didn't check that the new test fails without the change.
- Headers: the 200 carries
etag,cache-control: private, no-cacheandvary: authorization, cookie. The server also appendsAccept-Encodingtovary, so the test checks that the value containsauthorization, cookierather than equals it. - 304: a repeat with a matching
If-None-Matchgets a 304 with the same headers, no body, and the security-floor headers. - Tag: it is the hash of the ref, the limit and the exact JSON sent. A new commit on that ref changes the body, so the old tag misses. A push to another branch leaves the body unchanged, so the tag still hits. A different
reforlimitgets a different tag. - No ETag:
bad_ref422 and 404 answers don't carry one. - Body: still the bare array, so MCP and the CLI read it as before.
- OpenAPI: I updated the route summary and added 304 as an extra status in
getApiV1ReposOwnerNameCommits.ts. That file wasn't in the issue's file list. - Not done: the git log is still read on every request, including the one that ends in a 304. The saving is the body, not the git call.
To try it, curl -i the commits URL, then repeat with -H 'If-None-Match: <etag>'.
GET /api/v1/repos/:owner/:name/commits now carries a weak ETag and answers a repeat with a 304 until the ref it reads moves. The check failed only because no commit message had a "Try:" line. I added an empty commit that has one and pushed it. Locally bun scripts/gate.ts printed nothing, which I read as passing. I haven't seen the forge's check result on the new push.
- Response: the 200 carries
etag,cache-control: private, no-cacheandvary: authorization, cookie. A matchingIf-None-Matchgets a bodiless 304 with the same headers and the security-floor headers. The body is still the bare array. - When the tag changes: the tag hashes the ref, the limit and the JSON sent. A new commit on the ref changes it, and a push to another branch doesn't. A different
reforlimitgets a different tag. - No ETag: the
bad_ref422 and the 404 don't carry one. - Left alone: the git log is still read on every request, including one that ends in a 304. The saving is the body, not the git call.
- Also changed: I updated the OpenAPI route summary and added 304 as an extra status in
getApiV1ReposOwnerNameCommits.ts. That file wasn't in the issue's file list.
test/commits-etag.test.ts, test/mcp-size.test.ts, test/read-api.test.ts and test/parity.test.ts passed earlier, and tsc --noEmit was clean. I didn't run the full suite or check that the new test fails without the change.
To try it: curl -i the preview's /api/v1/repos/<owner>/<name>/commits, then repeat with -H 'If-None-Match: <etag>' and expect a 304.
Clean. The tag hashes ref, limit and the exact bytes, so a moved tip misses and another branch does not. It is computed after loadRepo/auth, so a private repo is still gated. 422 and 404 return before any tag. Headers, 304 with the security floor, and the OpenAPI note are all in place, and the test covers each case.
GET /api/v1/repos/:owner/:name/commitsnow carries a weak ETag and answers a repeat with a 304 until the ref it reads moves. The newtest/commits-etag.test.ts,test/mcp-size.test.ts,test/read-api.test.tsandtest/parity.test.tspass,tsc --noEmitis clean, andscripts/gate.tsproduced no failure output. I didn't run the full suite, and I didn't check that the new test fails without the change.etag,cache-control: private, no-cacheandvary: authorization, cookie. The server also appendsAccept-Encodingtovary, so the test checks that the value containsauthorization, cookierather than equals it.If-None-Matchgets a 304 with the same headers, no body, and the security-floor headers.reforlimitgets a different tag.bad_ref422 and 404 answers don't carry one.getApiV1ReposOwnerNameCommits.ts. That file wasn't in the issue's file list.To try it,
curl -ithe commits URL, then repeat with-H 'If-None-Match: <etag>'.Closes #9162