清理完美像素链路的死代码
Project CI / Frontend tests (pull_request) Failing after 1m43s
Project CI / Repository checks (pull_request) Successful in 1m16s
Project CI / Backend tests (pull_request) Successful in 4m2s
Project CI / Native shell tests (pull_request) Successful in 11m41s

- 删除只有测试调用的 snap_pixel_art_strict 与 snap_pixel_art 两个无 deadline
  包装,公开入口收敛为 snap_pixel_art_with_deadline 与
  snap_pixel_art_strict_with_deadline;原本只写在 snap_pixel_art 头上的双输入
  尺寸与输出契约合并进保留者的文档,调用点改为显式传 None。
- 去掉持久化结果里从不被读取的 status 透传(客户端枚举与 record 字段)。该段
  原本搭载了「status 缺失即拒绝」的校验,保留为显式 is_none 拦截,并补一个
  此前缺失的回归用例锁住它。
- 快速编辑面板不再对 dialog 状态做 pending-confirmation 的运行时收窄:dialog
  由面板派生,写回方只做 failed→idle 重置,该分支恒不成立,直接取面板状态。
- 收回三个无人导入的 export(reconcilePerfectPixelProject、
  createPerfectPixelReconciliationOperation、
  INVALID_PERFECT_PIXEL_OPERATION_ERROR_MESSAGE)。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-04 06:53:29 +00:00
parent 06d8fbb9c2
commit 3bea6441a8
6 changed files with 58 additions and 77 deletions
+2 -2
View File
@@ -5,8 +5,8 @@ pub mod vector_engine;
pub use pixel_art_snapper::{
PIXEL_ART_ALPHA_COVERAGE_THRESHOLD, PIXEL_ART_ANALYSIS_COLORS, PIXEL_ART_KMEANS_SAMPLE_LIMIT,
PIXEL_ART_MAX_IMAGE_PIXELS, PixelArtSnapError, snap_pixel_art, snap_pixel_art_strict,
snap_pixel_art_strict_with_deadline, snap_pixel_art_with_deadline,
PIXEL_ART_MAX_IMAGE_PIXELS, PixelArtSnapError, snap_pixel_art_strict_with_deadline,
snap_pixel_art_with_deadline,
};
pub use vector_engine::{
DownloadedImage, GPT_IMAGE_2_C_MODEL, GPT_IMAGE_2_MODEL, GeneratedImages, NANOBANANA_2_MODEL,
@@ -156,31 +156,11 @@ impl SnapConfig {
/// image is always a PNG at the original `rgba_source` dimensions. Its alpha
/// channel contains only `0` or `255`, and fully transparent pixels are
/// canonical `[0, 0, 0, 0]`.
pub fn snap_pixel_art(
grid_source: &DownloadedImage,
rgba_source: &DownloadedImage,
) -> Result<DownloadedImage, PixelArtSnapError> {
snap_pixel_art_with_deadline(grid_source, rgba_source, None)
}
/// Snap an image unless legacy analysis detects no grid step on either axis.
///
/// Unlike [`snap_pixel_art`], this entry does not synthesize a uniform
/// min-dimension/64 grid when neither axis contains a detectable step. Every
/// other detection, walking, sampling, and encoding behavior is identical.
pub fn snap_pixel_art_strict(
grid_source: &DownloadedImage,
rgba_source: &DownloadedImage,
) -> Result<DownloadedImage, PixelArtSnapError> {
snap_pixel_art_strict_with_deadline(grid_source, rgba_source, None)
}
/// Deadline-aware variant of [`snap_pixel_art`].
///
/// The deadline is checked before and after non-cooperative codec/resize
/// operations, and periodically inside the K-means, profile, and cell-sampling
/// loops. Exceeding it returns [`PixelArtSnapError::DeadlineExceeded`] without
/// producing a partial image.
/// producing a partial image. Pass `None` to opt out of deadline checks.
pub fn snap_pixel_art_with_deadline(
grid_source: &DownloadedImage,
rgba_source: &DownloadedImage,
@@ -189,7 +169,12 @@ pub fn snap_pixel_art_with_deadline(
snap_pixel_art_with_grid_policy(grid_source, rgba_source, deadline, false)
}
/// Deadline-aware variant of [`snap_pixel_art_strict`].
/// Snap an image unless legacy analysis detects no grid step on either axis.
///
/// Unlike [`snap_pixel_art_with_deadline`], this entry does not synthesize a
/// uniform min-dimension/64 grid when neither axis contains a detectable step.
/// Every other detection, walking, sampling, and encoding behavior — including
/// the deadline semantics — is identical.
pub fn snap_pixel_art_strict_with_deadline(
grid_source: &DownloadedImage,
rgba_source: &DownloadedImage,
@@ -1111,7 +1096,8 @@ mod tests {
let grid = downloaded_png(RgbaImage::from_pixel(8, 8, Rgba([10, 20, 30, 255])));
let rgba = downloaded_png(RgbaImage::from_pixel(8, 9, Rgba([10, 20, 30, 255])));
let error = snap_pixel_art(&grid, &rgba).expect_err("dimensions should mismatch");
let error = snap_pixel_art_with_deadline(&grid, &rgba, None)
.expect_err("dimensions should mismatch");
assert!(
error
.to_string()
@@ -1141,9 +1127,9 @@ mod tests {
fn strict_mode_rejects_only_when_legacy_would_use_uniform_fallback() {
let source = downloaded_png(RgbaImage::from_pixel(128, 128, Rgba([10, 20, 30, 255])));
let legacy = snap_pixel_art(&source, &source)
let legacy = snap_pixel_art_with_deadline(&source, &source, None)
.expect("legacy generation style should retain its uniform fallback");
let strict = snap_pixel_art_strict(&source, &source)
let strict = snap_pixel_art_strict_with_deadline(&source, &source, None)
.expect_err("explicit strict action should reject an undetected grid");
assert_eq!(decode_output(&legacy).dimensions(), (128, 128));
@@ -1179,9 +1165,9 @@ mod tests {
);
let source = downloaded_png(image);
let legacy = snap_pixel_art(&source, &source)
let legacy = snap_pixel_art_with_deadline(&source, &source, None)
.expect("legacy processing should succeed with a detected step");
let strict = snap_pixel_art_strict(&source, &source)
let strict = snap_pixel_art_strict_with_deadline(&source, &source, None)
.expect("strict processing should reuse the detected legacy step");
assert_eq!(strict.bytes, legacy.bytes);
assert_eq!(strict.mime_type, legacy.mime_type);
@@ -1208,9 +1194,10 @@ mod tests {
}
}
let output = snap_pixel_art(
let output = snap_pixel_art_with_deadline(
&downloaded_png(grid_image),
&downloaded_png(rgba_image.clone()),
None,
)
.expect("pixel snapping should succeed");
let decoded = decode_output(&output);
@@ -1237,8 +1224,10 @@ mod tests {
}
let rgba = downloaded_png(rgba);
let first = snap_pixel_art(&grid, &rgba).expect("first snap should succeed");
let second = snap_pixel_art(&grid, &rgba).expect("second snap should succeed");
let first =
snap_pixel_art_with_deadline(&grid, &rgba, None).expect("first snap should succeed");
let second =
snap_pixel_art_with_deadline(&grid, &rgba, None).expect("second snap should succeed");
assert_eq!(first.bytes, second.bytes);
for pixel in decode_output(&first).pixels() {
@@ -30,16 +30,8 @@ pub struct EditorPixelArtResultPersistRecordInput {
pub completed_at_micros: i64,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum EditorPixelArtResultPersistRecordStatus {
Applied,
DialogMissing,
AlreadyApplied,
}
#[derive(Clone, Debug, PartialEq)]
pub struct EditorPixelArtResultPersistRecord {
pub status: EditorPixelArtResultPersistRecordStatus,
pub asset_object: module_assets::AssetObjectUpsertSnapshot,
pub project_resource: EditorProjectResourceRecord,
pub asset: EditorAssetRecord,
@@ -1103,20 +1095,13 @@ fn map_editor_pixel_art_result_persist_result(
if !result.ok {
return Err(SpacetimeClientError::procedure_failed(result.error_message));
}
let status = match result
.status
.ok_or_else(|| SpacetimeClientError::validation_failed("完美像素持久化结果缺少状态"))?
{
crate::module_bindings::EditorPixelArtResultPersistStatus::Applied => {
EditorPixelArtResultPersistRecordStatus::Applied
}
crate::module_bindings::EditorPixelArtResultPersistStatus::DialogMissing => {
EditorPixelArtResultPersistRecordStatus::DialogMissing
}
crate::module_bindings::EditorPixelArtResultPersistStatus::AlreadyApplied => {
EditorPixelArtResultPersistRecordStatus::AlreadyApplied
}
};
// 中文注释:三种落库状态(Applied / DialogMissing / AlreadyApplied)目前没有任何
// 上层消费方,不再向上透传;但状态缺失说明 procedure 返回体不完整,仍要拦在这里。
if result.status.is_none() {
return Err(SpacetimeClientError::validation_failed(
"完美像素持久化结果缺少状态",
));
}
let asset_object = result.asset_object.ok_or_else(|| {
SpacetimeClientError::validation_failed("完美像素持久化结果缺少 asset object")
})?;
@@ -1141,7 +1126,6 @@ fn map_editor_pixel_art_result_persist_result(
.flatten();
Ok(EditorPixelArtResultPersistRecord {
status,
asset_object: map_editor_spritesheet_asset_object_snapshot(asset_object),
project_resource: map_editor_spritesheet_project_resource_snapshot(project_resource)?,
asset: map_editor_spritesheet_asset_snapshot(asset)?,
@@ -1422,29 +1406,36 @@ mod pixel_art_persist_mapper_tests {
}
#[test]
fn editor_pixel_art_persist_mapper_preserves_status_and_accepts_missing_project() {
fn editor_pixel_art_persist_mapper_rejects_missing_status() {
let mut result = successful_pixel_art_persist_result(
crate::module_bindings::EditorPixelArtResultPersistStatus::Applied,
);
result.status = None;
let error = map_editor_pixel_art_result_persist_result(result)
.expect_err("成功结果缺少状态时必须拒绝");
assert!(matches!(
error,
SpacetimeClientError::Runtime(message)
if message == "完美像素持久化结果缺少状态"
));
}
#[test]
fn editor_pixel_art_persist_mapper_accepts_every_status_and_missing_project() {
let cases = [
(
crate::module_bindings::EditorPixelArtResultPersistStatus::Applied,
EditorPixelArtResultPersistRecordStatus::Applied,
),
(
crate::module_bindings::EditorPixelArtResultPersistStatus::DialogMissing,
EditorPixelArtResultPersistRecordStatus::DialogMissing,
),
(
crate::module_bindings::EditorPixelArtResultPersistStatus::AlreadyApplied,
EditorPixelArtResultPersistRecordStatus::AlreadyApplied,
),
crate::module_bindings::EditorPixelArtResultPersistStatus::Applied,
crate::module_bindings::EditorPixelArtResultPersistStatus::DialogMissing,
crate::module_bindings::EditorPixelArtResultPersistStatus::AlreadyApplied,
];
for (binding_status, expected_status) in cases {
for binding_status in cases {
let mapped = map_editor_pixel_art_result_persist_result(
successful_pixel_art_persist_result(binding_status),
)
.expect("project=None 仍应映射成功");
assert_eq!(mapped.status, expected_status);
assert_eq!(mapped.asset_object.asset_object_id, "assetobj_pixel");
assert_eq!(mapped.project_resource.resource_id, "editor-resource-pixel");
assert_eq!(mapped.asset.asset_id, "editor-asset-pixel");
@@ -342,7 +342,7 @@ export const PERFECT_PIXEL_RECONCILIATION_WINDOW_MS = 75_000;
// 中文注释:第一批曾把 v1 快照写成 240 秒。滚动部署与旧标签页仍可能持久化该形状,
// 所以读取侧保留兼容上限;它只决定快照是否可信,不会延长当前 75 秒对账窗口。
const LEGACY_PERFECT_PIXEL_RECONCILIATION_WINDOW_MS = 240_000;
export const INVALID_PERFECT_PIXEL_OPERATION_ERROR_MESSAGE =
const INVALID_PERFECT_PIXEL_OPERATION_ERROR_MESSAGE =
'完美像素操作快照无效,禁止自动重试。';
const PERFECT_PIXEL_OPERATION_KEYS = new Set([
@@ -78,10 +78,11 @@ function syncPanelFromDialogUpdate(
model: normalizedDialog.imageModel ?? normalizedPanel.model,
quickEditReferences: normalizedDialog.generationReferences,
assetLabel: normalizedDialog.assetLabel,
status:
normalizedDialog.status === 'pending-confirmation'
? normalizedPanel.status
: normalizedDialog.status,
// 中文注释:dialog 由 createQuickEditDialog 从面板自身派生,组合器只会做
// failed→idle 的重置,不会写入 'pending-confirmation' 这类完美像素专属状态。
// 因此归一化后的 dialog 状态恒等于归一化后的面板状态,直接取面板侧即可,
// 也让面板的三态联合类型不必在这里做运行时收窄。
status: normalizedPanel.status,
errorMessage: normalizedDialog.errorMessage,
};
}
@@ -325,7 +325,7 @@ export function inspectPerfectPixelProjectSnapshot(
return { kind: 'applied', project, resource };
}
export function createPerfectPixelReconciliationOperation(
function createPerfectPixelReconciliationOperation(
operation: PerfectPixelOperationSnapshot,
startedAt = Date.now(),
): PerfectPixelOperationSnapshot {
@@ -362,7 +362,7 @@ function waitForPerfectPixelReconciliationDelay(
});
}
export async function reconcilePerfectPixelProject(
async function reconcilePerfectPixelProject(
projectId: string,
operation: PerfectPixelOperationSnapshot,
options: { signal?: AbortSignal } = {},