Repository navigation
Commit 7cacad5
feat(plugin-sharing,plugin-approvals,metadata-protocol)!: 18.x step 7 part 7a-3 — the organization-less readers of sharing rules, approval units and the seed loader retire (#24828)
Part of #24583 — step 7, part 7a-3 (claim 6285134534; governing text:
execution record 6285122667, ADR-0131 D2 and D8). The other step-7 parts
(7a-1 driver, 7a-2 authz, 7b-*, 7c webhooks) are not in this PR, and
#24583 remains open.
Clause-②: yes (narrowing): a declared sharing rule served under `single`
gains the `deploymentWide: true` key on the wire in place of
`organization_id: null` (widening); the sharing-rule admin reads, the
approval unit screen and the scoped seed pre-load stop reading rows with
no organization (narrowing). A declared rule keeps applying
deployment-wide; nothing an author declares is refused.
## What changes
**plugin-sharing `sharing-rule-service.ts`**
- A declared rule's `single` projection carries a typed marker,
`deploymentWide: true` (`DeploymentWideSharingRule`,
`isDeploymentWideSharingRule`), and no `organization_id` key. This is
the shape of the declared webhooks' `deploymentWide` (ruling A,
6278609968). The scope list holds a `DEPLOYMENT_WIDE_SCOPE` symbol in
place of `null`.
- `criteriaContext` loses its NULL branch. It answers one of three named
cases:
- the rule's organization, which is the tenant predicate;
- a deployment-wide projection, which carries no tenant (D8 computes no
predicate under `single`);
- a composition with no organization object (the lean embedding,
`no-organization-object`), which also carries no tenant.
- Otherwise it answers `null`: a stored row with no organization sweeps
nothing and grants nothing, and the service logs it once at `error` with
the remedy.
- **How the sweep runs (decided and pinned):**
- Under `single`: one deployment-wide pass, and each grant is stamped
with its record's organization.
- Under a wall: one projection per organization, each inside that
organization's one predicate, with grants stamped with it. No projection
carries the marker under a wall, so Layer 0's predicate is never
widened.
- `adminOrgScope` and `findRuleRowByName` read the caller's own
organization only.
- `assertCanDeletePlatformGlobalRule` is deleted, together with its
call.
- `sweepOrphanedRuleGrants` and `ruleGrantScope` follow the marker.
**plugin-approvals `ApprovalService.businessUnitOrgScope`**: a strict
equality. The ceremony attributes `sys_business_unit`, and a fresh
install stamps it.
**metadata-protocol `seed-loader.ts`**: the `unownedHolders` read is
deleted, together with its `refuse` decision and the refusal text #24681
had rewritten. A scoped load issues no `organization_id IS NULL` read on
any path.
**Pins rewritten to the new rule** (no assertion weakened):
- `rule-criteria-org-scope.test.ts` (real SqlDriver):
- declared rule under `single`: deployment-wide sweep;
- declared rule under `isolated`: per-organization sweep;
- stored org-less row: refused, logged once;
- lean embedding: the control case.
- `sharing-rule.test.ts`:
- #7676 / #7761 / #8158 blocks: own-organization only;
- the #7795 platform-global delete block is removed with its guard;
- declared single projection: carries the marker.
- `approval-service.test.ts` and
`business-unit-member-org-screen.test.ts` (fixtures re-stamped to the
request's organization).
- `seed-loader-null-organization-holder.test.ts` and its runtime
real-driver twin (no NULL read on any of the three readers).
- The two sharing dogfood files.
## Premise measured first (step 7's "after certification")
Every reader retired here was dead on all three trees:
| tree | tenant-column tables | rows with NULL `organization_id` |
|---|---|---|
| certified database (`ceremoniedFixture` over the 18.0 fixture), after
the ceremony and again after a HEAD boot | 66 | 0 |
| fresh birth-marked `single` install (showcase `--fresh`) | all | 0
(`sys_business_unit` 5 rows, all stamped) |
| fresh `isolated` install, real organizations runtime | all | 0 |
One live path remains. It is kept, not deleted: the lean embedding with
no organization object, which still writes NULL rows by design. It keeps
the deployment-wide sweep, keyed on the composition fact
(`sys_organization` not registered), never on a row's NULL. The
production `os serve` boot without `OS_AUTH_SECRET` is that same
composition today; 7b-3 makes it refuse.
## Proof
Final head `357025dc97`. The boots, harness and suites ran on
`62227f5632`, which differs from it only by `main`'s README commit.
- **R1:** a fresh showcase boot on a random port, run on the pre-merge
head and again on the final head:
- health 200, seeded-admin sign-in 200, 0 error lines;
- 0 NULL `organization_id` rows in any tenant table;
- the declared rule `share_key_account_qualified_contacts_with_managers`
materialised a stamped grant.
- **R2 + R3:** `upgrade-18x-harness.dogfood.test.ts` +
`organization-ownership-boot-refusal-order.dogfood.test.ts` passed,
together with the two sharing dogfood files: 33/33. This run includes
the ceremonied fixture, and the v17 refusal fired before the ceremony.
- **R4:**
- An `isolated` `os serve` with `@objectstack/organizations`
(invite-only membership, owner email set), on both heads: health 200,
sign-in 200, 0 error lines, 0 NULL rows. `GET /sharing/rules` serves
both declared rules as per-organization projections, with no marker. The
grant is stamped.
- Step 4's 7 walled e2e cases (`serve-organizations-host-resolution` +
`serve-organizations-mount-failure`, `OS_TEST_TIERS=nightly`): 7/7.
- **Suites:**
- plugin-sharing 51 files / 1181 tests;
- plugin-approvals 86 / 1147;
- metadata-protocol 251 / 20815;
- runtime 431 / 6781;
- typecheck of plugin-sharing, plugin-approvals, metadata-protocol,
runtime and dogfood: exit 0.
- **Gates:** `dispatch-gates --commands` on the 12 code paths derived 75
commands. All 75 ran, and every exit code was captured before any pipe.
- 73 exited 0 on the first run.
- `check-system-context-census` was red:
`content/docs/permissions/system-context.mdx` still cited the deleted
`assertCanDeletePlatformGlobalRule`. The citation was dropped, and the
re-run exited 0.
- `check-plugin-teardown-shape --self-test` was a shallow-clone
artefact: its pinned fixture commit was absent. It exited 0 once that
commit was fetched.
- Re-derived on the final 15 paths (1,641 changed lines, under the 3,000
line): the 26 newly derived docs families plus the 15 ratchet and
test-reading families, 41 commands, all exit 0.
- **More pins the suites found, rewritten:**
-
`packages/runtime/src/standalone-stack-seeder-declaration-copy.test.ts`:
the served declared shape now carries the marker.
- `sharing-rule-positions-name-authority.test.ts`: retitled. Its delete
case is refused by the scope gate, not by the retired guard.
- **A sweep of 11 more candidate files, all green:**
- 7 dogfood files (scope-depth ×3, BU projection, BU/user delete, single
platform insert, single-tenant identity create);
- the cli declared-rule-mirrors integration test;
- the rest canonical-query-AST test;
- the cloud-connection posture-gate test.
- **Ablation** of the main pin: restoring the NULL branch (`return
SYSTEM_CTX` for every org-less rule) turned exactly the two predicted
cases red ("a STORED rule with NO organization …", whole-rule and
per-record), and the other 6 stayed green. Restore was proven by blob ==
HEAD and an empty `git diff HEAD`.
## Acceptance notes
- `main`'s `recipient-membership-recompute.ts` (`ruleReadsRowsOf`,
landed in `0b7286ff`) still reads `rule.organization_id == null` as
"reads every row". With the marker the deployment-wide projection has no
`organization_id`, so it is still counted as affected, which is the
right answer. The spelling is a NULL-shaped reader outside this part's
file surface.
- `sharing-plugin.ts`'s `resolveDeclaredRuleScopes` still spells
`single` as `[null]`. `setDeclaredRuleScopes` translates it at that one
door, so no NULL travels past it. Retyping the plugin side is outside
the claimed surface.
- `approval-service.ts` `teamIsProvablyOutsideOrg` keeps its "no
organization ⇒ leave routing" limb (a team screen). It is not in this
part's surface, and its doc cross-reference was corrected.
- The ORG-STAMPED pin in `rule-criteria-org-scope.test.ts` still expects
`deal_p1` through the driver's NULL record arm. That is 7a-1's arm and
7a-1's pin. Separately, an org-less RECORD matched by two walled
projections aborts the second pass with `RECORD_NOT_FOUND`. That case
cannot occur on a certified database, and it goes away with 7a-1.
- File surface: beyond the claim's list, this PR edits one hand-written
docs page (`content/docs/permissions/system-context.mdx`, row 40: the
deleted guard's citation, which its census gate requires) and pins in
`packages/runtime` and `packages/qa/dogfood`. It touches no
`docs/adr/**` and no `content/docs/releases/`.
- The seed pin files keep their `null-organization-holder` names:
`scripts/engine-double-contract.pinned.json` registers them by path.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01XFEb4fSDbe4fK94S3x5FKX)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent abd5acd commit 7cacad5
16 files changed
Lines changed: 698 additions & 985 deletions
File tree
- .changeset
- content/docs/permissions
- packages
- metadata-protocol/src
- plugins
- plugin-approvals/src
- plugin-sharing/src
- qa/dogfood/test
- runtime/src
- spec/src/contracts
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
159 | 159 | | |
160 | 160 | | |
161 | 161 | | |
162 | | - | |
| 162 | + | |
163 | 163 | | |
164 | 164 | | |
165 | 165 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
6 | 6 | | |
7 | 7 | | |
8 | 8 | | |
9 | | - | |
10 | | - | |
11 | | - | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
12 | 12 | | |
13 | | - | |
14 | | - | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
15 | 16 | | |
16 | | - | |
17 | | - | |
18 | | - | |
19 | | - | |
20 | | - | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
21 | 24 | | |
22 | | - | |
| 25 | + | |
23 | 26 | | |
24 | 27 | | |
25 | 28 | | |
| |||
112 | 115 | | |
113 | 116 | | |
114 | 117 | | |
115 | | - | |
116 | | - | |
117 | | - | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
118 | 121 | | |
119 | 122 | | |
120 | | - | |
121 | | - | |
| 123 | + | |
122 | 124 | | |
123 | | - | |
124 | | - | |
125 | | - | |
126 | | - | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
127 | 129 | | |
128 | 130 | | |
129 | | - | |
130 | | - | |
131 | | - | |
132 | | - | |
133 | | - | |
134 | | - | |
135 | | - | |
136 | | - | |
137 | | - | |
138 | | - | |
139 | | - | |
140 | | - | |
141 | | - | |
142 | | - | |
143 | | - | |
144 | | - | |
145 | | - | |
146 | | - | |
147 | | - | |
148 | | - | |
149 | | - | |
150 | | - | |
151 | | - | |
152 | | - | |
153 | | - | |
154 | | - | |
155 | 131 | | |
156 | | - | |
157 | | - | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
158 | 142 | | |
159 | 143 | | |
160 | | - | |
| 144 | + | |
161 | 145 | | |
162 | | - | |
163 | | - | |
164 | | - | |
165 | | - | |
166 | | - | |
167 | | - | |
168 | | - | |
169 | | - | |
170 | | - | |
171 | | - | |
172 | | - | |
173 | | - | |
| 146 | + | |
174 | 147 | | |
175 | 148 | | |
176 | 149 | | |
177 | 150 | | |
| 151 | + | |
178 | 152 | | |
179 | | - | |
| 153 | + | |
180 | 154 | | |
181 | 155 | | |
182 | | - | |
| 156 | + | |
183 | 157 | | |
184 | | - | |
| 158 | + | |
185 | 159 | | |
186 | 160 | | |
187 | 161 | | |
| |||
195 | 169 | | |
196 | 170 | | |
197 | 171 | | |
| 172 | + | |
198 | 173 | | |
199 | 174 | | |
200 | | - | |
201 | 175 | | |
202 | | - | |
203 | | - | |
204 | | - | |
205 | | - | |
206 | | - | |
207 | | - | |
208 | | - | |
209 | | - | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
210 | 180 | | |
211 | 181 | | |
212 | 182 | | |
213 | 183 | | |
214 | | - | |
215 | | - | |
| 184 | + | |
216 | 185 | | |
217 | 186 | | |
218 | 187 | | |
| |||
224 | 193 | | |
225 | 194 | | |
226 | 195 | | |
227 | | - | |
| 196 | + | |
228 | 197 | | |
229 | 198 | | |
230 | 199 | | |
231 | 200 | | |
232 | 201 | | |
233 | 202 | | |
234 | | - | |
235 | | - | |
| 203 | + | |
236 | 204 | | |
237 | | - | |
| 205 | + | |
238 | 206 | | |
239 | 207 | | |
240 | | - | |
| 208 | + | |
241 | 209 | | |
242 | | - | |
| 210 | + | |
243 | 211 | | |
244 | 212 | | |
245 | | - | |
| 213 | + | |
246 | 214 | | |
247 | 215 | | |
248 | | - | |
| 216 | + | |
249 | 217 | | |
250 | 218 | | |
0 commit comments