import { readFileSync, existsSync, writeFileSync, mkdirSync } from 'node:fs' import { createHash } from 'node:crypto' import { execFileSync } from 'node:child_process' import { dirname, resolve, join } from 'node:path' import { fileURLToPath, pathToFileURL } from 'node:url' import { runCrossCustomer } from './fleet-cross-customer-test-env.mjs' import { createFleetCrossCustomerFixture } from './admin-test-env-modules/fleet-cross-customer-fixture.mjs' import { finishFleetTrip } from './admin-test-env-modules/fleet-trip-fulfillment.mjs' import { AcceptanceRun } from './admin-test-env-acceptance.mjs' import { fixtureContract } from './admin-test-env-modules/fleet-cross-customer-acceptance.mjs' import { discoverSecondDestination, verifyDualDestination, verifyReviewExtension, verifyCompetitionExtension, verifyFirstCompetitionExtension, verifyRelabelExtension, reconcileRelabelShared, prepareBolAppointments, verifyBolExtension, reconcileReviewTerminal, extensionMatrix } from './admin-test-env-modules/dispatch-workflow-extension-acceptance.mjs' const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..') const hash = bytes => createHash('sha256').update(bytes).digest('hex') export function parseExtensionArguments(args) { const config = { execute: false, environment: 'TEST', runId: 'plan', scenario: 'dual-destination', warehouseId: '', destinationWarehouseId: '', pdaEnvFile: '', syntheticPalletSpaces: null, resumeReport: '', resumeReportSha256: '', pdfPython: '' } const seen = new Set() for (let index = 0; index < args.length; index++) { const name = args[index] if (['--plan', '--execute'].includes(name)) { if (seen.has('mode')) throw Error('Duplicate mode'); seen.add('mode'); config.execute = name === '--execute'; continue } const field = { '--environment': 'environment', '--run-id': 'runId', '--scenario': 'scenario', '--warehouse-id': 'warehouseId', '--destination-warehouse-id': 'destinationWarehouseId', '--pda-env-file': 'pdaEnvFile', '--synthetic-pallet-spaces': 'syntheticPalletSpaces', '--resume-report': 'resumeReport', '--resume-report-sha256': 'resumeReportSha256', '--pdf-python': 'pdfPython' }[name] if (!field || seen.has(name) || !args[index + 1] || args[index + 1].startsWith('--')) throw Error('Unsupported/duplicate argument') seen.add(name); config[field] = args[++index] } if (config.environment !== 'TEST' || !/^[A-Za-z0-9][A-Za-z0-9_-]{0,47}$/.test(config.runId)) throw Error('Explicit TEST/fresh run ID required') if (config.execute && (!['dual-destination', 'reviews', 'competition', 'first-competition', 'relabel', 'relabel-shared', 'review-terminal', 'bol-empty', 'bol-same', 'bol-different'].includes(config.scenario) || config.runId === 'plan' || !config.pdaEnvFile || !/^[1-9]\d*$/.test(config.warehouseId) || !/^[1-9]\d*$/.test(config.destinationWarehouseId) || config.syntheticPalletSpaces !== '1')) throw Error('Ready scenario, explicit warehouse/destination/PDA config and synthetic pallet-spaces=1 required') if (['review-terminal', 'relabel-shared'].includes(config.scenario) && (!config.resumeReport || !/^[0-9a-f]{64}$/.test(config.resumeReportSha256))) throw Error('Explicit frozen owned report required') if (!['review-terminal', 'relabel-shared'].includes(config.scenario) && (config.resumeReport || config.resumeReportSha256) && (!config.scenario.startsWith('bol-') || !config.resumeReport || !/^[0-9a-f]{64}$/.test(config.resumeReportSha256))) throw Error('Resume options require an explicit frozen owned checkpoint') if (config.execute && config.scenario.startsWith('bol-') && !config.pdfPython) throw Error('Explicit PDF reader runtime required') return config } export async function runDispatchExtensions(config, env = process.env) { if (!config.execute) return { execute: false, environment: 'TEST', matrix: extensionMatrix, limits: 'No deploy, SQL writes, permission edits, deletion, old manual main mutation, blind retries or uncontrolled fault injection.' } if (env.CHONGCHONG_ENV !== 'test') throw Error('Only the explicitly loaded TEST configuration is accepted') const bol = config.scenario.startsWith('bol-') const relabelResume = config.scenario === 'relabel-shared' if (bol) execFileSync(config.pdfPython, ['-c', 'import pypdf'], { stdio: 'pipe', timeout: 10000 }) let prior if (config.scenario === 'review-terminal' || relabelResume || bol && config.resumeReport) { const sourcePath = resolve(ROOT, config.resumeReport) const prefix = bol ? 'fleet-cross-DISPATCH20261020EXTBOL' : relabelResume ? 'fleet-cross-DISPATCH20261020EXTRELABEL' : 'fleet-cross-DISPATCH20261020EXTREV' if (!sourcePath.startsWith(join(ROOT, 'reports', prefix))) throw Error('Only this extension-owned frozen report can be reconciled') const bytes = readFileSync(sourcePath) if (hash(bytes) !== config.resumeReportSha256) throw Error('Original review report changed') prior = JSON.parse(bytes) if (relabelResume) { const proof = prior.createdResources?.dispatchWorkflowRelabel if (prior.success !== false || prior.error !== "Expected values to be strictly equal:\n\n'S0500' !== '200'\n" || proof?.cancel?.status !== 'VERIFIED' || proof.sharedDispatches?.length !== 0 || proof.scenarios?.length !== 3 || !proof.scenarios.every(row => row.relabelVerified === true) || prior.createdResources?.fleetWriteBoundary || prior.createdResources?.fleetTrips?.[0]?.closure?.status !== 'CARGO_COMPLETED_AND_RESOURCES_RELEASED' || prior.createdResources?.fleetCrossCustomer?.status !== 'VERIFIED') throw Error('Not the bounded owned relabel candidate read checkpoint') } else if (bol) { if (prior.success !== false || prior.error !== 'Expected values to be strictly equal:\n\n0 !== 1\n' || prior.createdResources?.dispatchWorkflowBol?.status !== 'CHECKING' || prior.createdResources.dispatchWorkflowBol.scenario !== config.scenario || prior.createdResources?.fleetCrossCustomerFixture?.status !== 'READY' || prior.createdResources?.fleetCrossCustomer || prior.createdResources?.fleetWriteBoundary || prior.createdResources?.fleetTrips?.[0]?.closure) throw Error('Not the bounded PDF long-pallet-code assertion checkpoint') } else if (prior.success !== false || prior.error !== 'Native main/items/PDA retain both true customers and physical pallets' || prior.createdResources?.dispatchWorkflowReviews?.status !== 'VERIFIED' || prior.createdResources?.fleetWriteBoundary || prior.createdResources?.fleetTrips?.[0]?.closure) throw Error('Not the bounded known terminal-read race') for (let number = 1; number <= prior.requestCount; number++) if (JSON.parse(readFileSync(join(dirname(sourcePath), 'requests', `${number}.json`))).stage !== 'RESPONSE') throw Error('Prior request outcome uncertain; terminal mode forbidden') } const reportDirectory = join(ROOT, 'reports', `fleet-cross-${config.runId}`) const intentPath = join(ROOT, 'reports', `dispatch-workflow-${config.runId}.intent.json`) if (existsSync(reportDirectory) || existsSync(intentPath)) throw Error('Previous attempt exists; retain original requests and reconcile, never re-enter') const pda = Object.fromEntries(readFileSync(config.pdaEnvFile, 'utf8').replace(/^\uFEFF/, '').split(/\r?\n/) .filter(line => /^[A-Z][A-Z0-9_]*=/.test(line)).map(line => { const separator = line.indexOf('='); return [line.slice(0, separator), line.slice(separator + 1).trim().replace(/^["']|["']$/g, '')] })) if (!pda.PDA_USERNAME || !pda.PDA_PASSWORD) throw Error('Missing authorized existing overseas PDA credentials') const files = ['scripts/dispatch-workflow-extensions-test-env.mjs', 'scripts/admin-test-env-modules/dispatch-workflow-extension-acceptance.mjs', 'scripts/admin-test-env-modules/fleet-cross-customer-fixture.mjs', 'scripts/fleet-cross-customer-test-env.mjs', 'scripts/admin-test-env-acceptance.mjs', 'scripts/admin-test-env-modules/fleet-cross-customer-acceptance.mjs', 'scripts/admin-test-env-modules/fleet-trip-fulfillment.mjs', 'scripts/admin-test-env-modules/merchant-qualification-fixture.mjs', 'scripts/overseas-relabel-real-acceptance.mjs'] const seal = Object.fromEntries(files.map(path => [path, hash(readFileSync(join(ROOT, path)))])) const stable = () => { for (const [path, expected] of Object.entries(seal)) if (hash(readFileSync(join(ROOT, path))) !== expected) throw Error(`Source drift: ${path}`) } mkdirSync(join(ROOT, 'reports'), { recursive: true }) writeFileSync(intentPath, JSON.stringify({ runId: config.runId, scenario: config.scenario, environment: 'TEST', seal, createdAt: new Date().toISOString(), syntheticTestMaterials: true, physicalMeasurementVerified: false, hardwareVerified: false, originalManualMain: 'READ_ONLY_NOT_USED', resumeReportSha256: prior ? config.resumeReportSha256 : null, midTransactionRollback: 'NOT_TESTED_NO_CONTROLLED_INJECTION' }, null, 2), { flag: 'wx' }) const result = await runCrossCustomer(config, { env: { ...env, DISPATCH_EXISTING_PDA_PASSWORD: pda.PDA_PASSWORD }, contextFactory: options => { const context = new AcceptanceRun(options); if (prior) context.marker = prior.marker; return context }, pickerCreate: async context => { context.createdResources.extensionIdentity = { mode: 'EXISTING_TEST_PDA_OWNED_NEW_SESSION', accountMutation: false } const response = await context.request('POST', '/api/auth/login', { loginId: pda.PDA_USERNAME, password: pda.PDA_PASSWORD }, '') if (response.http !== 200 || String(response.body?.code) !== '200' || !response.body.data?.accessToken || !response.body.data.refreshToken) throw Error('Existing PDA login failed') return { membershipId: null, password: pda.PDA_PASSWORD, token: response.body.data.accessToken, refreshToken: response.body.data.refreshToken } }, pickerDisable: async () => { throw Error('Existing identity must never be disabled') }, prepare: async (context, options) => { stable(); context.createdResources.extensionSourceSeal = seal if (prior) { const tripProof = structuredClone(prior.createdResources.fleetTrips[0]) context.createdResources.fleetTrips = [tripProof] context.createdResources[bol ? 'explicitBolCheckpoint' : relabelResume ? 'explicitRelabelCheckpoint' : 'explicitReviewTerminal'] = { sourceReport: config.resumeReport, sourceReportSha256: config.resumeReportSha256, originalFailurePreserved: true, fulfillmentReplay: false, fixtureCreationReplay: false } if (bol) { context.createdResources.dispatchWorkflowBolAppointments = structuredClone(prior.createdResources.dispatchWorkflowBolAppointments) context.createdResources.fleetCrossCustomerFixture = structuredClone(prior.createdResources.fleetCrossCustomerFixture) return { marker: prior.marker, stage: fixtureContract.stage, dispatchNo: tripProof.dispatchNo, tripNo: tripProof.tripNo, warehouseId: config.warehouseId, pdaToken: options.pdaToken, tripProof, members: structuredClone(prior.createdResources.fleetCrossCustomerFixture.members), loadingMeasurements: structuredClone(prior.createdResources.extensionSyntheticLoadingInput) } } const members = prior.createdResources.fleetCrossCustomerFixture.members.map(member => { const match = prior.createdResources.fleetCrossCustomer.members.find(row => row.customerId === member.customerId) if (!match) throw Error('Original receipt/member attribution missing') return { ...structuredClone(member), ...structuredClone(match) } }) return { marker: prior.marker, stage: fixtureContract.stage, dispatchNo: tripProof.dispatchNo, tripNo: tripProof.tripNo, warehouseId: config.warehouseId, pdaToken: options.pdaToken, tripProof, members } } if (bol) { const master = await context.request('GET', `/api/platform/v1/warehouse-admin/${encodeURIComponent(config.destinationWarehouseId)}?tenantId=0`) const timezone = master.body?.data?.warehouse?.timezone if (master.http !== 200 || String(master.body?.code) !== '200' || !/^[A-Za-z_]+\/[A-Za-z_]+(?:\/[A-Za-z_]+)?$/.test(timezone || '')) throw Error('BOL appointment fixtures require an existing FBA destination with an actual regional timezone before any fixture write') } const secondId = bol ? config.destinationWarehouseId : await discoverSecondDestination(context, config.destinationWarehouseId) const fixture = await createFleetCrossCustomerFixture(context, { ...options, destinationWarehouseIds: [config.destinationWarehouseId, secondId], ...(bol ? { shipmentReferences: ['A', 'B'].map(suffix => `TEST-FBA-${context.marker.slice(-12)}-${suffix}`), prepareBatchAllocations: members => prepareBolAppointments(context, members, config.scenario, config.warehouseId) } : {}) }) fixture.loadingMeasurements = { environment: 'TEST', marker: context.marker, dispatchNo: fixture.dispatchNo, syntheticTestMaterials: true, physicalMeasurementVerified: false, hardwareVerified: false, pallets: fixture.members.map(member => ({ warehousePalletId: member.palletId, palletSpaces: 1, evidence: [{ field: 'palletSpaces', value: 1, actual: true, sourceType: 'TEST_SYNTHETIC_LOADING_INPUT', sourceBusinessNo: config.runId, observedAt: new Date().toISOString() }] })) } context.createdResources.extensionSyntheticLoadingInput = fixture.loadingMeasurements await context.checkpoint(); stable(); return fixture }, verify: async (...args) => { stable() if (relabelResume) return reconcileRelabelShared(...args, prior) if (prior && !bol) return reconcileReviewTerminal(...args, prior) if (bol) { const [context, fixture, options] = args return verifyBolExtension(context, fixture, { ...options, bol: config.scenario, inspectBol: async () => { const evidence = join(reportDirectory, 'evidence'), pdfPath = join(evidence, 'BOL.pdf'), journal = join(evidence, 'bol-http.json') const path = `/api/platform/v1/last-leg/dispatches/${encodeURIComponent(fixture.dispatchNo)}/prints/bol` const record = { method: 'GET', path, stage: 'INTENT', numberOfBinaryRequests: 1 } writeFileSync(journal, JSON.stringify(record, null, 2), { flag: 'wx' }); await context.checkpoint() const response = await context.requestBinary('GET', path) Object.assign(record, { stage: 'RESPONSE', http: response.http, contentType: response.contentType, requestId: response.requestId, traceId: response.traceId, bytes: response.bytes.length, sha256: hash(response.bytes) }) writeFileSync(journal, JSON.stringify(record, null, 2)) if (response.http !== 200 || !response.contentType.includes('application/pdf') || Buffer.from(response.bytes).subarray(0, 5).toString() !== '%PDF-') throw Error('Actual BOL endpoint did not return a PDF; preserve response metadata') writeFileSync(pdfPath, response.bytes, { flag: 'wx' }) const result = JSON.parse(execFileSync(config.pdfPython, ['-c', 'import json,sys; from pypdf import PdfReader; r=PdfReader(sys.argv[1]); print(json.dumps({"pages":[p.extract_text() for p in r.pages]}))', pdfPath], { encoding: 'utf8', timeout: 30000 })) writeFileSync(join(evidence, 'bol-pages.json'), JSON.stringify(result, null, 2), { flag: 'wx' }) context.createdResources.dispatchWorkflowBol.pdf = { path: 'evidence/BOL.pdf', ...record, pageCount: result.pages.length } await context.checkpoint(); return result.pages } }) } return (config.scenario === 'reviews' ? verifyReviewExtension : config.scenario === 'competition' ? verifyCompetitionExtension : config.scenario === 'first-competition' ? verifyFirstCompetitionExtension : config.scenario === 'relabel' ? verifyRelabelExtension : verifyDualDestination)(...args) }, finish: async (...args) => { stable() if (relabelResume) { if (args[2]?.closure?.status !== 'CARGO_COMPLETED_AND_RESOURCES_RELEASED') throw Error('Original normal trip closure missing') return args[2].closure } return finishFleetTrip(...args) }, }) return { success: result.success, error: result.error, runId: config.runId, requestCount: result.requestCount, summary: result.summary, sessionsClosed: result.sessionsClosed, scenario: config.scenario, extensionStatus: result.createdResources?.dispatchWorkflowExtensions?.status, reviewStatus: result.createdResources?.dispatchWorkflowReviews?.status, competitionStatus: result.createdResources?.dispatchWorkflowCompetition?.status, bolStatus: result.createdResources?.dispatchWorkflowBol?.status, relabelStatus: result.createdResources?.dispatchWorkflowRelabel?.status, report: join(reportDirectory, 'report.json'), syntheticTestMaterials: true, hardwareVerified: false, physicalMeasurementVerified: false } } if (process.argv[1] && import.meta.url === pathToFileURL(resolve(process.argv[1])).href) { const result = await runDispatchExtensions(parseExtensionArguments(process.argv.slice(2))) console.log(JSON.stringify(result)); if (result.success === false) process.exitCode = 1 }