scenario_attempts.status = 'abandoned' (a valid value since Phase 3B, never previously set by anything) now gets set on: environment destroy/reset, logout, session expiry (piggybacked on the existing hourly session sweeper - no new background job), and switching to a different scenario while one is still open. Never an academic failure marker - result stays NULL, history is preserved. Call-site wiring in server.js/admin-routes.js lands in the next commit alongside other platform hardening in those same files.
21 lines
1.2 KiB
SQL
21 lines
1.2 KiB
SQL
-- Abandoned/interrupted attempt handling — Phase 4.1, docs/PHASE4_1_PREPRODUCTION_HARDENING.md
|
|
-- §13. 'abandoned' was already a valid scenario_attempts.status value (migration 012's CHECK
|
|
-- constraint) but nothing ever set it — an attempt left open when a Lab was reaped, an
|
|
-- environment destroyed, a session ended, or a student moved on to a different scenario just
|
|
-- stayed 'in_progress' forever, an honest but incomplete signal. This is NOT an academic
|
|
-- failure marker — an abandoned attempt has no `result`, doesn't count against the student,
|
|
-- and the row is never deleted (see src/attempts.js abandonAttempt for the enforcement of
|
|
-- that). It exists so instructor views and needs-attention logic can tell "still working" from
|
|
-- "stopped, for a reason we know."
|
|
|
|
ALTER TABLE scenario_attempts ADD COLUMN IF NOT EXISTS abandoned_at TIMESTAMPTZ;
|
|
ALTER TABLE scenario_attempts ADD COLUMN IF NOT EXISTS abandoned_reason TEXT;
|
|
|
|
DO $$ BEGIN
|
|
ALTER TABLE scenario_attempts ADD CONSTRAINT scenario_attempts_abandoned_reason_check
|
|
CHECK (abandoned_reason IS NULL OR abandoned_reason IN
|
|
('environment_destroyed', 'session_ended', 'scenario_switched'));
|
|
EXCEPTION
|
|
WHEN duplicate_object THEN NULL;
|
|
END $$;
|