Files
baiyue-firstleg/scripts/admin-test-env-modules/phase3-producer-chain-contract.test.mjs
T

490 lines
26 KiB
JavaScript

import assert from 'node:assert/strict'
import { readFileSync } from 'node:fs'
import test from 'node:test'
import { selectCustomsFlow } from './phase3-customs.mjs'
import { buildFinalizeResource } from './phase3-loading-finalize.mjs'
import { selectContainerLoadingFixture, selectPlatformChannelIsolationPair } from './phase3-container-loading.mjs'
import { AcceptanceRun, normalizeModuleOrder, parseArguments } from '../admin-test-env-acceptance.mjs'
function source(name) {
return readFileSync(new URL(name, import.meta.url), 'utf8')
}
function assertOrder(value, snippets) {
let cursor = -1
for (const snippet of snippets) {
const next = value.indexOf(snippet)
assert.ok(next > cursor, `${snippet} must appear after the previous production step`)
cursor = next
}
}
test('pairs customs source fixture with the matching loading container', () => {
const resources = {
orders: { tenantId: 10001, orderId: 101, inboundId: 201 },
orchestrationFixtures: {
phase3Container: { tenantId: 10001, orderId: 102, inboundId: 202 },
},
phase3Loading: { tenantId: 10001, inboundId: 201, containerBookingId: 301 },
phase3ContainerLoading: { tenantId: 10001, inboundId: 202, containerBookingId: 302 },
}
const selected = selectCustomsFlow(resources)
assert.equal(selected.fixture.orderId, 101)
assert.equal(selected.container.containerBookingId, 301)
})
test('falls back to the matching container fixture without crossing source identities', () => {
const resources = {
orchestrationFixtures: { phase3Container: { tenantId: 10001, orderId: 102, inboundId: 202 } },
phase3Loading: { tenantId: 10001, inboundId: 201, containerBookingId: 301 },
phase3ContainerLoading: { tenantId: 10001, inboundId: 202, containerBookingId: 302 },
}
const selected = selectCustomsFlow(resources)
assert.equal(selected.fixture.orderId, 102)
assert.equal(selected.container.containerBookingId, 302)
})
test('records LOADING and a cleanup reason when finalize returns S0500', () => {
const result = buildFinalizeResource(
{ inboundStatus: 'LOADING', inboundVersion: 5, finalStatus: 'COMPLETED' },
{ summary: { processStatus: 'LOADING', version: 5 } },
{ http: 200, body: { code: 'S0500' } },
)
assert.equal(result.finalStatus, 'LOADING')
assert.equal(result.finalizeSucceeded, false)
assert.match(result.notCleanedReason, /S0500/)
})
test('records LOADED and clears the reason only after a real LOADED reread', () => {
const result = buildFinalizeResource(
{ inboundStatus: 'LOADING', inboundVersion: 5, finalStatus: 'COMPLETED' },
{ summary: { processStatus: 'LOADED', version: 6 } },
{ http: 200, body: { code: '200' } },
)
assert.equal(result.finalStatus, 'LOADED')
assert.equal(result.finalizeSucceeded, true)
assert.equal(result.notCleanedReason, null)
})
test('container loading follows push, claim, real pick, completed sequence', () => {
const value = source('./phase3-container-loading.mjs')
assert.match(value, /\['EDITING', 'WAIT_LOADING'\]\.includes\(containerDetail\?\.planStatus\)/)
assertOrder(value, [
"pushed?.status === 'EDITING'",
"claimedPlan?.status === 'LOADING'",
"const pickResponse = await request",
"const completeResponse = await request",
"finalPlan?.status === 'COMPLETED'",
])
assert.match(value, /picked\?\.workflowStatus === 'AWAITING_REVIEW'/)
assert.match(value, /`\$\{PDA\}\/tasks\/\$\{taskId\}\/complete`/)
assert.match(value, /expectedTaskVersion: Number\(picked\?\.version\)/)
assert.match(value, /operationId: `\$\{context\.marker\}-pda-complete`\.slice\(0, 128\)/)
})
test('bridge loading starts through a real PDA batch before preload confirmation', () => {
const value = source('./phase3-loading.mjs')
assertOrder(value, [
'原子关联入库预装与柜次装柜计划',
'无真实柜号拒绝推送柜次计划',
'无真实柜号推送失败后不生成 PDA 任务',
'绑定真实柜号后开放三期 PDA 推送门禁',
'订舱 CONFIRMED 即使已绑定真实柜号也不生成 PDA 任务',
'三期订舱补齐五项运输字段并放舱',
'三期订舱 RELEASED 后保持模拟柜关联身份',
'真实柜号与 RELEASED 订舱就绪后推送并生成 PDA 任务',
"pushedLoadingPlan?.status === 'EDITING'",
"claimedPlan?.status === 'LOADING'",
"const canonicalPick = await request",
"pickedPlan?.status === 'COMPLETED'",
"const confirming = await request",
])
assert.match(value, /confirmed\?\.mainStatus === 'LOADING' && confirmed\?\.preloadPlan\?\.status === 'CONFIRMING'/)
assert.match(value, /confirmed\?\.preloadPlan\?\.status === 'CONFIRMED'/)
assert.doesNotMatch(value, /关联柜次计划进入 LOADING/)
assert.match(value, /confirmed\?\.mainStatus === 'LOADING'/)
assert.match(value, /confirmed\?\.preloadPlan\?\.status === 'CONFIRMING'/)
assert.match(value, /Number\(confirmed\?\.preloadPlan\?\.version\) === 2/)
assert.match(value, /const missingContainerPushRejected = failure\(missingContainerPushResponse\)[\s\S]*if \(!missingContainerPushRejected\) return/)
assert.match(value, /const missingContainerTaskAbsent =[\s\S]*if \(!missingContainerTaskAbsent\) return/)
assert.match(value, /version: transportVersion/)
assert.match(value, /Number\.isInteger\(transportVersion\)/)
assert.match(value, /billOfLadingNo:[\s\S]*vesselName:[\s\S]*voyageNo:[\s\S]*estimatedSailingAt:[\s\S]*estimatedArrivalAt:/)
assert.match(value, /bookingReleased\?\.oceanBooking\?\.status === 'RELEASED'/)
})
test('PDA inventory snapshot gates batch and records the only safe mutation gap', () => {
const loading = source('./phase3-loading.mjs')
assertOrder(loading, [
'读取 PDA 提交前实时库存快照',
'未发生库存变化时重复读取实时库存快照',
'客户身份无权读取平台 PDA 实时库存快照',
'const overflowResource =',
'通过公开 A0 换绑接口制造真实库存变化',
'真实库存变化后旧 snapshot token 提交返回冲突',
'旧 token 冲突对任务、明细、已拣数量和操作历史零写入',
'库存变化后刷新 PDA 实时库存快照',
'const canonicalPick = await request',
'const canonicalBatchReplay = await request',
])
assert.match(loading, /inventorySnapshotToken: refreshedInventory\.snapshotToken/)
assert.match(loading, /warehouseId, loadingPlanId, containerBookingId,/)
assert.match(loading, /inventory\?\.currentContainerNo === containerNo/)
const batchPayload = loading.slice(loading.indexOf('const batchPayload ='), loading.indexOf('const staleBatch ='))
assert.doesNotMatch(batchPayload, /containerNo[,\s]/)
assert.doesNotMatch(loading, /\/loading\/picking\/(?:start|complete)/)
assert.match(loading, /inventorySnapshotVerified: inventorySnapshotVerified && directPdaCompletion && atomicBatchReplayVerified/)
assert.match(loading, /inventoryMutationVerified, inventoryMutationCleanup/)
assert.match(loading, /当前唯一平台代理库存变更入口只允许 A0 临时占用换绑/)
const convergence = source('./phase3-pda-convergence.mjs')
assert.doesNotMatch(convergence, /未公开实时库存查询或库存版本快照端点/)
assert.match(convergence, /fixture\?\.inventorySnapshotVerified !== true/)
assert.match(convergence, /fixture\?\.inventoryMutationVerified !== true/)
})
test('container loading arranges a simulation before linking a confirmed real booking', () => {
const value = source('./phase3-container-loading.mjs')
assert.match(value, /candidates\.find\(\(candidate\) => candidate\.marker === context\.marker\)/)
assertOrder(value, [
"const simulationResponse = await request(context, 'POST', CONTAINERS",
"const candidateResponse = await context.request('GET', `${SMART}/candidates?bookingId=",
"const planResponse = await request(context, 'POST', `${SMART}/plans`",
"const assignResponse = await request",
"const bookingCreate = await request",
"const submit = await request",
"const confirm = await request",
"const linkResponse = await request(context, 'POST', `${CONTAINERS}/${containerId}/ocean-booking-link`",
])
assert.match(value, /channelCode, warehouseId, warehouseName/)
assert.match(value, /publishPlatformLogisticsChannels\(context, warehouseId, MODULE\)/)
assert.match(value, /warehouseId, warehouseName/)
const draft = value.slice(value.indexOf('const bookingDraft = {'), value.indexOf('context.assert(MODULE, \'订舱渠道与仓库快照完整\''))
assert.doesNotMatch(draft, /billOfLadingNo|vesselName|voyageNo|estimatedSailingAt|estimatedArrivalAt/)
assert.match(value, /containerAllocations\.length === 0/)
assert.match(value, /version: Number\(linkedContainer\.version\), reason: context\.marker/)
assert.doesNotMatch(value, /version: Number\(containerDetail\?\.version \?\? 0\), reason: context\.marker/)
assert.match(value, /function responseEvidence\(response\)[\s\S]*HTTP=\$\{response\?\.http \?\? 'missing'\}[\s\S]*code=\$\{codeOf\(response\)\}[\s\S]*requestId=\$\{response\?\.requestId \|\| 'missing'\}[\s\S]*traceId=\$\{response\?\.traceId \|\| 'missing'\}/)
assert.match(value, /emptySimulation = context\.apiSuccess\(MODULE, '空模拟柜首次关联真实订舱', emptyLink,\s+responseEvidence\(emptyLink\), OPTIONS\)\s+if \(!emptySimulation\) return\s+const emptyUnlink = await request/)
assert.match(value, /emptySimulation = context\.apiSuccess\(MODULE, '空模拟柜允许解除关联', emptyUnlink,\s+responseEvidence\(emptyUnlink\), OPTIONS\)\s+if \(!emptySimulation\) return\s+const emptyRelink = await request/)
assert.match(value, /emptySimulation = context\.apiSuccess\(MODULE, '空模拟柜解绑后允许重新关联', emptyRelink,\s+responseEvidence\(emptyRelink\), OPTIONS\)\s+if \(!emptySimulation\) return\s+const emptyFinalUnlink = await request/)
assert.match(value, /const emptyReleased = context\.apiSuccess\(MODULE, '空模拟柜最终解绑释放真实订舱容量', emptyFinalUnlink,\s+responseEvidence\(emptyFinalUnlink\), OPTIONS\)\s+if \(!emptyReleased\) return\s+const beforeLinkItems/)
assertOrder(value, [
"const linkedContainer = context.apiSuccess(MODULE, '首次关联真实已确认订舱柜', linkResponse,",
'if (!linkedContainer) return',
"const afterLinkPlanResponse = await context.request('GET'",
"const duplicateSimulationResponse = await request(context, 'POST', CONTAINERS",
])
assert.equal(value.match(/responseEvidence\((?:emptyLink|emptyUnlink|emptyRelink|emptyFinalUnlink|linkResponse)\)/g)?.length, 5)
assert.match(value, /关联前后内部柜次、计划和排货明细身份稳定/)
assert.match(value, /bookingId=\$\{encodeURIComponent\(containerId\)\}&warehouseId=/)
assert.match(value, /tasks\?loadingPlanId=\$\{encodeURIComponent\(planId\)\}&warehouseId=/)
assert.match(value, /loadingPlanId: planId, containerBookingId: containerId/)
assert.ok(value.includes("'PATCH', `${CONTAINERS}/${containerId}/transport"))
assert.match(value, /在放舱前绑定本轮真实箱号/)
assert.match(value, /订舱五项运输字段放舱并满足 PDA 订舱门禁/)
assert.match(value, /无真实柜号拒绝推送预装计划/)
assert.match(value, /柜号与 RELEASED 订舱就绪后推送预装计划/)
assert.match(value, /const confirmedTaskAbsent =[\s\S]*if \(!confirmedTaskAbsent\) return/)
assert.match(value, /POST', CONTAINERS/)
})
test('container loading selects the current marker instead of a stale CAB fixture', () => {
const selected = selectContainerLoadingFixture({
marker: 'ADMIN-RUN-AUTO1',
createdResources: {
orchestrationFixtures: {
phase3Container: { marker: 'ADMIN-RUN-CAB', inboundId: 'CAB-INBOUND' },
},
inboundMeasurement: { marker: 'ADMIN-RUN-AUTO1', inboundId: 'FINANCE-INBOUND' },
orders: { marker: 'ADMIN-RUN-AUTO1', inboundId: 'FINANCE-ORDER-INBOUND' },
},
})
assert.equal(selected.inboundId, 'FINANCE-INBOUND')
assert.equal(selected.marker, 'ADMIN-RUN-AUTO1')
})
test('container loading keeps an unmatched candidate so marker failure stays observable', () => {
const selected = selectContainerLoadingFixture({
marker: 'ADMIN-RUN-AUTO1',
createdResources: {
orchestrationFixtures: {
phase3Container: { marker: 'ADMIN-RUN-CAB', inboundId: 'CAB-INBOUND' },
},
},
})
assert.equal(selected.marker, 'ADMIN-RUN-CAB')
})
test('channel isolation accepts only two active channels from the current platform warehouse catalog', () => {
const selected = selectPlatformChannelIsolationPair({
marker: 'ADMIN-RUN-AUTO1', originWarehouseId: '41',
sourcePath: '/api/platform/v1/frozen-channel-contract?originWarehouseId=41',
channels: [
{ channelCode: 'SEA-A', channelName: '海运 A', status: 'ACTIVE' },
{ channelCode: 'SEA-B', channelName: '海运 B', status: 'ACTIVE' },
{ channelCode: 'SEA-C', channelName: '海运 C', status: 'DISABLED' },
],
}, 'ADMIN-RUN-AUTO1', '41', 'SEA-A')
assert.deepEqual(selected.pair, {
primary: { channelCode: 'SEA-A', channelName: '海运 A' },
foreign: { channelCode: 'SEA-B', channelName: '海运 B' },
})
assert.equal(selected.reason, null)
})
test('channel isolation reports BLOCKED_FIXTURE instead of inventing a second channel', () => {
for (const catalog of [
{ marker: 'OLD-RUN', originWarehouseId: '41', sourcePath: '/api/platform/v1/channels', channels: [] },
{ marker: 'ADMIN-RUN-AUTO1', originWarehouseId: '42', sourcePath: '/api/platform/v1/channels', channels: [] },
{ marker: 'ADMIN-RUN-AUTO1', originWarehouseId: '41', sourcePath: '/api/merchant/v1/first-leg/pricing/channels', channels: [] },
{ marker: 'ADMIN-RUN-AUTO1', originWarehouseId: '41', sourcePath: '/api/platform/v1/channels',
channels: [{ channelCode: 'SEA-A', channelName: '海运 A', status: 'ACTIVE' }] },
]) {
const selected = selectPlatformChannelIsolationPair(catalog, 'ADMIN-RUN-AUTO1', '41', 'SEA-A')
assert.equal(selected.pair, null)
assert.match(selected.reason, /^BLOCKED_FIXTURE:/)
}
const value = source('./phase3-container-loading.mjs')
assert.doesNotMatch(value, /foreignChannelCode|\$\{channelCode\}-OTHER|异渠道-\$\{suffix\}/)
assert.match(value, /context\.createdResources\?\.platformLogisticsChannels/)
})
test('container loading enforces channel isolation and stable PDA identity across container number changes', () => {
const value = source('./phase3-container-loading.mjs')
assertOrder(value, [
'新增内部模拟柜',
'新增真实异渠道模拟柜',
'两个真实有效渠道之间拒绝跨渠道装柜',
'人工分配本轮候选货物',
'首次关联真实已确认订舱柜',
'无真实柜号拒绝推送预装计划',
'无真实柜号推送失败后不生成 PDA 任务',
'在放舱前绑定本轮真实箱号',
'订舱 CONFIRMED 即使已有真实柜号也不开放 PDA 任务',
'订舱五项运输字段放舱并满足 PDA 订舱门禁',
'柜号与 RELEASED 订舱就绪后推送预装计划',
'换柜号前读取 PDA 稳定库存快照',
'PDA 任务创建后替换真实柜号',
'PDA 任务创建后清空真实柜号失败',
'换柜号后按稳定计划身份回查 PDA 任务',
'换柜号不改变任务计划柜次柜次号和库存快照身份',
])
assert.match(value, /containerDetail\?\.channelCode === channelCode/)
assert.match(value, /id\(replacedTask\?\.cabinetNo\) === stableIdentity\.cabinetNo/)
assert.match(value, /afterReplacementSnapshot\?\.snapshotToken === beforeReplacementSnapshot\?\.snapshotToken/)
assert.match(value, /pdaIdentityStable: true/)
const batch = value.slice(value.indexOf('const staleBatchResponse'), value.indexOf('const completePath'))
assert.doesNotMatch(batch, /containerNo:/)
})
test('PDA completion acceptance verifies immutable BATCH and COMPLETE_LOADING audit with operator metadata', () => {
const container = source('./phase3-container-loading.mjs')
const convergence = source('./phase3-pda-convergence.mjs')
assert.match(container, /回查完成后的 PDA 操作审计/)
assert.match(container, /item\.actionType === 'BATCH'/)
assert.match(container, /item\.actionType === 'COMPLETE_LOADING'/)
assert.match(container, /Boolean\(item\.operatorId\) && Boolean\(item\.createdAt\)/)
assert.match(convergence, /PDA 原子批次完成审计包含 BATCH 操作/)
assert.match(convergence, /item\.actionType === 'BATCH'/)
})
test('phase3 loading proves mixed-line rollback across task, all items and operations', () => {
const loading = source('./phase3-loading.mjs')
assertOrder(loading, [
'非法混合批次前读取 PDA 全量任务基线',
'PDA 原子批次任一非法明细时整批拒绝',
'回查失败批次后的 PDA 任务快照',
'非法混合批次后回查 PDA 操作历史',
'合法明细加非法明细失败后任务、全部明细和操作历史零写入',
])
assert.match(loading, /taskItemsSignature\(unchangedAfterInvalid\) === taskItemsSignature\(beforeInvalidTask\)/)
assert.match(loading, /operationsSignature\(afterInvalidOperations\) === operationsSignature\(beforeInvalidOperations\)/)
})
test('phase3 loading proves stale inventory zero-write for all items and completion audit', () => {
const loading = source('./phase3-loading.mjs')
assert.match(loading, /taskItemsSignature\(afterStaleTask\) === taskItemsSignature\(beforeMutationTask\)/)
assertOrder(loading, [
'旧 token 冲突对任务、明细、已拣数量和操作历史零写入',
'库存变化后刷新 PDA 实时库存快照',
'原子提交柜次 PDA 整批拣货',
'PDA 原子批次同参同键重放保持待人工确认',
'人工确认柜次 PDA 装柜完成',
'回查原子 Batch 完成审计',
'人工完成后保留 CLAIM/BATCH/COMPLETE_LOADING 审计',
])
})
test('phase3 loading fixture forces A0 through reversible public location status APIs', () => {
const entry = source('../admin-test-env-acceptance.mjs')
const measurement = source('./inbound-measurement.mjs')
const orders = source('./orders.mjs')
assertOrder(entry, [
'disableAvailableLocationsForA0(warehouseId)',
'this.context.phase3LoadingRequireSharedOverflow = true',
"executeModule('inbound-measurement-phase3-loading-fixture'",
'restoreAvailableLocationsAfterA0(warehouseId, disabledLocations)',
])
assert.match(entry, /\/locations\/\$\{encodeURIComponent\(location\.id\)\}\/status/)
assert.match(entry, /\{ status: 'DISABLED', version: Number\(location\.version\) \}/)
assert.match(entry, /\{ status: 'AVAILABLE', version: location\.version \}/)
assert.match(measurement, /phase3LoadingRequireSharedOverflow !== true/)
assert.match(orders, /receivingWarehouseId: id\(master\.receiving\.id\)/)
})
test('customs provisions released booking and completed truck for the selected loading container', () => {
const value = source('./phase3-customs.mjs')
assertOrder(value, [
'selectCustomsFlow(context.createdResources)',
'if (!await ensureServiceCenterFlow(context, container)) return',
'const slicesPath =',
])
assert.match(value, /oceanBookings\.run\(context\)/)
assert.match(value, /serviceCenter\.run\(context\)/)
})
test('downstream producers prefer the phase3Loading container fixture', () => {
const ocean = source('./ocean-bookings.mjs')
const customs = source('./phase3-customs.mjs')
const serviceCenter = source('./service-center-flow.mjs')
assert.match(ocean, /context\.createdResources\?\.phase3Loading\s*\|\|\s*context\.createdResources\?\.phase3ContainerLoading/)
assert.match(customs, /createdResources\?\.phase3Loading,\s*\n\s*createdResources\?\.phase3ContainerLoading/)
assert.match(serviceCenter, /context\.createdResources\?\.phase3Loading\s*\|\|\s*context\.createdResources\?\.phase3ContainerLoading/)
assert.match(ocean, /request\(context, 'POST', `\$\{path\}\/release`/)
assert.match(ocean, /flowOceanBookingId = id\(containerFlow\?\.oceanBookingId\)/)
assert.match(ocean, /ocean-flow-release/)
assert.match(ocean, /existing\?\.marker === context\.marker && existing\?\.finalStatus === 'RELEASED'/)
assert.match(ocean, /const reconciled = await releaseLoadingBooking\(context, containerFlow, suffix\)/)
assert.match(ocean, /containerBookingId: id\(containerFlow\.containerBookingId\), loadingPlanId: id\(containerFlow\.loadingPlanId\)/)
assert.match(source('./phase3-loading.mjs'), /oceanBookingId: bookingId, loadingPlanId, containerBookingId/)
assert.doesNotMatch(ocean, /`\$\{context\.marker\}-\$\{endpoint\}`/)
assert.match(ocean, /`\$\{context\.marker\}-ocean-\$\{endpoint\}`/)
assert.match(serviceCenter, /if \(!allocationMatches\) return/)
const schedules = source('./phase3-port-schedules.mjs')
assert.match(schedules, /allocatedContainerBookingIds: \(detail\.containerAllocations \|\| \[\]\)/)
assert.match(schedules, /ocean\.allocatedContainerBookingIds\?\.includes\(containerBookingId\)/)
assert.match(schedules, /if \(containerBookingId && !knownAllocation\)/)
})
test('default acceptance order verifies loading evidence before finalizing LOADED', () => {
const entry = source('../admin-test-env-acceptance.mjs')
assertOrder(entry, [
"'phase3-loading'",
"'phase3-loading-model-bridge'",
"'phase3-pda-convergence'",
"'phase3-evidence-gate'",
"'phase3-customs'",
"'phase3-loading-finalize'",
])
})
test('container overview always follows phase3 loading in default and custom module selections', () => {
const reordered = normalizeModuleOrder(['phase3-container-overview', 'orders', 'phase3-loading', 'finance'])
assert.deepEqual(reordered, ['orders', 'phase3-loading', 'phase3-container-overview', 'finance'])
assert.deepEqual(parseArguments(['--modules', 'phase3-container-overview,phase3-loading']).modules,
['phase3-loading', 'phase3-container-overview'])
const entry = source('../admin-test-env-acceptance.mjs')
assert.match(entry, /const DEFAULT_MODULES = normalizeModuleOrder\(CONFIGURED_MODULES\)/)
assert.match(entry, /modules: normalizeModuleOrder\(/)
})
test('overview does not fall back to a container fixture when loading evidence was requested', () => {
const overview = source('./phase3-container-overview.mjs')
assert.match(overview, /loadingRequested[\s\S]*\? context\.createdResources\?\.phase3Loading/)
assert.match(overview, /source=\$\{loadingRequested \? 'phase3Loading-required'/)
})
test('phase3 loading provisions its own marker-isolated WAIT_SPLIT fixture', async () => {
const run = new AcceptanceRun({ gateway: 'http://127.0.0.1', modules: [], username: '', password: '', output: '' })
const entry = source('../admin-test-env-acceptance.mjs')
assert.match(entry, /module === 'phase3-loading'/)
assert.match(entry, /preparePhase3LoadingFixture\(\)/)
assert.match(entry, /orders-phase3-loading-fixture/)
assert.match(entry, /inbound-measurement-phase3-loading-fixture/)
assert.match(entry, /marker: originalMarker/)
assert.match(entry, /sourceMarker: fixtureMarker/)
assert.match(entry, /phase3Loading: loadingFixture,\s*\n\s*inboundMeasurement: loadingFixture/)
assert.equal(run.marker.includes('-LOAD'), false)
})
test('container fixture isolates order idempotency while publishing the run marker', () => {
const entry = source('../admin-test-env-acceptance.mjs')
assert.match(entry, /const fixtureMarker = `\$\{originalMarker\}-CAB`/)
assert.match(entry, /marker: originalMarker,\s*\n\s*sourceMarker: fixtureMarker/)
assert.match(entry, /fixture\.finalStatus !== 'APPROVED'/)
assert.match(entry, /禁止回退使用 WAIT_PRICING 订单/)
})
test('measurement fixture polls asynchronous completion before exporting loading identity', () => {
const measurement = source('./inbound-measurement.mjs')
assert.match(measurement, /waitForCompletedMeasurement/)
assert.match(measurement, /measurement\?\.processStatus === 'WAIT_SPLIT'/)
assert.match(measurement, /setTimeout\(resolve, 1_000\)/)
})
test('customs and finalize consume the same loading inbound identity', () => {
const loadingFixture = { marker: 'RUN-1', tenantId: 10001, orderId: 101, inboundId: 201 }
const loading = {
marker: 'RUN-1', tenantId: 10001, inboundId: 201,
containerBookingId: 301, loadingPlanId: 401, finalStatus: 'COMPLETED',
}
const selected = selectCustomsFlow({
orchestrationFixtures: {
phase3Loading: loadingFixture,
inboundMeasurement: loadingFixture,
},
phase3Loading: loading,
})
assert.equal(selected.fixture.marker, loading.marker)
assert.equal(selected.fixture.inboundId, loading.inboundId)
assert.equal(selected.container.inboundId, loading.inboundId)
const finalized = buildFinalizeResource(loading, {
summary: { processStatus: 'LOADED', version: 6 },
}, { http: 200, body: { code: '200' } })
assert.equal(finalized.marker, loading.marker)
assert.equal(finalized.inboundId, loading.inboundId)
assert.equal(finalized.finalStatus, 'LOADED')
})
test('loading evidence acceptance covers idempotency, reversible missing-type gate and scope isolation', () => {
const loading = source('./phase3-loading.mjs')
assertOrder(loading, [
'装柜证据绑定同键同参幂等重放',
'装柜证据绑定同键异参返回冲突',
'装柜证据作废旧版本返回冲突',
'临时作废唯一 PHOTO_STEP_4 证据',
'证据作废同键同参重放保持同一 VOID 结果',
'证据作废同键异参返回冲突',
'已作废证据使用新请求重复作废返回冲突',
'作废唯一证据类型后 LOADED 门禁拒绝',
'补传恢复 PHOTO_STEP_4 有效证据',
'客户身份无权访问平台装柜证据',
'错误客户作用域不可读取本轮装柜证据',
'错误入库单不可读取本轮装柜证据',
])
assert.match(loading, /missingTypeVoidedEvidenceId/)
assert.match(loading, /replacementEvidenceFileId/)
})
test('loaded boundary acceptance proves evidence and transport immutability with zero drift', () => {
const finalize = source('./phase3-loading-finalize.mjs')
assertOrder(finalize, [
'LOADED 后使用新键重复 complete 幂等保持终态',
'LOADED complete 同键异参返回冲突',
'LOADED 后新增装柜证据被拒绝',
'LOADED 后作废装柜证据被拒绝',
'LOADED 后运输信息修改被拒绝',
'回查 LOADED 高风险边界后的入库快照',
'回查 LOADED 高风险边界后的证据快照',
'回查 LOADED 高风险边界后的计划快照',
'LOADED 后拒绝与幂等请求保持状态、版本、证据、计划和审计零漂移',
])
assert.match(finalize, /evidenceSignature\(afterEvidence\) === immutableEvidenceSignature/)
assert.match(finalize, /afterHistorySignature === historySignature/)
assert.match(finalize, /afterPlanSignature === immutablePlanSignature/)
})