Skip to content

Commit 86e6f6c

Browse files
docs(runtime): errorResponseBase 文件头不再把 details.code 说成线上位置 (#6270) (#6912)
Claude-Session: https://claude.ai/code/session_017uFVNMmTxLpmfQYiuKM1Yx Co-authored-by: Claude <noreply@anthropic.com>
1 parent 17688fe commit 86e6f6c

2 files changed

Lines changed: 58 additions & 3 deletions

File tree

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
---
2+
"@objectstack/runtime": patch
3+
---
4+
5+
docs(runtime): `errorResponseBase` 文件头不再把 `details.code` 说成线上位置 (#6270)
6+
7+
**纯注释改动,零行为变更。** 没有一行运行时代码被触碰,线上响应体与本次改动前逐字节相同。修的是
8+
`packages/runtime/src/dispatcher-plugin.ts` 文件头里一句会误导下一个改这个函数的人的话。
9+
10+
原文说:`details.code`#3842, below)carries `READ_SCOPE_COMPILE_FAILED` **to the
11+
client** untouched,so **what a machine reads** is unchanged。这两个断言讲的都是**线上位置**
12+
#5811 之后线上位置不是 `details.code``errorResponseBase` 只是把 code **暂存**进一个本地
13+
`details` 对象,`buildApiError` 随即跑 `splitSemanticCode`,把它**提升**`ApiErrorSchema`
14+
声明的 `error.code` 字段,并把已经空掉的 `details` 返回为 `undefined` —— 于是 `details` 键整个
15+
从 body 中消失,`error.details.code` 根本不存在可读。实测 500 body 就是:
16+
17+
`{"success":false,"error":{"code":"READ_SCOPE_COMPILE_FAILED","message":"Internal server error","httpStatus":500}}`
18+
19+
这是同一句话漂移的**第四处**#6123(PR #6264)修了前三处,并明文把 `dispatcher-plugin.ts` 划为
20+
⛔ 只读参考面,所以第四处按 PD #10 单独立单。措辞刻意与 #6264 在另外三处落的保持一致 —— 这里的价值是
21+
四处同一句话,而不是第四种独立说法。
22+
23+
危害方向比前三处更陡:前三处的受害者是读 CHANGELOG / 读 `service-analytics` 的人,这一处的受害者
24+
**就站在做暂存的那个函数里**,读到「details.code carries it to the client」会直接把**本地变量名**
25+
当成**线上契约**。注释里因此明写了一句 `Do not mistake the local variable name for the wire contract`
26+
27+
顺带把同一 doc block 里 `:452`-`:457` 那段 JSON 示例的时态钉明确:它展示的是 #5811 **修复之前**
28+
泄漏形态(message 原文直接落在 body 里),与新补的当前 body 并排读极易混淆。现在 fence 顶部有一行
29+
`⚠️ PAST TENSE` 标注并指向 doc block 末尾的当前形态。示例本身**没有删** —— 它记录的是「我们曾经
30+
泄漏过什么」,是这条 `[#5811]` 条目在做的正经工作。
31+
32+
新措辞的真实性由**既有**测试锚定,本次没有新写断言:
33+
`packages/runtime/src/analytics-query-read-scope-withhold.test.ts:218` 用真 `AnalyticsService`
34+
+真挂载路由断言 `expect(res.body.error.code).toBe('READ_SCOPE_COMPILE_FAILED')`

packages/runtime/src/dispatcher-plugin.ts

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,8 @@ function sendResultBase(
450450
* the RLS POLICY the tenant is being filtered by:
451451
*
452452
* ```
453+
* ⚠️ PAST TENSE — the leak this entry CLOSED, not what this exit answers today.
454+
* For the current body see the corrected shape at the end of this block.
453455
* POST /analytics/query (tenant caller, object with a broken sharing rule)
454456
* → 500 {"success":false,"error":{"message":"[read-scope-sql] unsafe field
455457
* identifier \"secret_policy_field\" — refusing to build read scope
@@ -464,9 +466,28 @@ function sendResultBase(
464466
* boundaries. ⛔ It is NOT "withhold every 5xx" — #5667 kept UNDECLARED 5xx
465467
* legible on purpose, and a bare `Error` still goes through the heuristic alone.
466468
*
467-
* The code still travels: `details.code` (#3842, below) carries
468-
* `READ_SCOPE_COMPILE_FAILED` to the client untouched, so what a machine reads is
469-
* unchanged and only the prose is withheld — into `errorReporter` and the log.
469+
* The code still travels, and `READ_SCOPE_COMPILE_FAILED` reaches the client
470+
* untouched — so what a machine reads is unchanged and only the prose is withheld,
471+
* into `errorReporter` and the log.
472+
*
473+
* ⚠️ It reaches the client at `error.code` — NOT `error.details.code`, which is
474+
* where this note pointed until #6270 corrected it (#6123 corrected the same
475+
* sentence at three sibling sites). The `details` assembly below (#3842) only
476+
* STAGES the code in a local object; `buildApiError` then runs
477+
* `splitSemanticCode` (`./error-envelope.ts`), which PROMOTES it into the declared
478+
* `ApiErrorSchema` field and returns the now-empty `details` as `undefined` — so
479+
* the key is omitted from the body and `error.details.code` is never present to
480+
* read. Do not mistake the local variable name for the wire contract. The measured
481+
* 500 body is exactly:
482+
*
483+
* ```json
484+
* {"success":false,"error":{"code":"READ_SCOPE_COMPILE_FAILED",
485+
* "message":"Internal server error","httpStatus":500}}
486+
* ```
487+
*
488+
* Pinned end-to-end in `analytics-query-read-scope-withhold.test.ts`, which
489+
* asserts the code at `error.code` against a real `AnalyticsService` on a real
490+
* mounted route.
470491
*/
471492
function errorResponseBase(err: any, res: any, securityHeaders?: Record<string, string>): void {
472493
const validation = validationFailureDetails(err);

0 commit comments

Comments
 (0)