回退完美像素原尺寸恢复
直接持久化逻辑分辨率 PNG 并使用最终实际尺寸 升级手动完美像素算法版本并拦截跨版本重放孤儿对象 补充非整除网格和前端权威对账回归测试 同步完美像素契约、决策记录与排障说明
This commit is contained in:
@@ -2995,20 +2995,31 @@ describe('useImageCanvasGenerationWorkflow', () => {
|
||||
|
||||
it('retries the exact persisted request without creating a second dialog or operation', async () => {
|
||||
const flushProjectPersistence = vi.fn().mockResolvedValue(undefined);
|
||||
const applyProjectSnapshot = vi.fn();
|
||||
snapImageToPerfectPixelsMock
|
||||
.mockImplementationOnce(async (request: EditorPixelArtSnapInput) =>
|
||||
createMismatchedPerfectPixelResult(request),
|
||||
)
|
||||
.mockImplementationOnce(async (request: EditorPixelArtSnapInput) =>
|
||||
createMismatchedPerfectPixelResult(request),
|
||||
.mockRejectedValueOnce(
|
||||
new ApiClientError({
|
||||
message: '同一完美像素操作已有其它权威结果,请先读取项目状态对账。',
|
||||
status: 409,
|
||||
code: 'HTTP_409',
|
||||
details: { operationResultAlreadyExists: true },
|
||||
}),
|
||||
);
|
||||
loadEditorProjectMock.mockImplementation(async () => {
|
||||
const request = snapImageToPerfectPixelsMock.mock.calls.at(-1)?.[0] as
|
||||
| EditorPixelArtSnapInput
|
||||
| undefined;
|
||||
return createConflictingPerfectPixelProject(
|
||||
request!.canvasCompletion.dialogId,
|
||||
);
|
||||
return snapImageToPerfectPixelsMock.mock.calls.length === 1
|
||||
? createConflictingPerfectPixelProject(
|
||||
request!.canvasCompletion.dialogId,
|
||||
)
|
||||
: createPerfectPixelProject(
|
||||
request!.canvasCompletion.dialogId,
|
||||
'applied',
|
||||
);
|
||||
});
|
||||
render(
|
||||
<GenerationWorkflowHarness
|
||||
@@ -3019,7 +3030,7 @@ describe('useImageCanvasGenerationWorkflow', () => {
|
||||
src: '/generated-images/editor/source.png',
|
||||
}),
|
||||
]}
|
||||
applyProjectSnapshot={vi.fn()}
|
||||
applyProjectSnapshot={applyProjectSnapshot}
|
||||
flushProjectPersistence={flushProjectPersistence}
|
||||
/>,
|
||||
);
|
||||
@@ -3076,6 +3087,12 @@ describe('useImageCanvasGenerationWorkflow', () => {
|
||||
expect(flushProjectPersistence).toHaveBeenNthCalledWith(2, {
|
||||
preferLatestGenerationDialogs: true,
|
||||
});
|
||||
await waitFor(() => {
|
||||
expect(applyProjectSnapshot).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ projectId: 'project-1' }),
|
||||
{ type: 'perfect-pixel', count: 1 },
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('anchors the first submission reconciliation window at POST time when the pre-POST flush is slow', async () => {
|
||||
@@ -3559,7 +3576,10 @@ describe('useImageCanvasGenerationWorkflow', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('reconciles a responded failure that the server marked as post-persistence', async () => {
|
||||
it.each([
|
||||
['post-persistence', { resultPersistenceStarted: true }],
|
||||
['an existing operation result', { operationResultAlreadyExists: true }],
|
||||
])('reconciles a responded failure marked as %s', async (_label, details) => {
|
||||
const applyProjectSnapshot = vi.fn();
|
||||
const refreshAssetLibrary = vi.fn().mockResolvedValue(undefined);
|
||||
let operationId = '';
|
||||
@@ -3571,7 +3591,7 @@ describe('useImageCanvasGenerationWorkflow', () => {
|
||||
message: '画布版本冲突。',
|
||||
status: 409,
|
||||
code: 'HTTP_409',
|
||||
details: { resultPersistenceStarted: true },
|
||||
details,
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
@@ -2799,6 +2799,10 @@ export function useImageCanvasGenerationWorkflow({
|
||||
error instanceof ApiClientError &&
|
||||
(error.details as { resultPersistenceStarted?: unknown } | null)
|
||||
?.resultPersistenceStarted === true;
|
||||
const operationResultAlreadyExists =
|
||||
error instanceof ApiClientError &&
|
||||
(error.details as { operationResultAlreadyExists?: unknown } | null)
|
||||
?.operationResultAlreadyExists === true;
|
||||
const outcomeMayBePersisted =
|
||||
perfectPixelPostAttempted &&
|
||||
Boolean(perfectPixelDialogId) &&
|
||||
@@ -2808,6 +2812,9 @@ export function useImageCanvasGenerationWorkflow({
|
||||
// 而此时 api-server 可能已经走完 OSS PUT 与落库。必须算作未知结果去对账。
|
||||
(!(error instanceof ApiClientError) ||
|
||||
persistenceMayHaveStarted ||
|
||||
// 中文注释:跨算法版本护栏在本请求 PUT 前发现同 operation 已有权威结果;它不应
|
||||
// 冒充 resultPersistenceStarted,但同样必须读取项目事实完成收口。
|
||||
operationResultAlreadyExists ||
|
||||
isGatewayUnknownOutcomeError(error));
|
||||
let reconciledMessage: string | undefined;
|
||||
let keepPendingConfirmation = false;
|
||||
@@ -3041,10 +3048,15 @@ export function useImageCanvasGenerationWorkflow({
|
||||
error instanceof ApiClientError &&
|
||||
(error.details as { resultPersistenceStarted?: unknown } | null)
|
||||
?.resultPersistenceStarted === true;
|
||||
const operationResultAlreadyExists =
|
||||
error instanceof ApiClientError &&
|
||||
(error.details as { operationResultAlreadyExists?: unknown } | null)
|
||||
?.operationResultAlreadyExists === true;
|
||||
const outcomeMayBePersisted =
|
||||
postAttempted &&
|
||||
(!(error instanceof ApiClientError) ||
|
||||
persistenceMayHaveStarted ||
|
||||
operationResultAlreadyExists ||
|
||||
isGatewayUnknownOutcomeError(error));
|
||||
if (outcomeMayBePersisted) {
|
||||
const verdict = await reconcilePerfectPixelProject(
|
||||
|
||||
Reference in New Issue
Block a user