Repository navigation
feat(spec,drivers,objectql,plugin-security): organization_id NOT NULL per cleared table; one predicate for Layer 0 and every driver; both orWhereNull arms, the __global__ sentinel and the #13491 ledger retire (ADR-0131 D1/D8/D9) — protocol 18 #15212
Description
Activity
- addedpriority:p1High: required for production / M2High: required for production / M2
on Sep 4, 2026 Carrier hygiene — director seat (objectstack #12708, session_01LsEjuNMPitCHwEfYftZ1um), 2026-09-04.
needs:contract-reviewremoved from this card. Per the maintainer's 2026-08-28 ruling the carrier is never pre-hung: it marks a real reviewable increment (an open PR), and none exists — the card ispm:blockedbehind #15193 and its C-row predecessors with no PR (closed_by_pull_requests0). The Clause-② declaration in the body (yes, accept-set change, protocol 18) is the durable record; the carrier goes on the PR and the card the moment a draft PR opens. Labels rewritten read-modify-write, every other label untouched.
Generated by Claude Code
objectstack-fleet commented
on Oct 6, 2026 ContributorMore actionsv18 pre-opening re-verification (C8): DRIFTED and partly done. Its
Blocked-bylines missed C7Triage seat (objectstack-wide, seat post #6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-06T14:41Z. ⛔ Not a claim, ⛔ not a dispatch. Read-only re-verification on objectstackmain6befe19c6e. The cut base was 2026-09-04, 3,298 commits earlier. The maintainer asked for this pre-opening preparation in the triage seat's chat: 「现在就可以处理吧」. Classes, positions and functions only. The claiming seat applies these corrections before building. The body is not rewritten.Blocked-by: #15211
- Bookkeeping: the body says C8 waits on C7, and ADR §8 makes C7 its only predecessor, but no machine-readable line named feat(objectql,cli): inventory + migration — four fates per object, mirrors deleted only after the id→name rewrite is verified, per-table boot report (ADR-0131 D10) #15211. An unlock scan would have released this card before C7. Added above.
- The arms: both
orWhereNullarms remain (driver-sql/src/sql-driver.ts:15525,:15538).driver-tursonow compiles the same method into remote statements (turso-driver.ts:2295-2345), so it needs its own pins. sqlite-wasm and turso inherit from the SQL driver. - Moot now:
- the "audit
driver-memory/driver-mongodb" step: the memory driver refuses tenant-scoped calls (memory-tenancy-guard.ts:38-42) and is no longer a boot store; mongo refuses multi-tenant use; - "retire
reportLegacyPlatformAdminGrant": that was done on 17.x (74832b68f2).
- the "audit
- Half done: the Layer 0 half of "one scope" landed (
computeTenantLayer0Verdict,plugin-security/src/tenant-layer.ts:205). What remains is the driver threading (objectql/src/engine.ts:5502-5560still derivestenantIdon its own). - Flip, explicitly:
scripts/check-tenant-chokepoint.mjsenforces the NULL-organization rule today (:684-694). The card's "refuses an IS NULL arm" is a reversal, and the PR says so. - Grown:
GLOBAL_TENANTusers went from 30 to 33 non-test files. Files with NULL-organization semantics went from 199 to 275 tests and from 58 to 67 non-test. - Size L–XL. It is protocol 18.
Generated by Claude Code
objectstack-fleet commented
on Oct 7, 2026 ContributorMore actionsRecorded for C8, from C1's retriage (#15195
6039987580, triage's answer on #15195). Triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-07T14:56Z. ⛔ Not a claim, and no change to this card's state.The open point: "every-posture refusal" (§8's C8 row) and D9's "refused otherwise".
- What it means for a composition with no
sys_organizationregistered at all (lean embeddings, and the reduced-kernel test pattern of test kits: since 17.7.0 refuses unregistered object names, every reduced kernel without plugin-auth fails onsys_user, and plugin-security's own authz store fails onsys_member— each app re-implements identity-object registration; publish a preset #22074): the engine's lean-install branch (engine.tsprobeInstallOrganizations, about:5774) treats such a composition as having no organization to derive. - The C1 seat's reading, A: no organization object means no tenancy to enforce, stated and pinned.
- D9's literal reading: refuse.
C1 leaves the branch as it is today. At C8 the claimant measures the lean-composition reach first. If the measurement argues for A, it is a ruling of its own (it would narrow an accepted decision) and goes to the decision box. Otherwise D9 applies as written.
- What it means for a composition with no
objectstack-fleet commented
on Oct 8, 2026 ContributorMore actionsRemainder recorded for C8 from #14570 (
domain:engineseat 1, seat post #6367) ·session_01EUBvqtauTDmHi2ZgY759p2(os-litant) · 2026-10-08T19:10Z. ⛔ Not a claim, and no change to this card's scope or labels. This records a case for whoever builds C8.#14570's stage 0 (os-dev-report 6067123924) re-measured
sys_business_unit_member's four write paths onmaine36ee5351b, after C1 (34dba5ae1e). The measurements were taken on real showcase kernels throughbootStack, undersinglewith the Default Organization and underisolated(posture-only):path singleisolatedREST / session write stamped stamped seed loader (inline, pinned, sole-organization fallback) stamped stamped elevated system write ( isSystem, notenantId)NULL, not refused NULL, not refused (an application-object control in the same boot is refused walled-posture; the same insert carryingtenantIdlands stamped)- The cause is the exemption C1 kept until C8 by ruling.
packages/objectql/src/engine.tsnear:5856, insideresolveSystemInsertOrganization:if (isPlatformObjectOutOfTenantAuditScope(object)) return undefined;. The predicate is intenancy/platform-object-tenancy.tsnear:255. The object isunclassifiedby absence.- Of the census's 49 in-reach platform objects, 8 are admitted tenant-scoped. The early return fires for the other 41, which include
sys_business_unit_member,sys_business_unit(the identical path, measured: NULL undersingle) andsys_permission_set. - The same predicate sets
isTenantAuditInScopefalse (near:5628), so these NULL writes are also quiet (read, not measured).
- Of the census's 49 in-reach platform objects, 8 are admitted tenant-scoped. The early return fires for the other 41, which include
- Fixture to re-measure when the early return is lifted.
packages/qa/dogfood/test/showcase-bu-hierarchy-sharing.dogfood.test.ts:66callsfindOne('sys_organization', { where: {} }). The engine refuses that,.catch(() => null)swallows the refusal, and:68then mints a second organizationorg_bu. Once C8 lifts the early return, the fixture's bareisSystemmembership inserts (:73–:74) meet a two-organizationsingleinstall, so they would be refusedambiguous-organizationrather than derived. That is inferred from the C1 rule table, not measured. 5536484221 names C7 (feat(objectql,cli): inventory + migration — four fates per object, mirrors deleted only after the id→name rewrite is verified, per-table boot report (ADR-0131 D10) #15211) as owning that fixture case. - Stakes, carried from
sys_business_unit_memberis unadjudicated inPLATFORM_OBJECT_TENANCY, so seed-replayed and system-written membership rows land organization-less #14570: approvals:expandBusinessUnitUsersreadssys_business_unit_memberwith no organization predicate, so adepartmentapprover on a seeded unit resolves across tenants #14946 / PR fix(plugin-approvals): screen expanded business-unit members to the directory organization (#14946) #15912's strict organization screen on membership reads keeps resolving an organization-less membership to nobody until new rows stop landing NULL (C8) and existing rows get their fate (C7).
#14570 is re-blocked on this card in the same act.
Generated by Claude Code
- The cause is the exemption C1 kept until C8 by ruling.
- added a commit that references this issue
on Oct 9, 2026
⛔ BLOCKED — the v18 development line is not open.
Blocked-by: #15193
Blocked-by: #15196
Blocked-by: #15204
Blocked-by: #15205
Blocked-by: #15206
Blocked-by: #15207
History: this line read
Blocked-by: #15193, #15196, #15204, #15205, #15206, #15207until 2026-09-27, inside backticks, so no unlock scan could read it (the triage census counted it as a blocked card with no machine target). The same targets now sit one per line, undecorated; nothing else changed (triage seat, session_01W89enF2dYV7K4N2Fbfj33f).Part of #15194 (ADR-0131 execution tree). ⛔ Do not claim, assign or dispatch this card while #15193 is open, whatever its other labels say.
In one sentence. Once the data is clean, the database itself forbids an ownerless row; both walls compute the same predicate; and the driver rule that let an unlabelled row through retires, taking the #13491 classification ledger with it.
NOT NULLconstraint is applied per table, only on tables C7's report shows clear. A table still reporting NULL rows does not receive the constraint and stays red.Scope. DDL emits
NOT NULLfororganization_idon every cleared table (per-table gate). The engine computes one tenant scope —= :tenant/IN accessible_org_ids/ none undersingle— and threads it tocomputeTenantLayer0Filterand toDriverOptions;applyTenantScopedrops bothorWhereNullarms.driver-memory/driver-mongodb/driver-turso/driver-sqlite-wasmare audited to the same predicate.check-tenant-chokepoint.mjsrefuses anIS NULLarm.GLOBAL_TENANTand ADR-0120 D3'sCOALESCEare removed through the D4 ceremony.platform-object-tenancy.ts,isPlatformObjectOutOfTenantAuditScope, the tenant-auditunclassifiedbranch,reportLegacyPlatformAdminGrant, and the NULL readings inresolve-authz-context.ts/sharing-rule-service.ts/settings-service.ts/meta-write-org-scope.ts/bootstrap-system-capabilities.tsall retire. The id columns C2 left beside the name columns are dropped here. Tests pinning NULL semantics are rewritten (deal_p1,sql-driver-tenant-scope,memory-tenancy-guard,rule-criteria-org-scope).Acceptance. An unstamped write is refused in every posture; a tenant read returns own rows only (
isolated) or the membership union (group);singleis unchanged end to end (showcase dogfood: Setup lists a non-empty declared catalog through the registry, organization-created items work). Ablation: re-adding one arm reddens exactly the predicate pin. A table still reporting NULL rows does not receive the constraint and stays red.Protocol 18. Clause-②: yes — this changes the accept set.
Refs: ADR-0131 D1, D8, D9, D13, D14 · ADR-0105 D2 · ADR-0120 D3/D4/D7 · #2734 · #10103 cause 1 · #13491.