Found upgrading HotCRM to 17.0.0-rc.0 (tag commit fc156fa4a). Operational-safety report, not a crash.
Facts (verified in source)
- No occupancy detection anywhere on the path:
packages/cli/src/commands/migrate/apply.ts:64-160 gates only on --allow-destructive and the [y/N] prompt; packages/cli/src/utils/schema-migrate.ts:72-115 connects with no lock/-wal/PID check. Zero hits for busy_timeout / SQLITE_BUSY / "database is locked" handling across packages/cli/src and packages/plugins/driver-sql/src. - DDL before consent:
schema-migrate.ts:100await runtime.start() boots the full plugin set, which runs syncRegisteredSchemas (packages/objectql/src/plugin.ts:431/:456) — create-table/add-column DDL is issued against the target DB before the drift plan is rendered and the confirm prompt is shown (apply.ts:130). - For scope calibration:
replace_unique_index is plain index DDL (sql-driver.ts:2704-2733), and the SQLite column-op table rebuild (:2816-2877) swaps tables within the file inside one transaction — the DB file inode is never replaced. So the exposure with a live dev server on the same file is stale prepared statements / schema-cookie churn / SQLITE_BUSY during exclusive transactions, not a swapped-out file.
Ask
- Detect a live writer (e.g.
-wal/-shm presence + PRAGMA-based probe, or an advisory lock) and warn/refuse without --force. - Defer all DDL (including boot-time schema sync) until after the plan is confirmed, or run the plan phase against a read-only connection.
Found upgrading HotCRM to 17.0.0-rc.0 (tag commit
fc156fa4a). Operational-safety report, not a crash.Facts (verified in source)
packages/cli/src/commands/migrate/apply.ts:64-160gates only on--allow-destructiveand the[y/N]prompt;packages/cli/src/utils/schema-migrate.ts:72-115connects with no lock/-wal/PID check. Zero hits forbusy_timeout/SQLITE_BUSY/ "database is locked" handling acrosspackages/cli/srcandpackages/plugins/driver-sql/src.schema-migrate.ts:100await runtime.start()boots the full plugin set, which runssyncRegisteredSchemas(packages/objectql/src/plugin.ts:431/:456) — create-table/add-column DDL is issued against the target DB before the drift plan is rendered and the confirm prompt is shown (apply.ts:130).replace_unique_indexis plain index DDL (sql-driver.ts:2704-2733), and the SQLite column-op table rebuild (:2816-2877) swaps tables within the file inside one transaction — the DB file inode is never replaced. So the exposure with a live dev server on the same file is stale prepared statements / schema-cookie churn /SQLITE_BUSYduring exclusive transactions, not a swapped-out file.Ask
-wal/-shmpresence + PRAGMA-based probe, or an advisory lock) and warn/refuse without--force.