All files / web/src/test/journey-simulator index.ts

0% Statements 0/160
0% Branches 0/1
0% Functions 0/1
0% Lines 0/160

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 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161                                                                                                                                                                                                                                                                                                                                 
/**
 * Journey Simulator
 *
 * Test infrastructure for validating BKT-driven problem generation.
 *
 * Usage:
 * ```typescript
 * import {
 *   createEphemeralDatabase,
 *   createTestStudent,
 *   SeededRandom,
 *   SimulatedStudent,
 *   JourneyRunner,
 *   unevenSkillsProfile,
 *   logJourneyResults,
 * } from '@/test/journey-simulator'
 *
 * // Create isolated test database
 * const { db, cleanup } = createEphemeralDatabase()
 *
 * // Create test student in database
 * const { playerId } = await createTestStudent(db)
 *
 * // Set up simulation
 * const rng = new SeededRandom(42)
 * const student = new SimulatedStudent(unevenSkillsProfile, rng)
 * const runner = new JourneyRunner(db, student, config, rng, playerId)
 *
 * // Run simulation
 * const result = await runner.run()
 *
 * // Report results
 * logJourneyResults(result)
 *
 * // Cleanup
 * cleanup()
 * ```
 */

// Core types
export type {
  BktEstimate,
  ComparisonResult,
  JourneyConfig,
  JourneyMetrics,
  JourneyResult,
  JourneyResultJson,
  SessionSnapshot,
  SimulatedAnswer,
  SkillDataPoint,
  SkillTrajectory,
  StudentProfile,
} from './types'

// Seeded random
export {
  SeededRandom,
  withSeededRandom,
  withSeededRandomAsync,
} from './SeededRandom'

// Ephemeral database
export {
  createEphemeralDatabase,
  createTestStudent,
  getCurrentEphemeralDb,
  initializeSkillMastery,
  resetDatabase,
  type EphemeralDbResult,
  type TestDatabase,
} from './EphemeralDatabase'

// Simulated student
export { SimulatedStudent } from './SimulatedStudent'

// Journey runner
export { JourneyRunner } from './JourneyRunner'

// Profiles
export {
  ALL_SKILLS,
  BASIC_SKILLS,
  fastLearnerProfile,
  MINIMAL_SKILLS,
  slowLearnerProfile,
  STRONG_SKILLS,
  unevenSkillsProfile,
  WEAK_SKILLS,
} from './profiles'

// Reporters
export {
  comparisonToJsonSerializable,
  exportComparisonToJson,
  exportToJson,
  formatComparisonResults,
  formatJourneyResults,
  loadFromJson,
  logComparisonResults,
  logJourneyResults,
  toJsonSerializable,
} from './reporters'

/**
 * Helper to run an A/B comparison between adaptive and classic modes.
 *
 * Runs the same profile with the same seed in both modes and compares results.
 */
export async function runComparison(
  db: import('./EphemeralDatabase').TestDatabase,
  profile: import('./types').StudentProfile,
  config: Omit<import('./types').JourneyConfig, 'profile' | 'mode'>,
  playerId: string
): Promise<import('./types').ComparisonResult> {
  const { SeededRandom } = await import('./SeededRandom')
  const { SimulatedStudent } = await import('./SimulatedStudent')
  const { JourneyRunner } = await import('./JourneyRunner')
  const { resetDatabase, createTestStudent } = await import('./EphemeralDatabase')

  // Run adaptive mode
  await resetDatabase(db)
  await createTestStudent(db, playerId)
  const adaptiveRng = new SeededRandom(config.seed)
  const adaptiveStudent = new SimulatedStudent(profile, adaptiveRng)
  const adaptiveRunner = new JourneyRunner(
    db,
    adaptiveStudent,
    { ...config, profile, mode: 'adaptive' },
    adaptiveRng,
    playerId
  )
  const adaptiveResult = await adaptiveRunner.run()

  // Run classic mode (same seed)
  await resetDatabase(db)
  await createTestStudent(db, playerId)
  const classicRng = new SeededRandom(config.seed)
  const classicStudent = new SimulatedStudent(profile, classicRng)
  const classicRunner = new JourneyRunner(
    db,
    classicStudent,
    { ...config, profile, mode: 'classic' },
    classicRng,
    playerId
  )
  const classicResult = await classicRunner.run()

  return {
    adaptiveResult,
    classicResult,
    correlationDelta:
      adaptiveResult.finalMetrics.bktCorrelation - classicResult.finalMetrics.bktCorrelation,
    weakSkillSurfacingDelta:
      adaptiveResult.finalMetrics.weakSkillSurfacing -
      classicResult.finalMetrics.weakSkillSurfacing,
    accuracyImprovementDelta:
      adaptiveResult.finalMetrics.accuracyImprovement -
      classicResult.finalMetrics.accuracyImprovement,
  }
}