diff --git a/skills/deploy/SKILL.md b/skills/deploy/SKILL.md index 9d36756..5a97eb5 100644 --- a/skills/deploy/SKILL.md +++ b/skills/deploy/SKILL.md @@ -66,6 +66,38 @@ money. That is not hypothetical. - **A dirty tree means TRACKED changes.** `git status --porcelain` counts untracked files; a stray script a fast-forward could never touch is not a reason to skip a host. Use `--untracked-files=no`. +# `db:push` can offer data loss at a prompt, and it waits for an answer + +A schema push on a host that is many commits behind can stop and ask whether a table was RENAMED. Both +answers destroy something, so neither is safe to guess and neither is safe to automate. + +Seen 2026-08-27 catching `edge-pertento-bridge` up by 215 commits: + +``` +Is command_hq_spawned table created or renamed from another table? +❯ + command_hq_spawned create table + ~ dav_app_passwords › command_hq_spawned rename table +``` + +drizzle-kit saw one table leaving the platform schema and another arriving, and could not tell a rename +from a coincidence. `rename` would have turned the DAV app passwords into the spawned-commander table; +`create` would have dropped them. + +**The table had not gone anywhere — it had moved to a PLUGIN.** Caldav was extracted that day, so +`dav_app_passwords` belongs to `plugins/caldav/db/schema.ts` and reaches the barrel through +`gen-plugin-schemas`. Installing the plugin FIRST declares it, and the question disappears. + +So, on a host far enough behind that a plugin extraction is in the gap: + +1. Install the plugins whose tables are involved, **before** pushing. +2. Then `bun db:push < /dev/null` — stdin closed, so it can never hang waiting on a prompt in an + unattended run. A push that needs an answer fails instead, which is the outcome you want. +3. Expect ONE failure on a `role_permissions` foreign key, then `seed-roles.ts`, then push again. That + sequence is normal on a host predating the roles table. + +**Back up the database first.** `pg_dump` against the URL in `.env` — and read the variable name rather +than assuming: several hosts use `OFFICERDEV_POSTGRES_URL`, not `POSTGRES_URL`. + # The report is an artefact, the lock is the record Write the local record FIRST, then commit and push the report. If the push fails, say so and stop: the