Repository navigation
usd_import: read USD through Moho (scene-index S2) - #415
Conversation
Plans step S2 of the scene-index program: a second import route that reads the stage through Moho's scene index, migrated family by family behind a parity check against the direct import (samples, fixtures, ALab, Moana), with the default flipped to the index route once parity holds. Pins openusd by Moho's rev so the build carries one openusd, and lists the Moho-side gaps (cross-chunk light linking, materials outside loaded chunks, authored scene globals, prototype source paths) as follow-ups. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PUSvMHN9Akk66u2oG3rUbF
As UsdImaging's move onto scene indices was gated on parity alone (USDIMAGINGGL_ENGINE_ENABLE_SCENE_INDEX, legacy tests kept against the same baselines), import_parity.sh fails on report or image differences only and prints both routes' peak memory and import time with their ratios. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PUSvMHN9Akk66u2oG3rUbF
Moho's change scene-index-gaps closes the seven gaps the plan found: light linking after the merge (chain::input / chain::merged), the unresolved paths for the side input, stage metadata with authored-ness, primOrigin/scenePath, strategy (D) in the spike, every pass collection, and the merged children order. The design, tasks and parity spec now use them: task 1.5 builds against scene-index-gaps and bumps the moho rev once it merges, D9 keeps judging links after the last chunk with an agreement test streamed too, and the prototype warning-path parity exception goes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PUSvMHN9Akk66u2oG3rUbF
…itch The user's call: the Crust importer can drop and move to Moho in this change. No CRUST_USD_IMPORT switch and no default flip. Parity becomes "against baselines recorded from today's importer" (digest, check report and 16 spp image per sample and fixture, ALab and Moana memory and time as a report), with a regenerate flag, as UsdImaging moved onto scene indices. The bridge stays as a transitional device inside the change, and a final group deletes the direct readers, the bridge, EvalTimeScope and the prototype epoch. Specs, design and tasks revised to match; co-development with Moho goes through `cargo --config`, since .cargo/config.toml is tracked here. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PUSvMHN9Akk66u2oG3rUbF
Cargo identifies a git source by URL plus reference, so `branch = "main"` and Moho's `rev = "68a867a…"` would be two openusd packages at one commit. The patch now names the rev; bump order is Moho, then crust-render, then Mantle, and `cargo update -p openusd` no longer moves it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PUSvMHN9Akk66u2oG3rUbF
…openusd crust-core gains `moho` (git, rev 92c8b84), which pins openusd at the same rev as the workspace patch, so `cargo tree -i openusd` shows one package with moho among its dependents. deny.toml allows Moho's source. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PUSvMHN9Akk66u2oG3rUbF
tests/one_openusd.rs hands Moho's re-exported Stage, SchemaRegistry and an openusd-schemas type to functions taking the workspace's. With the patch set back to `branch = "main"` it failed with mismatched types, as recorded in its doc comment. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PUSvMHN9Akk66u2oG3rUbF
…pment Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PUSvMHN9Akk66u2oG3rUbF
Two live tests rewrote `live_primvars.usda` while running in parallel, so
one could read the other's half-written file ("Unexpected prim specifier").
Each test now writes its own.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PUSvMHN9Akk66u2oG3rUbF
The `parity` feature (test-only, on for crust-core's, crust-render's and crust-hydra's tests through dev-dependencies) ends every successful load_scene by comparing the scene's digest with a baseline under crust-core/tests/data/import_baselines/, panicking on the first differing line. The digest is stable text over the geometry in id order (pieces hashed bit for bit per ray category, material sharing and Signature, flags, side tables, motion), lights, volumes, camera, settings, AOVs, pass, warnings, provenance, layers and Source, with paths normalised. Baselines are keyed by the layers composed, the options, the switches and the importing test. CRUST_RECORD_BASELINES=1 records; CRUST_PARITY_IMAGES=1 adds a 16 spp image hash (meant for --release). crust-render/tests/import_parity.rs compares every committed sample's `crust check --json` report, import phases removed, with its baseline. All baselines here were recorded from the direct importer (tasks 2.1-2.3, images still to record in a release run). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PUSvMHN9Akk66u2oG3rUbF
Moho's main now carries M1 to M7 (light linking after the merge, streaming::unresolved, stage metadata with authored-ness, primOrigin, every pass collection, the merged children order, strategy D) and the light-linking performance fix. The workspace builds against the git rev with no local patch; `cargo tree -i openusd` still shows one package. Task 1.5 done; the design's note on Moho's rev updated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PUSvMHN9Akk66u2oG3rUbF
scripts/parity_images.sh runs the suite optimised with CRUST_PARITY_IMAGES=1: every import is imported again and rendered at 16 spp with the indirect clamp off, and its pixel hash compared with the .image baseline recorded here from the direct importer. With images on, recording writes images only (digests and check reports are compared, never rewritten, since the second import shows in counts). The 25 tests that observe the second import are listed in parity_images.expected. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PUSvMHN9Akk66u2oG3rUbF
…line `record` keeps the check report (import phases removed), the 16 spp EXR and the minimum peak memory and parse time over N runs; `check` compares report and image with the current build, exits 1 on a difference, and prints memory and time with their ratios without gating on them. Verified on the Cornell box: check exits 0, and 1 when the report differs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PUSvMHN9Akk66u2oG3rUbF
`Space` is an id interned per process in the order spaces are met, so the provenance's StageFacts printed `Space(6)` or `Space(7)` depending on which test ran first. The digests are re-recorded from the direct importer with the space's name. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PUSvMHN9Akk66u2oG3rUbF
Streaming is scheduling only: the stage's check report and its 16 spp image are equal with CRUST_STREAM_IMPORT=0 and without. Baselines (digests and images) recorded from the direct importer. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PUSvMHN9Akk66u2oG3rUbF
…pike) Recorded from the direct importer with scripts/import_parity.sh: ALab 10.96 GiB / 31.13 s and Moana 23.88 GiB / 173.66 s at the end of the import; Moho's spike on Moana, (B) 1.97 GiB and (D) 2.35 GiB. The baseline directory (reports, EXRs, goldens, a diagnostic report) is kept in target/import-baselines/. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PUSvMHN9Akk66u2oG3rUbF
load_scene no longer walks the stage: a single stage is one bridge chain (StageSceneIndex, Flattening, MaterialBindingResolving, RenderSettingsFlattening, light linking judged by the stage), and a streamed one is light linking over a MergingSceneIndex of the payload-free scene input and each chunk's masked stage, added, walked and removed in turn. The walk (index/walk.rs) keeps the direct traversal's stack discipline, takes children from the walked input's own chain (never the merged order above a chunk root), skips the prototypes listed under the root, and prunes from the index: abstract and inactive prims are absent, purpose and visibility are each prim's own values from the generic data. Each prim's families still read through the transitional bridge (index/bridge.rs), via visit_prim, the body traverse_into had. Parity with the direct importer's baselines is green on the whole suite, single-stage and streamed (tasks 3.1-3.3). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PUSvMHN9Akk66u2oG3rUbF
…Moho The layers a scene composed, its root layer stack and the invisible overrides its strongest layer authors are file and layer-spec facts, not scene description: they move to index/stage_facts.rs, read from the stage. The time range and whether it is authored come from the absolute root's __usdStageMetadata (Moho's M3), on the payload-free scene input, which load_scene now builds for every import and hands to the streamed merging index. Parity green (task 3.4). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PUSvMHN9Akk66u2oG3rUbF
…spec The fixture wrote `def Scope "Render"` and then `over "Render"` in the same layer. openusd keeps the second specifier, so the whole /Render was an undefined `over`: the direct importer read its prims anyway (it walked every prim), a scene index, like UsdImaging, leaves undefined prims out. Two specs of one prim in one layer is not valid USD; the charSettings now sit inside the one `def`. Baselines for the corrected fixture are recorded from the direct importer (36537fe). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PUSvMHN9Akk66u2oG3rUbF
The ALab and Moana runs with the index walk matched their baselines' images but not their reports: warnings inside prototypes named /__Prototype_83 for _82, _1 for _0. openusd numbers a stage's prototypes in the order they are first asked for, and the scene index's population walk asks in another order than the direct walk did; a streamed import numbers each chunk's stage from 0, so the number cannot be mapped between imports. The digest comparison, the sample report test and import_parity.sh write the digit run as `#` and compare the rest of the path. The import-parity spec lists the exception and its reason. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PUSvMHN9Akk66u2oG3rUbF
settings.rs reads the payload-free scene input instead of the index stage: the settings prim by its Hydra type, renderSettingsPrimPath from the root's __usdStageMetadata, the pass's renderSource and the camera and crust:dicingCamera targets from __usdRelationships, and every attribute (resolution, renderingColorSpace, the crust:* settings) from __usdAttributes with the direct readers' authored-versus-fallback rule (index/data.rs, PrimData). read_index, the live settings refresh and `crust ls` hand it a scene input over their index stage. The USD type named in a bad --pass error is read from the stage (stage_facts), since the index carries Hydra types only. Parity green (tasks 3.5, 4.1). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PUSvMHN9Akk66u2oG3rUbF
…ndex products.rs reads the settings prim, its products and vars from the scene input: Hydra types for RenderSettings, RenderProduct and RenderVar, forwarded `products` and `orderedVars` targets and every attribute from the generic data, with Crust's own product-over-settings resolution and its warnings kept. The precomp reads its settings relationships and the display filters' inputs from the index; shader ids, kernel assets and sample-filter graphs are shading networks and move with the materials. The design records which data an index reader takes. Parity green (task 4.2). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PUSvMHN9Akk66u2oG3rUbF
matte and cameraVisibility are read (one holdout, one prim hidden from the camera); prune and renderVisibility each warn once. Baselines recorded from the direct importer (36537fe). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PUSvMHN9Akk66u2oG3rUbF
The pass's collection opinions come from the generic data (prune and renderVisibility for the warning that they are not read), and membership of matte and cameraVisibility is judged by the chunk's StageSceneIndex (its CollectionMembership, openusd's query with expressions and predicates), on the chunk being walked as before. Instances are found by __usdPrimInfo/niPrototypePath. The walk hands the pass the input it walks. Parity green (task 4.3). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PUSvMHN9Akk66u2oG3rUbF
camera.rs reads the camera prim by its Hydra type and every attribute (projection, apertures and offsets, focal length, fStop and focus, clipping, shutter, exposure) from the generic data, and metersPerUnit with its authored-ness from the root's __usdStageMetadata (Moho's M3). The walk, the read ahead of the traversal (on the scene input, or an input over a stage masked to the camera), the first-camera search (now a walk of the scene index), the live settings refresh and `crust ls` all read through an index. The world transform still composes through the bridge until the transforms move (5.1). Parity green (task 4.4). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PUSvMHN9Akk66u2oG3rUbF
…the index) The settings-and-camera rebuild in live.rs goes through read_index with a scene input over its index stage and builds the camera through an input over the stage masked to it, so it reads what the import reads; live.rs tests pass with the in-place versus re-import checks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PUSvMHN9Akk66u2oG3rUbF
materialx_lion, materialx_teapot and materialx_showcase reference MaterialXTeapotLion-1.0, which is not committed: their check digests and images are recorded from the direct importer (36537fe) where the files exist, and compared there (CI skips them, as the sample test lists). The sample report test joins the image run's expected failures: the second import doubles the textures its report counts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PUSvMHN9Akk66u2oG3rUbF
…ndex Every mesh read takes the prim's generic data (PrimData, in the index being walked, kept on the caches for readers reached through the bridge, like a prototype's parts): points, counts, indices, holes, the scheme, orientation, boundary and face-varying rules (typed reads with their schema fallbacks), creases and corners, normals and primvars with their indices, interpolation, elementSize, type name and colour space (the attribute's colorSpace, then colorSpace:name up the index's ancestors), crust:subdivisionLevel, the displacement bounds, crust:rayMask and crust:motion:translate. Implicit shapes are told by their Hydra type (Cylinder_1 and Capsule_1 by the radiusBottom their schema declares) and read their sizes the same way; a sphere its radius. The live mesh and sphere rebuilds read through an index of their stage. `crust ls` keeps a type-only test of the shapes. Parity green on every digest and image (tasks 6.1-6.4, 7.1, 7.2). The image script now matches only the parity check's own panics. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PUSvMHN9Akk66u2oG3rUbF
curve_segments and nurbs_curve_segments read points, counts, widths, type, basis, order, knots, point weights and ranges from the prim's generic data, and the strand table its primvars (values, indices, interpolation, type name, colour space up the index's ancestors) and the reserved primvars:curve: names. Curves in a prototype read through the walk's index too. Parity green on every digest and on the image run (task 8.1). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PUSvMHN9Akk66u2oG3rUbF
The volume dispatch and emit_volume read the region's type, noise, grid, coefficients (colours converted from the space the attribute names, up the index's ancestors), anisotropy, density scale and size from the prim's generic data, in the walk and in a prototype's warning. The material's volume terminal moves with the material networks. Parity green (part of task 11.1). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PUSvMHN9Akk66u2oG3rUbF
Moana's coral shape: a point instancer whose prototypes are prims inside a native instance, so each target is an instance proxy. Its baseline is the direct importer's. Moho copies such a target as an empty prim until M12 (Moho PR #14), so the test is should_panic on the parity check until the Moho rev that carries it; M12 is listed in the design's open gaps, and Moana's 12.4 run waits for it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PUSvMHN9Akk66u2oG3rUbF
ALab's report was re-recorded for the reuse alone (unique triangles 12,007,504 to 12,001,706) and the direct importer's EXR kept; the import_parity check passes, report and image equal. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PUSvMHN9Akk66u2oG3rUbF
…ances) Moho now copies a point-instancer target that is an instance proxy from the instance's propagated prototype. Crust already takes copies from instancerTopology/prototypes, so it needs no change: the M12 fixture passes, digest and image equal to the direct importer's, and M12 is recorded closed in the design. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PUSvMHN9Akk66u2oG3rUbF
A copy of a prim inside a native instance binds a material beside its target, which the index holds in the instance's propagated prototype, outside the copy. The copy now carries the instance (the target's nearest ancestor the instancing chain holds as an instance, found at the target as the chain holds it), so the material is read there and named under the instance, as the direct importer named it through the proxy. Moana's isCoral raised 29 material.fallback_default without it. Two fixtures, recorded from the direct importer, cover a top-level and an instanced instancer; both match their digests and images. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PUSvMHN9Akk66u2oG3rUbF
cargo test --release (parity_images.sh) leaves a test build at target/release/crust, with crust-core's test-only parity feature, which digests and checks every import: a Moana check measured that build. The script now builds crust-render first unless BIN names a binary. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PUSvMHN9Akk66u2oG3rUbF
EvalTimeScope and time.rs go: every stage read takes its time code explicitly (the camera readers, stage_local_to_world, and crust ls's value reads at its frame), and the index readers take the index's time. The prototype and material caches are keyed by Moho's propagated paths alone: ImportCaches::epoch and MaterialCache::epoch go, since no root the instancing chain holds is a per-stage /__Prototype_N (probed across the suite before removing it). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PUSvMHN9Akk66u2oG3rUbF
The import reads openusd only through index/ and stage_facts.rs: the stage binding resolution, shader ids, attribute value reads, the stage pruning rule and the shape test, which only crust ls (walking the stage) still calls, move into listing.rs; Prune keeps the rule's documentation. prim_frames' authored ops (Xformable, xformOpOrder, the place op's default) are authoring facts, read in stage_facts::authored_ops (D7). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PUSvMHN9Akk66u2oG3rUbF
The import keeps no time in a thread-local (the index owns it, stage reads take it explicitly), and prototype caches key on Moho's propagated paths, never on openusd's per-stage /__Prototype_N. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PUSvMHN9Akk66u2oG3rUbF
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PUSvMHN9Akk66u2oG3rUbF
As import_parity.sh: a test build left at target/release/crust carries crust-core's test-only parity feature. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PUSvMHN9Akk66u2oG3rUbF
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PUSvMHN9Akk66u2oG3rUbF
ALab and Moana pass import_parity on Moho d09cc94, their reports re-recorded for D3c's cross-instancer reuse alone, with the spike's (A), (B) and (D) beside them; Moana's import time (12x) is reported. check_images is bit-identical against the direct importer's goldens (cornellbox_guided's re-rendered, guided rendering being nondeterministic), and crust diagnostic equals its report timings aside. hdCrust cannot pass on this machine's glibc, before or after the change alike; 14.1 stays open for the CI runner. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PUSvMHN9Akk66u2oG3rUbF
…5.2) Moho in the crate map and the render flow, the index/ module, two new invariants (a family's index reader and its in-place rebuild change together; one openusd through Moho, one rev across the stack), the epoch and EvalTimeScope rules gone; usd_import's module table names each family's index reader, and stale doc links are fixed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PUSvMHN9Akk66u2oG3rUbF
…ho (15.1) The layout, the walk, the stage facts, the bridge's history and the rev rule; the behaviour changes and the listed exceptions; Moho's gaps M1 to M12 with what Crust uses from each and the rev that closed it; the streaming and cache-keying paragraphs rewritten for the index. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PUSvMHN9Akk66u2oG3rUbF
Crust reads every stage through Moho's scene index and streams a large stage one subtree at a time; the overview names Moho beside openusd. zola build passes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PUSvMHN9Akk66u2oG3rUbF
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PUSvMHN9Akk66u2oG3rUbF
…oader On a host whose glibc is older than the OpenUSD package needs (anderslanglands/aswf-pixi#57) the delegate runs only through the pixi sysroot's loader and so its libm, and a host crust differs from it by an ulp on a few pixels. crust_sysroot.sh runs the release crust under that same loader; the pixi tasks compare-sysroot and interaction-sysroot point the scripts' CRUST (now overridable) at it. CI runs the scripts unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PUSvMHN9Akk66u2oG3rUbF
The Hydra workflow passes on the reference runner at 58b1a25, and locally with the CLI under the sysroot loader; ALab and Moana pass import_parity on the final code, their runs recorded. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PUSvMHN9Akk66u2oG3rUbF
PR Summary by QodoRead USD scenes through Moho's scene index
AI Description
Diagram
High-Level Assessment
Files changed (45)
|
Code Review by Qodo
1.
|
… assets are absent materialx_lion, _teapot and _showcase reference the DPEL MaterialX assets by absolute path, outside the repository (not committed). Where those files exist the sample is compared against its recorded baseline as before; where they do not (CI), the composed layers differ, no baseline matches, and the test now skips it with the paths it needs, as crust-render's import_parity.rs already does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PUSvMHN9Akk66u2oG3rUbF
… failed build Review of PR #415 (Qodo): a test listed in parity_images.expected had all of its failures excused, so a listed test (the sample report test among them) could hide a baseline mismatch; and a build error or a test binary dying before its summary left no FAILED line and passed. Now every parity: diagnostic fails the run, whichever test or crust process raised it, but an image difference of a stage listed as stage:<file> (cornellbox_guided.usda, nondeterministic guided render; its digest is still compared); a listed test's failure is excused, its import differences are not; a build error, a test target with no result, or cargo failing without a failed test fails the run. every_sample_imports_as_its_baseline is no longer listed: in the image run it still runs every sample's check (digest and image compared in the crust process) and only skips the report comparison. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PUSvMHN9Akk66u2oG3rUbF
Review of PR #415 (Qodo): the index readers anchored an asset value openusd had not resolved on the root layer's directory, where the direct importer used the attribute's authoring layer. openusd anchors an asset value on its layer and records where it resolves even with no file there (a UDIM set, a missing texture), so asset-typed paths were right; a path authored as a string was not. asset_value_path now takes the authoring layer's directory, read in stage_facts (authoring_layer_dir, following an interface connection), at every call site: UsdUVTexture and Pxr Ptex files, MaterialX filenames, the precomp kernel, IES, rect and dome light textures. tests/asset_anchoring.rs (recorded from the direct importer): assets in a referenced layer two directories below the root, a UDIM set, a missing file, a MaterialX filename and a light texture, and a string-typed texture path, which failed before this change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PUSvMHN9Akk66u2oG3rUbF
|
Replies to the Qodo review (comment 6444723949). Each finding was verified against the code first. 1. A sample import mismatch can pass the image gate: real, fixed in ab55f84.
2. Referenced-layer textures load from the wrong directory: real for string-typed paths, fixed in b5ee1de. Details are in the reply on the inline comment. 3. The parity image run passes when the build fails: real, fixed in ab55f84.
I checked the script against synthetic logs:
The real run ( Also on this branch, f58c950 fixes the CI 🤖 Generated with Claude Code |
… failed build Review of PR #415 (Qodo): a test listed in parity_images.expected had all of its failures excused, so a listed test (the sample report test among them) could hide a baseline mismatch; and a build error or a test binary dying before its summary left no FAILED line and passed. Now every parity: diagnostic fails the run, whichever test or crust process raised it, but an image difference of a stage listed as stage:<file> (cornellbox_guided.usda, nondeterministic guided render; its digest is still compared); a listed test's failure is excused, its import differences are not; a build error, a test target with no result, or cargo failing without a failed test fails the run. every_sample_imports_as_its_baseline is no longer listed: in the image run it still runs every sample's check (digest and image compared in the crust process) and only skips the report comparison. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PUSvMHN9Akk66u2oG3rUbF
The import through Moho is merged (#415): archive the change and sync its delta specs, creating the scene-index-import and import-parity specs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PUSvMHN9Akk66u2oG3rUbF
Summary
Step S2 of Mantle's
scene-indexprogram. Crust's USD import now reads the stage through Moho, a Hydra 2.0-style scene index over openusd. The directusd::Primimporter is removed: there is one route and no switch. An IPR frame andcrust render -iread a scene the same way, and later live updates can work from Moho's dirty locators.Reading through Moho. Every schema family reads Hydra prims, schemas and generic attribute data from a Moho index:
A small stage uses one standard chain. A streamed stage uses masked chunk inputs merged with a payload-free scene input.
Gated on parity. Each family moved on its own, gated by baselines recorded from the direct importer before anything moved:
crust check --jsonreport and a 16 spp image hash;Behaviour changes and accepted exceptions are listed in the design record (
openspec/specs/usd-scene-import/design.md). They include:openusd comes only through Moho (
moho::openusd,moho::openusd_schemas), so Moho's pin is the stack's openusd rev. Moho is pinned atd09cc946.Removed: the epoch and
EvalTimeScope. Stage listing helpers moved tolisting.rs, and authored transform ops tostage_facts.hdCrust on hosts with glibc older than 2.38.
hydra/hdCrust/test/crust_sysroot.shand the pixi taskscompare-sysrootandinteraction-sysrootrun the CLI under the pixi sysroot's glibc. Then both sides of the comparison use the samelibm. The underlying package issue is openusd 26.08 (linux-64) needs glibc 2.38 but its metadata allows any glibc anderslanglands/aswf-pixi#57.Capability
usd-scene-import. The change isopenspec/changes/moho-import/(53/53 tasks, validates with--strict). Also updated:docs/architecture.md: Moho in the crate map and render flow, theindex/module, and two invariants (an index reader changes together with its in-place rebuild; one openusd, through Moho);docs/architecture/usd-import.md.Image impact
scripts/check_images.shreports all 48 scenes identical.cornellbox_guidedgolden was an outlier of the nondeterministic guided render. It was re-rendered with the direct importer: 4 direct and 6 index renders agree.Performance
Reported, not gated. These are not
bench_ab.shA/B runs: they come from the parity runs, each alone on the machine.Most of Moana's slowdown is in Moho's read path. The Moho streaming spike shows a similar gap: strategy D (reading through Moho) takes 7.7x as long as strategy B. Part of it is in Crust: materials missing from the top index build a fresh chain, 39 times on isHibiscus alone. With full LTO, cornellbox renders about 2.5% slower than the direct binary, with no render code changed and equal digests; this is unexplained and recorded.
These are follow-ups. Moho is moving to strict Hydra parity next (one loaded stage, no chunk streaming), and update latency will be profiled before first-load time.
Checklist
cargo fmt --all -- --check(locally)cargo clippy --workspace --all-targets -- -D warnings(locally)cargo test --workspace --no-fail-fast(locally). The GitHub Rust workflow runs on this PR.docs/architecture.md§ Invariants changed together (index reader ↔ in-place rebuild, added here)unsafe, no new RNG outsideopenqmc, no asset decoding incrust-coresite/updated (docs/architecture/usd-import.md; zola build OK)CRUST_*switch: none addedHydra workflow (hdCrust, OpenUSD 26) passed on this branch at
58b1a25a: https://github.com/doubleailes/Crust/actions/runs/40494072921🤖 Generated with Claude Code
https://claude.ai/code/session_01PUSvMHN9Akk66u2oG3rUbF