diff --git a/content/docs/concepts/metadata-lifecycle.mdx b/content/docs/concepts/metadata-lifecycle.mdx
index a2d1780fa27..a3f1b64ef78 100644
--- a/content/docs/concepts/metadata-lifecycle.mdx
+++ b/content/docs/concepts/metadata-lifecycle.mdx
@@ -106,7 +106,7 @@ later ships. See [ADR-0070](https://github.com/objectstack-ai/objectstack/blob/m
**Most metadata types must not be overlaid by an environment** — overlaying a packaged item would break the physical schema or the behaviour its package ships. The whitelist lives in **one** place: `MetadataTypeRegistryEntry.allowEnvironmentOverlay` in `packages/spec/src/kernel/metadata-plugin.zod.ts` (spelled `allowOrgOverride` before protocol 18; `GET /api/v1/meta/types` serves it per entry as `allowEnvironmentOverlay`).
-> **ADR-0131 D6 — the per-organization overlay axis is retired.** The `/meta` doors (REST and the runtime dispatcher) carry no organization into a metadata write or read: a Studio or `PUT /api/v1/meta/...` write of the five ✅ types below lands **environment-wide** (since ADR-0131 D7 the `sys_metadata` family declares no organization column) and is served to every organization, and an organization admin holding only the retired `manage_org_presentation` capability is refused (`403`). The protocol itself refuses every organization-scoped write, and every read — item, list, layers, cached, history, diff, audit, drafts and the commit timeline — is environment → code, whatever organization a caller names. An overlay row an earlier release stored under an organization — under the `single` posture, every Studio save of these types, filed under the Default Organization — is served by no read, and an 18.x `os serve` refuses to start on a database still holding one until the v18 migration ceremony (ADR-0131 C7: `os migrate organization-ownership --out PLAN`, then `--apply --plan-file PLAN`) has carried it to the environment layer and dropped the column; nothing deletes or rewrites it before then. The anonymous form doors read the environment alone too: the ceremony carries every organization-layer public-form withdrawal onto the environment, fail-closed. The table still records which types take an overlay of a shipped item.
+> **ADR-0131 D6 — the per-organization overlay axis is retired.** The `/meta` doors (REST and the runtime dispatcher) carry no organization into a metadata write or read: a Studio or `PUT /api/v1/meta/...` write of the five ✅ types below lands **environment-wide** (since ADR-0131 D7 the `sys_metadata` family declares no organization column) and is served to every organization, and an organization admin holding only the retired `manage_org_presentation` capability is refused (`403`). The protocol itself refuses every organization-scoped write, and every read — item, list, layers, cached, history, diff, audit, drafts and the commit timeline — is environment → code, whatever organization a caller names. An overlay row an earlier release stored under an organization — under the `single` posture, every Studio save of these types, filed under the Default Organization — is served by no read, and on a SQL database (SQLite, PostgreSQL, MySQL) still holding one a v18 `os serve` refuses to start. 18.0 supports fresh installs only and does not upgrade a v17 database: keep a v17 database on a 17.x release until the 18.x release that carries the upgrade path. In that release, the v18 migration ceremony (ADR-0131 C7: `os migrate organization-ownership --out PLAN`, then `--apply --plan-file PLAN`) carries such a row to the environment layer and drops the column; nothing deletes or rewrites it before then. The anonymous form doors read the environment alone too: in that release the ceremony carries every organization-layer public-form withdrawal onto the environment, fail-closed. The table still records which types take an overlay of a shipped item.
| Type | `allowEnvironmentOverlay` | Rationale |
| :--- | :---: | :--- |
diff --git a/content/docs/deployment/cli.mdx b/content/docs/deployment/cli.mdx
index 4a9160f8908..dd6f1128007 100644
--- a/content/docs/deployment/cli.mdx
+++ b/content/docs/deployment/cli.mdx
@@ -196,18 +196,25 @@ os dev --database file:./data/test.db --auth-secret $(openssl rand -hex 32)
| `--seed-admin` / `--no-seed-admin` | — | Seed a dev admin (`admin@objectos.ai` / `admin123`) on an empty DB — default on; override with `--admin-email` / `--admin-password` |
| `-v, --verbose` | — | Verbose output |
-##### A 17.x development database is upgraded in place
+##### A 17.x development database
A v18 server refuses to start on a database still in the v17
organization-ownership shape until the [ownership ceremony](#os-migrate-organization-ownership)
-has run on it. `os dev` runs that ceremony for you when the database is a local
-SQLite file:
+has run on it.
18.0 supports fresh `single` installs; upgrades and walled postures arrive in 18.x. In 18.0 the ceremony refuses, so `os dev` stops at step 2 with its
refusal and changes nothing.
+18.0 does not upgrade a v17 database: keep a v17 database on a 17.x release
+until the 18.x release that carries the upgrade path. For a local SQLite file,
+`os dev` in 18.0 still takes step 1's copy first and prints where it is,
+beside the ceremony's `NOT_IMPLEMENTED` refusal; any other database gets no
+copy and the same answer.
+In the 18.x release that carries the upgrade path, `os dev` runs that ceremony
+for you when the database is a local SQLite file:
+
1. It copies the database file and its `telemetry` sibling (each with its
`-wal` / `-shm`) into `/backups/organization-ownership-/`.
2. It runs `os migrate organization-ownership --dev` (the plan), then applies
@@ -215,12 +222,14 @@ refusal and changes nothing.
beside the copy.
3. It prints the ceremony's warnings and starts the server again.
-If a step blocks, or the post-check still holds rows (a row whose owner cannot
+In that release, if a step blocks, or the post-check still holds rows (a row whose owner cannot
be derived, named per table with its remedy), `os dev` stops and prints what
holds it, where the copy is, and the command that resumes the run. It tries once per session. A database that is
not a local SQLite file (PostgreSQL, a remote libSQL, `:memory:`) is not
-upgraded in place: run the ceremony yourself. `os serve` and `os start` never run
-it; they refuse and name the command.
+upgraded in place: run the ceremony yourself.
+
+`os serve` and `os start` never run the ceremony: they refuse to start, and on
+a v17 database their 18.0 refusal says that 18.0 does not upgrade it.
##### Serving dev over https
@@ -1025,13 +1034,18 @@ safe. No flag skips these refusals:
- `sys_account.issuer` is dropped only when its retirement pre-flight reads the
table clean (`os migrate account-issuer` reports the colliding rows).
- `sys_comment.reactions` waits for a verified `os migrate comment-reactions --apply` run.
-- `organization_id` on any table the organization-ownership ceremony covers
- waits for a verified `os migrate organization-ownership --apply --plan-file FILE`
- run. These tables are the ADR-0131 D7 tables and the `sys_metadata` family.
- The ceremony drops those columns itself, in its column-drops step, before it
- records the run verified. Dropping one first would turn every legacy
+- `organization_id` waits for a verified run of the organization-ownership
+ ceremony, on every table the drift offers to drop it from: the ceremony plans
+ every table that still carries the column, the ADR-0131 D7 tables and the
+ `sys_metadata` family among them. Dropping one first would turn every legacy
organization row into an environment row. Under `--json` the refusal answers
`message: 'refused_organization_ownership_unmigrated'` and lists the `tables`.
+ 18.0 itself never records a verified run, so on a v17 database this refusal
+ holds on every run. 18.0 supports fresh installs only and does not upgrade a
+ v17 database: keep a v17 database on a 17.x release until the 18.x release
+ that carries the upgrade path. In that release, the ceremony's
+ `os migrate organization-ownership --apply --plan-file FILE` run drops these
+ columns itself, in its column-drops step, before it records the run verified.
Each refusal holds the whole `--allow-destructive` run: nothing in it is
created, applied or dropped, the run's other changes included. A run without
@@ -1478,14 +1492,15 @@ reports the failed read and exits `1`. A failed read or write exits `1`.
The v18 ownership ceremony (ADR-0131 D10). A v18 `os serve` / `os start` refuses
to start on a database still in the v17 organization-ownership shape until this
-has run. Under `os dev` it runs on its own for a local SQLite database (see
-[`os dev`](#os-dev)).
+has run. In the 18.x release that carries the upgrade path, `os dev` runs it on
+its own for a local SQLite database (see [`os dev`](#os-dev)).
18.0 supports fresh `single` installs; upgrades and walled postures arrive in 18.x. In 18.0 this command refuses, plan and apply alike: it exits `1` with
`NOT_IMPLEMENTED` (under `--json`, `code` beside `error`) and reads and
writes nothing. Keep a v17 database on a 17.x release until the 18.x release
-that carries the upgrade path.
+that carries the upgrade path. The invocations below, and what the list after
+them says the ceremony does, are that 18.x release's.
```bash
diff --git a/content/docs/kernel/contracts/metadata-service.mdx b/content/docs/kernel/contracts/metadata-service.mdx
index 3489e9ab65b..c082d2d5b3d 100644
--- a/content/docs/kernel/contracts/metadata-service.mdx
+++ b/content/docs/kernel/contracts/metadata-service.mdx
@@ -412,11 +412,16 @@ overlay axis is retired: the doors carry no organization, so the overlay is
column, ADR-0131 D7) and served to every organization
of the deployment, whatever the author's active organization. Every protocol
read is environment → code, whatever organization a caller names. An overlay
-row an earlier release stored under an organization is served by no read, and
-an 18.x `os serve` refuses to start on a database still holding one until the
-v18 migration ceremony (ADR-0131 C7) has carried it to the environment layer. The anonymous form doors read the environment alone too: the ceremony carries
-every organization-layer public-form withdrawal onto the environment,
-fail-closed. The per-user,
+row an earlier release stored under an organization is served by no read. On a
+SQL database (SQLite, PostgreSQL, MySQL) still holding one, a v18 `os serve`
+refuses to start, because the `sys_metadata` family there still carries its
+`organization_id` column. 18.0 supports fresh installs only and does not
+upgrade a v17 database: keep a v17 database on a 17.x release until the 18.x
+release that carries the upgrade path. In that release, the v18 migration
+ceremony (ADR-0131 C7) carries such a row to the environment layer. The
+anonymous form doors read the environment alone too; in that release the
+ceremony carries every organization-layer public-form withdrawal onto the
+environment, fail-closed. The per-user,
per-field patch overlay a previous revision of this page taught here was
removed in #13135 — it was never served by any route.
diff --git a/content/docs/permissions/capabilities.mdx b/content/docs/permissions/capabilities.mdx
index 9a3af4ea755..847f32c0bb1 100644
--- a/content/docs/permissions/capabilities.mdx
+++ b/content/docs/permissions/capabilities.mdx
@@ -217,8 +217,11 @@ and resource `requiredPermissions` match capability names **as strings**. The
boot writes no row for a capability, declared or curated: both are served by
the registry. The `sys_capability` object itself is retired and no longer
registered (ADR-0131 D3): a row an older database still holds is served by no
-route and read by nothing, and `os migrate organization-ownership --apply`
-reports the authored rows and deletes the seeded copies (ADR-0131 D10).
+route and read by nothing. In the 18.x release that carries the upgrade path
+(18.0 does not upgrade a v17 database: see
+[`os migrate organization-ownership`](/docs/deployment/cli#os-migrate-organization-ownership)),
+`os migrate organization-ownership --apply` reports the authored rows and
+deletes the seeded copies (ADR-0131 D10).
Withdraw a capability by withdrawing the **grant**.
diff --git a/content/docs/permissions/permission-sets.mdx b/content/docs/permissions/permission-sets.mdx
index 84ec96ec1ec..f3710de1cc1 100644
--- a/content/docs/permissions/permission-sets.mdx
+++ b/content/docs/permissions/permission-sets.mdx
@@ -396,7 +396,10 @@ posture, the platform operator. This has three author-visible consequences:
package. Uninstall the owning package to remove a packaged set entirely.
An older database keeps the `sys_permission_set` table and its rows, and
-nothing serves or reads them. `os migrate organization-ownership --apply`
+nothing serves or reads them. In the 18.x release that carries the upgrade
+path (18.0 does not upgrade a v17 database: see
+[`os migrate organization-ownership`](/docs/deployment/cli#os-migrate-organization-ownership)),
+`os migrate organization-ownership --apply`
(ADR-0131 D10) converts the sets an organization authored in Setup into
environment metadata under `single` and deletes the seeded copies. The shipped
sets that an install created before 2026-08-15 stored as `managed_by: 'admin'`