Skip to content

fix(lapis): restore insertion and mutation format in response - #1798

Draft
fengelniederhammer wants to merge 8 commits into
mainfrom
1797-restore-insertion-and-mutation-format-in-response
Draft

fix(lapis): restore insertion and mutation format in response#1798
fengelniederhammer wants to merge 8 commits into
mainfrom
1797-restore-insertion-and-mutation-format-in-response

Conversation

@fengelniederhammer

@fengelniederhammer fengelniederhammer commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

resolves #1797

Summary

SILO dropped the assembled insertion and mutation fields from its responses. This restores them by assembling them in LAPIS, keeping the API contract unchanged.

PR Checklist

- [ ] All necessary documentation has been adapted.
- [ ] All necessary changes are explained in the llms.txt.

  • The implemented feature is covered by an appropriate test.

@vercel

vercel Bot commented Jul 29, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
lapis Ready Ready Preview Jul 31, 2026 8:08am

Request Review

@fengelniederhammer fengelniederhammer changed the title 1797 restore insertion and mutation format in response fix(lapis): restore insertion and mutation format in response Jul 29, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR restores the public LAPIS API contract for mutation and insertion fields after SILO stopped returning those assembled strings, by assembling them within LAPIS from the remaining SILO-provided components.

Changes:

  • Assemble mutation values in SiloQueryModel from mutationFrom/position/mutationTo (and sequenceName where applicable) while keeping field-selection behavior intact.
  • Assemble insertion values in SiloQueryModel from sequenceName/position/insertedSymbols, restoring the legacy formatting for single- vs multi-segmented genomes.
  • Update Arrow row converters and tests to reflect SILO’s updated payloads (no longer containing pre-assembled mutation / insertion), and switch CI to use SILO_TAG: latest again.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated no comments.

Show a summary per file
File Description
lapis/src/main/kotlin/org/genspectrum/lapis/model/SiloQueryModel.kt Reassembles mutation/insertion strings in LAPIS responses; adjusts requested SILO fields accordingly.
lapis/src/main/kotlin/org/genspectrum/lapis/request/MutationProportionsRequest.kt Adds helpers for field-selection logic used when deciding what to return.
lapis/src/main/kotlin/org/genspectrum/lapis/response/SiloResponse.kt Updates internal data models to match SILO output (drops assembled fields).
lapis/src/main/kotlin/org/genspectrum/lapis/silo/ArrowRowConverter.kt Stops reading removed SILO columns (mutation, insertion) from Arrow rows.
lapis/src/main/kotlin/org/genspectrum/lapis/response/LapisResponse.kt Fixes capitalization in a JavaScript wording comment.
lapis/src/test/kotlin/org/genspectrum/lapis/controller/Helpers.kt Updates mutation test helper to provide mutationFrom/mutationTo instead of mutation.
lapis/src/test/kotlin/org/genspectrum/lapis/model/SiloQueryModelTest.kt Updates/extends tests to validate assembled mutation/insertion response formatting.
lapis/src/test/kotlin/org/genspectrum/lapis/silo/SiloClientTest.kt Updates SILO client Arrow test fixtures to remove now-missing SILO columns.
.github/workflows/lapis.yml Switches SILO docker tag back to latest in CI.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 19 out of 19 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

.github/workflows/lapis.yml:8

  • Using a floating Docker tag (SILO_TAG: latest) in CI makes test runs non-reproducible and can cause sudden breakages when SILO publishes a new image. Consider pinning to a specific SILO version (or image digest) that this PR is verified against, and bump it intentionally when needed.
env:
  DOCKER_IMAGE_NAME: ghcr.io/genspectrum/lapis
  SILO_TAG: latest

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 35 out of 35 changed files in this pull request and generated no new comments.

Suppressed comments (4)

lapis/src/main/kotlin/org/genspectrum/lapis/model/SiloQueryModel.kt:86

  • assembleMutation builds the assembled amino-acid mutation string from nullable fields (sequenceName, mutationFrom, position, mutationTo). If any of those columns are missing in the SILO response, the assembled mutation will contain "null" segments. It’s safer to require these fields when assembling the string (or otherwise explicitly handle missing values).
        val assembleMutation = { data: MutationData ->
            "${data.sequenceName}:${data.mutationFrom}${data.position}${data.mutationTo}"
        }

lapis/src/main/kotlin/org/genspectrum/lapis/model/SiloQueryModel.kt:61

  • assembleMutation concatenates nullable fields (mutationFrom, position, mutationTo, and (for multi-segmented) sequenceName). If SILO omits any of these columns (e.g., due to a fields projection), Kotlin string interpolation will produce strings containing "null" (like null123null), silently breaking the API contract. Consider failing fast when any required component is missing so incorrect assembled mutations can’t leak into responses.

This issue also appears on line 84 of the same file.

        val assembleMutation = { data: MutationData ->
            val core = "${data.mutationFrom}${data.position}${data.mutationTo}"
            if (referenceGenomeSchema.isSingleSegmented()) core else "${data.sequenceName}:$core"
        }

lapis/src/main/kotlin/org/genspectrum/lapis/model/SiloQueryModel.kt:31

  • import kotlin.collections.emptyList is redundant (the function is in Kotlin’s default imports) and will typically be flagged by ktlint/IDE inspections as an unused/redundant import. Removing it avoids unnecessary lint noise.
import kotlin.collections.emptyList

lapis/src/main/kotlin/org/genspectrum/lapis/request/MutationProportionsRequest.kt:32

  • ifRequested’s KDoc implies conditional evaluation (“Returns value only if field was requested”), but the value argument is evaluated eagerly at the call site. That means potentially expensive/unsafe computations (e.g., assembling mutation) still happen even when the field is not requested. Consider switching this to a lambda form (e.g., ifRequested(field) { ... }) and updating call sites accordingly.
    fun shouldResponseContainField(field: MutationsField) = fields.isEmpty() || fields.contains(field)

    /** Returns [value] only if [field] was requested (or all fields were requested), otherwise `null`. */
    fun <T> ifRequested(
        field: MutationsField,
        value: T,
    ): T? = if (shouldResponseContainField(field)) value else null

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.

restore insertion and mutation format in response

2 participants