Skip to content

docs(spec,drivers): managed-datasource read-only is a database privilege, not a platform gate (#4584) - #7241

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-4584-managed-readonly-docs
Aug 10, 2026
Merged

docs(spec,drivers): managed-datasource read-only is a database privilege, not a platform gate (#4584)#7241
os-zhuang merged 2 commits into
mainfrom
claude/issue-4584-managed-readonly-docs

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Executes the standing #4584 ruling verbatim. Docs-only — no platform gate is built, and no schema shape changes.

The ruling

From comment 5163028174 (2026-08-03), quoted untranslated:

裁决(PM 代决,维护者可否决):方案 B —— 不建平台层只读闸门,文档明确记录

两轴理由:

执行(docs-only,一并处理):

  1. datasource 文档明确「managed 库只读 = 数据库账号权限」,并写入 读副本路由(read/write splitting):真要做的话,从查询路径开始,而不是从 datasource 上加个字段(#4468 移除 readReplicas 后的正式立项位) #4479 的对偶结论(读副本 = 代理端点,平台不路由);
  2. 清理 examples/app-crm/src/datasources/crm.datasource.ts 文件头「等 managed datasource 没有任何只读闸门:external.allowWrites 只管联邦库,本地库声明只读无处可写(#4583 移除 capabilities.readOnly 后的正式立项位) #4584 裁决」的注释。

Premise check (verified on fresh origin/main, f40c5b4)

Premise Verdict
The hand-written datasource docs lack the ruled statement Holds. No GRANT SELECT / database-privilege statement anywhere in content/docs/data-modeling/; the only read-only mentions are the federation gate and a UI-readonly row.
crm.datasource.ts still waits on #4584 Holds. Whether a managed datasource should have a read-only gate at all is #4584 — until that is answered…
The gap the ruling describes is real Holds. ObjectQLEngine.assertWriteAllowed (packages/objectql/src/engine.ts:3397) returns early on !ds.schemaMode || ds.schemaMode === 'managed', before it reads external.allowWrites.

One thing the premise check turned up that the dispatch did not anticipate: packages/spec/src/data/driver/common.zod.ts (READ_ONLY_BELONGS_ON_DATASOURCE) already carries the ruled sentence — "grant the connection SELECT-only at the database instead, which is a real boundary rather than an application-layer flag (#4584)". The spec-side prose was ahead of the docs; only the docs were missing it, which is what this PR fixes.

Changes

content/docs/data-modeling/drivers.mdx — two new sections under Multi-Datasource:

content/docs/data-modeling/external-datasources.mdx — §5 Writes (double opt-in) now states that the gate is federation-only and cross-links; See also links both new sections.

packages/spec/src/data/datasource.zod.ts — the capabilities.readOnly tombstone said Tracked in #4584. It now carries the answer. Prose inside a guidance string only — no key, shape, default or validation behaviour changed, nothing pins the string, and check:docs confirms no generated page moves. Flagged here because the dispatch scoped this PR away from .zod.ts edits beyond prose; leaving a resolved issue described as "tracked" would have contradicted the docs this PR adds.

examples/app-crm/src/datasources/crm.datasource.ts — the crm_analytics header comment records the ruling instead of waiting on it.

.changeset/managed-datasource-readonly-documented.md@objectstack/spec patch + @objectstack/example-crm patch. Added because the diff changes a published package's author-facing rejection message; the repo's changeset-check enforces on every unlabelled PR.

Gates

Gate Result
pnpm --filter @objectstack/spec build ✅ (run before regen — stale-dist trap #7122)
pnpm --filter @objectstack/spec check:docs ✅ 231 generated files in sync
node scripts/check-doc-authoring.mjs ✅ 374 files clean
vitest run src/data/datasource (spec) ✅ 41 passed
vitest run src/conversions (spec) ✅ 199 passed
vitest run lint-liveness-properties (lint) ✅ 28 passed
tsc --noEmit (@objectstack/example-crm)
check-empty-changeset / check-changeset-no-major / check-changeset-fixed

Not touched

content/docs/releases/** and docs/adr/** — untouched, per the standing rule. No schema shape change, no acceptance change, no platform gate built.

Closes #4584


Generated by Claude Code

…ege, not a platform gate (#4584)

#4583 removed `datasource.capabilities.readOnly` — a key that read as a safety
property and gated nothing — and left the gap it exposed pointing at #4584:
`external.allowWrites: false` is the one enforced datasource-wide write gate and
it covers only FEDERATED datasources, so a managed datasource had no read-only
gate at all. #4584 ruled 方案 B: that stays so on purpose, and the docs say so.

An ObjectQL-level flag would stop writes on one path and leave a direct `psql`
session, a migration, a `syncSchema()` DDL statement and any process sharing the
connection string untouched. A boundary that holds in one path is not a
boundary, and one that merely looks like a boundary is worse than none because
it gets trusted — the exact defect #4583 removed. Read-only belongs to the
database account (`GRANT SELECT`), where there is no bypass surface.

Docs-only; no schema shape changes.

- content/docs/data-modeling/drivers.mdx: two new sections under
  Multi-Datasource. "Read-only: grant it at the database, not in metadata" —
  a worked `GRANT SELECT` role, the managed datasource that carries its
  credentials in `config` (an `external` block is rejected there), the DDL /
  schema-sync consequence of a read-only account, why the platform declines the
  flag, and a table of what actually enforces what. "Read replicas: the platform
  does not route" — the #4479 dual conclusion: no query path separates reads
  from writes, so put the replicas behind pgpool / ProxySQL / an RDS reader
  endpoint and point `config` there; that is the correct answer, not a stopgap.
- content/docs/data-modeling/external-datasources.mdx: the double opt-in write
  gate now says plainly that it is federation-only, and links across.
- packages/spec/src/data/datasource.zod.ts: the `capabilities.readOnly`
  tombstone carried "Tracked in #4584". It now carries the answer. Prose only —
  no key, shape or default changed, and `check:docs` confirms no generated page
  moves.
- examples/app-crm: the `crm_analytics` header comment recorded the ruling
  instead of waiting on it.

Closes #4584
@vercel

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

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

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

106 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 @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 @objectstack/spec)
  • content/docs/kernel/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/data-service.mdx (via @objectstack/spec)
  • content/docs/kernel/runtime-services/email-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/examples.mdx (via @objectstack/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 @objectstack/spec)
  • content/docs/kernel/runtime-services/sms-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/storage-service.mdx (via @objectstack/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/permissions/system-context.mdx (via packages/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/http-protocol.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/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/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)

7 release-owned page(s) also reference the affected code. These are read-only:

  • 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/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

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.

@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation protocol:data tooling labels Aug 10, 2026
…#4584)

The ADR-0090 D3 reserved-word ratchet (`check:role-word`) rejected two new uses
of "role" in the read-only section. Both are avoidable rather than genuine
boundaries, so this drops the word instead of taking a baseline waiver:

- prose: "at a role that can only read" → "at an account that can only read";
- SQL: `CREATE ROLE analytics_ro LOGIN PASSWORD …` → `CREATE USER analytics_ro
  PASSWORD …`, which in PostgreSQL is exactly the same statement — `CREATE USER`
  is `CREATE ROLE` with `LOGIN` implied — so the example is unchanged in effect.

`check:role-word` is green (44 baselined files, no new occurrences), as are
check:quick-reference-counts / adr-anchors / org-identifier / release-notes /
release-body and eslint over the changed sources.
@os-zhuang
os-zhuang marked this pull request as ready for review August 10, 2026 04:25
@os-zhuang
os-zhuang added this pull request to the merge queue Aug 10, 2026
Merged via the queue into main with commit c6b6bb4 Aug 10, 2026
39 of 41 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-4584-managed-readonly-docs branch August 10, 2026 04:56
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/m tooling

Projects

None yet

2 participants