修复 AGC Rust shard 4 的两个 CI 失败测试

- direct_registered_taonier_runtime_image_paths 通用平台图兜底补齐 canonical 切片排除:assets/art-spritesheet-slices/ 下的切片只经完整 manifest/receipt/内容校验放行,内容被篡改的切片不再绕过完成门禁
- direct_completion_scans_npm_scene_modules 测试改为保留 fixture 有效切片,不再依赖被修复的兜底漏洞
- mixed_project_history_rows 过时测试按 d48d09905 收紧后的契约改为断言 DirectProject 链对 legacy 行失败关闭
This commit is contained in:
2026-09-16 05:10:31 +08:00
parent a4a030dfb5
commit 51c4174b73
2 changed files with 16 additions and 19 deletions
@@ -2555,6 +2555,15 @@ fn direct_registered_taonier_runtime_image_paths(root: &Path) -> Vec<String> {
.generation_route
.as_deref()
.is_some_and(|route| route.starts_with("/api/external/v1/editor/"))
// Canonical slices are admitted only through
// `direct_registered_taonier_slice_paths` after the full slice
// manifest/receipt/content validation. This generic fallback
// must not re-admit a slice whose bytes no longer match the
// registered receipt.
&& !(asset.kind == "art-spritesheet-slice"
&& asset
.local_path
.starts_with("assets/art-spritesheet-slices/"))
})
.filter_map(|asset| {
let path = direct_normalized_project_asset_path(&asset.local_path)?;
@@ -8220,11 +8229,6 @@ mod tests {
"const player = new Image(); player.src = '/assets/art-spritesheet-slices/player.png';",
)
.expect("scene");
std::fs::write(
root.join("assets/art-spritesheet-slices/player.png"),
tiny_opaque_png(),
)
.expect("slice");
assert_eq!(
direct_game_sources_referenced_taonier_assets(&root),
@@ -272,7 +272,7 @@ fn project_history_skips_direct_project_rows_but_keeps_other_broken_rows_failing
}
#[test]
fn mixed_project_history_rows_stay_readable_from_both_sides() {
fn mixed_project_history_rows_read_by_generic_chain_but_fail_closed_for_direct_project() {
let root = unique_conversation_test_root();
init_local_game_project_at(&root, "project-1", "写侧统一测试").expect("init project");
write_project_history(&root, &[DIRECT_PROJECT_ROW]);
@@ -309,19 +309,12 @@ fn mixed_project_history_rows_stay_readable_from_both_sides() {
vec!["模式切换后由通用写入器补写的回复", "带 id 的旧格式回复"]
);
// 反向:DirectProject 链把同一份文件里的两种行都读出来,混合文件不构成毒化
let direct_items = crate::agent::read_direct_project_history_items_at(&root)
.expect("DirectProject must keep reading the mixed history");
assert_eq!(
direct_items
.iter()
.map(|item| item["content"][0]["text"].as_str().unwrap_or_default())
.collect::<Vec<_>>(),
vec![
"再加一个按钮",
"模式切换后由通用写入器补写的回复",
"带 id 的旧格式回复",
]
// 反向:DirectProject 链只接受 response_item 信封,混合文件里的 legacy 行让它失败关闭
let error = crate::agent::read_direct_project_history_items_at(&root)
.expect_err("DirectProject must fail closed on legacy rows");
assert!(
error.starts_with("DirectProject 历史记录类型无效"),
"{error}"
);
std::fs::remove_dir_all(root).ok();