// Author: Simon-Pierre Boucher — contact@spboucher.ai // // One row of log.csv (RESEARCH.md §3). valLoss is nil when the CSV holds // the -1 sentinel; elapsedS is nil for pre-elapsed_s runs (6-column header). import Foundation struct MetricPoint: Equatable, Sendable { var step: Int var trainLoss: Double var lr: Double var gradNorm: Double var tokensPerSec: Double var valLoss: Double? var elapsedS: Double? var tokensSeen: (Int) -> Int { { tokensPerStep in (step + 1) * tokensPerStep } } var perplexity: Double { exp(trainLoss) } }