> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tuturuuu.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Migration Incident Rollbacks

> Manual rollback inventory and forward-only token containment

## Manual batch rollback inventory

These files are manual incident artifacts under `apps/database/rollbacks/`, not
forward migrations. They are never automatically applied by the migration gate.
Take release-authority approval, stop affected writers/callers, retain the exact
source and catalog receipt, and run one file at a time with `psql -X -v
ON_ERROR_STOP=1 -f FILE` against the explicitly approved database. Do not change
hosted migration ledgers to replay history. Recovery uses an approved forward
repair; local rehearsal alone may use `supabase migration repair --local`.

For a whole batch, use reverse apply order:

| Order | Migration / PR | Manual artifact | Restores / limits |
| - | - | - | - |
| 1 | `20261026173000` / #6840 | `20261026173000_bound_cross_app_token_minting.containment.sql` | Forward-only containment; retains bounded minting DDL and revoked tokens. |
| 2 | `20261026172000` / #6880 | `20261026172000_pending_tuition_legacy_floor_before_first_explicit_month.rollback.sql` | Previous pending-tuition calculation; no invoice data rewrite. |
| 3 | `20261026170000` / #6879 | `20261026170000_least_privilege_workspace_storage_rls.incident-rollback.sql` | Prefer this incident variant. The sibling `.rollback.sql` restores broader legacy access and reopens the reviewed finding; use only with explicit risk acceptance. |
| 4 | `20261026145300` / #6460 | `20261026145300_reap_stale_devbox_runs.rollback.sql` | Previous S4 claim body; removes reaper/lease guard. Does not resurrect reaped runs or released leases. |
| 5 | `20261026145200` / #6460 | `20261026145200_guard_active_devbox_runs_index.rollback.sql` | No persistent object to undo; records the deliberate no-op. |
| 6 | `20261026145100` / #6460 | `20261026145100_index_active_devbox_runs.rollback.sql` | Concurrent index drop; no table data loss. |
| 7 | `20261026145000` / #6457 | `20261026145000_devbox_claim_mode_admission.rollback.sql` | Previous drain-aware claim body; drops S4 settings/freshness timestamps, preserving the earlier drain column and operational history. |

Devbox rollback removes admission/lease protections. Drain and stop all claim,
enqueue and control callers, deploy a compatible caller before resuming, and do
not run #6457's rollback while #6460 still depends on S4. The historical function
bodies are pinned in the files; compare them with the intended pre-migration
version before use. There is no `CASCADE` fallback for unexpected dependencies.
Every transactional file bounds locks to five seconds and statements to thirty
seconds; a busy database aborts the transaction for diagnosis and a fresh retry.

The index file sets session timeouts (five-second locks, five-minute statement)
and uses `DROP INDEX CONCURRENTLY`. Run it alone in autocommit: never use `BEGIN`,
`psql -1`/`--single-transaction`, or a runner that wraps/batches the file. Long
transactions can delay a concurrent drop. On timeout/cancellation, inspect
`pg_stat_activity`, `pg_stat_progress_create_index` and the exact index catalog
before retrying; do not start another build/drop blindly. Close the dedicated
session or reset both timeouts if execution stopped before the file's resets.

## Cross-app token containment is forward-only

The `20261026173000` migration bounds both minting overloads and marks overlong
unused tokens revoked. It leaves their expiry and other evidence intact, but
stores neither the previous revocation bit nor migration-specific provenance.
Never un-revoke rows or restore the vulnerable generator bodies. Rolling back
an application deployment does not restore these handoff credentials: users must
start a new bounded handoff after recovery.

1. Stop cross-app handoff routes and privileged minting callers. Keep server-side
   lifetime/audience validation in place.
2. Run the containment file. It revokes client `EXECUTE` for both minting
   overloads and marks at most 1,000 unused, unrevoked rows per invocation. It
   never changes used tokens, expiry fields or other audit data. Existing
   service/admin privileges remain; those callers must stay stopped separately.
3. Read `revoked_now` and `remaining`. Repeat bounded invocations after writers
   stop until `remaining = 0`; locked rows skipped by `SKIP LOCKED` still count
   as remaining. A nonzero count is incomplete containment. Stop and diagnose
   timeout/contention rather than retrying indefinitely.
4. Review a forward repair, prove both overloads' bounds and denial tests, then
   explicitly restore `authenticated` execution on the two signatures listed in
   the file. Do not broadly grant privileges. The original forward migration
   restates those grants; replay it only in a disposable rehearsal, not by
   changing a hosted ledger. Existing revocations remain permanent.

The disposable proof applies the complete batch with the real Supabase CLI,
compares Devbox function bodies/owners/ACLs, columns, indexes, triggers and
constraints with snapshots taken before each step, rolls back in reverse order,
and re-applies. Containment is checked separately for bounded progress,
idempotency, preserved expiry/used rows, denied client minting and permanent
revocation after re-apply. It intentionally cannot reproduce #6840's old catalog
or credential validity; no reversible rollback is claimed for that security fix.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.