From 2f9543db3187d31aa88f978ff29e387b58aa81a0 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 23 Oct 2026 00:43:16 +0000 Subject: [PATCH] docs(objectql): the injected organization_id is stamped on insert and NOT NULL on a table the driver creates "Multi-Tenant Schemas" said the column stays NULL where no organization context exists. Since the driver creates a tenant column NOT NULL, a table it creates refuses that write. Say what main does: the stamp (ADR-0131 D9), the NOT NULL at CREATE TABLE (ADR-0131 D1 and the tenant-column-not-null-ddl changeset), the tables that stay nullable until the ownership ceremony, and the opt-out for organization-less rows. Claude-Session: https://claude.ai/code/session_01Er1tmLgRYyGBSrDcDsUMqQ Co-authored-by: Claude --- content/docs/protocol/objectql/schema.mdx | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/content/docs/protocol/objectql/schema.mdx b/content/docs/protocol/objectql/schema.mdx index d7dbf6ebf40..88e341307c8 100644 --- a/content/docs/protocol/objectql/schema.mdx +++ b/content/docs/protocol/objectql/schema.mdx @@ -719,9 +719,9 @@ full_name: Row-level isolation runs on **one platform column**: `organization_id`, a lookup to `sys_organization`. The registry injects it into every registered object that has not -opted out (`hidden`, `readonly`, `required: false` — it is server-populated on insert -and stays NULL where no organization context exists), so a tenant-scoped object -declares **nothing** about tenancy: +opted out (`hidden`, `readonly`, `required: false` — the platform stamps it on +insert, so the author never writes it), so a tenant-scoped object declares **nothing** +about tenancy: ```yaml name: customer @@ -731,6 +731,22 @@ fields: required: true ``` +`required: false` describes the authoring surface, not the stored value: NULL is not an +organization (ADR-0131 D1). An insert is stamped with the writer's organization — under +the `single` posture, with the Default Organization — and a write that names none is +refused wherever an organization can exist (ADR-0131 D9). A table the SQL or Turso +driver creates carries the column `NOT NULL` at `CREATE TABLE`, so the database itself +refuses a row with no organization, an `upsert` included (ADR-0131 D1; changeset +`tenant-column-not-null-ddl` of `@objectstack/driver-sql` and `@objectstack/driver-turso`). +The in-memory driver enforces no `NOT NULL`. A table that already existed — created by an +earlier release, or one the driver adds the column to — keeps a nullable column until +[`os migrate organization-ownership`](/docs/deployment/cli#os-migrate-organization-ownership) +tightens it, and that ceremony cannot tighten a rotated shard or a table on the Turso +remote face; [`os migrate plan`](/docs/deployment/cli#tenant-columns-still-nullable-advisory) +lists every tenant column still nullable, with the reason. An object whose rows belong +to no organization does not leave the column empty — it opts out, and has no column at +all. + The column's existence does not depend on the deployment's tenancy posture — only its *index* does, since nothing filters by organization on a single-organization stack. An object opts **out** by declaring `tenancy.enabled: false`