2026-10-03 07:42:18 +08:00
import test from 'node:test'
import assert from 'node:assert/strict'
import { readFile } from 'node:fs/promises'
2026-10-20 10:35:52 +08:00
import { createHash } from 'node:crypto'
import { verifyFleetCrossCustomer , fixtureContract , continueFleetCrossCustomerAfterLoading , afterLoadingContinuationContract } from './fleet-cross-customer-acceptance.mjs'
2026-10-03 07:42:18 +08:00
2026-10-20 10:35:52 +08:00
function model ( fault = '' ) {
const copy = value => value == null ? value : structuredClone ( value ), calls = [], keys = new Map ()
const members = [ 0 , 1 ]. map ( i => ({ marker : 'RUN' , customerId : `C ${ i } ` , incomingNo : `IN ${ i } ` , dispatchNo : 'DS-ONE' , dispatchItemId : `ITEM ${ i } ` ,
balanceId : `B ${ i } ` , positionId : `P ${ i } ` , palletId : `PAL ${ i } ` , palletNo : `PALLET ${ i } ` , receiptVerified : true }))
const stops = [{ name : 'Origin' }, { name : 'A' , destinationKey : 'FBA:A' }, { name : 'B' , destinationKey : 'FBA:B' }]
const tripProof = { marker : 'FT-CURRENT' , dispatchNo : 'DS-ONE' , tripNo : 'TRIP' , warehouseId : 'WH' , vehicleId : 'V' , driverId : 'D' , stops ,
reassignment : { status : 'PENDING' }, updateRequest : { plannedDepartureAt : new Date ( Date . now () + 3600000 ). toISOString () } }
const actualEvidence = ( field , value , i ) => ({ field , value , actual : true , sourceType : 'WAREHOUSE_TRANSFER' , sourceBusinessNo : `IN ${ i } ` , observedAt : '2026-10-19T00:00:00Z' })
const fixture = { marker : 'RUN' , stage : fixtureContract . stage , dispatchNo : 'DS-ONE' , tripNo : 'TRIP' , tripProof , warehouseId : 'WH' , pdaToken : 'not-a-real-token' , members ,
loadingMeasurements : { marker : 'RUN' , environment : 'TEST' , dispatchNo : 'DS-ONE' , pallets : members . map (( m , i ) => ({ warehousePalletId : m . palletId ,
palletSpaces : 1 , deliveryIndex : i + 1 , evidence : [ actualEvidence ( 'palletSpaces' , 1 , i )] })) } }
const trip = { trip : { tripNo : 'TRIP' , warehouseId : 'WH' , status : 'PLANNED' , recordVersion : '0' , vehicleId : 'V' , driverId : 'D' , stops }, dispatches : [{ dispatchNo : 'DS-ONE' }] }
let nativeVersion = 5 , stage = 'LOADING' , arranged = false , confirmedLoad = null , stopAtArrangement = false , aggregationReads = 4
const state = members . map ( m => ({ picked : 0 , delivery : null , outbound : null ,
stock : { scope : { marker : 'RUN' , customerId : m . customerId , warehouseId : 'WH' , coverage : 'CUSTOMER_WAREHOUSE_COMPLETE' },
balances : [{ id : m . balanceId , customerId : m . customerId , overseasWarehouseId : 'WH' , availablePackages : '1' , holdPackages : '0' , allocatedPackages : '0' , pickedPackages : '0' , receivingPackages : '0' , inTransitPackages : '0' , procurementPackages : '0' }],
positions : [{ id : m . positionId , customerId : m . customerId , overseasWarehouseId : 'WH' , balanceId : m . balanceId , palletId : m . palletId , palletNo : m . palletNo , availablePackages : '1' , holdPackages : '0' , allocatedPackages : '0' , pickedPackages : '0' , receivingPackages : '0' }],
ledger : [{ id : `STOCK- ${ m . customerId } ` , customerId : m . customerId , overseasWarehouseId : 'WH' , positionId : m . positionId , businessType : 'STOCK_IN' , businessOrderNo : m . incomingNo , deltaPackages : '1' }] } }))
const counts = () => ({ itemCount : 2 , palletCount : 2 , packageCount : 2 , pickedPackageCount : state . reduce (( n , s ) => n + s . picked , 0 ), shippedPackageCount : [ 'DELIVERING' , 'DELIVERED' ]. includes ( stage ) ? 2 : 0 })
const items = () => members . map (( m , i ) => ({ dispatchItemId : m . dispatchItemId , customerId : m . customerId , warehousePalletId : m . palletId ,
palletNo : m . palletNo , destination : { key : i ? 'FBA:B' : 'FBA:A' }, scheduledPackages : 1 , pickedPackages : state [ i ]. picked }))
const deliveryRefs = () => state . filter ( s => s . delivery ). map (( s , i ) => ({ customerId : members [ i ]. customerId , deliveryNo : s . delivery . order . deliveryNo ,
outboundNo : s . outbound . outboundNo , packageCount : 1 , status : s . delivery . order . status , destination : { key : i ? 'FBA:B' : 'FBA:A' } }))
const detail = () => ({ dispatchNo : 'DS-ONE' , status : 'ACTIVE' , stage , recordVersion : nativeVersion , reviewState : 'APPROVED' ,
reviews : { dispatchReview : { status : 'APPROVED' }, loadingReview : { status : 'APPROVED' } }, counts : counts (),
documents : { deliveries : deliveryRefs (), outbounds : state . filter ( s => s . outbound ). map ( s => s . outbound ) } })
const result = ( body , payload , replayed = false ) => ({ dispatchNo : 'DS-ONE' , status : 'ACTIVE' , stage , recordVersion : nativeVersion ,
counts : counts (), idempotencyKey : body . idempotencyKey , result : payload , replayed })
const response = data => ({ http : 200 , body : { code : '200' , data : copy ( data ) }, requestId : 'request' , traceId : 'trace' })
const reject = message => ({ http : 200 , body : { code : 'A0409' , message }, requestId : 'request' , traceId : 'trace' })
const forbidden = () => ({ http : 200 , body : { code : 'A0403' , message : '该请求标识不属于当前操作员' , requestId : 'request' , traceId : 'trace' }, requestId : 'request' , traceId : 'trace' })
const remember = ( body , payload , actor , action ) => { const value = {... result ( body , payload ),...( action ? { action } : {})}; keys . set ( body . idempotencyKey ,{ body : copy ( body ), result : copy ( value ), actor }); return response ( value ) }
const context = { marker : 'RUN' , token : 'admin' , createdResources : { fleetTrips : [ tripProof ] }, assert ( _m , label , _r , condition ) { assert . ok ( condition , label ) },
apiSuccess ( _m , _l , r ) { return r . body . data },
async request ( method , raw , body , token ) {
calls . push ({ method , raw , body : copy ( body ), token }); const url = new URL ( raw , 'https://offline.invalid' ), path = url . pathname
if ( method === 'POST' && keys . has ( body ? . idempotencyKey )) {
const prior = keys . get ( body . idempotencyKey ); assert . deepEqual ( body , prior . body )
if ( token !== prior . actor ) {
2026-10-21 14:30:41 +08:00
if ( fault === 'foreign departure actor accepted' && path . endsWith ( '/loading-complete' )) return response ({... prior . result , replayed : true })
if ( fault === 'foreign departure actor mutates' && path . endsWith ( '/loading-complete' )) state [ 0 ]. stock . ledger . push ({... state [ 0 ]. stock . ledger [ 0 ], id : 'FOREIGN-ACTOR-MUTATION' })
2026-10-20 10:35:52 +08:00
return forbidden ()
2026-10-03 07:42:18 +08:00
}
2026-10-20 10:35:52 +08:00
return response ({... prior . result , replayed : true })
2026-10-03 07:42:18 +08:00
}
2026-10-20 10:35:52 +08:00
if ( path === '/api/platform/v1/last-leg/fleet/trips/TRIP' ) return response ( trip )
if ( path === '/api/platform/v1/last-leg/dispatches/DS-ONE/items' ) return response ({ dispatchNo : 'DS-ONE' , recordVersion : nativeVersion , items : items ()})
if ( path === '/api/platform/v1/last-leg/dispatches/DS-ONE' ) {
if ( method === 'PUT' ) return reject ( '已经真实扫码,不能编辑资源' )
if ( fault === 'aggregation delayed' && state . every ( s => s . delivery ? . order . status === 'DELIVERED' )) {
if ( aggregationReads === 0 ) stage = 'DELIVERED' ; else aggregationReads --
}
2026-10-21 14:30:41 +08:00
if ( stopAtArrangement && stage === 'DELIVERING' && fixture . tripProof . loadingCommand ? . afterReplay ) throw Error ( 'Explicit test checkpoint after confirmed loading' )
2026-10-20 10:35:52 +08:00
return response ( detail ())
}
if ( path . endsWith ( '/loading' ) && method === 'GET' ) return response ({ dispatchNo : 'DS-ONE' , status : 'ACTIVE' , stage , recordVersion : nativeVersion , manifestHash : 'REAL-MANIFEST' ,
pickingReconciled : state . every ( s => s . picked === 1 ), confirmedLoad , loadingComplete : { allowed : state . every ( s => s . picked === 1 )}, pallets : members . map (( m , i )=>({ warehousePalletId : m . palletId , palletNo : m . palletNo ,
scheduledPackages : 1 , pickedPackages : state [ i ]. picked , palletSpaces : null , weightKg : 100 , volumeCbm : 1 , deliveryIndex : i + 1 ,
evidence : [ actualEvidence ( 'weightKg' , 100 , i ), actualEvidence ( 'volumeCbm' , 1 , i )]}))})
if ( path . endsWith ( '/loading-complete' )) {
if ( ! state . every ( s => s . picked === 1 )) {
2026-10-21 14:30:41 +08:00
if ( fault === 'gate reorders route' )[ trip . trip . stops [ 1 ], trip . trip . stops [ 2 ]] = [ trip . trip . stops [ 2 ], trip . trip . stops [ 1 ]]
if ( fault === 'gate mutates second customer' ) state [ 1 ]. stock . balances [ 0 ]. holdPackages = '1'
2026-10-20 10:35:52 +08:00
if ( fault === 'outage disguised as rejection' ) return { http : 503 , body : { code : 'S0503' }, requestId : 'r' , traceId : 't' }
return reject ( fault === 'unrelated gate rejection' ? '车次版本已变化' : '逐项真实拣货尚未核平' )
}
assert . equal ( body . recordVersion , nativeVersion ); assert . equal ( body . measurements . length , 2 )
2026-10-21 14:30:41 +08:00
stage = 'DELIVERING' ; nativeVersion ++ ; trip . trip . status = 'IN_TRANSIT'
for ( const [ i , s ] of state . entries ()) { const m = members [ i ]; s . outbound = { outboundNo : `OUT ${ i } ` , dispatchNo : 'DS-ONE' , overseasWarehouseId : 'WH' , customerId : m . customerId , status : 'OUTBOUNDED' , packageCount : 1 }; s . delivery = { order : { deliveryNo : `DL ${ i } ` , customerId : fault === 'foreign delivery' ? 'OTHER' : m . customerId , dispatchNo : 'DS-ONE' , outboundNo : `OUT ${ i } ` , status : fault === 'partial departure' && i === 1 ? 'WAIT_DELIVERY' : 'DELIVERING' , version : 0 }} }
if ( fault === 'depart deducts again' ){ state [ 0 ]. stock . balances [ 0 ]. availablePackages = '-1' ; state [ 0 ]. stock . positions [ 0 ]. availablePackages = '-1' }
2026-10-20 10:35:52 +08:00
confirmedLoad = { manifestHash : body . manifestHash , pallets : copy ( body . measurements ), operatorId : 'PDA-ACTOR' , confirmedAt : '2026-10-19T01:00:00Z' }
return remember ( body ,{ confirmedLoad , loadingCompletionHash : 'LOADED' }, token , 'LOADING_COMPLETE' )
}
if ( path . endsWith ( '/pick' )) {
const index = members . findIndex ( m => path . includes ( `/items/ ${ m . dispatchItemId } /` )), m = members [ index ], row = state [ index ]
assert . equal ( body . recordVersion , nativeVersion ); assert . equal ( body . positionId , m . positionId ); row . picked = 1 ; nativeVersion ++
row . stock . positions [ 0 ]. availablePackages = '0' ; row . stock . balances [ 0 ]. availablePackages = '0'
row . stock . ledger . push (...[ 'ALLOCATE' , 'PICK' , 'SHIP' ]. map ( type =>({ id : ` ${ type }${ index } ` , customerId : m . customerId , overseasWarehouseId : 'WH' , positionId : m . positionId , businessOrderNo : 'DS-ONE' , businessType : type , deltaPackages : type === 'SHIP' ? '-1' : '1' })))
if ( fault === 'duplicate ship' ) row . stock . ledger . push ({... row . stock . ledger . at ( - 1 ), id : 'EXTRA' })
return remember ( body ,{ dispatchItemId : m . dispatchItemId , pickedPackages : 1 }, token )
}
if ( path === '/api/pda/v1/last-leg/dispatches/DS-ONE' ) return response ({ dispatchNo : 'DS-ONE' , warehouseId : 'WH' , status : 'ACTIVE' , stage , recordVersion : nativeVersion , counts : counts (), pickingReconciled : state . every ( s => s . picked === 1 ),
items : items (). map (( item , i )=>({... item , positions : fault === 'missing PDA position' ? [] : [{ positionId : members [ i ]. positionId , balanceId : members [ i ]. balanceId , availablePackages : state [ i ]. stock . positions [ 0 ]. availablePackages }]}))})
const index = members . findIndex (( _m , i )=> path . includes ( `/OUT ${ i } ` ) || path . includes ( `/DL ${ i } ` )), row = state [ index ]
2026-10-03 07:42:18 +08:00
if ( path . includes ( '/outbound-orders/' )) return response ({ outbound : row . outbound , deliveries : [ row . delivery . order ]})
2026-10-20 10:35:52 +08:00
if ( path . endsWith ( '/documents' )) {
2026-10-03 07:42:18 +08:00
if ( method === 'GET' ) return response ({ version : row . delivery . order . version , categories : []})
2026-10-20 10:35:52 +08:00
row . delivery . order . status = 'DELIVERED' ; row . delivery . order . version ++
2026-10-03 07:42:18 +08:00
if ( fault === 'signs both' ) state [ 1 - index ]. delivery . order . status = 'DELIVERED'
2026-10-20 10:35:52 +08:00
if ( state . every ( s => s . delivery . order . status === 'DELIVERED' ) &&! [ 'aggregation delayed' , 'aggregation never completes' ]. includes ( fault )) stage = 'DELIVERED'
2026-10-03 07:42:18 +08:00
return response ({ version : row . delivery . order . version })
}
2026-10-20 10:35:52 +08:00
if ( path . includes ( '/delivery-orders/' )) { assert . equal ( url . searchParams . get ( 'customerId' ), members [ index ]. customerId ); return response ( row . delivery )}
2026-10-03 07:42:18 +08:00
throw new Error ( `Unexpected ${ method } ${ path } ` )
2026-10-20 10:35:52 +08:00
}, async requestMultipart ( method , path ) { calls . push ({ method , raw : path , multipart : true }); return response ({ fileId : `FILE- ${ path . includes ( 'DL0' ) ? 0 : 1 } ` })} }
2026-10-03 07:42:18 +08:00
const readInventory = async scope =>{ const value = copy ( state [ members . findIndex ( m => m . customerId === scope . customerId )]. stock ); if ( fault === 'wrong stock scope' ) value . positions [ 0 ]. customerId = 'OTHER' ; return value }
2026-10-20 10:35:52 +08:00
return { context , fixture , readInventory , calls , state , stopAfterLoading (){ stopAtArrangement = true }, resumeAfterLoading (){ stopAtArrangement = false }}
2026-10-03 07:42:18 +08:00
}
test ( 'default call and import do not request, create or activate anything' , async ()=>{
let called = false ; const result = await verifyFleetCrossCustomer ({ request (){ called = true }},{})
assert . equal ( result , fixtureContract ); assert . equal ( called , false )
})
test ( 'current DTO-shaped two-customer trip rejects unready gate, departs once and signs independently' , async ()=>{
const m = model (); const proof = await verifyFleetCrossCustomer ( m . context , m . fixture ,{ execute : true , readInventory : m . readInventory })
assert . equal ( proof . status , 'VERIFIED' ); assert . equal ( proof . gateProof , 'PREREQUISITE_REJECTION_VERIFIED' ); assert . equal ( proof . midTransactionRollback , 'NOT_TESTED' )
2026-10-21 14:30:41 +08:00
assert . equal ( m . calls . some ( c => c . raw . endsWith ( '/depart' )), false )
2026-10-03 07:42:18 +08:00
assert . deepEqual ( m . state . map ( s => s . delivery . order . status ),[ 'DELIVERED' , 'DELIVERED' ])
assert . ok ( m . calls . filter ( c => c . raw . includes ( '/api/pda/' )). every ( c => c . token === m . fixture . pdaToken ))
assert . ok ( ! JSON . stringify ( proof ). includes ( m . fixture . pdaToken ))
2026-10-20 10:35:52 +08:00
assert . equal ( new Set ( proof . members . map ( row => row . dispatchNo )). size , 1 )
assert . equal ( new Set ( proof . members . map ( row => row . deliveryNo )). size , 2 )
assert . equal ( new Set ( proof . members . map ( row => row . outboundNo )). size , 2 )
assert . ok ( ! m . calls . some ( c => c . raw . endsWith ( '/complete' ) || c . raw . includes ( '/dispatches/bind' )))
})
test ( 'missing physical pallet-space evidence blocks after both real picks without fabricating loading or delivery' , async ()=>{
const m = model (); delete m . fixture . loadingMeasurements
await assert . rejects ( verifyFleetCrossCustomer ( m . context , m . fixture ,{ execute : true , readInventory : m . readInventory }), /palletSpaces/ )
assert . ok ( m . state . every ( row => row . picked === 1 && row . delivery === null ))
assert . equal ( m . calls . filter ( call => call . raw . endsWith ( '/loading-complete' )). length , 1 , 'only the earlier expected unready rejection was sent' )
assert . equal ( m . calls . some ( call => call . raw . endsWith ( '/transfer-delivery' )), false )
2026-10-03 07:42:18 +08:00
})
2026-10-04 10:32:26 +08:00
test ( 'explicit rollback verifier runs after both picks and before successful departure' , async ()=>{
const m = model (); let calls = 0
const proof = await verifyFleetCrossCustomer ( m . context , m . fixture ,{ execute : true , readInventory : m . readInventory ,
verifyDepartureRollback : async ({ ready , departPath , departBody })=>{
2026-10-21 14:30:41 +08:00
calls ++ ; assert . equal ( ready . trip . trip . status , 'PLANNED' ); assert . equal ( ready . dispatch . stage , 'LOADING' )
assert . ok ( ready . members . every ( row => ! row . outbound ))
assert . equal ( m . calls . filter ( call => call . raw . endsWith ( '/loading-complete' )). length , 1 )
assert . ok ( departPath . includes ( m . fixture . members [ 0 ]. dispatchNo )); assert . ok ( departBody . idempotencyKey )
2026-10-04 10:32:26 +08:00
return { verified : true , scope : 'OWNED_TWO_CUSTOMER_DEPARTURE_ROLLBACK' }
}})
assert . equal ( calls , 1 ); assert . equal ( proof . midTransactionRollback , 'VERIFIED' )
})
for ( const failure of [ 'unverified' , 'throws' , 'mutates' ]) test ( `rollback verification ${ failure } prevents successful departure` , async ()=>{
const m = model ()
await assert . rejects ( verifyFleetCrossCustomer ( m . context , m . fixture ,{ execute : true , readInventory : m . readInventory ,
verifyDepartureRollback : async ()=>{
if ( failure === 'throws' ) throw Error ( 'Observed rollback failed' )
if ( failure === 'mutates' ) m . state [ 0 ]. stock . balances [ 0 ]. availablePackages = '-1'
return { verified : failure !== 'unverified' , scope : 'OWNED_TWO_CUSTOMER_DEPARTURE_ROLLBACK' }
}}))
2026-10-21 14:30:41 +08:00
assert . equal ( m . calls . filter ( call => call . raw . endsWith ( '/loading-complete' )). length , 1 )
assert . ok ( m . state . every ( row => row . delivery === null ))
2026-10-04 10:32:26 +08:00
})
2026-10-20 10:35:52 +08:00
for ( const fault of [ 'wrong stock scope' , 'missing PDA position' , 'duplicate ship' , 'gate mutates second customer' , 'gate reorders route' , 'outage disguised as rejection' , 'unrelated gate rejection' , 'partial departure' , 'depart deducts again' , 'signs both' , 'foreign delivery' , 'foreign departure actor accepted' , 'foreign departure actor mutates' ]) {
2026-10-03 07:42:18 +08:00
test ( `fails closed without widening the claimed evidence: ${ fault } ` , async ()=>{
const m = model ( fault ); await assert . rejects ( verifyFleetCrossCustomer ( m . context , m . fixture ,{ execute : true , readInventory : m . readInventory }),
fault === 'gate reorders route' ? /Rejected departure leaves both complete inventories\/outbounds\/deliveries\/trip unchanged/ : undefined )
assert . equal ( m . context . createdResources . fleetCrossCustomer . status , 'FAILED' )
assert . equal ( m . context . createdResources . fleetCrossCustomer . midTransactionRollback , 'NOT_TESTED' )
})
}
test ( 'missing reader, reused customer and stale marker reject before any API request' , async ()=>{
for ( const change of [ 'reader' , 'customer' , 'marker' ]){
const m = model (); if ( change === 'customer' ) m . fixture . members [ 1 ]. customerId = m . fixture . members [ 0 ]. customerId ; if ( change === 'marker' ) m . fixture . marker = 'OLD'
await assert . rejects ( verifyFleetCrossCustomer ( m . context , m . fixture ,{ execute : true , readInventory : change === 'reader' ? undefined : m . readInventory })); assert . equal ( m . calls . length , 0 )
}
})
test ( 'module contains no autonomous runner or SQL/environment/credential plumbing' , async ()=>{
const source = await readFile ( new URL ( './fleet-cross-customer-acceptance.mjs' , import . meta . url ), 'utf8' )
assert . doesNotMatch ( source , /process\.env|fetch\(|execSync|INSERT INTO|UPDATE ll_|createPicker|createMerchant/ )
2026-10-20 10:35:52 +08:00
assert . match ( source , /confirmFleetLoading/ )
})
async function afterLoadingModel ( fault = '' ) {
const m = model ( fault )
m . stopAfterLoading ()
await assert . rejects ( verifyFleetCrossCustomer ( m . context , m . fixture ,{ execute : true , readInventory : m . readInventory }), /Explicit test checkpoint after confirmed loading/ )
const priorProof = structuredClone ( m . context . createdResources . fleetCrossCustomer )
assert . equal ( priorProof . status , 'FAILED' )
assert . equal ( priorProof . gateProof , 'PREREQUISITE_REJECTION_VERIFIED' )
2026-10-21 14:30:41 +08:00
assert . equal ( m . fixture . tripProof . loadingCommand . result . stage , 'DELIVERING' )
2026-10-20 10:35:52 +08:00
delete m . context . createdResources . fleetCrossCustomer
m . fixture . stage = afterLoadingContinuationContract . stage
m . resumeAfterLoading ()
m . calls . length = 0
return {... m , priorProof }
}
const continueLoaded = ( m , extra = {}) => continueFleetCrossCustomerAfterLoading ( m . context , m . fixture ,
{ execute : true , readInventory : m . readInventory , priorProof : m . priorProof , completionPolling : { maxAttempts : 8 , intervalMs : 1 , deadlineMs : 1000 },... extra })
const writes = m => m . calls . filter ( call => ! [ 'GET' , 'HEAD' , 'OPTIONS' ]. includes ( call . method ))
function alterRead ( m , match , alter ) {
const original = m . context . request
m . context . request = async function (... args ) {
const response = await original . apply ( this , args )
if ( args [ 0 ] === 'GET' && match ( args [ 1 ])) alter ( response . body . data )
return response
}
}
test ( 'explicit after-loading import/default stays offline and is not a fallback of the fresh entry' , async ()=>{
let called = false
assert . equal ( await continueFleetCrossCustomerAfterLoading ({ request (){ called = true }},{}), afterLoadingContinuationContract )
assert . equal ( called , false )
const m = await afterLoadingModel ()
await assert . rejects ( verifyFleetCrossCustomer ( m . context , m . fixture ,{ execute : true , readInventory : m . readInventory }))
assert . equal ( m . calls . length , 0 )
})
test ( 'explicit after-loading continuation reconciles original proof and never repeats picking or loading' , async ()=>{
const m = await afterLoadingModel (), original = structuredClone ( m . priorProof ), loading = structuredClone ( m . fixture . tripProof . loadingCommand )
const proof = await continueLoaded ( m )
assert . equal ( proof . status , 'VERIFIED' ); assert . equal ( proof . continued , true )
2026-10-21 14:30:41 +08:00
assert . equal ( proof . continuation . mode , 'EXPLICIT_COMPLETED_LOADING' )
2026-10-20 10:35:52 +08:00
assert . equal ( proof . continuation . gateProofSource , 'PRIOR_PROOF' )
assert . match ( proof . continuation . priorProofSHA256 , /^[a-f0-9]{64}$/ )
const normalize = value => Array . isArray ( value ) ? value . map ( normalize ) : value && typeof value === 'object' ? Object . fromEntries ( Object . keys ( value ). sort (). map ( key =>[ key , normalize ( value [ key ])])) : value
assert . equal ( proof . continuation . priorProofSHA256 , createHash ( 'sha256' ). update ( JSON . stringify ( normalize ( original ))). digest ( 'hex' ))
assert . deepEqual ( m . priorProof , original ); assert . deepEqual ( m . fixture . tripProof . loadingCommand , loading )
assert . equal ( proof . snapshots . AFTER_PICK_1 , undefined , 'no historical loading snapshot is fabricated in the new proof' )
assert . ok ( proof . snapshots . CONTINUATION_INITIAL ); assert . deepEqual ( proof . continuation . originalAfterPickSnapshot , original . snapshots . AFTER_PICK_1 )
2026-10-21 14:30:41 +08:00
assert . equal ( writes ( m ). some ( call => call . raw . endsWith ( '/pick' )), false )
assert . equal ( writes ( m ). some ( call => call . raw . endsWith ( '/transfer-delivery' ) || call . raw . endsWith ( '/depart' )), false )
2026-10-20 10:35:52 +08:00
assert . deepEqual ( m . state . map ( row => row . delivery . order . status ),[ 'DELIVERED' , 'DELIVERED' ])
assert . equal ( JSON . stringify ( proof ). includes ( m . fixture . pdaToken ), false )
})
for ( const failure of [ 'missing prior' , 'marker' , 'gate' , 'source identity' , 'prior picking' , 'unknown prior write' , 'loading result' , 'loading manifest' , 'loading pallet' , 'loading version' ]) {
test ( `after-loading refuses incomplete or foreign source proof before any request: ${ failure } ` , async ()=>{
const m = await afterLoadingModel ()
if ( failure === 'missing prior' ) m . priorProof = undefined
if ( failure === 'marker' ) m . priorProof . marker = 'OTHER-RUN'
if ( failure === 'gate' ) m . priorProof . gateProof = 'NOT_RUN'
if ( failure === 'source identity' ) m . priorProof . members [ 0 ]. positionId = 'FOREIGN-POSITION'
if ( failure === 'prior picking' ) m . priorProof . snapshots . AFTER_PICK_1 . dispatch . counts . pickedPackageCount = 1
if ( failure === 'unknown prior write' ) m . priorProof . requests . push ({ method : 'POST' , path : '/unconfirmed-command' , status : 'UNKNOWN_RESULT' })
if ( failure === 'loading result' ) delete m . fixture . tripProof . loadingCommand . result
if ( failure === 'loading manifest' ) m . fixture . tripProof . loadingCommand . body . manifestHash = 'OTHER-MANIFEST'
if ( failure === 'loading pallet' ) m . fixture . tripProof . loadingCommand . result . result . confirmedLoad . pallets [ 0 ]. warehousePalletId = 'OTHER-PALLET'
if ( failure === 'loading version' ) m . fixture . tripProof . loadingCommand . body . recordVersion = '1'
await assert . rejects ( continueLoaded ( m )); assert . equal ( m . calls . length , 0 )
})
}
2026-10-21 14:30:41 +08:00
for ( const failure of [ 'inventory drift' , 'current main version' , 'current shipped' , 'existing outbound' , 'current source identity' ]) {
2026-10-20 10:35:52 +08:00
test ( `after-loading refuses changed current facts before arranging or departing: ${ failure } ` , async ()=>{
const m = await afterLoadingModel ()
if ( failure === 'inventory drift' ) m . state [ 0 ]. stock . ledger . push ({... m . state [ 0 ]. stock . ledger [ 0 ], id : 'UNEXPECTED-MOVEMENT' })
if ( failure === 'current main version' ) alterRead ( m , path => path . endsWith ( '/DS-ONE' ), value =>{ value . recordVersion = 999 })
if ( failure === 'current shipped' ) alterRead ( m , path => path . endsWith ( '/DS-ONE' ), value =>{ value . counts . shippedPackageCount = 1 })
if ( failure === 'existing outbound' ) alterRead ( m , path => path . endsWith ( '/DS-ONE' ), value =>{ if ( value . documents ) value . documents . outbounds . push ({ outboundNo : 'EXISTING' })})
if ( failure === 'current source identity' ) alterRead ( m , path => path . endsWith ( '/items' ), value =>{ value . items [ 0 ]. warehousePalletId = 'FOREIGN' })
if ( failure === 'manifest drift' ) alterRead ( m , path => path . endsWith ( '/loading' ), value =>{ value . manifestHash = 'OTHER' })
if ( failure === 'confirmed load drift' ) alterRead ( m , path => path . endsWith ( '/loading' ), value =>{ value . confirmedLoad . pallets [ 0 ]. weightKg = 999 })
if ( failure === 'existing arrangement' ) alterRead ( m , path => path . endsWith ( '/delivery-arrangement' ), value =>{ value . arrangement = { status : 'ARRANGED' }})
await assert . rejects ( continueLoaded ( m )); assert . equal ( writes ( m ). length , 0 )
})
}
test ( 'read-only aggregation polling accepts delayed completion without repeating receipt uploads or signatures' , async ()=>{
const m = await afterLoadingModel ( 'aggregation delayed' )
const proof = await continueLoaded ( m )
assert . equal ( proof . completionPolling . status , 'COMPLETED' )
assert . ok ( proof . completionPolling . attempts . length > 1 && proof . completionPolling . attempts . length <= 8 )
assert . ok ( proof . completionPolling . attempts . every ( entry => entry . status === 'RESPONDED' ))
assert . equal ( m . calls . filter ( call => call . multipart ). length , 2 )
assert . equal ( m . calls . filter ( call => call . method === 'PUT' && call . raw . includes ( '/documents?' )). length , 2 )
})
test ( 'read-only aggregation polling times out as a real failure without changing the dispatch stage' , async ()=>{
const m = await afterLoadingModel ( 'aggregation never completes' )
await assert . rejects ( continueLoaded ( m ,{ completionPolling : { maxAttempts : 3 , intervalMs : 1 , deadlineMs : 1000 }}), /Automatic delivery completion/ )
const proof = m . context . createdResources . fleetCrossCustomer
assert . equal ( proof . status , 'FAILED' ); assert . equal ( proof . completionPolling . status , 'TIMED_OUT' )
assert . equal ( proof . completionPolling . attempts . length , 3 )
assert . ok ( proof . completionPolling . attempts . every ( entry => entry . stage === 'DELIVERING' ))
assert . equal ( m . calls . filter ( call => call . multipart ). length , 2 )
assert . equal ( m . calls . filter ( call => call . method === 'PUT' && call . raw . includes ( '/documents?' )). length , 2 )
})
for ( const failure of [ 'permission' , 'structure' ]) test ( `completion polling terminates immediately on ${ failure } errors` , async ()=>{
const m = await afterLoadingModel (), original = m . context . request
let reads = 0
m . context . request = async function (... args ){
const response = await original . apply ( this , args )
if ( args [ 0 ] === 'GET' && args [ 1 ] === '/api/platform/v1/last-leg/dispatches/DS-ONE'
&& m . context . createdResources . fleetCrossCustomer ? . completionPolling ? . status === 'WAITING' ) {
reads ++
if ( failure === 'permission' ) return { http : 403 , body : { code : 'A0403' }, requestId : 'request' , traceId : 'trace' }
response . body . data . documents = { outbounds : [], deliveries : []}
}
return response
}
await assert . rejects ( continueLoaded ( m ))
assert . equal ( reads , 1 ); assert . equal ( m . context . createdResources . fleetCrossCustomer . completionPolling . status , 'FAILED' )
assert . equal ( m . calls . filter ( call => call . multipart ). length , 2 )
assert . equal ( m . calls . filter ( call => call . method === 'PUT' && call . raw . includes ( '/documents?' )). length , 2 )
2026-10-03 07:42:18 +08:00
})