Skip to content

feat(viewer): open any finding in the genome viewer from the live site or the row itself - #296

Merged
GeiserX merged 4 commits into
mainfrom
pgp/live-viewer
Nov 5, 2026
Merged

GeiserX merged 4 commits into
mainfrom
pgp/live-viewer

Conversation

@GeiserX

@GeiserX GeiserX commented Nov 4, 2026 •

Copy link
Copy Markdown
Owner

The problem

The genome viewer only ran on 127.0.0.1 of the machine that holds the data, with no login. From the live site on a phone or another laptop, the report's "see the reads" links pointed at a port that was not there. In the report itself, only three tables had viewer links, as one line of links under each table, so the Slivar pairs, the AnnotSV class 4-5 SVs, the deep intronic sites, the cDNA scan and the mosaic calls had no way to open the reads.

The fix

  • Viewer on the live site. A new plugin, bin/owngenome_live_viewer.py, serves the same igv.js page for every run at /runs/<run>/viewer/, behind the site's password. It uses the same page, Content-Security-Policy and default files as scripts/owngenome-view.sh: the run folder's BAM or CRAM, VCF and SV VCF, each with its index, plus REF_FASTA. A track whose file or index is a symlink out of GENOME_DIR is left out, with both files. A file name with a space, # or ? is matched after unquoting the request path, as the standalone server does. The served report gets its viewer links pointed there. scripts/owngenome-live.sh passes the reference and igv.js, and downloads igv.js on the first start, checked by sha256. Without a reference index or igv.js the site starts without the viewer and says why. OWNGENOME_LIVE_VIEWER=off leaves the viewer out. Opening the viewer writes one access-log row. The byte ranges write none.
  • One pin. IGV_JS_VERSION and IGV_JS_SHA256 move from scripts/owngenome-view.sh to versions.env, so both launchers read the same pin. docs/versions.md lists only images, so it is unchanged (gen-versions-doc.sh --check passes).
  • A Viewer column on every findings table. ClinVar hits, secondary findings, mitochondrial variants, deep intronic sites, the cDNA scan, AnnotSV class 4-5 and the calls moved to class 3, slivar's pairs in trans, mosaic alterations and Exomiser's ranked variants each end with a Viewer column. It holds one link per row, to the row's position, or a range for an SV, a region or a pair. A note under each table says how to start the viewer. This replaces the single line of links under three tables. Both report paths get it, since bash and Nextflow both render through bin/render_report.py.
  • assets/viewer/serve.py gains sample_files and send_file (the byte-range sender, moved out of the handler), so the plugin reuses them instead of copying them.

Output change, as the 1.0 contract asks: the HTML report gains a column on these tables. No cell is renamed or removed, and the text and JSON outputs are unchanged.

Privacy, said plainly in docs/live-site.md and docs/viewer.md: from the live site the reads cross the network to the browser that logged in. Only the byte ranges igv.js asks for travel, and only after the login. Off loopback, use TLS. The standalone viewer keeps its "no login, do not expose the port" warning.

Decisions taken in this PR

  • A trailing Viewer column, not a link inside the locus cell. The bead says "in the locus cell". Wrapping the locus text in a link would break exact cell pins in five e2e cases owned by other lanes (50-html-report-24.sh, annotsv-report-section-1-chain.sh, clinvar-combined-allele-1.sh, construct-scan-1-both.sh, report-followups-1-sections.sh). One of them is a lacks check that would have gone silently true. A column of its own keeps every existing cell's text and keeps main true. Each row still gets its own link.
  • Renamed paths. The plan names bin/pgp_live_viewer.py and scripts/pgp-live.sh. Since the rename these are bin/owngenome_live_viewer.py (the live server loads only owngenome_live_*.py plugins) and scripts/owngenome-live.sh. The test is tests/test_live_viewer.py, as planned.
  • The page's header line. assets/viewer/index.html says "served from this computer only". The plugin swaps that line for "served by the run site, behind its login" when it serves the page, so the page stays true without editing the shared file.
  • tests/test_isec_columns.sh needed no change: it pins the chromosome, gene and genotype cells, not the end of the row.

How it was checked

CI on head f3189df. Every check except e2e is green. The Guard run's unit-tests job ran tests/test_viewer.py, tests/test_live_viewer.py and tests/test_collect_summary.py with both headless Chrome checks: https://github.com/GeiserX/OwnGenome/actions/runs/41854962919

Local runs on this branch (unit tests only, no containers):

  • python3 tests/test_viewer.py: ALL PASS. That covers the pin read from versions.env with its sha256, no pin left in owngenome-view.sh, a Viewer cell in every findings table, and headless Chrome on the standalone page.
  • python3 tests/test_live_viewer.py: ALL PASS. That covers the login redirect and 401s, the viewer policy, BAM byte ranges (206, 416), refused files and runs (404), report links rewritten to /runs/S/viewer/, one access-log row, a symlinked BAM left out, a site without the flags, and igv.js ready with 3 tracks in headless Chrome.
  • tests/test_collect_summary.py, tests/test_render_report.py, tests/test_owngenome_live.py, tests/test_live_post.sh and the other report tests: ALL PASS.

Red controls:

  • Mismatched pin. With IGV_JS_SHA256 in versions.env changed to a wrong value, tests/test_viewer.py exits 1: [FAIL] owngenome-view.sh: the server starts ... Download attempt 1/3 failed its check: sha256 checksum of igv.min.js is 87b991ae..., expected 000091ae....
  • Exomiser table. With bin/render_report.py of the previous head (no Viewer column on the Exomiser table), the table check names exactly that table: Exomiser ranking: the header does not end with the Viewer column, ... a row whose last cell is not a viewer link to chr3:700, ... no viewer note in the card under the table.
  • Links removed. Inside tests/test_viewer.py, every CI run renders the report with the Viewer cell emptied, and the table check must then name all 10 tables (report: control: ...).
  • Planted mistakes. Inside tests/test_live_viewer.py, every CI run loads four planted copies of the plugin: one serves any file of the run folder, one drops the report filter, one compares the still-quoted file name, one serves an index symlinked out of GENOME_DIR. The checks must fail on each (control: ...).

Beads

pgp-5bja.8, pgp-awpe

Merge order: after paralog-rows (#276) and cross-engine-biallelic (#281), which touch the same report renderers.

The report linked only the ClinVar hits, the secondary findings and the
mitochondrial variants to the genome viewer, as one line of links under
each table. Every findings table now ends with a Viewer column, one link
per row to that row's position: ClinVar hits, secondary findings, mito
variants, deep intronic sites, the cDNA scan, AnnotSV class 4-5 and the
calls moved to class 3, slivar's pairs in trans and mosaic alterations.
A column of its own keeps every other cell's text as it was.

Bead: pgp-awpe
The genome viewer ran only on 127.0.0.1 of the machine holding the data.
bin/owngenome_live_viewer.py serves the same igv.js page for every run of
the live site, behind its password, and points the served report's Viewer
links at it. The igv.js pin moves to versions.env so both launchers share
it. tests/test_live_viewer.py checks the login, the policy, the byte
ranges, the refused files, the report links, the access log and the page
in headless Chrome; tests/test_viewer.py checks every findings table and
reads the pin from versions.env.

Bead: pgp-5bja.8
Bead: pgp-awpe
@coderabbitai

coderabbitai Bot commented Nov 4, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 2 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

Run configuration

Commits

Reviewing files that changed from the base of the PR and between bb4ef0a and 7c62621.

Files selected for processing: 12

  • assets/viewer/serve.py
  • bin/owngenome_live_viewer.py
  • bin/render_report.py
  • docs/24-html-report.md
  • docs/live-site.md
  • docs/viewer.md
  • scripts/owngenome-live.sh
  • scripts/owngenome-view.sh
  • tests/test_collect_summary.py
  • tests/test_live_viewer.py
  • tests/test_viewer.py
  • versions.env
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@GeiserX

GeiserX commented Nov 4, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Nov 4, 2026 •

Copy link
Copy Markdown
Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

…ps tracks with an index out of GENOME_DIR and serves quoted names

The live viewer compared the still-quoted request name with the file name, so a
reference named with a space, '#' or '?' answered 404. It now unquotes it. An
index symlinked out of GENOME_DIR was served; now its track, file and index are
left out. Each new check has a planted mistake that must fail it.
@GeiserX
GeiserX merged commit 0d5f5d1 into main Nov 5, 2026
37 of 41 checks passed
@GeiserX
GeiserX deleted the pgp/live-viewer branch November 5, 2026 08:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant