22 KiB
M2 Content Workspace Native Evaluation
Evidence record — not current product guidance. Use the documentation index for current behavior and architecture.
Date: 2026-07-14
Milestone: M2 - Content workspace and asset pipeline
Epic: Gitea #59
Base commit: 931f561e7ff1489f897e22ebb3cc7545fcfef702
Implementation revision: Candidate tree passed all gates; exact commit assigned at publication
Release-candidate commit: Pending publication commit
Native interaction acceptance: Pass for the recorded content workflows; current Inspector UI acceptance remains in progress
Pinned Penpot acceptance targets: export index
Current UI comparison record: UI gallery delta matrix
This feature-level record covers the Content Browser interaction pass added during M2 completion. It does not close the milestone or replace the exact-commit, clean-checkout, import/reimport, forward/Solari, packaging, and independent signoff gates in the M2 plan.
Native Protocol
The normal debug editor was rebuilt with cargo build -p editor --bin editor, launched as
LD_LIBRARY_PATH=target/debug/deps target/debug/editor --project ., and exercised in native
Wayland windows at 3426x1384 and 1440x3440. The project stayed live throughout each workflow and
was stopped without saving the temporary placement scene.
| Workflow | Result | Evidence |
|---|---|---|
| Managed storage visibility | Pass | assets/.index, .trash, .thumbnails, .import-cache, and generated artifact directories were absent from the tree and content grid; ordinary content folders remained visible. |
| Empty workspace context | Pass | Right-clicking visible unused content space cleared the selected model and opened Import Here, PBR grouping, Create Material Here, New Folder, Open Trash, Paste, Undo, Select All, Refresh, and view actions. |
| Multi-selection | Pass | Ctrl-click selected assets/build_profiles and assets/levels together; both tiles, the two-item footer, and the multi-selection Details summary stayed synchronized. |
| Batch context menu | Pass | Right-clicking one selected folder preserved both selections and exposed Cut, Copy, Duplicate, and Move Selection To Trash. |
| Item context menu | Pass | Right-clicking the Poly Haven desk model selected it and exposed model actions plus Rename, Cut, Copy, Duplicate, and Move To Trash. |
| Details resizing | Pass | Dragging the Content Browser divider expanded the Details pane; its hover affordance described drag resize and double-click reset. |
| Background/item priority | Pass | The workspace background menu remained available without intercepting folder/model clicks or Ctrl multi-selection. |
| Destination-first bundled import | Pass | Created assets/Props/Office/ through reviewed folder transactions, chose Import Here from genuinely empty space, and imported the Poly Haven metal_office_desk_2k.gltf directly there with its .bin and three relative textures. No type-specific routing occurred. |
| Import To and final-path review | Pass | Chose assets/Furniture/Office without navigating away from the root browser view, opened the native picker, selected /tmp/m2-live.png, and confirmed the second review showed the pinned destination plus exact assets/Furniture/Office/m2-live.png target. Cancel closed the review and a filesystem assertion confirmed that no target was published. |
| Destination-first skeletal import and placement | Pass | Chose Import Here in assets/Furniture/Office/, imported blacksite-m2-robot-expressive.glb directly there, inspected its stable draw-slot IDs, and placed it as a live SkinnedMesh actor with its skeleton hierarchy intact. Registry ID 5b4640dd-fc17-4703-b9ea-e4eb49a8c7fc and both generated manifests survived the final headless refresh. |
| Editable material extraction | Pass | The review exposed the converted metallic/roughness values, base/normal/packed texture channels, double-sided state, destination path, and stable source provenance before one transactional publication. |
| Re-extraction diff/apply safety | Pass after corrective implementation | Native review found the provenance-matched Material, exposed a source-revision diff, and kept Extract disabled until Apply Reviewed Update or Create New Copy was chosen. Apply preserved Material ID 647a63d4-64c6-4431-ba46-9efdd515cd8f, mapped all eight active slots, and Undo Content restored the exact prior Material bytes. Pipeline tests additionally prove external-edit rejection and exact-byte rollback when dependent publication fails; editor tests prove undecided and stale reviews cannot publish. |
| Extract-and-map contract | Pass after corrective implementation | Native QA found that extraction initially created the Material without changing model defaults. The transaction now registers the Material and maps all nine draw-slot IDs using source material 0 before publishing either registry document; the generated static-mesh manifest contains the same nine Project(...) selections. |
| Guarded create/write undo | Pass | Undo Content moved the first extracted Material into one Trash batch while leaving the model bundle untouched. The corrected extraction was then rerun against the same fixture. |
| Forward/Solari DefaultGrid visibility | Pass | The scene's UV-independent neutral grid remained visible in Lit / Forward and after applying GiMode::Solari in memory; assets/project.ron remained configured as Forward. |
| Broken project fallback safety | Pass | Selected new_material_2 as the project fallback, moved that Material to Trash through the reviewed transaction, and confirmed affected primitives and the placed skinned model remained visible with DefaultGrid. Undo restored the Material; the project fallback was then cleared back to the built-in default. |
| Skinned scene-slot override | Pass | The Inspector exposed every imported draw slot and its stable ID. Assigning new_material_2 to the first slot changed only that scene slot to an explicit project Material while the remaining slots continued to report imported-source fallback. |
| Restart persistence and deterministic refresh | Pass | After a clean close/restart, the registry, runtime catalog, generated static-mesh manifest, and extracted Material retained identical SHA-256 hashes. Registry and manifest each retained nine project slot selections. |
| Editor/headless classification parity | Pass after corrective implementation | process-assets --check found that browser sync had collapsed a schema-classified Material Instance back to Material. Browser registry sync now reclassifies the authored file while retaining the unified visible Material family. A steady-state editor restart preserved both document hashes and the following headless check reported zero changes. |
| Reimport and orphan reconciliation | Pass after corrective implementation | Removing source node 8 from the QA glTF and choosing Reimport retained eight active Project(...) mappings by stable slot ID and exposed the removed mapping as one explicit orphan. Locate selected its extracted Material; Clear Orphan plus Apply published eight active mappings and zero orphans to registry and runtime manifests. The source bundle under source_assets/ was not modified. |
| Move/rename stable identity | Pass after corrective implementation | A reviewed Cut/Paste moved assets/Props/Office/ to assets/Furniture/Office/ while preserving model ID 36c51ff3-29ae-4ab1-aaca-f90f57e27966 and Material ID 647a63d4-64c6-4431-ba46-9efdd515cd8f. Native QA found stale nested MaterialRef.source_path caches on the first attempt; guarded Undo restored the prior bytes, the transaction rewrite was corrected, and the repeated move updated registry, catalog, both model manifests, Material provenance, and texture paths. Reimport at the destination retained all eight mappings. |
| Duplicate identity and internal references | Pass after corrective implementation | Native Duplicate assigned fresh IDs to the copied model, Material, and textures; every copied model slot referenced the copied Material and folder, while the original records remained unchanged. Copied models discarded inherited manifest paths and the watcher regenerated static/animation manifests under the copied model ID. |
| Duplicate guarded undo and derived cleanup | Pass after corrective implementation | Native Undo initially exposed orphan generated manifests after removing the copied tree. Trash manifest schema v2 now includes model static/animation artifacts. Rebuilt native Duplicate -> Undo moved the copy plus both generated manifests into one restorable Trash batch, removed copied registry/catalog records, and preserved the original tree and artifacts. |
Automated and Packaged Acceptance
The same local implementation passed the complete workspace/all-feature test suite, strict
all-target/all-feature Clippy with warnings denied, formatting, both project validators, and a
steady-state headless content check over 78 discovered assets. validate-levels audited 152
dependencies with zero blockers; validate-samples audited all five samples and 157 dependencies
with zero blockers. Both validators reported the expected eight non-blocking import/platform
findings. The final process-assets --check reported zero registry, catalog, model, texture, or
material-artifact changes. The QA package published 125 runtime files (87 written and 38 reused)
with no stale packaged files.
Focused Content Browser regressions also cover guarded undo for created folders and copied content: an unchanged created result is targeted as one restorable Trash batch, while any external tree change blocks the undo and preserves the workspace. Ordinary Move to Trash records its exact batch for guarded Ctrl/Cmd+Z restoration as well. Model trash/restore additionally verifies byte-exact static/animation manifest removal and restoration, and copy coverage verifies fresh IDs plus internal-only reference remapping.
The final transaction audit adds focused coverage for exact browser/scene status restoration when a content review is cancelled, stale-drag cleanup, registry/runtime-catalog drift refusal during an import review, and reviewed-import rollback that removes newly published bytes without deleting an in-project adopted asset. Destructive reference discovery reports external authored documents, project defaults, model mappings, and dependency records while excluding references removed in the same selected tree. Ambiguous out-of-editor fingerprint moves now leave registry/manifests unchanged and open an explicit identity-repair review in the editor; the user can preserve one candidate ID or intentionally register the file as new. Headless processing reports both candidate paths until that choice is published instead of silently allocating a replacement ID. Focused repair coverage proves preserved-ID continuity through the next shared scan, intentional new-ID behavior, duplicate-ID rejection, and one commit that publishes the world registry, registry file, and stripped runtime catalog together. Content shortcuts are also suppressed while a browser review or popup owns input, and Cut/Paste keeps the requested name so collisions reach review. The follow-up QoL audit made right-click targeting consistent for files, folders, and embedded subassets; distinguishes nested selections covered by a selected parent from genuinely unaffected built-ins/subassets; and clears selection when search/scope/type filters would hide it. Browser controls are disabled behind reviews. Startup, manual Refresh, and watcher processing now share the same pipeline, rediscover unresolved move repairs after restart, and selection-only changes no longer trigger whole-catalog fingerprint or registry work. A rebuilt native editor then mapped successfully on the live Wayland session with the shared startup refresh active. The Details drag strip now uses one stable explicit egui ID across layout passes; a final bounded launch produced no resize-handle ID warning, and the following headless check again reported zero content changes.
The architecture audit also moved destination-first import planning/publication, source
fingerprints, static-mesh normalization, animation normalization, and combined model-artifact
publication into content_pipeline. The process-assets feature's dependency tree no longer
contains the editor crate; the editor retains compatibility re-exports for its UI consumers.
The extraction correction adds focused coverage for dependent registry edits that can see newly registered asset IDs, byte-restoring rollback when that dependent edit fails, and source-index mapping across every draw slot that uses an extracted source material. Re-extraction coverage also requires an explicit decision for provenance matches, rejects stale external edits, preserves the existing asset ID on Apply, and restores exact prior bytes if dependent publication fails.
Property-block coverage verifies owner/slot-local Standard handles, stable handle counts across repeated application, strongest precedence above an existing Material Instance on the Surface path, and whole-block rejection for invalid Standard/schema/type/range/texture input. Invalid blocks leave the resolved base handle visible and emit one deduplicated diagnostic.
The reviewed promotion transaction has focused coverage for a direct Material and an existing Material Instance base, exact-slot assignment, one scene-history edit, cancel without mutation, source/slot/schema/block/target conflicts after review, invalid runtime input, and restoration of the exact prior file, registry, and runtime-catalog bytes when the scene edit fails. The import review likewise has focused coverage for non-mutating planning, collision refusal, post-review source/registry/runtime-catalog changes, complete textual-glTF dependency fingerprints, artifact processing failure with whole-bundle rollback, adopted-file preservation, and an explicitly pinned Import To destination that does not change the visible browser location.
The final native promotion scenario used the editor-only BRP reflection boundary to inject a
two-parameter MaterialPropertyBlock into Ground's exact slot:primitive:surface. The Inspector
reviewed and published one sparse direct-base Material Instance, assigned it to only that primitive
slot through one history edit, and removed the runtime block only after publication succeeded.
BRP readback proved the exact Material Instance reference and absence of the runtime component;
Undo restored the original Pebble Bricks slot. The temporary instance, registry, catalog, scene,
and Pebble fixture were then restored to their pre-scenario bytes. Runtime blocks remain absent
from Add Component and scene/prefab persistence; no QA-only authoring component was added.
The final moved/reimported QA fixture hashes were:
- registry:
e1eb425c2d52be06d7db840df1f14f1d3a96daf2c1876dfc025d861bf0d32b74 - runtime catalog:
cc296049b656d52e3159cca2e11f52bc4bdef0c922fb0dc00fa5d33f4e3748e7 - desk static-mesh manifest:
6c69a9f9502fce36cb88e82a7e2e2074e6279ca6da4d49e3e36c1ede35c0577f - desk animation manifest:
8a0632bd8b6ea4a5d117214ea168f4020f9399c92bb9da3d7cba1ad371b9e4e8 - extracted desk Material:
70e498f596d37da5735f5e0d0b1f3834442cd1aefa698232a640fec9d9e422f3 - skeletal static-mesh manifest:
ee9168b123d89ff57b312a35e54a3a8d5bf5b9dae3ed98e79c7bc24dcb6d6454 - skeletal animation manifest:
7c14b6ad016db5c09af7f56f50492a05f9bdd89b1bb672e9886bc9a3447e2130
The latest 2026-07-14 rerun of cargo package-project --profile development wrote zero changed
files and reused 74 unchanged files. The packaged
assets/content.catalog.ron was byte-identical to the source runtime catalog with SHA-256
cc296049b656d52e3159cca2e11f52bc4bdef0c922fb0dc00fa5d33f4e3748e7. A bounded native package
launch hydrated the authored scene and visibly rendered the world-space DefaultGrid across UV-less
primitives and the floor. The corrective binary also mapped a live 3426x1384 Hyprland window as
class bevy-fps-foundation, title Bevy FPS Foundation, before the bounded QA process stopped.
Screenshot Captures
The native PNGs are retained locally pending upload as Gitea issue attachments. Repository image copies are intentionally not required by the evaluation policy.
| Capture | Dimensions | SHA-256 |
|---|---|---|
blacksite-m2-managed-hidden.png |
3426x1384 RGB PNG | 97bb710d569039b54218a556865f366cff3bda2ae6ce3afe4a1933db8e58c36b |
blacksite-m2-empty-clears-selection.png |
3426x1384 RGB PNG | e162c865202717cf36eec7a37c3f95a4cc4c3c55dcc5d48243b00fe47be0d136 |
blacksite-m2-multiselect-fixed-2.png |
3426x1384 RGB PNG | 729ae5d2b10ca2d8acdd249f19c35f5e6f3a57d9dbb9550f80c371b703336868 |
blacksite-m2-multiselect-context.png |
3426x1384 RGB PNG | 88232360d592a1e4436e86a17fe1356ea10d7766cfbdb98eb6323767cbc16fe6 |
blacksite-m2-item-context.png |
3426x1384 RGB PNG | 6f01f23ea7ad65dffecd0d0e51e57b6a1fcf26cf06cfe6f536f8376557a6649b |
blacksite-m2-details-resized.png |
3426x1384 RGB PNG | 407ee7779367f83ca2a9c5d6f4a5803584609e319d881265f9544b194fbd0296 |
blacksite-m2-office-empty-context.png |
3426x1384 RGB PNG | a4004292f70b8a07f6c0d24e8bc47c1716e7de33b4b627a67c4198afe76a00a3 |
blacksite-m2-imported-model-details.png |
3426x1384 RGB PNG | cf68b41293b823945fdd17e9752d3733f8d38144504f5fdbfd9be7f793ce0205 |
blacksite-m2-extraction-review.png |
3426x1384 RGB PNG | f4d567d3353536ca1492d48fe59f72ff5b3e4b37c095ef27eaed51347c6a67ec |
blacksite-m2-extraction-transaction.png |
3426x1384 RGB PNG | 99944392580a88ec14868dbf5a422bacc89ca3b8d8d0750311f429e65250aef6 |
blacksite-m2-details-wide-mapped.png |
3426x1384 RGB PNG | 6aee075b4006909cde1625d5afd42a8be93b9323de93156bd8a55d27ef07e678 |
blacksite-m2-defaultgrid-solari.png |
3426x1384 RGB PNG | 9f23685f6354029ce772878a3f080c7efb045ccc73fce6c19f8fe7802e378ee8 |
blacksite-m2-orphan-controls.png |
3426x1384 RGB PNG | afe8f07d92c00ac1294b021682a66ea623b3c22158598119d2617f2e0b1dae72 |
blacksite-m2-orphan-locate.png |
3426x1384 RGB PNG | d7c841747e1a712da80537846699baa8b2f83f91a65ddc298d1d3e665f2e74b7 |
blacksite-m2-orphan-applied.png |
3426x1384 RGB PNG | c979981fba5b30692c3f858fd349b582bb204b5720702bd684f3721ed5a76350 |
blacksite-m2-root-empty-context.png |
3426x1384 RGB PNG | 960231dc8661f7b012abf7ddf0cc97ce42548e789e911895e12b8b800b29153d |
blacksite-m2-office-move-review-fixed.png |
3426x1384 RGB PNG | aaa06af27049858f2c691b9c251197a19a5330919048b59b2c313d06d2bf4471 |
blacksite-m2-office-moved-fixed.png |
3426x1384 RGB PNG | 0cfdd6206d56355583c55e483959c8c154223acf5142015f9f2329da54baf5ca |
blacksite-m2-moved-model-reimported.png |
3426x1384 RGB PNG | a6420434c25f72af94f1f4bdb22c8686bd840aad5fe114c192bdefc6db020aec |
blacksite-m2-duplicate-review.png |
3426x1384 RGB PNG | f0fae051ca8c807540779de662a5381b3e9f1ac3faaf1cd5412bb7f1cb2835b0 |
blacksite-m2-duplicate-committed.png |
3426x1384 RGB PNG | 3e3b0fd38f0374c47598307d93f5238028d269753742f4b296536f0fe886c1a5 |
blacksite-m2-duplicate-undo-clean-editor.png |
3426x1384 RGB PNG | 45aaa55e2069de66d9eb86f4157fd143d92afa2de07aaefb0bb2cc960958401a |
blacksite-m2-packaged-live-window.png |
3426x1384 RGB PNG | de8c19b2dbc2b488e290b5e4d1bd3e1c279388374a81e25a5684dd2454f58ee2 |
blacksite-m2-reextract-modal.png |
1440x3440 RGB PNG | b7139a3b6da88755be1c53ef9921450449f207a3082248efd8199bd8abdea515 |
blacksite-m2-reextract-selected.png |
1440x3440 RGB PNG | bd22912ff3d2e4bfdab6469909344a0b0e94f8309665ad876e98e43fe7c80563 |
blacksite-m2-reextract-applied.png |
1440x3440 RGB PNG | 007164ae995c64f048aac638e20664fc173769945691afc3e6a0a6fbf4704380 |
blacksite-m2-reextract-undo.png |
1440x3440 RGB PNG | 3f95eec702d4df6a55d88132c82282311d96d3bca15e2a8ebe11d06ee408461b |
m2-skeletal-import-review.png |
1440x3440 RGB PNG | a08dc1d17848d3089d601c8b31c697c5f22b36dda625baf5fa8f52ee7dad2ea2 |
m2-skeletal-selected.png |
1440x3440 RGB PNG | 2867517356b63a1b7627d5d069e7b45150325065ef247ff20a06c00b53c79581 |
m2-skeletal-placed.png |
1440x3440 RGB PNG | 1936dfcd84d9a6e6cf8f293f71d8a4cb89d1761ad9ee982954ad25682cfd999d |
m2-project-default-selected.png |
1440x3440 RGB PNG | ee3d5385ccd7af1d099a042fb02400e1e193374ca475a28b3d7f55d483d64547 |
m2-project-default-broken-fallback.png |
1440x3440 RGB PNG | 5efb715a619456afcbee808d13f7b4c2cf24bb975f6b69671401bba1fed07ba0 |
m2-inspector-open.png |
1440x3440 RGB PNG | 7ae9d456d0924ab50012ecbefb8e42847ccb141793ce89487c0fd2fbd2b8307e |
m2-skeletal-scene-override.png |
1440x3440 RGB PNG | 3c7ec6fce6a09f9e46402aa64dda77c5508703a11149b30297cee80d9e7907af |
m2-import-to-selected.png |
1440x3440 RGB PNG | d9cb38de6fca185dab6887324163698b2ac036e8f5eb19f16fb65415172f9605 |
m2-import-review.png |
1440x3440 RGB PNG | 631e1ac1d3c63d72d7c930c3b4789584e15a178f03425fd972df82da51dcfa05 |
property-block-promotion-20260717T130300Z.png |
3426x1384 RGB PNG | 69cd668618206b1cee25142521127882cc785031e8e7cd21684c1eab7c97befa |
Remaining Release Use
The complete deterministic candidate gate passes on the local candidate tree. After assigning its exact commit, confirm the clean-tree evidence digest, publish the native/candidate evidence on Gitea, and finish with issue/milestone readback. The local candidate tree covers static and skeletal import, edit/reimport/orphan resolution, broken project fallback, scene-slot precedence, reviewed Import To cancellation, runtime-injected property-block promotion, responsive Penpot material UI, dirty/save/restart behavior, and packaged runtime behavior. Publication readback—not another destructive native content-authoring repetition—is the remaining release use of this record.