Repository navigation
docs(adr): ADR-0095 D1 note — Layer 0 is inert on 22 of the 23 platform identity objects; Layer 1 silence is to mean the object's declared default row scope (#24164 ruling E′) - #24408
Conversation
…rm identity objects; Layer 1 silence is to mean the object's declared default row scope ADR-0095 gains a dated 2026-10-18 note under D1 and a matching status-line entry for ruling E' (record 6250748677): Layer 0 is inert on 22 named objects that carry no organization_id column; sys_user_preference carries it, so Layer 0 bounds it to its organisation and its declared default is to apply inside that wall (measured by the tenancy census). On all 23, Layer 1 silence is to mean the object's declared default row scope, a protocol key on the object. ADR-0090 D12's 2026-10-17 note points to it: the boundary keeps its three conditions and gains no fourth. Claude-Session: https://claude.ai/code/session_019oFY6Hi35J7atvgVFnmoaK Co-authored-by: Claude <noreply@anthropic.com>
The note cites the ruling comment and all four cards of ruling E': the key, the collection point, the declarations, and this note. Claude-Session: https://claude.ai/code/session_019oFY6Hi35J7atvgVFnmoaK Co-authored-by: Claude <noreply@anthropic.com>
Contract reviewServed-tier: Rules face, the two governed ① Derived judgmentsEvery sentence of the two hunks, named right or wrong against the ruling and the tree at the head.
② Semver levelDocs only: two ③ Boundary flags
Implemented-by: VERDICT: PASS Generated by Claude Code |
维护者速读 · PR #24408 ·
|
| item | reading |
|---|---|
| Shape | Draft, base main, assignee zhuangjianguo. Line 1 is Fixes #24339, line 2 is Clause-②: no, no other closing keyword. 2 files, +29/−0, both governed (check-governed-merges: 2 of 2 paths hit the register; 29 lines, under the human-merge threshold). skip-changeset (docs only). |
| Premises measured | P1 holds for 22 of 23. It fails for sys_user_preference: census reach: in, tenantField: organization_id, re-read by the seat at 78652c093 and by the review at the head. The dev stopped as told, and the seat answered A. P2: the note's 23 names equal ruling item 3 and #24341, with no glob. P3: ADR-0090's 2026-10-17 amendment is at :9 and :535. |
| Gates (check-runs on the head) | 43 runs: 31 success and 11 skipped (check-expected-skips: OK). The one failure is Check Changeset run 117820388210, from before the label; it was superseded by run 117821105107, skipped by the job's own skip-changeset condition. Dev: 19 derived families run, all exit 0, reconciled with --ran. |
| Accepted deviations | +29 lines against the card's "about 15": the 22 spelled-out names and the one sys_user_preference sentence. The card number in the note's heading. |
| Out of scope | The card body's sys_oauth_* glob and its "better-auth-managed" label are inexact. The note does not copy them, and the card stays as filed (answer 6256351977). A pointer on #24164 records the 22 + 1 correction in the ruling's thread, in this act. |
| Landing | After an approval by os-zhuang or hotlong (or the maintainer's merge): pr_ready then automerge_enable. The merge closes #24339, which unblocks #24340 (both its blockers then closed) and #24341. |
Generated by Claude Code
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:organization_idcolumn.sys_user_preferencecarries the organisation column, so Layer 0 bounds it to its organisation, and its declared default is to apply inside that wall.ObjectSchema.defaultRowScope, spec(data):ObjectSchemadeclares an object's default row scope — the existing RLS policy shape minusobject— applied when no held permission set carries a policy for it (#24164 ruling E′) #24338). The platform objects are to declare it (platform-objects: the identity objects declare their default row scope (the literals the shipped sets copy today), and the registry refuses anextendcontributor that loosens a platform object's default (#24164 ruling E′) #24341), the one collection point is to apply it (plugin-security:collectRLSPoliciesapplies an object's declared default row scope when no held set carries a policy for it — the platform identity objects stop depending on every set copying the same literals (#24164 ruling E′) #24340), and the registry is to refuse anextendcontributor that sets or loosens it (platform-objects: the identity objects declare their default row scope (the literals the shipped sets copy today), and the registry refuses anextendcontributor that loosens a platform object's default (#24164 ruling E′) #24341).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 [Decision] The organization administrator's assignment boundary: an assignable set with a wildcard read and no row scope reaches other organizations' SCIM rows in a deployment with no platform baseline #24164. The sentence says the case is ruled, points to the ADR-0095 note, and says plugin-security: organisation admins assign positions and permission sets to their own members inside the D12 boundary — gate branch, overrides, explain and my-delegable-scope, three-posture acceptance (ruling B on #23960) #24136 keeps the three conditions and gains no fourth.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_preferenceismanagedBy: 'system-data'and has no tenancy opt-out, so registration gives it anorganization_idcolumn. Under theisolatedandgrouppostures, 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
node scripts/platform-object-tenancy-census.mjs --json(exit 0) runsresolveInjectedSystemColumnsandresolveTenantFieldNamefrom source. On this PR's head 569c58e it readssys_user_preferenceasreach: in,tenantField: organization_id.reach: out,tenantField: null: 21 because ofmanagedBy: 'better-auth'(sys_api_keyalso because oftenancy.enabled: false), andsys_audit_logbecause ofsystemFields.tenant: false. Itstenant_idis a plain attribution field (ADR-0131 D7).packages/plugins/plugin-security/src/security-plugin.ts):objectHasOrgIdFieldis whether the registered field set hasorganization_id, andtenancyDisabledis the object's two opt-outs.computeTenantLayer0Verdict(packages/core/src/security/tenant-layer0-verdict.ts) answersnoneonly on those two.sys_user_preference's unique index isunique: 'organization'(ADR-0120 D1), and driver-sql pins the indexuniq_sys_user_preference_organization_id_user_id_key.node scripts/check-platform-object-tenancy-census.mjs, exit 0.extendcontributor that loosens a platform object's default (#24164 ruling E′) #24341 name the same 23 objects. docs(adr): ADR-0095 D1 dated note — Layer 0 is inert on the platform identity objects; Layer 1 silence means the object's declared default row scope, a protocol key (#24164 ruling E′; Tier H) #24339's body differs in two places, and the note follows the ruling in both:sys_oauth_*glob expands in the tree to 7 objects. Onlysys_oauth_access_token,sys_oauth_refresh_token,sys_oauth_consentandsys_oauth_applicationare declarers.sys_oauth_resource,sys_oauth_client_resourceandsys_oauth_client_assertioncarry no shipped row policy.sys_user_preferenceissystem-dataandsys_audit_logisappend-only.sys_scim_user,sys_scim_subject,sys_scim_projection_grant,sys_scim_identity_tombstone,sys_scim_group,sys_scim_group_memberandsys_scim_connection_binding. The tree's eighthsys_scim_object,sys_scim_connection_credential, carriesorganization_idand is not a declarer.· **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 security: the 18 migration text says organization admins assign positions and permission sets to their members; the shipped organization_admin sets are read-only on both assignment objects and the server refuses #23960, letter B …. Its last paragraph held "the general case … for the maintainer's decision on [Decision] The organization administrator's assignment boundary: an assignable set with a wildcard read and no row scope reaches other organizations' SCIM rows in a deployment with no platform baseline #24164". The appended sentence answers that.Landing order
PR #24398 (#24338, the
defaultRowScopekey) 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. TodaydefaultRowScopehas zero hits onorigin/main; the controlnameFieldhits 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_preferencesentence.Local gates (final head 569c58e)
dispatch-gates --commands --repo objectstack-ai/objectstackwith no paths derives 19 commands from the 2 changed paths. All 19 exit 0.--ranreconciles: "19 derived, 19 run, 0 NOT-MEASURED, 0 UNRUN", with every exit code recorded.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-expressionsneeds@objectstack/formulaand@objectstack/lintbuilt first. Its first run refused with exit 3 for that prerequisite, which is not a measurement. After the build it exits 0.维护者速读(草稿)
改了什么: 本 PR 只改文档,没有代码。
说明的内容是您 10 月 18 日的 E′ 裁决:平台身份对象的「默认行范围」由对象自己声明。当用户持有的权限集都没有为某张表写行级规则时,应用这张表声明的默认范围,而不是「不过滤」。
有一处修正需要您看到。 裁决第 8 条说「这些对象上组织墙(Layer 0)不起作用」。实测 23 张表里有 22 张是这样。
sys_user_preference(用户偏好表)带组织列,组织墙会把它限制在本组织内。为什么改:
collectRLSPoliciesapplies an object's declared default row scope when no held set carries a policy for it — the platform identity objects stop depending on every set copying the same literals (#24164 ruling E′) #24340(收集点)和 platform-objects: the identity objects declare their default row scope (the literals the shipped sets copy today), and the registry refuses anextendcontributor that loosens a platform object's default (#24164 ruling E′) #24341(平台对象声明)。sys_user_preference写出一句与实测相反的话。后来写元数据的 AI 可能因此以为偏好记录跨组织可见,或者以为这张表不受组织墙约束。风险与代价(含回滚):
ObjectSchema.defaultRowScope来自 PR feat(spec): an object declares its default row scope, defaultRowScope, the RLS policy shape without object #24398(spec(data):ObjectSchemadeclares an object's default row scope — the existing RLS policy shape minusobject— applied when no held permission set carries a policy for it (#24164 ruling E′) #24338)。它还在合并队列里,所以本 PR 要等 feat(spec): an object declares its default row scope, defaultRowScope, the RLS policy shape without object #24398 合入之后再合。席位意见:
你要做的:
sys_user_preference这处修正可以接受。如果不同意这处修正,在本 PR 上说明,席位会重开这个问题。
Generated by Claude Code