Skip to content

fix(client): data.find 的 top/skip 按存在性发射,limit: 0 不再被静默丢弃 (#6485) - #6578

Merged
os-project-manager merged 1 commit into
mainfrom
claude/issue-6485-find-pagination-presence
Aug 8, 2026
Merged

fix(client): data.find 的 top/skip 按存在性发射,limit: 0 不再被静默丢弃 (#6485)#6578
os-project-manager merged 1 commit into
mainfrom
claude/issue-6485-find-pagination-presence

Conversation

@os-project-manager

Copy link
Copy Markdown
Collaborator

Fixes#6485

两处 findObjectStackClient.data.findScopedProjectClient.data.find 的逐字节副本)都以真值判断发射分页参数,而其上方十行的 canonical normalizer 早已按存在性判断(if (v2.limit != null))。于是 0 通过了 normalizer,又被发射端丢掉。两处一并改为 != null

行号漂移

卡片正文记的是 eb7613c 上的 :4224/:4225:4908/:4909;两条分诊评论分别在 b7d3be4 读到 :4104/:4105:4778/:4779,在 3a1d9c7 读到 :4225/:4909。本次在 53ef05744按内容定位,落点回到 :4224/:4225:4908/:4909 —— 与卡片正文数字重合纯属巧合,中间三次读数各不相同。所以按 pattern 找,不要信任何一处记下的行号。

前提复现(改动前,在 origin/main 上量的)

新增断言直接跑在未修复的源码上,6 条红:

FAIL canonical zero: { limit: 0 } → `top=0` on both copies
AssertionError: expected '' to be 'top=0'

{ limit: 0 } 发出的是空查询串 —— 一个 top 参数都没有。

服务端 top=0 到底怎么处理:先测后改

这半边是本卡的关键。客户端把 top=0 发出去,只有在服务端真的认这个值时才算修好。三层都实测过,不是读代码推的:

top=0 的实测行为
REST 列表路由 → ObjectStackProtocolImplementation.findData既不拒绝也不忽略top 折叠进 limitNumber('0') 得 0,{ limit: 0 } 原样转发给引擎;信封给出 total: 0, hasMore: false
SqlDriver.find(默认文件型 SQLite 数据源背后的驱动,也是 Postgres/MySQL 部署用的那个)按存在性分页 —— LIMIT 0零行
TursoRemoteTransport同样按存在性 —— LIMIT ? 绑 0,零行

探针输出:

PROBE top="0" => { engineFindOptions: { limit: 0 }, result: { records: 0, total: 0, hasMore: false } }
PROBE sql-driver => {"limit0_rows":0,"limit2_rows":2,"noLimit_rows":3}

即派发单列的三种结局里的第一种:服务端返回零记录,修复如描述般正确。

顺带纠正卡片正文一处措辞:丢掉 top 之后拿到的不是「服务端默认页大小」—— 这条 GET 列表路由没有默认页大小。实测 no top 一栏返回 3/3 全量。所以 find('task', { limit: 0 }) 的旧行为是「要零条、给全部」,比「给一页」更糟。

offset: 0 / skip: 0:这半边是一致性修改,没有行为后果

明说,不包装成 bug fix:skip=0 本就是服务端默认值,发不发这个参数请求含义相同。改它的理由只有一个 —— 一个发射端不该对同一对参数持两套规则。

测试:结构上保证半边修复必红

复用 #6322 建立的 driveBoth 表格 —— 同一组 options 同时驱动两份 find,比对同一个期望查询串。新增 5 行表项({ limit: 0 } / { offset: 0 } / { top: 0 } / { skip: 0 } / { limit: 0, offset: 0 }),外加一条性质断言:{ limit: 0 }{} 在线上必须可区分(旧代码里两者都发空串,正是这个坍缩本身)。

反向验证:先写下预测,再跑

方向预测红实测红失败断言
两份都回退(= origin/main66expect(direct) L1401
只回退主 client 一份66expect(direct) L1401
只回退 ScopedProjectClient 一份66expect(scoped) L1402

第三行是本卡要的那条约束:只修一份,另一份的 scoped 断言就红。6 条断言没有一条在两个方向都是绿的,所以没有需要从红计数里剔除的「不变量 pin」。

门禁(真实输出,非声明)

  • pnpm --filter @objectstack/client testTest Files 21 passed (21) / Tests 269 passed (269)
  • pnpm --filter @objectstack/client typechecktsc --noEmit 通过;check:test-typecheck: OK — 0 file(s) / 0 error(s)
  • pnpm lint → 无输出(干净)
  • lint.yml 枚举的全部 check:*:37 条根级门禁 + 11 条 spec 门禁全 PASS,含 check:query-options-erasurecheck:route-envelopecheck:error-code-casingcheck:engine-double-contractcheck:nul-bytes
  • turbo run typecheck --filter='./packages/*' --filter='./packages/*/*' --filter='./apps/*'120 successful, 120 total
  • check:i18n / check:i18n-coverage 首轮报的是前置条件未满足(本 worktree 未构建 CLI),不是发现;补齐构建后两条均 PASS(12 config(s), 660 baselined, none new
  • 控制字节自查:grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]' 三个改动文件均无命中;check:nul-bytes OK

Changeset

@objectstack/client: patch。判断依据:这是缺陷修复,不新增 API、不新增选项、不移除能力;行为变化只落在 limit: 0 / top: 0 这一组此前返回明确错误答案的输入上。变更正文把 wire 行为变化写明,以便进入 release notes。

范围外发现

🤖 Generated with Claude Code

https://claude.ai/code/session_017uFVNMmTxLpmfQYiuKM1Yx


Generated by Claude Code

两处 `find`(`ObjectStackClient.data.find` 与 `ScopedProjectClient.data.find`
的逐字节副本)都以**真值**判断发射分页参数,而其上方十行的 canonical
normalizer 早已按**存在性**判断(`if (v2.limit != null)`)。于是 `0` 通过了
normalizer,又被发射端丢掉。两处一并改为存在性判断。
`find('task', { limit: 0 })` 此前到达服务端时**完全没有 `top` 参数**。GET 列表
路由没有默认页大小,所以缺失 `top` 返回的是**全量**匹配集:请求「不要记录」的
调用方拿到了每一条记录,HTTP 200,无任何告警。
方向是先测后改,而非假定:REST 列表路由(`findData`)既不拒绝也不忽略 `top=0`,
它折叠为 `limit: 0` 转发给引擎;`SqlDriver.find`(默认 SQLite 数据源背后的驱动)
同样按存在性分页,语句带 `LIMIT 0`,返回零行。
`offset: 0` / `skip: 0` 同样被丢弃,但那半边是一致性修改、无行为后果——`skip=0`
本就是服务端默认值。改它是因为一个发射端不该对同一对参数持两套规则。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017uFVNMmTxLpmfQYiuKM1Yx
@vercel

vercelBot commented Aug 8, 2026

Copy link
Copy Markdown

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

1 Skipped Deployment
ProjectDeploymentActionsUpdated (UTC)
objectstackIgnoredIgnoredAug 8, 2026 5:47am

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/client.

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

  • content/docs/ai/skills-reference.mdx(via packages/client)
  • content/docs/api/client-sdk.mdx(via @objectstack/client)
  • content/docs/api/data-flow.mdx(via @objectstack/client)
  • content/docs/api/environment-routing.mdx(via @objectstack/client)
  • content/docs/api/error-catalog.mdx(via @objectstack/client)
  • content/docs/getting-started/your-first-project.mdx(via @objectstack/client)
  • content/docs/kernel/runtime-services/data-service.mdx(via @objectstack/client)
  • content/docs/kernel/runtime-services/index.mdx(via packages/client)
  • content/docs/permissions/authentication.mdx(via @objectstack/client)
  • content/docs/plugins/packages.mdx(via @objectstack/client)
  • content/docs/protocol/kernel/realtime-protocol.mdx(via @objectstack/client)
  • content/docs/releases/implementation-status.mdx(via @objectstack/client)
  • content/docs/releases/v16.mdx(via @objectstack/client)
  • content/docs/releases/v17.mdx(via @objectstack/client)

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.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/mteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[finding][client] data.find's pagination params are emitted on truthiness, so { limit: 0 } is dropped exactly like the limit bug #6322 fixed

2 participants

@os-project-manager@claude