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 f2ee5ad
Browse filesBrowse the repository at this point in the historyBrowse files
feat(cli): `os migrate plan` lists the tenant columns still nullable and names the voluntary organization-ownership ceremony; the ceremony reports a rotation shard already NOT NULL as such (#25134)
6
+
7
+
Clause-②: yes (widening) — `os migrate plan --json` gains the `nullableTenantColumns` field, and the ceremony's `not-null` step gains the `already-not-null` outcome and the `alreadyNotNull` summary count. No exit code, drift entry, op, refusal or accepted input moves.
8
+
9
+
Metadata-protocol: none
10
+
11
+
A database the published 18.0.0 created is certified at birth with its tenant columns (`organization_id`) nullable, and `os migrate organization-ownership`, which tightens them to `NOT NULL`, is voluntary on it. Nothing told the operator that.
12
+
13
+
-**`os migrate plan`: a new advisory section.** It lists every tenant column the database still holds nullable (table and column) and names `os migrate organization-ownership` as the remedy. Each column says whether the ceremony tightens it or leaves it, and why. The ceremony leaves a rotation shard created before shards were created `NOT NULL`, `sys_email_template` (its rows are mirrors the ceremony deletes, and the table retires), a table its inventory exempts, and every table on a database whose transport cannot rebuild a table (the Turso remote face). When the ceremony would tighten none of the listed columns, the section says so and does not offer it. A fresh install lists nothing. A column named `organization_id` on an object with tenancy disabled (`sys_sso_provider`) is not a tenant column and is not listed.
14
+
-**Advisory only.** It is not drift: it proposes no change, adds nothing to `total` or `changes`, and the exit code does not change. Under `--json` it is the separate field `nullableTenantColumns`: `{ status: 'read', adr, remedy, columns: [{ table, column, database?, ceremony: 'tightens' | 'leaves', reason? }] }`, or `{ status: 'unreadable', adr, detail }` when the plan could not read it.
15
+
-**The ceremony's `not-null` step.** A rotation shard that the driver created `NOT NULL` used to be reported as `unsupported`, with a note saying each new shard is created nullable. That has not been true since the driver began creating shards `NOT NULL`. Such a shard is now `already-not-null` (counted in `alreadyNotNull`) and gets no note. A shard rotated in before then stays `unsupported`, and its note says it is dropped when its period leaves the base table's retention.
16
+
17
+
**What to do.** Nothing is required: the server starts either way. To tighten the columns the plan lists, run `os migrate organization-ownership --out PLAN`, review it, then run `os migrate organization-ownership --apply --plan-file PLAN --backup-taken`.
fix(cli,create-objectstack): new projects declare vitest `~4.1.12`, outside GHSA-qxg6-89mg-rqv8, and still install on npm 10
7
+
8
+
Clause-②: no
9
+
Metadata-protocol: none
10
+
11
+
The vitest range every scaffold declares moves from `~4.0.0` to `~4.1.12`: the `create-objectstack` blank template, `os init -t plugin` and `os create plugin` (in `devDependencies`), and the npm `overrides` block that every standalone scaffold emits, `os init -t app` and `-t empty` included. `~4.0.0` resolved to vitest and `@vitest/mocker` 4.0.18, inside GHSA-qxg6-89mg-rqv8 (`@vitest/mocker` from 2.1.0-beta.7 up to the fix in 4.1.12), which has no 4.0.x fix. A new project now resolves vitest and `@vitest/mocker` 4.1.12 or a later 4.1.x patch, and `npm audit` of a fresh scaffold lists no vitest or `@vitest/*` advisory.
12
+
13
+
npm 10, the npm Node 22 bundles, still installs every scaffold. The `overrides.vitest` entry, which equals `devDependencies.vitest`, is what makes that hold: it settles vitest 4.1.12's contradictory optional peer (`@vitest/browser-webdriverio`), which npm 10 otherwise crashes on with `Cannot read properties of null (reading 'edgesOut')`. Measured on npm 10.9.4, 10.9.9 and 11.21.1. pnpm ignores npm's `overrides` field.
14
+
15
+
**An existing project made by an earlier `create-objectstack`, `os init` or `os create plugin`** keeps its own `~4.0.0`. To move it, set `overrides.vitest` to `~4.1.12` in `package.json`, and `devDependencies.vitest` too where the project declares it, then run `npm install`. npm refuses an override that differs from the direct dependency (`EOVERRIDE`), so the two move together.
Copy file name to clipboardExpand all lines: content/docs/deployment/cli.mdx
+31Lines changed: 31 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -986,6 +986,37 @@ without `NODE_ENV=development` describes a production `os serve`, which keeps th
986
986
objects in the primary unless `OS_TELEMETRY_DB` names a file. A `plan` against a
987
987
sibling that does not exist yet lists its tables to create and leaves no file behind.
988
988
989
+
#### Tenant columns still nullable (advisory)
990
+
991
+
`os migrate plan` lists every tenant column the database still holds nullable, in a
992
+
section of its own, and names `os migrate organization-ownership` as the remedy. A
993
+
database the published 18.0.0 created is certified at birth with its tenant columns
994
+
nullable, and the [organization-ownership ceremony](#os-migrate-organization-ownership)
995
+
that tightens them is voluntary on it: the server starts either way. A database the
996
+
ceremony upgraded keeps only the few the ceremony leaves, and each of those is listed
997
+
with the reason it stays nullable:
998
+
999
+
```text
1000
+
ℹ 2 tenant column(s) are still nullable (ADR-0131 D1). This is advisory: it is not drift, and nothing in this plan or in "os migrate apply" changes it.
1001
+
• sys_activity__r20261020.organization_id — the ceremony leaves it nullable: a rotation shard of sys_activity, created before shards were created NOT NULL: the ceremony rebuilds no shard, and it is dropped when its period leaves sys_activity's retention
1002
+
• sys_email_template.organization_id — the ceremony leaves it nullable: its rows are mirrors the ceremony deletes, and the table retires (ADR-0131 D10 fate 2, D13), so the ceremony does not tighten it
1003
+
None of them is one the organization-ownership ceremony tightens; each line says why it stays nullable.
1004
+
```
1005
+
1006
+
When the ceremony would tighten any listed column, the section's last line names its
1007
+
two commands instead. On a Turso remote database every listed column is one the
1008
+
ceremony leaves, because that transport cannot rebuild a table. A fresh install creates
1009
+
every tenant column `NOT NULL` and the section prints nothing. A column named
1010
+
`organization_id` on an object with tenancy disabled (`sys_sso_provider`) is not a
1011
+
tenant column and is not listed.
1012
+
1013
+
The section is advisory only. It is not drift: it proposes no change, adds nothing to
1014
+
the change count, and does not change the exit code. Under `--json` it is the separate
1015
+
`nullableTenantColumns` field: `{ status: "read", adr, remedy, columns }`, where each
1016
+
column is `{ table, column, database?, ceremony: "tightens" | "leaves", reason? }`. It is
1017
+
`{ status: "unreadable", detail }` when the plan could not read it; `columns: []` means
1018
+
it read and found none.
1019
+
989
1020
#### Nothing is applied before you confirm
990
1021
991
1022
Both commands boot your app to read its metadata. That boot writes no row and no
Copy file name to clipboardExpand all lines: content/docs/deployment/troubleshooting.mdx
+6-4Lines changed: 6 additions & 4 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -12,19 +12,21 @@ Solutions to the most common issues encountered when working with ObjectStack.
12
12
13
13
### "Cannot read properties of null (reading 'edgesOut')" from npm install
14
14
15
-
**Symptom:** npm exits 1 with `npm error Cannot read properties of null (reading 'edgesOut')` while installing `@objectstack/cli` or `@objectstack/plugin-auth`. This includes the install step of `npm create objectstack` and `npm install -g @objectstack/cli`.
15
+
**Symptom:** npm exits 1 with `npm error Cannot read properties of null (reading 'edgesOut')` while installing `@objectstack/cli` or `@objectstack/plugin-auth`. This includes `npm install -g @objectstack/cli`, and `npm install` in a project whose `package.json` has no `vitest` override (fix 2).
16
16
17
-
**Cause:** npm 10, the npm that Node 22 ships, crashes on an optional `vitest` peer in the auth library's dependency tree: the newest vitest 4 has no matching `@vitest/browser-webdriverio` release. npm 11 and pnpm install the same packages, and `npm ci` from a committed lockfile is not affected.
17
+
**Cause:** npm 10, the npm that Node 22 ships, crashes on the newest vitest 4, 4.1.12. Its optional peer `@vitest/browser-webdriverio ^4.1.11` has one matching release, 4.1.11, and that release requires exactly vitest 4.1.11. npm 10 reaches vitest through an optional `vitest` peer in the auth library's dependency tree, or through your project's own `vitest`. npm 11 and pnpm install the same packages, and `npm ci` from a committed lockfile is not affected.
18
18
19
19
**Fix** (either one):
20
20
21
21
1.**Use npm 11** (it needs Node 22.9+): run `npm install -g npm@11`, then repeat the install. This is the only fix for `npm install -g`, because a global install reads no `overrides`. In a Dockerfile, install under a pinned npm 11, as the [self-built runtime recipe](/docs/deployment/self-hosting#docker-official-image--the-standard-path) does.
22
-
2.**Stay on npm 10 and pin vitest** in your project's root `package.json`. Then run `npm install` again and commit the lockfile:
22
+
2.**Stay on npm 10 and pin vitest** in your project's root `package.json`. The override puts every `vitest` in the tree, optional peers included, on one range, and npm 10 installs it. Then run `npm install` again and commit the lockfile:
23
23
24
24
```json title="package.json"
25
-
"overrides": { "vitest": "~4.0.0" }
25
+
"overrides": { "vitest": "~4.1.12" }
26
26
```
27
27
28
+
If `devDependencies` lists `vitest`, set it to the same `~4.1.12`: npm refuses an override that differs from a direct dependency (`EOVERRIDE`). A project created by `npm create objectstack`, `os init` or `os create plugin` already has this block. If yours reads `~4.0.0`, an earlier scaffold's value, change both to `~4.1.12`: `~4.0.0` installs vitest 4.0.18, which is affected by security advisory GHSA-qxg6-89mg-rqv8.
29
+
28
30
This entry, the npm 11 steps in [Self-hosting](/docs/deployment/self-hosting), and the npm 10 notes in [Getting Started](/docs/getting-started#prerequisites) and [Your First Project](/docs/getting-started/your-first-project#prerequisites) can be removed once `@vitest/browser-webdriverio` publishes the version that `npm view vitest dist-tags` lists as `V4`, and a plain npm 10 install of `@objectstack/plugin-auth` passes.
0 commit comments