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

scout/forge:scout/8464-llms-txt-revalidates-on-every-read-so-it → main 2 commits fork

  • Merged. scout/8464-llms-txt-revalidates-on-every-read-so-it was merged into main as c7aaeee.

Review

Sign in to review this change.
3 files changed +28 −2
src/web/standards.ts +3 −1
@@ -370,11 +370,13 @@ export function llmsTxt(ctx: Ctx): Response {
370370 if (llmsBodies.size >= 16) llmsBodies.clear();
371371 llmsBodies.set(key, kept);
372372 }
373 const cache = "public, max-age=3600";
373 // The third line names the running commit: a client revalidates (one small 304) rather than keep an old build for an hour.
374 const cache = "private, no-cache";
374375 const sent = ctx.request.headers.get("if-none-match");
375376 if (sent !== null && sent.split(",").some((t) => t.trim() === kept.etag))
376377 return new Response(null, { status: 304, headers: { etag: kept.etag, "cache-control": cache, vary: "Cookie, Authorization" } });
377378 const res = text(kept.body, "text/markdown; charset=utf-8");
379 res.headers.set("cache-control", cache);
378380 res.headers.set("etag", kept.etag);
379381 res.headers.append("vary", "Cookie, Authorization");
380382 return res;
test/llms-tools.test.ts +1 −1
@@ -39,7 +39,7 @@ describe("/llms.txt MCP tools", () => {
3939 test("lists, for a signed-in reader, exactly the tools in the index and `report`, by their `doc`, with (admin) and (writes)", async () => {
4040 const res = await fetch(`${servers.url}/llms.txt`, { headers: { authorization: `Bearer ${token}` } });
4141 expect(res.status).toBe(200);
42 expect(res.headers.get("cache-control")).toContain("max-age");
42 expect(res.headers.get("cache-control")).toContain("no-cache");
4343 const lines = (await res.text()).split("\n");
4444 const start = lines.indexOf("## MCP tools");
4545 expect(start).toBeGreaterThan(-1);
test/standards.test.ts +24
@@ -270,6 +270,10 @@ describe("what the open web expects", () => {
270270 expect(again.status).toBe(304);
271271 expect(await again.text()).toBe("");
272272 expect(again.headers.get("etag")).toBe(etag);
273 expect(first.headers.get("cache-control")).toBe("private, no-cache");
274 expect(again.headers.get("cache-control")).toBe("private, no-cache");
275 expect(again.headers.get("vary")).toContain("Cookie");
276 expect(again.headers.get("x-content-type-options")).toBe("nosniff");
273277 const made = await createRepo(app, alice, { name: "etagged", visibility: "public" });
274278 if (!made.ok) throw new Error(String(made.error));
275279 // A new repository reaches the listing when its minute is up.
@@ -280,6 +284,26 @@ describe("what the open web expects", () => {
280284 expect(await after.text()).toContain("alice/etagged");
281285 });
282286
287 test("llms.txt changes its ETag when the running commit changes", async () => {
288 const saved = { c: process.env["FORGE_COMMIT"], a: process.env["FORGE_APP_COMMIT"] };
289 try {
290 delete process.env["FORGE_COMMIT"];
291 process.env["FORGE_APP_COMMIT"] = "aaaaaaa1111111";
292 const one = await fetch(`${base}/llms.txt`);
293 await one.text();
294 process.env["FORGE_APP_COMMIT"] = "bbbbbbb2222222";
295 const two = await fetch(`${base}/llms.txt`, { headers: { "if-none-match": one.headers.get("etag")! } });
296 expect(two.status).toBe(200);
297 expect(two.headers.get("etag")).not.toBe(one.headers.get("etag"));
298 expect(await two.text()).toContain("at bbbbbbb");
299 } finally {
300 for (const [k, v] of [["FORGE_COMMIT", saved.c], ["FORGE_APP_COMMIT", saved.a]] as const) {
301 if (v === undefined) delete process.env[k];
302 else process.env[k] = v;
303 }
304 }
305 });
306
283307 test("llms.txt opens with the version, and the short commit only when one is known", async () => {
284308 const saved = {
285309 v: process.env["FORGE_VERSION"],

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs