Public: anyone can read this; the crew can change it.
GET /api/v1/admin/drills carries an ETag and answers a repeat with 304 until a drill runs or its result changes #9233
Check · Review · Land · Live done — Landed and live in production.
`GET /api/v1/admin/drills` now carries a weak ETag, and a repeat holding it gets a 304 until a drill's recorded result changes. The new test and the existing `test/api-admin-drills.test.ts` pass (8 tests), and `tsc` and `scripts/gate.ts` are clean. I did not run the full suite; the forge runs it on push. I also did not call the `keep_plan` tool, so there is no plan on the issue.
shipped production is serving it deploy 78f82e5
GET /api/v1/admin/drills now carries a weak ETag, and a repeat holding it gets a 304 until a drill's recorded result changes. The new test and the existing test/api-admin-drills.test.ts pass (8 tests), and tsc and scripts/gate.ts are clean. I did not run the full suite; the forge runs it on push. I also did not call the keep_plan tool, so there is no plan on the issue.
- What changed:
src/http/api/drills.tsnow serialises the body once. The ETag comes fromweakEtagover those exact bytes, so the body is byte-for-byte what it was. Both the 200 and the 304 carryetag,cache-control: private, no-cacheandvary: authorization, cookie. The 304 has no body and keeps thesecurityFloorheaders.src/http/api.tsis untouched. - Access check: the tag is computed only after the person-admin check. No session (401), a non-admin member (403) and an agent admin (403) answer as before with no ETag, even with
If-None-Match: *. - When the tag moves: it moves when a drill result is recorded, which is the only state the body shows. The body has no "running" field, so a drill that has started but not finished does not change it.
- Viewers: every viewer allowed through gets the same body, so two admins share a tag. That is correct, since the tag follows the bytes. The issue's "two viewers shown different bodies never share an etag" can't arise here, and the test shows two admins sharing a tag.
- Tests:
test/drills-etag.test.tscovers the headers and floor on the 200 and the 304, the tag moving after each of two recorded drills, a second admin matching the tag, and the 401/403 cases withIf-None-Match: *.
To try it, fetch /api/v1/admin/drills as a person admin with a bearer token, then repeat with If-None-Match set to the returned etag. That repeat is a 304.
The check failed because no commit message had a "Try:" line. I added an empty commit that has one and pushed it (2703aa0a). The local gate (scripts/gate.ts) printed nothing when I ran it, and I read that as passing. I haven't seen the forge's re-run of the check on the new push.
The line reads: "Try: GET /api/v1/admin/drills as a person admin with a bearer token, then repeat with If-None-Match set to the returned etag and see a bodiless 304".
The code is unchanged, so the tests I ran earlier still stand.
Clean. The tag is a weakEtag over the exact bytes sent and is computed only after the person-admin check, so the 401 and 403 carry no ETag. The 200 and the 304 both carry etag, private no-cache and vary. The 304 has no body and keeps the floor headers. The tests cover each of these. Preview answers 401 without an admin token, as expected. The body has no running field, so a drill that has started but not finished cannot move the tag; the tag follows what the body shows, which is right.
GET /api/v1/admin/drillsnow carries a weak ETag, and a repeat holding it gets a 304 until a drill's recorded result changes. The new test and the existingtest/api-admin-drills.test.tspass (8 tests), andtscandscripts/gate.tsare clean. I did not run the full suite; the forge runs it on push. I also did not call thekeep_plantool, so there is no plan on the issue.src/http/api/drills.tsnow serialises the body once. The ETag comes fromweakEtagover those exact bytes, so the body is byte-for-byte what it was. Both the 200 and the 304 carryetag,cache-control: private, no-cacheandvary: authorization, cookie. The 304 has no body and keeps thesecurityFloorheaders.src/http/api.tsis untouched.If-None-Match: *.test/drills-etag.test.tscovers the headers and floor on the 200 and the 304, the tag moving after each of two recorded drills, a second admin matching the tag, and the 401/403 cases withIf-None-Match: *.To try it, fetch
/api/v1/admin/drillsas a person admin with a bearer token, then repeat withIf-None-Matchset to the returnedetag. That repeat is a 304.Closes #9205