import test from 'node:test' import assert from 'node:assert/strict' import { readFileSync, mkdtempSync, rmSync } from 'node:fs' import { join } from 'node:path' import { tmpdir } from 'node:os' import { installRetainedJournal, validateRetainedScope, validateNativeRetainedDispatch, runRetainedNativeDispatch, saveRetainedReport } from './mixed-container-outbound-test-env.mjs' import { retainedRelabelSource } from './overseas-relabel-fulfillment-acceptance.mjs' const BASE = '/api/platform/v1/last-leg/dispatches' const DOCS = '/api/platform/v1/last-leg/delivery-orders/DL-1/documents?customerId=100' const ok = data => ({ http: 200, body: { code: '200', data }, requestId: 'REQ-1', traceId: 'TRACE-1' }) const scope = () => ({ marker: 'RUN-1', sourceSha256: 'a'.repeat(64), customerId: '100', warehouseId: '80', inboundCodes: ['IN-1'], expectedPackages: 4 }) function nativeProof() { return { marker: 'RUN-1', customerId: '100', dispatchNo: 'DS-1', createBody: { warehouseId: '80', idempotencyKey: 'RUN-1-CREATE', cargo: [{ sourceType: 'INBOUND_PLAN', planPalletId: '9007199254740993', warehousePalletId: '9007199254740994', sourceVersion: 'b'.repeat(64) }] }, createResult: { dispatchNo: 'DS-1', action: 'CREATE', recordVersion: '0', status: 'ACTIVE', stage: 'BEFORE_LOADING', result: { dispatchNo: 'DS-1', changedItemIds: ['9007199254740995'] } }, detail: { dispatchNo: 'DS-1', recordVersion: '0', status: 'ACTIVE', stage: 'BEFORE_LOADING', counts: { packageCount: '4' }, orderDetails: [{ sourceKey: 'PLAN:9007199254740993', customerId: '100', inboundCode: 'IN-1' }] } } } const resultFor = () => ({ schema: 'NATIVE_RETAINED_OUTBOUND_V1', environment: 'TEST', ...scope(), nativeDispatch: nativeProof(), requests: [] }) test('retained scope rejects legacy data, foreign marker/source identity and unresolved original writes before continuation', () => { assert.throws(() => validateRetainedScope({ dispatchNo: 'DS-1' }, scope()), /legacy reports/) for (const mutate of [value => { value.marker = 'HISTORY' }, value => { value.sourceSha256 = 'other' }, value => { value.customerId = '200' }, value => { value.warehouseId = '81' }, value => { value.requests.push({ status: 'UNKNOWN' }) }, value => { value.requests.push({ status: 'SENDING' }) }]) { const value = resultFor(); mutate(value); assert.throws(() => validateRetainedScope(value, scope())) } assert.deepEqual(validateNativeRetainedDispatch(nativeProof(), scope()), ['PLAN:9007199254740993']) for (const mutate of [value => { delete value.createBody }, value => { value.createResult.recordVersion = 9007199254740992 }, value => { value.createResult.action = 'EDIT' }, value => { value.detail.orderDetails[0].customerId = '200' }, value => { value.createBody.cargo[0].sourceVersion = 'unknown' }, value => { value.detail.orderDetails[0].sourceKey = 'PLAN:OTHER' }]) { const value = nativeProof(); mutate(value); assert.throws(() => validateNativeRetainedDispatch(value, scope())) } }) test('journal saves exact original intent before network, blocks unknown/malformed native successes, and refuses replacement commands', async () => { for (const response of [{ http: 0 }, { http: 503, body: { code: 'A0500' } }, ok(null), { http: 200, body: null }]) { const result = resultFor(), snapshots = [], calls = [] const context = installRetainedJournal({ createdResources: {}, context: {}, async request(method, path, body) { calls.push({ method, path, body }); assert.equal(snapshots.at(-1).requests.at(-1).status, 'SENDING'); return response }, }, result, async () => { snapshots.push(structuredClone(result)) }) const body = { recordVersion: '0', idempotencyKey: 'ORIGINAL' } await assert.rejects(context.request('POST', `${BASE}/DS-1/depart`, body), /Unknown write/) assert.equal(result.requests[0].status, 'UNKNOWN') assert.deepEqual(result.requests[0].body, body) await assert.rejects(context.request('POST', `${BASE}/DS-1/depart`, { ...body, idempotencyKey: 'NEW' }), /stopped/) assert.equal(calls.length, 1) assert.throws(() => validateRetainedScope(result, scope()), /Unknown write/) } }) test('retained report stores file hashes and redacts credentials and binary bytes', () => { const directory = mkdtempSync(join(tmpdir(), 'native-retained-contract-')) try { const path = join(directory, 'report.json') saveRetainedReport(path, { marker: 'RUN-1', password: 'SECRET-PASSWORD', accessToken: 'SECRET-TOKEN', requests: [{ file: { sha256: 'a'.repeat(64), content: 'SECRET-BYTES' } }] }) const text = readFileSync(path, 'utf8') assert.doesNotMatch(text, /SECRET-/) assert.ok(text.includes('a'.repeat(64))) } finally { rmSync(directory, { recursive: true, force: true }) } }) function stock(after) { const quantity = after ? 0 : 4 return [{ id: '1', totalPackages: quantity, balance: { id: '1', totalPackages: quantity }, positions: [{ id: '11', balanceId: '1', customerId: '100', overseasWarehouseId: '80', inboundCode: 'IN-1', palletNo: 'P-1', totalPackages: quantity, availablePackages: quantity, holdPackages: 0, allocatedPackages: 0, pickedPackages: 0, receivingPackages: 0 }], globalGroups: [{ totalPackages: quantity }] }] } function nativeRunFixture() { const result = resultFor(), events = [], calls = [] let stage = 'BEFORE_LOADING', picked = false, signed = false, departure, pod result.loadingMeasurements = { environment: 'TEST', marker: 'RUN-1', dispatchNo: 'DS-1', pallets: [] } const delivery = { customerId: '100', deliveryNo: 'DL-1', outboundNo: 'OB-1', packageCount: '4', destination: { key: 'FBA:ABE4', warehouseCode: 'ABE4' } } const context = { token: 'PLATFORM-IN-MEMORY', marker: 'RUN-1', createdResources: {}, context: {}, apiSuccess(_module, _label, response) { return response.body?.data }, assert(_m, _l, _r, passed) { assert.equal(passed, true) }, async requestBinary() { return { http: 200, contentType: 'application/pdf', bytes: Buffer.from('%PDF-1.4 TEST') } }, async request(method, path, body, token) { calls.push({ method, path, body: structuredClone(body), token }) if (method === 'GET' && path.includes('/commands/')) return ok(result.nativeDispatch.createResult) if (method === 'GET' && path.endsWith('/items')) return ok({ items: [{ sourceKey: 'PLAN:9007199254740993', customerId: '100', inboundCode: 'IN-1' }] }) if (method === 'GET' && path.startsWith('/api/pda/')) return ok({ dispatchNo: 'DS-1', warehouseId: '80', counts: { pickedPackageCount: picked ? '4' : '0' }, items: [{ customerId: '100', scheduledPackages: '4', positions: [{ positionId: '11', balanceId: '1' }] }] }) if (method === 'GET' && path === `${BASE}/DS-1`) return ok({ dispatchNo: 'DS-1', status: 'ACTIVE', stage, recordVersion: '9007199254740997', counts: { packageCount: '4' } }) if (method === 'POST' && path.endsWith('/depart')) { events.push('depart'); assert.equal(body.recordVersion, '9007199254740996'); assert.equal(token, 'PDA-IN-MEMORY') if (departure) { assert.deepEqual(body, result.departBody); return ok({ ...departure, replayed: true }) } stage = 'DELIVERING' departure = { dispatchNo: 'DS-1', action: 'DEPART', status: 'ACTIVE', stage, recordVersion: '9007199254740997', result: { shippedPackages: '4', deliveries: [delivery] } } return ok(departure) } if (method === 'GET' && path.includes('/outbound-orders/')) return ok({ outbound: { status: 'OUTBOUNDED', customerId: '100', outboundNo: 'OB-1', dispatchNo: 'DS-1', packageCount: 4 }, pallets: [{ cartonMarks: 'NEW-1,NEW-2,NEW-3,NEW-4' }] }) if (method === 'GET' && path.includes('/delivery-orders/')) return ok({ order: { customerId: '100', outboundNo: 'OB-1', status: signed ? 'DELIVERED' : 'DELIVERING', signedAt: signed ? '2026-10-19T01:00:00' : null } }) if (method === 'PUT' && path === DOCS) { events.push('pod') if (pod) return ok({ ...pod, replayed: true }) signed = true; stage = 'DELIVERED'; pod = { version: '9007199254740998', categories: [{ category: 'RECEIPT' }] } return ok(pod) } throw Error(`Unexpected offline ${method} ${path}`) }, } installRetainedJournal(context, result, async () => { events.push('checkpoint') }) const deps = { async prepareFleetTrip(_context, _module, dispatchNo, warehouseId) { events.push('prepare'); stage = 'LOADING'; return { dispatchNo, warehouseId, tripNo: 'TR-1', preparation: 'VERIFIED' } }, async pickAll(_context, token) { events.push('pick'); assert.equal(token, 'PDA-IN-MEMORY'); picked = true; return true }, async confirmFleetLoading(_context, _module, _proof, token, measurements) { events.push('loading'); assert.equal(token, 'PDA-IN-MEMORY'); assert.equal(measurements, result.loadingMeasurements) if (!measurements) throw Error('Actual palletSpaces measurement is missing') stage = 'DELIVERING'; return '9007199254740995' }, async readAutomaticDispatchDelivery() { events.push('arrange'); return { data: { result: {} }, deliveries: [delivery], outbounds: [{ customerId: '100', outboundNo: 'OB-1' }] } }, async verifyAutomaticDeparture() { events.push('ready'); return { data: { dispatchNo: 'DS-1', status: 'ACTIVE', stage: 'DELIVERING', recordVersion: '9007199254740996', counts: { shippedPackageCount: 4 } } } }, async saveReceiptAndComplete(current) { await current.request('PUT', DOCS, { expectedVersion: '0', idempotencyKey: 'ORIGINAL-POD' }); return { order: { status: 'DELIVERED' } } }, async finishFleetTrip(_context, _module, proof) { events.push('finish'); proof.closure = { status: 'VERIFIED' }; return proof.closure }, async inventorySnapshot() { return stock(picked) }, async ledger() { return picked ? [{ id: '81', customerId: '100', overseasWarehouseId: '80', businessType: 'SHIP', businessOrderNo: 'DS-1', outboundOrderNo: 'DS-1', palletNo: 'P-1', beforePackages: 4, deltaPackages: -4, afterPackages: 0 }] : [] }, } return { context, result, deps, events, calls } } test('retained native execution preserves real ordering, token/measurement scope, current zero-safe version, SHIP once, POD and same-run resume', async () => { const f = nativeRunFixture() await runRetainedNativeDispatch(f.context, f.result, scope(), 'PDA-IN-MEMORY', f.deps) assert.equal(f.result.finalStatus, 'PASSED') assert.deepEqual(f.events.filter(value => value !== 'checkpoint'), ['prepare', 'pick', 'loading', 'arrange', 'ready', 'pod', 'finish']) assert.equal(f.result.inventory.conservation.totals.ledgerShipped, 4) assert.deepEqual(f.result.inventory.ledgerAfter, f.result.inventory.ledgerAfterDepart) assert.equal(f.result.departure.recordVersion, '9007199254740996') const originalDepartCount = f.calls.filter(row => row.method === 'POST').length await runRetainedNativeDispatch(f.context, f.result, scope(), 'PDA-IN-MEMORY', f.deps) assert.equal(f.calls.filter(row => row.method === 'POST').length, originalDepartCount) assert.equal(f.events.filter(value => value === 'pod').length, 2) assert.equal(f.events.filter(value => value === 'pick').length, 1) assert.equal(f.calls.some(row => /pre-arrange|transfer-delivery/.test(row.path)), false) }) test('missing real measurements stops after scanned quantity proof and before arrangement, departure and POD', async () => { const f = nativeRunFixture(); delete f.result.loadingMeasurements await assert.rejects(runRetainedNativeDispatch(f.context, f.result, scope(), 'PDA-IN-MEMORY', f.deps), /measurement is missing/) assert.equal(f.events.includes('arrange'), false); assert.equal(f.events.includes('depart'), false); assert.equal(f.events.includes('pod'), false) assert.equal(f.result.inventory.conservation.totals.ledgerShipped, 4) assert.equal(f.result.blocker.code, 'ACTUAL_MEASUREMENT_REQUIRED') assert.equal(f.result.blocker.field, 'palletSpaces') }) test('relabel input retains original/new mark evidence and cannot upgrade legacy report or a bare business number into native success', () => { assert.throws(() => retainedRelabelSource({ marker: 'RUN-1', scenarios: [{ name: 'SPLIT-TWO-TARGETS', dispatchNo: 'DS-1' }] }, '100'), /native source report/) const native = nativeProof() native.createBody.cargo[0] = { sourceType: 'RELABEL', relabelNo: 'RL-1', warehousePalletId: '9007199254740994', sourceVersion: 'b'.repeat(64) } native.detail.orderDetails[0].sourceKey = 'RELABEL:RL-1:9007199254740994' const source = { environment: 'TEST', marker: 'RUN-1', scenarios: [{ name: 'SPLIT-TWO-TARGETS', relabelNo: 'RL-1', nativeDispatch: native, relabelCartonMarks: ['NEW-1', 'NEW-2', 'NEW-3', 'NEW-4'], sourceCartonMarks: ['OLD-1', 'OLD-2', 'OLD-3', 'OLD-4'] }] } assert.equal(retainedRelabelSource(source, '100', 'DS-1').scope.expectedPackages, 4) const missing = structuredClone(source); delete missing.scenarios[0].sourceCartonMarks assert.throws(() => retainedRelabelSource(missing, '100', 'DS-1'), /original\/new/) assert.throws(() => retainedRelabelSource(source, '200', 'DS-1'), /native source report/) assert.throws(() => retainedRelabelSource(source, '100', 'DS-HISTORY'), /native source report/) }) test('both live entries use unified Auth and native helper without fixed physical measurements or an implicit historical delivery fallback', () => { const mixed = readFileSync(new URL('./mixed-container-outbound-test-env.mjs', import.meta.url), 'utf8') const relabel = readFileSync(new URL('./overseas-relabel-fulfillment-acceptance.mjs', import.meta.url), 'utf8') for (const source of [mixed, relabel]) assert.doesNotMatch(source, /overseasAccessToken|ADMIN_OVERSEAS_GATEWAY|requestOverseas|READY_TO_DEPART|tripVersion|controlledPalletMeasurements/) assert.match(mixed, /confirmFleetLoading\(context, MODULE, trip, pdaToken, result.loadingMeasurements \|\| native.loadingMeasurements\)/) assert.match(mixed, /\/prints\/bol/) assert.match(mixed, /OUTBOUND_PASSED_DELIVERY_NOT_SUPPORTED/) assert.match(relabel, /runRetainedNativeDispatch/) assert.doesNotMatch(relabel, /existingDeliveries|\/api\/merchant\/v1\/last-leg\/delivery-orders/) })