Skip to content

Commit dee9b26

Browse files
docs(cli): document unbuildable_index drift op and complete the never-applied set (#20563)
Fixes #20538 Clause-②: no `content/docs/deployment/cli.mdx` now documents the report-only `unbuildable_index` drift op (added by #20519) and names the complete never-applied set. ## Before / after `needs_confirm` row (category table) - before: `os migrate apply` — except `manual_widen_varchar_to_text`, which nothing applies - after: `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 New Index-drift row (after `drop_index`) - after: `unbuildable_index` — a declared index whose key column can never exist (name is not a field of the object, or a virtual `formula` field). Report-only, category `needs_confirm`; severity `error` for a UNIQUE index, `warning` for a plain one. `os migrate apply` never performs it and reports it `skipped`. A column merely not added yet is pending `add_columns` work and is not reported. `os migrate multi-value-columns` prose - before: "it isn't the only one: `manual_widen_varchar_to_text` (...) is also never applied, but has no `os migrate` subcommand of its own. This section covers the op that does." - after: names `manual_widen_varchar_to_text` and `unbuildable_index` as also never applied, with no subcommand of their own; the section covers `manual_column_type_change`. Command table row for `os migrate multi-value-columns` (same never-applied set) - before: "one of two drift ops `apply` never reconciles" - after: "one of three drift ops" ## Code anchors measured on origin/main 6154165 - `packages/drivers/driver-sql/src/schema-drift.ts:294` `unbuildable_index` member of `DriftOp` (fields `table`, `column?`, `indexName`, `unique`, `missingColumns`); `:373` listed in `INDEX_DRIFT_OPS`; `:378` in `IndexDriftOp`. - `schema-drift.ts:1970-1975` doc: classified `needs_confirm`, `os migrate apply` reports it skipped; UNIQUE is `error`, plain is `warning`. - `schema-drift.ts:1976-2020` `diffUnbuildableIndexes`: `severity: idx.unique ? 'error' : 'warning'` (`:2001`), `category: 'needs_confirm'` (`:2002`); qualifies only when a key column is absent AND never materializes (misspelt name or virtual `formula`, `:1958-1963`); a not-yet-added column is excluded (`:1965-1968`). - `packages/drivers/driver-sql/src/sql-driver.ts:13884` `applyIndexDriftOp`: `if (op.type === 'unbuildable_index') return false;`, so the entry is reported `skipped` on every dialect (call site `:13865`, dispatch `:14022`). - `manual_column_type_change` never applied: `schema-drift.ts:166-180` (no reconciler arm, "skipped, never applied ... the intended behaviour"), emitted at `:1137-1138` as severity `error`, category `needs_confirm`; `sql-driver.ts:14131` (no reconciler arm on any dialect, by decision). - `manual_widen_varchar_to_text`: `schema-drift.ts:212`, emitted `:1341-1342` as `error` / `needs_confirm`. The code agrees with the card on every point, with one correction found in review: `manual_column_type_change` is never applied by `os migrate apply` but IS applied by `os migrate multi-value-columns --apply` (`packages/cli/src/commands/migrate/multi-value-columns.ts:105-107` selects only that op; `:315-318`, `:338-339` the `--apply` path), so the row separates it from the two ops nothing applies. Follow-up commit b982ca1. Nothing was copied from the card without a read. ## Acceptance notes - CLI source and `os migrate apply`'s skip-summary wording are untouched (other lane). - Gates (re-run on b982ca1, 36 of 41 derived, all exit 0 except the one below): docs-relevant families derived by `dispatch-gates.mjs --commands` run in the foreground; all 0 except `check:skill-examples`, which exits 3 (PREREQUISITE NOT MET: needs a `@objectstack/client-react` build; not a finding, NOT MEASURED). Neither `check:docs` nor `check:docs-transcript-drift` nor `check:nul-bytes` flags the change. - Docs-only; no changeset (`content/docs/**` is not shipped in a package `files[]`). - Commit trailers are the model-free pair. ## 维护者速读(草稿) Not applicable: no managed path (`.claude/**`) is touched. --- 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01VDtqoecgES7ScQYGbFVDRv --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 199002b commit dee9b26

1 file changed

Lines changed: 4 additions & 3 deletions

File tree

‎content/docs/deployment/cli.mdx‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -763,7 +763,7 @@ diverges from the live schema, and the physical column wins at write time.
763763
|---------|-------------|
764764
| `os migrate plan` | Dry-run: show how the database has drifted from metadata, categorised safe / needs-confirm / destructive (no changes applied) |
765765
| `os migrate apply` | Reconcile the database to metadata. Applies loosening changes; destructive ones require `--allow-destructive` |
766-
| `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 |
766+
| `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 |
767767
768768
```bash
769769
os migrate plan # Preview drift (no changes)
@@ -852,7 +852,7 @@ occupancy on its own.
852852
| Category | Examples | Applied by |
853853
|----------|----------|------------|
854854
| `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) |
855-
| `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 |
855+
| `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 |
856856
| `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` |
857857
858858
#### Index drift
@@ -865,6 +865,7 @@ occupancy on its own.
865865
| `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 |
866866
| `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 |
867867
| `drop_index` | An index carrying ObjectStack's generated naming (`uniq_…` / `idx_…`) that metadata no longer declares |
868+
| `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 |
868869
869870
Orphan detection is deliberately limited to indexes ObjectStack itself
870871
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.
887888
888889
#### `os migrate multi-value-columns`
889890
890-
`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.
891+
`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.
891892
892893
A field that gains `multiple: true` over a database that already exists keeps
893894
its old `varchar` / `text` column: the additive sync adds columns, and never

0 commit comments

Comments
 (0)