All files / web/src/db/schema practice-sessions.ts

80.95% Statements 68/84
100% Branches 0/0
0% Functions 0/2
80.95% Lines 68/84

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 852x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x       2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x                            
/**
 * Practice session types
 *
 * NOTE: The practice_sessions table has been dropped.
 * Session data is now stored in session_plans table.
 * These types are kept for backwards compatibility with the dashboard.
 */
 
/**
 * Practice session data - used for dashboard display
 */
export interface PracticeSession {
  id: string
  playerId: string
  phaseId: string
  problemsAttempted: number
  problemsCorrect: number
  /** RAW mean response time (ms). Distortion is preserved and shown alongside the clean substats. */
  averageTimeMs: number | null
  /** RAW sum of response times (ms). Preserved verbatim; see `cleanTotalTimeMs` for the de-poisoned total. */
  totalTimeMs: number | null
  skillsUsed: string[]
  visualizationMode: boolean
  startedAt: Date
  completedAt: Date | null
 
  // ---- Timing-integrity display substats (#157; context-free per-session) ----
 
  /** Count of Tier-1 (auto-quarantined) attempts in this session. */
  quarantinedTimingCount?: number
  /**
   * Count of flagged attempts in this session that still NEED adult review —
   * resolution-aware (flagged AND not omitted/adjusted/confirmed). Drives the
   * session-list "review timings" badge so it disappears once every flag is
   * acted on; `quarantinedTimingCount` stays as the raw informational substat.
   */
  unresolvedTimingCount?: number
  /** Σ effective response time (ms) over non-Tier-1 samples — the de-poisoned total. */
  cleanTotalTimeMs?: number | null
  /** Count of samples summed into `cleanTotalTimeMs` (its denominator companion). */
  timedProblemCount?: number
}
 
/**
 * Helper to calculate accuracy from a session
 */
export function getSessionAccuracy(session: PracticeSession): number {
  if (session.problemsAttempted === 0) return 0
  return session.problemsCorrect / session.problemsAttempted
}
 
/**
 * Session summary for display
 */
export interface PracticeSessionSummary {
  id: string
  phaseId: string
  problemsAttempted: number
  problemsCorrect: number
  accuracy: number
  averageTimeMs: number | null
  totalTimeMs: number | null
  visualizationMode: boolean
  startedAt: Date
  completedAt: Date | null
}
 
/**
 * Convert a session to a summary
 */
export function toSessionSummary(session: PracticeSession): PracticeSessionSummary {
  return {
    id: session.id,
    phaseId: session.phaseId,
    problemsAttempted: session.problemsAttempted,
    problemsCorrect: session.problemsCorrect,
    accuracy: getSessionAccuracy(session),
    averageTimeMs: session.averageTimeMs,
    totalTimeMs: session.totalTimeMs,
    visualizationMode: session.visualizationMode,
    startedAt: session.startedAt,
    completedAt: session.completedAt,
  }
}