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 | /** * JSON Reporter * * Exports journey simulation results to JSON for further analysis. * Converts Maps to objects for JSON serialization. */ import * as fs from 'node:fs' import * as path from 'node:path' import type { ComparisonResult, JourneyResult, JourneyResultJson } from '../types' /** * Convert a JourneyResult to JSON-serializable format. */ export function toJsonSerializable(result: JourneyResult): JourneyResultJson { return { config: { profileName: result.config.profile.name, mode: result.config.mode, sessionCount: result.config.sessionCount, sessionDurationMinutes: result.config.sessionDurationMinutes, seed: result.config.seed, practicingSkills: result.config.practicingSkills, }, metrics: { bktCorrelation: result.finalMetrics.bktCorrelation, weakSkillSurfacing: result.finalMetrics.weakSkillSurfacing, accuracyImprovement: result.finalMetrics.accuracyImprovement, }, trajectories: Object.fromEntries(result.finalMetrics.skillTrajectories), snapshots: result.snapshots.map((s) => ({ session: s.sessionNumber, accuracy: s.accuracy, problemsAttempted: s.problemsAttempted, bktEstimates: Object.fromEntries(s.bktEstimates), trueSkillProbabilities: Object.fromEntries(s.trueSkillProbabilities), cumulativeExposures: Object.fromEntries(s.cumulativeExposures), sessionExposures: Object.fromEntries(s.sessionExposures), })), } } /** * Export journey results to a JSON file. * * @param result - The journey result to export * @param filepath - Path to write the JSON file */ export function exportToJson(result: JourneyResult, filepath: string): void { const jsonData = toJsonSerializable(result) const jsonString = JSON.stringify(jsonData, null, 2) // Ensure directory exists const dir = path.dirname(filepath) if (!fs.existsSync(dir)) { fs.mkdirSync(dir, { recursive: true }) } fs.writeFileSync(filepath, jsonString, 'utf-8') } /** * JSON-serializable comparison result. */ export interface ComparisonResultJson { adaptive: JourneyResultJson classic: JourneyResultJson deltas: { bktCorrelation: number weakSkillSurfacing: number accuracyImprovement: number } winner: 'adaptive' | 'classic' | 'tie' } /** * Convert a ComparisonResult to JSON-serializable format. */ export function comparisonToJsonSerializable(comparison: ComparisonResult): ComparisonResultJson { // Determine winner let adaptiveWins = 0 let classicWins = 0 if (comparison.correlationDelta > 0.05) adaptiveWins++ else if (comparison.correlationDelta < -0.05) classicWins++ if (comparison.weakSkillSurfacingDelta > 0.1) adaptiveWins++ else if (comparison.weakSkillSurfacingDelta < -0.1) classicWins++ if (comparison.accuracyImprovementDelta > 0.02) adaptiveWins++ else if (comparison.accuracyImprovementDelta < -0.02) classicWins++ let winner: 'adaptive' | 'classic' | 'tie' if (adaptiveWins > classicWins) winner = 'adaptive' else if (classicWins > adaptiveWins) winner = 'classic' else winner = 'tie' return { adaptive: toJsonSerializable(comparison.adaptiveResult), classic: toJsonSerializable(comparison.classicResult), deltas: { bktCorrelation: comparison.correlationDelta, weakSkillSurfacing: comparison.weakSkillSurfacingDelta, accuracyImprovement: comparison.accuracyImprovementDelta, }, winner, } } /** * Export comparison results to a JSON file. */ export function exportComparisonToJson(comparison: ComparisonResult, filepath: string): void { const jsonData = comparisonToJsonSerializable(comparison) const jsonString = JSON.stringify(jsonData, null, 2) // Ensure directory exists const dir = path.dirname(filepath) if (!fs.existsSync(dir)) { fs.mkdirSync(dir, { recursive: true }) } fs.writeFileSync(filepath, jsonString, 'utf-8') } /** * Load a journey result from a JSON file. */ export function loadFromJson(filepath: string): JourneyResultJson { const jsonString = fs.readFileSync(filepath, 'utf-8') return JSON.parse(jsonString) as JourneyResultJson } |