/* * 예측 틱 크기 — **지평선이 정하고, 양끝은 묶인다.** * * 이 규칙이 틀리면 예측이 알리지 않고 비싸지거나(1초 고정 시절 9,000틱·28.5초) 알리지 않고 성글어진다 * (짧은 작업이 한 틱에 삼켜진다). 둘 다 화면에는 그럴듯한 숫자로 나오므로 시험이 지킨다. */ import { test } from 'node:test' import assert from 'node:assert/strict' import { forecastStepMs, TARGET_TICKS_PER_RUN, MAX_STEP_MS, MIN_STEP_MS } from '../dist-server/service/twin-forecast/forecast-tuning.js' test('기본 지평선(5분)은 5초 단위 — 실측으로 1초와 답이 같고 5배 싸다', () => { assert.equal(forecastStepMs(300_000), 5_000) }) test('짧은 지평선은 더 잘게 — 1분이면 1초', () => { assert.equal(forecastStepMs(60_000), 1_000) }) test('아주 짧아도 커널 시각 단위 아래로 내려가지 않는다', () => { assert.equal(forecastStepMs(5_000), MIN_STEP_MS) assert.equal(forecastStepMs(0), MIN_STEP_MS) assert.equal(forecastStepMs(Number.NaN), MIN_STEP_MS) }) test('아무리 길어도 상한을 넘지 않는다 — 짧은 작업이 한 틱에 삼켜진다', () => { assert.equal(forecastStepMs(2 * 60 * 60_000), MAX_STEP_MS) assert.equal(forecastStepMs(24 * 60 * 60_000), MAX_STEP_MS) }) test('틱 크기는 초 단위로 떨어진다 — 3,333ms 는 사람도 화면도 설명할 수 없다', () => { for (const h of [100_000, 200_000, 333_000, 777_000]) { assert.equal(forecastStepMs(h) % 1000, 0, `${h}ms`) } }) test('상한에 걸리지 않는 구간에서는 목표 틱 수 근처로 돈다', () => { for (const h of [60_000, 120_000, 300_000, 600_000]) { const ticks = h / forecastStepMs(h) assert.ok(ticks >= TARGET_TICKS_PER_RUN * 0.8 && ticks <= TARGET_TICKS_PER_RUN * 1.25, `${h}ms → ${ticks}틱`) } })