1+ import { readFileSync } from "node:fs" ;
2+ import { resolve , dirname } from "node:path" ;
3+ import { fileURLToPath } from "node:url" ;
14import { describe , it , expect } from "vitest" ;
25import { simulateStepwise } from "../domain/simulation" ;
36import { buildSimResult } from "../domain/result" ;
47import { hysteresisPolicy , neverPausePolicy } from "../domain/policy" ;
58import { tokensPerSecond } from "../domain/physics" ;
6- import type { FullProfile , CO2Timeline , SimConfig } from "../domain/types" ;
9+ import type { FullProfile , CO2Timeline , SimConfig , SimProgress } from "../domain/types" ;
710
811/**
912 * Regression test: TypeScript simulation output must match Python.
@@ -88,26 +91,7 @@ const deepseek: FullProfile = {
8891 checkpointResumeTime : 0 ,
8992} ;
9093
91- /**
92- * Build a synthetic CO2 timeline that matches the ENTSO-E data
93- * (5-min resolution, 4 years wrapping). Python averages multiple
94- * years into one; TS does the same via simulateStepwise's modulo
95- * indexing. The specific carbon_intensity values come from the
96- * actual public/data/co2/CN.json used by both implementations.
97- */
98- function buildCNTimeline ( ) : CO2Timeline {
99- // Load CN.json (it's a single-line JSON, 105k+ points)
100- // We commit the exact reference values inline so this test
101- // doesn't depend on the data file being present at test time.
102- //
103- // Hard-coding the full 105k array would be enormous, so we
104- // store a fingerprint and verify against it.
105- return { zone : "CN" , years : [ 2022 , 2023 , 2024 , 2025 ] ,
106- timestamps : [ ] , carbonIntensity : [ ] } ;
107- }
108-
10994describe ( "regression vs Python (CN, Deepseek, 4-year average)" , ( ) => {
110- const MAX_ABS_ERROR = 0.1 ; // kg CO₂, hours, percent points
11195
11296 /**
11397 * Generate averaged CN timeline dynamically from the JSON file.
@@ -116,15 +100,9 @@ describe("regression vs Python (CN, Deepseek, 4-year average)", () => {
116100 */
117101 function loadCNTimeline ( ) : CO2Timeline | null {
118102 try {
119- // Vite-injected BASE_URL — works in dev + test
120- const base = "/data" ;
121- const url = `${ base } /co2/CN.json` ;
122- // During Vitest, we read from filesystem via a helper
123- // since there's no HTTP server.
124- const fs = require ( "fs" ) as typeof import ( "fs" ) ;
125- const path = require ( "path" ) as typeof import ( "path" ) ;
126- const filePath = path . resolve ( __dirname , "../../public/data/co2/CN.json" ) ;
127- const raw = fs . readFileSync ( filePath , "utf-8" ) ;
103+ const __dirname = dirname ( fileURLToPath ( import . meta. url ) ) ;
104+ const filePath = resolve ( __dirname , "../../public/data/co2/CN.json" ) ;
105+ const raw = readFileSync ( filePath , "utf-8" ) ;
128106 return JSON . parse ( raw ) as CO2Timeline ;
129107 } catch {
130108 return null ;
@@ -142,15 +120,15 @@ describe("regression vs Python (CN, Deepseek, 4-year average)", () => {
142120 } ;
143121
144122 // --- baseline (never-pause) ---
145- const baselineProg : any [ ] = [ ] ;
123+ const baselineProg : SimProgress [ ] = [ ] ;
146124 for ( const p of simulateStepwise ( deepseek , neverPausePolicy ( ) , tl , simConfig ) ) {
147125 baselineProg . push ( p ) ;
148126 }
149127 const baselineLast = baselineProg [ baselineProg . length - 1 ] ;
150128
151129 // --- policy simulation ---
152130 const policy = hysteresisPolicy ( ref . thetaPause , ref . thetaResume ) ;
153- const prog : any [ ] = [ ] ;
131+ const prog : SimProgress [ ] = [ ] ;
154132 for ( const p of simulateStepwise ( deepseek , policy , tl , simConfig ) ) {
155133 prog . push ( p ) ;
156134 }
@@ -217,11 +195,11 @@ describe("structural invariants (cross-referenced with Python)", () => {
217195 checkpointPauseTime : 0 , checkpointResumeTime : 0 ,
218196 } ;
219197
220- const neverPause : any [ ] = [ ] ;
198+ const neverPause : SimProgress [ ] = [ ] ;
221199 for ( const p of simulateStepwise ( profile , neverPausePolicy ( ) , tl , config ) ) neverPause . push ( p ) ;
222200 const lastNp = neverPause [ neverPause . length - 1 ] ;
223201
224- const highTheta : any [ ] = [ ] ;
202+ const highTheta : SimProgress [ ] = [ ] ;
225203 const hp = hysteresisPolicy ( 9999 , 0 ) ;
226204 for ( const p of simulateStepwise ( profile , hp , tl , config ) ) highTheta . push ( p ) ;
227205 const lastHt = highTheta [ highTheta . length - 1 ] ;
0 commit comments