Show a bounded native-cache preview before authoritative reconstruction (#463)

Refs #303. file.save / file.save_as can store a warm native geometry cache (cache: true, off by default) keyed to the document hash, app version and adapter revision. Opening shows a bounded preview from it until the rebuilt session replaces it. Any cache failure counts as a miss.
This commit is contained in:
selune authored and GitHub committed 2026-10-13 02:54:01 -04:00
1 parent 1abd989a67
commit 913583bfee
20 files changed
+943 -84

No files matched your search

+5 -2
View File
@@ -47,8 +47,11 @@ Containers deduplicate identical STEP, mesh and image payloads. Mesh coordinates
their original double precision; this is not a conversion to STL. Geometry still rebuilds
from the timeline when opening. When a saved display preview is available, desktop Open
shows it while checking geometry; editing starts after the complete rebuild. Cancelling
keeps the current design. Previews cannot be edited or measured. This experimental option
requires `preview: true` in an engine Save/Save As call; ordinary saves omit display caches.
keeps the current design. Previews cannot be edited or measured. Scripts can opt in to a disposable geometry
cache with `cache: true` on warm saves; saving never rebuilds cold geometry just to
create one. Ordinary saves and browser downloads default to `cache: false`. An additional display-mesh cache remains opt-in
with `preview: true`. Unsupported or mismatched caches are ignored. Browser opening
still rebuilds synchronously.
The repository's `docs/design-container.md` describes limits and encoding details.
Current designs use format 16, including the font of sketch text, sheet metal corner relief shapes, sketch face anchors on cylinder caps, sketch axis
+51 -14
View File
@@ -60,7 +60,7 @@ use the same container reader/writer; JSON export and Save As remain available.
Experimental engine saves with `preview: true` can include `cache/preview.json` and
`cache/preview.bin` when the evaluated
world display meshes are already warm. Ordinary saves omit this redundant display data
to avoid extra save work; it is not the proposed evaluated B-rep cache. Saving never triangulates a cold body for this
to avoid extra save work; it is separate from the native B-rep cache below. Saving never triangulates a cold body for this
cache. Pending occurrence moves, active sketch edits, feature errors and oversized
previews omit it. The cache is bounded to 8 MiB, 1,024 bodies and 100,000 triangles;
its manifest is at most 64 KiB. Body names/colours and contiguous binary mesh slices
@@ -86,9 +86,9 @@ geometry, used for measurements, or used to seed evaluated model state. The orig
design remains intact until the complete rebuilt session is ready. Cancellation or
any change of active document/revision discards both preview and completion.
Normal design reading, CLI and browser opening still rebuild authoritatively; no
evaluated B-rep is deserialized or adopted. Portable evaluated B-rep/state restoration
and interactive cached viewport navigation remain further work in #303.
Normal design reading, CLI and browser opening still rebuild authoritatively.
Native B-rep caches can supply provisional display as described below; they never
supply evaluated session state. The saved picture is not an interactive viewport.
## Seekable reader (phase 2, first increment)
@@ -98,16 +98,51 @@ headers, then `preview()` reads the optional display entries and document metada
`read_document()` consumes the reader and resolves and validates the required
source blobs through the same archive. No complete archive buffer is required.
The existing byte-based readers use this implementation too; JSON keeps its existing
reader. This increment provides the IO API; desktop and browser integration remain
separate. It does not yet change application opening times or saving behavior.
reader. `read_design_file` integrates it with desktop Open using one file handle,
without buffering the complete container. Browser VFS uses a memory cursor.
The source must remain unchanged for the lifetime of the reader. A file handle is
not an immutable snapshot of concurrent in-place writes: application integration
must address that before publishing a cached view. Optional preview success never
validates source blobs or makes a document editable. An invalid required blob still
Metadata used to validate a provisional cache is retained in an immutable buffer
and reused for authoritative reconstruction. Concurrent in-place writes therefore
either retain that document or fail required-part CRC/hash validation. Optional
preview success never validates source blobs or makes a document editable. An invalid required blob still
fails the later document read. ZIP directory scans can touch a bounded suffix of a
stored blob; deferral means not loading or decoding the complete payload, not zero
physical reads of its byte range. Metadata retains the existing part-size budget.
physical reads of its byte range. Optional cache metadata is capped at 16 MiB;
larger metadata misses the cache and uses the normal authoritative part-size budget.
## Native evaluated cache
Engine Save/Save As can include `cache/key.json` and `cache/brep.bin` when
explicitly requested with `cache: true` and geometry is warm. The default is
`cache: false`, including browser downloads, to avoid extra save time and file size.
JSON and recovery/autosave
remain independent of the native cache. Saving never forces cold placement,
evaluation or tessellation. Active sketches, uncaptured moves, errors, mesh bodies,
unsupported adapter representations and exceeded budgets omit the cache.
The manifest records `solidcraft-brep-cache/1`, the package version, the explicit
producer revision `solidcraft-truck-adapter/2`, exact document/payload SHA-256 hashes
and contiguous named body slices. The producer revision is deliberately maintained
when adapter semantics change; it is not a source-tree fingerprint or build script.
The binary data uses [SolidCraft's portable B-rep schema and codec](native-brep.md),
including topology, curves/surfaces, face-source certificates, appearances and
operation history. Truck's serialized structures are never stored. A different
kernel can implement the same schema; until its adapter is tested it conservatively
misses this producer's cache and rebuilds the authoritative document.
Native caches cap 4,096 bodies, 100,000 total faces, a 1 MiB manifest and 64 MiB
binary payload. Individual bodies have the schema/codec's additional limits.
The reader validates metadata, manifest, slices and bodies before requesting a
bounded provisional mesh. Original STEP/image/mesh blobs are resolved afterwards.
No redundant display mesh is stored by default: `preview: true` remains a separate
opt-in for already warm display meshes, which take precedence when present.
Every failure in the optional cache is a miss. Even a checksum-valid forged body
never becomes editable state: Open builds a fresh session from the document and
original blobs, then replaces the provisional picture. Picking, measurements,
persistent names and subsequent modelling use that rebuilt session. Existing
cancellation/document-revision guards also apply. The web build retains synchronous
authoritative rebuilding; portability does not imply background web evaluation.
A counting-reader regression uses a 2.6 MB stored source blob and obtains the saved
preview with fewer than 256 KiB read, then verifies the authoritative document is
@@ -115,9 +150,10 @@ identical after resolving its source. Corrupt-source and preview-miss regression
and truncation/seeded mutations through the combined reader, protect the boundary.
This is an IO-volume test, not a geometry or first-frame benchmark.
## Remaining #303 increments and kernel independence
## Review increments and kernel independence
Keep each increment independently reviewable after the phase-one container PR:
The implementation is split into the following review increments after the
phase-one container PR (#327):
1. Seekable IO and its read-volume/hostile-input tests (the API above).
2. A versioned SolidCraft-owned B-rep schema and bounded binary codec, tested without
@@ -128,7 +164,8 @@ Keep each increment independently reviewable after the phase-one container PR:
No truck serialized structs, memory layouts, pointers or opaque kernel blobs
form part of the persisted contract. No evaluated STEP round trip is a substitute.
3. Separate adapters between the neutral schema and supported kernels. Unsupported
geometry or provenance is a cache miss, never a lossy approximation. A neutral
geometry or provenance is a cache miss. Explicitly fitted intersection splines
carry their fitting target and remain provisional display geometry. A neutral
file schema alone does not prove interoperability: each adapter needs round-trip,
modelling and naming tests; compatibility with a second kernel is unverified
until that adapter exists. Kernel/version information belongs in producer and
+20 -2
View File
@@ -4,7 +4,8 @@ This is SolidCraft's geometry interchange data model in `solidcraft_geom::brep`.
It has no modelling-backend dependency. It is the basis for #303's disposable
native cache; it is not an editable-session snapshot or a STEP replacement for
external interchange. The container reader, binary codec and kernel adapters are
separate layers. The schema is not yet emitted by application saves.
separate layers. Warm application saves can emit it as the optional native cache
described in [the container format](design-container.md#native-evaluated-cache).
## Geometry and topology
@@ -127,7 +128,8 @@ intersection annotation. This approximation is suitable only for the provisional
cache, never authoritative modelling state.
Decoded bodies remain provisional; the application must never use an untrusted
cache as its editable model. Application cache integration is separate. A second
cache as its editable model. Application integration keeps it provisional while
rebuilding the document and original sources. A second
backend needs its own tested adapter before cross-kernel interoperability can be
claimed.
@@ -136,3 +138,19 @@ field names, tags, topology, geometry and metadata. Integer and structural value
are exact; floating coefficients allow 1e-10 relative/absolute platform rounding.
The signature is asserted separately. This protects the wire contract against
accidental runtime-refactor changes.
## Bounded provisional display
`native_preview_mesh` samples at most 32 points along each curved edge, caps each
face's boundary at 4,096 points, and bounds spline controls and nested surfaces
before parameter searches. Searches use at most 16 refinement trials. Revolution
profiles involving procedural intersections are refused in this display path.
The separate mesher uses a fixed grid of at most 16 subdivisions per direction
and fixed periodic-seam connections; it never invokes adaptive edge, surface or
aspect-ratio refinement. Planes use a single grid cell.
Before projection, the caller reserves a conservative triangle bound covering
duplicated projected boundary points, periodic seams and the grid for the complete
body. Output is checked against that reservation and for finite coordinates.
Missing faces or exceeded budgets cause a cache miss. This mesh is approximate,
read-only display; normal modelling/export tessellation is unchanged.
+109 -5
View File
@@ -109,14 +109,14 @@ See [the versioned container format](design-container.md) for layout and bounds.
This phase does not restore evaluated B-reps, skip STEP import, or make cold geometry
rebuilds instant. A matching cache key is not enough to trust unvalidated geometry.
Evaluated B-rep/state restoration remains further work in #303. The provisional saved
display described below is separate from #287's import parallelism.
The native B-rep increment described below supplies provisional display, not editable
session restoration. It is separate from #287's import parallelism.
## Provisional saved display (#303)
## Opt-in mesh preview measurements (#303, phase one)
Desktop Open can show an experimental saved picture while the existing file worker rebuilds geometry.
The phase-one desktop implementation can show an experimental saved picture while the file worker rebuilds geometry.
It requires an explicit `preview: true` engine Save/Save As call. Ordinary saves omit
display caches to avoid the measured overhead; native evaluated B-rep caching remains open.
display meshes to avoid the measured overhead; these measurements predate native B-rep caching.
The cache contains only already warm evaluated display meshes, capped at 8 MiB, 1,024
bodies and 100,000 triangles. Larger or cold models save without it. Cached geometry is
never used for editing, measurements or picking. Source/document fingerprints and
@@ -151,6 +151,110 @@ For actual desktop opening phases, launch with `SOLIDCRAFT_PROFILE_OPEN=1`: `rea
reports saved-picture preparation, while the normal phase log reports reconstruction,
display warmup and thumbnail completion. Neither log measures the exact GPU first frame.
## Native cache opening (#303)
The portable native B-rep cache is opt-in with `cache: true` on warm container
saves, without duplicating display meshes. Ordinary saves and browser downloads
default to `cache: false`: the measurements below do not justify imposing the
additional save time and file size on every design. Desktop Open reads metadata and
optional geometry through a seekable file, produces a bounded provisional picture,
then resolves original sources and reconstructs the complete session before editing.
This improves the opportunity for early display, not the cost of authoritative feature
evaluation. An absent, invalid or incompatible cache uses the original reconstruction.
Browser OPFS/downloads share the format; browser opening still rebuilds synchronously.
The reproducible engine benchmarks separate atomic saving, provisional mesh readiness,
reconstruction and final display-mesh readiness:
```sh
cargo test -p solidcraft-io --profile ci benchmark_step_storage -- --ignored --nocapture --test-threads=1
cargo test -p solidcraft-engine --profile ci benchmark_native_cache_save -- --ignored --nocapture --test-threads=1
cargo test -p solidcraft-engine --profile ci benchmark_native_cache_open -- --ignored --nocapture --test-threads=1
```
Use an absolute `CARGO_TARGET_DIR`. The save benchmark defaults to the generated
512-box STEP document and accepts `SOLIDCRAFT_BENCH_FILE` for another public design.
It alternates nine saves of each encoding, including flush/replacement/backup, and
verifies document identity and native-cache presence. It never times initial fixture
evaluation as save work. Open runs once per process; `SOLIDCRAFT_BENCH_ENCODING`
selects 0=JSON, 1=container without cache, 2=native cache, 3=compact native cache.
Changing only `cache/key.json`'s application version provides a cache-miss control.
Fresh processes do not imply a cold operating-system file cache. The engine callback
time is provisional mesh readiness, not a rendered desktop frame; use the desktop
profile log and actual screenshots to check the saved picture and completed model.
Measured 2026-10-13 on Windows 11, Ryzen AI MAX+ 395 (16 cores/32 threads), `ci`
profile, with the neutral codec revision `75381fa`, envelope `SCBREP03`, producer
`solidcraft-truck-adapter/2`, and opening integration revision `3243422` on upstream `2880525`
(0.6.0). These replace the earlier prototype measurements. They compare encodings
on the same code and do not attribute upstream modelling improvements to the cache.
Runs started after local builds and the complete CI suite finished; ordinary
desktop activity remained. Save values are medians of nine alternating atomic
saves. Open values are medians of five fresh processes per encoding, alternating
forward/reverse order. Memory is each process's peak working set from Windows
`GetProcessMemoryInfo`, sampled every 10 ms, then the median across those five
processes; it excludes a desktop window/GPU.
The original STEP fixture is a 32 by 16 array of 10 mm cubes, 12 mm apart, exported
by SolidCraft: 512 bodies and 6,144 final triangles. Its JSON embeds about 2 MB of
STEP. Every encoding reopens without feature errors and with those same counts.
| STEP encoding | Bytes | Atomic save, ms |
|---|---:|---:|
| JSON | 1,998,826 | 12.616 |
| Container, no cache | 1,950,084 | 10.516 |
| Native cache, fast | 4,694,035 | 47.755 |
| Native cache, compact | 837,067 | 44.015 |
| STEP encoding | Provisional mesh, ms | Reconstructed, ms | Final meshes, ms | Peak working set, MiB |
|---|---:|---:|---:|---:|
| JSON | none | 175.842 | 748.911 | 40.102 |
| Container, no cache | none | 175.885 | 722.306 | 40.504 |
| Native cache, fast | 62.099 | 228.794 | 747.976 | 40.883 |
| Native cache, compact | 65.981 | 235.403 | 762.120 | 40.918 |
| Native cache miss | none | 169.039 | 647.617 | 40.453 |
The public `examples/acceptance/sensor_enclosure.json` script, saved as a JSON
design, has 21 features, two bodies and 4,364 final triangles on this revision.
| Sensor enclosure encoding | Bytes | Atomic save, ms |
|---|---:|---:|
| JSON | 52,281 | 5.243 |
| Container, no cache | 5,545 | 4.969 |
| Native cache, fast | 379,095 | 12.646 |
| Native cache, compact | 72,603 | 14.111 |
| Sensor enclosure encoding | Provisional mesh, ms | Reconstructed, ms | Final meshes, ms | Peak working set, MiB |
|---|---:|---:|---:|---:|
| JSON | none | 3,979.063 | 3,984.593 | 70.438 |
| Container, no cache | none | 4,038.127 | 4,042.006 | 71.789 |
| Native cache, fast | 241.541 | 4,269.124 | 4,274.272 | 70.465 |
| Native cache, compact | 236.739 | 4,271.254 | 4,275.159 | 70.148 |
| Native cache miss | none | 4,136.517 | 4,140.903 | 69.941 |
Native display is available earlier, at the cost of encoding, file size and work
before reconstruction. It does not make the full design editable earlier, and
these results do not establish a memory reduction. Final-mesh readiness varied
from 611 to 856 ms for STEP and 3.84 to 4.60 s for the enclosure; small differences
in full-opening medians should not be read as modelling speedups. Compact storage
reduces this STEP example's size and atomic-save time, but costs slightly more save
time on the enclosure. The default `cache: false` retains the phase-one save path;
`compression: "compact"` is an explicit space/CPU choice. Larger or unsupported
geometry can exceed the documented budgets and reopen without a provisional image.
A separate desktop check used a fresh 0.6.0 application process for each enclosure
encoding, with no local compilation or test suite running. The native cache's
provisional picture was prepared at 429 ms and captured visibly during opening;
the completed model was adopted in 6.48 s. JSON had no provisional picture and
completed in 6.08 s. These are single visual checks, not repeated timing medians;
the worker reported 6.10/5.66 s respectively, and external observations include
UI scheduling and screenshot requests. During native opening, 94 control-channel
inspections had a median round trip of 20.8 ms and a maximum of 106.5 ms (JSON:
95 inspections, 20.3/36.9 ms). The provisional picture is explicitly labelled as
being checked before editing; the final frame shows the rebuilt Case and Lid and
their editable feature timeline. This demonstrates early feedback, not faster
completion of feature evaluation or a worst-case UI-latency guarantee.
## Analytic extrusion source preparation
New-body extrusion certificates now prepare the sketch's bounded analytic segments once