Repository navigation
chore: delete retired guests, refresh the schema snapshot, document non-rolling upgrades - #75
Conversation
RetireGuestUsers hid guest content and marked each guest's personal workspace for deletion, leaving the user rows "until a later cleanup". This is that cleanup. Deleting a guest user cascades to its personal organization, workspace, memberships and tokens. Pastes restrict workspace deletion, so they go first: - Inline pastes live only in PostgreSQL, so the migration deletes them, which is all the cleaner would do for them. - Pastes with a storage key also have an object in local or S3 storage that a migration cannot reach. They are left to the cleaner, and their guest is skipped. On an install where the cleaner has run since RetireGuestUsers (it purges marked workspaces every 15 minutes by default) nothing is skipped. On an install that applies both migrations in one go, only guests with stored pastes remain, as inert rows; the admin "Guest" status and test fixture stay for them. The migration test shares its database setup and covers a guest with an inline paste (deleted), a guest with a stored paste (kept) and a registered account (untouched). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019fnjMN7WpEjQJD2zveakV6
priv/repo/structure.sql had not been dumped since #59, so it was missing every migration from #63 onward: paste title and reference, last-used workspace, the removal lifecycle and recovery window, guest retirement, appearance, and the guest deletion migration. Regenerated with `mix ecto.migration` against PostgreSQL 17.11, the major version CI runs and the one the previous snapshot came from. pending_uploads now lists claimed_at before inserted_at with plain `timestamp`, which is what its migration creates (both columns are :utc_datetime_usec); the old snapshot's order and explicit precision did not come from these migrations. The types are identical. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019fnjMN7WpEjQJD2zveakV6
The upgrade procedure promises migrations are safe under a rolling deployment. Two recent ones are not, and the web app and its background cleaner run in the same instance, so one old instance left running is enough: - The paste lifecycle migration. Older code treats a paste as live unless it has expired, so it would show pastes deleted under the new code, and its cleaner would hard-delete expired pastes that are still restorable. - The guest retirement migration. Older code still creates guest accounts, and those would never be retired. Also note that the two guest migrations cannot be undone, and what is left behind when an install applies both at once. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019fnjMN7WpEjQJD2zveakV6
Remove conflicting rolling-deployment guidance for retirement. Limit rolling guest deletion to guest-free lifecycle-aware instances, and explain that skipped user rows require later cleanup. Exercise migrations from before retirement and assert storage-backed guests remain retired/token-free while registered accounts are unchanged. 564 tests and Credo pass.
|
Oracle review complete: signed off after correcting contradictory upgrade guidance. Guest retirement still requires stopping all old instances. The later guest-deletion migration supports normal rolling deployment only when all running instances already use guest-free, lifecycle-aware code. Clarified that storage-backed guests skipped by the migration remain pending a later user cleanup even after the cleaner purges their pastes. Strengthened the migration test: fixtures now predate retirement, retained guests have deletion markers/expired pastes/revoked tokens, and registered accounts remain unaffected. No migration SQL or schema snapshot changes were required by review. Validation: mix precommit (564 ExUnit tests plus JS tests) and mix credo passed. Corrections committed and pushed without rewriting published history. No production migration or deployment was triggered. Review session: https://ampcode.com/threads/T-01a12594-e2f1-75be-b343-9239564f5c84 Post-push CI is green: memory/local/S3 Elixir tests, Rust tests, formatting/linting, and production-container build all passed. Release/publication jobs skipped as expected. |
Summary
Three follow-ups left over from the design stack, #63–#69.
1. Delete retired guest users (
20261012090000)RetireGuestUsershid guest content and left the user rows "until a later cleanup". This migration is that cleanup.2. Regenerate
priv/repo/structure.sqlon PostgreSQL 17The snapshot hadn't been dumped since #59, so it was missing every migration from #63 on. I regenerated it with
mix ecto.migrationagainst PG 17.11, the major version CI runs. One change isn't from a migration:pending_uploadsnow listsclaimed_atbeforeinserted_at, which is the order its migration creates. The column types are the same.3. Upgrade guidance in
docs/self-hosting.mdThe upgrade guide promised that every migration was safe during a rolling deploy. Two aren't, and each instance runs its own cleaner, so one old instance left running is enough to cause trouble:
The guide now says to stop every old instance before running
/app/bin/migratefor these two. It also notes which migrations can't be undone.Deploying this to an existing install
The safe sequence:
Test plan
mix test: 564 tests, 0 failures.mix credoreports no issues.mix compile --warnings-as-errorsis clean.🤖 Generated with Claude Code
https://claude.ai/code/session_019fnjMN7WpEjQJD2zveakV6
Generated by Claude Code