Skip to content

feat(objectql,spec,client,metadata-protocol)!: #4286 收官 — having 落地执行,cursor/distinct 连同 SDK 生产者移除 - #4307

Merged
os-zhuang merged 4 commits into
mainfrom
claude/queryast-executor-liveness-ledger-tbg5sf
Jul 31, 2026
Merged

feat(objectql,spec,client,metadata-protocol)!: #4286 收官 — having 落地执行,cursor/distinct 连同 SDK 生产者移除#4307
os-zhuang merged 4 commits into
mainfrom
claude/queryast-executor-liveness-ledger-tbg5sf

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

按裁决执行 #42863、4 步(前置分析见 issue 讨论;第 1/2/5 步已由 #4294 合并)。趁 17 发布窗口,三项破坏性收拢在同一未发布 major。两个 commit,可分开审:

Commit 1 — having ENFORCE(6c0b13d,非破坏)

裁决理由:groupBy+aggregations+having 是模型先验里的固定搭配——enforce 是唯一让先验与平台一致的选项。落地:

  • 引擎持有语义:applyHaving()(objectql/src/having-filter.ts)在聚合之后统一应用,原生驱动路径与内存兜底路径完全一致——沿用 dateGranularity 的 correct-first / optimize-later 两层模式,将来 SQL 原生 HAVING 下推挂驱动能力旗即可,语义不变。
  • 命名空间 = 聚合结果行自己的列(聚合别名 + groupBy 投影),标准 FilterCondition 算子 + $and/$or/$not
  • 未知算子响亮拒绝:容忍式 matcher 会忽略未知算子,在 HAVING 上那等于静默返回未过滤聚合——正是本次要消灭的 ADR-0078 失败模式,所以直接抛错并列出支持集。
  • 线上路径打通(finding 1 的修复):EngineAggregateOptionsSchema 声明 having;findData 聚合分支转发;ast 携带它使 FLS 谓词卫兵(早已遍历 having)看得到调用者输入——上一个 PR 特意保留那段遍历,就是为今天。
  • 无迁移:此前带 having 的查询是静默返回全部分组,现在按字面过滤——这就是 enforcement 本身。

Commit 2 — cursor / distinct REMOVE(9484d1a,破坏性)

  • cursor:无任何驱动实现 keyset,游标被接受并忽略——每页都是第一页,while (hasMore) 永不终止。QuerySchema + EngineQueryOptionsSchema 双点墓碑(共享处方),QueryBuilder.cursor() 删除。处方指向手动 keyset(sort key 上的 where 谓词,文档既有正解);将来真做 first-class cursor 应是响应侧铸造的不透明 token,与今天这个调用者拼的 record 是不同 API——保留只会保存一个错误设计。⚠️ listRevisions/flow-runs/notifications 的 cursor: string 参数是那些端点自己的活 token 分页,未动(ledger 注记已写明)。
  • distinct:比死键更糟的 mis-wired(finding 2)——唯一可观测效果是 REST 列表 count 抑制:调用者拿到重复行 + 退化的 total/hasMore,而这个副作用还会让自验证的 agent 误信旗标生效。三点墓碑(QuerySchema / EngineQueryOptionsSchema / ?distinct querystring 拼写 HttpFindQueryParamsSchema),QueryBuilder.distinct() 删除,count 抑制分支一并删除——受影响查询的 total 恢复真实(可观测 REST 变化,changeset 已明示)。每聚合项 AggregationNode.distinct(活)不受影响。
  • 双双注册为 protocol-18 semantic migration(query-cursor-retired / query-distinct-retired)——请求面,无源可改写,[P3] data: FieldNode's nested-select object form is declared but nothing produces or consumes it — enforce or remove #4196 先例。

Ledger 收官

liveness/query.json:havinglive(端到端证据),cursor/distinct 翻 REMOVED 注记(墓碑使键留在 walked shape,行保留)。闸门现报 query 27 classified (live 16, experimental 7, dead 4)——dead 4 全部是已墓碑化的移除项,#4286 的 enforce-or-remove 工单在请求面上闭环,issue 可关

验证

  • 新增测试:having 求值器 8 例(含未知算子拒绝)+ 引擎双路径 6 例(原生/内存语义一致、别名命名空间、未知算子拒绝)+ REST 转发针脚;cursor/distinct 退休 pin(处方正文、空值也拒、替代写法可解析、?distinct querystring 拒绝、EngineQueryOptions 双拒)。
  • 全量套件:spec 7132 / objectql 1360 / client 204 / metadata-protocol 122 / plugin-security 677 全绿;tsc --noEmit 干净;spec 14 个闸门全 PASS;check:generated 产物按裁定窄向重生成(api-surface 新增两个导出的处方常量;authorable-surface 三键翻 [RETIRED]EngineAggregateOptions:having 新增)。
  • changeset ×3:having(spec/objectql/metadata-protocol minor)、cursor(spec/client major)、distinct(spec/client major + metadata-protocol minor,count 恢复已注明)。
  • 文档与 objectstack-query skill 同步:HAVING 从「protocol only/后置过滤 workaround」翻为已执行语义;keyset 与 distinct 小节改为移除记录 + 活拼写。

🤖 Generated with Claude Code

https://claude.ai/code/session_012K2BX3WQwPBA2ZBehqJUBX


Generated by Claude Code

claude added 2 commits July 31, 2026 04:44
…gine applies it after aggregation (#4286 step 3)

ADR-0049 resolved to ENFORCE: having was the one declared member every
SQL-literate author expects to work next to groupBy/aggregations, and its
gap was structural (finding 1 — aggregate() rebuilt the driver AST without
it, and the findData aggregate branch dropped it on the wire).

- applyHaving() (objectql/src/having-filter.ts) runs AFTER aggregation on
  the native-driver path and the in-memory fallback alike; namespace is the
  aggregated row's own columns (aggregation aliases + groupBy projections).
  An unknown operator rejects loudly — ignoring one would silently return
  unfiltered aggregates, the ADR-0078 failure enforcement exists to end.
- EngineAggregateOptionsSchema declares having; findData's aggregate branch
  forwards it; the ast carries it so the FLS predicate guard (which already
  walked having references) sees caller input.
- Native SQL HAVING pushdown can come later behind a driver capability flag
  (the dateGranularity two-tier pattern) without changing semantics.
- Ledger: query.having flips dead → live with end-to-end evidence; docs and
  the objectstack-query skill stop teaching the app-code post-filter
  workaround.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012K2BX3WQwPBA2ZBehqJUBX
…ry.distinct with their SDK producers (#4286 step 4)

ADR-0049 resolved both to REMOVE. Neither ever had an executor:

- cursor promised keyset pagination no driver implemented — accepted and
  ignored, every page identical, so a caller looping "until hasMore" never
  terminated. Tombstoned on QuerySchema and EngineQueryOptionsSchema (one
  shared prescription); QueryBuilder.cursor() deleted. The manual keyset (a
  where predicate on the sort key) is the documented pattern; a first-class
  cursor, if ever designed, will be a response-minted opaque token. The
  cursor params on listRevisions/flow-runs/notifications are those endpoints'
  own live tokens — untouched.
- distinct was MIS-WIRED, not merely dead (finding 2): its only observable
  effect was suppressing the REST list count, so callers got duplicate rows
  AND degraded total/hasMore — a side effect that "confirmed" a capability
  that never ran. Tombstoned on both schemas plus the ?distinct querystring
  spelling (HttpFindQueryParamsSchema); QueryBuilder.distinct() deleted; the
  countable suppression branch deleted — total is truthful again (the
  observable REST change, carried in the changeset). AggregationNode.distinct
  (per-aggregation dedupe) is a different, live member and stays.

Both register as protocol-18 semantic migrations (query-cursor-retired,
query-distinct-retired) — request shapes, nothing stored to rewrite. Ledger
entries flip to REMOVED notes (rows stay: retiredKey keeps each key in the
walked shape); docs and the objectstack-query skill teach the live spellings.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012K2BX3WQwPBA2ZBehqJUBX
@vercel

vercel Bot commented Jul 31, 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 Jul 31, 2026 5:32am

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation protocol:data tests tooling size/xl labels Jul 31, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 4 package(s): @objectstack/client, @objectstack/metadata-protocol, @objectstack/objectql, @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/skills-reference.mdx (via packages/client, @objectstack/spec)
  • content/docs/ai/skills.mdx (via @objectstack/spec)
  • content/docs/api/client-sdk.mdx (via @objectstack/client, @objectstack/spec)
  • content/docs/api/data-flow.mdx (via @objectstack/client)
  • content/docs/api/environment-routing.mdx (via @objectstack/client, @objectstack/spec)
  • content/docs/api/error-catalog.mdx (via @objectstack/client, @objectstack/spec)
  • content/docs/api/error-handling-client.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-server.mdx (via @objectstack/spec)
  • content/docs/api/index.mdx (via @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 @objectstack/metadata-protocol, @objectstack/objectql, packages/spec)
  • content/docs/concepts/north-star.mdx (via packages/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 packages/objectql, @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/migration-from-objectql.mdx (via @objectstack/objectql)
  • content/docs/deployment/troubleshooting.mdx (via @objectstack/spec)
  • content/docs/deployment/validating-metadata.mdx (via @objectstack/spec)
  • content/docs/deployment/vercel.mdx (via @objectstack/objectql)
  • 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/client, @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/data-service.mdx (via packages/client)
  • content/docs/kernel/runtime-services/email-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/index.mdx (via packages/client, 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/objectql, @objectstack/spec)
  • content/docs/kernel/services.mdx (via @objectstack/objectql, @objectstack/spec)
  • content/docs/permissions/authentication.mdx (via @objectstack/client, @objectstack/objectql)
  • 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/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/objectql, @objectstack/spec)
  • content/docs/plugins/packages.mdx (via @objectstack/client, @objectstack/objectql, @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/i18n-standard.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/index.mdx (via @objectstack/objectql, @objectstack/spec)
  • content/docs/protocol/kernel/lifecycle.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/plugin-spec.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/realtime-protocol.mdx (via @objectstack/client)
  • content/docs/protocol/kernel/runtime-capabilities.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 packages/objectql, @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/objectql, @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/client, @objectstack/objectql, @objectstack/spec)
  • content/docs/releases/index.mdx (via @objectstack/spec)
  • content/docs/releases/v12.mdx (via @objectstack/spec)
  • content/docs/releases/v13.mdx (via @objectstack/spec)
  • content/docs/releases/v16.mdx (via @objectstack/client, @objectstack/spec)
  • content/docs/releases/v17.mdx (via @objectstack/spec)
  • content/docs/releases/v9.mdx (via @objectstack/objectql, @objectstack/spec)
  • content/docs/ui/actions.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/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.

…ng the removed cursor key (#4286)

Found via the docs-drift advisory on #4307: the 'Query is slow' checklist
still demonstrated cursor: { id: lastSeenId } — the key the same PR
tombstones. The example now expresses the keyset as a where predicate on
the sort key, matching the pattern every other page teaches.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012K2BX3WQwPBA2ZBehqJUBX
@os-zhuang
os-zhuang marked this pull request as ready for review July 31, 2026 05:48
@os-zhuang
os-zhuang merged commit b09d8d9 into main Jul 31, 2026
17 checks passed
@os-zhuang
os-zhuang deleted the claude/queryast-executor-liveness-ledger-tbg5sf branch July 31, 2026 05:48
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 protocol:data size/xl tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants