From 40a9ce3f37d81ef529aabf89bbc68f50410cbff7 Mon Sep 17 00:00:00 2001 From: Orual Date: Mon, 10 Aug 2026 23:42:14 -0400 Subject: [PATCH] PM-86: fix protocol-root-collapsed duplicate resource identity The target_keys_by_path cache dedupes on local RootId, but resolved_closure.resolved stores protocol_root() which collapses multiple local roots (Models|Parts|P|External -> UploadedLdraw, OfficialParts|OfficialP -> OfficialLibrary). Same path resolved through two different local roots bypassed the cache and pushed to resolved_closure.resolved twice, causing DuplicateIdentity at validation. Add a resolved_identities HashSet keyed on (protocol_root, path) matching the validation identity exactly, and guard both push sites. Epic: PM-86 --- Cargo.lock | 1 + crates/polymodel-ldraw-core/Cargo.toml | 1 + crates/polymodel-ldraw-core/src/mpd.rs | 7 +++++++ src/appview/ldraw.rs | 1 - 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index acd88f5..85c3e8f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6793,6 +6793,7 @@ dependencies = [ "serde_json", "smol_str", "thiserror 2.0.18", + "tracing", "web-time", ] diff --git a/crates/polymodel-ldraw-core/Cargo.toml b/crates/polymodel-ldraw-core/Cargo.toml index e682f95..c38a53f 100644 --- a/crates/polymodel-ldraw-core/Cargo.toml +++ b/crates/polymodel-ldraw-core/Cargo.toml @@ -12,6 +12,7 @@ serde = { workspace = true } smol_str = { workspace = true } miette = { workspace = true } thiserror = { workspace = true } +tracing = "0.1" web-time = { workspace = true } [dev-dependencies] diff --git a/crates/polymodel-ldraw-core/src/mpd.rs b/crates/polymodel-ldraw-core/src/mpd.rs index a88e36f..da5d165 100644 --- a/crates/polymodel-ldraw-core/src/mpd.rs +++ b/crates/polymodel-ldraw-core/src/mpd.rs @@ -329,6 +329,13 @@ impl ResourceClosure { let mut identities = std::collections::HashSet::with_capacity(self.resolved.len()); for resource in &self.resolved { if !identities.insert((resource.root, resource.path.clone())) { + tracing::error!( + root = ?resource.root, + path = %resource.path, + total_resolved = self.resolved.len(), + all_identities = ?self.resolved.iter().map(|r| (r.root, r.path.as_str().to_string())).collect::>(), + "DUPLICATE RESOURCE IDENTITY DETECTED" + ); return Err(ResourceClosureError::DuplicateIdentity); } resource.validate()?; diff --git a/src/appview/ldraw.rs b/src/appview/ldraw.rs index 62d36cc..a6cc324 100644 --- a/src/appview/ldraw.rs +++ b/src/appview/ldraw.rs @@ -789,7 +789,6 @@ async fn build_model_load_bundle(state: AppState, uri: AtUri) -> AppResult