Skip to content

feat(spec)!: retire datasource.capabilities — 十一个无人读的标志,其中一个是安全声明(#4583 批 A) - #4601

Merged
os-zhuang merged 2 commits into
mainfrom
claude/auth-gate-disconnect-issues-6wz8ew
Aug 2, 2026
Merged

feat(spec)!: retire datasource.capabilities — 十一个无人读的标志,其中一个是安全声明(#4583 批 A)#4601
os-zhuang merged 2 commits into
mainfrom
claude/auth-gate-disconnect-issues-6wz8ew

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

#4583批 A。B/C/D(retryPolicy / healthCheck / external 两键)留在那条 issue 下可并行认领。

问题

DatasourceCapabilities 声明了十一个布尔位 —— transactions、七个 query*joinsfullTextSearchreadOnlydynamicSchema —— 全部 strict 校验,全部无人读取。下推判断读的是运行时 driver 自己的 supports.*objectql/src/engine.ts:3671, :4529, :4810),是另一套机制:一个声明 queryAggregations: false 的 datasource 从未因此改变过引擎走哪条路径。

所以这里是 remove 而非 enforce —— 对面没有可连接的东西。这也是 #4487 判定时给这十一条写的 authorHint 无一例外都是 "Delete it" 的原因。

readOnly:这不是顺手清理

它读起来像安全属性,也确实被当作安全属性来写。examples/app-crm 里一个标着 "CRM Analytics Read Replica" 的 datasource 就靠它声称只读,而那个 datasource 和主库一样照常接受写入。

更值得记一笔的是它的履历:这个键已经被搬过两次,每次都是朝着"也许那边会强制执行"的方向 —— #4410 把它移出 config#4465 把它移进 capabilities —— 每一个地址上都是惰性的。本 PR 删掉它,而不是搬第三次。

而且直到这次改动之前,packages/spec/src/data/driver/common.zod.tsREAD_ONLY_BELONGS_ON_DATASOURCE(所有 SQL driver 共享的处方)仍在把作者指向这个键。一条落在惰性键上的处方,恰好制造出它本要纠正的那个误解。

删掉它并没有给作者替代方案,报错必须说清这一点

账本原本给的替代是 external.allowWrites: false。读一下 assertWriteAllowed

// No recorded definition, or an explicitly managed one ⇒ allow.
if (!ds || !ds.schemaMode || ds.schemaMode === 'managed') return;

它只管联邦库。 对一个本地的、managed 的 datasource(crm 那个正是),这个键同样是惰性的 —— 把作者从一个惰性键指向另一个惰性键,就是把本次要退役的缺陷洗一遍再发出去。

managed datasource 目前根本没有只读闸门。这个缺口是 #4584,本 PR 刻意不就地发明机制(照 #4479 的先例)。墓碑因此明说了它不适用于哪种情况,并建议在数据库侧用 SELECT-only 账号 —— 那是真边界。

顺带闭合的一条调用图

DriverDefinition.capabilities 一并删除,不是"顺着 datasource 侧判死":MemoryDriverSpec / MongoDriverSpec 只被它们自己的测试引用,无任何运行时消费者,所以整个 schema 对象都是惰性的。

路线与产物

strict-removal(两个形状都是 .strict()):键离开 walked shape ⇒ 11 条账本行删除而非改状态(留着会被 orphans.mts 判 ORPHAN)。

验证

  • 三个拒绝测试作回归钉(datasource.test.ts):写 capabilities 被拒;写顶层 readOnly 的报错同时包含 external.allowWrites managed —— 后者是防止处方退化成"改个键名"的钉子;driver definition 上的 capabilities 同样被拒
  • 全仓 pnpm build / pnpm test132 tasks 全绿)/ pnpm typecheck / pnpm lint 全部通过
  • 六个闸门绿:check:livenesscheck:empty-statecheck:variant-docscheck:strictness-ledgercheck:generatedcheck:i18n,外加 check-slot-lookup-ratchet
  • 生成物已重跑:gen:spec-changes / gen:upgrade-guide / gen:api-surface / gen:docs
  • 手写文档 quick-reference.mdx 的类型表已去掉 DatasourceCapabilities;⛔ content/docs/releases/ 未触碰

datasource 账本:dead 20 → 9(剩 healthCheck ×3、retryPolicy ×4、external ×2 = 批 B/C/D)。

给 reviewer 的两点


Generated by Claude Code

…ad, one a safety claim (#4583)

DatasourceCapabilities declared eleven booleans — transactions, seven query*
flags, joins, fullTextSearch, readOnly, dynamicSchema — all strict-guarded, all
read by nothing. Pushdown is decided by the runtime driver's own `supports.*`, a
different mechanism, so declaring `queryAggregations: false` never once changed
which engine path ran. Removed rather than bridged: there was nothing on the
other side to connect it to.

readOnly is why this is not tidy-up. It reads as a safety property and was
authored as one — the shipped CRM example labelled a datasource "CRM Analytics
Read Replica" on its strength while the datasource took writes like the primary.
The key had already been MOVED twice toward somewhere it might be enforced (out
of `config` in #4410, into `capabilities` in #4465) and was inert at every
address. This removes it instead of moving it a third time.

Removing it does NOT hand the author a replacement, and the rejection says so.
`external.allowWrites: false` is the one enforced write gate and applies only to
FEDERATED datasources — assertWriteAllowed returns early for a managed (or
unset-schemaMode) one, so that key would be equally inert for a local database. A
managed datasource has no read-only gate at all; that gap is #4584, deliberately
not invented here.

Also fixed: READ_ONLY_BELONGS_ON_DATASOURCE — the prescription every SQL driver
shares for a `readOnly` written inside `config` — was still sending authors TO
the removed key. A prescription that lands on an inert key manufactures exactly
the belief it was meant to correct.

DriverDefinition.capabilities goes with it: its call graph is closed too —
MemoryDriverSpec / MongoDriverSpec are referenced only by their own tests, so the
whole schema object is inert, not just the datasource-side use.

Route is strict-removal (both shapes are .strict()): keys leave the walked shape,
so the 11 ledger rows are DELETED rather than flipped, and the 13 baseline lines
in authorable-surface.json are removed deliberately in this PR — the readReplicas
(#4468) precedent. ADR-0087 conversion `datasource-capabilities-removed` is
registered in step 17, so `os migrate meta --from 16` really does rewrite author
sources rather than the tombstone merely claiming it.

datasource ledger: 20 dead -> 9 (healthCheck x3, retryPolicy x4, external x2 —
batches B/C/D of #4583). Strictness-ledger site count 9 -> 8.

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

vercel Bot commented Aug 2, 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 2, 2026 10:53am

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation protocol:data tests tooling size/l labels Aug 2, 2026
@github-actions

github-actions Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

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

107 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 @objectstack/spec)
  • content/docs/ai/skills.mdx (via @objectstack/spec)
  • content/docs/api/client-sdk.mdx (via @objectstack/spec)
  • 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/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 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 @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/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/spec)
  • content/docs/kernel/services.mdx (via @objectstack/spec)
  • 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/spec)
  • content/docs/plugins/packages.mdx (via @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/spec)
  • content/docs/protocol/kernel/lifecycle.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/plugin-spec.mdx (via @objectstack/spec)
  • 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 @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/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/spec)
  • content/docs/releases/v17.mdx (via @objectstack/spec)
  • content/docs/releases/v9.mdx (via @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.

@os-zhuang
os-zhuang marked this pull request as ready for review August 2, 2026 09:47
@os-zhuang
os-zhuang enabled auto-merge August 2, 2026 09:48
Conflict was in `content/docs/references/data/datasource.mdx` — a GENERATED
file, conflicting because both sides regenerated it: main's #4595 taught the
generator to spell import examples from the real export surface, while this
branch removed `DatasourceCapabilities` from that surface.

Resolved by regenerating rather than hand-merging. The result is exactly what
the two changes imply together — #4595's corrected spelling minus the removed
export:

  import { DatasourceSchema, DriverDefinitionSchema, DriverType,
           ExternalDatasourceSettingsSchema } from '@objectstack/spec/data';

#4595 also added an import-surface baseline, which listed
`data/DatasourceCapabilities — no type export` as a known gap. This removal
closes that gap, and the baseline is shrink-only, so the stale line is deleted
(--update-import-baseline) — a stale exemption would otherwise stay available
to excuse the NEXT missing export.

The three auto-merged baseline JSONs (authorable-surface, api-surface,
json-schema.manifest) were not trusted as merged text: `gen:schema` rewrites
them wholesale once its vanished-key gate passes, and the full build confirms
no residue of either side's removals.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E5CYr5SDwe85gH2Jr5KSgu
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/l tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants