Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions content/docs/releases/v18/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,47 @@ in one major (its D14) instead of spreading them across 17.x minors. While the
line was open, every other breaking change that landed on `main` shipped on it
too, under the same rules.

## Upgrading a database to 18.0.0

An existing database moves to 18.0.0 through the **organization-ownership
ceremony**, `os migrate organization-ownership` (ADR-0131 D10).

- **A fresh install writes a birth marker.** The first boot that creates a
datastore from empty writes a `sys_migration` row
(`adr-0131-organization-ownership`) naming the ownership shape generation it
was born in. A fresh 18.0.0 install never needs the ceremony, under any
tenancy posture.
- **A database without one is refused at boot.** A database 17.x or an 18.0
pre-release (`18.0.0-next.*`) created carries no birth marker, so an 18.0.0
server refuses it and names the ceremony command. Start 18.0.0 against it
once (the refused boot still creates the tables 18.0.0 adds), take a backup,
run `os migrate organization-ownership --out plan.json`, review the plan, run
`os migrate organization-ownership --apply --plan-file plan.json --backup-taken`,
and start the server again. The ceremony writes the same marker, verified,
when its post-check passes.
- **A development boot passes `--dev`.** On a deployment served with `--dev`
(`os dev`, `os serve --dev`), for example a local one with no
`OS_AUTH_SECRET`, both ceremony commands take `--dev`, as the refusal
`os serve --dev` prints names them. `os dev` runs the ceremony itself for a
local SQLite development database.
- **Walled postures boot.** `OS_TENANCY_POSTURE=group` and `isolated` (and
`OS_MULTI_ORG_ENABLED=true`) boot on a fresh install and on a database the
ceremony upgraded, under the same prerequisites as 17.x: the enterprise
`@objectstack/organizations` runtime and `OS_PLATFORM_OWNER_EMAIL`. The
18.0 pre-releases refused them; 18.0.0 does not.
- **A production `os serve` needs an auth secret.** A production `os serve`
whose stack enables auth and which resolves no `OS_AUTH_SECRET` is refused
before any plugin starts: with no AuthPlugin, no caller can
authenticate and every row the boot wrote would have no owner. Set the
secret, or serve without the data API (`--no-server`). `os dev` and
`os serve --dev` use a development fallback and need none, and `os start`
generates an auth secret on its first run and persists it to
`<home>/auth-secret`.

The step-by-step is [Upgrading to 18.0](/docs/upgrading#upgrading-to-180), and
every flag is in
[`os migrate organization-ownership`](/docs/deployment/cli#os-migrate-organization-ownership).

## How a breaking stage lands on this line

- **Through `next` before `latest`.** Every major is published to the `next`
Expand Down
56 changes: 56 additions & 0 deletions content/docs/upgrading.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,61 @@ writes no artifact, which makes it the fast inner loop while you work through
the to-dos. Full command reference in the [CLI
documentation](/docs/deployment/cli).

## Upgrading to 18.0

18.0 refuses to serve an existing database until an operator step has run on
it. [ADR-0131](https://github.com/objectstack-ai/objectstack/blob/main/docs/adr/0131-total-organization-ownership-no-null-organization-id.md)
makes organization ownership total, and the rows a 17.x database holds have to
be given their owners before an 18.0 server serves them. That is the
**organization-ownership ceremony**, `os migrate organization-ownership`.

**Which databases need it.** A database 17.x created, or one an 18.0
pre-release (`18.0.0-next.*`) created. The first boot that creates a datastore
from empty writes a **birth marker**, so a fresh 18.0 install never needs the
ceremony, under any tenancy posture. A v18 server serves a database it created
itself or one the ceremony certified, and refuses any other at boot, naming the
command.

**The sequence:**

1. Start 18.0 against the database once (`os serve` / `os start`). The boot is
refused, but its schema sync has already created the tables 18.0 adds, which
the ceremony moves rows into.
2. Take a backup. The platform takes none.
3. Write the plan: `os migrate organization-ownership --out plan.json`. It reads
only.
4. Review the plan.
5. Apply exactly that plan:
`os migrate organization-ownership --apply --plan-file plan.json --backup-taken`.
6. Start the server again.

```bash
os migrate organization-ownership --out plan.json
os migrate organization-ownership --apply --plan-file plan.json --backup-taken
```

**A development boot passes `--dev` to both commands.** A deployment served
with `--dev` (`os dev`, `os serve --dev`), for example a local one with no
`OS_AUTH_SECRET`, composes as a development boot, and the ceremony has to boot
the same way to see the same database. The refusal `os serve --dev` prints names
the command with `--dev`. `os dev` runs the whole sequence itself for a local
SQLite development database.

**Walled postures upgrade too.** `OS_TENANCY_POSTURE=group` and `isolated` boot
in 18.0 on a fresh install and on a database the ceremony upgraded. On a walled
database, a customized copy of a declared webhook or sharing rule blocks its
step and names the row.

**A production `os serve` deployment needs an auth secret.** A production
`os serve` whose stack enables auth and which resolves no `OS_AUTH_SECRET` is
refused before any plugin starts, so set the secret before you start such a
deployment on 18.0. `os start` is not affected: it generates an auth secret on
its first run and persists it to `<home>/auth-secret`.

What the plan lists, how a blocked row is resolved, and every flag are in the
command's reference:
[`os migrate organization-ownership`](/docs/deployment/cli#os-migrate-organization-ownership).

## Per-release specifics

Everything above is the mechanism. The *contents* of a given release — which keys
Expand All @@ -349,6 +404,7 @@ have no other channel to reach you than the page below.

| Release | Where its upgrade notes live |
| :--- | :--- |
| v18.0.0 | [Upgrading to 18.0](#upgrading-to-180) (the ownership ceremony) · [v18](/docs/releases/v18) |
| v17.4.0 | [17.4.0](/docs/releases/v17/17-4) — ⛔ checklist not written; machine-draft notes only |
| v17.3.0 | [Upgrade checklist — 17.3.0](/docs/releases/v17/17-3#upgrade-checklist) |
| v17.2.0 | [Upgrade checklist — 17.2.0](/docs/releases/v17/17-2#upgrade-checklist) |
Expand Down
14 changes: 7 additions & 7 deletions packages/cli/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

### Minor Changes

- fc34d00: feat(cli): `os serve` (and so `os dev` and `os start`) boots a walled tenancy posture again; `group` and `isolated` are supported on fresh installs
- fc34d00: feat(cli): `os serve` (and so `os dev` and `os start`) boots a walled tenancy posture again; `group` and `isolated` are supported on fresh installs and on databases the ownership ceremony upgraded

Clause-②: yes (widening)

Expand Down Expand Up @@ -159,18 +159,18 @@
os migrate organization-ownership --out plan.json # plan, then review plan.json
os migrate organization-ownership --apply --plan-file plan.json --backup-taken # perform exactly that plan
```
- ae6bd1a: feat(cli)!: 18.0 supports fresh `single` installs only — `os migrate organization-ownership` refuses, and `os serve` refuses a walled posture at boot
- ae6bd1a: feat(cli)!: the 18.0 pre-release refusals of `os migrate organization-ownership` and of a walled posture at boot, both lifted in 18.0.0

Clause-②: yes (narrowing)

<!-- adr-0087: not-required (no-migration-prescription) Nothing an author writes, and no stored shape an author owns, is added, removed, renamed or converted: a CLI command and two deployment postures that used to run now refuse, with no spec key, export, config field or error code removed or renamed. The remedy is an operator's one, stated below: stay on 17.x, or run 18.0 under `single` on a fresh database. -->
<!-- adr-0087: not-required (no-migration-prescription) Nothing an author writes, and no stored shape an author owns, is added, removed, renamed or converted: a CLI command and two deployment postures refused in an 18.0 pre-release, with no spec key, export, config field or error code removed or renamed. 18.0.0 lifts both refusals (12d1476 and fc34d00 in this section), so the operator's remedy is the ownership ceremony, stated below. -->

**BREAKING** (a command and a boot posture that used to run now refuse), shipped as `minor` under the launch-window convention for breaking changes. 18.0 supports fresh installs under the `single` tenancy posture only; upgrading a v17 database and the walled postures arrive in an 18.x release.
**This entry described `18.0.0-next.5`, not 18.0.0.** That pre-release refused the ownership ceremony and the walled postures. 18.0.0 ships neither refusal:

- **FROM** `os migrate organization-ownership` (plan) and `os migrate organization-ownership --apply …` running the v18 ownership ceremony **TO** both refusing with exit `1` and the standard code `NOT_IMPLEMENTED` (under `--json`: `{ error: 'plan_refused' | 'apply_refused', reason: 'upgrade-unavailable', code: 'NOT_IMPLEMENTED', detail }`), reading and writing nothing. The 18.0 ceremony is knowingly incomplete, and an incomplete ceremony must never certify an old database. **Fix:** keep a v17 database on a 17.x release until the 18.x release that carries the upgrade path. `os dev`'s in-place upgrade of a v17 development database runs this command, so it now stops with the same refusal and changes nothing.
- **FROM** `os serve` (and so `os dev` and `os start`) booting with `OS_TENANCY_POSTURE=group` or `isolated`, or with `OS_MULTI_ORG_ENABLED=true`, **TO** a FATAL refusal at the tenancy-posture gate, exit `1`, naming `NOT_IMPLEMENTED` and the 18.x release, before a config is read. `OS_ALLOW_DEGRADED_TENANCY` does not lift it, and no flag or variable does. **Fix:** set `OS_TENANCY_POSTURE=single` (or unset it and `OS_MULTI_ORG_ENABLED`), or keep a walled deployment on a 17.x release.
- **`os migrate organization-ownership` runs** and upgrades a database 17.x or an 18.0 pre-release (`18.0.0-next.*`) created (12d1476 above). A v18 server refuses such a database at boot and names the command. Start 18.0.0 against it once (the boot is refused), take a backup, run `os migrate organization-ownership --out plan.json`, review the plan, run `os migrate organization-ownership --apply --plan-file plan.json --backup-taken`, then start the server again. A deployment served as a development boot (`os dev`, `os serve --dev`, for example a local one with no `OS_AUTH_SECRET`) passes `--dev` to both commands, as the refusal `os serve --dev` prints names it. `os dev` runs the ceremony itself for a local SQLite development database.
- **`os serve` (and so `os dev` and `os start`) boots `OS_TENANCY_POSTURE=group` or `isolated`, and `OS_MULTI_ORG_ENABLED=true`** (fc34d00 above), on a fresh install and on a database the ceremony upgraded.

**What stays as it was.** A fresh install under `single` boots exactly as before. The boot guard that refuses a v17-shaped database is unchanged. Kernel-level boots (`@objectstack/verify`'s `bootStack`, embedded hosts) still accept every posture.
**What else holds.** A fresh install boots under every tenancy posture and writes its birth marker, so it never needs the ceremony. Kernel-level boots (`@objectstack/verify`'s `bootStack`, embedded hosts) still accept every posture.
- 78652c0: feat(cli,plugin-sharing)!: in the 17 → 18 ownership ceremony, a row whose owner cannot be derived blocks certification, and a declared-rule mirror's grants are renamed only onto a rule plugin-sharing serves

Clause-②: yes (narrowing)
Expand Down
Loading