From abe86ceca8a55a58e834b7f6f9f101e1612bff18 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 5 Aug 2026 07:20:03 +0000 Subject: [PATCH 1/2] =?UTF-8?q?docs(examples):=20showcase=20=E7=9A=84=20ca?= =?UTF-8?q?cheTtl=20=E6=B3=A8=E9=87=8A=E5=86=99=E6=88=90=20private=20?= =?UTF-8?q?=E2=80=94=E2=80=94=20=E8=BF=90=E8=A1=8C=E6=97=B6=E5=8F=91?= =?UTF-8?q?=E7=9A=84=E5=B0=B1=E6=98=AF=E5=AE=83,=E4=B8=94=E5=AE=83?= =?UTF-8?q?=E6=98=AF=E5=AE=89=E5=85=A8=E8=A7=84=E5=88=99=20(#5244)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `examples/app-showcase/src/system/apis/index.ts` 里 `TaskFeedEndpoint.cacheTtl` 上方的注释把响应头写成 `Cache-Control: public, max-age=30`,运行时发的是 `private, max-age=30`(`packages/runtime/src/endpoint-policy.ts` 的 `computeCacheControl`;PR #5230 的真实 boot 探针 P1 也打印了实测值)。 `private` 在这条链上不是调优选择而是安全规则:任何一条响应都可能按调用者被 RLS 裁剪,共享缓存绝不能存下来再发给别人。而这份文件是声明式端点唯一的一手示例,是 AI 作者最可能整段抄走的那份 —— 抄走 `public` 正好得出该规则要挡住的推断。 因此除了把 `public` 改成 `private`,注释还点明它不是本示例的调优选择(在 `authRequired: false` 上同样成立),并**引用** `computeCacheControl` 的文档块而不是 复述第二套规则;顺带把 `cacheTtl: 0` 的语义(`no-store`,不是「不发头」)一并指过去。 注释的后半句(只随成功答案上线、不随 401/429/5xx、GET-only)本来就是对的,保留。 零行为变更:不动运行时,不动声明本身(`cacheTtl: 30` 是对的)。 Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01VkPSGsX9o17MsGv3Lbxu2w --- examples/app-showcase/src/system/apis/index.ts | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/examples/app-showcase/src/system/apis/index.ts b/examples/app-showcase/src/system/apis/index.ts index c372360fde..5f04fbe3cd 100644 --- a/examples/app-showcase/src/system/apis/index.ts +++ b/examples/app-showcase/src/system/apis/index.ts @@ -77,11 +77,18 @@ export const TaskFeedEndpoint: ApiEndpoint = { operation: 'find', }, authRequired: true, - // Seconds. Emitted as `Cache-Control: public, max-age=30` on a SUCCESSFUL + // Seconds. Emitted as `Cache-Control: private, max-age=30` on a SUCCESSFUL // answer only — never on a 401/429/5xx, because telling a client to reuse a - // failure for half a minute is worse than saying nothing. GET-only by rule: - // publish rejects `cacheTtl` on any other method rather than parsing it and - // ignoring it. + // failure for half a minute is worse than saying nothing. `private` is not + // this example's tuning choice: the runtime emits it for every ttl, on + // `authRequired: false` endpoints too, because any answer can be RLS-trimmed + // for its caller and a shared cache must never store one and hand it to + // somebody else. `computeCacheControl` in + // `packages/runtime/src/endpoint-policy.ts` states that rule and the rest of + // the ladder with it — including `cacheTtl: 0`, which is `no-store` rather + // than "no header": writing 0 says something, and saying nothing is spelled + // by omitting the key. GET-only by rule: publish rejects `cacheTtl` on any + // other method rather than parsing it and ignoring it. cacheTtl: 30, }; From 8f25f8375a4039dba8e9c63a5dff90b3f1487667 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 5 Aug 2026 07:23:29 +0000 Subject: [PATCH 2/2] =?UTF-8?q?docs(examples):=20=E6=8A=8A=E3=80=8Cevery?= =?UTF-8?q?=20ttl=E3=80=8D=E6=94=B6=E7=B4=A7=E6=88=90=E3=80=8Cevery=20posi?= =?UTF-8?q?tive=20ttl=E3=80=8D(#5244)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 自查时发现上一版注释里「the runtime emits it for every ttl」本身就不准:`private` 只出现在正 ttl 上,`cacheTtl: 0` 走的是 `no-store`,并不带 `private`。这正是本 PR 要 消灭的那一类失真,故就地收紧为「every positive ttl」,与紧随其后的 `cacheTtl: 0` 说明自洽。 Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01VkPSGsX9o17MsGv3Lbxu2w --- examples/app-showcase/src/system/apis/index.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/app-showcase/src/system/apis/index.ts b/examples/app-showcase/src/system/apis/index.ts index 5f04fbe3cd..d1a2810258 100644 --- a/examples/app-showcase/src/system/apis/index.ts +++ b/examples/app-showcase/src/system/apis/index.ts @@ -80,10 +80,10 @@ export const TaskFeedEndpoint: ApiEndpoint = { // Seconds. Emitted as `Cache-Control: private, max-age=30` on a SUCCESSFUL // answer only — never on a 401/429/5xx, because telling a client to reuse a // failure for half a minute is worse than saying nothing. `private` is not - // this example's tuning choice: the runtime emits it for every ttl, on - // `authRequired: false` endpoints too, because any answer can be RLS-trimmed - // for its caller and a shared cache must never store one and hand it to - // somebody else. `computeCacheControl` in + // this example's tuning choice: the runtime emits it for every positive + // ttl, on `authRequired: false` endpoints too, because any answer can be + // RLS-trimmed for its caller and a shared cache must never store one and + // hand it to somebody else. `computeCacheControl` in // `packages/runtime/src/endpoint-policy.ts` states that rule and the rest of // the ladder with it — including `cacheTtl: 0`, which is `no-store` rather // than "no header": writing 0 says something, and saying nothing is spelled