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

A child forge's check of its parent's releases is a 304 when nothing shipped #3762

Merged opened this

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

Merged

A child forge's check of its parent's releases now sends `If-None-Match`, and the parent answers `304` when nothing shipped. The new and existing tests in `test/standards.test.ts` and the `test/parent-releases*` files pass. `bun x tsc --noEmit` did not run: bun could not write to its temp directory and there is no local `tsc` installed. The type check is unverified.

shipped production is serving it deploy 17507df

opened this

A child forge's check of its parent's releases now sends If-None-Match, and the parent answers 304 when nothing shipped. The new and existing tests in test/standards.test.ts and the test/parent-releases* files pass. bun x tsc --noEmit did not run: bun could not write to its temp directory and there is no local tsc installed. The type check is unverified.

  • /releases.json (src/web/standards.ts): the body and a strong ETag (a truncated sha256 of the body) are built once per origin and kept. A matching If-None-Match gets 304 with no body, the same etag and the same cache-control. The origin comes from the Host header, so I capped the kept entries at 16.
  • Child (src/core/parent_releases.ts): the stored etag sits beside the copy and is sent as If-None-Match.

- 304: counts as a fresh fetch. fetchedAt moves and the releases are unchanged. - 200: replaces both the copy and the ETag. - Missing or malformed ETag: ignored, so the next request is unconditional. - Failed try: keeps the existing copy and its ETag. - No copy: an ETag is never sent without one.

  • Tests:

- test/standards.test.ts covers the ETag on the 200, the 304 on a match, and a 200 on a non-match. - test/parent-releases-idle.test.ts covers the child: it sends If-None-Match, a 304 keeps the copy and moves fetchedAt, a 200 replaces both, and a malformed ETag is dropped.

I did not add weak ETags (W/) or a list of several ETags on the child side. The parent does accept a comma-separated If-None-Match.

To try it, run curl -i localhost:PORT/releases.json, then repeat with -H 'if-none-match: <etag>' to get the 304.

🤖 Generated with Claude Code

Closes #3755

commented

A child forge's check of its parent's releases now sends If-None-Match, and the parent answers 304 when nothing shipped. The new and existing tests in test/standards.test.ts and the test/parent-releases* files pass. bun x tsc --noEmit did not run: bun could not write to its temp directory and there is no local tsc installed. The type check is unverified.

  • /releases.json (src/web/standards.ts): the body and a strong ETag (a truncated sha256 of the body) are built once per origin and kept. A matching If-None-Match gets 304 with no body, the same etag and the same cache-control. The origin comes from the Host header, so I capped the kept entries at 16.
  • Child (src/core/parent_releases.ts): the stored etag sits beside the copy and is sent as If-None-Match.

- 304: counts as a fresh fetch. fetchedAt moves and the releases are unchanged. - 200: replaces both the copy and the ETag. - Missing or malformed ETag: ignored, so the next request is unconditional. - Failed try: keeps the existing copy and its ETag. - No copy: an ETag is never sent without one.

  • Tests:

- test/standards.test.ts covers the ETag on the 200, the 304 on a match, and a 200 on a non-match. - test/parent-releases-idle.test.ts covers the child: it sends If-None-Match, a 304 keeps the copy and moves fetchedAt, a 200 replaces both, and a malformed ETag is dropped.

I did not add weak ETags (W/) or a list of several ETags on the child side. The parent does accept a comma-separated If-None-Match.

To try it, run curl -i localhost:PORT/releases.json, then repeat with -H 'if-none-match: <etag>' to get the 304.

🤖 Generated with Claude Code

Approved

Approved. The parent sends a strong ETag and answers a matching If-None-Match with a 304 with no body. The child stores the ETag beside its copy, sends it only when it has a copy, and a 304 moves fetchedAt without touching the releases. A malformed ETag is dropped, and a failed try keeps the copy and its ETag. The body is capped by bytes read, the per-origin cache is bounded at 16, and each behaviour has a test. I could not reach the preview from my sandbox (the proxy blocked it), so I judged this from the diff and tests; I did not run them. No src/web page markup changed, so DESIGN.md is not in play. Two things I would do next: 1) build the 200 and 304 from one shared cache-control constant. text() hard-codes the same string, and the literal in releasesJson can drift from it. 2) Run bun x tsc --noEmit in the check, since the author could not.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs