This commit is contained in:
2026-10-20 15:48:38 +08:00
parent da6b4685d7
commit 0ff1eefff6
50 changed files with 3933 additions and 78 deletions
@@ -47,7 +47,14 @@ export async function dispatchEvidenceContext(context) {
}
export function query(path, values) {
const params = new URLSearchParams()
for (const [key, value] of Object.entries(values)) if (value !== undefined && value !== null && value !== '') params.set(key, String(value))
for (const [key, value] of Object.entries(values)) {
if (value === undefined || value === null || value === '') continue
if (Array.isArray(value)) {
for (const item of value) if (item !== undefined && item !== null && item !== '') params.append(key, String(item))
continue
}
params.set(key, String(value))
}
return `${path}?${params}`
}
export function commandKey(marker, namespace, action) {
@@ -112,8 +119,8 @@ export function dispatchIo(context, module, proof, namespace) {
const boundary = context.createdResources.dispatchWriteBoundary ??= { marker: context.marker, stopped: false }
if (!context.marker || boundary.marker !== context.marker) throw new DispatchNotRun('请求边界不属于本轮marker')
const checkpoint = async () => { if (typeof context.checkpoint === 'function') await context.checkpoint() }
const check = (label, response, passed) => {
context.assert?.(module, label, response, passed, `marker=${context.marker}; HTTP=${response?.http}; requestId=${response?.requestId}; traceId=${response?.traceId}`, { scenario: namespace, deploymentBlocker: true })
const check = (label, response, passed, detail = '') => {
context.assert?.(module, label, response, passed, `${detail ? `${detail}; ` : ''}marker=${context.marker}; HTTP=${response?.http}; requestId=${response?.requestId}; traceId=${response?.traceId}`, { scenario: namespace, deploymentBlocker: true })
if (!passed) throw Error(`${namespace}: ${label}`)
}
const send = async (method, path, body, label) => {
@@ -136,7 +143,8 @@ export function dispatchIo(context, module, proof, namespace) {
}
const command = async (method, path, body, label) => { const response = await send(method, path, body, label); check(label, response, success(response)); return response.body.data }
const key = action => commandKey(context.marker, namespace, action)
return { check, send, command, key }
return { check, send, command, key,
planIds: (context.createdResources?.phase4OverseasPda?.generatedPlanIds || []).map(String) }
}
export function replayFacts(result) { const copy = structuredClone(result); if (copy && typeof copy === 'object') delete copy.replayed; return copy }
export async function replay(io, path, body, result, label, method = 'POST') {
@@ -145,7 +153,9 @@ export async function replay(io, path, body, result, label, method = 'POST') {
return again
}
export async function candidatePage(io, warehouseId, extra = {}) {
const result = await io.command('GET', query(`${DISPATCH_BASE}/candidates`, { warehouseId, sourceStage: 'RECEIVED', ...extra }), undefined, '读取同仓原生候选')
const planIds = extra.planIds ?? io?.planIds
const params = { warehouseId, sourceStage: 'RECEIVED', ...(Array.isArray(planIds) && planIds.length ? { planIds } : {}), ...extra }
const result = await io.command('GET', query(`${DISPATCH_BASE}/candidates`, params), undefined, '读取同仓原生候选')
io.check('候选完整包络', null, result?.complete === true && Array.isArray(result.candidates))
return result.candidates
}