- migrate.js → legacy-migrate.js (kept for rollback, delete 2026-07-01)
- tests/setup.js now uses migrations-runner.run() on fresh temp DB
- npm run migrate → versioned runner (was legacy init-every-start)
- npm run migrate:legacy → legacy-migrate.js (emergency rollback only)
After `npm run migrate:bootstrap` on prod:
npm run migrate → "Nothing to apply — schema is up to date"
All 32 previously-passing tests continue to pass.
Pre-existing 3 auth.test.js failures (rate-limiter shared state) unchanged.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Focused suite covering IDOR and privilege-escalation patterns:
1. Student cannot delete another teacher's class (role block)
2. Teacher cannot delete another teacher's class (ownership check)
3. Banned user blocked on all protected routes
4. Token revoked after token_version bump (password change flow)
5. Join class with wrong invite code → 404, no membership created
6. Admin-only route blocks teacher role
7. Protected route without token → 401
All 7 pass. Pre-existing auth.test.js failures (rate-limiter shared
state in test server) are unrelated and were present before this PR.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>