You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit a10b69e
Browse filesBrowse the repository at this point in the historyBrowse files
feat(driver-sql)!: a tenant-scoped read no longer answers a row with no organization; the driver's `OR organization_id IS NULL` arm is retired
7
+
8
+
Clause-②: no (narrowing)
9
+
10
+
<!-- adr-0087: not-required (no-migration-prescription) A read-scope narrowing in the SQL driver's tenant chokepoint and the lifecycle sweep's global pass: no key of any metadata schema is removed, renamed or re-shaped, so there is nothing for `objectstack migrate meta` to rewrite and no tombstone. No export, type or error code is added, removed or renamed. The data it stops reaching is retired by the 18.x upgrade ceremony, which certifies zero organization-less rows before a database boots. -->
11
+
12
+
**BREAKING** read-scope narrowing, shipped as `minor` under the repo's launch-window convention for breaking changes (ADR-0131 D1, D14). Step 7 of the 18.x organization-ownership line: it lands after the upgrade ceremony opens.
13
+
14
+
-**Before.**`SqlDriver.applyTenantScope` compiled a tenant scope as `(organization_id = :tenant OR organization_id IS NULL)`, and the `group` posture's union as `(organization_id IN (…) OR organization_id IS NULL)`. That was the v17 reading, in which a row with no organization stood for platform state, and every tenant's scoped read, count, update and delete reached it. The Turso remote face compiles the same scope, so it answered the same rows.
15
+
-**Now.** The scope is `organization_id = :tenant`, or `organization_id IN (…)` under `group`. NULL is not an owner: a row with no organization is no tenant's, and only an unscoped read (no tenant on the call) reaches it. The lifecycle sweep's global retention and archive pass over an `organization_id` partition is a bare `$nin` of the overriding tenants: it no longer selects organization-less rows.
16
+
-**Unchanged.** A call with no tenant context and an object with no tenant column are unscoped, as before. The `single` posture's driver reads carry no tenant scope at all (ADR-0131 D8). The `sys_audit_log` attribution partition (`tenant_id`, ADR-0131 D7) keeps its NULL arm: a deployment-level ledger row is about no organization by design, and the global pass still reaps it. Insert stamping (`injectTenantOnInsert`) is unchanged.
17
+
18
+
**Who is affected.** Only a database that still holds organization-less rows in a tenant-scoped table, and only under a walled posture (`group` / `isolated`) or a caller that passes `tenantId` to the driver itself. A certified 18.x database holds none: a v17 database is refused at boot until `os migrate organization-ownership` certifies it, and a fresh install never writes one.
19
+
20
+
**The remedy.** If a scoped read misses a row you expect, the row has no organization: run the upgrade ceremony (`os migrate organization-ownership` to review its plan, then the same command with `--apply`), which stamps each such row with its owner, or stamp it yourself (`organization_id = <the owning organization>`).
fix(plugin-approvals): the out-of-office delegation form's Delegator picker offers only the signed-in user, the one delegator the server accepts
6
+
7
+
Clause-②: no
8
+
9
+
No accept set moves. The field gains a picker filter, which nothing on the write path reads, and the delegation write guard and `required` are unchanged.
10
+
11
+
-**Before.**`sys_approval_delegation.delegator_id` was a free `sys_user` lookup, so Approvals → Delegations → New offered every user. The delegation write guard accepts one delegator on a non-system write, the acting user, so picking anyone else was refused with 403 `FORBIDDEN`.
12
+
-**Now.** The field declares `lookupFilters: [{ field: 'id', operator: 'eq', value: '{current_user_id}' }]`. The engine resolves the placeholder against the caller on every read, so the picker's candidate query offers the signed-in user and nobody else.
13
+
-**Unchanged.** What a write may store. A create or an update that names another delegator is still refused, and there is no admin exemption. An admin covering for an absent approver reassigns, recalls or rejects that approver's pending approvals through the approval override instead.
0 commit comments