Repository navigation
feat(viewer): list an element's saved parameters in the info panel, read on selection (#35) (RE-207) - #1468
Merged
Conversation
…ead on selection (#35) (RE-207) Selecting an element shows its saved parameters under "Saved parameters": instance, then type, named ones first, built-ins by id behind a fold that says why they have no name (#255). A new binding, savedParameters, reads them for the selected element in a worker of its own that ends with the answer; the open, and so every export, is unchanged. States: loading, ready, empty, release not read, no ElementId, error with retry, and a button for a file that may not fit twice. File Status's Parameters row no longer says the rest are still to be decoded.
…pare entries by content, cover a selection in the no-network spec (#35) The group was built and never appended, which typecheck caught. savedParameters now makes each entry the way rvt-elements does (serde_json::to_value), and the spec compares entries with their keys in one order. The empty state has a test of its own that looks for an element to show it on, and no-network.spec.ts selects an element and allows only the same-origin assets the parameters worker loads.
viewer-test.yml: main moved the native build into the build job and the legs now take an artifact, so rvt-elements is built beside gen-fixture there, copied into the artifact, and checked to run in each leg. deploy-viewer.yml builds and uploads the artifact its tests and measure jobs download, so it carries rvt-elements the same way.
…office, and list rvt-elements in the build artifact docs (#35) folded-pieces.spec.ts selects the office's first owner again at the end and prints whether the page read its saved parameters on its own or asked first, the entries, the read's time and wasm memory, and the open worker's. It fails on a read that errors. The artifact descriptions in viewer-build-pipeline.md and maintaining.md now name rvt-elements.
…er tests run 42103334445 (#35) Einhoven, Core Interior and the BIM4LCA office: read time and wasm memory against the open's, and the office's selection read on its own. States that the ten-times-size estimate understates a read on the office and that the gate is not corrected for it.
… keep each element's answer (#35) The page read automatically while the ten-times-size estimate plus the open's memory fit the ceiling. On the BIM4LCA office a read took 943 MiB against 616 MiB estimated, 1.04 times the open's worker, so a file of about 166 MiB would have been read with about 2.4 GiB open and 2.5 GiB read at once. The page now reads on selection only while twice the open's wasm memory fits the ceiling, and asks above it. Each element's answer is kept, up to 64 and the least recently selected going first, until a file is opened again, so an element selected twice is read once. tests: the gate at its edge with the ceiling set either side of twice the open's measured memory, an element selected again, a file opened again, and the bound.
…e starts a new map (#35) Run 42106122918 failed only here: the browser raises no change event when a file input is given the file it already holds, so the page never reopened. The gate test, the bound and the office read passed.
…he page keeps, from viewer tests run 42109657349 (#35) Einhoven, Core Interior and the BIM4LCA office against rvt-elements and the open's worker, the gate held at its edge, and what the map holds on the office. The gate follows the open's wasm memory, not the ten-times-size estimate, which the office's read overran.
DrunkOnJava
marked this pull request as ready for review
November 5, 2026 21:29
…n only within what is measured, and the panel's states are tested and accessible (#35) The parameters worker is bundled into the page (?worker&inline, a blob URL; worker-src gains blob:) and starts from the compiled wasm the open's worker hands over with initSync, so a read fetches nothing and an offline page reads. A selection is read on its own only while the page holds at most 1 GiB of wasm memory (the open's and the main thread's), asks first above it with a copy that says clicking may close the tab, and after a read that ran out of memory, or a worker that went without a word (found by a Web Lock it holds), the file is read only when asked. A read for an element no longer shown is ended, and the element being read is not started over. Focus moves to the result, a live region announces, a row says where its parameter is defined, nameless rows are grouped by reason, and Revit 2015 to 2022 are said to be read experimentally. The binding's keys are renamed release_read, release_experimental, releases_read and releases_measured. outOfMemory is shared. tests: no request and offline, the bare unreachable, a worker ended with no word, stray workers, and a real wasm cap on the office.
10 tasks done
…s static, the open's worker is inline, and every use starts from the module the first open compiled (#35) The main thread's exports imported ../pkg/rvt.js and fetched the wasm at the first export click, and opening the file again (another phase, the saved-mesh toggle, the large-model retry) fetched the worker script and the wasm. The glue is now a static import, the open's worker is bundled and starts from a blob URL like the parameters worker, the page resolves the wasm's URL and keeps the module the first open compiled, and the main thread instantiates it with default({module_or_path}), which the main thread allows at any size. tests: no-network.spec.ts clicks an IFC, a plan and a glTF export and reopens the file, and fails on any request; the offline test does the same; worker-failures.spec.ts patches the blob's script instead of routing a worker URL.
… reading (#35) Run 42122623374 passed every other test of the saved-parameters work, the real wasm cap on the office included, and failed only here: a read of Einhoven takes about a quarter of a second, so the worker had answered before the test ended it.
…capped read and the first page load, from viewer tests run 42125048710 (#35) Figures from run 42125048710 on head 3146f14: Einhoven, Core Interior and the BIM4LCA office against rvt-elements and the open's worker, a read really running out of memory under a 927 MiB wasm cap on the office, and the page's one script 40.27 kB (8.65 kB gzipped) larger than in the build of d1de8ad, with the glue and both workers inside it.
DrunkOnJava
added a commit
that referenced
this pull request
Nov 5, 2026
…its model (#1192) (#1484) ## Summary W10 of the 1.0 criteria (#1192): `tools/ci/measured_numbers.py`, the last steps of the PII guard job, fails a number on the README or the supported profile that has no model of a new "Model index" table in `docs/reference-models.md` within 300 characters in its own clause, or a number on a `local only` or `not shared` model without those words beside that model's name, or an index row that does not say who can fetch its model. The pages are edited until they pass, and the figures the second read found stale are updated. One Measure dispatch is documented as the command that re-runs the numbers on the models anyone can fetch. The criteria's W10 row records both and stays **not measured**. ## Motivation W10 was not measured because nothing checked that a number names its model (#1192). Several figures rest on models nobody else can fetch (Snowdon Towers' exports, the MIT house, the 255ribeiro projects, flowbim's house, the pre-2015 files, the client models), and a reader could not tell which. ## Changes - `tools/ci/measured_numbers.py` and `tools/ci/test_measured_numbers.py`; three steps at the end of `ci.yml`'s `pii-guard` job (the check, `--refusals`, the failure-first tests). - `docs/reference-models.md`: the Model index (19 models, four fetchability words) and "Re-run the numbers" (the Measure dispatch, what it covers, what it does not). - `README.md`, `docs/supported-profile.md`, `docs/evidence.md`, `docs/support-matrix.json`, `docs/release-1.0-criteria.md`: models named, `local only` and `not shared` said, eight clauses marked `<!-- w10: reason -->`, the stale saved-mesh figures replaced, and a sentence on how to read the figures. - `docs/maintaining.md`: "Numbers on the README and the supported profile". - `changelog.d/changed/1192-numbers-name-their-model.md`. ### The rule Every numeral on the two pages, in a heading as in a cell, is a number except what its spelling marks as an identifier (an issue, a report, a hash, a date, a Revit release or other year, a Measure run id, a layout width, a tool's version, the 1.0 release). It needs a name from the index within 300 characters in its own clause (between semicolons and sentence ends, never split inside parentheses; each cell, item and heading its own unit). `local only` / `not shared` must stand beside that model's name (within 60 characters and nearer to it than to another model's name; "both" and "all" reach back). A number that is not a measurement carries `<!-- w10: reason -->`, which fails without a reason or with nothing to excuse, and the failure message says so. No allowlist. A pattern for measurements would miss the next form someone writes; this fails any new form until it names a model. What it cannot catch (stated in `docs/maintaining.md`): a number placed near the wrong model's name, a number that is not true or not current, a measured count inside a code span that is more than a number, a figure spelled out in words, and the pages other than these two. ### Second read, and what I changed - **Stale figures updated, not relabelled.** The BIM4LCA office's 1,294 of 1,709 and RE1's 207 and 148 of 214 (Measure 40192112285, October) are now run 41850769925's at `e024f03c`, which RE-304 and RE-331 section 4.4 agree on, and which I re-totalled from that run's scorer files: the office 1,554 of 1,650 exact as built and 1,638 of 1,738 at permit (265 of 269 doors and all 269 windows exact as built, run 41850758987 for the default export, RE-331 section 4.1), RE1 148 of 228 exact (Architecture 45 of 53, Electrical 31 of 47, Mechanical 65 of 68, Plumbing 7 of 60) and 228 of 228 within 0.01 ft of Revit's box. The "221 of 269 doors keep their box" and "1,294 of the 1,352 bodies then drawn" sentences are gone. **Core Interior: your note said 158 of 158 stands; run 41850769925 scores 138 saved-mesh bodies there (132 doors, 6 windows) and no shading device, and RE-331 says 138, so the pages now say 138 of 138.** RE-78's 158 counted 20 shading devices; I did not find why they are no longer scored. Snowdon Towers' 3,332 of 3,736 stays, labelled as RE-78's local run not re-run since. - `profile` 8 files' ElementIds: now the one Revit-side check from #421 (2026-11-04), with its counts; the other 7 are not checked. - 1,030 and 724: cited to #446, not RE-70 to RE-74 (also on `docs/evidence.md`). - `--large-model`: the source's presets (2 GiB per stream, 8 GiB inflate on 64-bit), marked. - Beams and landings hold on 28 Revit 2025 models, arcs on 25 (README, profile). `docs/compatibility.md`, `docs/evidence.md` line 15 and `docs/support-matrix.json` lines 395, 422 and 440 still say 25 for the beam and landing claims; outside the two pages, not changed. - 923 of 942 Snowdon beams: the fetched samples (run 41787230413, RE-328 section 3), no longer local only. - Index rows: the MIT house (the course page serves it, no script fetches it), 255ribeiro (GitHub repository, no script fetches it), Vitoria (`ALD26 Before` is spent and measured in full, the rest held out); W10 row "none was cut"; fork dispatch and `-f ifc_flags=` figures stated as untried and not covered; the "nobody has re-run and compared" caveat is on the README and the profile. - A pull request that moves a figure edits the page: `docs/maintaining.md`. - Check: parentheses, headings, proximity, local-only nearness, the marker way out in the message, steps last. ### Numbers that could not be traced to a run, or only weakly - **Snowdon Towers' 1,030 of 1,078 walls and 724 of 1,078 ends:** only in #446's description (a local run, 2026-09-27) and `docs/evidence.md`; kept, labelled "not re-run since". If you want them gone it is one phrase in the Walls row. - **Client-model counts:** #421 (comments of 2026-10-28, 2026-11-02, 2026-11-03, 2026-11-04) and #1075 (2026-11-02); the reporter's counts on files nobody else has. - **Snowdon Towers' 3,332 of 3,736 within 0.01 ft:** RE-78 (a local run, not re-run since); CI cannot re-measure it. - Spelled-out counts are not read; I named the models behind those in the By-input table and the README by hand. ## Testing Unit tests are banned here; the one exception is a pure helper, and `test_measured_numbers.py` is that (35 cases, failure-first, no file or network I/O; the first 28 are unchanged). - [x] No Rust changed; `tools/check-local.sh` N/A (CI is the build) - [x] End to end on the real pages: `python3 tools/ci/measured_numbers.py` passes (255 of 271 numbers name a model, 8 clauses marked). On the pages as they were at `f009976e`, the first form of the check failed 51 clauses. - [x] `python3 tools/ci/measured_numbers.py --refusals` copies the pages and the index to a scratch directory, appends or breaks one thing each time, and the check refuses it for the stated reason: a number with no model, a local-only model that does not say so, a local-only word beside another model's name, a number far from its model in a long clause, a number in a heading, a marker with no reason, a marker with nothing to excuse, an index row with no fetchability. It runs in CI. A scratch copy with ", and 4,321 more beams" added to the 3,592-character Properties clause also fails. - [x] 22 mutations of the script (longest name, flag surviving its unit, stale marker, no reason required, years, thousands comma, link targets, hashes, heading rule, headings skipped, name boundary, any word flagging, flag to every nearby name, unbounded flag gap, "both" and "all" ignored, unbounded proximity, split inside parentheses, glued unit, number-only code span, `2D`, numberless clause needing a flag, message without the marker way out), each run against the tests in a scratch copy: all fail them. - [x] `changelog.py check`, `api-doc-ids.py`, `readme-matrix.py --check`, `wasm-api.py docs`, `render-mcp-tools.py --check`, `check-workflows.py` (PyYAML in a scratch venv, 0 errors) pass; the matrix is valid JSON; the script and tests also pass on Python 3.11 and 3.12. - Not run: `actionlint` (the environment's command filter refused it) and CI itself, the first run of the new steps on a runner. - Not measured: that the re-run command reproduces the pages' figures. Nobody has compared; the dispatch is the one the cited runs were made with. I did not dispatch Measure. ## Audit-honesty checklist - [x] README / docs reflect the current state after this PR - [x] Changelog fragment under `changelog.d/changed/` - [x] No new limitation beyond those stated above - [x] No emojis; no private paths or personal email addresses in committed files - N/A: no reverse-engineering finding ## Legal and contribution hygiene - [x] Apache-2.0; no Autodesk source; no fixtures added ## Breaking changes None for users. A pull request that adds a number to the README or the supported profile without a model fails the PII guard job (`docs/maintaining.md`). Open pull requests that touch these pages pass their own CI until their next run after this merges, and #1468 (12 bindings becomes 13) will meet the marker at README line 85. ## Related issues Refs #1192. Not `Closes`: the third done-when item is the maintainer setting W10's bar, and the row's status records the result without moving *proposed*.
8 of 15 tasks
# Conflicts: # README.md
DrunkOnJava
enabled auto-merge (squash)
November 6, 2026 00:14
DrunkOnJava
added a commit
to puzzbobb/rvt-rs
that referenced
this pull request
Nov 6, 2026
Main moved by DrunkOnJava#1468, DrunkOnJava#1477 and DrunkOnJava#1481; the addenda of RE-353 and RE-362 both stay.
DrunkOnJava
added a commit
that referenced
this pull request
Nov 6, 2026
#1499) (#1504) ## Summary CodeQL's `analyze` job retries a failed SARIF upload once, in a job of its own, with the same shape #1461 gave Scorecard and zizmor. A real rejection of the file still fails the run. ## Motivation #1499: `Analyze (rust)` failed on #1468 (CodeQL run 42128776536) at `github/codeql-action/analyze` with the log ending at "Uploading results" and no finding. `arm.sh` refuses a head with a red check, so the landing waited for a hand rerun. ## Changes `.github/workflows/codeql.yml` and `docs/maintaining.md`; the matrix stays the four languages and the check names `Analyze (<language>)` do not change. - `analyze` gets `upload: failure-only` and `output: ${{ runner.temp }}/codeql-sarif`: it writes the SARIF, with the category already in it (analyze passes `category` to the CLI as the SARIF category), and does not upload it. At the pinned commit (v4.39.1, `analyze-action.ts`) analyze post-processes and writes the files for every value of `upload`, and sends them only for `always`; the one-category-per-job sentinel is set only by an upload (`validateUniqueCategory`, inside `uploadPostProcessedFiles`), so `failure-only` leaves the later upload step free of it. It is `failure-only` and not `never` because `never` makes `init-action-post-helper.ts` (`prepareFailedSarif`) skip the failed-run SARIF when the analysis itself dies, and analyze's `action.yml` calls `never` not recommended. It still saves the overlay base database on `main`. - A step of its own, `Upload the results to code scanning` (`upload-sarif`, same category, `continue-on-error: true`, waits for processing as analyze did), uploads that directory. Its failure does not fail the leg. - `Keep the SARIF for the retry` runs only when that step failed and uploads the directory as the artifact `codeql-sarif-<language>` (7 days, `overwrite: true` so that "Re-run all jobs" can replace the one an earlier attempt left; an artifact name is taken once per run). A healthy leg leaves no artifact. - `analyze-retry` (new job, `needs: analyze`, runs when `analyze` succeeded; skipped on a draft and when a leg really failed) downloads `codeql-sarif-*` into one directory (`merge-multiple`, since a single match is otherwise not put in a directory of its own) and, for each language whose SARIF is there, uploads it once more with that language's category, the matrix input the leg has (`{"language": "<language>"}`, as `toJson(matrix)` writes it) and `CODEQL_ACTION_ANALYSIS_KEY: .github/workflows/codeql.yml:analyze`, so the retry is the same configuration in code scanning and leaves no second one holding alerts. The steps are one per language, each `if: ${{ !cancelled() && hashFiles('retry/<codeql language>.sarif') != '' }}` (javascript-typescript's file is `javascript.sarif`): a rejected file fails its step and the job, and the next language is still tried. - The job's last step, `Fail on a SARIF no step above uploads`, fails on a kept `retry/<name>.sarif` that no `sarif_file:` of the workflow names, so a language added to `analyze`'s matrix and not to the retry cannot pass with its kept results unsent. It reads the steps from the job's own checkout, not from a second list of names. - The retry job holds `contents: read` and `security-events: write`. It does not hold `actions: read`: with the analysis key set, the only call `upload-sarif` makes about the run (`GET /repos/:owner/:repo/actions/runs/:run_id`, `getWorkflowRelativePath` in `api-client.ts`) is not made, and the other `actions` API call in the action's source is the cache listing `analyze` uses. - Why a job of its own: codeql-action's `upload-lib.ts` exports a sentinel into the job's `GITHUB_ENV` before it sends anything and refuses a second upload of one category in a job ("only one run of the codeql/analyze or codeql/upload-sarif actions is allowed per job per tool/category"), so a second step would fail at once whatever the first died of. Shown by #1461 (run 42096477400). - Why the artifacts say which leg failed: a matrix job's outputs are one set shared by its legs (the last to finish sets them), so a leg cannot report its own failure through them. The cost is one job on each non-draft run that does a checkout and an empty download when nothing failed. - `docs/maintaining.md`'s CodeQL bullet names the retry job. - The SHA pins are the ones the file and #1461 already use (`upload-sarif` at the pinned v4.39.1, `upload-artifact` v7.0.2, `download-artifact` v8, as in `scorecard.yml`). ## Left alone - The retry covers a short outage, as #1461's do: a new job starts seconds after the first fails. It does not cover a long one, or a file code scanning rejects (a 422), which fail both and fail the run. The cause of #1468's failure was not recorded in the log (it ended at "Uploading results"), so that it was a transport failure is an inference, as it was for #1461. - On a pull request the retried upload skips the post-filter that drops alerts outside the diff: `filterAlertsByDiffRange` (in `postProcessSarifFiles`, `upload-lib.ts`) reads the diff-ranges file from the leg's own `RUNNER_TEMP`, which the retry job does not have, while the first attempt, in the leg's job, applies it. The query-time `restrictAlertsTo` of the diff-informed analysis still narrows the results, so the retried file is the one the analysis wrote, not the one the post-filter would have trimmed further. - A re-run of the run (all jobs) can find an artifact an earlier attempt left and upload that file again; the same commit and category replace it. ## Testing Unit tests are banned in this repository: do not add them. Show the change working end to end on real files instead. - [ ] `tools/check-local.sh` passes. N/A: CI-only change; no local compute on this lane. - [ ] Verified end to end on real Revit files. N/A: no Rust or reader change. - [ ] If this touches the IFC exporter. N/A. - [ ] If this is a performance change. N/A. On this head (`4837ed23`): - `actionlint` exits 0. `python3 tools/ci/check-workflows.py`: 0 errors, 0 warnings (66 jobs run steps in 17 workflows, the new job has its timeout). `zizmor` 1.32.0 offline over `.github`: 45 findings (2 ignored, 37 suppressed, 6 medium: the Dependabot 3-day cooldown), the same count as `origin/main`; at the pedantic persona the retry job has no finding. The first version of the retry steps passed the matrix input as `toJson(fromJSON('{...}'))`, which zizmor reports as obfuscation, so it is written out. - First proof, on the first version (`upload: never`, `actions: read` held, a list of file names in the last step; run 42130620963, scratch branch, a copy of this workflow with the trigger `push` on that branch, the matrix cut to `actions` and `python`, and in the first upload of both legs `CODEQL_ACTION_ANALYSIS_KEY` set, so that the action needs no API call before it sends the file, and `token` set to a refused one for the `actions` leg only): the `actions` leg's upload logged `Post-processing sarif files`, `Uploading results`, then `Bad credentials`, failed, and the job stayed green; `codeql-sarif-actions` was kept; `python`'s upload succeeded and left no artifact; the retry job warned, uploaded `retry/actions.sarif` (`Successfully uploaded results`, `Analysis upload status is complete`) and skipped the other languages; code scanning listed the retried analysis with category `/language:actions`, analysis key `.github/workflows/codeql.yml:analyze` and environment `{"language":"actions"}`, the same three values `main`'s `actions` analysis has. - Second proof, on the changes of the second read (`upload: failure-only`, no `actions: read`, `!cancelled()`; run 42133787781, scratch branch, the same copy with the matrix `actions`, `javascript-typescript` and `python`, every first upload given the refused token, the retry of `actions` given a refused token as well, and the python retry step removed): all three legs' uploads failed with `Bad credentials` after `Uploading results` (so `analyze` under `failure-only` had not uploaded, and set no sentinel) and the jobs stayed green; the three artifacts were kept; the retry job (permissions `contents: read` and `security-events: write` only) downloaded the three, warned for each, failed the `actions` retry step on the refused token, still ran the `javascript-typescript` retry step, which uploaded (`Successfully uploaded results`, `Analysis upload status is complete`), skipped rust, and the job ended `failure`, so the run did. That is a real rejection staying red with the next language still tried, and the upload working without `actions: read`. - That run's last step was the first version of it, which listed the file names and so passed for the python SARIF whose upload step I had removed; it now reads the steps from the workflow. Its script, taken from the workflow, run with bash on fake kept files: no file exits 0; `actions`, `javascript`, `python` and `rust` exits 0; a kept `go.sarif` exits 1 with the error naming it; the workflow with the python step's `sarif_file` renamed and a kept `python.sarif` exits 1. Not run on a runner. - Both scratch runs' analyses on their refs, their artifacts and the two scratch branches were deleted afterwards (their commits were never on this branch). - Not exercised: the real workflow's own run. CodeQL runs on this pull request once it is ready, so the first run of `upload: failure-only` followed by the upload step, the retry job finding nothing, and all four languages on the real file is the CI run of this head; a retry of `rust` (the shape is the others', with `rust.sarif`'s name taken from a run's log); `overwrite` on a re-run. ## Audit-honesty checklist - [x] README / docs reflect the current state after this PR (`docs/maintaining.md`, and the workflow's header comment says what the retry is and why) - [ ] A user-visible change has its entry as a fragment under `changelog.d/<section>/`. N/A: CI only, as agreed for #1457. - [ ] If a limitation was resolved, the "Known limitations" section is updated. N/A. - [x] If a new limitation was introduced, it is documented in the PR body (Left alone) - [x] Commit messages describe WHAT changed and WHY - [x] No emojis in code, docs, or commit messages - [x] No private paths, personal email addresses, or internal jargon in committed files - [ ] Reverse-engineering finding. N/A. ## Legal and contribution hygiene - [x] I agree this work is licensable under Apache-2.0 - [x] This PR contains no Autodesk proprietary source, decompiled internals, or NDA'd SDK content - [x] Any new test fixtures use synthetic values ## Breaking changes None. ## Screenshots or output samples See Testing. ## Related issues Closes #1499
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The viewer's info panel lists a selected element's saved parameters (RE-207): instance, then type, named ones first, nameless ones behind a fold grouped by why they have no name (#255), each row saying where its parameter is defined. They are read for that element only, on selection, by a new
savedParametersbinding in a worker of its own; the open and every export are unchanged. File Status's Parameters row no longer says the rest are "still to be decoded".Nothing is requested once the first file is open (Griffin, 2026-11-05, "Keep the claim, no request"): selecting an element, exporting IFC, plan or glTF, and opening the file again fetch nothing, and a page taken offline after it loaded does all of them.
Motivation
The last open acceptance item of #35 that is not blocked: "Viewer info panel displays them in readable form". The CLI, Python and IFC (
--revit-property-sets) expose the saved parameters; the viewer showed a count and a sentence that RE-207 had already made wrong.Changes
rvt-wasm/src/lib.rs,rvt-wasm/Cargo.toml,Cargo.lock:savedParameters(bytes, ids, limits)returns JSON text: each entry isserde_json::to_valueof the parameternative_element_parameters::readgives, the callrvt-elementsmakes, with the release and how far it is read.rvtgetsunstable-researchhere, which "adds paths and changes nothing else" (src/research.rs); no file undersrc/changes, so no export can move, andarm.sh'ssrc/gate path does not matchrvt-wasm/src/. The result's keys are a 1.0-stable surface (RELEASE.md):release,release_read,release_experimental,releases_read,releases_measured,elements,unresolved_family_slots,instance_parameters_without_value. I chose them to say what they mean (not the research module's "native"): the read range, the measured range (Revit 2015 to 2022 are read experimentally, RE-281), and what could not be listed.idsis aFloat64Array.viewer/src/parameters-worker.ts,viewer/src/saved-parameters.ts,viewer/src/wasm-failure.ts(new; the out-of-memory test both workers use),viewer/src/worker.ts,viewer/src/main.ts,viewer/src/styles.css,viewer/index.html,viewer/src/env.d.ts: the panel group and its states (loading, ready, empty, release not read, experimental release, no ElementId, error with Try again, read-when-asked), the page's map of answers, focus and a live region, the status row text, and the no-request mechanics below. The "Not recovered" note for an element with no IFC property set now says "IFC property sets".viewer/tests/parameters-row.spec.ts,viewer/tests/no-network.spec.ts,viewer/tests/worker-failures.spec.ts(now patches the inline worker's blob where it routed a worker URL),viewer/tests/folded-pieces.spec.ts(prints what a read does and what the page keeps on the BIM4LCA office, and fails if the read errors)..github/workflows/viewer-test.yml,.github/workflows/deploy-viewer.yml: after ci(viewer): build the WASM once per run, and test the file Deploy viewer publishes (#1457) #1458,--bin rvt-elementsis built besidegen-fixturein thebuildjob, copied into the artifact and checked to run in each leg; Deploy viewer builds and uploads its own artifact fortestsandmeasure, so it carries the binary the same way. A localpnpm test:browserneedsrvt-elementson PATH (viewer/README.md); theparameters-rowspecs skip without it locally and fail in CI.docs/viewer-api.md,docs/viewer-privacy-posture.md(the CSP change, below),README.md(13 bindings),docs/status.md,docs/support-matrix.json(it also drops the "wall's or floor's type parameters are not joined" caveat RE-256 made stale),docs/evidence.md,docs/export-diagnostics.md,docs/user-guide.md,docs/viewer-build-pipeline.md,docs/maintaining.md,viewer/README.md, andchangelog.d/added/35-viewer-saved-parameters.md.Design
A worker of its own, nothing resident.
extractis a pass over the file, so the read is lazy, per selected element. The open's worker keeps noRevitFileand no bytes: a held handle would keep the file's bytes and every partition it inflates for the session, and its reads would hold up the panel (Core Interior's take seconds). Instead the page opens a worker for one element, which reads theFilethe page already holds, calls the binding, answers and is terminated, or is terminated at once when another element, a storey or a scaffold panel replaces the group. wasm linear memory only grows, so ending the worker gives a read's memory back. A worker the browser ends with no word (no event) is found by a Web Lock it holds, so "Reading" cannot show for ever.No request once the file is open; the CSP change. The page's
worker-srcwas'self'; it is now'self' blob:, and nothing else in the policy moves (docs/viewer-privacy-posture.mdsays so and why). Both workers (the open's and the reader) are bundled into the page (?worker&inline) and start from blob URLs; the decoder's glue is a static import (the main thread's exports used toimport()it, and fetch the wasm, at the first export click). The first open's worker fetches the wasm once, compiles it and hands the module to the page, which keeps it: the next open (another phase, the saved-mesh toggle, the large-model retry), the readers (initSync({ module })) and the main thread's exports (default({ module_or_path }); the main thread does not allowinitSyncof a large module) start from it. The lazy loads inviewer/srcthat could run after the open were:import('../pkg/rvt.js')(static now),new Worker(new URL('./worker.ts', ...))(inline now), the worker'sfetch(new URL('../pkg/rvt_bg.wasm', ...))(the page resolves the URL once, and fetches only at the first open). Opening a gallery demo still fetches the demo, which is an open.First page load. The page's one script is 999.56 kB (271.47 kB gzipped) against 959.29 kB (262.82 kB) in the build of
d1de8adf: 40.27 kB, 8.65 kB gzipped, more, mostly the glue and the two workers it used to fetch later; the built site holds one script, one stylesheet and the wasm.When a selection is read on its own. A read has taken 0.74 to 1.04 times the open's wasm memory, and the ratio rises with the file (Einhoven 23 MiB, Core Interior 326, the office 910). Nothing above the office has been measured, so a selection is read on its own only while the wasm memory the page holds (the open's, plus the main thread's instance if an export made one) is at most 1 GiB (a quarter of
?memoryCeilingBytes=where that lowers the 4 GiB ceiling), and above that the panel asks first with a button whose copy says clicking may close the tab: a renderer out of memory takes the tab and the model with it, with no error. After a read that ran out of memory, or a worker that went without a word, that file is read only when asked. This replaces the rule that two instances stay inside the ceiling, which extrapolated past what is measured.What the page keeps. Each element's answer, in a map on the page: at most 64 (
?parametersRemembered=lowers it for the test), the least recently selected going first, emptied when a file is opened. Selecting an element again starts no worker. On the office after the test's selections it held 2 answers, 4,654 characters of JSON (the entries are small; the answers there have 8 entries).Testing
Unit tests are banned in this repository: none added. Measured in Viewer tests run 42125048710, dispatched on head
3146f14e6fcf221adc4f632ac1a5cfa31a3b885d(the merge of main with #1457's changes included),release_wasm=false, on a CI runner: success in all three legs,check-wasm-in-site.shfinding the one wasm sha256 in the site in each. Deploy viewer run 42125109395, dispatched on the same head, on the release (LTO) wasm: success. Itstestsjob passed all 61 tests of the suite (the whole of it, on the wasm the site publishes), itsmeasurejob 6, andcheck-wasm-in-site.shfound the artifact's one sha256 (d2b60a7e…) in the built site in each of the three jobs that build it; the page's one script is the same size as in the viewer tests' build (999.56 kB, 271.47 kB gzipped). On the office with that wasm a read took 3.3 s in 942 MiB beside the open's 910 MiB, on selection, and the page kept 3 answers, 4,929 characters; the real capped read ran out of memory as in the other run. (deployis skipped on a branch, by design.) This PR's head is3146f14eplus documentation (the figures, in the changelog,docs/status.mdanddocs/viewer-api.md) plus a merge of main as it stood at #1470, whose export changes (#1456, #1470,src/ifc) were not part of either run; the full CI of the ready PR runs the viewer tests on this head. Earlier runs on earlier code are not counted; Deploy viewer 42122627698 and viewer tests 42122623374, on7663a4f3, each failed once, in the test of a worker ended with no word, which ended a worker that had already answered (a read of Einhoven takes a fraction of a second); the test now holds the file back first.viewer/tests/parameters-row.spec.ts, in the viewer's leg 1/3 (no new spec file). The oracle is the command line: the test runsrvt-elementson the same file.rvt-elements, whole entriesAlso in the spec (each passed in 42125048710):
--wasm-max-mem-pages, the pattern ofmemory-ceiling-capped.spec.ts) opens the office (910 MiB) and the read (943 MiB) really runs out: the page says "The tab ran out of memory reading the file a second time (unreachable)... read only when asked from now on", and the next element asks. A read of Einhoven cannot fail after its open succeeds (17 MiB against 23), so the office is the only file in CI where a cap separates the two.rvt-elements', an IFC, a plan and a glTF export are made, the file is opened again (the saved-mesh toggle), an element is read again, and no http(s) request was made.no-network.spec.tsruns the same exports and re-open, and a selection, in phases that allow nothing, and fails if the sample has no element to select, if the wasm is fetched to boot the page or more than once.unreachablebranch and its copy, and the file read only when asked afterwards; a worker ended with no word, with the file held back four seconds so it is still reading; a read for an element no longer shown ended (another element, a storey), and the shown element's read not started over by selecting it again; an element selected again starting no worker; a copy of the file opened under another name emptying the map; the bound; a read that fails with a panic, with Try again, and focus on the result; the empty state; the Parameters row text; Revit 2013 (the worker's answer replaced) and Revit 2019 experimental (replaced).Not verified:
release_readfalse;release_experimentaltrue). They test the page's rendering only. The Rust branches (NATIVE_RELEASES.contains, the measured range) are not exercised by any file.tools/check-local.sh, clippy andtools/ci/check-workflows.py(no local compute; PyYAML is not installed here); CI's fast jobs on this PR are the check. The wasm network-import audit passed in the viewer legs.u32::MAX: the binding reads it, the command line lists such elements asid: null, so nothing compares them.rvt-elements; only that its read does not error. The gate is held at its edge on Einhoven's open memory; no file between 910 MiB and the 4 GiB ceiling is in the viewer's job, which is why the limit is the measured 1 GiB.no-network.spec.tsmay not see worker requests; the offline test, which records every request and fails any, is what covers them.Breaking changes
None. A binding is added (
tools/ci/wasm-api.py compathas nothing to flag); no existing binding or output changes. Theworker-srcof the page's Content-Security-Policy gainsblob:.Related issues
Refs #35 (#255 and the family built-in slots stay open).