Files
rootnode-academy/platform/api/migrations/015_scenario_attempts_abandonment.sql
T
ced4568 6dda13b837 feat(learning): abandoned attempt handling
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.
2026-08-24 20:14:52 -05:00

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 $$;