import test from 'node:test' import assert from 'node:assert/strict' import { sharedPalletFreezeEvidence } from './inbound-measurement.mjs' function fixture() { const sources = ['A', 'B'].map(inboundId => ({ inboundId, boxCodes: [`${inboundId}#1-1`], skuLinesByBox: { [`${inboundId}#1-1`]: [{ inboundDetailId: `${inboundId}1`, skuCode: 'SHARED', quantity: 2 }] } })) const pallet = { palletId: 'P1', palletNo: 'DP-260930-0001', status: 'SEALED', sealedAt: '2026-09-30T16:00:00', version: 3, cartons: sources.map(source => ({ boxCode: source.boxCodes[0], inboundId: source.inboundId, palletId: 'P1', palletNo: 'DP-260930-0001', skuLines: [{ inboundDetailId: `${source.inboundId}1`, skuCode: 'SHARED', expectedQuantity: 2, actualQuantity: 2 }], })) } return { sources, tasks: [0, 1].map(() => ({ taskStatus: 'COMPLETED', pallets: [structuredClone(pallet)] })) } } test('shared pallet compares both complete task projections to independently frozen per-box SKU sources', () => { const { tasks, sources } = fixture() assert.equal(sharedPalletFreezeEvidence(tasks, sources).passed, true) tasks[1].pallets[0].cartons.reverse() assert.equal(sharedPalletFreezeEvidence(tasks, sources).passed, true) }) for (const [name, mutate] of [ ['wrong owner despite matching aggregate count', task => { task.pallets[0].cartons[1].inboundId = 'A' }], ['duplicate box despite matching aggregate count', task => { task.pallets[0].cartons[1] = structuredClone(task.pallets[0].cartons[0]) }], ['SKU quantity drift', task => { task.pallets[0].cartons[0].skuLines[0].actualQuantity = 1 }], ['wrong SKU detail ownership', task => { task.pallets[0].cartons[0].skuLines[0].inboundDetailId = 'B1' }], ['box bound to another pallet', task => { task.pallets[0].cartons[0].palletId = 'P2' }], ['missing seal fact', task => { delete task.pallets[0].sealedAt }], ['incomplete carton snapshot', task => { task.pallets[0].cartons.pop() }], ]) { test(`shared pallet rejects ${name}`, () => { const { tasks, sources } = fixture() mutate(tasks[1]) assert.equal(sharedPalletFreezeEvidence(tasks, sources).passed, false) }) }