Skip to content

Commit 7cda377

Browse files
docs(adr): ADR-0090 D12 names the organization administrator's assignment boundary; ADR-0131 D3 notes it (#24163)
Fixes #24135 Clause-②: no ## Summary Executes the maintainer's ruling of record `6228728551` on #23960 (letter B, 「同意」): the boundary for what an organization administrator may assign is declared in the ADRs first, so the `plugin-security` card (#24136, `Blocked-by:` this one; it remains open) can enforce it. - **ADR-0090** (`docs/adr/0090-permission-model-v2-concept-convergence.md`): one status-line entry (the ADR's own convention for amendments, beside the 2026-10-15 entry for ruling `6181988435`) and one dated note under D12, `Amended 2026-10-17` — the form D11's 2026-10-14 note uses. D12 now names three kinds of administrator (tenant-level, organization-level, delegated); the organization-level kind creates and removes `sys_user_position` / `sys_user_permission_set` rows for its own organization's members when every distributed set has no wildcard superuser bit, no `adminScope` and only `scope: 'org'` capabilities; `admin_full_access`, platform sets, `organization_admin` itself and every delegated set stay outside; organization-administrator status is conferred by membership grade only. Strict containment and the `everyone` / `guest` anchors are unchanged. Ruling item 4's denylist names the three D10 agent ceilings, which the three conditions mis-settle; the general case behind them is held for the maintainer's decision on #24164. The D12 text above the note is not rewritten. - **ADR-0131** (`docs/adr/0131-total-organization-ownership-no-null-organization-id.md`): one dated note under D3's assignment paragraph, pointing at the D12 boundary as the rule that sentence runs under. It inherits the denylist by reference. - No code, no `packages/spec` key, no test, no migration text. The v18 entry's `replacement` text (`18.walled-catalog-tenant-writes-retired`) stays as published. ## Patch round 1 (contract review `6232429140` on head `b0173e29c`, FAIL) The review found precision 5 of the previous head wrong for this boundary: the three D10 agent ceilings pass the three conditions mechanically but are not wall-bounded on their own. Re-measured here before editing, on `origin/main` `eda6f14b7b`: `mcp_agent_data_read` is `objects: { '*': { allowRead: true } }` with no `rowLevelSecurity` (`default-permission-sets.ts:1427`–`:1435`); the seven SCIM projection objects are `tenantField: null`, `reach: out` in `scripts/platform-object-tenancy-census.json`; `fallbackPermissionSet: null` composes the human baseline to `[]` (`app-default-permission-set.ts:40`–`:57`). The head `61c8a5d34` therefore: 1. moves `mcp_agent_data_read`, `mcp_agent_data_write` and `mcp_agent_restricted` (the last by kind: an agent ceiling is not a person's set) from "Inside" to "Outside (denylist)" in the D12 note's measured paragraph, with the reason — an agent ceiling's bound is the delegating principal's own grants (D10 rule 1), not the organization wall; held by a person as a direct grant, the two reading ceilings carry no row scope on the Layer-0-inert SCIM projection tables, and in a walled deployment with no platform baseline they read every organization's rows there, a read the granting organization administrator does not hold; 2. replaces "names no set at this date" with "names those three sets", keeping the clause that a set shipped later that the conditions cannot settle joins the denylist by an amendment; 3. adds one sentence: the general case — an authored set with a `'*'` read and no row scope on a Layer-0-inert readable object, in a deployment with no platform baseline — is not settled by the note and is held for the maintainer's decision on #24164. No fourth condition is written; 4. tightens "refuses from every non-system writer" to "refuses from every writer": `reserved_identity_position` takes no provenance exemption (`sys-user-position.object.ts:225`–`:265`). The rule paragraph of the note (the three conditions and the by-name exclusions) is unchanged; the denylist lives in the measured paragraph, as the review prescribed. ## Mechanism assumptions, measured on `origin/main` `eda6f14b7b` - **A1 — holds.** ADR-0090 keeps amendments as dated `· **Amended** (…)` status-line entries (`:4`–`:8`), and a superseding change also gets a dated blockquote in the decision itself (D11's `> **Amended 2026-10-14 …**`; D3 / D5 / D8 carry `> **Note (2026-10-14) …**`). The 2026-10-15 D12 amendment is status-line only. This PR uses both: the status line, and an `Amended 2026-10-17` blockquote at the end of D12 (D12 now at `:515`). - **A2 — holds.** ADR-0131 D3's assignment paragraph is `:322`–`:328`. ADR-0131 itself already uses `> **Note (2026-10-14) — …**` blockquotes (`:66`); the note follows that form. No status-line entry was added to ADR-0131: the note changes no D3 text (its inline 2026-10-10 withdrawal at `:315` set the precedent of a note without a status entry). - **A3 — holds, with the exact fields.** `packages/spec/src/security/capabilities.ts:33` declares `PlatformCapability.scope: 'platform' | 'org'`, and every one of the 10 `PLATFORM_CAPABILITIES` rows sets it (`platform`: `manage_users`, `manage_metadata`, `manage_platform_settings`, `setup.access`, `studio.access`; `org`: `manage_org_users`, `setup.write`, `manage_sharing`, `view_all_audit_log`, `manage_mailboxes`). A package capability declares it through `CapabilityDeclarationSchema.scope` (`:189`), `z.enum(['platform', 'org']).default('platform')`. The superuser bits are `ObjectPermissionSchema.viewAllRecords` / `modifyAllRecords` on the `objects['*']` entry; the delegation key is `PermissionSetSchema.adminScope` (`permission.zod.ts:1022`). All three conditions are readable from declarations alone. - **A4 — measured; the conditions settle five of the eight shipped sets, and ruling item 4's denylist names the other three (the D10 agent ceilings).** Table below. The shipped roster is the eight sets in `packages/plugins/plugin-security/src/objects/default-permission-sets.ts`, held equal to `SHIPPED_PERMISSION_SET_NAMES` (`packages/cli/src/utils/organization-ownership-inventory.ts:215`) by that file's test; a repo-wide search for `PermissionSetSchema.parse(` / `definePermissionSet(` outside tests finds no other shipped set (fixtures in `packages/verify` and `packages/qa` only). - **A5 — holds.** No heading was added (both notes are blockquotes), so no anchor moved; `pnpm check:adr-anchors` exits 0 on the final head. ### Shipped permission sets against the three conditions | set | (a) no `*` superuser bit | (b) no `adminScope` | (c) `org` capabilities only | verdict | |---|---|---|---|---| | `admin_full_access` | no — `viewAllRecords` + `modifyAllRecords` | yes | no — `manage_users`, `manage_metadata`, `manage_platform_settings`, `setup.access`, `studio.access` | **outside** | | `organization_admin` | no — `viewAllRecords` + `modifyAllRecords` | yes | no — `setup.access` | **outside** (also by name) | | `organization_admin_no_bypass` | yes — the derivation drops both bits | yes | no — `setup.access` | **outside** (also by name) | | `member_default` | yes — no `*` entry at all | yes | yes — none | inside | | `viewer_readonly` | yes — `allowRead` only | yes | yes — none | inside (it carries the SCIM row scope itself) | | `mcp_agent_data_read` | yes — `allowRead` only, no row scope | yes | yes — none | **outside (denylist)** — mis-settled | | `mcp_agent_data_write` | yes — CRUD bits only, no row scope | yes | yes — none | **outside (denylist)** — mis-settled | | `mcp_agent_restricted` | yes — `objects: {}` | yes | yes — none | **outside (denylist)** — by kind | Shipped positions: the four ADR-0068 D2 identity names (`platform_admin`, `org_owner`, `org_admin`, `org_member`) are refused on `sys_user_position.position` for every writer by the object validation `reserved_identity_position` (`sys-user-position.object.ts:256`, no provenance exemption), and the two anchors by the gate's unconditional anchor refusal (`delegated-admin-gate.ts:298`–`:312`). Neither is a question for this boundary; the note records them as unchanged. ## Precisions the contract review should read Each narrows; none widens the ruled rule. 1. **"Tenant-level" is the platform administrator alone.** ADR-0095 names the organization administrator's posture rung `TENANT_ADMIN`; the note says in so many words that D12's "tenant-level" is the first kind only, so the two vocabularies cannot be read into each other. 2. **Condition (c) is fail-closed on an undeclared scope.** A package declaration that omits `scope` defaults to `'platform'`, and a `systemPermissions` name no declaration carries is not an `org` capability. 3. **"Each set a position carries" includes the position-name fold.** The resolver requests `[...positions, ...explicitPermissionSets]` (`security-plugin.ts:6542`), so a held position also grants the permission set of its own name; the note counts that set while the fold stands. Without this a position could carry an outside set past the boundary. 4. **Both organization-administrator variants are outside by name.** `organization_admin_no_bypass` is outside by (c) today only because `setup.access` is `platform`; the note also excludes it by name, which is what "conferred by membership grade only" requires. 5. **The three D10 agent ceilings are outside, on ruling item 4's denylist.** The conditions place them inside and so mis-settle them: an agent ceiling's bound is the delegating principal's own grants (D10 rule 1), not the organization wall. Held by a person as a direct grant there is no intersection, and the two reading ceilings carry no row scope on the seven Layer-0-inert SCIM projection tables; in a walled deployment with no platform baseline (`fallbackPermissionSet: null`) they read every organization's rows there, a read the granting organization administrator does not hold (its explicit per-object entries keep the `_self` / `_none` scope). `mcp_agent_restricted` is named by kind. The general case — any authored set with a `'*'` read and no row scope on a Layer-0-inert readable object, in a no-baseline deployment — is not settled by the conditions or by a shipped-set denylist; the note holds it for the maintainer's decision on #24164 and writes no fourth condition. 6. **Create and remove only** — the ruling's `allowCreate` / `allowDelete` on, `allowEdit` off. ## Gates (final head `61c8a5d34`) `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` derived 19 commands from the tree at `61c8a5d34` (change set: the two ADR files, +76 / -0 against the base; the same 19 on every head of this PR). Each ran on `61c8a5d34` with the exit code captured before any pipe: - `node scripts/check-adr-links.mjs` :: exit 0 — "769 relative link destination(s) under docs/adr/ resolve"; `--self-test` :: exit 0 - `node scripts/check-adr-symbol-anchors.mjs` :: exit 0 — "2353 anchors across 142 records resolve"; `--self-test` :: exit 0 - `node scripts/check-ci-filter-parity.mjs` :: exit 0 - `node scripts/check-closing-keyword-parity.mjs` :: exit 0; `--self-test` :: exit 0 - `node scripts/check-comment-mask-corpus.mjs` :: exit 0 — "9404 files, 0 disagree" - `pnpm --filter @objectstack/lint run check:doc-formula-expressions` :: exit 0 (its prerequisites `@objectstack/formula` and `@objectstack/lint` built first under the verify lock, `pnpm exec turbo run build --filter=@objectstack/formula --filter=@objectstack/lint --concurrency=2`, VERDICT command-exit 0; on the first head the gate had answered exit 3, PREREQUISITE NOT MET, before that build) - `pnpm check:adr-anchors` :: exit 0 — "check-adr-anchors: OK (70 anchored file(s), every governing ADR still referenced; 136 decision number(s) …; 47869 citation(s) across 6347 file(s) resolve …)" - `pnpm check:cross-package-test-inputs`, `check:doc-authoring`, `check:driver-memory-census`, `check:gitlink-declared`, `check:nul-bytes`, `check:pm-governed-merges`, `check:pm-prior-rulings`, `check:refd-timer-probe`, `check:watch-hint-literal` :: exit 0 each `--ran` reconciliation: "19 derived famil(ies) accounted for — 19 run, 0 NOT-MEASURED (a DERIVED zero — all 19 recorded an exit code and none of them is 3)". `node scripts/pm/check-governed-merges.mjs --branch claude/issue-24135-adr-0090-d12-org-admin-boundary` (exit 3, the governed code): "GOVERNED — a human merge is the review record for this PR", "landing tier: H(人合)", `docs/adr/**` ×2, under the 3000-line threshold. Everything else CI runs on this PR is CI's; nothing was re-run locally. No package builds or tests are owed: the diff touches no package. ## Acceptance notes Read-only inferences from the measurement above, not reproduced and not filed: - The delegated gate's position walk (`setsBoundToPosition`, `delegated-admin-gate.ts:1086`) reads only the definition's `permissionSets`, while the resolver also grants the set of the position's own name (precision 3). A delegate's allowlist check therefore does not see a same-named set. Carrier: #24136, whose third branch reuses that walk. - `isTenantAdmin` (`delegated-admin-gate.ts:256`, a wildcard `modifyAllRecords` holder) reads the walled `organization_admin` as tenant-level and the wall-less variant as no administrator at all; under the amended D12 both are organization-level. Carrier: #24136. - The companion reference `docs/design/permission-model.md` §10 describes delegated administration only; the organization-level kind belongs there once #24136 enforces it (docs follow the implementation). Carrier: #24136. - The D10 agent ceilings as a person's direct grant: the shipped instance is now on the item-4 denylist in this PR (precision 5); the general class — an authored wildcard-read set with no row scope on a Layer-0-inert object, in a no-baseline deployment — is the maintainer's decision on #24164, filed by the seat. ## 维护者速读(草稿) ### 改了什么 在权限模型 ADR-0090 的 D12(管理权限)里加了一条带日期的修订,并在 ADR-0131 D3 下加了一行注记,纯文字,不改代码、不加 spec 键。修订把管理者分成三类:租户级(平台管理员)、组织级(组织的 owner / admin,自动获得组织管理员权限集)、委托级(带 `adminScope` 的人)。组织级管理员可以给**本组织成员**增加或移除岗位与权限集,但只限"被组织墙约束住"的集:不带通配超级用户位、不带 `adminScope`、所含能力全部是组织级。`admin_full_access`、平台级集、组织管理员集本身、任何委托集都不能分;组织管理员身份只能由成员资格(owner / admin)获得,不能靠分配复制。本轮按席位复核意见补了一条:三个给 AI 代理用的 MCP 上限权限集列入裁决预留的黑名单,组织管理员不能把它们分给人。 ### 为什么改 这是您 10 月 17 日对 #23960 的裁决 B(「同意」)的第一步。ADR-0131 D3 承诺"组织的管理员给本组织成员分配",但代码为了防止组织管理员给自己绑 `admin_full_access` 越过组织墙,把两张分配表设成了只读;缺的正是"组织管理员能分配哪些"这条边界。边界先写进 ADR,代码卡 #24136(被本卡阻塞)才能开工。实测出货的 8 个权限集:三条件能判定 5 个(2 个在内、3 个在外);剩下 3 个 MCP 代理上限集按三条件看似在内,但它们本来只配给 AI 代理、靠委托人自己的权限收窄,直接分给人时在"不配平台基线"的部署里能读到其他组织的 SCIM 身份数据,而分配它的组织管理员自己都读不到——所以按裁决第 4 条列入黑名单。 ### 风险与代价(含回滚) 只改两份 ADR 的文字,今天的产品行为不变:两张分配表仍然只读,直到 #24136 落地。规则措辞上的几处精确化全部是收紧、没有放宽:未声明范围的能力按平台级算;岗位按名字带出的同名权限集也算"岗位携带的集";无墙部署用的 `organization_admin_no_bypass` 也按名字排除;三个 MCP 上限集列入黑名单。还有一个更一般的口子没有在本 ADR 里定:任何自建的"通配只读、没有行级范围"的权限集,在不配平台基线的部署里同样能碰到那几张没有组织列的 SCIM 表——是否加第四个条件,还是把保证写成"以平台基线为前提",已单独立成待您决策的 #24164,本 PR 不替您决定。回滚:直接 revert 本 PR,不涉及数据和发布。 ### 席位意见 ### 你要做的(一个动作) 席位复核通过后,在本 PR 上点 Approve。 --- _Generated by [Claude Code](https://claude.ai/code/session_01HSDGREvqxQUt7K7pjHXMyC)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent eda6f14 commit 7cda377

2 files changed

Lines changed: 76 additions & 0 deletions

File tree

‎docs/adr/0090-permission-model-v2-concept-convergence.md‎

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
· **Amended** (2026-10-14, ruling of record 6159300530 on #23268, letter A) — D11's external org-wide default is retired: external visibility is the [ADR-0095](./0095-authz-kernel-tenant-layer-and-posture-ladder.md) `EXTERNAL` rung, explicitly shared rows only. See the note under D11.
77
· **Amended** (2026-10-15, ruling of record 6181988435 on #23488, letter A) — D12's position↔set binding right and its environment-set authoring right are retired (`AdminScope.manageBindings` and `AdminScope.authorEnvironmentSets`, ADR-0049 enforce-or-remove): a position's sets and a permission set's body are environment definitions, and the definition write is `manage_metadata`'s per [ADR-0131](./0131-total-organization-ownership-no-null-organization-id.md) D3, never a delegate scope's. D12's *what* is user↔position assignments (and direct set grants) inside the subtree; read its bindings and authoring clauses as superseded by this line.
88
· **Amended** (2026-10-14, [ADR-0138](./0138-guest-model-anonymous-principal-doors-grants-and-organization.md) D3 item 5, ruling C of record 6159279205 on #23267) — D9's last bullet holds for `everyone` alone: a package suggests `everyone` bindings and the admin confirms each, while no door binds a set to `guest` (no package suggestion, no confirmation, no operator bind) until ADR-0138 D3 item 5's bind door is built, an act of the environment's administrator, never of a package. Read that bullet's `guest` half as superseded by this line.
9+
· **Amended** (2026-10-17, ruling of record 6228728551 on #23960, letter B) — D12 names three kinds of administrator, tenant-level, organization-level and delegated: an organization administrator (`organization_admin` / `organization_admin_no_bypass` for the organization, not a platform administrator) creates and removes `sys_user_position` / `sys_user_permission_set` rows for that organization's members when every set the row distributes has no `*` wildcard superuser bit, no `adminScope` and only `scope: 'org'` capabilities; `admin_full_access`, platform sets, `organization_admin` itself and every delegated set stay outside, and organization-administrator status is conferred by membership grade only. Strict containment and the `everyone` / `guest` anchors are unchanged. See the note under D12.
910
**Deciders**: ObjectStack Protocol Architects
1011
**Builds on**: [ADR-0049](./0049-no-unenforced-security-properties.md) (enforce-or-remove),
1112
[ADR-0056](./0056-permission-model-landing-verification.md) (permission-model landing verification),
@@ -531,6 +532,75 @@ Security-domain publishes (D7) and the `everyone`/`guest` anchors stay tenant-le
531532
delegated scope can touch them. Explain (D6) learns to answer "who *could have* granted this",
532533
not just "who did".
533534

535+
> **Amended 2026-10-17 (ruling of record 6228728551 on #23960, letter B — the maintainer's
536+
> 「同意」) — the organization administrator's assignment boundary.**
537+
> [ADR-0131](./0131-total-organization-ownership-no-null-organization-id.md) D3 has an organization's
538+
> admins create and remove the assignments of its own members, while the shipped `organization_admin`
539+
> keeps both assignment tables read-only: nothing said what a built-in organization administrator may
540+
> hand out, and an unbounded one could bind `admin_full_access`, which the organization wall does not
541+
> bound, to itself. This note is that boundary. D12 names three kinds of administrator:
542+
>
543+
> 1. **Tenant-level** — the environment's administrator: the platform administrator, an unscoped
544+
> `admin_full_access` holder ([ADR-0095](./0095-authz-kernel-tenant-layer-and-posture-ladder.md)'s
545+
> `PLATFORM_ADMIN` rung). It defines the catalog (`manage_metadata`, ADR-0131 D3), owns
546+
> security-domain publishes (D7) and the `everyone` / `guest` anchors, and assigns any set to
547+
> anyone. ADR-0095 names the next kind's rung `TENANT_ADMIN`; in D12, "tenant-level" means this
548+
> kind alone.
549+
> 2. **Organization-level** — a holder of `organization_admin` (under a posture that enforces the
550+
> organization wall) or `organization_admin_no_bypass` (under a wall-less posture,
551+
> [ADR-0105](./0105-group-tenancy-posture-and-first-class-org-scope.md) D4) for one organization,
552+
> who is not a platform administrator. It creates and removes `sys_user_position` and
553+
> `sys_user_permission_set` rows of that organization, for that organization's members, when
554+
> every permission set the row distributes — the granted set, or each set the assigned position
555+
> carries — meets all three conditions:
556+
> - (a) no wildcard superuser bit: its `objects['*']` entry carries neither `viewAllRecords` nor
557+
> `modifyAllRecords`;
558+
> - (b) no `adminScope`;
559+
> - (c) organization capabilities only: every name in its `systemPermissions` is declared
560+
> `scope: 'org'` — `PlatformCapability.scope` in `packages/spec/src/security/capabilities.ts`
561+
> for a platform capability, the declaration's `scope` (default `'platform'`) for a package's
562+
> `defineCapability`; a name no declaration carries is not an organization capability.
563+
>
564+
> The sets a position carries are every set an assignment of it grants: the names its
565+
> definition's `PositionSchema.permissionSets` lists and, while the resolver folds held position
566+
> names into the requested set names (`plugin-security` `security-plugin.ts`,
567+
> `[...positions, ...explicitPermissionSets]`), the permission set of the position's own name.
568+
> One set outside the boundary puts the whole position outside. The right is create and remove;
569+
> an assignment row is not edited in place.
570+
>
571+
> Outside the boundary, by the conditions or by name: `admin_full_access`; every set carrying a
572+
> platform capability; `organization_admin` itself, in both variants (`organization_admin_no_bypass`
573+
> lacks the superuser bits and is outside by (c) today, and by name whatever a capability's scope
574+
> later becomes); and every delegated set. Organization-administrator status is conferred by
575+
> membership grade only — an owner or admin `sys_member` row, from which `auto-org-admin-grant.ts`
576+
> grants the set — and is never copied by an assignment.
577+
> 3. **Delegated** — an `adminScope` holder, decided by the bullets above (subtree, allowlist,
578+
> strict containment) as amended on 2026-10-15.
579+
>
580+
> Unchanged: strict containment; the `everyone` / `guest` anchors, which no organization-level or
581+
> delegated administrator binds and no caller assigns (D9); and the ADR-0068 D2 identity names,
582+
> which `sys_user_position.position` refuses from every writer.
583+
>
584+
> **Measured on `origin/main` `eda6f14b7b`.** Of the eight permission sets `plugin-security` ships
585+
> (`default-permission-sets.ts`), the three conditions settle five. Inside: `member_default` and
586+
> `viewer_readonly`. Outside: `admin_full_access` (a, c), `organization_admin` (a, c) and
587+
> `organization_admin_no_bypass` (c: `setup.access`). Outside (denylist): the three D10 agent
588+
> ceilings — `mcp_agent_data_read`, `mcp_agent_data_write` and, by kind, `mcp_agent_restricted`, since
589+
> an agent ceiling is not a person's set. The conditions place them inside and so mis-settle them: an
590+
> agent ceiling's bound is the delegating principal's own grants (D10 rule 1), not the organization
591+
> wall. Held by a person as a direct grant, the two reading ceilings carry no row scope on the
592+
> Layer-0-inert SCIM projection tables (no organization column), and in a walled deployment with no
593+
> platform baseline they read every organization's rows there — a read the granting organization
594+
> administrator does not hold. The ruling's fallback — an explicit denylist for a shipped set the conditions cannot settle,
595+
> in place of a wider rule — therefore names those three sets; a set shipped later that the conditions
596+
> cannot settle joins that denylist by an amendment here. The general case — an authored set with a
597+
> `'*'` read and no row scope on a Layer-0-inert readable object, in a deployment with no platform
598+
> baseline — is not settled by this note: it is held for the maintainer's decision on #24164.
599+
> The delegated-administration gate's `isTenantAdmin` (a wildcard `modifyAllRecords` holder) reads
600+
> the walled `organization_admin` as tenant-level today; under this note it is organization-level.
601+
> No spec key is added, and the v18 upgrade entry's `replacement` text
602+
> (`18.walled-catalog-tenant-writes-retired`) stands as published: this note makes it true.
603+
534604
---
535605

536606
## Consequences

‎docs/adr/0131-total-organization-ownership-no-null-organization-id.md‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,12 @@ organization data. So are the other things an organization writes: business unit
327327
record shares it authors, approvals, files, and every business row. Every such row carries the
328328
authoring organization, NOT NULL.
329329

330+
> **Note (2026-10-17, ruling of record `6228728551` on #23960, letter B).** The organization's admins
331+
> who create and remove assignments in the paragraph above are the organization-level administrators
332+
> of [ADR-0090](./0090-permission-model-v2-concept-convergence.md) D12's 2026-10-17 amendment, and the
333+
> sentence runs under that amendment's boundary: they assign only sets with no wildcard superuser bit,
334+
> no `adminScope` and only `scope: 'org'` capabilities.
335+
330336
Under `single` the authoring organization is the Default Organization
331337
([ADR-0093](./0093-tenancy-mode-and-membership-lifecycle.md); `ensure-default-organization.ts`), which
332338
becomes **load-bearing**: it exists before the first write that needs an owner (today it is created on

0 commit comments

Comments
 (0)