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

GET /api/v1/repos/:owner/:name/runs carries an ETag and answers a repeat with 304 until a run in the page starts, moves or finishes #9148

shipped production is serving it opened this has it
opened this

Intent: an agent or the terminal polling a repository's runs gets an empty 304 while nothing in its page has changed, instead of the whole list each poll.

Today the route at src/http/api.ts (~line 3709) answers with no etag and no cache-control. The repos, explore and pulls list routes already tag their answers with holds/weakEtag from src/http/etag.ts.

Done when:

  • [x] The answer carries a weak etag built from the repository, the viewer (or anonymous), every query word that shapes the page (kind, env, state, cursor, limit), and a cheap marker over the matching runs (for example the newest run id, the highest updated_at/state change and the count), plus cache-control: private, no-cache and vary: authorization, cookie.
  • [x] A matching If-None-Match answers 304 with no body before listRepoRuns and nameRuns run; Server-Timing shows a tag phase and no runs phase on the 304.
  • [x] A bad state is still a 422 and an unseen repository still a 404, neither tagged.
  • [x] A reader who sees cost and turns (the owner) and a stranger who does not never share a tag.
  • [x] src/contract/openapi/routes/getApiV1ReposOwnerNameRuns.ts names the ETag, If-None-Match and the 304.
  • [x] Tests in test/runs-etag.test.ts: a repeat is a 304; a new run makes the next answer a 200 with a new tag; a run moving from queued to running to done changes it each time; a filter (state=done) keeps its tag when a run that does not match changes; owner and stranger tags differ. Each fails on main.

Files: src/http/api.ts, the runs store under src/core/ (a marker beside listRepoRuns), src/contract/openapi/routes/getApiV1ReposOwnerNameRuns.ts, test/runs-etag.test.ts. Risks: a running run's live fields (turns, cost) change without a state change — the marker must cover whatever the row shows, or a poller sees a frozen run.

commented

Reviewed pull #9158 at its head: ticked The answer carries a weak etag built from the repository, the viewer (or anonymous), every query word that shapes the page (kind, env, state, cursor, limit), and a cheap marker over the matching runs (for example the newest run id, the highest updated_at/state change and the count), plus cache-control: private, no-cache and vary: authorization, cookie.; A matching If-None-Match answers 304 with no body before listRepoRuns and nameRuns run; Server-Timing shows a tag phase and no runs phase on the 304.; A bad state is still a 422 and an unseen repository still a 404, neither tagged.; A reader who sees cost and turns (the owner) and a stranger who does not never share a tag.; src/contract/openapi/routes/getApiV1ReposOwnerNameRuns.ts names the ETag, If-None-Match and the 304.; Tests in test/runs-etag.test.ts: a repeat is a 304; a new run makes the next answer a 200 with a new tag; a run moving from queued to running to done changes it each time; a filter (state=done) keeps its tag when a run that does not match changes; owner and stranger tags differ. Each fails on main..

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs