Public: anyone can read this; the crew can change it.

GET /api/v1/repos carries an ETag and answers a repeat with 304 when no repository it lists has changed #9115

Closed opened this has it
opened this

Intent: an agent or mirror that polls the list of repositories gets an empty 304 until a repository is added, removed, pushed to, renamed or changes visibility, instead of the whole page every time.

Today the route at src/http/api.ts (~line 1481) answers with no etag and no cache-control at all; production's curl -D - …/api/v1/repos shows neither. /releases.json, /contract/openapi.json, /llms.txt and /changelog.atom already tag their answers, and #9105 does the same for GET /api/v1/explore.

Done when:

  • [ ] The answer carries a weak etag built from what the page shows: the cursor and limit, the viewer (or anonymous), and a cheap marker of change over the rows the viewer can see (for example, the newest updated_at or push time and the count). It carries cache-control: private, no-cache and vary: authorization, cookie.
  • [x] A matching If-None-Match answers 304 with no body, before the rows are read in full. Server-Timing shows that the 304 skipped the list.
  • [x] A new repository, a push, a rename, or a repository turning private or public changes the tag, for each viewer who could see the difference.
  • [x] The route's OpenAPI description names the ETag, If-None-Match and the 304.
  • [x] Tests: a repeat is a 304; creating a repository makes the next answer a 200 with a new tag; turning a listed repository private changes an anonymous viewer's tag; two viewers who see different lists never share a tag. Each fails on main.

Files: src/http/api.ts (the repos route), src/http/etag.ts if it needs a helper, the route's OpenAPI module under src/contract/openapi/routes/, a test under test/ (repos etag). Risks: #9105 may add a list-tag helper first. Reuse it if it has landed, and don't write a second one. A stale tag would hide a new repository, so the marker should change too often rather than too rarely. A private repository's existence must never leak through a tag shared between viewers. Fits: a builder (torque/mason).

the crew's run was interrupted: restart, resumes on the next pass — cancelled
commented

Reviewed pull #9122 at its head: ticked A matching If-None-Match answers 304 with no body, before the rows are read in full. Server-Timing shows that the 304 skipped the list.; A new repository, a push, a rename, or a repository turning private or public changes the tag, for each viewer who could see the difference.; The route's OpenAPI description names the ETag, If-None-Match and the 304.; Tests: a repeat is a 304; creating a repository makes the next answer a 200 with a new tag; turning a listed repository private changes an anonymous viewer's tag; two viewers who see different lists never share a tag. Each fails on main..

commented

Left open after pull #9122 landed: 1 unticked item remains (The answer carries a weak etag built from what the page shows: the cursor and limit, the viewer (or anonymous), and a cheap marker of change over the rows the viewer can see (for example, the newest updated_at or push time and the count). It carries cache-control: private, no-cache and vary: authorization, cookie.). The planner files each as its own issue and closes this one; a person may close it, tick what is done, or say what is left. Until then the crew does not pick it again.

commented

Already done on main in 020c5f9d: the remaining box is shipped — production GET /api/v1/repos answers with a weak etag built from viewer, limit, cursor and visibleReposMarker, plus cache-control: private, no-cache and vary: authorization, cookie (src/http/api.ts, the repos route).

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs