回退完美像素原尺寸恢复
Project CI / Repository checks (pull_request) Successful in 1m12s
Project CI / Frontend tests (pull_request) Successful in 2m52s
Project CI / Backend tests (pull_request) Successful in 3m54s
Project CI / Native shell tests (pull_request) Successful in 13m24s

直接持久化逻辑分辨率 PNG 并使用最终实际尺寸
升级手动完美像素算法版本并拦截跨版本重放孤儿对象
补充非整除网格和前端权威对账回归测试
同步完美像素契约、决策记录与排障说明
This commit is contained in:
2026-08-10 04:45:02 +00:00
parent bcff8f1957
commit 8aea7364b6
11 changed files with 209 additions and 60 deletions
@@ -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(