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
15 changes: 15 additions & 0 deletions .changeset/orphan-search-column-runbook.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
---

Document how to handle database-only columns reported by `os migrate plan` after
a platform upgrade (#528): a new "Destructive schema drift" section in
`docs/MAINTENANCE.md` covering how to tell a genuine orphan from a
runtime-provisioned column the planner cannot see, and the safe
`os migrate apply --allow-destructive` procedure (stop the service, back up,
clear every destructive entry against both tests, apply, verify).

Records the 17.0 `__search` report as a known **false positive**: those 9 columns
are live pinyin search-companion columns, not orphans, and dropping them breaks
search. Root cause is a schema-view mismatch between the migrate CLI and the dev
runtime, filed upstream as objectstack#3955; no cleanup on that class until it is
fixed. Documentation only — releases nothing.
62 changes: 62 additions & 0 deletions docs/MAINTENANCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,68 @@ can silently invalidate existing metadata or **seed data** (see §4). Treat ever
and restart. This is an environment issue, not an app change.
7. Note the new platform version in `CHANGELOG.md`.

### 3.1 Destructive schema drift — database-only columns after an upgrade

`os migrate plan` diffs the live database schema against the current metadata.
After a platform upgrade it can report columns that exist in the database but
are not described by any metadata the planner can see. Some are genuine orphans
— companion columns an older platform version provisioned automatically and the
new version no longer does. A genuine orphan is harmless (nothing reads or
writes it), so cleaning it up is **deferred by design**: schedule it for a
maintenance window instead of bundling it into the upgrade itself. Others are
not orphans at all, only invisible to the planner, and dropping them causes an
outage — so the first job is always to tell the two apart.

> [!WARNING]
> **Not every "orphan" the planner reports is really an orphan.** `os migrate
> plan` describes the schema as the *migrate CLI* understands it, which is not
> always what the *running server* provisioned. A column the runtime creates and
> actively uses can show up as database-only, and dropping it breaks the feature
> that depends on it. Confirm what a column is for before you let anything drop
> it — see the `__search` case below for a live example of this exact trap.

**Known false positive — `__search` companion columns
([#528](https://github.com/objectstack-ai/hotcrm/issues/528)).** After the 17.0
upgrade, `os migrate plan` reports 9 database-only `__search` columns
(`crm_competitor`, `crm_opportunity_line_item`, `crm_quote_line_item`,
`crm_task`, `sys_metadata`). **They are not orphans — do not drop them.**
Column-level comparison on two freshly created databases from the same artifact
showed the split clearly: the database created by `objectstack dev` has 34
columns on `crm_task` *including* `__search`, while the one created by
`os migrate plan --database-url <new file>` has 33 *without* it — and migrate
reports 0 destructive changes against the database it built itself. The
`__search` columns are live pinyin search-companion columns that the dev runtime
provisions and reads; the report is a **schema-view mismatch between the migrate
CLI and the dev runtime**, filed upstream as
[objectstack#3955](https://github.com/objectstack-ai/objectstack/issues/3955).
Dropping them removes working search columns, and the next dev boot may simply
recreate them. **Take no cleanup action on this class until #3955 is fixed.**

Cleanup procedure — for columns you have *positively identified* as genuine
orphans (the `__search` class above is excluded until #3955 lands):

1. **Stop the service first.** Applying destructive schema changes under live
traffic is unsafe — see ObjectStack platform issue #526.
2. Back up the database (for a local dev database, copy `.objectstack/data`).
3. Run `os migrate plan` and read the whole plan. Clear **every** destructive
entry against two questions, not one:
- *Does it back a field you still declare?* If yes, stop and fix the metadata
drift instead of dropping the column.
- *Is it a runtime-provisioned companion column* (search/index/derived
helpers such as `__search`)? These belong to the running server, not to
your metadata, so the planner cannot vouch for them. If you cannot prove a
column is dead, treat it as live and stop.

A useful proof: point `os migrate plan --database-url` at a **freshly
created** database from the same artifact and compare column lists. Anything
present in both is being provisioned on purpose, whatever the plan calls it.
4. Run `os migrate apply --allow-destructive`.
5. Restart the service and smoke-test: `os migrate plan` should now be clean,
and global search in the Console should still return records.

`--allow-destructive` drops columns irreversibly — never run it without the
backup from step 2, and never against a database whose plan you have not read.

## 4. Seed-data staleness — the #1 HotCRM pitfall

Stale seed data is the most common cause of "Studio shows a red
Expand Down
Loading