github xiao-villamor/PrintStash v0.15.0
v0.15.0 — faster libraries and native processing

5 hours ago

Back up before upgrading to 0.15.0. Every model file will be re-derived in
the background; a large library on a 4 GB NAS can keep the CPU busy for hours.
DBOS 3.3.0 and application database migrations require restoring the pre-upgrade
backup to roll back.

Release notes: PrintStash 0.15.0

Stop all API and worker processes before upgrading them together. Source
installations require Python 3.14 or newer; Docker images include the runtime.
See 0.15.0 upgrade notes.

  • The Unraid template starts again with the GPU field left blank. Unraid
    passes an empty Device field to Docker as --device='', which stopped every
    install without a GPU before it started. The Intel or AMD GPU is now an
    optional GPU: Intel or AMD (optional) field shown with the main
    settings: enter /dev/dri or leave it blank for the CPU. Existing installs
    that entered /dev/dri in the old field keep working; to switch to the new
    field, update the template, enter /dev/dri there and remove the old
    Device entry.

  • A GPU mapped as /dev/dri is now usable without naming its group. The
    container used to drop every supplementary group when it switched to
    PUID/PGID, including the host's render group and any --group-add, so
    Intel and AMD GPUs were visible but could not be opened and work stayed on
    the CPU. It now runs in the group that owns each /dev/dri node and keeps
    groups granted with --group-add.

  • Thumbnails drawn without a GPU take less CPU: the renderer now tests only
    the pixels each row of a triangle covers instead of its whole bounding box,
    most of which a long thin triangle leaves empty. The thumbnails are
    byte-for-byte the same, so nothing is regenerated.

  • STEP parts in the Docker image get their exact B-rep volume and similarity
    fingerprints again. The image lacked libgl1, which OpenCASCADE's binding
    loads even without a display, so every B-rep read reported STEP as
    unavailable. The image build now fails if that binding cannot load.

  • Thumbnails, measurements and previews of a ZIP's Models now start while the
    rest of the ZIP is still being imported, instead of after its last file. The
    import still shows every Model almost as soon as before, because the derived
    work looks for new Models every two seconds
    (VAULT_JOBS_PACED_DISCOVERY_SECONDS) rather than after each file. Search
    indexing still waits for the import to finish.

  • Importing a ZIP no longer wakes the derivative passes after every file. They
    would only wait for the import to end, so they now stay asleep until it does,
    leaving the database to the import, so large ZIPs import and finish
    processing sooner.

  • A ZIP prepared while the server's clock stepped back (an NTP or virtual
    machine time resync) no longer stays at Queued forever: the Task Center
    now offers Choose files as soon as the preparation ends, whatever time the
    server stamped on it.

  • Administrators choose how many models are processed at once on Settings →
    Background work → Worker settings. Automatic keeps the CPU-and-memory
    default; a chosen count may go up to what the native memory pool fits,
    overrides VAULT_MAX_RENDER_JOBS, and applies without a restart (separate
    worker processes apply it when they restart). Use default clears it.

  • The default number of simultaneous mesh jobs now follows CPUs and memory:
    one per usable CPU plus one, no more than fit the native memory pool, up to
    eight. Two- and three-CPU installs used to process one file at a time and now
    run three or four, so large imports finish in about half the time.
    VAULT_MAX_RENDER_JOBS still overrides it; local AI inference keeps its own
    default of one job per two CPUs unless that variable is set.

  • STEP measurements and previews no longer reserve the whole native memory
    pool. Each part is first admitted under 1 GiB, so STEP files are derived
    alongside other work instead of one at a time; a part that does not fit runs
    once more with the whole pool, and nothing is published twice. A new
    mesh_escalation log and printstash_mesh_escalations_total counter report
    those reruns.

  • STEP files are tessellated at 0.05 mm instead of 0.01 mm, the precision the
    similarity fingerprints already used: about a quarter of the triangles, so
    STEP measurements, previews and viewer models are made roughly four times
    faster in half the memory. Dimensions change by under 0.1% and previews are
    visually unchanged. A STEP whose mesh exceeds the memory allowance is now
    reported as a resource limit rather than an invalid file. Existing STEP
    outputs are re-derived once; other formats are not.

  • 3MF packages are read through lib3mf, the 3MF Consortium's reference
    library, instead of an XML tree: large plates read two to three times faster
    in a fraction of the memory, and packages that ran out of memory before now
    get their dimensions and volume. Coordinates are read in single precision.
    Packages lib3mf cannot read with the same meaning (extensions beyond
    production, mixed units, production parts without a build, geometry far from
    the origin) and arm64 installs keep the XML reader. 3MF memory claims and
    loader ceilings follow the reader that will run, and existing 3MF
    measurements, thumbnails and viewer previews are re-derived once; other mesh
    formats are not.

  • 3MF thumbnails and measurements no longer reserve the whole native memory
    pool. The supervisor bounds each package's placed faces and parsed XML
    without parsing it, so small and medium 3MF files are derived side by side
    instead of one at a time. Fingerprint analysis, packages that cannot be
    bounded, and very large packages keep the whole-pool claim. A new
    mesh_estimate log and printstash_mesh_estimate_duration_seconds histogram
    report each claim.

  • Library Back and Forward keep the same visible reading position when a
    revision notice changes the page height.

  • Refresh library now recovers an initial read rejected by concurrent changes,
    even before the first page has loaded.

  • Ingestion qualification returns idle capacity credits during drain instead of
    depending on the work heartbeat's timing. Active reservations remain protected.

  • PrintStash now keeps a manifest for the Cosmos Cloud market
    (azukaar/cosmos-servapps-official) next to the other store catalogues, with the
    install dialog creating the first administrator and the same memory budgets the
    other stores pass. Nothing changes for existing installations; the store
    submission is a separate step, described in catalogues/README.md.

  • SQLite installations temporarily poll interactive derivative work and its
    discovery passes more frequently after accepting a submission. Duplicate,
    delayed and backfill submissions keep the ordinary polling policy; the
    temporary interval expires after activity stops.

  • The Model filters panel lists G-code below a divider, after the source formats
    it is sliced from, and writes formats as STL, 3MF, OBJ, STEP, DXF and G-code.
    Active-filter chips use the panel's names and values ("File type: G-code",
    "Revision: Needs test"), and material or printer names show as written.

  • An upload into a library folder on a network or automounted share no longer
    fails with storage_root_changed when the share briefly reports a different
    identity while it reconnects. PrintStash re-checks the folder and retries the
    write once; a folder that was really replaced, or that disagrees again, is
    still refused (#210).

  • Bambu LAN printers reporting zero or missing task IDs reuse their external
    print job across status updates instead of adding a row on every tick.
    Repeated completion reports no longer queue duplicate notifications, while
    an observed new run of the same file still creates a separate history row.

  • An idle server uses about half the CPU again: only the ingest lane, where an
    upload or import waits to start, is still polled four times a second
    (VAULT_JOBS_INTERACTIVE_QUEUE_POLL_INTERVAL_SECONDS, 0.25). Derive, network,
    printing and reconcile lanes go back to once a second
    (VAULT_JOBS_QUEUE_POLL_INTERVAL_SECONDS, now 1.0). On a 4-core test server
    with 300 Models, idle CPU fell from 11.4% to 6.1% of one core (0.14.0: 6.1%),
    and uploads start as soon as before.

  • Interactive background work can prepare its next queued job while the
    current job runs, using the existing queue and admission limits.

  • Search projection waits for an import to finish while previews can start
    during the import. Its writes competed with the import for SQLite's single writer. A 300-file ZIP
    import on a 4-core test server took 60 s instead of 121 s (0.14.0: 55–67 s).
    Library browsing and filters do not depend on it.

  • A valid 3MF too large to read within the preview memory budget is reported
    as too large to preview, not as a damaged file. Its XML parser running out
    of memory was recorded as invalid_source. The invalid_source message now
    says the file may be damaged or incomplete instead of asking you to check
    its storage.

  • A ZIP over the upload limit says so, with its size and the settings that
    raise the limit, and the message stays in Tasks. The image's proxy refused it
    with its own page, which the app reported as a server it could not reach.

  • Library titles and controls adapt to the available pane width. Cards use the
    full grid width, collection tags and description actions share a compact row,
    and description editing stays visible and usable on phones.

  • Library filters keep their position while facet counts load, so a response
    arriving during a click does not lose the selected filter.

  • Uploads wait for newly created tags to be saved, so a quick submission keeps
    every selected tag. Cancelling a draft ignores late tag acknowledgements.

  • Restoring large unfiltered collection trees reuses subtree counts instead of
    repeating the same lookup for every descendant.

  • Model metadata stays current when derivative updates arrive during an in-flight
    detail read, including revision comparison fields. Confirmed edit receipts
    with a different derivative snapshot trigger a fresh authorized read.

  • Preparing-preview activity waits until the Library is ready before reading
    the background queue. Opening Notifications can still request activity early.

  • Interrupted uploads remain in Notifications after reloading the page, so you
    can select the same file and resume the existing upload session.

  • Mesh previews and geometry processing continue to work when a busy server has
    more than 1,024 files open. Compute connections also wait for replies and detect
    disconnected peers without the same descriptor limit. Warm workers preserve
    high-numbered resource permits and close every unrelated descriptor before
    processing a model.

  • Native mesh processing now chooses a bounded concurrency default from the CPUs
    available to PrintStash. Explicit concurrency settings and shared memory
    admission continue to apply.

  • An idle server on SQLite no longer uses more CPU the longer it runs. Each
    background-work lane keeps checking for queued work on a short interval, and on
    SQLite every check read the engine's entire workflow history, which the
    default 7-day retention grows into tens of thousands of rows. On a low-power
    mini PC that kept the server near 30% CPU with nothing to do. The checks now
    use an index (DBOS 3.3). PostgreSQL was not affected.

  • Background work no longer gets stuck after a restart. Stopping or
    restarting PrintStash while a long job ran (a mesh, a backup, an import)
    could leave that job "running" forever. On lanes that run one job at a time,
    such as backups and maintenance, nothing else on the lane ran again until the
    next upgrade. Such jobs are now picked up and rerun after the restart. With
    separate worker processes, a worker that started after the backup being
    restored now registers itself again instead of having its jobs rerun.

  • A job whose work had finished is no longer marked failed because the
    database was briefly busy (a locked SQLite file, a PostgreSQL restart) while
    its result was being saved. Saving the result is retried.

  • Cancelling a running job no longer lets its lane start another job before the
    cancelled one has actually stopped, so lanes sized to the server's memory stay
    within their limit. A cancelled job whose work never stops still frees its
    lane after VAULT_JOBS_EXECUTOR_STALE_SECONDS (2 minutes by default).

  • The admin Background work page and each reconcile pass read lane depth
    and active work without scanning the engine's whole history on SQLite (137 ms
    per read at 200,000 history rows, now under a millisecond).

  • With a pinned executor id, a job that crashes the server is retried as many
    times as VAULT_JOBS_MAX_RESUBMITS allows (3 by default), instead of up to
    100 restarts.

  • Background work does less redundant database work: submitting a job no
    longer reads the engine first, creating one no longer reads it back, the
    periodic check skips the 12 kinds of requested work that have nothing to
    repair (a third of its engine runs, and of the history they leave behind), and
    its two sweeps share one read. Per job that is about 10% fewer database
    statements on each of the engine and application databases.

  • A reconcile interval that does not divide evenly into a minute, hour or day
    (for example 90 seconds) now runs at an even cadence rounded down, instead of
    firing twice in quick succession.

  • Settings no longer re-measures Storage insights or re-checks Server
    GPU
    every time you open them. Both took several seconds to load; each
    answer is now kept for the session. Storage insights are measured again after
    the library changes or when you choose Refresh measurement, and the GPU
    status when you choose Check again. The last figures stay on screen while
    a new measurement runs.

  • Adding a G-code revision to a model you uploaded no longer fails with "This
    model's source is remote and read-only" when a remote library source (S3,
    WebDAV, SFTP) has also indexed the same file. The revision is stored in the
    vault with the rest of the model. A model that only a remote source holds
    still gets that message.

  • AI Search can run a second local text model: all-MiniLM-L6-v2 (English,
    90 MB). It embeds a query in about half the time BGE takes and needs less
    memory, at slightly lower recall. BGE stays the recommended default; the
    model choice in guided setup now shows each model's size, languages and which
    one is recommended.

  • AI Search preparation now shows its four steps (check library content, index
    passages, catch up on recent changes, verify the index), which one is running
    and what it does, and how many passages are waiting for a retry. A prepared or
    active index shows an Index check: entries indexed out of searchable
    entries, entries waiting for a retry or shortened to fit the model, the model,
    and when verification last passed.

  • Local AI models use less memory: each worker now loads a model's weights once
    instead of twice and keeps a single tokenizer. Loading bge-small-en-v1.5
    peaks near 290 MB instead of 375 MB. Graphs still load only after
    their digest and structure checks pass, now through a pinned file
    descriptor, so a file swapped in after the check is never loaded.

  • A local AI model worker may now use up to 4 GB (VAULT_EMBEDDING_WORKER_MEMORY_MB
    default 4096, was 1024), still capped by the model memory share (a quarter of
    RAM, so 2 GB on an 8 GB host). At 1 GB, indexing eight full-length passages
    with bge-small-en-v1.5 failed with embedding_inference_failed.

  • Upgrading from 0.13.0 or 0.14.0 no longer requires draining derivation work
    first. Work still waiting under the old ordering is re-ranked on start instead
    of stopping the container in a restart loop with
    derivation_queue_requires_drain. Checked on real 0.13.0 and 0.14.0 data
    directories, including one with old-rank work queued.

  • AI Search can run multilingual-e5-small locally: one model for about 93
    languages, including Spanish, with the best recall on the search regression
    corpus. It needs about 1.15 GB of worker memory (hosts with 6 GB of RAM or
    more). Guided setup shows a language count for multilingual models.

  • A background-work engine database that DBOS cannot migrate (workflow rows but
    no migration record, left by an earlier failed first start) is now reported at
    startup with what to do, instead of looping on table workflow_status already exists.

  • Upgrading an existing install no longer stops at startup with
    derivation_queue_requires_drain and "no such column: queue_partition_key".
    The check that waits for old derivation work to drain read the previous
    version's engine database with a client that expects the new schema, so it
    failed on every existing install, even with nothing queued. It now reads only
    the columns every version has; waiting work from the old ordering is
    re-ranked on startup.

  • Adding a G-code revision to a Model that comes from a remote Library source no
    longer ends in "[500] internal_server_error". PrintStash never writes back to a
    remote source, so it now says so (409) and the dialog shows a readable
    explanation. In the same dialog, "Mark as recommended" is a star you fill
    instead of a checkbox next to one.

  • Deleted models can be selected in Settings, Trash: tick several (or all) and
    restore or permanently delete them in one step.

  • Large slicer 3MF files get a 3D view. A 20 MB Bambu Studio 3MF holds over
    100 MB of model XML, which hit a fixed 64 MB limit and showed "3D preview
    omitted due to memory limits". The limit is now VAULT_MESH_3MF_MAX_XML_MB
    (256 by default). A model with more triangles than the memory budget allows
    still needs VAULT_MESH_MEMORY_BUDGET_FRACTION raised; see docs/compute.md.

  • There is a single PrintStash image, and it can use the GPU. The separate GPU
    image variants are gone: the one image on GHCR uses an NVIDIA, Intel or AMD
    GPU, or the WSL2 GPU, whenever the container is handed one, and runs on the
    CPU otherwise. Docker Compose, Unraid and the other app stores can now pass a
    GPU and set the GPU and system memory budgets
    (VAULT_COMPUTE_MEMORY_MB, VAULT_MESH_MEMORY_BUDGET_FRACTION,
    VAULT_EMBEDDING_MEMORY_BUDGET_FRACTION); see docs/compute.md.

  • A model's 3D view opens straight away, even for a large mesh; the
    "Load 3D preview" button is gone from the model page.

  • The library loads the next page as you scroll, so there is no "Load more"
    button to press. Loading starts a little before you reach the end, shows a
    spinner while it reads, and the button only comes back if a read fails or the
    browser cannot watch scrolling.

  • Storage insights now show where your files live: the vault on this computer,
    and each library source with its type and connection, with the total held on
    this computer apart from what sits in remote storage such as R2. Library
    sources stay where they are, so only their previews and catalog count against
    the vault.

  • Thumbnail and 3D-view generation now shows in Tasks. After an import or a scan,
    administrators see one "Preparing previews" task counting what is left, which
    completes when the queue empties instead of the work being invisible.

  • The library no longer asks you to refresh when it changes. In a view that is a
    single page, a new Model or folder eases in where it belongs and a change in
    another folder only updates the counts; the notice remains only deeper in a
    long list, where reloading every page read so far would move your place.
    Changes are noticed within about ten seconds.

  • A 3D preview that cannot be made now says why. A model over the preview size
    limit, a file that is not a valid 3D model, a STEP file that will not convert
    and a source that cannot be read each have their own message, instead of
    "Something went wrong reaching the server".

  • A scan of a remote source reports its progress while it lists the bucket: the
    task shows how many files it has found and which folder it is in, instead of
    a bare "running" for minutes.

  • Filters work in a folder that only holds folders. The filter options and
    their counts now describe the whole folder tree below you, and applying a
    filter searches that tree, so the root of a library no longer offers nothing
    to filter. An unfiltered folder still lists only its own Models. Print
    history and Uploaded now look and behave like the other filter groups.

  • A remote scan that finds no model file now says so on the source card, naming
    where it looked (S3 paths are case-sensitive) and linking to the connection,
    instead of ending quietly at "+0 added".

  • Library sources can be edited. Each source card has an Edit button to rename
    it and change how it maps to collections. A mounted folder can be pointed at
    another folder, and a remote source at another path inside its connection
    while it has indexed nothing. A remote source now shows its connection and the bucket or
    host it reads (for example R2Test · test/PrintStash/) instead of the
    internal source://1/.

  • Applying a filter no longer rebuilds the collection tree. Its rows stay put,
    the counts dim while they reload, and each count that changes ticks toward
    its new value.

  • Picking a filter value no longer hides the other values of its group, so you
    can add a second file type (or any other value) without clearing the first.
    While a filter is on, the view lists the matching Models only, without the
    open folder's subfolders beside them.

  • Starring a Model, or regenerating covers, no longer shows "The library has
    changed" on every open library. Only edits that can change a listing do.
    Reloading reopens the path to the open folder and the six folders you opened
    last, not every folder of the session.

  • Cards now ease in one after another when you open a folder, even when
    everything is already cached.

  • Settings → GPU shows what the server can reach. Administrators get a
    Server GPU card saying whether a GPU is accessible from the API, with its
    device, backend, driver, memory budget, capabilities and recent activity, or
    the reason there is none.

  • Saving a collection description no longer reloads the collection tree or the
    library, and the Tags, Upload and New multipart set dialogs no longer open on
    an empty frame the first time: their code is fetched once the library is
    usable.

  • Opening a folder now has a little motion. Its contents ease in from the right
    when you go deeper and from the left when you go back up, and fade in when
    you jump somewhere unrelated. It is a short, small nudge that keeps scroll
    positions intact, and reduced motion keeps only the fade.

  • Models first, then thumbnails. While an upload, an import or a library
    scan is still adding Models, thumbnails and other derived previews wait; they
    start as soon as the last one finishes. A large import shows all its Models
    sooner, and the library can be browsed while the previews catch up. Opening
    a Model in 3D is not held back.

  • The library no longer starts over while an import runs. Every imported file,
    and every folder an import or a library scan created, told open library
    views that access might have changed, so they discarded what they showed and
    loaded again. A new Model is now created in its Collection instead of being
    moved there afterwards (it was also briefly visible at the root), and only a
    change that can affect access (a role, a disabled account, a moved or deleted
    Collection) advances the access revision. The upgrade replaces two database
    triggers; no rows change.

  • Importing costs the database less. Steps that are only waiting share one
    cancellation read instead of making one each, a finished upload no longer
    queues a reconcile pass that has nothing to find, and several reads that ran
    as their own transaction now ride on one that was already open.

  • Opening a collection no longer makes the page jump. Its tags and description
    appeared only once the folder and its description had loaded, pushing the
    models down; their place is now held by a skeleton of the same shape.

  • A multi-material G-code now shows the filament weight and length of the whole
    plate. A two-filament plate (; total filament weight [g] : 70.97,16.48) was
    shown as 70.97 g, its first filament only, and was costed accordingly. Files
    already in the library are re-read in the background (#453).

  • Multi-material prints now route to printers with several filaments. A G-code
    using two or more materials was unknown on every Bambu AMS printer, because
    all its trays share one tool; it now fits when the printer holds a distinct
    tray for each material, and is a proven mismatch when it does not (two PLA
    colours on one PLA spool). Colour advice is given per material instead of per
    last-seen tray (#453).

  • Importing a reviewed archive shows how far along it is. The task used to say
    "Discovering total…" with an empty bar until the last file was done, although
    the selection was known from the start.

  • A multi-material G-code now shows the material it actually prints with. A
    plate sliced on AMS slot 3 of a PETG;PLA;PLA;PETG setup was shown as PETG,
    the first slot; the slicer's ; filament: 3 header is now read, and only the
    slots the plate uses are required of a printer. Files already in the library
    are re-read in the background (#445, #453).

  • G-code exported by BambuStudio 2.x now shows its slicer, estimated print time,
    filament weight and filament length. Its header block writes
    ; BambuStudio 02.08.02.61, ; total estimated time: 17m 21s and
    ; total filament weight [g] : 6.15, none of which the parser recognised.
    Files already in the library are re-read in the background.

  • View a Model from underneath. The 3D preview now orbits all the way
    around a mesh, so the underside can be inspected; it previously stopped at
    the horizon (#427).

  • Start with only the selected language. Each translation catalog is now its
    own asset, loaded when its language is shown, which removes about a fifth of
    the JavaScript downloaded at startup.

  • Read a Model's details once when opening it. The page no longer repeats the
    read just to confirm that nothing changed while it was connecting to live
    updates.

  • Keep one events connection and one setup admission while moving between
    application pages. Opening a Model and returning no longer hides the app
    behind a setup probe, reopens the events socket or refetches every view.

  • Compress 3D preview meshes between the server and the browser. Binary STL
    previews transfer at about half their size and ASCII STL at about an eighth,
    and a slow connection no longer makes the proxy spool a large mesh to disk.

  • Keep folder descriptions and model cards together when navigating, clamp long descriptions before the first paint, and avoid fading cached library thumbnails on every visit.

  • Open large Models on their thumbnail. A 3D preview whose source file is over
    16 MB is no longer downloaded just by opening the Model; the page shows its
    size and a "Load 3D preview" action instead. Shared links and the similar
    Models comparison follow the same rule.

Performance

  • A 3MF's slicer picture appears as soon as the file is committed. It used to wait until the mesh had been read and measured, although it needs nothing from the mesh.

  • Do about 45% less database writing per uploaded file on SQLite (write transactions per file 57 → 32):

    • a Job attempt ends in one write that also carries its staging release and the notices to the work that follows it, instead of five to eight;
    • progress a Job reports in its first second is written with its next write (VAULT_JOBS_PROGRESS_HOLD_SECONDS);
    • scratch space for a file is admitted against the same free-space budget without a database write of its own;
    • the search index reads a changed Model before it takes the database's writer, not while holding it.
  • An accepted upload starts sooner. The request hands its Job straight to the job engine instead of queuing a pass to find it, and the lane it was handed to is polled faster for a few seconds (VAULT_JOBS_BOOSTED_QUEUE_POLL_INTERVAL_SECONDS, VAULT_JOBS_QUEUE_BOOST_SECONDS). Median wait before an upload's import starts: 0.37 s → 0.13 s.

  • Geometry and thumbnail workers start from a process that has already loaded the application and its geometry libraries (Linux), instead of a fresh interpreter per file: about half a second of CPU less per file. Each worker keeps its own session, memory ceiling and deadline. VAULT_MESH_WORKER_TEMPLATE_ENABLED=false restores a fresh interpreter per file.

  • A file in a bulk upload now waits when the server is busy instead of failing. Session creation was limited to 30 per minute, which held a 200-file drop to one file every two seconds and failed files that arrived faster; that limit now bounds a runaway client (600 per minute) and staging admission paces real uploads.

  • Halve the CPU an idle installation spends polling its job queues: lanes nobody waits on (search, maintenance, notifications, similarity, captions, expansion) are looked at every two seconds (VAULT_JOBS_RELAXED_QUEUE_POLL_INTERVAL_SECONDS) instead of four times a second.

  • Do less database work per uploaded file on SQLite: keep connections pooled instead of reopening them under load (VAULT_SQLITE_POOL_SIZE), open the job engine's own SQLite file in write-ahead mode, stop writing a row-level audit entry for every job, reconciler-cursor and capacity-claim heartbeat, check a step's ownership without taking the write lock, and report commit stages only for files slow enough to watch. Cancellation is noticed within half a second and worker memory is sampled ten times a second.

  • Release prepared thumbnail parsers before GPU eligibility/dispatch instead of repeating broker status inside each disposable process. Keep model publication ahead of background DBOS captures, preserve guarded recovery from the same geometry packet, use compact exact OBJ corner keys, and skip STL preflight scans that cannot change the minimum memory claim.

  • Simplify source geometry preparation and native supervision: load qualified OBJ directly, bound text admission without parsing coordinates twice, avoid redundant vertex/edge sorting, and reuse a narrow cancellation query with fresh results. Keep native settings minimal and sample each staged worker's RAM once. A fixed 250-source WSL GPU comparison improves from 497.090 to 358.937 seconds (27.79%, using the longer of the two recorded clocks in the final repeat; first candidate: 357.279 seconds), preserving all metadata, 238 byte-identical images and the same 12 invalid-source outcomes; CPU-only geometry uses the same preparation path.

  • Decode ASCII STL geometry once for both CPU-only and GPU-enabled ingestion, retaining bounded source blocks instead of reparsing for allocation. Preserve exact source measurements, validation and output images. The fresh 250-source GPU comparison reduces elapsed time by 2.77%; a repeated three-source CPU-only probe improves by 29.02%.

  • Share a single bounded source-worker execution between measurements and previews. Basic STL measurements use source-precision arrays without importing Trimesh, preserving topology and signed-volume evidence; OBJ/CAD and optional fingerprints retain their specialized analysis. Eligible small previews now prepare normals on GPU while analytic views keep their canonical policy. Preserve identical metadata and original-file integrity.

  • Reduce repeated compute fingerprinting and admission-ticket decoding, give cold GPU ownership its bounded startup allowance, retain canonical STL bounds without gathering another vertex array, and compile worker application bytecode during image builds. Count bounded OBJ sources under separate CPU/wall budgets so scheduling contention does not unnecessarily serialize the RAM pool.

  • Render compact indexed triangles with GPU bounds/framing and visual position welding, grouping model uploads and drawing into one bounded submission per batch. Retain multiple geometries in VRAM and repair degenerate normal neighborhoods locally. Release an eligible disposable parser after clean reap, then render prepared geometry and encode final pixels in the owning Job without another encoder process. Retain explicit host/CPU credit through completion; GPU refusal uses a guarded renderer without reparsing. Unready devices, unmatched qualification, insufficient headroom and optional fingerprint work retain the combined worker. Preserve publication fences and reject empty GPU frames through the existing CPU recovery path. Assemble immutable geometry packets without repeated full-buffer copies. Avoid repeated framing/encoding of validated renderer output and use quality-85/method-2 lossy WebP with exact alpha and a codec completion slot independent of parser admission; thumbnail/visual recipes track the changed rendering semantics.

  • Prepare large render meshes with portable GPU normal accumulation and indexed packing, using guarded per-model CPU fallback and shared RAM/VRAM accounting. Keep canonical analytic preparation separate, reuse resident GPU state, and encode accelerated WebP through the same canonical preview encoder. Version changed thumbnail and visual recipes while preserving authoritative measurements and source bytes.

  • Coalesce independently admitted thumbnail work across Models, preserve per-item cancellation and deadlines, and report actual model/frame batch sizes. Keep disposable worker priorities across process startup, bound OBJ/ASCII STL admission preflight, avoid redundant mesh copies, topology work and unused worker imports, and reduce durable queue dispatch latency without changing concurrency or backfill ownership.

  • Drive native OpenDAL source reads through its asynchronous API so slow remote storage does not retain the Python GIL. Preserve bounded streaming and conditional reads, and interrupt waits at the existing cancellation and scan deadlines.

  • Keep GPU thumbnail resampling, alpha conversion and vignette on the device after an exact canonical canary. Download only final pixels, avoid timeout-mode socket polling delays, and reuse validated geometry through bounded binary references instead of repeated base64 transfers. Retire completed broker references so evicted geometry can release host RAM while the owner remains idle.

  • GPU thumbnail evaluation can use Mesa OpenGL/D3D12 entirely inside Docker/WSL, with hardware verification independent of GPU brand. A persistent render owner reuses geometry and shaders, batches up to eight ready frames per readback, and caches repeated shaded views. Evaluation remains distinct from automatic performance qualification and operator visual acceptance; CPU fallback stays available.

  • Correct shared-edge opacity in portable GPU rendering; document physical RTX 5060 probes and the remaining WSL Dozen/ONNX compatibility blocker.

  • Optional portable compute broker for qualified WebGPU rendering and ONNX inference, resident geometry/model reuse, bounded tensor batching and administrator diagnostics. CPU-only installations retain normal ingestion. Physical GPU combinations remain unqualified pending quality, end-to-end performance and recovery gates.

  • Enable mesh preview readiness after its first rendered frame; verify overlay alignment, display-mode pixels, and repeated resource cleanup on WebGL/WebGPU.

  • Extend native mesh preview checks for camera movement, screenshot scales, capture failures, and disposal; retain WebGPU as experimental after baseline comparison.

  • Open Models faster from the Library: resting the pointer or keyboard focus on
    a Model card reads its details ahead of the click.

  • Release the mesh preview GPU device when renderer construction or initialization cleanup fails.

  • Parse mesh previews in a cancellable worker and add an experimental WebGPU
    preference with camera-preserving WebGL recovery and asynchronous screenshots.
    WebGL remains the default; GPU performance qualification is still pending.

  • Request the platform-preferred GPU before enumerating other graphics backends in the optional research adapter. Preserve capability fallback, software exclusion and explicit adapter selection.

  • Retain expanded NVIDIA quality rejection, real-model browser comparisons and fresh-worker failure evidence; document an isolated experimental WSL/Docker diagnostic without changing production eligibility.

  • Automate fresh-worker GPU benchmark campaigns with retained failures and immutable output directories; add ASCII/binary STL and overlapping geometry controls.

  • Report native GPU readback separately from CPU face resolution and canonical shading in qualification measurements.

  • Record revised RTX 5060 control evidence: exact CPU/GPU images across 60 observations after precision and native cleanup fixes; production qualification remains gated.

  • PRI-16: preserve canonical interpolation precision in the optional WebGPU
    adapter, bound retained geometry, and reject invalid face readback before publication.

  • Add an optional Python 3.14 WebGPU raster qualification adapter, adapter diagnostics,
    frozen benchmark manifests and statistical reports. Production rendering remains CPU.

  • Avoid deep-cloning lexical search queries for each page; keep rank materialization
    local to each query and reuse immutable current-recipe predicates. Measure tab
    indicators after native layout instead of forcing layout during React commit.

  • Reuse bounded subtree count query structure with current roots and permissions.
    Decode admitted thumbnails without a second native visibility wait.

  • Start selected collection reads before rendering their destination, cancel abandoned
    reads, and keep pointer prefetch scheduling outside the grid's rendering path.

  • Optimize the restored tree's rendering with explicit locale dependencies, preserving
    live language changes, drag-and-drop and pagination. Reuse immutable card projection
    statements with fresh page/user parameters; avoid constructing unused tree ancestry.

  • Reuse immutable ancestry and similarity query structure while reading current
    permissions on every request. Avoid rerendering an unselected departing grid
    before starting a collection navigation.

  • Reuse HTTP-cached content-hashed assets during reload without weakening HTML
    or bootstrap revalidation, offline fallback, or private-response isolation.

  • Keep scheduled upload recovery outside an active verification or Job handoff,
    avoiding spurious upload conflicts while retaining recovery after interruption.

  • Reuse the current locale's card-date formatters without caching timestamps.

  • Preserve visible nesting at every collection-tree depth and align Model leaves
    beneath their parent, keeping deep rows selectable on narrow screens.

  • Ignore system-only maintenance notices in Task Center instead of repeatedly
    downloading an unchanged Jobs list.

  • Serialize search-preference writes before reading SQLite state, avoiding failures
    when background processing commits concurrently.

  • Reduce thumbnail transfer size with quality-85 WebP color and lossless transparency,
    preserving resolution and regenerating existing mesh/G-code previews through Jobs.

  • Restore remembered Library branches in bounded batches, prioritize visible thumbnails,
    and keep deeply nested folders selectable on narrow screens. Load the multipart
    editor separately from Library cards, reuse restoration counts and permission scopes,
    and avoid repeated thumbnail access lookups and image decoding. Reuse immutable
    similarity SQL construction while checking current permissions on every read.
    Reuse authorized empty child levels and defer the initial event connection until
    critical content is ready, retaining immediate permission checks. Opening the mobile
    tree no longer competes with filter catalogs below the visible area.

  • Keep the first visit intact when the service worker installs, while still refreshing
    an existing installation after a worker update.

  • Measure each Library destination through restored tree rows and decoded viewport
    images, with a reproducible reference-host acceptance command and explicit failures.
    Tie timings to committed history entries and actual input events.

  • Keep the collection tree visible when selecting folders, preserving open branches
    and downloaded sibling pages without reloading them on every click.

  • Finish Settings cache and audit ownership: preserve pending edits during refresh,
    reject obsolete cache-policy changes, share audit reads, and retire commands
    when leaving a view or changing session.

  • Keep manual printer-material drafts after rejected saves and offer explicit review
    before adoption; cancel obsolete reads when switching printers.

  • Preserve first-run storage drafts across locale changes, retire setup requests
    on navigation, and recover one initial Library read conflict without mixing snapshots.

  • Keep Library view metadata out of AI Search filter requests, so filtered and saved searches remain usable.

  • Offer Everything and Multipart Sets as the two Library views. Filter and order
    mixed results on the server before pagination so later matching results remain
    reachable. Reject stale continuation pages instead of mixing catalog revisions.

  • Preserve each Library history entry's filters and reading position through
    detail navigation. Bound restoration after cache eviction, explain missing
    anchors, keep rapid folder transitions coherent and retire private snapshots
    when the session or access changes.

  • Detect competing edits to Models, Multipart Sets, Documents, printer settings,
    Profiles, Search, Vault settings, browser names, notifications, storage connections,
    Library sources and Spoolman. Preserve drafts for explicit review after conflicts
    or uncertain responses. Bind edits to database history so restored backups cannot
    authorize obsolete drafts. Legacy clients retain unversioned compatibility.

  • Keep confirmed changes authoritative during refetch and pagination races. Remove
    the duplicate transport GET cache and transport-owned invalidation. Feature owners
    coordinate reads, receipts and recovery; session changes retire private requests,
    cached results, local secrets and pending confirmations.

  • Retain protected thumbnail URLs while displayed, admit nearby images under a
    four-download limit and cancel abandoned work. Bound idle encoded image data
    without evicting mounted consumers. Preserve Shift selection after page append
    and the reading position after removing a confirmed favorite.

  • Share Inbox and durable Job state across consumers. Preserve accepted uploads
    and scans after their forms close, recover missed events and prevent disposed
    printer subscriptions from reconnecting. Retire bulk transfers with their session.

  • Give settings, storage migration, backup, source management, manufacturing and
    ZIP review explicit loading, error and recovery states. Preserve unsaved input,
    require the reviewed destination for destructive actions and avoid replaying
    commands after an uncertain acknowledgement. Save compound Vault configuration
    in one transaction; retain omitted credentials and independent edit counters.

  • Bind browser-extension captures to the selected connection throughout download
    and upload. Retire revoked credentials, cancelled pairing and obsolete callbacks;
    clean up malformed upload receipts and unnecessary host permissions.

  • Keep route-chunk recovery bounded and localized, restrict the offline cache to
    public static resources and recover online navigation when Cache Storage fails.
    Retain React Router and the static Vite deployment; enforce app/package dependency
    directions and remove obsolete navigation and invalidation compatibility APIs.

  • Load the Library route immediately and defer upload, tag, multipart creation
    and ZIP review forms until opened. Prioritize cards and the bounded tree,
    release auxiliary reads after paint or explicit interaction, and share the
    initial Jobs snapshot with the event handshake and a one-second fallback.
    Deliver bootstrap and hashed assets without waiting for Cache Storage, keep
    an offline shell fallback, and bound Model pages to 24 cards. Add production
    startup measurements against a disposable real SQLite library in Deep CI.
    Discard reads from previous sessions, prevent late GET/blob results from
    refilling invalidated caches, and recognize session changes across tabs.

  • Add storage publication authority boundary tests for incompatible receipts and stale reconciliation.

  • Add import download contracts for staging names, redirect and window ceilings, stream cleanup and ZIP CRC refusal.

  • Add thumbnail engine contracts for unavailable allocation, source files and RSS telemetry, preserving publication errors.

  • Add real database contracts for mesh continuation recovery, cache lease deferral and current Job withdrawal authority.

  • Add authenticated HTTP contracts for outliner printer-filter authority and contradictory query scopes.

  • Add real ZIP preview contracts for embedded 3MF budgets, unsafe member names, CRC recovery and strict PNG validation.

  • Add real database contracts for similarity ingestion continuation authority, durable analysis eligibility and caller write rollback.

  • Verify fingerprint publication preserves active caller transactions and leases,
    rejecting detached authority, changed recipes and invalid descriptor metadata.

  • Verify STL publication readers preserve buffered byte semantics and cancellation,
    refusing nonregular output and unavailable or mismatched source storage.

  • Verify local inference rejects missing capabilities, model assets and oversized
    input while preserving admission recovery and read-only cached model support.

  • Verify viewer STL conversion refuses nonfinite facets, excess streamed output
    and changed or missing source identities before reporting success.

  • Verify prepared mesh resource identity and immutable detached buffers refuse
    incoherent evidence before native analysis.

  • Verify import resolver selection identities reject malformed provider responses
    while preserving stable errors and redacting private transport data.

  • Verify durable ingestion receipt writer authority, result pagination and canonical
    File confirmation through real SQLite contracts.

  • Verify batch session lifecycle, frozen snapshots and result context against
    real durable receipts, including refusal of incomplete artifact commit results.

  • Verify retained scene measurements preserve finite dimensions when closed
    resources collapse or numeric volume aggregation exceeds its representable range.

  • Verify mesh output frame boundaries reject malformed flags, incoherent evidence,
    oversized payloads and invalid fingerprint records before publication.

  • Verify preparation resource lifecycle rejects malformed recovery identities,
    preserves failed cleanup ownership and enforces source-before-native ordering.

  • Verify durable volume evidence reads preserve closed variants and refuse
    incompatible scalar, method, cause or state combinations.

  • Verify search generation proposal provider, visual profile and aggregation
    rejection contracts directly at the public schema boundary.

  • Measure whole-host native fairness in the mandatory serial resource phase,
    retaining real workers, branch coverage and the existing timing budgets.

  • Isolate provider HTTP pools and host capacity between tests so a previous
    test's ended event loop cannot affect transport shutdown.

  • Keep fairness qualification reads bounded to pending foreground uploads while
    preserving exact progress totals, native budgets and its existing deadline.

  • Qualify backup recovery and exact deletion against versioned S3 generations;
    verify that missing receipts on unversioned targets are refused without
    changing the published archive.

  • Reset PostgreSQL work-engine state by removing only its DBOS schema, preserving
    application tables in the shared database and rebuilding the reconciler schedule.

  • Run Python compatibility tests and external service contracts in independent
    Deep CI jobs, preserving both required results and their execution limits.

  • Distinguish repeated uploads from same-Job retries in sustained ingestion
    qualification, verify versioned Artifact identities, and stop after the first
    failed mandatory control while preserving failure evidence. Configure E2E
    SQLite connections before concurrent work starts, matching production WAL
    initialization and native-extension startup; prepare backup recovery through
    permanent purge with foreign-key enforcement intact.

  • Keep Model card tag and similarity badge reads bounded as the SQLite catalog grows, including
    installations with stale query-planner statistics.

  • Defer parent-only metrics and database URL parsing in disposable mesh workers,
    reducing measured small-model startup costs while preserving CPU outputs,
    parent telemetry and guarded process cleanup.

  • Add isolated GLB/LOD qualification tools with supervised native exports, real
    browser memory/draw/quality measurements and protected-feature checks. Retain
    STL after measured candidate correctness, resource and performance limits.

  • Publish batch Artifacts before materializing later entries. Bound disposable
    staging by files and bytes, record each entry with its Artifact transaction,
    and resume confirmed entries without reopening their sources. Keep partial
    failures retryable and report unknown totals until discovery finishes.

  • Stop withdrawn batch imports between entries and source blocks, preserving
    committed Artifacts and durable upload sources while cleaning owned staging.
    Copy and hash browser upload bytes in one pass, and preserve cancellation when
    receipt cleanup fails.

  • Add an isolated prepared-geometry cache benchmark with bounded, checksummed
    arrays, current-loader STL equivalence checks and supervised worker timings.
    Keep production preparation unchanged pending demonstrated reuse and recovery
    guarantees.

  • Publish viewer STL conversions from verified staged streams without buffering
    whole outputs in the API/worker parent. Reserve expanded output space before
    conversion, reject changed or incomplete publications, and release request
    database connections before work hints so concurrent viewer misses share one
    durable conversion without pool timeouts. Release native compute credits before
    storage publication; viewer recipe 3 rejects malformed STL and float32 overflow
    or collapsed faces, rebuilding older viewer outputs on demand.

  • Bound file acceptance commands independently of ordinary API workers. Keep SQL
    sessions on their creating thread, release them while streamed bodies wait,
    revalidate credentials before publication, and finish admitted writes before
    returning cancellation. Slow storage or engine hints leave lightweight API
    requests responsive; accepted imports remain durable background Jobs.

  • Reserve interactive discovery slots beside one active backfill Job per
    derivation lane. Keep bounded indexed scans and durable backfill progress
    during uploads, dispatch admitted derivatives in FIFO order, and carry Job
    priority through shared native and source-preparation admission with aging.
    Preserve backfill reservations across public retries and engine-acceptance
    crashes without spending another attempt while waiting. Verify legacy queue state before starting consumers; upgrades drain and
    restart API and workers together.

  • Local ONNX models reserve a shared, bounded memory partition across API and worker processes, retain warm reuse, retire idle residents under pressure, and release their credits after guarded process-tree termination.

Source installs require Python 3.14 or newer. See the upgrade guide.

  • Coordinate mesh CPU/RAM credits across local API and worker processes. Bound
    source preparation separately by bytes and I/O slots, retain native credits
    through descendant cleanup, and recover abandoned source copies before reuse.
    Reserve memory for the requested geometry, raster dimensions and optional
    analysis, preserving WebP output and complete fingerprints for admitted work.
    Reduce temporary raster buffers while keeping complete frames and output pixels.
    Report queue time independently of native execution.

  • Remove the sidebar tree’s global 500-model limit with folder-scoped pages, complete branch counts, and global paginated name search with “Open location”. Keep permissions and library views in the server query; retry failed pages without losing loaded rows (#335).

  • Keep backup and vault audit clock inputs within valid minutes on Python 3.14; reject 24:00 rather than treating it as midnight.

  • Preserve traceable printer display names for extension-only and genuinely named inputs on Python 3.14.

  • Require Python 3.14 for the application and shared core, pin development and container runtimes to 3.14.8, and update the mesh stack to NumPy 2.5.3, SciPy 1.18.1 and Trimesh 5.1.1.

  • Publish mesh metadata and thumbnails before optional fingerprints finish, with durable bounded recovery that preserves completed outputs after native failures.

  • Reuse immutable mesh positions and smooth normals across each visual pass.
    Embedding views and similarity view hashes consume pixels directly without
    repeated PNG encoding and decoding, while preserving existing preview bytes
    and descriptor identities.

  • Retain unique 3MF resources and explicit placements through measurement and
    preview rendering. Measure repeated instances without first allocating a whole
    placed mesh, materialize only for admitted fingerprints or global topology,
    and release that mesh before rendering. Keep exact dimensions and counts when
    optional volume or fingerprint analysis fails, with explicit volume evidence.
    Preserve finite volume when source and placement scales compensate, and clear
    measurement topology caches before rendering even without fingerprints.
    Refresh mesh outputs under the new eligibility and budget policy.

  • Share bounded STL source validation across measurements, full loading, fallback
    samples and streamed previews. Validate complete source facets and stable EOF
    before reporting coverage, retain exact full-source bounds and counts for
    partial samples, and refuse malformed or changed sources consistently.

  • Interpret reachable Core 3MF geometry and Production external model references
    through an explicit bounded scene reader. Refuse unsupported required
    capabilities with typed metadata, similarity and viewer reasons while retaining
    original downloads and independently usable embedded previews. Refresh mesh
    derivative recipes without introducing a Lib3MF dependency.

  • Keep mesh measurements and previews available when optional fingerprint analysis
    exceeds its triangle budget, and release analysis buffers before STL rendering fallbacks.
    Re-derive earlier terminal refusals at updated mesh recipes.

  • Independent mesh, G-code metadata/thumbnail and binary toolpath processing controls, with deployment defaults and live administrator settings. Disabling retains published previews and lets admitted processing finish; re-enabling resumes eligible missing work (#263).

  • Harden mesh workers with pre-import address-space limits, one admission controller
    across concurrency changes, process-tree memory accounting, and shared budgets
    for nested CAD/streaming work (#259).

  • Report refused mesh geometry separately from usable thumbnails, retain terminal
    failures for unchanged input, and backfill accurate metadata with recipe 3 (#259).

Upgrade note: The background engine now uses DBOS 3.3.0. Stop all API and
worker processes before upgrading together. Restore the pre-upgrade application
database and managed files to roll back; discarding the DBOS engine state alone
is insufficient. Every model file is re-derived in the background after upgrading.
See the upgrade guide.

Added

  • Measure mesh rendering, supervised native workers and upload-to-visible
    production DBOS ingestion through separate reproducible benchmark paths.
    Preserve phase costs, resource observations and failed samples, with an expanded
    versioned corpus and opt-in large inputs and hash-pinned real slicer projects.

  • Publish explicit mesh volume state, method and cause independently of similarity
    fingerprints. Preserve historical scalar provenance, keep small measurements
    unrounded and evaluate signed volume accurately across large translations.
    Reject nonphysical dimensions before publication and repair unusable historical
    measurements during the additive upgrade.

  • Add a frozen synthetic mesh contract corpus and record benchmark environment, limits, versions and target expectations separately from observed render results.

  • Mesh workers retain bounded phase costs and parent-observed resource usage in structured process logs and local Prometheus counters, including metadata-only work and failed or cancelled native processes.

  • Deep CI exercises the production mesh pipeline under 1 GiB and 4 GiB
    limits on amd64 and arm64, publishing memory, failure and cleanup evidence.

  • Job details show retained ingest capacity and provide a confirmed, identity-checked
    discard action serialized against retry. Completed staging is reconciled at
    startup; failed input retains its existing expiry (#259).

  • API responses include Server-Timing for total request time, SQL time and
    statement count. Requests exceeding VAULT_SLOW_REQUEST_MS (1,000 ms by
    default) emit a warning with those timings and the request ID to help diagnose
    slow library pages without logging query values.

  • The API serves the collection tree a page at a time:
    GET /api/v1/collections/children lists one level (or a user's top level),
    GET /api/v1/collections/lookup resolves a path with its ancestors, and
    GET /api/v1/collections/search finds collections by name at a minimum role.
    Each result carries its subtree Model count, child count and display path.
    GET /api/v1/collections, which returns the whole tree, is deprecated and
    will be removed in 0.16.

Fixed

  • Expired printers now appear in garbage-collection previews and can be purged
    after backup verification, approval and quarantine. Printer configuration is
    removed without foreign-key failures; print and notification history survives.

  • Refused storage writes no longer strand thumbnail reservations. Hourly cleanup
    recovers stale failed publications even when trash expiry is disabled or a GC
    preview awaits approval, so thumbnails can be generated again after enrollment.

  • Preserve remote scan deadlines when native metadata or streaming reads time out, so bounded imports continue instead of entering provider-error backoff.

  • Continue manual remote-library scans across bounded pages and time slices using durable requests committed with the saved cursor. Cancellation and provider backoff remain distinct from normal continuation.

  • Normalize S3 library listing timestamps to HTTP HEAD precision so unchanged Cloudflare R2 models can be indexed; retain size, ETag, version and post-download change checks.

  • Keep admitted editor state while setup navigation is checked, retire it on rejection, and show legacy local/S3 storage details.

  • Preserve confirmed Model batch results when a later request loses its response, with explicit review and conditional undo of acknowledged changes.

  • Bounded STL previews report whether all source triangles are represented independently from a complete source scan. Mesh processing now uses separate admission, loading, measurement and preview owners with validated geometry and fingerprint contracts.

  • Mesh workers reject unknown or malformed fingerprint result states before publication.

  • Capture and similarity commands keep the API event loop responsive through database writes, background-engine notification and response projection.

  • Preserve existing paired Point model manifests and native encoder alignment when mesh rendering recipes change. Visual vector caches still track their rendering recipe.

  • Mesh metadata preserves measurement precision, including submillimeter dimensions and small positive volumes; existing rounded measurements are recalculated.

  • Small meshes placed far from the coordinate origin retain their thumbnail
    geometry and shading. Visual recipes now refresh previews, view fingerprints,
    and derived image vectors while preserving original files and encoder assets.

  • Geometric verification reuses an exact point index and preserves nearest-point
    distances for models placed far from the origin. Previous pair proofs are
    rechecked under the new verifier recipe while retaining review decisions.

  • Ingest acceptance keeps the API event loop responsive while staging files,
    recording work and notifying the background engine.

  • Keep mesh-worker memory limits and cancellation active after the child closes its reply stream.

  • Active mesh workers can release their render admission while a queued worker checks durable cancellation state.

  • The thumbnail benchmark now runs the real engine, measures persisted local thumbnail reads, and preserves failed attempts with their costs instead of reporting misleading cache timings.

  • Large STL files now retain complete bounding dimensions and facet counts when only metadata is requested; measurements no longer depend on producing a thumbnail.

  • Mesh previews and image embeddings ignore vertices unused by any face when
    framing the surface. Existing visual derivatives are regenerated.

  • Meshes with repeated identical faces no longer expand the same thumbnail pixels
    repeatedly, avoiding unnecessary rasterization work during ingestion.

  • Meshes with inconsistent triangle winding now report unknown volume while
    retaining dimensions and triangle counts. Existing metadata is recalculated
    automatically.

  • Browser-local upload queues recover as interrupted after a reload, so stale
    tasks can be cleared. Resumable uploads retain their recovery controls, and
    queued browser work now asks users to keep the tab open (#336).

  • 3D viewer conversions run as durable, on-demand Jobs. Requests share preparation
    and retain failure reasons; memory refusals show a clear message while original
    downloads and slicer handoff stay available. Hovering a model card no longer
    starts a mesh conversion (#259).

  • Containers start with read-only Library source mounts beneath /data. Startup
    ownership repair is limited to app-owned directories and preserves external
    sources, including bind mounts on the same filesystem (#330).

  • Cancelling active mesh work now stops its native worker tree, releases capacity,
    and preserves the original. Immediate retry cannot resume the cancelled attempt (#259).

  • Keep native STEP/STP conversion within small worker memory budgets by using serial tessellation, and classify B-rep allocation failures as resource refusals.

  • Background work starts on DBOS 3.3.0, with a persistent reconciler schedule
    that survives process restarts and is recreated after restore.

  • Late derivative results can no longer overwrite cancellation, retries, regeneration, trashed Artifacts or replaced source bytes. Stale Job executions also cannot settle a newer attempt or reclaim its staging files.

  • Removed the duplicate Wiki entry from the profile dropdown.

  • Rendering model views for learned similarity embeddings no longer happens in
    the API process (#259).
    With embeddings enabled, the similarity run rendered six views of every model
    in the library inside the API; it now uses the same disposable worker as the
    other mesh work. A model that exhausts memory or never finishes fails that one
    embedding and the run continues with the rest.

  • Collection search, breadcrumbs and subtree counts now follow indexed parent
    links, keeping these reads responsive in libraries with tens of thousands of
    collections (#295).

  • Opening the 3D viewer on a 3MF or OBJ no longer converts it inside the API
    process (#259).
    The conversion runs in the same disposable worker as mesh derivatives, so a
    model that exhausts memory or never finishes fails that one request with
    stl_conversion_failed instead of taking the API down. A model that cannot
    be converted still answers the same error; the viewer's behaviour is
    otherwise unchanged.

  • Comparing two models during a similarity run no longer happens in the API
    process (#259).
    Verification now runs in the same disposable worker as mesh derivatives, so a
    pair whose comparison exhausts memory or never finishes is counted as a failed
    verification and the run moves on to the next pair.

  • Analysing the whole library for similar models no longer runs in the API
    process (#259).
    The fingerprint pass now uses the same disposable worker as mesh derivatives,
    so a file that exhausts memory or never finishes is recorded as a failed
    fingerprint for that file alone. The run carries on with the rest of the
    library instead of taking the API down or stopping.

  • The Settings Maintenance heading now uses the same framed section treatment as neighboring tabs.

  • Opening the 3D viewer, converting to STL, and geometry comparison no longer
    expand a 3MF's repeated parts before checking their size. These paths still
    used a loader that composed every placed instance first, so a small project
    file that places one part many times could exhaust the API's memory
    (#259). They now
    share the bounded 3MF resource loader and the same face budget as thumbnail
    generation; an over-budget project is refused instead.

  • Manual and scheduled backup tasks now show database snapshot, file archiving,
    archive verification, destination publication and finalization progress in
    Tasks and Background work, including the number of files archived. Scheduled
    backups now appear in administrators' Tasks while they run, and the latest
    completed scheduled backup remains visible if it finished before reconnect.

  • A model file that needs more memory than expected can no longer take the API
    down or crash-loop the container
    (#259). Mesh
    geometry, thumbnails and similarity fingerprints now run in a disposable
    worker process. When a file passes its memory budget or the worker deadline,
    the worker is killed and that one file is recorded as failed: a file over the
    memory budget is not retried, while a timeout keeps its bounded retries. Every
    other request keeps working. The deadline is VAULT_MESH_WORKER_TIMEOUT_SECONDS
    (default 300 s).

  • Backup history disables replica retries when a run has no completed archive
    record. Its guidance now refers to that run instead of implying that existing
    backup archives have been lost.

  • Storage migration no longer clears destination fields when an obsolete
    startup request finishes after the form becomes editable.

  • Storage migration deadlines now include their UTC timezone, so a fresh plan
    remains usable and source-retention deadlines display correctly outside UTC.

  • Restoring a backup no longer fails because a completed ZIP inspection is
    waiting for file selection. Its staged archive remains available; unfinished
    uploads and imports still block restore until they are settled.

  • Large STL previews frame every source component and preserve ASCII geometry after large translations.

  • Streamed STL previews preserve valid oblique facets that the degeneracy filter could discard.

  • Serialize storage adoption and retirement by immutable reservation generation;
    retain exact cleanup revocations and preserve newer objects at reused keys.
    S3 backup deletion now requires an immutable object version. Failed commit
    acknowledgements preserve already adopted covers, documents and embedded images.

  • Import completion prepares private source-cover candidates and switches their
    visible pointer only under the current Job and Inbox authority.

  • Interrupted downloads, archive extraction and local copies retain exact cleanup
    receipts and disk reservations; restart or retry reclaims their private workspaces
    before the next input is admitted.

  • Recover maintenance capacity when a process dies after committing a Job result
    but before its engine execution finishes, preserving the completed outcome.

Performance

  • Convex hull descriptors use normalized SciPy/Qhull geometry, preserving dense convex surfaces and finite extreme scales while rejecting invalid coordinates. Existing fingerprints are recalculated.

  • Tag counts now follow collection links when inheriting tags, so listing tags
    stays responsive in libraries with tens of thousands of collections and
    100,000 Models, including for users with collection-specific access.

  • 3MF geometry loads about 1.6 times faster. The bounded 3MF loader read
    every vertex and triangle attribute with a Python call per value; it now
    hands each column to NumPy in one pass. A 320,000-face project went from
    3.1 s to 1.9 s. Memory use is unchanged, and malformed attributes are still
    refused as an invalid package.

  • Splitting a mesh into its separate parts is about three times faster.
    Similarity fingerprints of STL, OBJ and other non-3MF meshes joined connected
    faces one edge at a time in Python; a 500,000-face surface spent 4.3 s there
    and now spends 1.4 s. The parts found are unchanged.

  • Large libraries load their collection tree in about a second. A library
    with 9,000 collections and 40,000 Models took over a minute to show its
    sidebar, because each collection's model count was checked against every
    other collection. Non-administrators' library, tag, collection, document,
    Multipart Model, build, search and similar-model reads no longer send their
    whole list of visible collections with every query. The library sidebar now
    loads one folder level at a time and starts collapsed on a first visit,
    except along the path to the current folder. Move, upload, ZIP review and
    new Multipart Model destinations use search instead of loading every folder.
    Model cards and detail pages receive their folder names from the server.
    Multipart Model browsing loads one folder page at a time; Pending Import and
    Similar Models collection scopes use search. Settings loads grants only for
    the collection an administrator selects, avoiding a permissions request for
    every collection when the page opens.

Full changelog: v0.14.0...v0.15.0

Don't miss a new PrintStash release

NewReleases is sending notifications on new releases.