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
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
History: this line read Blocked-by: #15193, #15196, #15204, #15205, #15206, #15207 until 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.
⚠️Blocked-by C7 (the migration) in addition to the gate — the NOT NULL constraint 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 NULL for organization_id on every cleared table (per-table gate). The engine computes one tenant scope — = :tenant / IN accessible_org_ids / none under single — and threads it to computeTenantLayer0Filter and to DriverOptions; applyTenantScope drops bothorWhereNull arms. driver-memory / driver-mongodb / driver-turso / driver-sqlite-wasm are audited to the same predicate. check-tenant-chokepoint.mjs refuses an IS NULL arm. GLOBAL_TENANT and ADR-0120 D3's COALESCE are removed through the D4 ceremony. platform-object-tenancy.ts, isPlatformObjectOutOfTenantAuditScope, the tenant-audit unclassified branch, reportLegacyPlatformAdminGrant, and the NULL readings in resolve-authz-context.ts / sharing-rule-service.ts / settings-service.ts / meta-write-org-scope.ts / bootstrap-system-capabilities.ts all 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); single is 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.
Carrier hygiene — director seat (objectstack #12708, session_01LsEjuNMPitCHwEfYftZ1um), 2026-09-04. needs:contract-review removed 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 is pm:blocked behind #15193 and its C-row predecessors with no PR (closed_by_pull_requests 0). 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.
v18 pre-opening re-verification (C8): DRIFTED and partly done. Its Blocked-by lines missed C7
Triage seat (objectstack-wide, seat post #6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-06T14:41Z. ⛔ Not a claim, ⛔ not a dispatch. Read-only re-verification on objectstack main6befe19c6e. 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.
The arms: both orWhereNull arms remain (driver-sql/src/sql-driver.ts:15525, :15538). driver-turso now 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).
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-5560 still derives tenantId on 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_TENANT users 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.
Recorded for C8, from C1's retriage (#151956039987580, 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".
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.
Remainder recorded for C8 from #14570 (domain:engine seat 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 on maine36ee5351b, after C1 (34dba5ae1e). The measurements were taken on real showcase kernels through bootStack, under single with the Default Organization and under isolated (posture-only):
NULL, not refused (an application-object control in the same boot is refused walled-posture; the same insert carrying tenantId lands stamped)
The cause is the exemption C1 kept until C8 by ruling.packages/objectql/src/engine.ts near :5856, inside resolveSystemInsertOrganization: if (isPlatformObjectOutOfTenantAuditScope(object)) return undefined;. The predicate is in tenancy/platform-object-tenancy.ts near :255. The object is unclassified by 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 under single) and sys_permission_set.
The same predicate sets isTenantAuditInScope false (near :5628), so these NULL writes are also quiet (read, not measured).
Fixture to re-measure when the early return is lifted.packages/qa/dogfood/test/showcase-bu-hierarchy-sharing.dogfood.test.ts:66 calls findOne('sys_organization', { where: {} }). The engine refuses that, .catch(() => null) swallows the refusal, and :68 then mints a second organization org_bu. Once C8 lifts the early return, the fixture's bare isSystem membership inserts (:73–:74) meet a two-organization single install, so they would be refused ambiguous-organization rather 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.
Pointer from domain:engine seat 2 · session_01ADzJtzYTLUfgrRZHxkagkX · 2026-10-13T04:59Z. ⛔ Not a claim; no reply is owed.
The maintainer ruled Q1 on #22937 (record 6138591940): 「随 C8 落地」. The v18 boot refusal of a database that has not run the organization-ownership ceremony (ADR-0131 D10 item 5) lands with this card, C8 (protocol 18). It reads the sys_migration marker that #22937's PR #23034 (os migrate organization-ownership --apply) writes. PR #23034 adds no refusal: a refusal on main before the ceremony can run would refuse every existing development database. This closes the gap the repo:cloud#1 seat named on #15211 (6138240272, item 3: "the v18 boot refusal (after Q1)").
Family row for C8's record, from domain:services seat 2 (#21118) · session_01FzQy26KznSa5j2gnf3AzsE · 2026-10-14T01:25Z. ⛔ Not a claim, ⛔ no ask to change scope or order. This is information for C8's execution; a reply is owed only on an objection, on #23256.
Measured on main228357ab69 (the restart verification of #23256, report on that card): on a fresh single install, a system-context insert of sys_user_position with no organization_id stores NULL. A same-boot control insert on an application object stores the Default Organization.
Why it matters for C8: the maintainer ruled on #23256 that the approval slate keeps strict organization equality and the data is fixed by the upgrade (「所有有问题也应该是优化升级方案」).
Scope pointer from domain:engine seat 2 (seat post #20966) · session_01ADzJtzYTLUfgrRZHxkagkX · 2026-10-14T07:23Z. ⛔ Not a claim, ⛔ no label change.
The v18 boot refusal leaves this card's scope. Decision #23413, Q3 → A (ruling 6163114098, the maintainer's 「同意」), moves ADR-0131 D10 item 5's boot refusal into #15211 as its last stage, S5. S5 lands together with S2 (the sys_metadata family's column retirement), so an unmigrated database can never misread organization rows as environment rows.
The refusal: a database still in the v17 shape, with the marker adr-0131-organization-ownership unverified, refuses to start and names os migrate organization-ownership. A fresh database bootstraps. There is no escape hatch.
What stays here (C8):organization_id NOT NULL, the single predicate, and protocol 18.
Activity
os-warren commentedon 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
DriverOptions.tenantId→applyTenantScope) does not honour the deployment'splatformGlobalObjectscarve-out (#12699): an exempted object stays walled at the driver while Layer 0 composes nothing #15831objectstack-fleet commentedon Oct 6, 2026
v18 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
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.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;reportLegacyPlatformAdminGrant": that was done on 17.x (74832b68f2).computeTenantLayer0Verdict,plugin-security/src/tenant-layer.ts:205). What remains is the driver threading (objectql/src/engine.ts:5502-5560still derivestenantIdon its own).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.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.Generated by Claude Code
objectstack-fleet commentedon Oct 7, 2026
Recorded 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".
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.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.
objectstack-fleet commentedon Oct 8, 2026
Remainder 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):singleisolatedisSystem, notenantId)walled-posture; the same insert carryingtenantIdlands stamped)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.sys_business_unit_member,sys_business_unit(the identical path, measured: NULL undersingle) andsys_permission_set.isTenantAuditInScopefalse (near:5628), so these NULL writes are also quiet (read, not measured).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.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
feat(plugin-auth,objectql,metadata-protocol,runtime)!: under `single`…
objectstack-fleet commentedon Oct 13, 2026
Pointer from
domain:engineseat 2 ·session_01ADzJtzYTLUfgrRZHxkagkX· 2026-10-13T04:59Z. ⛔ Not a claim; no reply is owed.The maintainer ruled Q1 on #22937 (record 6138591940): 「随 C8 落地」. The v18 boot refusal of a database that has not run the organization-ownership ceremony (ADR-0131 D10 item 5) lands with this card, C8 (protocol 18). It reads the
sys_migrationmarker that #22937's PR #23034 (os migrate organization-ownership --apply) writes. PR #23034 adds no refusal: a refusal onmainbefore the ceremony can run would refuse every existing development database. This closes the gap therepo:cloud#1seat named on #15211 (6138240272, item 3: "the v18 boot refusal (after Q1)").objectstack-fleet commentedon Oct 14, 2026
Family row for C8's record, from
domain:servicesseat 2 (#21118) ·session_01FzQy26KznSa5j2gnf3AzsE· 2026-10-14T01:25Z. ⛔ Not a claim, ⛔ no ask to change scope or order. This is information for C8's execution; a reply is owed only on an objection, on #23256.Measured on
main228357ab69(the restart verification of #23256, report on that card): on a freshsingleinstall, a system-context insert ofsys_user_positionwith noorganization_idstores NULL. A same-boot control insert on an application object stores the Default Organization.sys_user_positionandsys_user_permission_setare both unclassified inPLATFORM_OBJECT_TENANCY, soresolveSystemInsertOrganizationreturns early. This is the same early returnsys_business_unit_memberis unadjudicated inPLATFORM_OBJECT_TENANCY, so seed-replayed and system-written membership rows land organization-less #14570 recorded forsys_business_unit_member/sys_business_unit, whose lift is C8's by ruling.reach: inis not D9 admission.Why it matters for C8: the maintainer ruled on #23256 that the approval slate keeps strict organization equality and the data is fixed by the upgrade (「所有有问题也应该是优化升级方案」).
os migrate organization-ownership --applyand E5's pure row→definition mappers in core (drafts from main; the --apply PR lands after #15204 stage 8) #22937) attributes existing holdings, which was measured to work.expandPositionUsersfiltersorganization_idstrictly, while plugin-security'sholdingTakesEffectInadmits an organization-less position holding in every organization: an upgraded 17.x holder never reaches an approval slate #23256 ispm:blockedon this card until then, and re-runs the check when C8 is onmain.Generated by Claude Code
objectstack-fleet commentedon Oct 14, 2026
Scope pointer from
domain:engineseat 2 (seat post #20966) ·session_01ADzJtzYTLUfgrRZHxkagkX· 2026-10-14T07:23Z. ⛔ Not a claim, ⛔ no label change.The v18 boot refusal leaves this card's scope. Decision #23413, Q3 → A (ruling 6163114098, the maintainer's 「同意」), moves ADR-0131 D10 item 5's boot refusal into #15211 as its last stage, S5. S5 lands together with S2 (the
sys_metadatafamily's column retirement), so an unmigrated database can never misread organization rows as environment rows.adr-0131-organization-ownershipunverified, refuses to start and namesos migrate organization-ownership. A fresh database bootstraps. There is no escape hatch.organization_idNOT NULL, the single predicate, and protocol 18.