优化
This commit is contained in:
@@ -387,16 +387,19 @@ export async function run(context) {
|
||||
const releasedContainer = context.apiSuccess(MODULE, '放舱后回查货柜运输版本', releasedContainerResponse, '', OPTIONS)
|
||||
|
||||
const pushKey = `${context.marker}-container-push`.slice(0, 128)
|
||||
const pushResponse = await request(context, 'POST', `${SMART}/plans/${planId}/push-preload`,
|
||||
{ expectedVersion: Number(assigned.version) }, { 'Idempotency-Key': pushKey })
|
||||
const pushRequest = Object.freeze({
|
||||
path: `${SMART}/plans/${planId}/push-preload`,
|
||||
body: Object.freeze({ expectedVersion: Number(assigned.version) }),
|
||||
headers: Object.freeze({ 'Idempotency-Key': pushKey }),
|
||||
})
|
||||
const pushResponse = await request(context, 'POST', pushRequest.path, pushRequest.body, pushRequest.headers)
|
||||
const pushed = context.apiSuccess(MODULE, '柜号与 RELEASED 订舱就绪后推送预装计划', pushResponse, '', OPTIONS)
|
||||
context.assert(MODULE, '推送后计划保持 EDITING 且版本递增', pushResponse,
|
||||
pushed?.status === 'EDITING' && Number(pushed?.version) === Number(assigned.version) + 1,
|
||||
`status=${pushed?.status || 'missing'}, version=${pushed?.version ?? 'missing'}`, OPTIONS)
|
||||
if (pushed?.status !== 'EDITING') return
|
||||
|
||||
const pushReplayResponse = await request(context, 'POST', `${SMART}/plans/${planId}/push-preload`,
|
||||
{ expectedVersion: Number(assigned.version) }, { 'Idempotency-Key': pushKey })
|
||||
const pushReplayResponse = await request(context, 'POST', pushRequest.path, pushRequest.body, pushRequest.headers)
|
||||
const pushReplay = context.apiSuccess(MODULE, '推送预装 Idempotency-Key 重放', pushReplayResponse, '', OPTIONS)
|
||||
context.assert(MODULE, '推送重放保持同一 EDITING 计划', pushReplayResponse,
|
||||
id(pushReplay?.id) === planId && pushReplay?.status === 'EDITING'
|
||||
@@ -476,6 +479,15 @@ export async function run(context) {
|
||||
context.addStep(MODULE, 'PDA 任务仓库隔离拒绝', wrongWarehouseResponse,
|
||||
failure(wrongWarehouseResponse), `HTTP=${wrongWarehouseResponse.http}, code=${codeOf(wrongWarehouseResponse)}`, OPTIONS)
|
||||
|
||||
const beforeClaimPlanResponse = await context.request('GET', `${SMART}/plans/${planId}`)
|
||||
const beforeClaimPlan = context.apiSuccess(MODULE, '领取任务前读取装柜计划即时版本',
|
||||
beforeClaimPlanResponse, '', OPTIONS)
|
||||
const beforeClaimPlanVersion = Number(beforeClaimPlan?.version)
|
||||
context.assert(MODULE, '领取任务前计划保持 EDITING 且版本有效', beforeClaimPlanResponse,
|
||||
beforeClaimPlan?.status === 'EDITING' && Number.isInteger(beforeClaimPlanVersion),
|
||||
`status=${beforeClaimPlan?.status || 'missing'}, version=${beforeClaimPlan?.version ?? 'missing'}`, OPTIONS)
|
||||
if (beforeClaimPlan?.status !== 'EDITING' || !Number.isInteger(beforeClaimPlanVersion)) return
|
||||
|
||||
const claimResponse = await request(context, 'POST', `${PDA}/tasks/${taskId}/claim`, {
|
||||
expectedAssignmentVersion: Number(task?.assignment?.version || 0),
|
||||
operationId: `${context.marker}-pda-claim`.slice(0, 128),
|
||||
@@ -489,7 +501,7 @@ export async function run(context) {
|
||||
const claimedPlanResponse = await context.request('GET', `${SMART}/plans/${planId}`)
|
||||
const claimedPlan = context.apiSuccess(MODULE, '领取后回查装柜计划', claimedPlanResponse, '', OPTIONS)
|
||||
context.assert(MODULE, '领取任务后计划进入 LOADING 且版本递增', claimedPlanResponse,
|
||||
claimedPlan?.status === 'LOADING' && Number(claimedPlan?.version) === Number(pushed?.version) + 1,
|
||||
claimedPlan?.status === 'LOADING' && Number(claimedPlan?.version) > beforeClaimPlanVersion,
|
||||
`status=${claimedPlan?.status || 'missing'}, version=${claimedPlan?.version ?? 'missing'}`, OPTIONS)
|
||||
|
||||
const inventoryResponse = await context.request('GET',
|
||||
|
||||
@@ -211,9 +211,11 @@ export async function run(context) {
|
||||
}, { 'Idempotency-Key': `${context.marker}-p3-smart`.slice(0, 128) })
|
||||
const smartData = context.apiSuccess(MODULE, '智能分柜并生成预装清单', smart, `inboundId=${inboundId}`, OPTIONS)
|
||||
const planId = id(smartData?.preloadPlan?.id)
|
||||
const smartPreloadVersion = Number(smartData?.preloadPlan?.version)
|
||||
context.assert(MODULE, '智能分柜预装计划 PENDING、版本和明细正确', smart,
|
||||
smartData?.mainStatus === 'WAIT_SPLIT' && Boolean(planId) && smartData?.preloadPlan?.status === 'PENDING'
|
||||
&& Number(smartData?.preloadPlan?.version) === 0 && smartData?.preloadPlan?.items?.length === 1,
|
||||
&& Number.isInteger(smartPreloadVersion) && smartPreloadVersion >= 0
|
||||
&& smartData?.preloadPlan?.items?.length === 1,
|
||||
`mainStatus=${smartData?.mainStatus || 'missing'}, planId=${planId || 'missing'}, status=${smartData?.preloadPlan?.status || 'missing'}`, OPTIONS)
|
||||
if (!planId) return
|
||||
|
||||
@@ -225,16 +227,19 @@ export async function run(context) {
|
||||
&& replay.body?.data?.preloadPlan?.items?.length === 1,
|
||||
`HTTP=${replay.http}, code=${codeOf(replay)}, planId=${id(replay.body?.data?.preloadPlan?.id) || 'missing'}`, OPTIONS)
|
||||
|
||||
const bindVersions = Object.freeze({
|
||||
expectedPreloadVersion: smartPreloadVersion,
|
||||
expectedLoadingPlanVersion: Number(assignedLoadingPlan.version),
|
||||
})
|
||||
const bindResponse = await request(context, 'POST',
|
||||
`${base}/preload/loading-plans/${loadingPlanId}?tenantId=${encodeURIComponent(tenantId)}`, {
|
||||
expectedPreloadVersion: Number(smartData.preloadPlan.version),
|
||||
expectedLoadingPlanVersion: Number(assignedLoadingPlan.version),
|
||||
}, { 'Idempotency-Key': `${context.marker}-bridge-bind`.slice(0, 128) })
|
||||
`${base}/preload/loading-plans/${loadingPlanId}?tenantId=${encodeURIComponent(tenantId)}`,
|
||||
bindVersions, { 'Idempotency-Key': `${context.marker}-bridge-bind`.slice(0, 128) })
|
||||
const link = context.apiSuccess(MODULE, '原子关联入库预装与柜次装柜计划', bindResponse, '', OPTIONS)
|
||||
context.assert(MODULE, '桥接双版本递增且关联归属唯一', bindResponse,
|
||||
id(link?.inboundId) === inboundId && id(link?.loadingPlanId) === loadingPlanId
|
||||
&& id(link?.preloadPlanId) === planId && Number(link?.allocatedPackageCount) === 1
|
||||
&& Number(link?.preloadVersion) === 1 && Number(link?.loadingPlanVersion) === 2,
|
||||
&& Number(link?.preloadVersion) > bindVersions.expectedPreloadVersion
|
||||
&& Number(link?.loadingPlanVersion) > bindVersions.expectedLoadingPlanVersion,
|
||||
`linkId=${id(link?.id) || 'missing'}, preloadVersion=${link?.preloadVersion ?? 'missing'}, loadingVersion=${link?.loadingPlanVersion ?? 'missing'}`, OPTIONS)
|
||||
if (!link?.id) return
|
||||
|
||||
@@ -606,7 +611,8 @@ export async function run(context) {
|
||||
{ expectedVersion: Number(link.preloadVersion) }, { 'Idempotency-Key': `${context.marker}-p3-confirming`.slice(0, 128) })
|
||||
const confirmingData = context.apiSuccess(MODULE, '提交预装清单确认', confirming, '', OPTIONS)
|
||||
context.assert(MODULE, '预装清单进入 CONFIRMING 且版本递增', confirming,
|
||||
confirmingData?.preloadPlan?.status === 'CONFIRMING' && Number(confirmingData?.preloadPlan?.version) === 2,
|
||||
confirmingData?.preloadPlan?.status === 'CONFIRMING'
|
||||
&& Number(confirmingData?.preloadPlan?.version) > Number(link.preloadVersion),
|
||||
`status=${confirmingData?.preloadPlan?.status || 'missing'}, version=${confirmingData?.preloadPlan?.version ?? 'missing'}`, OPTIONS)
|
||||
if (confirmingData?.preloadPlan?.status !== 'CONFIRMING') return
|
||||
|
||||
@@ -618,9 +624,9 @@ export async function run(context) {
|
||||
: '预装确认推进主状态 LOADING 和计划 CONFIRMED', confirm,
|
||||
directPdaCompletion
|
||||
? confirmed?.mainStatus === 'LOADING' && confirmed?.preloadPlan?.status === 'CONFIRMING'
|
||||
&& Number(confirmed?.preloadPlan?.version) === 2
|
||||
&& Number(confirmed?.preloadPlan?.version) === Number(confirmingData.preloadPlan.version)
|
||||
: confirmed?.mainStatus === 'LOADING' && confirmed?.preloadPlan?.status === 'CONFIRMED'
|
||||
&& Number(confirmed?.preloadPlan?.version) === 3,
|
||||
&& Number(confirmed?.preloadPlan?.version) > Number(confirmingData.preloadPlan.version),
|
||||
`mainStatus=${confirmed?.mainStatus || 'missing'}, planStatus=${confirmed?.preloadPlan?.status || 'missing'}, version=${confirmed?.preloadPlan?.version ?? 'missing'}`, OPTIONS)
|
||||
if (confirmed?.mainStatus !== 'LOADING') return
|
||||
|
||||
|
||||
@@ -105,7 +105,7 @@ test('bridge loading starts through a real PDA batch before preload confirmation
|
||||
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, /Number\(confirmed\?\.preloadPlan\?\.version\) === Number\(confirmingData\.preloadPlan\.version\)/)
|
||||
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/)
|
||||
@@ -312,6 +312,21 @@ test('container loading enforces channel isolation and stable PDA identity acros
|
||||
assert.doesNotMatch(batch, /containerNo:/)
|
||||
})
|
||||
|
||||
test('preload and loading versions use immediate operation baselines and exact push replay', () => {
|
||||
const container = source('./phase3-container-loading.mjs')
|
||||
assert.match(container, /const pushRequest = Object\.freeze\(\{[\s\S]*path:[\s\S]*body: Object\.freeze[\s\S]*headers: Object\.freeze/)
|
||||
assert.equal((container.match(/request\(context, 'POST', pushRequest\.path, pushRequest\.body, pushRequest\.headers\)/g) || []).length, 2)
|
||||
assert.match(container, /const beforeClaimPlanVersion = Number\(beforeClaimPlan\?\.version\)/)
|
||||
assert.match(container, /Number\(claimedPlan\?\.version\) > beforeClaimPlanVersion/)
|
||||
|
||||
const loading = source('./phase3-loading.mjs')
|
||||
assert.match(loading, /Number\.isInteger\(smartPreloadVersion\) && smartPreloadVersion >= 0/)
|
||||
assert.match(loading, /Number\(link\?\.preloadVersion\) > bindVersions\.expectedPreloadVersion/)
|
||||
assert.match(loading, /Number\(link\?\.loadingPlanVersion\) > bindVersions\.expectedLoadingPlanVersion/)
|
||||
assert.match(loading, /Number\(confirmingData\?\.preloadPlan\?\.version\) > Number\(link\.preloadVersion\)/)
|
||||
assert.doesNotMatch(loading, /Number\((?:smartData|link|confirmingData|confirmed)[^\n]*version\) === [0-9]/)
|
||||
})
|
||||
|
||||
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')
|
||||
|
||||
Reference in New Issue
Block a user