From 28b771bf636498ea2f13c7c7bfc048847ad7fc65 Mon Sep 17 00:00:00 2001 From: mhenrixon Date: Thu, 27 Aug 2026 17:46:40 +0200 Subject: [PATCH] fix(llms): send a public max-age so shared caches can store llms.txt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `public` alone is not storable under RFC 9111 — the dash-proxy response cache skipped /llms.txt for lack of a freshness lifetime. 300s matches the proxy.cache.max_ttl docs-kit scaffolds; the etag still revalidates. Claude-Session: https://claude.ai/code/session_01SdEc37DFCkYzwpQpadu9My --- app/controllers/docs_kit/llms_controller.rb | 7 +++++++ spec/docs_kit/llms_controller_spec.rb | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/app/controllers/docs_kit/llms_controller.rb b/app/controllers/docs_kit/llms_controller.rb index 7269812..3df3234 100644 --- a/app/controllers/docs_kit/llms_controller.rb +++ b/app/controllers/docs_kit/llms_controller.rb @@ -47,6 +47,12 @@ def full render_text(body) if stale_llms?(body) end + # Freshness lifetime for a shared cache (dash-proxy, a CDN). `public` on its + # own is not storable under RFC 9111 — without a max-age the proxy cache + # skips the response. 300s matches the `proxy.cache.max_ttl` docs-kit + # scaffolds; the etag below still revalidates within that window. + LLMS_MAX_AGE = 300 + private # NOT named #config — ActionController::Base#config is the Rails config @@ -66,6 +72,7 @@ def render_text(body) # busts it) plus the gem version as the etag salt. In development, always # re-render; production sites deploy immutably so the version etag is stable. def stale_llms?(body) + expires_in LLMS_MAX_AGE, public: true stale?(etag: [DocsKit::VERSION, body], public: true) end diff --git a/spec/docs_kit/llms_controller_spec.rb b/spec/docs_kit/llms_controller_spec.rb index c399298..acfb523 100644 --- a/spec/docs_kit/llms_controller_spec.rb +++ b/spec/docs_kit/llms_controller_spec.rb @@ -45,6 +45,13 @@ expect(source).to include("stale?(etag: [DocsKit::VERSION, body]") end + it "sends a public max-age so a shared cache (dash-proxy, CDN) can store it" do + # `public` alone is not storable under RFC 9111 — a shared cache needs a + # freshness lifetime. expires_in adds max-age; stale? keeps `public`. + expect(source).to include("expires_in LLMS_MAX_AGE, public: true") + expect(source).to include("LLMS_MAX_AGE = 300") + end + it "does not shadow ActionController::Base#config (forgery delegates to it)" do # RequestForgeryProtection delegates allow_forgery_protection to #config, so # a `def config` on the controller breaks csrf_meta_tags when #full renders a