View on GitHub

IntaRNA

Efficient target prediction incorporating accessibility of interaction sites

Step 4: results and Pages deployment (#286)

Results contract

The CSV checklist covers all OutputHandlerCsv column IDs. The worker requests those columns plus internal target/query IDs, coordinates, energy and hybridDP needed for pair grouping, result validation and visualization. Downloads project the untouched native CSV cells onto the user’s selected columns, in selection order, retaining every row regardless of table filtering/visibility. No computed mfe difference is inserted into native CSV. The selected-column catalog is checked against the C++ mapping.

Native output is unquoted and semicolon-delimited. Semicolons in IDs become underscores; quotes remain literal. The parser checks column IDs, finite core energy/coordinate values, integer inclusive coordinates and ascending bounds. Signed coordinates are allowed. Optional NAN and colon-separated seed lists remain strings; numeric sorting puts unavailable/list values after numbers.

Sequence 1 is target, sequence 2 is query. Energy uses kcal/mol. The computed mfe Δ is E - min(reported E for the same query–target pair), rounded to hundredths. Evaluation uses the best supplied structure as its reference. This is relative suboptimality, not a free-energy change or probability.

Every heading is a keyboard-operable sort button with aria-sort; its hover tooltip repeats the matching CSV-selection description. Search covers all returned values. A separate checklist shows/hides table columns after the run; it does not change selected CSV output. All identifiers, output previews and diagnostics render with textContent. The table has a 500 px maximum height with vertical scrolling for longer results and a sticky heading; CSV downloads still contain every selected row. Selected extra files appear below the table with their original filename, covered sequence/sequence-pair names, a header-level download, and bounded text previews, including SVG source. Empty output is successful and still permits CSV/accessibility downloads.

Additional output visualizations

Plot-capable additional CSV files open on a Visualization tab, with the original File Content in an adjacent tab. Query/target minimum-energy and spot-probability profiles use line plots; pair minimum-energy and all-spot probability matrices use heatmaps; explicitly requested spot probabilities use a bar plot. Plot axes use the literal coordinate strings from IntaRNA rather than numerical scales, so signed indices cross from -1 to 1 without inventing coordinate zero. Plot titles and additional-file headers identify the target/query records covered by native -t#q# or -s# filename suffixes.

Plotly renders locally from the pinned Cartesian bundle. A separate Export PNG button uses the active plot’s current dimensions. The plotting area can be resized from its lower-right corner, and matrix plots provide Swap X/Y to transpose query and target axes without changing the data. The normal file download and reproducible ZIP retain untouched native data. Plots render lazily when their file is unfolded, resize with restored sessions, and are purged when a session is deleted. Non-plot formats keep the direct content view.

Selected interaction in vaRRI

Each row has a keyboard-accessible View button; clicking a row also selects it. When computation returns interactions, the first row in the initial energy-sorted table is selected and visualized automatically. Selection survives table sorting, filtering and visibility changes within each session. Input edits, new runs, errors and cancellation preserve prior sessions and their archive snapshots. Folding a session unloads its viewer; reopening restores its selected interaction. visualization.js uses native seq1 = target, seq2 = query and maps the native CSV identifiers to the completed run’s normalized FASTA records (including semicolon-to-underscore ID conversion). It pads the interaction dot-bracket structure with unpaired positions to the full input lengths, using each start index and the native negative-to-positive transition that skips zero. When all four seed-boundary columns are present, each reported seed is passed to vaRRI as a translucent purple paired-region highlight. Prediction defaults select those columns; custom CSV selections without complete boundaries omit highlights.

The URL follows vaRRI’s embedding API: sequence, structure, seqName1/2, startIndex1/2, and showRenderingOnly=true. Names use the main-v2 API; older deployed vaRRI versions may retain generic strand names. A separate Open in vaRRI link opens the full viewer. The local status always identifies the selected pair and coordinates. Zero-based CLI start indices remain accepted for computation/export, but vaRRI requires nonzero start indices; choosing View for such a run explains this limit.

The first successful interaction result loads the external viewer automatically; choosing another row shares that pair and structure through vaRRI’s URL. Computation and ZIP generation remain local. CSP permits frames only at the vaRRI deployment; the iframe sends no referrer. Viewer availability depends on that external site; the full-viewer link permits retry, and scientific outputs remain downloadable.

Reproducible ZIP download

Download ZIP sits in each session header, including while its output is folded. archive.js creates a standard UTF-8, uncompressed ZIP with CRC-32 checksums locally, without a library or CDN. It uses the completed request and result, independent of table sorting/filtering and column visibility. Editing inputs preserves every completed snapshot.

The archive contains only parameter.json, intarna-interactions.csv, and every generated additional output with its original filename and contents. JSON embeds normalized FASTA and any SHAPE/accessibility text, non-default settings, selected CSV columns, compiled provenance and native replay commands in _comment. Additional report commands override CSV-only settings and use another native invocation, matching the worker. All JSON is valid with standard parsers.

Load/Store use this same JSON format. Store snapshots the current editable form; ZIP snapshots the completed run and ignores table filtering/sorting/visibility. Store requires the compiled version file. Completed sessions still retain their results if that file is unavailable, recording the missing version information explicitly in JSON. See the JSON workflow.

Packaging and deployment

bash scripts/wasm/build.sh
node scripts/wasm/smoke.mjs
node scripts/wasm/smoke-protocol.mjs
bash scripts/wasm/stage.sh
npm test --prefix gui
python3 -m pip install -r scripts/wasm/requirements-browser.txt
python3 -m playwright install chromium firefox
python3 -m http.server 8765 --directory build-wasm/site
# In another terminal:
python3 scripts/wasm/test-browser.py http://127.0.0.1:8765
python3 scripts/wasm/test-browser.py http://127.0.0.1:8765 --browser firefox

The staging script includes matched WASM assets, only the application source files needed at runtime, compiled version metadata and dependency notices. It also verifies and stages the pinned Plotly.js 4.1.2 Cartesian bundle and MIT license plus the Pyodide 314.0.7 core runtime and MPL-2.0 license; no CDN is used. Build-time build-info.json and build-info.txt record actual CLI IntaRNA/ViennaRNA/Boost versions, source commit and tracked modifications, SDK version and asset SHA-256 digests. Staging checks these digests and preserves the original metadata; it never replaces the compiled revision with a later staging checkout. The footer displays versions. It needs the same activated SDK and dependency build directory as the build. No generated WASM or Pyodide artifacts are committed; both runtimes are staged from checksum-verified build inputs. HTTP(S), module workers and WebAssembly are required; file:// and legacy browsers are unsupported. No backend, SharedArrayBuffer, credentials, CDN or cross-origin headers are needed. CSP keeps scripts/styles same-origin and allows ephemeral blob images solely for PNG export.

The existing repository already publishes its user guide and API with Pages. Publishing a second independent artifact would overwrite them. Therefore documentation.yml is now a reusable build (also manually dispatchable), and build-wasm.yml is the single publisher. Both builds run on PRs (including dependent feature-branch PRs) and on the actual default branch, master. After JS tests, the real WASM smoke test and Chromium/Firefox integration tests pass, the package job combines:

The artifact intarna-pages-preview permits PR review of the complete site. Pull requests and manual runs on feature branches do not publish. Only a push or manual run on BackofenLab/IntaRNA’s master may upload the Pages artifact and use the github-pages deployment environment. Pages permissions are scoped to that deploy job. Concurrent deployments are serialized without cancellation.

The repository’s current Pages source is already GitHub Actions. A fork would need that source enabled, its repository guard adjusted deliberately, and an environment allowing its default branch. Existing environment protection rules still apply. After merging this PR, check the workflow’s deploy job and its returned environment URL. This implementation PR does not merge itself or claim that deployment happened before merge.

Validation scope

Node tests cover input boundaries, lifecycle races, parser failures, numeric sorting and suboptimal differences. The WASM smoke test compares a real Turner/default-accessibility prediction with the native reference. Browser integration runs real WASM (no mocked scientific results), checking coordinates, energy, sorting, filtering, CSV download, mobile overflow, abort during download and active C++, clean restart, empty predictions and asset-load recovery.

Local verification, 2026-10-20

GitHub’s platform checks independently cover GCC 14 release/debug and Apple Clang. Deployment itself occurs only after merge; local browser tests do not claim a live Pages deployment.

PR #287 visualization review verification, 2026-10-26

PR #287 review verification, 2026-10-21

PR #287 follow-up verification, 2026-10-22