统一队列生成的冻结价格与资产成本

worker 优先读取任务 billing context 中的入队价格

扣费与 generationCostMudPoints 共用同一有效价格

新增冻结价格显式数据流回归测试
This commit is contained in:
2026-08-08 18:10:17 +08:00
parent 92832e56c2
commit 84ec79a8bb
@@ -65,7 +65,9 @@ use spacetime_client::{
use crate::{
api_response::json_success_body,
asset_billing::{
begin_editor_generation_commit_attempt, editor_generation_commit_attempt_was_dispatched,
begin_editor_generation_commit_attempt,
current_external_generation_billing_price_mud_points,
editor_generation_commit_attempt_was_dispatched,
execute_billable_asset_operation_with_cost, mark_editor_generation_commit_dispatched,
mark_editor_generation_commit_outcome_confirmed,
with_editor_generation_durable_billing_boundary,
@@ -2952,20 +2954,25 @@ where
} else {
provider_request_size
};
let configured_price_mud_points = state
.editor_generation_pricing()
.await
.map_err(|error| {
AppError::from_status(StatusCode::INTERNAL_SERVER_ERROR).with_details(json!({
"provider": "editor-generation-pricing",
"message": error.to_string(),
}))
})?
.image_generation_mud_points(
normalized_kind,
Some(generation_options.model),
Some(generation_options.image_size),
);
let effective_price_mud_points =
if let Some(price_mud_points) = current_external_generation_billing_price_mud_points() {
price_mud_points
} else {
state
.editor_generation_pricing()
.await
.map_err(|error| {
AppError::from_status(StatusCode::INTERNAL_SERVER_ERROR).with_details(json!({
"provider": "editor-generation-pricing",
"message": error.to_string(),
}))
})?
.image_generation_mud_points(
normalized_kind,
Some(generation_options.model),
Some(generation_options.image_size),
)
};
let prompt_generation_inputs = payload.generation_inputs.take();
let generate_operation = async {
let prompt_build = prompt_builder(prompt_generation_inputs).await?;
@@ -3062,7 +3069,7 @@ where
caller.owner_user_id.as_str(),
editor_image_generation_billing_asset_kind(normalized_kind),
request_context.request_id(),
u64::from(configured_price_mud_points),
u64::from(effective_price_mud_points),
generate_operation,
)
.await?;
@@ -3168,7 +3175,7 @@ where
.clone()
.or_else(|| Some("character".to_string())),
generation_inputs: generation_inputs.clone(),
generation_cost_mud_points: u64::from(configured_price_mud_points),
generation_cost_mud_points: u64::from(effective_price_mud_points),
thumbnail_src: None,
group_task_id: None,
group_task_expected_asset_count: None,
@@ -3435,7 +3442,7 @@ where
generation_cost_mud_points: if is_character_generation {
0
} else {
u64::from(configured_price_mud_points)
u64::from(effective_price_mud_points)
},
image_sequence_frames: None,
image_sequence_duration_ms: None,
@@ -15970,7 +15977,7 @@ mod tests {
assert_function_contains(
source,
"pub(crate) async fn generate_editor_image_for_owner",
"let configured_price_mud_points",
"let effective_price_mud_points",
&[
"is_publication_material_generation",
"Some(GPT_IMAGE_2_MODEL)",
@@ -18951,7 +18958,7 @@ mod tests {
"fn normalize_editor_image_generation_size",
&[
"execute_billable_asset_operation_with_cost",
"configured_price_mud_points",
"effective_price_mud_points",
],
);
assert_function_contains(
@@ -18983,6 +18990,23 @@ mod tests {
);
}
#[test]
fn queued_image_generation_persists_the_frozen_billing_price() {
let source = include_str!("editor_project.rs");
assert_function_contains_in_order(
source,
"pub(crate) async fn generate_editor_image_for_owner_with_prompt_builder",
"fn editor_image_generation_billing_asset_kind",
&[
"current_external_generation_billing_price_mud_points()",
".editor_generation_pricing()",
"execute_billable_asset_operation_with_cost(",
"u64::from(effective_price_mud_points)",
"generation_cost_mud_points: u64::from(effective_price_mud_points)",
],
);
}
#[test]
fn editor_ui_design_asset_extraction_commits_prepared_bundle_atomically() {
let source = include_str!("editor_project.rs");