diff --git a/src/config.test.ts b/src/config.test.ts index 1295d1a..a4c42f6 100644 --- a/src/config.test.ts +++ b/src/config.test.ts @@ -58,4 +58,14 @@ describe('loadConfig', () => { const cfg = await loadConfig('config.json'); expect(cfg.calibration).toBeNull(); }); + + it('rejects a warp with a non-positive-integer degree', async () => { + const square = [[0, 0], [10, 0], [10, 10], [0, 10]] as [number, number][]; + // A negative degree makes termCount collapse to 0, so empty coeff arrays would + // vacuously validate — guard against that. + const warp = { degree: -1, fwd: { norm: { off: [0, 0], scl: [1, 1] }, cu: [], cv: [] }, inv: { norm: { off: [0, 0], scl: [1, 1] }, cu: [], cv: [] } }; + mockFetch({ streamUrl: 'x', calibration: { imagePoints: square, machinePoints: square, warp } }); + const cfg = await loadConfig('config.json'); + expect(cfg.calibration).toBeNull(); + }); }); diff --git a/src/config.ts b/src/config.ts index a83be00..235e526 100644 --- a/src/config.ts +++ b/src/config.ts @@ -35,7 +35,9 @@ function parsePolyMap(m: unknown, degree: number): PolyMap | null { function parseWarp(w: unknown): PolyWarp | null { if (!w || typeof w !== 'object') return null; const o = w as Record; - if (!isFiniteNumber(o.degree)) return null; + // Require a positive integer degree: a negative/zero/fractional degree makes termCount + // collapse to 0, which would vacuously accept empty coefficient arrays (a garbage warp). + if (!isFiniteNumber(o.degree) || !Number.isInteger(o.degree) || o.degree < 1) return null; const fwd = parsePolyMap(o.fwd, o.degree); const inv = parsePolyMap(o.inv, o.degree); if (!fwd || !inv) return null;