Skip to content

Julenmendieta/MILAB-6617_adaptToSingleCellVhh - #38

Merged
julenmendieta merged 4 commits into
mainfrom
julenmendieta/MILAB-6617_adaptToSingleCellVhh
Jul 17, 2026
Merged

Julenmendieta/MILAB-6617_adaptToSingleCellVhh#38
julenmendieta merged 4 commits into
mainfrom
julenmendieta/MILAB-6617_adaptToSingleCellVhh

Conversation

@julenmendieta

@julenmendieta julenmendieta commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes a workflow crash on VHH (heavy-chain-only) single-cell IG datasets where the chain selector previously offered "Light" even when no light-chain columns existed. A new model output availableScChains reports which chain letters actually have V-gene columns; the UI chain selector is filtered to that set and hidden when only one chain is present.

  • model/src/index.ts — Adds the availableScChains output, which inspects pl7.app/vdj/geneHit / VGene columns for the primary chain index to detect which chains have real data; returns undefined (no filter) for bulk and non-IG datasets.
  • ui/src/utils.tsuseScChainOptions gains a second availableChains argument and filters the receptor-derived options list, falling back to the full list while the output is still resolving (undefined).
  • ui/src/pages/Settings.vue — The chain PlBtnGroup is now hidden when scChainOptions?.length ≤ 1, removing the user's ability to pick an invalid chain.

Confidence Score: 3/5

The chain selector is correctly hidden for VHH datasets, but the underlying scChain model field can remain stale when a user switches from a paired IG dataset to a VHH one, leaving the backend to fail with the same error the PR set out to fix.

The new availableScChains output and option-filtering logic are sound. The gap is in Settings.vue and app.ts: hiding the UI control does not reset model.data.scChain, so an existing block with Light chain (B) previously selected will still send B to the workflow after a VHH dataset is chosen.

ui/src/pages/Settings.vue and ui/src/app.ts — no auto-reset of model.data.scChain when the available chain list narrows to a single entry.

Important Files Changed

Filename Overview
model/src/index.ts Adds availableScChains output that probes the result pool for V-gene columns per chain; logic looks correct for the IG/VHH case, and the output correctly returns undefined for resolving/empty pool states which is handled upstream in the UI.
ui/src/utils.ts Refactors useScChainOptions to accept and filter by availableChains; fall-through for undefined (resolving) is handled; TCR path is unaffected since availableScChains returns undefined for non-IG.
ui/src/pages/Settings.vue Hides the chain selector when scChainOptions?.length ≤ 1, but does not reset model.data.scChain when a dataset switch leaves a stale chain value that will fail the backend workflow.
ui/src/app.ts Passes availableScChains to useScChainOptions for label-generation use; no auto-reset logic added for the scChain data field.
.changeset/vhh-presence-driven-chain-menu.md Accurate patch changeset entry describing the bug and the fix.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant UI as Settings.vue
    participant Utils as utils.ts (useScChainOptions)
    participant Model as model/index.ts (availableScChains)
    participant Pool as ResultPool

    UI->>Model: reads availableScChains output
    Model->>Pool: getPColumnSpecByRef(datasetRef)
    alt spec is not SC-IG
        Model-->>UI: undefined (no filtering)
    else spec is SC-IG
        Model->>Pool: getAnchoredPColumns(VGene / primary index)
        alt pool still resolving
            Pool-->>Model: undefined
            Model-->>UI: undefined (no filtering)
        else columns available
            Pool-->>Model: [col_A, col_B, ...]
            Model->>Model: collect chain letters from domain
            Model-->>UI: ["A"] or ["A","B"]
        end
    end
    UI->>Utils: useScChainOptions(datasetSpec, availableScChains)
    Utils->>Utils: build full receptor options (IG to Heavy/Light)
    alt availableScChains is undefined
        Utils-->>UI: full options list (fallback)
    else availableScChains is []
        Utils-->>UI: [] (hidden, nothing to pick)
    else availableScChains is ["A"]
        Utils-->>UI: "[{Heavy, A}] (hidden, only one chain)"
    else availableScChains is ["A","B"]
        Utils-->>UI: "[{Heavy,A},{Light,B}] (shown)"
    end
    UI->>UI: "v-if length > 1, show/hide PlBtnGroup"
    Note over UI: scChain in model.data is NOT reset when selector is hidden
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant UI as Settings.vue
    participant Utils as utils.ts (useScChainOptions)
    participant Model as model/index.ts (availableScChains)
    participant Pool as ResultPool

    UI->>Model: reads availableScChains output
    Model->>Pool: getPColumnSpecByRef(datasetRef)
    alt spec is not SC-IG
        Model-->>UI: undefined (no filtering)
    else spec is SC-IG
        Model->>Pool: getAnchoredPColumns(VGene / primary index)
        alt pool still resolving
            Pool-->>Model: undefined
            Model-->>UI: undefined (no filtering)
        else columns available
            Pool-->>Model: [col_A, col_B, ...]
            Model->>Model: collect chain letters from domain
            Model-->>UI: ["A"] or ["A","B"]
        end
    end
    UI->>Utils: useScChainOptions(datasetSpec, availableScChains)
    Utils->>Utils: build full receptor options (IG to Heavy/Light)
    alt availableScChains is undefined
        Utils-->>UI: full options list (fallback)
    else availableScChains is []
        Utils-->>UI: [] (hidden, nothing to pick)
    else availableScChains is ["A"]
        Utils-->>UI: "[{Heavy, A}] (hidden, only one chain)"
    else availableScChains is ["A","B"]
        Utils-->>UI: "[{Heavy,A},{Light,B}] (shown)"
    end
    UI->>UI: "v-if length > 1, show/hide PlBtnGroup"
    Note over UI: scChain in model.data is NOT reset when selector is hidden
Loading

Fix All in Claude Code

Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
ui/src/pages/Settings.vue:36-40
**Stale `scChain` survives a dataset switch**

Hiding the selector prevents picking an invalid chain for new configurations, but `model.data.scChain` is never reset when the available-chains list narrows. If a user previously selected `"B"` (Light) on a paired IG dataset and then switches to a VHH dataset, `scChain` stays `"B"`, the `PlBtnGroup` is hidden (nothing to correct it), and the backend workflow receives a chain letter with no columns — reproducing the original "expected exactly 1 V gene column for chain, got 0" error.

The default in `initData` is `"A"`, so fresh blocks are safe; the failure only appears when a user changes the dataset reference on an existing block that had the Light chain selected. A `watchEffect` in `app.ts` that sets `model.data.scChain` to `scChainOptions.value[0].value` whenever the option list resolves to exactly one entry would close this gap.

Reviews (1): Last reviewed commit: "Changeset" | Re-trigger Greptile

Greptile also left 1 inline comment on this PR.

Context used:

  • Context used - Terms is a types in codebase. Provide the list of ... (source)

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request dynamically filters single-cell chain options based on the columns present in the selected dataset, hiding the selector when only one chain is available. Feedback points out a potential runtime TypeError in model/src/index.ts due to inconsistent null-checking of spec, and a stale state issue in ui/src/app.ts when switching datasets, suggesting a watchEffect to automatically update the selected chain.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread ui/src/app.ts
Comment thread model/src/index.ts
Comment thread ui/src/pages/Settings.vue
@mzueva
mzueva self-requested a review July 17, 2026 13:19
@julenmendieta
julenmendieta merged commit 96209b8 into main Jul 17, 2026
11 checks passed
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.

2 participants