diff --git a/content/docs/deployment/cli.mdx b/content/docs/deployment/cli.mdx index cc0f5769b63..f90159de36c 100644 --- a/content/docs/deployment/cli.mdx +++ b/content/docs/deployment/cli.mdx @@ -763,7 +763,7 @@ diverges from the live schema, and the physical column wins at write time. |---------|-------------| | `os migrate plan` | Dry-run: show how the database has drifted from metadata, categorised safe / needs-confirm / destructive (no changes applied) | | `os migrate apply` | Reconcile the database to metadata. Applies loosening changes; destructive ones require `--allow-destructive` | -| `os migrate multi-value-columns` | Migrate a stale `varchar`/`text` column to `json` where the field declares `multiple: true` — one of two drift ops `apply` never reconciles for you. Dry run by default; `--apply` runs the statement the finding prints | +| `os migrate multi-value-columns` | Migrate a stale `varchar`/`text` column to `json` where the field declares `multiple: true` — one of three drift ops `apply` never reconciles for you. Dry run by default; `--apply` runs the statement the finding prints | ```bash os migrate plan # Preview drift (no changes) @@ -852,7 +852,7 @@ occupancy on its own. | Category | Examples | Applied by | |----------|----------|------------| | `safe` | relax `NOT NULL` → nullable, widen a `varchar`, create a declared index (a `UNIQUE` one only when its duplicate pre-flight comes back clean), replace a legacy installation-wide unique with its per-organization composite | `os migrate apply` (and dev auto-reconcile) | -| `needs_confirm` | non-narrowing type change, rebuild a non-unique index whose columns changed | `os migrate apply` — except `manual_widen_varchar_to_text`, which nothing applies | +| `needs_confirm` | non-narrowing type change, rebuild a non-unique index whose columns changed | `os migrate apply` — except `manual_column_type_change` (only `os migrate multi-value-columns --apply` runs it), and `manual_widen_varchar_to_text` and `unbuildable_index`, which nothing applies | | `destructive` | drop an orphaned column or index, tighten `NOT NULL`, narrow a type, rebuild an index as `UNIQUE`, create a `UNIQUE` index existing rows already violate | `os migrate apply --allow-destructive` | #### Index drift @@ -865,6 +865,7 @@ occupancy on its own. | `replace_unique_index` | A field's `unique` used to be enforced installation-wide, but metadata now scopes it per organization — the legacy single-column index is swapped for the NULL-safe `(COALESCE(organization_id, '__global__'), field)` composite. A pure relaxation: it creates before it drops, and cannot fail | | `recreate_index` | An index exists under the declared name but with different columns/uniqueness. The additive sync skips it by name, so it must be dropped and rebuilt. This is also how a per-organization unique becomes NULL-safe: a **tightening**, so it runs a duplicate pre-flight probe first — rows the old NULL-distinct index wrongly admitted **block** the op with a report instead of failing a boot, and the old index stays in place until they are resolved | | `drop_index` | An index carrying ObjectStack's generated naming (`uniq_…` / `idx_…`) that metadata no longer declares | +| `unbuildable_index` | Metadata declares an index whose key column can never exist: the name is not a field of the object (a misspelling), or it is a virtual `formula` field. Report-only, category `needs_confirm`: severity `error` for a `UNIQUE` index (the declared uniqueness is not enforced), `warning` for a plain one. `os migrate apply` never performs it — it reports the entry `skipped`. Fix the metadata: make every column in the index's `fields` a stored field, or remove the index. A column that is merely not added yet is pending `add_columns` work and is not reported | Orphan detection is deliberately limited to indexes ObjectStack itself generated. A hand-rolled covering index you added in `psql` is never reported as @@ -887,7 +888,7 @@ it reconciles via a table rebuild (copy → swap) that preserves your data. #### `os migrate multi-value-columns` -`os migrate apply` will **never** apply this drift op — and it isn't the only one: `manual_widen_varchar_to_text` (an unbounded text-family field left on a pre-existing `varchar` column) is also never applied, but has no `os migrate` subcommand of its own. This section covers the op that does. +`os migrate apply` will **never** apply this drift op — and it isn't the only one: `manual_widen_varchar_to_text` (an unbounded text-family field left on a pre-existing `varchar` column) and `unbuildable_index` (see [Index drift](#index-drift)) are also never applied, and have no `os migrate` subcommand of their own. This section covers `manual_column_type_change`, the op that does. A field that gains `multiple: true` over a database that already exists keeps its old `varchar` / `text` column: the additive sync adds columns, and never