Skip to content

fix(analytics,rest)!: read-scope 拒收改判 READ_SCOPE_COMPILE_FAILED/500,路由的 message 正则名单完全退休 - #5808

Merged
os-zhuang merged 5 commits into
mainfrom
claude/issue-5367-readscope-500
Aug 6, 2026
Merged

fix(analytics,rest)!: read-scope 拒收改判 READ_SCOPE_COMPILE_FAILED/500,路由的 message 正则名单完全退休#5808
os-zhuang merged 5 commits into
mainfrom
claude/issue-5367-readscope-500

Conversation

@os-zhuang

@os-zhuang os-zhuang commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Fixes #5367

第二个也是最后一个 PR。前一个(PR #5723,已 merge)信封化五族并把正则名单收到只剩 /read-scope-sql/ 一条;本 PR 按**维护者 2026-08-06 裁决(方案 B)**处理第六族并删掉那最后一条 —— PD #12 的退休时间表至此完整兑现,/analytics/dataset/query 的 catch 里不再有任何按措辞分类的代码。

前提重验

十处拒收在 origin/main 上仍是裸 throw new Error(...),现位置 104 / 138 / 144 / 190 / 209 / 217 / 262 / 267 / 272 / 284;rest-server.ts:6829/read-scope-sql/ 条目原样在。上一个 PR 的五族信封与 dataset-refusal.ts 已在 main(978fed281)。前提成立。

⚠️ 一处派发前提需要更正(先说,因为它改变了实现)

派发单第 2 条写「该 500 进入 #5667looksLikeInternalErrorLeak withhold 路径」。实测:不会进。 那个谓词是对 SQL/驱动措辞的启发式(sqlite_SQLSTATE、以语句开头、约束转储),而 read-scope 的全部十一种 message 形态跑下来全部返回 false:

ECHOED   [read-scope-sql] unsafe field identifier "owner id" — refusing to buil…
ECHOED   [read-scope-sql] unsupported operator "$regex" on "owner" (fail-closed…
ECHOED   [read-scope-sql] "owner" has a nested/relation value which is not supp…
…(11/11 全部 ECHOED)

也就是说:只删名单会把 RLS 策略内容从 400 的 body 搬到 500 的 body,而不是搬出响应。而裁决把「结构性堵泄漏」列为批准方案 B 的依据之一,所以这个验收标准必须真的成立。

两条路:把启发式教会认 [read-scope-sql] —— 那是更多措辞嗅探,正是本单要消灭的机制;或者让 withhold 依据声明。取后者:生产方声明 status >= 500 且带 code,就是声明了「这是服务端故障」,而服务端故障的细节属于运维日志而非调用方 body。 这是对 ADR-0112 信封的结构规则,不是对散文的猜测,而且未声明的 5xx 仍走 #5667 的分级(自产故障 "no strategy can handle query …" 依旧可读)—— 两侧都有用例钉住。

顺带说明这条规则的范围:它是加在本路由 ③ 分支内的三行判断,没有抽成共享谓词。姐妹面 /analytics/querydispatcher-plugin.errorResponseBase 走同一个启发式,因此同样在泄漏;但那是本单之前就存在、且在另一条路由上的既有缺陷,按 PD #10 单独立单(见下),不夹带进本 PR。等第二个边界采用这条规则时再考虑提升到 @objectstack/types(与 looksLikeInternalErrorLeak 同居),现在提升就是没有消费者的推测性面。

做了什么

  1. 十处 500 信封:read-scope-sql.ts 新增模块内readScopeCompileError(READ_SCOPE_COMPILE_FAILED / 500)。放模块内而非共享模块,证据同 filter-normalizer.tsinvalidFilterError:十个拒收点全在这一个文件里,共享模块买不到任何东西,而第二种写法会让「⛔ 本模块唯一的拒收方式」这个不变量失效 —— 这个不变量正是 analytics 的 filter 拒收到不了调用方:service 侧多数拒收没有 ADR-0112 信封,REST 面又用 message 正则嗅探,一律答 500 #5352 用七个裸站点换来的教训。
  2. :104 的 alias/field 分叉随 B 取消:两支同答一个 500,并钉成「已取消」(用例断言两行产出同一 code/status),所以将来若要重新区分必须改那一行 —— 取消是记录在案的决策,不是遗漏。
  3. 正则名单最后一条删除,分支 ② 整体消失。
  4. ledger:READ_SCOPE_COMPILE_FAILEDERROR_CODE_LEDGER@objectstack/service-analytics(ADR-0112 D3),构造器处标注 RegisteredErrorCode,未登记即编译错误。这次 union 确实增长(与上个 PR 的 DATASET_INVALID 不同,那是既有 code),因此 content/docs/references/** 需要重新生成 —— 已按 check:generated --fix 只重生这一项,单独一个 commit,diff 纯粹是枚举里多一个成员。
  5. 为什么值得一个具名 code 而不是 INTERNAL:本路由 ③ 分支会把 code 覆写成 ANALYTICS_QUERY_FAILED,所以在这条路上 code 不上线;但姐妹面 errorResponseBase 会把 err.code 放进 error.details.code(The dispatcher puts the HTTP status in error.code and parks the real code in details — pinned in #3687, still unfixed #3842),所以 READ_SCOPE_COMPILE_FAILED 在那里是机器可读的,加上日志侧的运维分诊 —— 有真实读者,不是装饰。

既有用例逐条改判(不批量放宽)

  1. producer 套件第三段的两例(上个 PR 写的「刻意留裸」,注释里写着「一旦翻转就必须同 PR 删掉路由最后一条」)→ 今天正是那一天:改为断言 READ_SCOPE_COMPILE_FAILED / 500,并加一条负向断言 not.toBe('DATASET_INVALID')。同段的「内部不变量仍是裸 Error」一例保留且加注:它与 read-scope 的差别现在是可观测的 —— 声明 5xx 的被 withhold,未声明的按 fix(service-analytics,rest): analytics dimension 的源字段闸门 —— 不存在的 dimension 答 400 INVALID_FIELD,dataset 500 不再回显 SQL (#5520) #5667 保持可读。
  2. analytics-filter-refusal-envelope.test.ts 保留的那一例(靠名单答 400)→ 改判成两例:声明 500 → 500 + body 不含策略字段名;同一条 message 裸抛 → 也是 500 且可读。后者钉住「名单真的没了」,前者钉住「withhold 真的生效」。文件头「什么绝不能变」的第 1 条(名单还在分类)改写为「已退休」。
  3. analytics-dataset-dimension-gate.test.ts 新增的 ③ 半 → 从 400 改判为 500 + INTERNAL_ERROR_MESSAGE,并把该半的守护目标写清:[17.0-rc2验收] analytics: 不存在的 dimension 500(泄漏 SQL / SQLITE_ERROR)而不是 400 指名字段 —— #4437 只给 measure 加了闸门,dimension 侧对称缺口仍在 #5520 的启发式 withhold 与本单的声明式 withhold 是复合而非互斥。用例名由「4xx branches」改为「classification branches」。
  4. WAREHOUSE_UNAVAILABLE/503 那一例(原本只断言 status+code)→ 补 expect(res.body.error).toBe(INTERNAL_ERROR_MESSAGE)。它现在是这条声明式规则的通用形态用例:规则适用于任何声明的 5xx,不是一张认得的措辞清单。

新增覆盖

  • packages/services/service-analytics/src/__tests__/read-scope-refusal-envelope.test.ts(28 例)—— 两段式:先钉拒收集合没动(11 个输入 × 十个抛出点,quoteIdent 两个 kind 各一行;外加 6 个「必须仍然编译」的 read scope,连编出的 SQL 与 bind 参数一起断言),再钉信封;另有「无半信封」结构断言、「alias/field 同判」断言,以及一条把泄漏当输入的断言 —— message 确实含策略字段名(运维需要),这正是边界必须 withhold 的理由。
  • packages/rest/src/analytics-read-scope-refusal-envelope.test.ts(8 例)—— 五种策略形态端到端穿过真实 AnalyticsService(getReadScope 就是管理员策略进来的那个缝),每例断言:500 / ANALYTICS_QUERY_FAILED / not.toBe(400) / not.toBe('DATASET_INVALID') / body 是 Internal server error / body 不含该策略细节 / body 没有 4xx 的 message 字段 / logError 里有完整原文和该细节(「withheld」只有在运维仍拿到全文时才可接受,所以断言而非假设);外加正面控制(可编译的 read scope 仍然 200 且真的加了 scope)、未声明 5xx 仍可读、声明 4xx 仍走信封分支。

反向验证(方向先预测,后实测)

方向 A —— 把十处改回裸 throw new Error(...) 并重建 service-analytics(路由保持无名单):

  • 预测:producer 两套件第二段共 15 例转红(code/status undefined),第一段与「message 含策略内容」段保持绿;端到端 5 例转红的位置是「泄漏」那一半而不是「分类」那一半 —— 500/ANALYTICS_QUERY_FAILED 仍成立(名单已删,自然落 ③),但 declaredServerFault 为假且启发式不匹配,于是 message 被回显;两条 tiering 用例与正面控制保持绿;另外三个 rest 文件不受影响(自造错误)。
  • 实测:producer Tests 15 failed | 31 passed (46),断言原文 expected undefined to be 'READ_SCOPE_COMPILE_FAILED'expected [ undefined, undefined ] to deeply equal [ 'READ_SCOPE_COMPILE_FAILED', 500 ];rest Tests 5 failed | 40 passed (45),断言原文 expected '[read-scope-sql] unsafe field identif…' to be 'Internal server error'与预测一致。 这条实测本身就是上面那个前提更正的证据:声明一撤,策略内容立刻回到 body。

方向 B —— 把 /read-scope-sql/ 正则加回去(生产方保持信封):

  • 预测:与上个 PR 方向相反。上次五族声明的是 4xx,分支 ① 先答,所以加回名单时端到端文件察觉不到(只有「裸 → 500」那一半能钉住)。这次十处声明的是 5xx,① 明确只管 4xx,于是控制流会落到重新加回的 ② 被截走 —— 端到端文件这次自己就能察觉。预测:端到端 5 例 + filter-refusal 2 例 + dimension-gate ③ 共 8 例转红成 400;五族那个文件全绿。
  • 实测:Tests 8 failed | 45 passed (53),断言原文 expected 400 to be 500,五族文件 1 passed与预测一致,包括那个不对称的反转:名单删除现在由端到端用例直接守护,不再只靠一条伴生断言。

两个方向跑完均已 git checkout 复原并重新验证全绿。(过程记录一笔:方向 A 复原时我对尚未提交的文件用了 git checkout --,把该文件的改动清掉并重做了一遍 —— 后续先提交再做方向 B。)

验证

  • pnpm --filter @objectstack/service-analytics testTest Files 57 passed (57) / Tests 1039 passed (1039)
  • pnpm --filter @objectstack/rest testTest Files 56 passed (56) / Tests 791 passed (791)
  • pnpm --filter @objectstack/spec check:generated → 10/10 up to date(gen:docs 已按 --fix 单项重生并单独 commit)
  • pnpm --filter @objectstack/spec exec tsc --noEmit → 通过
  • lint.yml 门逐条跑全,全部 PASS:check:nul-bytes check:route-envelope check:error-code-casing check:adr-anchors check:role-word check:doc-authoring check:docs-audit-scope check:org-identifier check:authz-resolver check:service-providers check:wildcard-fallthrough check:init-service-contract check:durability-log-level check:startup-registry-verdict check:release-notes check:node-version check:published-files check:engine-double-contract check:resume-authority-declared check:slot-lookup check:query-options-erasure check:type-check-coverage check:objectui-changeset check:workflow-status-functions check:driver-conformance check:i18n
    • check:i18n 首跑九包齐报 extract failed — no output;定位为它调用 packages/cli/bin/run.js 而本 worktree 未建 CLI dist(九包一致失败即该签名),建完 @objectstack/cli...9 package(s) — all bundles in sync。本 PR 不含任何 translation 改动。
  • node scripts/check-nul-bytes.mjs → OK(5681 文件);另按纪律 grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f]' 自扫本 PR 全部改动文件 → clean
  • npx eslint 覆盖本 PR 全部改动文件 → 无输出
  • check:type-check-coverage PASS;两个 DEBT 包直接量 tsc --noEmit:@objectstack/rest 2 errors(与 ledger 记的 2 一致)、@objectstack/service-analytics 7 errors —— 均与改动前同数,且无一条落在本 PR 的文件上
  • 已 merge origin/main(1624f4ad2)后按 §9/§10 refresh build state 并重跑上述全部

范围外发现(已按 #4949 先搜重)

claude added 3 commits August 6, 2026 05:42
…PILE_FAILED/500 and the route's message list is fully retired (#5367)

`read-scope-sql.ts`'s ten fail-closed refusals were the last error family
`/analytics/dataset/query` classified by matching their message text. That
verdict (400 DATASET_INVALID) was wrong twice: the inputs are an admin-authored
RLS policy and a compiler-generated join alias, never the caller's, and the 400
echoed the refusal message, handing a tenant the field names and comparands of
the policy governing them.

Per the maintainer's 2026-08-06 ruling (option B on #5367's decision card):

- read-scope-sql.ts gains a module-local `readScopeCompileError` -- the twin of
  filter-normalizer's `invalidFilterError`, and likewise the only way the module
  refuses. All ten sites declare READ_SCOPE_COMPILE_FAILED / 500. The :104
  alias-vs-field split (option C) collapses under B and is pinned as collapsed.
- rest-server.ts loses branch (2) entirely. Nothing in that catch reads prose
  any more; Prime Directive #12's retirement schedule is paid off in full.
- The 5xx branch withholds the message of any producer that DECLARES a server
  fault. Needed rather than inherited: `looksLikeInternalErrorLeak` is a
  heuristic over SQL/driver phrasing and, measured, returns false for all ten
  read-scope messages, so retiring the list alone would have moved the policy
  content from a 400 body into a 500 body. Widening that heuristic would have
  been more message sniffing; the rule keys on the ADR-0112 envelope instead.
  Undeclared 5xx keeps #5667's tiering and stays readable.
- READ_SCOPE_COMPILE_FAILED registered in ERROR_CODE_LEDGER under
  @objectstack/service-analytics, typed as RegisteredErrorCode at the site.

Visible behaviour change: this family answers 500 instead of 400, with its
message withheld from the body and intact in the log.
@vercel

vercel Bot commented Aug 6, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Aug 6, 2026 6:18am

Request Review

@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 3 package(s): @objectstack/rest, @objectstack/service-analytics, @objectstack/spec.

113 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/ai/agents.mdx (via @objectstack/spec)
  • content/docs/ai/connect-mcp.mdx (via @objectstack/rest)
  • content/docs/ai/skills-reference.mdx (via @objectstack/spec)
  • content/docs/ai/skills.mdx (via @objectstack/spec)
  • content/docs/api/client-sdk.mdx (via @objectstack/spec)
  • content/docs/api/data-api.mdx (via @objectstack/service-analytics)
  • content/docs/api/environment-routing.mdx (via @objectstack/spec)
  • content/docs/api/error-catalog.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-client.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-server.mdx (via @objectstack/rest, @objectstack/spec)
  • content/docs/api/index.mdx (via @objectstack/rest, @objectstack/service-analytics, @objectstack/spec)
  • content/docs/automation/approvals.mdx (via @objectstack/spec)
  • content/docs/automation/connectors.mdx (via @objectstack/spec)
  • content/docs/automation/flows.mdx (via @objectstack/spec)
  • content/docs/automation/hook-bodies.mdx (via packages/spec)
  • content/docs/automation/hooks.mdx (via @objectstack/spec)
  • content/docs/automation/index.mdx (via @objectstack/spec)
  • content/docs/automation/webhooks.mdx (via @objectstack/spec)
  • content/docs/automation/workflows.mdx (via @objectstack/spec)
  • content/docs/concepts/architecture.mdx (via @objectstack/spec)
  • content/docs/concepts/design-principles.mdx (via packages/spec)
  • content/docs/concepts/index.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-driven.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-lifecycle.mdx (via packages/spec)
  • content/docs/concepts/north-star.mdx (via @objectstack/spec)
  • content/docs/data-modeling/analytics.mdx (via @objectstack/spec)
  • content/docs/data-modeling/drivers.mdx (via @objectstack/spec)
  • content/docs/data-modeling/external-datasources.mdx (via @objectstack/spec)
  • content/docs/data-modeling/field-types.mdx (via @objectstack/spec)
  • content/docs/data-modeling/fields.mdx (via @objectstack/spec)
  • content/docs/data-modeling/formulas.mdx (via @objectstack/spec)
  • content/docs/data-modeling/index.mdx (via @objectstack/spec)
  • content/docs/data-modeling/objects.mdx (via @objectstack/spec)
  • content/docs/data-modeling/queries.mdx (via @objectstack/spec)
  • content/docs/data-modeling/schema-design.mdx (via @objectstack/spec)
  • content/docs/data-modeling/seed-data.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation-rules.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation.mdx (via @objectstack/spec)
  • content/docs/deployment/cli.mdx (via @objectstack/spec)
  • content/docs/deployment/tenancy-modes.mdx (via @objectstack/spec)
  • content/docs/deployment/troubleshooting.mdx (via @objectstack/spec)
  • content/docs/deployment/validating-metadata.mdx (via @objectstack/spec)
  • content/docs/getting-started/build-with-claude-code.mdx (via @objectstack/spec)
  • content/docs/getting-started/common-patterns.mdx (via @objectstack/spec)
  • content/docs/getting-started/examples.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-reference.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-start.mdx (via @objectstack/spec)
  • content/docs/getting-started/your-first-project.mdx (via @objectstack/spec)
  • content/docs/kernel/cluster.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/auth-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/cache-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/data-engine.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/index.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/metadata-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/storage-service.mdx (via packages/spec)
  • content/docs/kernel/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/email-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/queue-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sharing-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sms-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/storage-service.mdx (via packages/spec)
  • content/docs/kernel/services-checklist.mdx (via @objectstack/service-analytics, @objectstack/spec)
  • content/docs/kernel/services.mdx (via @objectstack/spec)
  • content/docs/permissions/authentication.mdx (via @objectstack/rest)
  • content/docs/permissions/authorization.mdx (via @objectstack/spec)
  • content/docs/permissions/permission-sets.mdx (via @objectstack/spec)
  • content/docs/permissions/permissions-matrix.mdx (via @objectstack/spec)
  • content/docs/permissions/positions.mdx (via @objectstack/spec)
  • content/docs/permissions/rls.mdx (via @objectstack/spec)
  • content/docs/permissions/sharing-rules.mdx (via @objectstack/service-analytics, @objectstack/spec)
  • content/docs/plugins/adding-a-metadata-type.mdx (via @objectstack/spec)
  • content/docs/plugins/development.mdx (via @objectstack/spec)
  • content/docs/plugins/index.mdx (via @objectstack/rest, @objectstack/spec)
  • content/docs/plugins/packages.mdx (via @objectstack/rest, @objectstack/service-analytics, @objectstack/spec)
  • content/docs/protocol/backward-compatibility.mdx (via @objectstack/spec)
  • content/docs/protocol/diagram.mdx (via packages/spec)
  • content/docs/protocol/kernel/config-resolution.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/http-protocol.mdx (via @objectstack/rest, @objectstack/spec)
  • content/docs/protocol/kernel/i18n-standard.mdx (via packages/rest, @objectstack/spec)
  • content/docs/protocol/kernel/index.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/lifecycle.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/plugin-spec.mdx (via @objectstack/spec)
  • content/docs/protocol/knowledge.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/query-syntax.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/schema.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/security.mdx (via packages/spec)
  • content/docs/protocol/objectql/state-machine.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/actions.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/concept.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/layout-dsl.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/record-alert.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/widget-contract.mdx (via @objectstack/spec)
  • content/docs/releases/implementation-status.mdx (via @objectstack/rest, @objectstack/service-analytics, @objectstack/spec)
  • content/docs/releases/index.mdx (via @objectstack/spec)
  • content/docs/releases/v12.mdx (via @objectstack/rest, @objectstack/spec)
  • content/docs/releases/v13.mdx (via @objectstack/spec)
  • content/docs/releases/v16.mdx (via @objectstack/spec)
  • content/docs/releases/v17.mdx (via @objectstack/rest, @objectstack/service-analytics, @objectstack/spec)
  • content/docs/releases/v9.mdx (via @objectstack/service-analytics, @objectstack/spec)
  • content/docs/ui/actions.mdx (via @objectstack/spec)
  • content/docs/ui/apps.mdx (via @objectstack/spec)
  • content/docs/ui/create-vs-edit-form.mdx (via @objectstack/spec)
  • content/docs/ui/dashboards.mdx (via @objectstack/spec)
  • content/docs/ui/field-grouping-and-order.mdx (via @objectstack/spec)
  • content/docs/ui/forms.mdx (via @objectstack/spec)
  • content/docs/ui/index.mdx (via @objectstack/spec)
  • content/docs/ui/public-data-collection.mdx (via @objectstack/spec)
  • content/docs/ui/setup-app.mdx (via @objectstack/spec)
  • content/docs/ui/translations.mdx (via @objectstack/spec)
  • content/docs/ui/views.mdx (via @objectstack/spec)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

claude added 2 commits August 6, 2026 06:13
…etired `endpoints` (#5674)

`analytics-read-scope-refusal-envelope.test.ts` was written from a sibling
analytics test before #5674 landed, so its `getDiscovery` double carried
`endpoints: {}` -- the dispatcher-only copy of `routes` that #4828 retired under
ADR-0049 and that no producer ever emitted. #5674 corrected the 26 existing
doubles and added `discovery-double-retired-key.test.ts` to pin the key out of
the fixture layer; this file arrived after that sweep and reintroduced it.

Corrected to the producer's real shape -- `routes: { data: '', metadata: '' }`,
`ApiRoutesSchema` as `DiscoverySchema` requires it -- matching the three sibling
analytics doubles verbatim. The key was inert here (nothing in this file drives
discovery), which is exactly the reason it kept surviving retirement, so this is
the double being made faithful to its producer rather than a guard being
satisfied.
@os-zhuang
os-zhuang marked this pull request as ready for review August 6, 2026 06:57
@os-zhuang
os-zhuang added this pull request to the merge queue Aug 6, 2026
Merged via the queue into main with commit fb3d99b Aug 6, 2026
25 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-5367-readscope-500 branch August 6, 2026 07:08
baozhoutao pushed a commit that referenced this pull request Aug 6, 2026
CI 在 b8433ca 上判红:@objectstack/rest 记 136,实测 140。原因不是量错了 ——
`pull_request` 运行编译的是「分支 merge 进当前 main」的树,而 sweep 之后 main
又落地了三个动 packages/rest 的 PR(#5808 / #5821 / #5806)。合并 main 后重量
得 143,tests 56 -> 58,其余 33 条纹丝不动。

这个竞态是引导期的一次性成本,不是常态:本不变式上了 main 之后,引入错误的那个
PR 自己会红 —— 这正是它的目的。写进 MEASURED 的文档块和 rest 的 note,下一个做
全量重测的人不必再自己发现一遍。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01559M8FVm6W6vDLABL3jvdW
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/xl tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

analytics dataset 路由的 message 正则兜底没有退休时间表:六族拒收仍靠措辞分类,改一个字就换一个 HTTP 码

2 participants