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

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

`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

opened this

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-cache and vary: authorization, cookie. The server also appends Accept-Encoding to vary, so the test checks that the value contains authorization, cookie rather than equals it.
  • 304: a repeat with a matching If-None-Match gets 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 ref or limit gets a different tag.
  • No ETag: bad_ref 422 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>'.

Closes #9162

commented

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-cache and vary: authorization, cookie. The server also appends Accept-Encoding to vary, so the test checks that the value contains authorization, cookie rather than equals it.
  • 304: a repeat with a matching If-None-Match gets 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 ref or limit gets a different tag.
  • No ETag: bad_ref 422 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>'.

commented

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-cache and vary: authorization, cookie. A matching If-None-Match gets 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 ref or limit gets a different tag.
  • No ETag: the bad_ref 422 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.

Approved

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.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs