Repository navigation
Commit 97cb5c5
Fixes #24339
Clause-②: no
## What this changes
- `docs/adr/0095-authz-kernel-tenant-layer-and-posture-ladder.md`: one
status-line entry (`· **Amended** (2026-10-18, ruling of record
6250748677 on #24164, letter E′) — …`) and one dated blockquote at the
end of D1, just before D2. The note says:
- Layer 0 is inert on 22 objects, each named, which carry no
`organization_id` column.
- `sys_user_preference` carries the organisation column, so Layer 0
bounds it to its organisation, and its declared default is to apply
inside that wall.
- On all 23, Layer 1 silence (no held set carries a row policy for the
object) is to mean the object's declared default row scope, not no
filter.
- The default is a protocol key on the object
(`ObjectSchema.defaultRowScope`, #24338). The platform objects are to
declare it (#24341), the one collection point is to apply it (#24340),
and the registry is to refuse an `extend` contributor that sets or
loosens it (#24341).
- One line of mainstream precedent: Salesforce OWD on the object;
Dataverse ownership type on the table; PostgreSQL `CREATE POLICY ON
table`.
- `docs/adr/0090-permission-model-v2-concept-convergence.md`: one
sentence appended to D12's 2026-10-17 note. That note held the general
case for #24164. The sentence says the case is ruled, points to the
ADR-0095 note, and says #24136 keeps the three conditions and gains no
fourth.
- +29 / −0 in two files. No code and no changeset (docs only).
## A correction to the ruling's sentence (please read)
Ruling E′ item 8 reads "Layer 0 is inert on these objects". Measured,
that is true for 22 of the 23 objects item 3 names.
`sys_user_preference` is `managedBy: 'system-data'` and has no tenancy
opt-out, so registration gives it an `organization_id` column. Under the
`isolated` and `group` postures, Layer 0 walls it to the organisation.
The note says this instead of repeating the ruling's sentence.
The 23 declarers, the key, the collection point and the registry rule do
not change. The dev reported the difference as `needs_decision`
(os-dev-report 6256329876 on #24339). The seat answered A to both
questions (comment 6256351977 on #24339). The maintainer can veto the
correction on this PR.
## Premises, each with its reading
- **P1 fails for one object, so the note is narrower.**
- `node scripts/platform-object-tenancy-census.mjs --json` (exit 0) runs
`resolveInjectedSystemColumns` and `resolveTenantFieldName` from source.
On this PR's head 569c58e it reads `sys_user_preference` as `reach:
in`, `tenantField: organization_id`.
- All 22 objects named in the note read `reach: out`, `tenantField:
null`: 21 because of `managedBy: 'better-auth'` (`sys_api_key` also
because of `tenancy.enabled: false`), and `sys_audit_log` because of
`systemFields.tenant: false`. Its `tenant_id` is a plain attribution
field (ADR-0131 D7).
- plugin-security's Layer 0 inputs agree
(`packages/plugins/plugin-security/src/security-plugin.ts`):
`objectHasOrgIdField` is whether the registered field set has
`organization_id`, and `tenancyDisabled` is the object's two opt-outs.
`computeTenantLayer0Verdict`
(`packages/core/src/security/tenant-layer0-verdict.ts`) answers `none`
only on those two.
- Corroboration: `sys_user_preference`'s unique index is `unique:
'organization'` (ADR-0120 D1), and driver-sql pins the index
`uniq_sys_user_preference_organization_id_user_id_key`.
- Gate: `node scripts/check-platform-object-tenancy-census.mjs`, exit 0.
- **P2: the note writes the ruling's 23 names.** Ruling item 3 and
#24341 name the same 23 objects. #24339's body differs in two places,
and the note follows the ruling in both:
- (i) The card's `sys_oauth_*` glob expands in the tree to 7 objects.
Only `sys_oauth_access_token`, `sys_oauth_refresh_token`,
`sys_oauth_consent` and `sys_oauth_application` are declarers.
`sys_oauth_resource`, `sys_oauth_client_resource` and
`sys_oauth_client_assertion` carry no shipped row policy.
- (ii) The card calls the whole list better-auth-managed, but
`sys_user_preference` is `system-data` and `sys_audit_log` is
`append-only`.
- "The seven SCIM projections" are `sys_scim_user`, `sys_scim_subject`,
`sys_scim_projection_grant`, `sys_scim_identity_tombstone`,
`sys_scim_group`, `sys_scim_group_member` and
`sys_scim_connection_binding`. The tree's eighth `sys_scim_` object,
`sys_scim_connection_credential`, carries `organization_id` and is not a
declarer.
- **P3 holds.** ADR-0090's status line has the entry `· **Amended**
(2026-10-17, ruling of record 6228728551 on #23960, letter B) — …`, and
D12 has the matching dated blockquote, **Amended 2026-10-17 (ruling of
record 6228728551 on #23960, letter B …**. Its last paragraph held "the
general case … for the maintainer's decision on #24164". The appended
sentence answers that.
## Landing order
PR #24398 (#24338, the `defaultRowScope` key) was read once at write
time: it is open and not merged (it is in the merge queue). So the note
cites #24338, not a merge commit, and **this PR lands after #24398**.
Today `defaultRowScope` has zero hits on `origin/main`; the control
`nameField` hits in the same file.
## Size
The card estimated about 15 lines; this PR adds 29. The extra lines come
from spelling out the 22 inert names (the seat's Q2 answer: no glob) and
the `sys_user_preference` sentence.
## Local gates (final head 569c58e)
- `dispatch-gates --commands --repo objectstack-ai/objectstack` with no
paths derives 19 commands from the 2 changed paths. All 19 exit 0.
- `--ran` reconciles: "19 derived, 19 run, 0 NOT-MEASURED, 0 UNRUN",
with every exit code recorded.
- The ADR families:
- `check-adr-links`: "770 relative link destination(s) under docs/adr/
resolve".
- `check-adr-symbol-anchors`: "2357 anchors across 142 records resolve".
- `check:adr-anchors`: OK.
- `check:doc-formula-expressions` needs `@objectstack/formula` and
`@objectstack/lint` built first. Its first run refused with exit 3 for
that prerequisite, which is not a measurement. After the build it exits
0.
- The rest of the farm runs in CI.
## 维护者速读(草稿)
**改了什么:** 本 PR 只改文档,没有代码。
- ADR-0095 的 D1(租户隔离 Layer 0)下加了一段注明日期的说明,状态行加了一条对应记录。
- ADR-0090 D12 的 10 月 17 日说明末尾加了一句交叉引用。
说明的内容是您 10 月 18 日的 E′
裁决:平台身份对象的「默认行范围」由对象自己声明。当用户持有的权限集都没有为某张表写行级规则时,应用这张表声明的默认范围,而不是「不过滤」。
**有一处修正需要您看到。** 裁决第 8 条说「这些对象上组织墙(Layer 0)不起作用」。实测 23 张表里有 22
张是这样。`sys_user_preference`(用户偏好表)带组织列,组织墙会把它限制在本组织内。
- 说明照实写了这一点:这张表仍然声明自己的默认范围(只看自己的偏好),这个默认范围在组织墙之内生效。
- 23 张声明表、规约键、收集点和注册规则都不变。
- 席位已在 #24339 的评论 6256351977 中按 A 答复。
**为什么改:**
- 裁决要求这段说明先于代码落地。后续两张卡以它为前置:#24340(收集点)和 #24341(平台对象声明)。
- 如果照抄原句,ADR 会对 `sys_user_preference` 写出一句与实测相反的话。后来写元数据的 AI
可能因此以为偏好记录跨组织可见,或者以为这张表不受组织墙约束。
**风险与代价(含回滚):**
- 纯文档,不改变任何运行时行为。
- 说明里写的规约键 `ObjectSchema.defaultRowScope` 来自 PR
#24398(#24338)。它还在合并队列里,所以本 PR 要等 #24398 合入之后再合。
- 回滚就是撤销这两处文字,没有其他影响。
**席位意见:**
**你要做的:**
1. 读 ADR-0095 D1 下的新说明,确认 `sys_user_preference` 这处修正可以接受。
2. 等 #24398 合入后,批准或合并本 PR。
如果不同意这处修正,在本 PR 上说明,席位会重开这个问题。
---
_Generated by [Claude
Code](https://claude.ai/code/session_019oFY6Hi35J7atvgVFnmoaK)_
---------
Co-authored-by: Claude <noreply@anthropic.com>
1 parent ee882b8 commit 97cb5c5
2 files changed
Lines changed: 29 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
600 | 600 | | |
601 | 601 | | |
602 | 602 | | |
| 603 | + | |
| 604 | + | |
| 605 | + | |
| 606 | + | |
| 607 | + | |
603 | 608 | | |
604 | 609 | | |
605 | 610 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | 3 | | |
| 4 | + | |
4 | 5 | | |
5 | 6 | | |
6 | 7 | | |
| |||
174 | 175 | | |
175 | 176 | | |
176 | 177 | | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
177 | 201 | | |
178 | 202 | | |
179 | 203 | | |
| |||
0 commit comments