import test from 'node:test' import assert from 'node:assert/strict' import { replayCompletedCommand, completedPlanAssignmentProbe } from './phase3-loading-finalize.mjs' test('completed-command replay retries one connection failure and keeps its diagnostic', async () => { const failure = { http: 0, raw: 'fetch failed' } const success = { http: 200, body: { code: '200' } } const responses = [failure, success] const diagnostics = [] let calls = 0 assert.equal(await replayCompletedCommand(async () => { calls++; return responses.shift() }, r => diagnostics.push(r)), success) assert.equal(calls, 2) assert.deepEqual(diagnostics, [failure]) }) test('business failures are never retried; a second connection failure remains failure', async () => { for (const response of [{ http: 200, body: { code: 'A0409' } }, { http: 503 }, { http: 0 }]) { let calls = 0 const result = await replayCompletedCommand(async () => { calls++; return response }, () => {}) assert.equal(result, response) assert.equal(calls, response.http === 0 ? 2 : 1) } }) function assignmentFixture(change = false) { const baseline = { status: 'COMPLETED', version: 7, items: [{ id: '11', packageCount: 2 }] } const reads = [], writes = [] const context = { marker: 'batch', createdResources: {}, async request(method, path) { reads.push({ method, path }); return { http: 200, body: { code: '200', data: change ? { ...baseline, version: 8 } : structuredClone(baseline) } } } } const input = { planPath: '/plans/1', baseline, body: { inboundId: '10', inboundDetailId: '11', packageCount: 1, expectedVersion: 7, operationId: 'batch-negative' } } const send = async (_context, method, path, body) => { writes.push({ method, path, body: structuredClone(body) }) return writes.length === 1 ? { http: 0, raw: 'fetch failed', transportError: { code: 'ECONNRESET' } } : { http: 200, body: { code: 'A0409' } } } return { baseline, context, input, reads, writes, send } } test('completed plan rejection probe checks unchanged authoritative state before exact original replay and retains first transport evidence', async () => { const f = assignmentFixture() const result = await completedPlanAssignmentProbe(f.context, f.input, f.send) assert.equal(result.body.code, 'A0409'); assert.equal(f.writes.length, 2) assert.deepEqual(f.writes[0], f.writes[1]); assert.equal(f.reads.length, 2) const proof = f.context.createdResources.completedPlanAssignmentProbes[0] assert.equal(proof.attempts[0].transportError.code, 'ECONNRESET') assert.equal(proof.status, 'VERIFIED_REJECTION_AFTER_TRANSPORT_RECOVERY') }) test('changed completed plan after lost response stops without any second write', async () => { const f = assignmentFixture(true) await assert.rejects(completedPlanAssignmentProbe(f.context, f.input, f.send), /禁止重放/) assert.equal(f.writes.length, 1) assert.equal(f.context.createdResources.completedPlanAssignmentProbes[0].status, 'UNKNOWN_RESULT_STATE_CHANGED') }) test('completed plan rejection recovery never retries business rejection, server error or permits an ordinary active plan', async () => { for (const response of [{ http: 200, body: { code: 'A0409' } }, { http: 503 }, { http: 0 }]) { const f = assignmentFixture(); let count = 0 await completedPlanAssignmentProbe(f.context, f.input, async () => { count++; return response }) assert.equal(count, response.http === 0 ? 2 : 1) } const f = assignmentFixture(); f.input.baseline.status = 'ACTIVE' await assert.rejects(completedPlanAssignmentProbe(f.context, f.input, f.send), /不可变命令/) assert.equal(f.writes.length, 0) })