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

GET /api/v1/repos/:owner/:name/map carries an ETag and answers a repeat with 304 while the map snapshot has not changed #9156

shipped production is serving it opened this has it
opened this

Intent: the crew and any agent polling a repository's map (the planner reads it every run, the board every few seconds) get an empty 304 while nothing on the map moved, instead of the whole graph each time.

Today the route at src/http/api.ts (~line 2235) serves a cachedMap snapshot but sends no etag and no cache-control, so every poll ships the full JSON (hundreds of issues and edges on trevato/forge).

Done when:

  • [x] The answer carries a weak etag derived from the snapshot it serves and the reader's sealed scope (sealedScope), plus cache-control: private, no-cache and vary: authorization, cookie.
  • [x] A matching If-None-Match answers 304 with no body; on a snapshot hit no graph phase runs, and Server-Timing says the answer was a 304.
  • [x] Opening, closing or blocking an issue, a run starting on one, or a pillar changing makes the next answer a 200 with a new tag.
  • [x] Two readers whose sealed scopes differ never share a tag, so a sealed issue's existence never leaks through one.
  • [x] The route's OpenAPI module under src/contract/openapi/routes/ names the ETag, If-None-Match and the 304.
  • [x] Tests in test/map-etag.test.ts cover each of the above and fail on main.

Files: src/http/api.ts (the map route), the map cache module beside cachedMap if the tag is best kept with the snapshot, src/contract/openapi/routes/getApiV1ReposOwnerNameMap.ts, test/map-etag.test.ts. Risks: the snapshot has a time component (now); if the JSON carries ages that tick, tag the facts rather than the rendered text, or the tag changes on every poll and the work buys nothing. Reuse holds/weakEtag from src/http/etag.ts.

commented

Reviewed pull #9159 at its head: ticked The answer carries a weak etag derived from the snapshot it serves and the reader's sealed scope (sealedScope), plus cache-control: private, no-cache and vary: authorization, cookie.; A matching If-None-Match answers 304 with no body; on a snapshot hit no graph phase runs, and Server-Timing says the answer was a 304.; Opening, closing or blocking an issue, a run starting on one, or a pillar changing makes the next answer a 200 with a new tag.; Two readers whose sealed scopes differ never share a tag, so a sealed issue's existence never leaks through one.; The route's OpenAPI module under src/contract/openapi/routes/ names the ETag, If-None-Match and the 304.; Tests in test/map-etag.test.ts cover each of the above and fail on main..

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs