/* * Folding a span that crosses a daylight-saving transition. * * ── Why this is worth a test ─────────────────────────────────────────────── * `utcOffsetMinutes` on the model is one number, resolved when the host starts the twin. * Folding walks a past span, so a year of facts gets read with whatever offset happened to * be current at start — and a year holds two transitions. Facts after one land an hour off * and are counted into the neighbouring shift. Nothing errors; shift performance is simply * wrong, and plausible. * * `America/Tijuana` is already in this deployment's data (PST -480 / PDT -420), so this is * not a hypothetical. */ import test from 'node:test' import assert from 'node:assert/strict' import { foldKpi } from '../server/engine/kpi-fold.js' /* Two shifts that between them cover the day, so a misread hour lands in the other one. */ const SHIFTS = [ { id: 'day', fromTime: '06:00', toTime: '18:00' }, { id: 'night', fromDayOffset: 0, fromTime: '18:00', toDayOffset: 1, toTime: '06:00' } ] as any[] /* Tijuana: PDT (-420) in July, PST (-480) in December. */ const SUMMER = Date.UTC(2026, 6, 15, 13, 30) // 06:30 local under -420 → day shift const WINTER = Date.UTC(2026, 11, 15, 13, 30) // 05:30 local under -480 → night shift /* * The same rule the host uses (`utcOffsetOf`), written out here because that function lives * beside code the test runner cannot load. Kept small and checked by its own test below, so a * drift in it does not quietly turn the rest of this file green. */ function offsetAt(atMs: number): number | undefined { const name = new Intl.DateTimeFormat('en-US', { timeZone: 'America/Tijuana', timeZoneName: 'longOffset' }) .formatToParts(new Date(atMs)) .find(p => p.type === 'timeZoneName')?.value const m = /^GMT([+-])(\d{1,2}):(\d{2})$/.exec(name ?? '') return m ? (m[1] === '-' ? -1 : 1) * (Number(m[2]) * 60 + Number(m[3])) : undefined } /* * A completed task is a transition, not one row — the fold counts throughput at completion * and needs the earlier states to have a lead time to measure. */ const doneAt = (ms: number, id: string): any[] => ['created', 'in-progress', 'completed'].map((status, i) => ({ eventType: 'task.status', eventTime: new Date(ms - (2 - i) * 30_000).toISOString(), payload: { data: { taskId: id, status } } })) function shiftsOf(events: any[], options: any) { const out = foldKpi(events, { fromMs: Date.UTC(2026, 0, 1), toMs: Date.UTC(2027, 0, 1) } as any, { groupBy: 'shift', shifts: SHIFTS, ...options } as any) return (out as any)?.groups?.items?.map((g: any) => g.key) ?? [] } test('the probe itself reads Tijuana as -420 in July and -480 in December', () => { /* If this drifts, the rest of the file is measuring nothing. */ assert.equal(offsetAt(SUMMER), -420) assert.equal(offsetAt(WINTER), -480) }) test('a fixed offset puts a December fact in the wrong shift — the defect', () => { /* * Both facts are 13:30 UTC. Read with the summer offset the December one looks like * 06:30 local and lands on the day shift, when locally it was 05:30 and belongs to the * night shift. */ const keys = shiftsOf([...doneAt(WINTER, 'w')], { utcOffsetMinutes: -420 }) assert.deepEqual(keys, ['day']) }) test('offsetAt resolves per fact, so the December fact lands on the night shift', () => { const keys = shiftsOf([...doneAt(WINTER, 'w')], { utcOffsetMinutes: -420, offsetAt }) assert.deepEqual(keys, ['night']) }) test('the same span read per instant splits across both shifts, not one', () => { const keys = shiftsOf([...doneAt(SUMMER, 's'), ...doneAt(WINTER, 'w')], { utcOffsetMinutes: -420, offsetAt }).sort() assert.deepEqual(keys, ['day', 'night']) }) test('offsetAt returning undefined falls back to the number rather than to UTC', () => { /* * Not knowing the offset for an instant is not the same as the instant being UTC. * Falling through to the declared number keeps the previous behaviour instead of * silently asserting Greenwich. */ const keys = shiftsOf([...doneAt(WINTER, 'w')], { utcOffsetMinutes: -420, offsetAt: () => undefined }) assert.deepEqual(keys, ['day']) }) test('no offset at all still folds, reading times as UTC as the contract states', () => { const keys = shiftsOf([...doneAt(WINTER, 'w')], {}) /* 13:30 UTC is inside 06:00-18:00. */ assert.deepEqual(keys, ['day']) })