Skip to content

Use ResourceId for referring to Resources#4176

Merged
timon-schelling merged 12 commits into
masterfrom
resource-id-migration
May 29, 2026
Merged

Use ResourceId for referring to Resources#4176
timon-schelling merged 12 commits into
masterfrom
resource-id-migration

Conversation

@timon-schelling
Copy link
Copy Markdown
Member

No description provided.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a migration from referencing resources by hash to referencing them by a unique ID (ResourceId), backed by a new ResourceRegistry to manage resource sources and garbage collection. Key feedback focuses on making the JSON migration parser more robust against pretty-printed or multi-field objects, removing a strict check that could cause deserialization failures on documents with missing embedded resources, and optimizing the resource garbage collection pipeline by passing HashSet references directly to avoid redundant conversions and allocations.

Comment thread editor/src/messages/portfolio/document_migration.rs Outdated
Comment thread editor/src/messages/portfolio/document_migration.rs Outdated
Comment on lines +3493 to 3501
pub fn used_resources(&self, include_history: bool) -> Box<[ResourceId]> {
let mut resources = HashSet::new();
self.network_interface.collect_used_resources(&mut resources);
if include_history {
self.document_undo_history.iter().for_each(|interface| interface.collect_used_resources(&mut resources));
self.document_redo_history.iter().for_each(|interface| interface.collect_used_resources(&mut resources));
}
resources
resources.into_iter().collect::<Vec<_>>().into_boxed_slice()
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

used_resources collects the used resource IDs into a HashSet, but then converts it to a Vec and then a Box<[ResourceId]>. When this is passed to garbage_collect, the first thing garbage_collect does is collect it back into a HashSet.

This results in redundant allocations and conversions (HashSet -> Vec -> Box -> HashSet). Returning HashSet<ResourceId> directly from used_resources and updating garbage_collect to accept &HashSet<ResourceId> avoids these redundant operations.

Suggested change
pub fn used_resources(&self, include_history: bool) -> Box<[ResourceId]> {
let mut resources = HashSet::new();
self.network_interface.collect_used_resources(&mut resources);
if include_history {
self.document_undo_history.iter().for_each(|interface| interface.collect_used_resources(&mut resources));
self.document_redo_history.iter().for_each(|interface| interface.collect_used_resources(&mut resources));
}
resources
resources.into_iter().collect::<Vec<_>>().into_boxed_slice()
}
pub fn used_resources(&self, include_history: bool) -> HashSet<ResourceId> {
let mut resources = HashSet::new();
self.network_interface.collect_used_resources(&mut resources);
if include_history {
self.document_undo_history.iter().for_each(|interface| interface.collect_used_resources(&mut resources));
self.document_redo_history.iter().for_each(|interface| interface.collect_used_resources(&mut resources));
}
resources
}

Comment on lines +931 to +941
let used_resources = self.used_resources(false);

let embedded_resource_hashes = Vec::from_iter(used_resources.iter().filter_map(|id| match self.resources.registry.info(id) {
Some(ResourceInfo { hash: Some(hash), sources, .. }) if sources.contains(&DataSource::Embedded) => Some(hash),
_ => None,
}))
.into_boxed_slice();

let mut document = self.clone();

document.resources.registry.garbage_collect(used_resources.as_ref());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If used_resources is updated to return HashSet<ResourceId>, we should update this call to pass &used_resources instead of used_resources.as_ref() to match the updated garbage_collect signature.

Suggested change
let used_resources = self.used_resources(false);
let embedded_resource_hashes = Vec::from_iter(used_resources.iter().filter_map(|id| match self.resources.registry.info(id) {
Some(ResourceInfo { hash: Some(hash), sources, .. }) if sources.contains(&DataSource::Embedded) => Some(hash),
_ => None,
}))
.into_boxed_slice();
let mut document = self.clone();
document.resources.registry.garbage_collect(used_resources.as_ref());
let used_resources = self.used_resources(false);
let embedded_resource_hashes = Vec::from_iter(used_resources.iter().filter_map(|id| match self.resources.registry.info(id) {
Some(ResourceInfo { hash: Some(hash), sources, .. }) if sources.contains(&DataSource::Embedded) => Some(hash),
_ => None,
}))
.into_boxed_slice();
let mut document = self.clone();
document.resources.registry.garbage_collect(&used_resources);

Comment on lines +274 to +278
pub fn garbage_collect(&mut self, used: &[ResourceId]) {
let used_set: std::collections::HashSet<ResourceId> = used.iter().copied().collect();
self.sources.retain(|id, _| used_set.contains(id));
self.hashes.retain(|id, _| used_set.contains(id));
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Accepting &HashSet<ResourceId> directly in garbage_collect avoids the need to re-collect a slice into a HashSet on every call, eliminating redundant allocations and hashing operations.

	pub fn garbage_collect(&mut self, used: &std::collections::HashSet<ResourceId>) {
		self.sources.retain(|id, _| used.contains(id));
		self.hashes.retain(|id, _| used.contains(id));
	}

@timon-schelling timon-schelling marked this pull request as ready for review May 29, 2026 08:26
@timon-schelling timon-schelling changed the title Use ResourceId to refer to Resources Use ResourceId for refer to Resources May 29, 2026
@timon-schelling timon-schelling changed the title Use ResourceId for refer to Resources Use ResourceId for refering to Resources May 29, 2026
@timon-schelling timon-schelling changed the title Use ResourceId for refering to Resources Use ResourceId for referring to Resources May 29, 2026
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 30 files

Confidence score: 2/5

  • There is a high-confidence regression risk: in node-graph/graph-craft/src/document/value.rs, switching TaggedValue::Resource from ResourceHash to ResourceId without a legacy "Resource" migration is likely to break deserialization of existing documents.
  • editor/src/node_graph_executor.rs has a concrete runtime correctness risk because GraphUpdate is still gated by network/inspect hash checks and can miss resource changes, leaving stale resources in use.
  • Given one severe backward-compatibility break plus another medium-to-high runtime staleness issue, this looks risky to merge until both behaviors are addressed.
  • Pay close attention to node-graph/graph-craft/src/document/value.rs and editor/src/node_graph_executor.rs - deserialization compatibility and resource-change invalidation are the key risk areas.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="node-graph/graph-craft/src/document/value.rs">

<violation number="1" location="node-graph/graph-craft/src/document/value.rs:399">
P1: Changing `TaggedValue::Resource` from `ResourceHash` to `ResourceId` without a legacy `"Resource"` migration breaks backward deserialization for existing documents.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

VectorModification(Box<VectorModification>),
ImageData(Image<Color>),
Resource(graphene_application_io::resource::ResourceHash),
Resource(graphene_application_io::resource::ResourceId),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Changing TaggedValue::Resource from ResourceHash to ResourceId without a legacy "Resource" migration breaks backward deserialization for existing documents.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At node-graph/graph-craft/src/document/value.rs, line 399:

<comment>Changing `TaggedValue::Resource` from `ResourceHash` to `ResourceId` without a legacy `"Resource"` migration breaks backward deserialization for existing documents.</comment>

<file context>
@@ -396,7 +396,8 @@ tagged_value! {
 	VectorModification(Box<VectorModification>),
 	ImageData(Image<Color>),
-	Resource(graphene_application_io::resource::ResourceHash),
+	Resource(graphene_application_io::resource::ResourceId),
+	ResourceHash(graphene_application_io::resource::ResourceHash),
 	// ==========
</file context>

Comment thread editor/src/node_graph_executor.rs
Comment thread node-graph/libraries/resources/src/lib.rs Outdated
Comment thread node-graph/libraries/resources/src/lib.rs Outdated
@timon-schelling timon-schelling enabled auto-merge May 29, 2026 10:30
@timon-schelling timon-schelling disabled auto-merge May 29, 2026 10:30
@timon-schelling timon-schelling force-pushed the resource-id-migration branch from 9b2c896 to a5b9aea Compare May 29, 2026 10:33
@timon-schelling timon-schelling enabled auto-merge May 29, 2026 10:34
@timon-schelling timon-schelling disabled auto-merge May 29, 2026 10:35
@timon-schelling timon-schelling added this pull request to the merge queue May 29, 2026
Merged via the queue into master with commit a40e0d2 May 29, 2026
10 checks passed
@timon-schelling timon-schelling deleted the resource-id-migration branch May 29, 2026 10:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants