Skip to content

Commit fb9c22a

Browse files
docs(adr): ADR-0131 D6 charts sharing_rule under regime C; D7 ledger reading and lines for #24377 and #24435; D14 records the 18.0 scope (#24422)
Fixes #24420 Part of #24343 Part of #15212 Clause-②: no ## What this changes The PR adds seven dated notes to `docs/adr/0131-total-organization-ownership-no-null-organization-id.md` (+73 / −0). It rewrites no ruled sentence. - **Note 1** carries out ruling **A** on #24378, recorded at comment `6258883445`, items 1–4 (the maintainer's 「24378 同意 A」). Ruling A supersedes ruling B′ (`6257388265`). - **Note 2** is the ledger reading that B′ item 1 ordered. A keeps it, and sharing rules are added as a fifth reader. - **Notes 3–5** are the three D7 lines for ruling `6257510973` on #24377 (Q2 A, Q4 A). - **Note 6** carries out ruling Q1 A on #24435, recorded at comment `6259141885` (「同意」). - **Note 7** records the 18.0 release scope from ruling records `6259608309` and `6259698357` on #15194 (「同意」, twice). 1. **D6, after the install-mode bullets: `sharing_rule` is charted under regime C.** - Declared rules are read-only and clonable. - Switch-off is the `active` bit of a `sys_metadata_activation` row of type `sharing_rule`. The switch is deployment-level and operator-gated under a wall, and there is no per-organization switch-off. Organizations author their own rules (D3). - Customising is a clone under a new name, plus switching the base off. - Same-name shadowing is retired. Every same-name row, new or renamed, is refused. A declaration that arrives over an authored row is reported loudly at load. - The ceremony migrates customised copies and deletes uncustomised mirrors (D10 fate 2). - The ruling is built by #24421. PR #24428 landed the switch, the refusals and the load-time report on 2026-10-19. The ceremony step lands with the 18.x upgrade path. 2. **D7, after its first paragraph: the activation ledger reads one way.** D7's "reverted before 17.3" clause is read the way D6, D13, D14 and C0 hold it. The note now names sharing rules as a fifth reader. 3. **D7, after the writer-membership paragraph: three dated notes for ruling `6257510973` on #24377.** Each is stated as ruled, not shipped. - Identity mail goes to a deployment-level sibling of `sys_email`. - `sys_secret` has no organization column. - `sys_setting_audit`'s global rung goes to a deployment-level sibling. 4. **D7, after the #24377 lines: `sys_flow_credential` is deployment-level** (ruling `6259141885`, Q1 A). - It is to declare `systemFields: { tenant: false }`. A credential's ownership follows its flow, which is environment metadata (D2/D6). This matches the `sys_secret` note. - It is ruled, not shipped. - #24435 Q2 orders no line, because D2 already says no seeder writes declared items into any table. 5. **D14, after the 2026-10-10 execution-plan note: a release-scope note** (ruling records `6259608309` and `6259698357`). - 18.0 ships for fresh installs on `single` only. In 18.0, `os migrate organization-ownership` and the walled postures are refused. - Stage 8b ships in 18.0. - The upgrade path, the walled postures, 8b-0d / 8b-0e / 8b-0g, 8c, 8d and 8e ship in 18.x. - The v18 line, the fence and §8 stand. ## Why this reading, and not a new decision The contradiction needed no new decision, because the record and the code agree on one side. Measured on `origin/main` `71fa166e`: - `packages/platform-objects/src/system/sys-metadata-activation.object.ts` declares `sys_metadata_activation` with `systemFields: { tenant: false }`. This is C0, shipped by #15024, which is closed. - Flows read the ledger (`service-automation` `FlowActivationStore`), and so do actions (`objectql/src/action-activation.ts`) and positions and permission sets (`core/src/security/resolve-authz-context.ts`, `runtime/src/domains/catalog-activation.ts`). - The C7 inventory (`packages/cli/src/utils/organization-ownership-inventory.ts`) cites "D7, D6, D14 (C0): the tenant-less activation ledger". Nothing in the tree reverts the ledger. ## Verification Docs only. No package, no `content/docs/releases/`. Gates were derived with `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack` against merge base `71fa166e9`. They ran on commit `7b9b0c0`. The pushed head `a41ddd96` has the same tree; only the commit trailer was reworded so the pre-push trailer check would pass. The D7 commit `2261458d` re-derived the same 74 commands on that head: 19/19 derived families exit 0, 50/55 roster rows exit 0, and the other five are NOT MEASURED for want of PR context or a whole-tree build (os-dev-report 6257947772). - **19 derived families: 19 run, all exit 0.** `--ran` reports "19 derived famil(ies) accounted for — 19 run, 0 NOT-MEASURED (a DERIVED zero)". The families include `check-adr-links`, `check-adr-symbol-anchors`, `check:adr-anchors`, `check:doc-authoring`, `check:nul-bytes`, `check:pm-governed-merges` and `check:pm-prior-rulings`. - `check:doc-formula-expressions` first exited 3 with PREREQUISITE NOT MET, because `@objectstack/formula` had no `dist/`. After `turbo run build --filter=@objectstack/formula --filter=@objectstack/lint` under the verify lock, it exited 0. - **Artifact-roster block (55 rows): 49 exit 0. The other 6 are NOT MEASURED, and none is a finding.** - `check-closing-target-claim`, `check-partof-closing-keyword` and `check-single-claim-paths` (exit 2), and `check-governed-queue-guard` (exit 1, no `GITHUB_EVENT_PATH`), had no PR context. CI runs them. - `check:dts-closure` and `check:published-readme-exports` (exit 3) need a whole-tree build. CI runs them. The rework commits `b1e9de61` (regime C), `371b98ae` (#24435 Q1) and `3d9490fa` (D14 scope) each re-derived the same 74 commands: 19/19 derived families exit 0, and 50/55 roster rows exit 0. The same five are NOT MEASURED. Source: the final os-dev-report on #24420 for `3d9490fa`. ## Changeset None. The diff publishes nothing: `docs/adr/**` is a fast-lane, unpublished path, so the PR carries `skip-changeset`. ## Landing This is a governed surface (`docs/adr/**`), so the PR is **Tier H**. It needs an at-tier `## Contract review` record, and then the maintainer merges it. No seat readies, queues or merges it. ## 维护者速读 - **改了什么:** ADR-0131 加七段带日期的 Note(+73 行),不改任何已裁决原文。 - ① **D6:** 按裁决 A(「24378 同意 A」,取代 B′)把 sharing_rule 归入 C(停用 + 克隆)制度。 - 声明的规则只读、可克隆。 - 停用是 sys_metadata_activation 中 sharing_rule 类型行的 active 位:部署级,隔离部署下由运维把关,没有组织级停用。 - 定制 = 新名克隆 + 停用原规则。 - 同名覆盖退役:同名行一律拒绝;升级带来的同名声明在加载时响亮报告。 - 仪式把已定制副本迁成克隆 + 停用,并删除未定制镜像(仪式部分随 18.x 升级路径)。 - ② **D7:** 启用账本统一读作「保留」;共享规则成为第五个读者。 - ③ **D7:** #24377 的三行(身份邮件、`sys_secret`、全局设置审计)。 - ④ **D7:** 按 #24435 Q1 A(「同意」),`sys_flow_credential` 不设组织列,凭据归属随所属 flow。 - ⑤ **D14:** 记下 18.0 范围。 - 18.0 只面向新装、只支持 single;`os migrate organization-ownership` 与隔离部署在 18.0 拒绝。 - 8b 进 18.0;升级路径、隔离部署、8b-0d/8b-0e/8b-0g、8c、8d、8e 进 18.x。 - **为什么改:** 执行以下裁决,让 ADR 与 18.0 范围只有一种读法: - #24378 的裁决 A 第 1–4 项; - #24435 Q1; - #24377 Q2、Q4; - #15194 上的 18.0 范围裁决记录。 - **风险与代价(含回滚):** 纯文档,73 行,零运行时影响;回滚即 revert 本 PR。 - **席位意见:** 最终契约评审 PASS(记录见本 PR 评论,head `3d9490fa`)。 - 评审提示两点,可接受为「按发版口径」的日期状态: - D6、D7 两段写「尚未发布」,而 #24428 已于 05:27Z 合入 main,但 18.x 尚未发版; - D14 未写「18.0 新装库以后也走 18.x 升级路径」和「8b 在 18.0 只对 single 撤豁免」。 - 席位建议照现文合并,这两句随 18.0 发版说明或下一条 D14 日期行补上。 - **你要做的:** 读七段 Note;PR 仍是草稿,请转 ready 并合并(Tier H)。 --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 94e60c0 commit fb9c22a

1 file changed

Lines changed: 73 additions & 0 deletions

File tree

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

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,20 @@ spelling moves: the copy-once import, full editability, no upgrade channel and t
431431
naming the posture: a template import would hand every tenant an editable shared schema. Under `single`
432432
it is how a customer takes an app and makes it theirs wholesale — Salesforce's unmanaged package.
433433

434+
> **Note (2026-10-19, ruling of record `6258883445` on #24378, letter A, which supersedes ruling
435+
> `6257388265`, letter B′) — `sharing_rule` is charted under regime C.** A managed declared sharing rule
436+
> is read-only and clonable. **Switching it off** is the `active` bit of a `sys_metadata_activation` row
437+
> of type `sharing_rule`. Like the bit for flows and actions, it is deployment-level and operator-gated
438+
> under a wall. There is no per-organization switch-off, and organizations still author their own rules
439+
> (D3). **Customising** is a clone under a new name, plus the base switched off. **Same-name shadowing is
440+
> retired.** A `sys_sharing_rule` row that takes a declared rule's name in its scope is refused, whether
441+
> it is new or renamed. A declaration that arrives over an authored row, as in a package upgrade, is
442+
> reported loudly at load and never becomes an overlay. **D10's ownership ceremony** migrates each
443+
> existing customised copy to a clone plus the base switched off, and deletes the uncustomised mirrors
444+
> (fate 2). The promise that a customised copy keeps answering and a switch-off survives redeploys is
445+
> kept by that migration and the ledger, not by shadowing. This is a ruled decision that #24421 builds;
446+
> it has not shipped.
447+
434448
Creating one's own item — a new permission set, position, view, flow — is environment authoring
435449
(Studio, or Setup acting as a metadata editor under `single`), gated as D2/D3 describe and refused to
436450
tenants of a shared-DB deployment. It is not customization of a managed item; pre-filling the form from a
@@ -499,6 +513,18 @@ settings — `sys_setting`'s global rung leaves the tenant-scoped table: infrast
499513
configuration; a tenant-less object holds only values an operator must change without a restart (ruled
500514
2026-09-04). Such objects are governed by object permission, not by the wall.
501515

516+
> **Note (2026-10-19, ruling of record `6257388265` on #24378, letter B′) — the activation ledger reads
517+
> one way.** The clause above saying `sys_metadata_activation` "is reverted before 17.3 and does not
518+
> return" is left over from the draft before the standard-package reversal, which re-scoped its card
519+
> (#15024) from a revert to a column drop (§7). D6, D13, D14 and C0 hold the reading: the object
520+
> stays as the tenant-less activation ledger and carries regime C's disable bit. It is off D13's
521+
> retirement list, and its reserved organization column was dropped before 17.3. It is a member of this
522+
> paragraph's family. The code follows this reading: the object is declared with
523+
> `systemFields: { tenant: false }` (`packages/platform-objects/src/system/sys-metadata-activation.object.ts`),
524+
> and flows, actions, positions and permission sets read it. Sharing rules join them as a fifth reader by
525+
> ruling `6258883445` on #24378, which is ruled and not yet shipped (the D6 note above). The clause stays
526+
> as written, and this note governs how it is read.
527+
502528
⚠️ **Membership in this list is decided by the writer, not by the object's name.** The read-side ledger
503529
grouped `sys_http_delivery`, `sys_inbox_message`, `sys_notification*` and `sys_email` as "plumbing"; the
504530
tree has since decided otherwise for each — #13565 stamps `sys_http_delivery` from the webhook's
@@ -509,6 +535,32 @@ column (NOT NULL, D3); an object no writer attributes is deployment-level and lo
509535
inventory records the verdict per object with the writer fact as its citation — this record names only
510536
the objects whose verdict the tree already states.
511537

538+
> **Note (2026-10-19, ruling of record `6257510973` on #24377, letter Q2 A) — identity mail is
539+
> deployment-level.** Some mail goes to a person before any organization is theirs to stamp: verify,
540+
> reset, magic link, email change, and an account invitation to a person with no organization. That
541+
> mail is written to a sibling of `sys_email` that has no organization column and the same row shape.
542+
> The same outbox, status and attachment pipeline serves it. Tenant mail stays in `sys_email` with
543+
> its organization NOT NULL, and #11303 decision 2 keeps it stamped at its producers. ⛔ Neither a
544+
> nullable column nor unpersisted mail. This is a ruled decision that a C8 stage builds; it has not
545+
> shipped.
546+
547+
> **Note (2026-10-19, ruling of record `6257510973` on #24377, letter Q4 A) — `sys_secret` has no
548+
> organization column.** A secret's ownership follows the row that references it: `sys_setting` /
549+
> `sys_platform_setting`, the webhook, the flow credential, the field's record, or the datasource.
550+
> Every read stays by id under privilege. This is a ruled decision that a C8 stage builds; it has not
551+
> shipped.
552+
553+
> **Note (2026-10-19, ruling of record `6257510973` on #24377, letter Q4 A) — `sys_setting_audit`'s
554+
> global rung moves to a deployment-level sibling.** This is the same departure `sys_setting`'s global
555+
> rung already makes. The settings audit's tenant and user rows stay in `sys_setting_audit` with the
556+
> organization NOT NULL. This is a ruled decision that a C8 stage builds; it has not shipped.
557+
558+
> **Note (2026-10-19, ruling of record `6259141885` on #24435, letter Q1 A) — `sys_flow_credential` is
559+
> deployment-level.** The object is to declare `systemFields: { tenant: false }`, so it has no
560+
> organization column. A credential's ownership follows the flow it belongs to, and a flow is
561+
> environment metadata (D2, D6). This matches the `sys_secret` note above. This is a ruled decision that
562+
> a C8 stage builds; it has not shipped.
563+
512564
The #12699 deployment declaration becomes **total**: an object a deployment declares platform-global
513565
gets **no organization column on that deployment** (the injected-columns plan reads the declaration),
514566
so Layer 0 and the driver agree by having nothing to scope. This is how the cloud control plane
@@ -762,6 +814,27 @@ sits beside them.
762814
under `single` for capability holders" is the accurate wording, and D3's "no Studio capability is
763815
required" is withdrawn by this ruling.
764816

817+
**Release-scope note (2026-10-19, ruling records `6259608309` and `6259698357` on #15194).** Two ruling
818+
records of the maintainer (「同意」, twice) split the v18 line between 18.0 and later 18.x releases.
819+
⛔ Neither changes a decision of this record: the line, the fence above and §8's order stand, and this
820+
note sits beside them.
821+
822+
1. **18.0 ships for fresh installs, on the `single` posture only.** A v17 database stays on 17.x
823+
until the 18.x release that carries the upgrade path. In 18.0, `os migrate organization-ownership`
824+
refuses to run, and the walled postures (`group`, `isolated`) are refused at the operator's boot
825+
path. Both refusals name the 18.x release that will carry the missing piece.
826+
2. **Stage 8b ships in 18.0.** Every system insert is stamped or refused; under `single` it is stamped
827+
with the Default Organization.
828+
3. **These ship in 18.x:**
829+
- the v17 → v18 upgrade path, which is the ceremony's deferred fates and moves;
830+
- the walled postures;
831+
- C8 stages 8b-0d, 8b-0e and 8b-0g: the identity-mail and settings-audit siblings, the column-less
832+
`sys_secret` and `sys_flow_credential`, and declared webhooks served from the registry (the D7
833+
notes above);
834+
- 8c, the organization-less read branches;
835+
- 8d, `COALESCE` and `__global__`;
836+
- 8e, the NOT NULL constraint.
837+
765838
---
766839

767840
## 3. Non-goals

0 commit comments

Comments
 (0)