修复完美像素对账请求的绝对截止

为 requestJson 增加覆盖鉴权、重试和响应体读取的可选绝对 deadline。

让完美像素项目对账按 75 秒窗口和单次 10 秒上界读取权威快照。

补充鉴权等待、响应体读取、客户端透传和对账边界的定向测试与文档。
This commit is contained in:
2026-08-04 10:01:44 +00:00
parent 88087455d6
commit 2c07b91c25
8 changed files with 301 additions and 32 deletions
@@ -2710,7 +2710,7 @@ describe('useImageCanvasGenerationWorkflow', () => {
expect(loadEditorProjectMock).toHaveBeenNthCalledWith(
1,
'project-1',
expect.objectContaining({ timeoutMs: 10_000 }),
expect.objectContaining({ deadlineAt: expect.any(Number) }),
);
expect(snapImageToPerfectPixelsMock).toHaveBeenCalledTimes(1);
expect(applyProjectSnapshot).toHaveBeenCalledWith(reconciledProject, {
@@ -3197,7 +3197,7 @@ describe('useImageCanvasGenerationWorkflow', () => {
});
expect(loadEditorProjectMock).toHaveBeenCalledWith(
'project-1',
expect.objectContaining({ timeoutMs: 10_000 }),
expect.objectContaining({ deadlineAt: expect.any(Number) }),
);
expect(refreshAssetLibrary).toHaveBeenCalledTimes(1);
expect(screen.getByTestId('dialog').textContent).not.toContain('failed');
@@ -3862,9 +3862,16 @@ describe('useImageCanvasGenerationWorkflow', () => {
'project-1',
expect.objectContaining({
signal: expect.any(AbortSignal),
timeoutMs: 10_000,
deadlineAt: expect.any(Number),
}),
);
const readOptions = loadEditorProjectMock.mock.calls[0]?.[1] as
| { deadlineAt?: number }
| undefined;
expect(readOptions?.deadlineAt).toBeLessThanOrEqual(Date.now() + 10_000);
expect(readOptions?.deadlineAt).toBeLessThanOrEqual(
hydratedDialog.perfectPixelOperation!.reconcileUntil,
);
expect(snapImageToPerfectPixelsMock).not.toHaveBeenCalled();
expect(applyProjectSnapshotWithoutHistory).toHaveBeenCalledTimes(1);
expect(applyProjectSnapshot).not.toHaveBeenCalled();
@@ -3902,6 +3909,7 @@ describe('useImageCanvasGenerationWorkflow', () => {
it('observes an expired hydrated operation at least once and leaves it pending when no result exists', async () => {
const operationId = 'perfect-pixel-hydrated-expired';
const readStartedAt = Date.now();
const hydratedDialog = createHydratedPerfectPixelDialog({
operationId,
reconcileUntil: Date.now() - 1_000,
@@ -3930,6 +3938,11 @@ describe('useImageCanvasGenerationWorkflow', () => {
);
});
expect(loadEditorProjectMock).toHaveBeenCalledTimes(1);
const readOptions = loadEditorProjectMock.mock.calls[0]?.[1] as
| { deadlineAt?: number }
| undefined;
expect(readOptions?.deadlineAt).toBeGreaterThanOrEqual(readStartedAt);
expect(readOptions?.deadlineAt).toBeLessThanOrEqual(Date.now() + 10_000);
expect(snapImageToPerfectPixelsMock).not.toHaveBeenCalled();
expect(applyProjectSnapshotWithoutHistory).not.toHaveBeenCalled();
expect(screen.getByTestId('dialog-error').textContent).toBe(
@@ -391,17 +391,18 @@ async function reconcilePerfectPixelProject(
}
try {
hasAttemptedRead = true;
const readStartedAt = Date.now();
const remainingAtReadMs = operation.reconcileUntil - readStartedAt;
const readDeadlineAt =
remainingAtReadMs > 0
? Math.min(
operation.reconcileUntil,
readStartedAt + PERFECT_PIXEL_PROJECT_READ_TIMEOUT_MS,
)
: readStartedAt + PERFECT_PIXEL_PROJECT_READ_TIMEOUT_MS;
latestProject = await loadEditorProject(projectId, {
signal: options.signal,
timeoutMs: Math.max(
1,
Math.min(
PERFECT_PIXEL_PROJECT_READ_TIMEOUT_MS,
remainingAfterDelayMs > 0
? remainingAfterDelayMs
: PERFECT_PIXEL_PROJECT_READ_TIMEOUT_MS,
),
),
deadlineAt: readDeadlineAt,
});
const verdict = inspectPerfectPixelProjectSnapshot(
latestProject,