Skip to content

feat(visualization): add genome browser - #28

Merged
dsk-dev-ai merged 4 commits into
mainfrom
feat/visualization-genome-browser
Aug 10, 2026
Merged

feat(visualization): add genome browser#28
dsk-dev-ai merged 4 commits into
mainfrom
feat/visualization-genome-browser

Conversation

@dsk-dev-ai

@dsk-dev-ai dsk-dev-ai commented Aug 8, 2026

Copy link
Copy Markdown
Owner

Summary

Implements Phase 6.2 — Genome Browser of the GenomeAI Visualization Platform.

This builds on the Phase 6.1 visualization foundation and introduces the first
real biological visualization in GenomeAI: a reusable genome browser for
viewing genomic regions and coordinate-based features.

Features

Genome Browser

  • Genomic coordinate axis
  • Chromosome/contig display
  • One-based inclusive genomic coordinates
  • Genomic region input
  • Region parsing and validation
  • Viewport management
  • Zoom in/out
  • Pan left/right
  • Viewport reset
  • Boundary clamping
  • Basic genomic feature rendering
  • Track/feature lanes
  • Feature labels
  • Loading state
  • Empty state
  • Error state

Architecture

  • Reuses Phase 6.1 VisualizationContainer
  • Strongly typed TypeScript genomic models
  • Reusable GenomeBrowser component
  • Typed genome API adapter
  • Coordinate/viewport utilities
  • Track layout and geometry utilities
  • Debounced per-track data loading
  • Extensible track architecture for future visualization milestones

API Integration

Uses the existing Phase 5 coordinate-search API:

POST /search/{domain}/coordinate

The browser requests only the currently visible genomic interval.

No backend changes were required.

Testing

Added comprehensive frontend coverage for:

  • Chromosome validation
  • Region parsing
  • Coordinate validation
  • Viewport behavior
  • Zoom behavior
  • Pan behavior
  • Boundary handling
  • Geometry/scaling
  • Track layout
  • API adapter
  • Genome Browser rendering
  • Navigation controls
  • Loading/error/empty behavior

Verification

  • make setup
  • make lint
  • make typecheck
  • make test
  • pnpm turbo build

Results:

  • Biome: passed
  • Ruff: passed
  • Pyright: 0 errors
  • TypeScript: passed
  • Web tests: 90 passed
  • Python tests: 1606 passed
  • Production build: passed
  • /visualization route: builds successfully

Dependencies

No new visualization dependencies were introduced.

No:

  • C++
  • WebGPU
  • WebAssembly
  • D3
  • Three.js
  • Cytoscape.js

The implementation uses the existing React/TypeScript/Next.js foundation.

Documentation

Added:

  • Genome Browser architecture documentation
  • Coordinate conventions
  • Viewport model
  • Track architecture
  • API/data flow
  • Navigation behavior
  • Accessibility considerations
  • Future extension points

Updated:

  • Visualization README
  • Visualization roadmap

Roadmap

Completed

  • Phase 6.1 — Visualization Foundation
  • Phase 6.2 — Genome Browser

Next

Phase 6.3 — Gene / Transcript Visualization

Future milestones:

  • Phase 6.4 — Variant Visualization
  • Phase 6.5 — Protein Structure Viewer
  • Phase 6.6 — Biological Network Visualization
  • Phase 6.7 — Scientific Charts
  • Phase 6.8 — Integrated Research Workspace
  • Phase 6.9 — Visualization Performance
  • Phase 6.10 — Visualization Testing & Finalization

Scope

This PR intentionally does not implement:

  • Full UCSC/IGV/Ensembl feature parity
  • Gene/transcript-specific visualization
  • Variant visualization
  • Protein structures
  • Network visualization
  • Scientific charts
  • WebGPU rendering
  • WebAssembly
  • C++ rendering
  • Genome-scale performance optimization

Those belong to subsequent milestones.

Summary by Sourcery

Introduce an interactive genome browser as the first concrete visualization on top of the Phase 6.1 visualization foundation, wired to the existing coordinate-search API and exposed via the /visualization page.

New Features:

  • Add a reusable GenomeBrowser React component with viewport navigation, region input, and per-track lanes for genes and variants.
  • Provide a GenomeBrowserDemo on the /visualization route that connects to the Phase 5 coordinate-search API for live genomic data.
  • Define strongly typed genome models, viewport state, track layout utilities, and a debounced genome browser state hook for coordinate-based feature visualization.

Enhancements:

  • Extend the visualization platform documentation with Genome Browser architecture, coordinate conventions, viewport model, track design, and roadmap updates.
  • Refine the Phase 6 visualization roadmap to mark the genome browser milestone as implemented and adjust descriptions of later milestones.

Documentation:

  • Add dedicated Genome Browser documentation covering scope, data flow, API usage, accessibility, and test coverage.
  • Update the visualization README and roadmap to reflect Phase 6.2 status and capabilities.

Tests:

  • Add unit and integration tests for genome API adapters, region parsing and validation, viewport math, geometry utilities, track layout, the genome browser hook, and the GenomeBrowser component.

Summary by CodeRabbit

  • New Features
    • Added an interactive Genome Browser to the visualization page.
    • Browse genes, transcripts, and variants across genomic regions.
    • Navigate with region input, zoom, pan, reset, and viewport controls.
    • Added loading, empty, error, retry, and accessibility feedback states.
    • Added chromosome and region validation with clear input feedback.
  • Documentation
    • Updated visualization guides and roadmap for Genome Browser availability.
  • Tests
    • Added coverage for rendering, navigation, validation, viewport controls, and track loading.

@sourcery-ai

sourcery-ai Bot commented Aug 8, 2026

Copy link
Copy Markdown

Reviewer's Guide

Implements Phase 6.2 Genome Browser: a reusable, typed genome visualization atop the Phase 6.1 VisualizationContainer and Phase 5 coordinate-search API, including viewport math, region parsing, track rendering, and a demo wired into the /visualization page with comprehensive tests and docs.

Sequence diagram for Genome Browser viewport-driven data loading

sequenceDiagram
  actor User
  participant GenomeBrowser
  participant useGenomeBrowser
  participant useVisualizationData
  participant genome_api
  participant Phase5_coordinate_search_API

  User->>GenomeBrowser: click Zoom in / enter region
  GenomeBrowser->>useGenomeBrowser: zoomIn() / navigateTo(interval)
  useGenomeBrowser->>useGenomeBrowser: update viewport state
  useGenomeBrowser->>useGenomeBrowser: useDebouncedViewport(viewport, debounceMs)
  useGenomeBrowser->>useVisualizationData: loader(interval, signal)
  useVisualizationData->>genome_api: fetchIntervalFeatures(interval, signal)
  useVisualizationData->>genome_api: fetchVariantFeatures(interval, signal)
  genome_api->>Phase5_coordinate_search_API: POST /search/{domain}/coordinate
  Phase5_coordinate_search_API-->>genome_api: items[]
  genome_api-->>useVisualizationData: GenomicFeature[] / VariantFeature[]
  useVisualizationData-->>GenomeBrowser: trackResults updated
  GenomeBrowser-->>User: updated axis and SVG tracks
Loading

File-Level Changes

Change Details Files
Introduce a reusable GenomeBrowser React component and demo wired into the existing visualization page.
  • Add GenomeBrowser component that renders axis, controls, status, and per-track SVG lanes using VisualizationContainer.
  • Implement Browser controls for zoom/pan/reset and region input wired to viewport/navigation logic.
  • Add GenomeBrowserDemo that configures gene and variant tracks and mounts the browser on /visualization.
  • Update visualization page copy and layout to include the GenomeBrowser demo alongside VisualizationDemo.
apps/web/src/components/genome/GenomeBrowser.tsx
apps/web/src/components/genome/GenomeBrowser.test.tsx
apps/web/src/app/visualization/GenomeBrowserDemo.tsx
apps/web/src/app/visualization/page.tsx
Add typed genome domain models, viewport math, geometry, track layout, and chromosome/region parsing utilities as pure TypeScript modules.
  • Define core types for genomic intervals, features, variants, contig bounds, and genome viewports with one-based inclusive coordinates.
  • Implement chromosome normalization/validation mirroring backend patterns.
  • Implement region parser with strict syntax, normalization, and typed error codes for validation failures.
  • Provide pure viewport math (initial/whole-contig viewport, zoom/pan with clamping and min-width) and tests.
  • Provide pixel geometry helpers (scales, tick computation, base-position and region label formatting) and tests.
  • Implement minimal track architecture with greedy non-overlapping row layout and viewport clipping helpers, plus tests.
apps/web/src/lib/genome/types.ts
apps/web/src/lib/genome/chromosome.ts
apps/web/src/lib/genome/chromosome.test.ts
apps/web/src/lib/genome/region.ts
apps/web/src/lib/genome/region.test.ts
apps/web/src/lib/genome/viewport.ts
apps/web/src/lib/genome/viewport.test.ts
apps/web/src/lib/genome/geometry.ts
apps/web/src/lib/genome/geometry.test.ts
apps/web/src/lib/genome/tracks.ts
apps/web/src/lib/genome/tracks.test.ts
Implement a GenomeBrowser state hook that composes viewport navigation with the existing visualization data-loading lifecycle and debounced per-track fetching.
  • Define track loader and track definition interfaces that accept GenomicInterval and AbortSignal.
  • Use useVisualizationData per track to manage loading/success/empty/error states, with refetch capability.
  • Debounce viewport changes before triggering track refetches to avoid excessive API calls during navigation.
  • Expose navigation methods (zoom, pan, reset, navigateTo) that mutate viewport state via pure viewport helpers.
  • Add tests to verify per-track status propagation, debounced refetch behavior, and navigation effects on intervals.
apps/web/src/lib/genome/useGenomeBrowser.ts
apps/web/src/lib/genome/useGenomeBrowser.test.tsx
Add a thin typed adapter over the Phase 5 coordinate-search API for genes, transcripts, and variants, integrated as track loaders.
  • Configure API base URL and coordinate-search domains for the genome browser client.
  • Implement normalization helpers for gene, transcript, and variant search items into strongly typed feature objects, with safe handling of missing/invalid coordinates.
  • Implement POST /search/{domain}/coordinate client with overlap semantics, pagination options, and non-2xx error surfacing via GenomeApiError.
  • Provide fetchIntervalFeatures and fetchVariantFeatures helpers that request only the visible interval and filter unusable records.
  • Add tests that mock fetch to verify request shape, normalization behavior, error handling, and filtering logic.
apps/web/src/lib/genome/api.ts
apps/web/src/lib/genome/api.test.ts
Update visualization documentation and roadmap to reflect Phase 6.2 implementation and describe the genome browser architecture, behavior, and scope.
  • Change current milestone status from 6.1 to 6.2 in visualization roadmap and README, marking Genome Browser as implemented.
  • Document delivered components for Phase 6.2, including coordinate model, viewport math, track architecture, API adapter, and demo.
  • Adjust future milestones table to reflect updated expectations for dense tracks and integrated workspace dependencies.
  • Add dedicated Genome Browser documentation covering scope, data flow, API contract, accessibility, test coverage, and file list.
docs/visualization/roadmap.md
docs/visualization/README.md
docs/visualization/genome-browser.md

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@dsk-dev-ai, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 52 minutes

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

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 0363bfd3-467e-4780-9c73-496810e39492

📥 Commits

Reviewing files that changed from the base of the PR and between e4cd8c2 and 20ab85d.

📒 Files selected for processing (2)
  • apps/web/src/components/genome/GenomeBrowser.test.tsx
  • apps/web/src/components/genome/GenomeBrowser.tsx
📝 Walkthrough

Walkthrough

The PR adds a Genome Browser with genomic types, coordinate parsing, viewport navigation, API adapters, track layout, SVG rendering, browser controls, tests, visualization-page integration, and Phase 6.2 documentation.

Changes

Genome Browser

Layer / File(s) Summary
Genome data and navigation foundation
apps/web/src/lib/genome/types.ts, apps/web/src/lib/genome/chromosome.ts, apps/web/src/lib/genome/region.ts, apps/web/src/lib/genome/geometry.ts, apps/web/src/lib/genome/viewport.ts, apps/web/src/lib/genome/tracks.ts, apps/web/src/lib/genome/*.test.*
Defines genomic data types, chromosome normalization, region parsing, viewport navigation, axis geometry, track layout, and viewport filtering with test coverage.
Coordinate API adapter
apps/web/src/lib/genome/api.ts, apps/web/src/lib/genome/api.test.ts
Normalizes gene, transcript, and variant records and fetches overlapping intervals through the coordinate-search API with pagination, abort handling, validation, and errors.
Browser state and visible-region loading
apps/web/src/lib/genome/useGenomeBrowser.ts, apps/web/src/lib/genome/useGenomeBrowser.test.tsx
Adds debounced viewport changes, independent track loading, abort signals, navigation controls, status values, errors, and retry callbacks.
Genome Browser UI integration
apps/web/src/components/genome/GenomeBrowser.tsx, apps/web/src/components/genome/GenomeBrowser.test.tsx, apps/web/src/app/visualization/GenomeBrowserDemo.tsx, apps/web/src/app/visualization/page.tsx
Renders the genomic axis, gene and variant features, navigation controls, region input, track states, and a chromosome 17 demo on the visualization page.
Milestone documentation
docs/visualization/README.md, docs/visualization/genome-browser.md, docs/visualization/roadmap.md
Documents Genome Browser behavior, architecture, tests, validation commands, and completed Phase 6.2 roadmap status.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant GenomeBrowserDemo
  participant GenomeBrowser
  participant useGenomeBrowser
  participant fetchIntervalFeatures
  participant CoordinateSearchAPI
  GenomeBrowserDemo->>GenomeBrowser: provide viewport and tracks
  GenomeBrowser->>useGenomeBrowser: initialize browser state
  useGenomeBrowser->>fetchIntervalFeatures: request visible interval
  fetchIntervalFeatures->>CoordinateSearchAPI: POST overlapping interval
  CoordinateSearchAPI-->>fetchIntervalFeatures: return coordinate records
  fetchIntervalFeatures-->>useGenomeBrowser: return normalized features
  useGenomeBrowser-->>GenomeBrowser: provide track status and features
  GenomeBrowser-->>GenomeBrowserDemo: render controls and tracks
Loading

Possibly related PRs

  • dsk-dev-ai/GenomeAI#27: Provides the visualization foundation reused by the Genome Browser and updates the same visualization page.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 54.76% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the primary change: adding the Genome Browser to visualization.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/visualization-genome-browser

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

Comment @coderabbitai help to get the list of available commands.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 3 issues, and left some high level feedback:

  • BrowserStatus renders an but tests query role="status"; consider adding role="status" (or adjusting tests) so the accessibility semantics and test expectations align.
  • useDebouncedViewport relies on window.setTimeout directly; if you ever reuse this hook outside of strictly client-only components, consider guarding against non-browser environments to avoid reference errors during SSR or tests.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- BrowserStatus renders an <output aria-live="polite"> but tests query role="status"; consider adding role="status" (or adjusting tests) so the accessibility semantics and test expectations align.
- useDebouncedViewport relies on window.setTimeout directly; if you ever reuse this hook outside of strictly client-only components, consider guarding against non-browser environments to avoid reference errors during SSR or tests.

## Individual Comments

### Comment 1
<location path="apps/web/src/lib/genome/region.ts" line_range="37-46" />
<code_context>
+const REGION_PATTERN = /^([^:\s]+)\s*:\s*(-?\d+)\s*-\s*(-?\d+)\s*$/i
</code_context>
<issue_to_address>
**issue (bug_risk):** Negative coordinate handling is inconsistent with the documented error codes and pattern semantics.

Because `REGION_PATTERN` only accepts `-?\d+`, inputs with non-numeric coordinates (e.g. `chr1:abc-200000`) are rejected as `malformed` before `coordinateError` runs, while `chr1:-100-200000` yields `negative_start`. However, patterns like `chr1:100--200000` fail the regex and are also marked `malformed`, even though a `negative_end` error code exists. This mismatch makes error codes hard to predict and reason about. Please consider relaxing the regex to accept more general coordinate tokens and performing all numeric/negativity checks in one validation path, so `malformed`, `negative_*`, and `invalid_*` errors are applied consistently.
</issue_to_address>

### Comment 2
<location path="apps/web/src/lib/genome/useGenomeBrowser.ts" line_range="174-180" />
<code_context>
+    setViewport({ ...initialViewport, bounds: initialViewport.bounds })
+  }, [initialViewport])
+
+  const navigateTo = useCallback((interval: GenomicInterval) => {
+    setViewport((current) => ({
+      chromosome: interval.chromosome,
+      start: interval.start,
+      end: interval.end,
+      bounds: current.bounds,
+    }))
+  }, [])
+
</code_context>
<issue_to_address>
**issue (bug_risk):** Navigating to a new chromosome keeps the previous contig bounds, which can incorrectly clamp the viewport.

In `navigateTo`, the new viewport reuses `current.bounds`. If the user switches to a different chromosome/contig, those bounds may not match the new contig (or may be undefined when they should be defined), causing incorrect pan/zoom clamping or making an open-ended contig appear bounded. Consider clearing `bounds` on cross-chromosome navigation, or passing the correct bounds with the interval when contig metadata is available, instead of inheriting the previous viewport’s bounds.
</issue_to_address>

### Comment 3
<location path="apps/web/src/components/genome/GenomeBrowser.tsx" line_range="123-127" />
<code_context>
+  const handleSubmit = useCallback(
+    (event: FormEvent<HTMLFormElement>) => {
+      event.preventDefault()
+      const result = parseGenomeRegion(regionText)
+      if (result.ok) {
+        browser.navigateTo(result.interval)
+      }
+      setRegionText('')
+    },
+    [browser, regionText],
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Clearing the region input even on parse failure can hurt UX and accessibility.

In `BrowserControls.handleSubmit`, `regionText` is cleared on every submit, even when `parseGenomeRegion` fails. This removes the user’s input with no feedback and makes correcting errors harder, particularly for keyboard-only and screen-reader users. Please only clear `regionText` on successful parses and expose `RegionValidationError` (e.g., inline error message or `aria-live`) so users can understand and fix invalid input.

Suggested implementation:

```typescript
function BrowserControls({ browser }: { browser: GenomeBrowserResult }) {
  const [regionText, setRegionText] = useState('')
  const [regionError, setRegionError] = useState<RegionValidationError | null>(null)

```

```typescript
  const handleSubmit = useCallback(
    (event: FormEvent<HTMLFormElement>) => {
      event.preventDefault()
      const result = parseGenomeRegion(regionText)

      if (result.ok) {
        browser.navigateTo(result.interval)
        setRegionText('')
        setRegionError(null)
      } else {
        setRegionError(result.error)
      }
    },
    [browser, regionText],
  )

```

1. Ensure `RegionValidationError` is imported in this file (likely from the same module as `parseGenomeRegion`), e.g.:
   `import { parseGenomeRegion, RegionValidationError } from '...';`.
2. In the JSX for `BrowserControls`, render an inline error message when `regionError` is non-null, using accessible patterns (e.g. `aria-live="polite"` on the error container and `aria-describedby` on the region input pointing to the error element).
3. Optionally clear `regionError` on input change (`onChange` for the region field) so that the error message disappears as the user edits, while still preserving their existing input.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread apps/web/src/lib/genome/region.ts
Comment thread apps/web/src/lib/genome/useGenomeBrowser.ts Outdated
Comment thread apps/web/src/components/genome/GenomeBrowser.tsx Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 14

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/web/src/components/genome/GenomeBrowser.test.tsx`:
- Around line 121-126: Update the test around the genes-lane resolution to
assert “Loading genes...” before calling resolveGenes([]), then assert “No genes
found in region.” after the resolution completes. Keep the existing genesLoader
invocation check if needed, but ensure the assertions verify the
loading-to-empty state transition rather than only confirming the loader was
called.

In `@apps/web/src/components/genome/GenomeBrowser.tsx`:
- Around line 123-127: Update the region submission flow around
parseGenomeRegion so failed parsing preserves the submitted regionText, marks
the input invalid, and renders an accessible validation message; retain
navigation and clearing only for valid intervals. Update the related
invalid-input test to assert the value remains, the invalid state is set, and
the error message is rendered.
- Around line 100-108: Update the reverse-strand arrow geometry in the feature
rendering logic so the triangle is positioned at the feature’s start edge and
remains visible rather than being covered by the rectangle. Adjust the `arrow`
calculation for `forward === false` while preserving the existing forward-strand
rendering and dimensions.
- Line 38: Update the axis SVG in GenomeBrowser to use the same responsive width
behavior as the track SVGs rendered with w-full, removing the min-w-[640px]
constraint while preserving the existing viewBox and height configuration so
genomic tick positions align at all container widths.

In `@apps/web/src/lib/genome/api.test.ts`:
- Around line 109-195: Update requestCoordinateSearch, used by
fetchIntervalFeatures and fetchVariantFeatures, to fetch and combine subsequent
coordinate-search pages while page_size multiplied by the current page remains
below total_count, preserving the existing normalized result behavior. Add
coverage in the coordinate-fetch tests with total_count greater than page_size
and verify later-page items are included.

In `@apps/web/src/lib/genome/api.ts`:
- Line 197: The coordinate and variant loaders currently fetch only the first
page, so update both request flows in apps/web/src/lib/genome/api.ts at lines
197-197 and 210-210 to continue requesting pages until all interval results are
loaded, using the response pagination total_count or equivalent metadata.
Preserve the supplied AbortSignal on every page request and combine all returned
items before returning.

In `@apps/web/src/lib/genome/chromosome.ts`:
- Around line 11-21: Restrict CHROMOSOME_PATTERN and normalizeChromosome to
accept autosomes only from 1 through 22, while canonicalizing both M and MT to
chrMT. Update apps/web/src/lib/genome/chromosome.ts lines 11-21 and add
corresponding expectations in apps/web/src/lib/genome/chromosome.test.ts lines
16-26 for M, while rejecting chr23, chr99, and equivalent unsupported
identifiers.

In `@apps/web/src/lib/genome/geometry.ts`:
- Around line 84-98: Normalize minorPerMajor in computeTicks to a finite integer
before calculating minorStep, ensuring minorStep is an integer of at least one
so generated genomic tick positions remain integral and the loop always
advances. Preserve the existing major/minor tick behavior, and add regression
coverage for a non-aligned start and an infinite divisor.

In `@apps/web/src/lib/genome/region.test.ts`:
- Around line 50-54: Update the non-digit start-coordinate test for
parseGenomeRegion to expect the invalid_start error code returned by
coordinateError instead of malformed. Add a corresponding test for a non-digit
end coordinate and assert invalid_end if that path is not already covered.

In `@apps/web/src/lib/genome/region.ts`:
- Around line 104-105: Validate the parsed start and end coordinates after
converting rawStart and rawEnd to numbers, requiring both start and end to
satisfy Number.isSafeInteger before the region parser returns success. Preserve
the existing invalid-coordinate failure behavior and prevent unsafe or infinite
values from reaching the viewport or API request.

In `@apps/web/src/lib/genome/tracks.ts`:
- Around line 90-95: Update featuresInViewport to require feature.chromosome ===
viewport.chromosome before applying the existing inclusive coordinate-overlap
condition, so features from other chromosomes are excluded. Add a test covering
overlapping numeric coordinates across different chromosomes.

In `@apps/web/src/lib/genome/useGenomeBrowser.ts`:
- Around line 174-180: Update navigateTo so bounds are cleared when
interval.chromosome differs from the current viewport chromosome, rather than
reusing current.bounds. When navigating on the same chromosome and bounds are
available, clamp interval.start and interval.end to those bounds before storing
the viewport; preserve the submitted interval when bounds do not apply.
- Line 148: Refactor useGenomeBrowser so useGenomeTrack is not invoked inside
the tracks.map callback. Move the per-track Hook usage into a stable child
component or aggregate Hook implementation, ensuring Hook call order remains
consistent when tracks are added, removed, or reordered while preserving the
existing trackResults behavior.

In `@docs/visualization/genome-browser.md`:
- Around line 37-43: Add language identifiers to the fenced code blocks in
genome-browser.md: mark the architecture diagram block as text and the
validation commands block as shell, including the corresponding closing fences.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: d21886c2-112d-4602-8e57-0d2e2126fd62

📥 Commits

Reviewing files that changed from the base of the PR and between b7d4217 and cd11615.

📒 Files selected for processing (22)
  • apps/web/src/app/visualization/GenomeBrowserDemo.tsx
  • apps/web/src/app/visualization/page.tsx
  • apps/web/src/components/genome/GenomeBrowser.test.tsx
  • apps/web/src/components/genome/GenomeBrowser.tsx
  • apps/web/src/lib/genome/api.test.ts
  • apps/web/src/lib/genome/api.ts
  • apps/web/src/lib/genome/chromosome.test.ts
  • apps/web/src/lib/genome/chromosome.ts
  • apps/web/src/lib/genome/geometry.test.ts
  • apps/web/src/lib/genome/geometry.ts
  • apps/web/src/lib/genome/region.test.ts
  • apps/web/src/lib/genome/region.ts
  • apps/web/src/lib/genome/tracks.test.ts
  • apps/web/src/lib/genome/tracks.ts
  • apps/web/src/lib/genome/types.ts
  • apps/web/src/lib/genome/useGenomeBrowser.test.tsx
  • apps/web/src/lib/genome/useGenomeBrowser.ts
  • apps/web/src/lib/genome/viewport.test.ts
  • apps/web/src/lib/genome/viewport.ts
  • docs/visualization/README.md
  • docs/visualization/genome-browser.md
  • docs/visualization/roadmap.md

Comment thread apps/web/src/components/genome/GenomeBrowser.test.tsx
Comment thread apps/web/src/components/genome/GenomeBrowser.tsx Outdated
Comment thread apps/web/src/components/genome/GenomeBrowser.tsx
Comment thread apps/web/src/components/genome/GenomeBrowser.tsx Outdated
Comment thread apps/web/src/lib/genome/api.test.ts
Comment thread apps/web/src/lib/genome/region.ts
Comment thread apps/web/src/lib/genome/tracks.ts Outdated
Comment thread apps/web/src/lib/genome/useGenomeBrowser.ts Outdated
Comment thread apps/web/src/lib/genome/useGenomeBrowser.ts Outdated
Comment thread docs/visualization/genome-browser.md
@qodo-code-review

Copy link
Copy Markdown

ⓘ Your Qodo trial ends soon. Ask your workspace admin to set up billing to keep reviews running after the trial. Manage billing

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Add Phase 6.2 Genome Browser visualization (viewport + tracks + API adapter)

✨ Enhancement 🧪 Tests 📝 Documentation 🕐 40+ Minutes

Grey Divider

AI Description

• Add a reusable Genome Browser with zoom/pan/reset navigation and region input.
• Fetch per-track features for the visible interval via the existing coordinate-search API.
• Add unit/component test coverage and Phase 6 visualization documentation updates.
Diagram

graph TD
  Page["/visualization page"] --> Demo["GenomeBrowserDemo"] --> Browser["GenomeBrowser"] --> Hook(["useGenomeBrowser"]) --> Adapter["genome/api.ts"] --> Api{{"Phase 5 coord-search API"}}
  Browser --> Container["VisualizationContainer"]
  Hook --> Utils["genome utils"]

  subgraph Legend
    direction LR
    _c["Component"] ~~~ _h(["Hook"]) ~~~ _e{{"External"}}
  end
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Adopt an existing genome browser library (e.g., IGV.js)
  • ➕ Much richer track ecosystem out of the box (genes, alignments, coverage, etc.)
  • ➕ Potentially better performance on dense tracks (Canvas/WebGL-based implementations)
  • ➖ Introduces heavy dependencies and integration complexity; may conflict with current “no new viz deps” constraint
  • ➖ Harder to keep strict one-based-inclusive semantics consistent across adapters and UI
  • ➖ Less control over design-system/a11y conventions already established in Phase 6.1
2. Use a D3-based scale/tick/layout layer
  • ➕ Battle-tested axis tick generation and scales
  • ➕ Could reduce custom math code surface area
  • ➖ Conflicts with the stated milestone constraint of not adding D3
  • ➖ Would increase bundle size and dependency footprint for a relatively small feature set
3. Render tracks on Canvas (keep React controls + state)
  • ➕ Better scalability for dense features and many tracks
  • ➕ Avoids large SVG DOM trees as Phase 6.3–6.4 add complexity
  • ➖ More complex hit-testing/a11y (tooltips, focus, screen reader support)
  • ➖ Harder to test rendering behavior at unit level; would likely shift toward visual regression tests

Recommendation: Given the explicit constraint of avoiding new visualization dependencies, the PR’s approach (pure, unit-tested math + lightweight SVG rendering + per-track async loading via the existing Phase 6.1 data layer) is the best fit. The main strategic follow-up is to keep the track/rendering boundary clean so a future Canvas/WebGL renderer can be swapped in for dense data without rewriting viewport/navigation or API adapters.

Files changed (22) +2279 / -15

Enhancement (11) +1295 / -3
GenomeBrowserDemo.tsxAdd GenomeBrowser demo wired to real coordinate-search loaders +42/-0

Add GenomeBrowser demo wired to real coordinate-search loaders

• Introduces a client-side demo component that instantiates the GenomeBrowser with two tracks (genes and variants). Wires track loaders to the typed API adapter functions and sets an initial chr17 window for immediate real-data rendering.

apps/web/src/app/visualization/GenomeBrowserDemo.tsx

page.tsxRender GenomeBrowser demo on the visualization page +5/-3

Render GenomeBrowser demo on the visualization page

• Updates the /visualization page metadata and copy to reflect Phase 6.2. Renders the new GenomeBrowserDemo alongside the existing VisualizationDemo.

apps/web/src/app/visualization/page.tsx

GenomeBrowser.tsxImplement GenomeBrowser UI (controls, axis, per-track lanes) +247/-0

Implement GenomeBrowser UI (controls, axis, per-track lanes)

• Adds the main GenomeBrowser component with viewport controls (zoom/pan/reset) and a region input that uses the region parser. Renders an axis SVG with ticks, and per-track lanes inside the Phase 6.1 VisualizationContainer, including feature clipping and simple glyphs for genes and variants.

apps/web/src/components/genome/GenomeBrowser.tsx

api.tsAdd typed genome API adapter over Phase 5 coordinate-search endpoint +214/-0

Add typed genome API adapter over Phase 5 coordinate-search endpoint

• Implements POST /search/{domain}/coordinate requests with AbortSignal support and a stable error type (GenomeApiError). Normalizes untyped response items into typed GenomicFeature/VariantFeature records and filters out invalid coordinates.

apps/web/src/lib/genome/api.ts

chromosome.tsIntroduce chromosome/contig normalization mirroring backend validation +27/-0

Introduce chromosome/contig normalization mirroring backend validation

• Adds shared chromosome validation and normalization to canonical chr-prefixed identifiers. Mirrors the backend’s permissive boundary rules but enforces client-side checks for clearer UX.

apps/web/src/lib/genome/chromosome.ts

geometry.tsAdd pure geometry utilities for scale and axis ticks +137/-0

Add pure geometry utilities for scale and axis ticks

• Implements one-based-inclusive scale creation, tick computation (major/minor), and formatting helpers for base positions and region labels. Keeps logic pure and testable outside the DOM.

apps/web/src/lib/genome/geometry.ts

region.tsImplement region string parser with typed error codes +136/-0

Implement region string parser with typed error codes

• Parses chr:start-end input into a validated one-based-inclusive interval and returns structured, stable validation errors. Uses shared chromosome normalization and explicitly enforces start/end >= 1 and start <= end.

apps/web/src/lib/genome/region.ts

tracks.tsAdd minimal track utilities (row packing + in-viewport filter) +96/-0

Add minimal track utilities (row packing + in-viewport filter)

• Defines track kinds and provides pure functions for deterministic row layout of overlapping features and inclusive overlap filtering against the current viewport. Establishes a foundation for future track types.

apps/web/src/lib/genome/tracks.ts

types.tsAdd strongly-typed genome models and coordinate conventions +93/-0

Add strongly-typed genome models and coordinate conventions

• Introduces TypeScript types for intervals, features, variants, and viewport bounds, with explicit one-based-inclusive coordinate semantics. Documents invariants and expected adapter behavior for future zero-based sources.

apps/web/src/lib/genome/types.ts

useGenomeBrowser.tsImplement useGenomeBrowser hook with debounced per-track fetching +184/-0

Implement useGenomeBrowser hook with debounced per-track fetching

• Composes pure viewport pan/zoom math with the Phase 6.1 useVisualizationData lifecycle. Debounces viewport changes before triggering per-track refetch, and exposes navigation methods plus per-track statuses/data/errors.

apps/web/src/lib/genome/useGenomeBrowser.ts

viewport.tsAdd pure viewport navigation math (zoom/pan/clamp) +114/-0

Add pure viewport navigation math (zoom/pan/clamp)

• Implements immutable viewport operations for zooming and panning with optional contig-length clamping. Defines navigation constants (min span, pan fraction, zoom factor) and helper constructors for initial/whole-contig viewports.

apps/web/src/lib/genome/viewport.ts

Tests (8) +814 / -0
GenomeBrowser.test.tsxAdd component tests for GenomeBrowser controls and states +127/-0

Add component tests for GenomeBrowser controls and states

• Adds Vitest/Testing Library coverage for rendering controls/axis/lanes, initial per-track interval requests, region input navigation, invalid input handling, basic navigation actions, and loading/empty behavior.

apps/web/src/components/genome/GenomeBrowser.test.tsx

api.test.tsTest coordinate-search API adapter normalization and request shape +195/-0

Test coordinate-search API adapter normalization and request shape

• Adds unit tests for gene/transcript/variant normalization helpers and for the fetch functions’ request payload (interval + overlap match_type). Verifies error handling for non-2xx responses and filtering of invalid items.

apps/web/src/lib/genome/api.test.ts

chromosome.test.tsAdd tests for chromosome normalization and validation +44/-0

Add tests for chromosome normalization and validation

• Validates canonicalization of autosomes/sex/mitochondrial contigs and rejection of malformed identifiers. Ensures whitespace trimming and case-insensitivity behavior.

apps/web/src/lib/genome/chromosome.test.ts

geometry.test.tsAdd tests for genome pixel scale and axis tick formatting +81/-0

Add tests for genome pixel scale and axis tick formatting

• Covers one-based-inclusive pixel mapping, span-to-pixel conversion, nice tick step selection, tick generation ordering, and human-friendly label formatting (K/M units and region labels).

apps/web/src/lib/genome/geometry.test.ts

region.test.tsAdd tests for region parsing and validation errors +71/-0

Add tests for region parsing and validation errors

• Exercises happy paths (including prefixless chromosomes) and failure modes (malformed input, invalid chromosome, negative/invalid coordinates, and start-after-end). Confirms stable error codes.

apps/web/src/lib/genome/region.test.ts

tracks.test.tsAdd tests for track row layout and viewport clipping +55/-0

Add tests for track row layout and viewport clipping

• Verifies greedy non-overlap row packing determinism and y-offset assignment. Tests inclusive overlap filtering for selecting features that intersect the viewport.

apps/web/src/lib/genome/tracks.test.ts

useGenomeBrowser.test.tsxAdd tests for useGenomeBrowser hook (per-track status + debouncing) +119/-0

Add tests for useGenomeBrowser hook (per-track status + debouncing)

• Covers per-track loader execution, initial interval requests, error propagation, and debounced refetch behavior on viewport changes using fake timers.

apps/web/src/lib/genome/useGenomeBrowser.test.tsx

viewport.test.tsAdd tests for viewport math (zoom/pan clamping and helpers) +122/-0

Add tests for viewport math (zoom/pan clamping and helpers)

• Validates inclusive base counting, initial/whole-contig viewport generation, zoom behavior with min span and bounds clamping, and pan behavior across bounded and unbounded contigs.

apps/web/src/lib/genome/viewport.test.ts

Documentation (3) +170 / -12
README.mdUpdate visualization docs to mark Phase 6.2 as implemented +19/-8

Update visualization docs to mark Phase 6.2 as implemented

• Updates the Phase 6 visualization README to reflect the Genome Browser milestone as current. Adds a link to new Genome Browser documentation and summarizes what Phase 6.2 provides.

docs/visualization/README.md

genome-browser.mdAdd Genome Browser architecture, API contract, a11y, and test docs +124/-0

Add Genome Browser architecture, API contract, a11y, and test docs

• Introduces a dedicated Phase 6.2 document covering scope, data flow, coordinate conventions, API usage, accessibility decisions, and where tests live. Serves as an extension-point guide for future visualization milestones.

docs/visualization/genome-browser.md

roadmap.mdPromote Phase 6.2 to current milestone and record deliverables +27/-4

Promote Phase 6.2 to current milestone and record deliverables

• Marks Phase 6.2 as complete, documents delivered features and constraints, and moves Phase 6.1 into the previous milestones section. Updates roadmap notes to align subsequent phases around 6.3+ work.

docs/visualization/roadmap.md

@qodo-code-review

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (5) 📘 Rule violations (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Hooks called in map 🐞 Bug ≡ Correctness
Description
useGenomeBrowser calls useGenomeTrack (which uses React hooks) inside tracks.map(...), so any
change in track count/order between renders can violate the Rules of Hooks and crash or misassociate
per-track state. This is especially likely once tracks become user-configurable (toggle/reorder)
given tracks is a public prop.
Code

apps/web/src/lib/genome/useGenomeBrowser.ts[148]

+  const trackResults = tracks.map((track) => useGenomeTrack(track, debouncedViewport))
Relevance

●● Moderate

Rules-of-Hooks risk is real, but fixing may require nontrivial refactor; no close repo precedent
found.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The PR introduces a hook (useGenomeTrack) that itself uses multiple React hooks, and then invokes
it from within a .map() over the tracks prop, making hook call order dependent on runtime track
list shape.

apps/web/src/lib/genome/useGenomeBrowser.ts[86-113]
apps/web/src/lib/genome/useGenomeBrowser.ts[142-149]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`useGenomeBrowser` currently derives `trackResults` via `tracks.map((track) => useGenomeTrack(...))`. Because `useGenomeTrack` uses hooks (`useRef`, `useCallback`, `useEffect`, `useVisualizationData`), this is a Rules-of-Hooks violation when `tracks` is not strictly constant in length and order across renders.

## Issue Context
This hook is intended to be reusable/extensible; as soon as consumers toggle or reorder tracks, React can throw hook-order errors or attach the wrong state to the wrong track.

## Fix Focus Areas
- apps/web/src/lib/genome/useGenomeBrowser.ts[86-149]

## Implementation direction
- Refactor so hooks are called in a stable component boundary per track (e.g., a `GenomeTrackLane` component keyed by `track.id` that owns `useVisualizationData` and the viewport-change refetch effect), and have `GenomeBrowser` render those components.
- Alternatively, implement a single hook that manages all tracks in one `useEffect` + `useState` (no per-track hook calls in a loop), preserving per-track identity by `track.id`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Stale bounds on navigate 🐞 Bug ≡ Correctness
Description
navigateTo() carries current.bounds forward even when the chromosome changes, so subsequent
pan/zoom clamping may use the previous contig’s length. This can incorrectly restrict navigation (or
clamp to the wrong end) after jumping to a different chromosome.
Code

apps/web/src/lib/genome/useGenomeBrowser.ts[R176-179]

+      chromosome: interval.chromosome,
+      start: interval.start,
+      end: interval.end,
+      bounds: current.bounds,
Relevance

●●● Strong

Likely real navigation bug; resetting bounds on chromosome change is a small, targeted fix.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
navigateTo explicitly preserves current.bounds, while viewport navigation functions clamp using
viewport.bounds?.length; therefore bounds from one chromosome can incorrectly affect later
pan/zoom after navigating to another chromosome.

apps/web/src/lib/genome/useGenomeBrowser.ts[174-181]
apps/web/src/lib/genome/viewport.ts[30-33]
apps/web/src/lib/genome/viewport.ts[67-90]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`navigateTo` updates `chromosome/start/end` but preserves `bounds: current.bounds`. Bounds represent contig length and are only valid for the contig they came from; reusing them across chromosomes makes later zoom/pan math clamp against the wrong length.

## Issue Context
`zoomViewport`/`panViewport` clamp based on `viewport.bounds?.length`, so stale bounds directly alter navigation behavior.

## Fix Focus Areas
- apps/web/src/lib/genome/useGenomeBrowser.ts[174-181]
- apps/web/src/lib/genome/viewport.ts[30-33]

## Implementation direction
- When navigating to a different chromosome, clear bounds:
 - `bounds: interval.chromosome === current.chromosome ? current.bounds : undefined`
- If you have (or will have) a chromosome->length map, update bounds to the destination chromosome’s known bounds instead of clearing.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Features not actually clipped 🐞 Bug ≡ Correctness
Description
Despite the comment, interval features are only overlap-filtered, not clipped, so features that
extend beyond the viewport can render into the reserved TRACK_HEADER_WIDTH area and have
misleading glyph widths. This is caused by using raw feature.start/end for x/width after
featuresInViewport (which does no clamping and doesn’t enforce chromosome equality).
Code

apps/web/src/components/genome/GenomeBrowser.tsx[R94-96]

+        const x = TRACK_HEADER_WIDTH + scale.toX(feature.start)
+        const width = Math.max(3, scale.spanToPixels(feature.end - feature.start + 1))
+        const forward = feature.strand !== '-'
Relevance

●●● Strong

Clear rendering bug; clipping to viewport is expected and fix is localized, low-risk.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The renderer computes x and width from raw feature.start/end, and the helper it relies on only
checks overlap; therefore a feature that overlaps but starts before the viewport will not be clipped
and can render into the left offset region.

apps/web/src/components/genome/GenomeBrowser.tsx[56-96]
apps/web/src/components/genome/GenomeBrowser.tsx[193-218]
apps/web/src/lib/genome/tracks.ts[86-96]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`featuresInViewport` only checks overlap and returns the original coordinates. The renderer then uses `feature.start/end` directly to compute `x` and `width`, so a feature starting before `viewport.start` will produce an `x` less than the intended drawing region (including into the reserved header offset).

## Issue Context
The code comment in `GenomeTrackSvg` says features are clipped before rendering, but no clipping/clamping is applied.

## Fix Focus Areas
- apps/web/src/components/genome/GenomeBrowser.tsx[56-115]
- apps/web/src/lib/genome/tracks.ts[86-96]

## Implementation direction
- Update `featuresInViewport` (or add a new helper) to:
 - filter by chromosome: `feature.chromosome === viewport.chromosome`
 - return a clipped copy: `start = Math.max(feature.start, viewport.start)`, `end = Math.min(feature.end, viewport.end)`
- Then render using the clipped coordinates for `x`/`width`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


4. Null JSON payload deref 🐞 Bug ☼ Reliability
Description
requestCoordinateSearch assumes response.json() returns an object and immediately reads
payload.items; if the API returns null, this throws a TypeError instead of producing a clean
empty/error result. The adapter should defensively validate the parsed JSON shape before
dereferencing.
Code

apps/web/src/lib/genome/api.ts[R179-180]

+  const payload = (await response.json()) as CoordinateSearchPayload
+  return Array.isArray(payload.items) ? payload.items : []
Relevance

●●● Strong

Defensive JSON-shape guarding matches team’s recent runtime-safety fixes.

PR-#27

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The code dereferences payload.items immediately after response.json() with only a TypeScript
cast; at runtime, a null payload will cause an exception.

apps/web/src/lib/genome/api.ts[155-181]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`payload.items` is accessed without checking that `payload` is a non-null object. A `null` JSON body (or other unexpected shapes) will throw.

## Issue Context
This module explicitly treats API payloads as untyped (`unknown[]`), so it should also handle malformed-but-2xx responses safely.

## Fix Focus Areas
- apps/web/src/lib/genome/api.ts[155-181]

## Implementation direction
- Guard payload shape:
 - `const raw = await response.json()`
 - `if (typeof raw !== 'object' || raw === null) return []` (or throw `GenomeApiError`)
 - Then read `items` safely: `const items = (raw as any).items; return Array.isArray(items) ? items : []`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Informational

5. Fractional axis tick positions 🐞 Bug ≡ Correctness
Description
computeTicks can produce fractional tick.position values because it sets `minorStep = majorStep
/ minorPerMajor and iterates pos += minorStep`. Fractional base positions contradict the one-based
integer coordinate model and can create visually misleading tick marks for small windows.
Code

apps/web/src/lib/genome/geometry.ts[R83-86]

+  const majorStep = niceTickStep(targetStep, 1)
+  const minorStep = majorStep / minorPerMajor
+
+  const ticks: AxisTick[] = []
Relevance

●● Moderate

Correctness concern, but fractional minor ticks may be considered acceptable/visual-only without
clear precedent.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Minor tick step is computed via division and then used as an increment for positions, and each pos
is stored as tick.position without rounding, allowing fractional genomic positions.

apps/web/src/lib/genome/geometry.ts[75-98]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Minor ticks may be emitted at fractional positions (e.g. 1.25) when `majorStep` is small, since `minorStep` is computed via division.

## Issue Context
The browser models coordinates as one-based inclusive integer bases.

## Fix Focus Areas
- apps/web/src/lib/genome/geometry.ts[75-98]

## Implementation direction
- Ensure `minorStep` and emitted positions are integers, e.g.:
 - Compute minor ticks as integer-rounded subdivisions and de-duplicate, or
 - Skip minor ticks when subdivision would be fractional, or
 - Use `const minorStep = Math.max(1, Math.round(majorStep / minorPerMajor))` and ensure loop progress + deduplication.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


To customize comments, go to the Qodo configuration screen, or learn more in the docs.

Qodo Logo

Comment thread apps/web/src/lib/genome/useGenomeBrowser.ts Outdated
Comment thread apps/web/src/lib/genome/useGenomeBrowser.ts Outdated
Comment thread apps/web/src/components/genome/GenomeBrowser.tsx Outdated
Comment thread apps/web/src/lib/genome/geometry.ts
Comment thread apps/web/src/lib/genome/api.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/web/src/components/genome/GenomeBrowser.tsx`:
- Around line 282-292: Use a single displayed viewport for both AxisSvg and
BrowserTrack so axis ticks and track glyphs remain aligned during pan, zoom, and
region navigation. Update the viewport passed through the GenomeBrowser render
path, preserving debouncing only if stale glyphs are hidden while settling, and
add a navigation test covering the debounce interval.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: ffa81d93-b896-4983-b916-46d2ed8bc9e4

📥 Commits

Reviewing files that changed from the base of the PR and between cd11615 and e4cd8c2.

📒 Files selected for processing (12)
  • apps/web/src/components/genome/GenomeBrowser.test.tsx
  • apps/web/src/components/genome/GenomeBrowser.tsx
  • apps/web/src/lib/genome/api.test.ts
  • apps/web/src/lib/genome/api.ts
  • apps/web/src/lib/genome/geometry.test.ts
  • apps/web/src/lib/genome/geometry.ts
  • apps/web/src/lib/genome/region.test.ts
  • apps/web/src/lib/genome/region.ts
  • apps/web/src/lib/genome/tracks.test.ts
  • apps/web/src/lib/genome/tracks.ts
  • apps/web/src/lib/genome/useGenomeBrowser.test.tsx
  • apps/web/src/lib/genome/useGenomeBrowser.ts
🚧 Files skipped from review as they are similar to previous changes (7)
  • apps/web/src/lib/genome/region.test.ts
  • apps/web/src/lib/genome/tracks.ts
  • apps/web/src/lib/genome/api.test.ts
  • apps/web/src/lib/genome/useGenomeBrowser.test.tsx
  • apps/web/src/lib/genome/geometry.test.ts
  • apps/web/src/lib/genome/geometry.ts
  • apps/web/src/lib/genome/region.ts

Comment thread apps/web/src/components/genome/GenomeBrowser.tsx
@dsk-dev-ai
dsk-dev-ai merged commit 6615d05 into main Aug 10, 2026
5 checks passed
@dsk-dev-ai
dsk-dev-ai deleted the feat/visualization-genome-browser branch August 10, 2026 04:39
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