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

/llms.txt revalidates on every read, so its "Running … at <commit>" line is never an hour stale after a deploy #8470

Merged opened this

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

Merged

`/llms.txt` now answers `cache-control: private, no-cache` on both the 200 and the 304, so a client revalidates on every read instead of holding an old "Running … at <commit>" line for up to an hour. The fix is in `src/web/standards.ts`.

shipped production is serving it deploy cc21c84

opened this

/llms.txt now answers cache-control: private, no-cache on both the 200 and the 304, so a client revalidates on every read instead of holding an old "Running … at <commit>" line for up to an hour. The fix is in src/web/standards.ts.

  • The 200: it previously sent the shared public, max-age=3600 default. It now sets private, no-cache explicitly.
  • The 304: an If-None-Match with the current ETag still answers 304. The 304 keeps Vary: Cookie, Authorization, and the test checks x-content-type-options on it.
  • ETag: it is a hash of the body, so it changes when the running commit changes. A new test sets two FORGE_APP_COMMIT values and checks the ETag differs and the old one gets a 200 with the new commit line.
  • Tests: the existing ETag/304 test now asserts the header on 200 and 304, and fails against max-age=3600.

test/standards.test.ts and test/cache-private.test.ts pass, tsc --noEmit is clean, and scripts/gate.ts printed nothing.

I chose private, no-cache over public, max-age=0, must-revalidate. The body differs for signed-in callers, so a shared cache should not keep it. The cost is that a shared cache can no longer serve the anonymous copy.

I left /sitemap.xml and the other standards files on their one-hour cache, since the issue covers only /llms.txt.

Closes #8464

commented

/llms.txt now answers cache-control: private, no-cache on both the 200 and the 304, so a client revalidates on every read instead of holding an old "Running … at <commit>" line for up to an hour. The fix is in src/web/standards.ts.

  • The 200: it previously sent the shared public, max-age=3600 default. It now sets private, no-cache explicitly.
  • The 304: an If-None-Match with the current ETag still answers 304. The 304 keeps Vary: Cookie, Authorization, and the test checks x-content-type-options on it.
  • ETag: it is a hash of the body, so it changes when the running commit changes. A new test sets two FORGE_APP_COMMIT values and checks the ETag differs and the old one gets a 200 with the new commit line.
  • Tests: the existing ETag/304 test now asserts the header on 200 and 304, and fails against max-age=3600.

test/standards.test.ts and test/cache-private.test.ts pass, tsc --noEmit is clean, and scripts/gate.ts printed nothing.

I chose private, no-cache over public, max-age=0, must-revalidate. The body differs for signed-in callers, so a shared cache should not keep it. The cost is that a shared cache can no longer serve the anonymous copy.

I left /sitemap.xml and the other standards files on their one-hour cache, since the issue covers only /llms.txt.

commented

/llms.txt now sends Cache-Control: private, no-cache for a signed-in reader, so it revalidates on every read. The running-commit line is therefore never stale. That is the change from #8464.

The failing check was a test that still expected the old max-age header. The new header is intended, so I fixed the test, not the code. The assertion in test/llms-tools.test.ts:42 now expects no-cache.

test/llms-tools.test.ts and test/standards.test.ts pass (25 tests), and tsc --noEmit is clean. I didn't run scripts/gate.ts or the full suite; the forge's check runs the full suite on this push.

To try it, fetch /llms.txt with a bearer token and read the cache-control header.

Approved

Approved. The preview answers /llms.txt with cache-control: private, no-cache, an ETag, Vary: Cookie, Authorization and nosniff. The 304 path carries the same header. The ETag hashes the body, so a new commit gives a new ETag and the old one gets a 200. The tests cover both states and would fail against max-age=3600. Nothing in src/web/ markup changed, so DESIGN.md is not touched. No new dependency, no README edit.

Two things I would do next:

  1. Give the other standards files that name the build (if any do) the same revalidation, or state in a comment why sitemap.xml can stay on an hour.
  2. Use the 304 branch's cache constant for the 200 as well, by building both from one headers object, so the two cannot drift apart again.
commented

Left #8464 open: 3 unticked items remain (/llms.txt answers cache-control: private, no-cache (or public, max-age=0, must-revalidate with the Vary kept) on both the 200 and the 304; an If-None-Match with the current ETag still answers 304.; When the running commit changes, the ETag changes (it is a hash of the body, which carries the line; a test proves it with two FORGE_APP_COMMIT values).; A test asserts the header on 200 and 304 and fails on today's max-age=3600.).

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs