Skip to content

Release rehearsal — the work inbox against production data (2026-09-23)

Rehearsal for the release that adds the work inbox (WRK-001…016), the outbound message queue lockdown (AUD-022) and a visa billed by its supplier. Done before the production migrations, as 15-platform-reliability and the 2026-09-19 rehearsal require.

1. What was restored

Source GitHub Actions run 35852911414, artifact supabase-backup-20260923T110957Z
Checksums all three verified (roles, schema, data)
Target local stack alhuda-rehearsal, port 59322
Result 130 public tables, zero schema errors

Restored per Backup & restore, including Correction 2 from 19 September: the local image's default privileges are revoked before schema.sql loads, or the copy grants anon and authenticated rights production does not have. 22 data errors, all in auth tables whose columns differ between production's auth service and the local one — the same list as 19 September, none of them business data.

The snapshot is five releases behind main. It was taken at 11:09 UTC; releases #387–#391 merged between 12:07 and 16:53. So anything this rehearsal reports as "missing in production" may simply post-date the backup. Where that matters it is said below.

Production carries very little data: 0 bookings, 0 customers, 10 journal entries. This is a system in use for configuration, not yet for trading.

2. What ran

The three migrations this release adds, in filename order, one transaction each, stopping on the first error — exactly as supabase db push would:

Migration Result
20260926200000_a_visa_is_billed_by_its_supplier.sql applied
20260926220000_work_inbox.sql applied
20260926230000_the_outbound_queue_is_for_senders.sql applied

Then all three again, to prove they are idempotent: no errors, and no duplicated seed rows (8 work.* permissions, 9 queues, 16 work types, 16 weights, 6 calendar days, 7 channel targets — the same counts as the first pass).

What production gains: 7 Work* tables, the business calendar, the eight work.* permissions with SUPER_ADMIN holding all of them through the existing Permission_grant_super_admin trigger, and CommunicationQueue going from one blanket staff policy to three permission-gated ones with no DELETE for anybody.

3. What broke, and what it means

Nothing in this release. 46 of 52 database suites passed on the production copy. All six failures are pre-existing or artefacts of the snapshot:

Suite Why it failed Is it this release?
access_model.sql ACC-049: OPS_MANAGER holds admin.cities.view and admin.locations.view but not admin.view, so it can act in the admin module without being able to open it No — passes on a database built from migrations
journal_write_paths.sql FIN-076: bookings.edit not granted to TICKET_MANAGER No — same family as above
lead_keeps_its_passengers.sql Lead.passengers does not exist No — that migration reached main at 16:53, after the 11:09 snapshot
incidents.sql the fixture cannot insert an Incident without a counter row No — test/data collision
tickets_visa_comms.sql duplicate key on CommunicationSetting_key_key No — the setting already exists in production
role_dashboards.sql counts differ against real rows No — also fails on the dev database

Two of these deserve the owner's attention, and neither is settled by this rehearsal because the snapshot is old:

  1. Grant coherence. If production still lacks admin.view for OPS_MANAGER and bookings.edit for TICKET_MANAGER, then an operations manager cannot open the admin pages they hold rights inside, and a ticketing manager cannot edit the bookings they are expected to ticket. Both are documented as granted in PERMISSIONS.md. Deliberately not "fixed" here: a migration that grants permissions on a hunch is permission widening, and if either was revoked on purpose that decision should be found before it is undone.
  2. Whether production has #387–#391's migrations at all. The CLI on this machine is not authenticated, so supabase migration list could not be run. Check it before pushing.

4. Before the push

  • npx supabase migration list — confirm what Remote is missing. Expect the three above; if it also lists #387–#391's migrations, production's database is behind its frontend and that is the more urgent thing.
  • Take a fresh backup (gh workflow run supabase-backup.yml) if the newest is older than the last release.
  • npx supabase db push applies in filename order and stops at the first failure. The 19 September rehearsal exists because a back-fill hit the FIN-031 voucher guard and would have stopped halfway.

5. After the push

  • npx supabase migration list — the three show against Remote.
  • select count(*) from "Permission" where name like 'work.%'; → 8.
  • select polname from pg_policy where polrelid = 'public."CommunicationQueue"'::regclass; → three communications.send policies, and not CommunicationQueue staff only.
  • Open /work as a member of staff: the inbox lists your own items, and rows from bookings, incidents, requests, visa enquiries, holds and groups appear read-only with Open links (WRK-001).
  • A cashier signing in should see the Work inbox in the nav and be unable to claim anything (ACC-044).