Skip to content

fix(pcp): compose nested instance proxies - #135

Merged
mxpv merged 2 commits into
mxpv:mainfrom
yohawing:agent/fix-nested-instance-proxy-payload
Aug 14, 2026
Merged

fix(pcp): compose nested instance proxies#135
mxpv merged 2 commits into
mxpv:mainfrom
yohawing:agent/fix-nested-instance-proxy-payload

Conversation

@yohawing

Copy link
Copy Markdown
Contributor

Summary

Compose nested instance prototypes from the prim that actually composes inside
their enclosing prototype.

Add a three-layer regression fixture containing:

  • an instance of a payload-backed outer prim;
  • a sub-root payload target;
  • a nested instance with a sub-root external reference target; and
  • a value below the nested instance proxy.

Root cause

register_prototype accepted an instance path that could itself be an instance
proxy. It built the nested prototype key and materialized root from the sparse
authored namespace at that path. Child-name composition could still discover
the nested reference, but the materialized prototype descendants had no
contributing specs.

Resolve the instance through effective_path first, then use that composed
index for the instance key and prototype materialization. The original path is
still retained for prototype registry membership and load-rule scoping.

Regression fixture

Before this change, nested_payload_proxy fails because
/Placed/Nested/Leaf.value resolves to None. After the change it resolves to
7.0, and /Placed/Nested/Leaf maps to /__Prototype_1/Leaf.

The fixture is intentionally small and contains only three USDA files. Pixar
OpenUSD usdchecker validates its root layer successfully.

Validation

  • cargo fmt --all -- --check
  • cargo test --all-targets --all-features (2315 passed, 1 ignored)
  • cargo clippy --all-targets --all-features -- -D warnings
  • Pixar OpenUSD usdchecker on the regression fixture
  • Downstream production asset: 2,044 composed Mesh prims and 249 renderable
    Mesh prims, matching Pixar OpenUSD; generated GLB includes the formerly
    missing nested-payload geometry

A nested instance can itself be an instance proxy when it is authored inside a payload-backed outer prototype. register_prototype previously seeded the nested prototype from the sparse instance namespace instead of the prim that composes inside the enclosing prototype, so the prototype root advertised child names while its descendants had no specs.

Resolve the instance through effective_path before deriving its key and materializing its prototype. Keep the original instance path for registry membership and load-rule scoping.

Add a three-layer regression fixture with sub-root payload and reference targets. The test proves that a value beneath the nested proxy resolves and maps into the nested prototype.
@yohawing
yohawing marked this pull request as ready for review August 14, 2026 11:05
@mxpv

mxpv commented Aug 14, 2026

Copy link
Copy Markdown
Owner

Good catch, thanks for opening this!

I think the payload isn't the trigger. I've spent some tokens - minimal repro is a single
layer, no payload — the nested reference just has to target a sub-root prim:

def Scope "Library" { def Scope "Inner" { def Scope "Leaf" { double v = 3.0 } } }
def Scope "Outer" { def Scope "Nested" ( instanceable = true; references = </Library/Inner> ) {} }
def Scope "A" ( instanceable = true; references = </Outer> ) {}

/A/Nested/Leaf.v is None before your change, 3.0 after. Point it at a
root-level </Inner> and it passes without the fix — that's the existing
instancing_nested_in_prototype.usda.

I'll fold in a few cleanups before merging: single-file fixture to match the
other instancing_* ones, the sharing assertions from
nested_prototype_proxy_redirects (same prototype from both routes, exactly 2
minted, proxy never indexed), and materialize_prototype's param, which is
passed the composed path but still named canonical.

The payload and the extra layers were incidental: the trigger is a nested
instance whose reference targets a sub-root prim, which reproduces in a
single layer. Swap the fixture for one matching the other instancing_*
fixtures, and assert what the fix guarantees — the proxy path is never
composed in place, and both routes to the nested instance resolve to one
prototype.

materialize_prototype is handed the path whose index composes the
instance, so name and document it as such rather than as the canonical
instance. Note why the key takes its arcs from that path but its load
rules from the instance's own path.
@mxpv
mxpv merged commit 737118b into mxpv:main Aug 14, 2026
5 checks passed
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