fix: settle puzzle failures and profile tasks

This commit is contained in:
kdletters
2026-05-26 22:02:58 +08:00
parent 4001ee0a5c
commit 17a184b0a7
14 changed files with 436 additions and 81 deletions

View File

@@ -388,6 +388,22 @@ pub fn normalize_puzzle_draft(mut draft: PuzzleResultDraft) -> PuzzleResultDraft
draft
}
pub fn mark_failed_puzzle_result_draft_generation(
mut draft: PuzzleResultDraft,
) -> PuzzleResultDraft {
if draft.levels.is_empty() {
draft = normalize_puzzle_draft(draft);
}
for level in &mut draft.levels {
if level.generation_status.trim() != "ready" {
level.generation_status = "failed".to_string();
}
}
sync_primary_level_fields(&mut draft);
draft.generation_status = "failed".to_string();
draft
}
pub fn sync_primary_level_fields(draft: &mut PuzzleResultDraft) {
if let Some(primary_level) = draft.levels.first() {
draft.level_name = primary_level.level_name.clone();
@@ -3212,6 +3228,50 @@ mod tests {
);
}
#[test]
fn failed_generation_marks_pending_levels_failed_without_touching_ready_assets() {
let anchor_pack = infer_anchor_pack("雨夜猫街", Some("雨夜猫街"));
let mut draft = compile_result_draft(&anchor_pack, &[]);
draft.generation_status = "generating".to_string();
draft.levels[0].generation_status = "generating".to_string();
draft.levels.push(PuzzleDraftLevel {
level_id: "puzzle-level-2".to_string(),
level_name: "第二关".to_string(),
picture_description: "第二关画面".to_string(),
picture_reference: None,
ui_background_prompt: None,
ui_background_image_src: None,
ui_background_image_object_key: None,
level_scene_image_src: None,
level_scene_image_object_key: None,
ui_spritesheet_image_src: None,
ui_spritesheet_image_object_key: None,
level_background_image_src: None,
level_background_image_object_key: None,
background_music: None,
candidates: vec![PuzzleGeneratedImageCandidate {
candidate_id: "candidate-1".to_string(),
image_src: "/ready.png".to_string(),
asset_id: "asset-1".to_string(),
prompt: "prompt".to_string(),
actual_prompt: None,
source_type: "generated".to_string(),
selected: true,
}],
selected_candidate_id: Some("candidate-1".to_string()),
cover_image_src: Some("/ready.png".to_string()),
cover_asset_id: Some("asset-1".to_string()),
generation_status: "ready".to_string(),
});
let failed = mark_failed_puzzle_result_draft_generation(draft);
assert_eq!(failed.generation_status, "failed");
assert_eq!(failed.levels[0].generation_status, "failed");
assert_eq!(failed.levels[1].generation_status, "ready");
assert_eq!(failed.levels[1].cover_image_src.as_deref(), Some("/ready.png"));
}
#[test]
fn form_seed_keeps_multiline_picture_description() {
let anchor_pack = infer_anchor_pack(

View File

@@ -68,6 +68,15 @@ pub struct PuzzleDraftCompileInput {
pub compiled_at_micros: i64,
}
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct PuzzleDraftCompileFailureInput {
pub session_id: String,
pub owner_user_id: String,
pub error_message: String,
pub failed_at_micros: i64,
}
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct PuzzleGeneratedImagesSaveInput {