From cd46f849df9586e0f1148f3a0848fc6d4a6515a6 Mon Sep 17 00:00:00 2001 From: CompAII Date: Fri, 4 Sep 2026 17:07:59 +0000 Subject: [PATCH] [verified] fix(live): move remaining Umbral sessions to 14:00 ART Signed-off-by: CompAII --- .../migration.sql | 41 +++++++++++++++++++ src/app/__tests__/page.test.tsx | 8 ++-- src/app/page.tsx | 21 +--------- src/lib/__tests__/public-cycle.test.ts | 19 ++++++++- 4 files changed, 63 insertions(+), 26 deletions(-) create mode 100644 prisma/migrations/20260901180000_move_remaining_umbral_sessions_to_1400_argentina/migration.sql diff --git a/prisma/migrations/20260901180000_move_remaining_umbral_sessions_to_1400_argentina/migration.sql b/prisma/migrations/20260901180000_move_remaining_umbral_sessions_to_1400_argentina/migration.sql new file mode 100644 index 00000000..a25dbd2c --- /dev/null +++ b/prisma/migrations/20260901180000_move_remaining_umbral_sessions_to_1400_argentina/migration.sql @@ -0,0 +1,41 @@ +-- Sai moved the two remaining public-cycle sessions to 14:00 Argentina +-- (America/Argentina/Cordoba, UTC-3), which is 17:00 UTC. Historical sessions +-- keep their actual times. Access, facilitator and room state remain intact. +BEGIN; + +WITH corrected_sessions ("id", "scheduled_at") AS ( + VALUES + ('50000000-0000-4000-8000-202609050001'::uuid, '2026-09-05 17:00:00'::timestamp), + ('50000000-0000-4000-8000-202609120001'::uuid, '2026-09-12 17:00:00'::timestamp) +) +UPDATE "scheduled_sessions" AS session +SET + "scheduled_at" = corrected_sessions."scheduled_at", + "updated_at" = CURRENT_TIMESTAMP +FROM corrected_sessions +WHERE session."id" = corrected_sessions."id" + AND session."status" = 'SCHEDULED'::"ScheduledSessionStatus"; + +DO $$ +DECLARE + initialized_count integer; + corrected_count integer; +BEGIN + SELECT count(*) INTO initialized_count FROM "users"; + + SELECT count(*) INTO corrected_count + FROM "scheduled_sessions" + WHERE ("id", "scheduled_at") IN ( + ('50000000-0000-4000-8000-202609050001'::uuid, '2026-09-05 17:00:00'::timestamp), + ('50000000-0000-4000-8000-202609120001'::uuid, '2026-09-12 17:00:00'::timestamp) + ) + AND "status" = 'SCHEDULED'::"ScheduledSessionStatus"; + + IF initialized_count = 0 AND corrected_count <> 0 THEN + RAISE EXCEPTION 'Empty installation contains a partial remaining Umbral cycle'; + ELSIF initialized_count > 0 AND corrected_count <> 2 THEN + RAISE EXCEPTION 'Remaining Umbral sessions must both start at 17:00 UTC'; + END IF; +END $$; + +COMMIT; diff --git a/src/app/__tests__/page.test.tsx b/src/app/__tests__/page.test.tsx index 66b4ada0..62fead5b 100644 --- a/src/app/__tests__/page.test.tsx +++ b/src/app/__tests__/page.test.tsx @@ -235,11 +235,9 @@ describe('landing page', () => { }); it.each([ - ['third legacy', REMAINING_PUBLIC_ID, '2026-09-05T16:00:00.000Z'], - ['third canonical', REMAINING_PUBLIC_ID, '2026-09-05T17:00:00.000Z'], - ['fourth legacy', FINAL_PUBLIC_ID, '2026-09-12T16:00:00.000Z'], - ['fourth canonical', FINAL_PUBLIC_ID, '2026-09-12T17:00:00.000Z'], - ])('shows the remaining public cycle at 14:00 Argentina with the %s stored schedule', async (_state, id, storedAt) => { + ['third', REMAINING_PUBLIC_ID, '2026-09-05T17:00:00.000Z'], + ['fourth', FINAL_PUBLIC_ID, '2026-09-12T17:00:00.000Z'], + ])('shows the canonical %s public-cycle schedule at 14:00 Argentina', async (_state, id, storedAt) => { const scheduledAt = new Date(storedAt); mountDb(vi.fn().mockResolvedValue([{ ...SATURDAY, diff --git a/src/app/page.tsx b/src/app/page.tsx index 65056132..88323645 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -31,31 +31,12 @@ type WeekendEvent = { }; const INTERNAL_NEXT = /^\/session(\/[A-Za-z0-9_-]+)*$/; -// Rollout-safe editorial override: normalize only the legacy stored times. -// Once scheduled_at is migrated to the canonical value, this becomes a no-op -// so the app cannot show 15:00 while old and new revisions overlap. -const LANDING_1400_ART_SCHEDULES = new Map([ - ['50000000-0000-4000-8000-202609050001', { - legacy: '2026-09-05T16:00:00.000Z', - canonical: '2026-09-05T17:00:00.000Z', - }], - ['50000000-0000-4000-8000-202609120001', { - legacy: '2026-09-12T16:00:00.000Z', - canonical: '2026-09-12T17:00:00.000Z', - }], -]); // A missed lifecycle transition must not leave an old LIVE row advertising the // current checkout indefinitely. Weekend sessions last hours, not days; 24 // hours keeps a delayed/extended live room discoverable while failing closed // before a stale row can be presented as the next paid event. const PUBLIC_LIVE_DISCOVERY_MAX_AGE_MS = 24 * 60 * 60 * 1000; -function landingDisplayTime(event: Pick): string { - const stored = event.scheduledAt.toISOString(); - const schedule = LANDING_1400_ART_SCHEDULES.get(event.id); - return schedule?.legacy === stored ? schedule.canonical : stored; -} - function publicScheduleNow(): Date { const pinned = process.env.E2E_DASHBOARD_ENABLED === '1' ? process.env.E2E_CLOCK_NOW?.trim() @@ -184,7 +165,7 @@ export default async function LandingPage({ )} )} - +

diff --git a/src/lib/__tests__/public-cycle.test.ts b/src/lib/__tests__/public-cycle.test.ts index cdc849ee..36db81ae 100644 --- a/src/lib/__tests__/public-cycle.test.ts +++ b/src/lib/__tests__/public-cycle.test.ts @@ -14,7 +14,7 @@ describe('public four-Saturday cycle', () => { expect(isPublicCycleSession('10000000-0000-4000-8000-000000000001')).toBe(false); }); - it('keeps the final migration contract at the confirmed 16:00 UTC', () => { + it('preserves the historical four-session correction at 16:00 UTC', () => { const migration = readFileSync( new URL( '../../../prisma/migrations/20260821194000_correct_four_saturday_cycle_start/migration.sql', @@ -31,6 +31,23 @@ describe('public four-Saturday cycle', () => { expect(migration).not.toContain('14:00:00'); }); + it('moves only the two remaining sessions to 14:00 Argentina / 17:00 UTC', () => { + const migration = readFileSync( + new URL( + '../../../prisma/migrations/20260901180000_move_remaining_umbral_sessions_to_1400_argentina/migration.sql', + import.meta.url, + ), + 'utf8', + ); + + expect(migration).toContain("'2026-09-05 17:00:00'::timestamp"); + expect(migration).toContain("'2026-09-12 17:00:00'::timestamp"); + expect(migration).not.toContain('2026-08-22 17:00:00'); + expect(migration).not.toContain('2026-08-29 17:00:00'); + expect(migration).toContain('corrected_count <> 2'); + expect(migration).toMatch(/BEGIN;[\s\S]*UPDATE[\s\S]*RAISE EXCEPTION[\s\S]*COMMIT;/); + }); + it('recognizes only an entirely anonymous COMP entitlement for a reviewed public room', () => { const candidate = { staffUser: null,