2026-10-20 10:35:52 +08:00
import { createHash } from 'node:crypto'
import { confirmFleetLoading } from './fleet-trip-fulfillment.mjs'
2026-10-03 07:42:18 +08:00
const MODULE = 'fleet-cross-customer-acceptance'
const ROOT = '/api/platform/v1/last-leg'
const PDA = '/api/pda/v1/last-leg/dispatches'
const OPTIONS = { scenario : 'fleet-cross-customer-departure' , deploymentBlocker : true }
const id = value => value == null ? '' : String ( value )
const ok = response => response ? . http === 200 && id ( response . body ? . code ) === '200'
const encode = encodeURIComponent
const scoped = ( path , customerId ) => ` ${ path } ? ${ new URLSearchParams ({ customerId } )}`
const canonical = value => JSON . stringify ( normalize ( value ))
function normalize ( value ) {
if ( Array . isArray ( value )) return value . map ( normalize )
2026-10-20 10:35:52 +08:00
return value && typeof value === 'object' ? Object . fromEntries ( Object . keys ( value ). sort (). map ( key => [ key , normalize ( value [ key ])])) : value
2026-10-03 07:42:18 +08:00
}
function integer ( value ) {
2026-10-20 10:35:52 +08:00
if ( ! [ 'number' , 'string' ]. includes ( typeof value ) || ! /^(0|[1-9][0-9]*)$/ . test ( String ( value )) || ! Number . isSafeInteger ( Number ( value ))) throw new Error ( 'Invalid inventory integer' )
2026-10-03 07:42:18 +08:00
return Number ( value )
}
2026-10-20 10:35:52 +08:00
const buckets = [ 'availablePackages' , 'holdPackages' , 'allocatedPackages' , 'pickedPackages' , 'receivingPackages' ]
const balanceBuckets = [... buckets , 'inTransitPackages' , 'procurementPackages' ]
2026-10-03 07:42:18 +08:00
export const fixtureContract = Object . freeze ({
2026-10-20 10:35:52 +08:00
stage : 'TWO_FRESH_CUSTOMERS_ONE_REVIEWED_DISPATCH_LOADING_NOT_PICKED' ,
fixture : 'marker, warehouseId, dispatchNo, tripNo, tripProof, pdaToken, optional current-run loadingMeasurements; members[2]: marker/customerId/incomingNo/shared dispatchNo/dispatchItemId/balanceId/positionId/palletId/palletNo/receiptVerified' ,
preparation : 'Two independently qualified customers formally received one pallet/box each in the same warehouse. One native Create with both actual source selections; automatic unique Fleet record, resources and both native reviews. No picking or delivery arrangement.' ,
reader : 'readInventory(scope) returns all raw balances/positions/immutable movements including zero, exact marker/customer/warehouse and CUSTOMER_WAREHOUSE_COMPLETE coverage.' ,
boundary : 'Prerequisite rejection is separate from an explicitly injected real mid-transaction rollback. Actual loading needs actual evidence; absent measurement fields block. No environment loader, SQL or implicit account lifecycle.' ,
2026-10-03 07:42:18 +08:00
})
2026-10-20 10:35:52 +08:00
export const afterLoadingContinuationContract = Object . freeze ({
... fixtureContract ,
2026-10-21 14:30:41 +08:00
stage : 'TWO_OWNED_CUSTOMERS_ONE_DISPATCH_DELIVERING' ,
preparation : 'Explicit continuation only: prior failed proof with verified gate and complete AFTER_PICK_1; original successful loadingCommand/confirmedLoad; current DELIVERING with automatically created execution documents.' ,
2026-10-20 10:35:52 +08:00
boundary : 'Reconcile original identities, complete picked inventory and original loading receipt through current reads before any new write. Never repeat picking/loading or rewrite the prior proof.' ,
})
export async function verifyFleetCrossCustomer ( context , fixture , { execute = false , readInventory , verifyDepartureRollback , completionPolling } = {}) {
2026-10-03 07:42:18 +08:00
if ( ! execute ) return fixtureContract
2026-10-20 10:35:52 +08:00
return runCrossCustomerCore ( context , fixture , { readInventory , verifyDepartureRollback , completionPolling })
}
export async function continueFleetCrossCustomerAfterLoading ( context , fixture , { execute = false , readInventory , verifyDepartureRollback , priorProof , completionPolling } = {}) {
if ( ! execute ) return afterLoadingContinuationContract
2026-10-21 14:30:41 +08:00
if ( ! priorProof ) throw new Error ( 'Explicit prior cross-customer proof is required for completed-loading continuation' )
2026-10-20 10:35:52 +08:00
return runCrossCustomerCore ( context , { ... fixture , members : structuredClone ( fixture ? . members ) },
{ readInventory , verifyDepartureRollback , priorProof , completionPolling })
}
async function runCrossCustomerCore ( context , fixture , { readInventory , verifyDepartureRollback , priorProof , completionPolling }) {
const continuation = priorProof !== undefined
const contract = continuation ? afterLoadingContinuationContract : fixtureContract
if ( ! context ? . marker || fixture ? . marker !== context . marker || fixture . stage !== contract . stage
|| ! fixture . dispatchNo || ! fixture . tripNo || fixture . tripProof ? . dispatchNo !== fixture . dispatchNo || fixture . tripProof . tripNo !== fixture . tripNo
|| ! context . createdResources ? . fleetTrips ? . includes ( fixture . tripProof )
|| ! fixture . warehouseId || ! fixture . pdaToken || typeof readInventory !== 'function' || fixture . members ? . length !== 2
|| new Set ( fixture . members . map ( row => row . customerId )). size !== 2
|| fixture . members . some ( row => row . marker !== context . marker || row . receiptVerified !== true || row . dispatchNo !== fixture . dispatchNo
|| [ 'customerId' , 'incomingNo' , 'dispatchItemId' , 'balanceId' , 'positionId' , 'palletId' , 'palletNo' ]. some ( field => ! id ( row [ field ]))))
throw new Error ( 'Requires two distinct current-run customers and one reviewed native dispatch with complete raw inventory evidence' )
for ( const field of [ 'incomingNo' , 'dispatchItemId' , 'positionId' , 'palletId' , 'balanceId' ])
if ( new Set ( fixture . members . map ( row => id ( row [ field ]))). size !== 2 ) throw new Error ( `Cross-customer fixture reuses ${ field } ` )
const polling = { maxAttempts : 41 , intervalMs : 500 , deadlineMs : 20000 , ... completionPolling }
if ( ! Number . isSafeInteger ( polling . maxAttempts ) || polling . maxAttempts < 1 || polling . maxAttempts > 121
|| ! Number . isSafeInteger ( polling . intervalMs ) || polling . intervalMs < 1 || polling . intervalMs > 2000
|| ! Number . isSafeInteger ( polling . deadlineMs ) || polling . deadlineMs < 1 || polling . deadlineMs > 60000 )
throw new Error ( 'Finite completion polling bounds are required' )
context . createdResources ??= {}
2026-10-03 07:42:18 +08:00
if ( context . createdResources . fleetCrossCustomer ) throw new Error ( 'Proof already exists; retain failed run and reconcile explicitly' )
2026-10-20 10:35:52 +08:00
const proof = context . createdResources . fleetCrossCustomer = { marker : context . marker , dispatchNo : fixture . dispatchNo , tripNo : fixture . tripNo ,
warehouseId : fixture . warehouseId , members : fixture . members . map (({ marker , customerId , incomingNo , dispatchNo , dispatchItemId , balanceId , positionId , palletId , palletNo }) =>
({ marker , customerId , incomingNo , dispatchNo , dispatchItemId , balanceId , positionId , palletId , palletNo })),
status : 'CHECKING' , requests : [], snapshots : {}, gateProof : 'NOT_RUN' , midTransactionRollback : 'NOT_TESTED' , cleanup : 'Caller owns account/session lifecycle; retain all business fixtures' }
const check = ( name , passed ) => { context . assert ( MODULE , name , null , Boolean ( passed ), '' , OPTIONS ); if ( ! passed ) throw new Error ( name ) }
const equal = ( a , b , name ) => check ( name , canonical ( a ) === canonical ( b ))
2026-10-03 07:42:18 +08:00
const key = suffix => ` ${ context . marker } -CROSS- ${ suffix } `
2026-10-20 10:35:52 +08:00
const path = ` ${ ROOT } /dispatches/ ${ encode ( fixture . dispatchNo ) } ` , pdaPath = ` ${ PDA } / ${ encode ( fixture . dispatchNo ) } `
2026-10-03 07:42:18 +08:00
const tripPath = ` ${ ROOT } /fleet/trips/ ${ encode ( fixture . tripNo ) } `
2026-10-20 10:35:52 +08:00
const request = async ( method , target , body , label , pda = false , rejection ) => {
const entry = { method , path : target , body , label , status : 'SENDING' }; proof . requests . push ( entry ); await context . checkpoint ? .()
let response
try { response = await context . request ( method , target , body , pda ? fixture . pdaToken : context . token , {}) }
catch ( error ) { entry . status = 'UNKNOWN_RESULT' ; await context . checkpoint ? .(); throw error }
Object . assign ( entry , { status : 'RESPONDED' , http : response ? . http , code : response ? . body ? . code , requestId : response ? . requestId , traceId : response ? . traceId })
await context . checkpoint ? .()
const denied = response ? . http === 409 || ( response ? . http === 200 && id ( response . body ? . code ) === 'A0409' )
const actorDenied = [ 200 , 403 ]. includes ( response ? . http ) && id ( response . body ? . code ) === 'A0403'
check ( label , Boolean ( response ? . requestId && response ? . traceId )
&& ( rejection === 'ACTOR_FORBIDDEN' ? actorDenied : rejection ? denied && rejection ( id ( response . body ? . message )) : ok ( response )))
2026-10-03 07:42:18 +08:00
return response . body ? . data
}
const stock = async member => {
const scope = { marker : context . marker , customerId : member . customerId , warehouseId : fixture . warehouseId }
const raw = await readInventory ( scope )
check ( 'Inventory reader proves complete customer/warehouse scope' , canonical ( raw ? . scope ) === canonical ({... scope , coverage : 'CUSTOMER_WAREHOUSE_COMPLETE' }))
for ( const collection of [ 'balances' , 'positions' , 'ledger' ]) check ( `Complete ${ collection } rows have unique identities and customer ownership` , Array . isArray ( raw [ collection ])
&& new Set ( raw [ collection ]. map ( row => id ( row . id ))). size === raw [ collection ]. length
&& raw [ collection ]. every ( row => id ( row . id ) && id ( row . customerId ) === id ( member . customerId ) && id ( row . overseasWarehouseId ) === id ( fixture . warehouseId )))
check ( 'Original receipt balance and physical position are retained even at zero' , raw . balances . some ( row => id ( row . id ) === id ( member . balanceId ))
&& raw . positions . some ( row => id ( row . id ) === id ( member . positionId ) && id ( row . balanceId ) === id ( member . balanceId ) && id ( row . palletId ) === id ( member . palletId ) && row . palletNo === member . palletNo ))
for ( const balance of raw . balances ) {
for ( const field of balanceBuckets ) integer ( balance [ field ])
const positions = raw . positions . filter ( row => id ( row . balanceId ) === id ( balance . id ))
for ( const field of buckets ) check ( `Raw balance and every position conserve ${ field } ` , integer ( balance [ field ]) === positions . reduce (( sum , row )=> sum + integer ( row [ field ]), 0 ))
}
check ( 'No orphan stock positions' , raw . positions . every ( row => raw . balances . some ( balance => id ( balance . id ) === id ( row . balanceId ))))
return raw
}
const snapshot = async label => {
2026-10-20 10:35:52 +08:00
const trip = await request ( 'GET' , tripPath , undefined , 'Read automatic unique Fleet resource record' )
check ( 'One trip binds exactly this one native cross-customer dispatch' , trip . trip ? . tripNo === fixture . tripNo
&& id ( trip . trip . warehouseId ) === id ( fixture . warehouseId ) && trip . dispatches ? . length === 1 && trip . dispatches [ 0 ]. dispatchNo === fixture . dispatchNo )
const dispatch = await request ( 'GET' , path , undefined , 'Read native whole dispatch' )
const items = await request ( 'GET' , ` ${ path } /items` , undefined , 'Read actual per-customer cargo' )
const task = await request ( 'GET' , pdaPath , undefined , 'Read bound warehouse native PDA task' , true )
check ( 'Native main/items/PDA retain both true customers and physical pallets' , dispatch . dispatchNo === fixture . dispatchNo
&& items . dispatchNo === fixture . dispatchNo && task . dispatchNo === fixture . dispatchNo && id ( task . warehouseId ) === id ( fixture . warehouseId )
&& id ( dispatch . recordVersion ) === id ( items . recordVersion ) && id ( task . recordVersion ) === id ( dispatch . recordVersion )
&& items . items ? . length === 2 && task . items ? . length === 2 && fixture . members . every ( member =>
items . items . some ( i => id ( i . dispatchItemId ) === member . dispatchItemId && id ( i . customerId ) === member . customerId
&& id ( i . warehousePalletId ) === member . palletId && i . palletNo === member . palletNo && integer ( i . scheduledPackages ) === 1 )
&& task . items . some ( i => id ( i . dispatchItemId ) === member . dispatchItemId && id ( i . customerId ) === member . customerId && i . palletNo === member . palletNo )))
const members = []
for ( const member of proof . members ) {
let outbound = null , delivery = null
if ( member . outboundNo || member . deliveryNo ) {
check ( 'Customer execution documents are both explicit' , member . outboundNo && member . deliveryNo )
outbound = await request ( 'GET' , scoped ( ` ${ ROOT } /outbound-orders/ ${ encode ( member . outboundNo ) } ` , member . customerId ), undefined , 'Read customer outbound' )
delivery = await request ( 'GET' , scoped ( ` ${ ROOT } /delivery-orders/ ${ encode ( member . deliveryNo ) } ` , member . customerId ), undefined , 'Read customer delivery' )
check ( 'Execution documents keep customer, warehouse and shared main ownership' , outbound . outbound ? . outboundNo === member . outboundNo
&& outbound . outbound . dispatchNo === fixture . dispatchNo && id ( outbound . outbound . overseasWarehouseId ) === id ( fixture . warehouseId )
&& outbound . deliveries ? . length === 1 && outbound . deliveries [ 0 ]. deliveryNo === member . deliveryNo
&& id ( outbound . deliveries [ 0 ]. customerId ) === member . customerId && delivery . order ? . deliveryNo === member . deliveryNo
&& id ( delivery . order . customerId ) === member . customerId && delivery . order . dispatchNo === fixture . dispatchNo && delivery . order . outboundNo === member . outboundNo )
}
members . push ({ outbound , delivery , stock : await stock ( member ) })
2026-10-03 07:42:18 +08:00
}
2026-10-20 10:35:52 +08:00
const value = { trip , dispatch , items , task , members }; proof . snapshots [ label ] = value ; return value
2026-10-03 07:42:18 +08:00
}
2026-10-20 10:35:52 +08:00
const pick = async ( member , index ) => {
const before = await snapshot ( `BEFORE_PICK_ ${ index } ` ), item = before . task . items . find ( i => id ( i . dispatchItemId ) === member . dispatchItemId )
check ( 'PDA exposes exactly this customer real current-run pallet and position' , integer ( item . scheduledPackages ) === 1 && integer ( item . pickedPackages ) === 0
&& item . palletNo === member . palletNo && item . positions ? . length === 1 && id ( item . positions [ 0 ]. positionId ) === member . positionId
&& integer ( item . positions [ 0 ]. availablePackages ) === 1 )
const body = { recordVersion : before . task . recordVersion , positionId : member . positionId , packages : 1 , productQuantity : 1 ,
idempotencyKey : key ( `PICK- ${ index } ` ), remark : context . marker }
const pickPath = ` ${ pdaPath } /items/ ${ encode ( member . dispatchItemId ) } /pick`
await request ( 'POST' , pickPath , body , 'Pick this customer only' , true )
const after = await snapshot ( `AFTER_PICK_ ${ index } ` )
equal ( before . members [ 1 - index ]. stock , after . members [ 1 - index ]. stock , 'Other customer inventory unchanged by picking' )
const expected = structuredClone ( before . members [ index ]. stock )
for ( const collection of [ 'balances' , 'positions' ]) expected [ collection ]. find ( row => id ( row . id ) === ( collection === 'balances' ? member . balanceId : member . positionId )). availablePackages = 0
const counts = raw => Object . fromEntries ([ 'balances' , 'positions' ]. map ( collection => [ collection , raw [ collection ]. map ( row => ({ id : id ( row . id ),
... Object . fromEntries (( collection === 'balances' ? balanceBuckets : buckets ). map ( field => [ field , integer ( row [ field ])])) }))]))
equal ( counts ( expected ), counts ( after . members [ index ]. stock ), 'Only selected customer position and balance lose one box' )
const old = before . members [ index ]. stock . ledger , newRows = after . members [ index ]. stock . ledger . filter ( row => ! old . some ( prior => id ( prior . id ) === id ( row . id )))
equal ( old , after . members [ index ]. stock . ledger . filter ( row => old . some ( prior => id ( prior . id ) === id ( row . id ))), 'Immutable old movements preserved' )
check ( 'Single ALLOCATE/PICK/SHIP sequence has exact source and quantity' , newRows . length === 3 && [ 'ALLOCATE' , 'PICK' , 'SHIP' ]. every ( type => newRows . filter ( row =>
row . businessType === type && id ( row . positionId ) === member . positionId && row . businessOrderNo === fixture . dispatchNo && Number ( row . deltaPackages ) === ( type === 'SHIP' ? - 1 : 1 )). length === 1 ))
await request ( 'POST' , pickPath , body , 'Replay exact customer pick' , true )
equal ( after , await snapshot ( `PICK_REPLAY_ ${ index } ` ), 'Pick replay changes neither customer nor any execution record' )
2026-10-03 07:42:18 +08:00
}
try {
2026-10-21 14:30:41 +08:00
let cargoBasis
2026-10-20 10:35:52 +08:00
if ( continuation ) {
2026-10-21 14:30:41 +08:00
const command = fixture . tripProof . loadingCommand
const prior = priorProof . snapshots ? . AFTER_PICK_1
check ( 'Continuation preserves original successful loading command and current-run picked inventory' , priorProof . dispatchNo === fixture . dispatchNo && priorProof . marker === context . marker && priorProof . gateProof === 'PREREQUISITE_REJECTION_VERIFIED'
&& canonical ( priorProof . members ) === canonical ( proof . members )
&& priorProof . requests . every ( row => row . method === 'GET' || row . status === 'RESPONDED' )
&& Number ( prior ? . dispatch ? . counts ? . pickedPackageCount ) === 2 && id ( command ? . body ? . recordVersion ) === id ( prior ? . dispatch ? . recordVersion )
2026-10-21 18:44:26 +08:00
&& canonical ( fixture . tripProof . loadingPreview ? . pallets ? . map ( p =>({ warehousePalletId : id ( p . warehousePalletId ), palletSpaces : 1 , weightKg : p . weightKg ?? null , volumeCbm : p . volumeCbm ?? null , deliveryIndex : p . deliveryIndex }))) === canonical ( command ? . result ? . result ? . confirmedLoad ? . pallets )
2026-10-21 14:30:41 +08:00
&& prior ? . dispatch ? . dispatchNo === fixture . dispatchNo && prior . dispatch . stage === 'LOADING'
&& command ? . body ? . idempotencyKey && command . result ? . action === 'LOADING_COMPLETE' && command . result . stage === 'DELIVERING'
&& command . result . dispatchNo === fixture . dispatchNo && command . result . idempotencyKey === command . body . idempotencyKey
&& command . result . result ? . confirmedLoad ? . manifestHash === command . body . manifestHash )
const current = await snapshot ( 'CONTINUATION_INITIAL' )
check ( 'Continuation is already delivering with the original automatic documents' , current . dispatch . stage === 'DELIVERING'
&& current . task . stage === 'DELIVERING' && current . trip . trip . status === 'IN_TRANSIT'
&& id ( current . dispatch . recordVersion ) === id ( command . result . recordVersion ) && Number ( current . dispatch . counts . shippedPackageCount ) === 2
&& canonical ( current . items . items ) === canonical ( prior . items . items )
&& current . dispatch . documents ? . outbounds ? . length === 2 && current . dispatch . documents ? . deliveries ? . length === 2 )
equal ( prior . members . map ( row => row . stock ), current . members . map ( row => row . stock ), 'Continuation preserves complete picked inventory' )
proof . continued = true ; proof . gateProof = priorProof . gateProof
proof . continuation = { mode : 'EXPLICIT_COMPLETED_LOADING' , gateProofSource : 'PRIOR_PROOF' , originalAfterPickSnapshot : structuredClone ( prior ), priorProofSHA256 : createHash ( 'sha256' ). update ( canonical ( priorProof )). digest ( 'hex' ) }
cargoBasis = prior
2026-10-20 10:35:52 +08:00
} else {
const initial = await snapshot ( 'INITIAL' )
check ( 'Fresh native fixture is reviewed LOADING with both customer receipts untouched' , initial . trip . trip . status === 'PLANNED'
&& initial . dispatch . status === 'ACTIVE' && initial . dispatch . stage === 'LOADING' && initial . dispatch . reviewState === 'APPROVED'
&& initial . dispatch . reviews ? . dispatchReview ? . status === 'APPROVED' && initial . dispatch . reviews ? . loadingReview ? . status === 'APPROVED'
&& integer ( initial . dispatch . counts . packageCount ) === 2 && integer ( initial . dispatch . counts . pickedPackageCount ) === 0
&& initial . dispatch . documents ? . deliveries ? . length === 0 && initial . members . every (( row , index ) =>
integer ( row . stock . positions . find ( p => id ( p . id ) === fixture . members [ index ]. positionId ). availablePackages ) === 1
&& row . stock . balances . every ( balance => balanceBuckets . filter ( field => field !== 'availablePackages' ). every ( field => integer ( balance [ field ]) === 0 ))
&& row . stock . balances . reduce (( sum , balance ) => sum + integer ( balance . availablePackages ), 0 ) === 1 ))
await pick ( proof . members [ 0 ], 0 )
const rejectedBefore = await snapshot ( 'GATE_BEFORE' )
check ( 'Precisely one customer picked while main remains LOADING' , integer ( rejectedBefore . dispatch . counts . pickedPackageCount ) === 1
&& rejectedBefore . dispatch . stage === 'LOADING' && rejectedBefore . task . pickingReconciled === false )
const preview = await request ( 'GET' , ` ${ pdaPath } /loading` , undefined , 'Read incomplete native loading manifest' , true )
await request ( 'POST' , ` ${ pdaPath } /loading-complete` , { recordVersion : rejectedBefore . task . recordVersion , idempotencyKey : key ( 'UNREADY-LOAD' ),
2026-10-21 18:44:26 +08:00
manifestHash : preview . manifestHash , remark : context . marker }, 'Unready second customer blocks explicit loading' , true ,
2026-10-20 10:35:52 +08:00
message => / 拣货 . * 核平 | 尚未核平 / . test ( message ))
equal ( rejectedBefore , await snapshot ( 'GATE_AFTER' ), 'Rejected departure leaves both complete inventories/outbounds/deliveries/trip unchanged' )
proof . gateProof = 'PREREQUISITE_REJECTION_VERIFIED'
await pick ( proof . members [ 1 ], 1 )
cargoBasis = proof . snapshots . AFTER_PICK_1
2026-10-21 14:30:41 +08:00
await confirmFleetLoading ( context , MODULE , fixture . tripProof , fixture . pdaToken , fixture . loadingMeasurements , async command => {
if ( verifyDepartureRollback === undefined ) return
check ( 'Explicit rollback verifier is callable' , typeof verifyDepartureRollback === 'function' )
const ready = await snapshot ( 'READY' )
const rollback = await verifyDepartureRollback ({ context , fixture , ready , departPath : command . path , departBody : command . body , snapshot })
check ( 'Mid-transaction rollback has exact owned verification' , rollback ? . verified === true && rollback . scope === 'OWNED_TWO_CUSTOMER_DEPARTURE_ROLLBACK' )
equal ( ready , await snapshot ( 'ROLLBACK_RESTORED' ), 'Rollback restores both complete inventory snapshots before loading completion' )
proof . rollbackEvidence = rollback ; proof . midTransactionRollback = 'VERIFIED'
})
2026-10-04 10:32:26 +08:00
}
2026-10-21 14:30:41 +08:00
const detail = await request ( 'GET' , path , undefined , 'Read documents created by the one loading-complete command' )
const documents = detail . documents
check ( 'Automatic loading creates both customer-isolated outbounds and deliveries' , detail . dispatchNo === fixture . dispatchNo && detail . stage === 'DELIVERING'
&& documents ? . deliveries ? . length === 2 && documents . outbounds ? . length === 2
&& new Set ( documents . deliveries . map ( d => d . deliveryNo )). size === 2 && new Set ( documents . outbounds . map ( o => o . outboundNo )). size === 2 )
2026-10-20 10:35:52 +08:00
for ( const [ index , member ] of proof . members . entries ()) {
2026-10-21 14:30:41 +08:00
const deliveries = documents . deliveries . filter ( d => id ( d . customerId ) === member . customerId )
check ( 'Each customer has its own source destination and quantity' , deliveries . length === 1 && deliveries [ 0 ]. status === 'DELIVERING'
&& integer ( deliveries [ 0 ]. packageCount ) === 1 && deliveries [ 0 ]. destination ? . key === cargoBasis . items . items . find ( i => id ( i . customerId ) === member . customerId ) ? . destination ? . key
&& documents . outbounds . some ( o => id ( o . customerId ) === member . customerId && o . status === 'OUTBOUNDED' && o . outboundNo === deliveries [ 0 ]. outboundNo && integer ( o . packageCount ) === 1 ))
2026-10-20 10:35:52 +08:00
Object . assign ( member , { outboundNo : deliveries [ 0 ]. outboundNo , deliveryNo : deliveries [ 0 ]. deliveryNo })
Object . assign ( fixture . members [ index ], { outboundNo : member . outboundNo , deliveryNo : member . deliveryNo })
2026-10-03 07:42:18 +08:00
}
2026-10-21 14:30:41 +08:00
const command = fixture . tripProof . loadingCommand , departed = command . result
2026-10-20 10:35:52 +08:00
proof . departure = departed
const after = await snapshot ( 'DEPARTED' )
check ( 'Both customer outbounds completed and main delivering' , after . trip . trip . status === 'IN_TRANSIT' && after . dispatch . stage === 'DELIVERING'
&& after . members . every ( row => row . outbound . outbound . status === 'OUTBOUNDED' && row . delivery . order . status === 'DELIVERING' ))
2026-10-21 14:30:41 +08:00
equal ( cargoBasis . members . map ( row => row . stock ), after . members . map ( row => row . stock ), 'Loading completion does not deduct either inventory again' )
const replay = await request ( 'POST' , command . path , command . body , 'Original PDA actor exact replay of loading completion' , true )
check ( 'Loading replay returns the original complete result' , replay . replayed === true && id ( replay . recordVersion ) === id ( departed . recordVersion )
2026-10-20 10:35:52 +08:00
&& canonical ( replay . result ) === canonical ( departed . result ))
const replayed = await snapshot ( 'DEPART_REPLAY' )
2026-10-21 14:30:41 +08:00
equal ( after , replayed , 'Loading replay preserves both complete inventories and execution documents' )
await request ( 'POST' , ` ${ path } /loading-complete` , command . body , 'Different platform actor cannot reuse the PDA loading key' , false , 'ACTOR_FORBIDDEN' )
equal ( replayed , await snapshot ( 'FOREIGN_ACTOR_DEPART_REJECTED' ), 'Actor rejection preserves both complete inventories and execution facts' )
2026-10-20 10:35:52 +08:00
for ( const [ index , member ] of proof . members . entries ()) {
const before = await snapshot ( `BEFORE_SIGN_ ${ index } ` ), documentPath = scoped ( ` ${ ROOT } /delivery-orders/ ${ encode ( member . deliveryNo ) } /documents` , member . customerId )
const docs = await request ( 'GET' , documentPath , undefined , 'Read this customer delivery document version' )
const uploadPath = scoped ( ` ${ ROOT } /delivery-orders/ ${ encode ( member . deliveryNo ) } /documents/RECEIPT/files` , member . customerId )
const uploadEntry = { method : 'POST' , path : uploadPath , label : 'Upload own synthetic receipt' , status : 'SENDING' }; proof . requests . push ( uploadEntry ); await context . checkpoint ? .()
let uploaded
try { uploaded = await context . requestMultipart ( 'POST' , uploadPath , { name : ` ${ context . marker } - ${ index } -TEST-receipt.txt` , type : 'text/plain' ,
content : new TextEncoder (). encode ( ` ${ context . marker } synthetic TEST receipt ${ member . deliveryNo } ` ) }) }
catch ( error ) { uploadEntry . status = 'UNKNOWN_RESULT' ; await context . checkpoint ? .(); throw error }
Object . assign ( uploadEntry , { status : 'RESPONDED' , http : uploaded ? . http , code : uploaded ? . body ? . code , requestId : uploaded ? . requestId , traceId : uploaded ? . traceId }); await context . checkpoint ? .()
check ( 'Receipt uploaded through correct customer endpoint' , ok ( uploaded ) && uploaded . requestId && uploaded . traceId && id ( uploaded . body ? . data ? . fileId ))
const documents = ( docs . categories || []). filter ( row => row . category !== 'RECEIPT' ). map ( row => ({ category : row . category , fileIds : ( row . files || []). map ( file => file . fileId ) }))
documents . push ({ category : 'RECEIPT' , fileIds : [ id ( uploaded . body . data . fileId )] })
await request ( 'PUT' , documentPath , { expectedVersion : docs . version , idempotencyKey : key ( `SIGN- ${ index } ` ), bolNo : docs . bolNo || null , documents }, 'Attach receipt to independently complete this delivery' )
const signed = await snapshot ( `SIGNED_ ${ index } ` )
check ( 'This customer independently signed' , signed . members [ index ]. delivery . order . status === 'DELIVERED' )
equal ( before . members [ 1 - index ]. delivery , signed . members [ 1 - index ]. delivery , 'Other customer delivery is not signed or changed implicitly' )
equal ( before . members . map ( row => row . stock ), signed . members . map ( row => row . stock ), 'Signing does not mutate either customer inventory' )
}
const started = Date . now ()
proof . completionPolling = { ... polling , status : 'WAITING' , attempts : [] }
for ( let attempt = 1 ; attempt <= polling . maxAttempts ; attempt ++ ) {
if ( Date . now () - started >= polling . deadlineMs ) break
const entry = { attempt , elapsedMs : Date . now () - started , status : 'READING' }
proof . completionPolling . attempts . push ( entry )
const current = await request ( 'GET' , path , undefined , 'Read bounded automatic delivery completion progress' )
check ( 'Completion progress retains the exact normal main, counts and both execution-document owners' , current . dispatchNo === fixture . dispatchNo
&& current . status === 'ACTIVE' && [ 'DELIVERING' , 'DELIVERED' ]. includes ( current . stage )
&& /^(0|[1-9]\d*)$/ . test ( id ( current . recordVersion )) && integer ( current . counts ? . packageCount ) === 2
&& integer ( current . counts ? . pickedPackageCount ) === 2 && integer ( current . counts ? . shippedPackageCount ) === 2
&& current . documents ? . outbounds ? . length === 2 && current . documents ? . deliveries ? . length === 2
&& proof . members . every ( member => current . documents . outbounds . some ( row => id ( row . customerId ) === member . customerId && row . outboundNo === member . outboundNo )
&& current . documents . deliveries . some ( row => id ( row . customerId ) === member . customerId && row . deliveryNo === member . deliveryNo && row . outboundNo === member . outboundNo )))
Object . assign ( entry , { status : 'RESPONDED' , stage : current . stage , recordVersion : current . recordVersion , elapsedMs : Date . now () - started })
if ( entry . elapsedMs >= polling . deadlineMs ) break
if ( current . stage === 'DELIVERED' ) { proof . completionPolling . status = 'COMPLETED' ; break }
await context . checkpoint ? .()
const remaining = polling . deadlineMs - ( Date . now () - started )
if ( attempt < polling . maxAttempts && remaining > 0 ) await new Promise ( resolve => setTimeout ( resolve , Math . min ( polling . intervalMs , remaining )))
}
proof . completionPolling . elapsedMs = Date . now () - started
if ( proof . completionPolling . status !== 'COMPLETED' ) {
proof . completionPolling . status = 'TIMED_OUT'
await context . checkpoint ? .()
throw new Error ( 'Automatic delivery completion did not reach DELIVERED within the explicit read-only polling bounds' )
}
const final = await snapshot ( 'FINAL' )
check ( 'All normal customer signatures aggregate native delivery completion' , final . dispatch . status === 'ACTIVE' && final . dispatch . stage === 'DELIVERED' )
proof . status = 'VERIFIED' ; return proof
} catch ( error ) {
proof . status = 'FAILED' ; proof . error = error . message
if ( proof . completionPolling ? . status === 'WAITING' ) {
proof . completionPolling . status = 'FAILED' ; proof . completionPolling . error = error . message
const attempt = proof . completionPolling . attempts . at ( - 1 )
if ( attempt ? . status === 'READING' ) attempt . status = 'FAILED'
}
throw error
}
2026-10-03 07:42:18 +08:00
}