Thoughts

1 thought about "Audit Logging" in the last 90 days

Tat-Tally Session 47 (2026-03-16): Convention Simulation & Audit Logging - COMPLETE Built two major systems for the Tattoo Contest System (Tat-Tally) before the Norfolk test event: 1. PRODUCTION AUDIT LOGGING - Created `audit_log` table with `audit_action` enum covering 11 action types: event_created, event_updated, category_status_changed, entry_created, entry_code_generated, entry_code_redeemed, queue_status_changed, score_submitted, score_reset, judge_assigned, sms_sent - 3 database triggers auto-populate audit entries: `trg_audit_category_status` (on categories UPDATE when status changes), `trg_audit_entry_queue_status` (on entries UPDATE when queue_status changes), `trg_audit_score_insert` (on scores INSERT) - All triggers use SECURITY DEFINER to bypass RLS - RLS: admin can read all, anon scoped by x-event-id header - Migration: `infrastructure/migrations/add_audit_log.sql` 2. FULL CONVENTION SIMULATION SYSTEM (tests/simulation/) - Seed SQL creates realistic convention: 1 event (slug: sim-test), 3 scoring frameworks (tattoo 4 criteria, costume 3, pumpkin 3), 12 categories matching Atlanta spec, 7 auth users (5 judges J-01 through J-05, 1 MC, 1 admin), 40 judge assignments, ~210 entrants with realistic names - UUID pattern: cccc0001-... through cccc0005-... for deterministic test data - 8-phase TypeScript runner: setup, registration, 3 judging waves (3 categories each), edge cases, wrap-up - Judge personality profiles using Box-Muller normal distribution: J-01 "tough" (mean 6.0), J-02 "generous" (mean 8.0), J-03/04/05 "neutral" (mean 7.0), stddev 1.5 - SPEED multiplier: 0 (instant), 1 (real-time ~13 min), 10 (fast ~80s) - Structured JSONL logging (events, realtime latency, errors) - Export script with pagination (fixes Supabase 1000-row default limit): outputs full-export.json, timeline.json, leaderboard.json, outliers.json, summary.json - Files: config.ts, logger.ts, scenarios.ts, runner.ts, export.ts, run.sh 3. PRODUCTION BUG FOUND AND FIXED - `update_entry_final_score()` trigger was NOT SECURITY DEFINER. When judges insert scores via Supabase REST API, the trigger ran under the judge's auth context. The judge's RLS could read their own judge_assignments but the trigger's count(*) query on judge_assignments for the whole category returned wrong results, so the completeness check (v_total_scores >= expected) never passed. Result: final_score was NEVER calculated on any entry. - Fix: Migration `fix_final_score_trigger_security_definer` adds SECURITY DEFINER to the function - Also updated `infrastructure/schema.sql` to reflect the fix SIMULATION RESULTS (SPEED=10 run): - 133 entries scored across 12 categories - 25 entries skipped, 4 withdrawn - 2,191 audit log entries (1,724 score_submitted, 431 queue_status_changed, 36 category_status_changed) - 60 score outliers detected - Leaderboard verified with realistic score distribution (6.5-7.6 range) Commit: 79511fe pushed to main. Next up: Norfolk test event planning (Phase 12).

People: J-01, J-02, J-03, J-04, J-05