Repository: Clinical-Genomics/scout

Issue:
Enable filtering on matched normal
**⚠️ Important:** Please avoid sharing any sensitive or personal information, including text or images, in this issue.

**Is your feature request related to a problem in the current program to new available techology or software? Please describe and add links/citations if appropriate.**

In the next release of balsamic we're planning to enable soft-filtering of SNVs present in the matched normal (the current matched normal filters will be unchanged but will not be hard-filtered), and as a result variants will be uploaded to Scout with a couple of new filters. See issue in MTP-BALSAMIC: https://github.com/Clinical-Genomics/MTP-BALSAMIC/issues/1

At the moment we have 2 filters which are both used to filter out variants based on presence in the normal. There is "germline_risk" from TNscope, and a custom bcftools filter which used to be called "high_normal_tumor_af_frac" but which we will rename in balsamic v17.0.0 to "in_normal". 

![Image](https://github.com/user-attachments/assets/f9da42b2-5336-4c82-803b-04f856548820)

This was requested by some customers mainly due to the risk of filtering out clinically relevant variants with a high presence in the normal, but will cause some institutes in Scout to receive variants they are not used to seeing, and which they likely do not wish to see, and to avoid this it would be nice to have easy option to filtering out these "high normal" variants by default for these institutes by applying the balsamic soft-filters.

**Describe the solution you'd like**

We discussed adding another checkbox here:

![Image](https://github.com/user-attachments/assets/070b8274-e281-4950-a809-d3c0e9d68c8e)

Which can be set to default removing the soft filtered normal variants on an institute level. But I trust in the scout-devs to figure out the best solution! 🙏 

**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.

**Additional context**

This feature is planned to be activated on the balsamic side in release 17.0.0, for all T+N matched panel analyses, which will increase the number of variants uploaded to Scout for this analysis type. But as the common germline variants are mostly filtered out by population databases the increase shouldn't be that massive. They will in essence in terms of number of variants become like tumor only analyses, which based on what I have seen would roughly increase the number of variants from 2k to 4k, but it varies on the panel.

To get a sense of what this will mean for the total number of variants uploaded from balsamic I counted the current number of tumor only cases in the production directory to 187, and the number of tumor normal cases to 19. Which means that roughly for every 10 tumor only case there's a tumor normal. As a very rough guesstimate the total number of variants from balsamic should with this feature increase by roughly 5%. 

But together with new filters planned to be added in 17.0.0 probably the net variants will actually decrease. It could also be looked into how this feature could be selectively implemented for certain institutes / or optionally per order.




Discussion:
sonarqubecloud[bot]: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=Clinical-Genomics_scout&pullRequest=5254) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=Clinical-Genomics_scout&pullRequest=5254&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=Clinical-Genomics_scout&pullRequest=5254&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=Clinical-Genomics_scout&pullRequest=5254&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=Clinical-Genomics_scout&pullRequest=5254&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=Clinical-Genomics_scout&pullRequest=5254&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=Clinical-Genomics_scout&pullRequest=5254)


codecov[bot]: ## [Codecov](https://app.codecov.io/gh/Clinical-Genomics/scout/pull/5254?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Clinical-Genomics) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 84.42%. Comparing base [(`2bcf037`)](https://app.codecov.io/gh/Clinical-Genomics/scout/commit/2bcf0377f4fab17c2114ee53a6e952fea5a90c93?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Clinical-Genomics) to head [(`37396ac`)](https://app.codecov.io/gh/Clinical-Genomics/scout/commit/37396ac794ea84c0e5bf4145c88d0aa0f76b18c8?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Clinical-Genomics).

<details><summary>Additional details and impacted files</summary>


```diff
@@           Coverage Diff           @@
##             main    #5254   +/-   ##
=======================================
  Coverage   84.42%   84.42%           
=======================================
  Files         326      326           
  Lines       19874    19881    +7     
=======================================
+ Hits        16778    16785    +7     
  Misses       3096     3096           
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/Clinical-Genomics/scout/pull/5254?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Clinical-Genomics).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Clinical-Genomics).

sonarqubecloud[bot]: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=Clinical-Genomics_scout&pullRequest=5254) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=Clinical-Genomics_scout&pullRequest=5254&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=Clinical-Genomics_scout&pullRequest=5254&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=Clinical-Genomics_scout&pullRequest=5254&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=Clinical-Genomics_scout&pullRequest=5254&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=Clinical-Genomics_scout&pullRequest=5254&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=Clinical-Genomics_scout&pullRequest=5254)


sonarqubecloud[bot]: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=Clinical-Genomics_scout&pullRequest=5254) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [1 New issue](https://sonarcloud.io/project/issues?id=Clinical-Genomics_scout&pullRequest=5254&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=Clinical-Genomics_scout&pullRequest=5254&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=Clinical-Genomics_scout&pullRequest=5254&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=Clinical-Genomics_scout&pullRequest=5254&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=Clinical-Genomics_scout&pullRequest=5254&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=Clinical-Genomics_scout&pullRequest=5254)


sonarqubecloud[bot]: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=Clinical-Genomics_scout&pullRequest=5254) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [1 New issue](https://sonarcloud.io/project/issues?id=Clinical-Genomics_scout&pullRequest=5254&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=Clinical-Genomics_scout&pullRequest=5254&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=Clinical-Genomics_scout&pullRequest=5254&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=Clinical-Genomics_scout&pullRequest=5254&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=Clinical-Genomics_scout&pullRequest=5254&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=Clinical-Genomics_scout&pullRequest=5254)


sonarqubecloud[bot]: ## [![Quality Gate Failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-failed-20px.png 'Quality Gate Failed')](https://sonarcloud.io/dashboard?id=Clinical-Genomics_scout&pullRequest=5254) **Quality Gate failed**  
Failed conditions  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [11.5% Duplication on New Code](https://sonarcloud.io/component_measures?id=Clinical-Genomics_scout&pullRequest=5254&metric=new_duplicated_lines_density&view=list) (required ≤ 3%)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=Clinical-Genomics_scout&pullRequest=5254)


sonarqubecloud[bot]: ## [![Quality Gate Failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-failed-20px.png 'Quality Gate Failed')](https://sonarcloud.io/dashboard?id=Clinical-Genomics_scout&pullRequest=5254) **Quality Gate failed**  
Failed conditions  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [11.4% Duplication on New Code](https://sonarcloud.io/component_measures?id=Clinical-Genomics_scout&pullRequest=5254&metric=new_duplicated_lines_density&view=list) (required ≤ 3%)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=Clinical-Genomics_scout&pullRequest=5254)


sonarqubecloud[bot]: ## [![Quality Gate Failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-failed-20px.png 'Quality Gate Failed')](https://sonarcloud.io/dashboard?id=Clinical-Genomics_scout&pullRequest=5254) **Quality Gate failed**  
Failed conditions  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [11.2% Duplication on New Code](https://sonarcloud.io/component_measures?id=Clinical-Genomics_scout&pullRequest=5254&metric=new_duplicated_lines_density&view=list) (required ≤ 3%)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=Clinical-Genomics_scout&pullRequest=5254)


sonarqubecloud[bot]: ## [![Quality Gate Failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-failed-20px.png 'Quality Gate Failed')](https://sonarcloud.io/dashboard?id=Clinical-Genomics_scout&pullRequest=5254) **Quality Gate failed**  
Failed conditions  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [9.7% Duplication on New Code](https://sonarcloud.io/component_measures?id=Clinical-Genomics_scout&pullRequest=5254&metric=new_duplicated_lines_density&view=list) (required ≤ 3%)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=Clinical-Genomics_scout&pullRequest=5254)


northwestwitch: Ready for review now
sonarqubecloud[bot]: ## [![Quality Gate Failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-failed-20px.png 'Quality Gate Failed')](https://sonarcloud.io/dashboard?id=Clinical-Genomics_scout&pullRequest=5254) **Quality Gate failed**  
Failed conditions  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [9.7% Duplication on New Code](https://sonarcloud.io/component_measures?id=Clinical-Genomics_scout&pullRequest=5254&metric=new_duplicated_lines_density&view=list) (required ≤ 3%)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=Clinical-Genomics_scout&pullRequest=5254)


sonarqubecloud[bot]: ## [![Quality Gate Failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-failed-20px.png 'Quality Gate Failed')](https://sonarcloud.io/dashboard?id=Clinical-Genomics_scout&pullRequest=5254) **Quality Gate failed**  
Failed conditions  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [6.1% Duplication on New Code](https://sonarcloud.io/component_measures?id=Clinical-Genomics_scout&pullRequest=5254&metric=new_duplicated_lines_density&view=list) (required ≤ 3%)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=Clinical-Genomics_scout&pullRequest=5254)


northwestwitch: This one needs some refinement, after having tested with a demo case. I'm marking it as in progress 






sonarqubecloud[bot]: ## [![Quality Gate Failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-failed-20px.png 'Quality Gate Failed')](https://sonarcloud.io/dashboard?id=Clinical-Genomics_scout&pullRequest=5254) **Quality Gate failed**  
Failed conditions  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [6.5% Duplication on New Code](https://sonarcloud.io/component_measures?id=Clinical-Genomics_scout&pullRequest=5254&metric=new_duplicated_lines_density&view=list) (required ≤ 3%)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=Clinical-Genomics_scout&pullRequest=5254)


sonarqubecloud[bot]: ## [![Quality Gate Failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-failed-20px.png 'Quality Gate Failed')](https://sonarcloud.io/dashboard?id=Clinical-Genomics_scout&pullRequest=5254) **Quality Gate failed**  
Failed conditions  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [6.8% Duplication on New Code](https://sonarcloud.io/component_measures?id=Clinical-Genomics_scout&pullRequest=5254&metric=new_duplicated_lines_density&view=list) (required ≤ 3%)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=Clinical-Genomics_scout&pullRequest=5254)


sonarqubecloud[bot]: ## [![Quality Gate Failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-failed-20px.png 'Quality Gate Failed')](https://sonarcloud.io/dashboard?id=Clinical-Genomics_scout&pullRequest=5254) **Quality Gate failed**  
Failed conditions  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [6.8% Duplication on New Code](https://sonarcloud.io/component_measures?id=Clinical-Genomics_scout&pullRequest=5254&metric=new_duplicated_lines_density&view=list) (required ≤ 3%)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=Clinical-Genomics_scout&pullRequest=5254)


northwestwitch: Tested on stage using the following filters on cust000:

<img width="304" alt="image" src="https://github.com/user-attachments/assets/e49aeba9-167d-4f0e-b7c7-460029bb9774" />


And [this case](https://scout-stage.scilifelab.se/cust000/10-2-TWISTpancan4/cancer/variants?variant_type=clinical):

### Default filters applied:

<img width="1022" alt="image" src="https://github.com/user-attachments/assets/87c293ae-9b2d-4d1d-a65d-b892f6e0b06b" />

### Include soft filtered vars:

<img width="991" alt="image" src="https://github.com/user-attachments/assets/c4f37edf-59ad-44e6-9f59-e53f659eee44" />






sonarqubecloud[bot]: ## [![Quality Gate Failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-failed-20px.png 'Quality Gate Failed')](https://sonarcloud.io/dashboard?id=Clinical-Genomics_scout&pullRequest=5254) **Quality Gate failed**  
Failed conditions  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [6.9% Duplication on New Code](https://sonarcloud.io/component_measures?id=Clinical-Genomics_scout&pullRequest=5254&metric=new_duplicated_lines_density&view=list) (required ≤ 3%)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=Clinical-Genomics_scout&pullRequest=5254)


sonarqubecloud[bot]: ## [![Quality Gate Failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-failed-20px.png 'Quality Gate Failed')](https://sonarcloud.io/dashboard?id=Clinical-Genomics_scout&pullRequest=5254) **Quality Gate failed**  
Failed conditions  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [6.9% Duplication on New Code](https://sonarcloud.io/component_measures?id=Clinical-Genomics_scout&pullRequest=5254&metric=new_duplicated_lines_density&view=list) (required ≤ 3%)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=Clinical-Genomics_scout&pullRequest=5254)


sonarqubecloud[bot]: ## [![Quality Gate Failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-failed-20px.png 'Quality Gate Failed')](https://sonarcloud.io/dashboard?id=Clinical-Genomics_scout&pullRequest=5254) **Quality Gate failed**  
Failed conditions  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [6.9% Duplication on New Code](https://sonarcloud.io/component_measures?id=Clinical-Genomics_scout&pullRequest=5254&metric=new_duplicated_lines_density&view=list) (required ≤ 3%)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=Clinical-Genomics_scout&pullRequest=5254)


sonarqubecloud[bot]: Please retry analysis of this Pull-Request directly on SonarQube Cloud
sonarqubecloud[bot]: ## [![Quality Gate Failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-failed-20px.png 'Quality Gate Failed')](https://sonarcloud.io/dashboard?id=Clinical-Genomics_scout&pullRequest=5254) **Quality Gate failed**  
Failed conditions  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [6.8% Duplication on New Code](https://sonarcloud.io/component_measures?id=Clinical-Genomics_scout&pullRequest=5254&metric=new_duplicated_lines_density&view=list) (required ≤ 3%)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=Clinical-Genomics_scout&pullRequest=5254)


sonarqubecloud[bot]: ## [![Quality Gate Failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-failed-20px.png 'Quality Gate Failed')](https://sonarcloud.io/dashboard?id=Clinical-Genomics_scout&pullRequest=5254) **Quality Gate failed**  
Failed conditions  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [6.8% Duplication on New Code](https://sonarcloud.io/component_measures?id=Clinical-Genomics_scout&pullRequest=5254&metric=new_duplicated_lines_density&view=list) (required ≤ 3%)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=Clinical-Genomics_scout&pullRequest=5254)



Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4247b63a6..174bfedb2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -16,6 +16,7 @@ About changelog [here](https://keepachangelog.com/en/1.0.0/)
 - Enhanced SNV and SV filtering for cancer and rare disease cases, now supporting size thresholds (≥ or < a specified base pair length)
 - Option to exclude ClinVar significance status in SNVs filters form
 - Made HRD a config parameter and display it for cancer cases.
+- Preset institute-level soft filters for variants (filtering based on "filters" values on variant documents). Settings editable by admins on the institute's settings page. Allows e.g. hiding tumor `in_normal` and `germline_risk` filter status variants.
 ### Changed
 - Do not show overlapping gene panels badge on variants from cases runned without gene panels
 - Set case as research case if it contains any type of research variants
diff --git a/scout/adapter/mongo/institute.py b/scout/adapter/mongo/institute.py
index 5de01aba9..461988e02 100644
--- a/scout/adapter/mongo/institute.py
+++ b/scout/adapter/mongo/institute.py
@@ -56,6 +56,7 @@ class InstituteHandler(object):
         check_show_all_vars: Optional[str] = None,
         clinvar_key: Optional[str] = None,
         clinvar_submitters: Optional[List[str]] = None,
+        soft_filters: Optional[dict] = None,
     ) -> Union[dict, str]:
         """Update the information for an institute."""
 
@@ -127,6 +128,7 @@ class InstituteHandler(object):
             "alamut_institution": alamut_institution,
             "clinvar_key": clinvar_key,
             "show_all_cases_status": show_all_cases_status,
+            "soft_filters": soft_filters,
         }
         for key, value in ADMIN_SETTINGS.items():
             if value not in [None, "", []]:
diff --git a/scout/adapter/mongo/query.py b/scout/adapter/mongo/query.py
index 17e341dc3..58b384514 100644
--- a/scout/adapter/mongo/query.py
+++ b/scout/adapter/mongo/query.py
@@ -307,6 +307,9 @@ class QueryHandler(object):
             if criterion == "show_unaffected" and query.get(criterion) is False:
                 self.affected_inds_query(mongo_query, case_id, gt_query)
 
+            if criterion == "show_soft_filtered" and query.get(criterion) is False:
+                self.soft_filters_query(query=query, mongo_query=mongo_query)
+
             ##### end of fundamental query params
 
         ##### start of the custom query params
@@ -373,6 +376,11 @@ class QueryHandler(object):
 
         return mongo_query
 
+    def soft_filters_query(self, query: dict, mongo_query: dict):
+        """Adds info to variants query to exclude variants flagged by specific filters."""
+        if query.get("institute_soft_filters"):
+            mongo_query["filters"] = {"$nin": query["institute_soft_filters"].split(",")}
+
     def affected_inds_query(self, mongo_query, case_id, gt_query):
         """Add info to variants query to filter out variants which are only in unaffected individuals
 
diff --git a/scout/constants/query_terms.py b/scout/constants/query_terms.py
index d3a80fe0a..b008a020d 100644
--- a/scout/constants/query_terms.py
+++ b/scout/constants/query_terms.py
@@ -18,6 +18,7 @@ FUNDAMENTAL_CRITERIA = [
     "variant_ids",
     "hide_dismissed",
     "show_unaffected",
+    "show_soft_filtered",
 ]
 
 # If there is only one primary criterion given without any secondary, it will also be
diff --git a/scout/server/blueprints/institutes/controllers.py b/scout/server/blueprints/institutes/controllers.py
index 9a9d422af..5b34c067a 100644
--- a/scout/server/blueprints/institutes/controllers.py
+++ b/scout/server/blueprints/institutes/controllers.py
@@ -20,7 +20,10 @@ from scout.constants import (
     SEX_MAP,
     VARIANTS_TARGET_FROM_CATEGORY,
 )
-from scout.server.blueprints.variant.utils import predictions, update_representative_gene
+from scout.server.blueprints.variant.utils import (
+    predictions,
+    update_representative_gene,
+)
 from scout.server.extensions import beacon, store
 from scout.server.utils import institute_and_case, user_institutes
 
@@ -328,6 +331,21 @@ def get_clinvar_submitters(form: MultiDict) -> Optional[List[str]]:
     return clinvar_submitters
 
 
+def get_soft_filters(form: MultiDict) -> Optional[list]:
+    """
+    Return a list with custom soft filters or None.
+    This is not available on the form for unprivileged users, only admin.
+    """
+    if current_user.is_admin is False:
+        return None
+
+    soft_filters = []
+    for filter in form.getlist("soft_filters"):
+        soft_filters.append(filter)
+
+    return soft_filters
+
+
 def get_loqusdb_ids(form: MultiDict) -> Optional[List[str]]:
     """
     Return loqusdb ids from the form multiselect.
@@ -390,6 +408,7 @@ def update_institute_settings(store: MongoAdapter, institute_obj: Dict, form: Mu
         check_show_all_vars=form.get("check_show_all_vars"),
         clinvar_key=form.get("clinvar_key"),
         clinvar_submitters=get_clinvar_submitters(form),
+        soft_filters=get_soft_filters(form),
     )
     return updated_institute
 
diff --git a/scout/server/blueprints/institutes/forms.py b/scout/server/blueprints/institutes/forms.py
index e64f68a60..1a1ab323a 100644
--- a/scout/server/blueprints/institutes/forms.py
+++ b/scout/server/blueprints/institutes/forms.py
@@ -95,7 +95,11 @@ class InstituteForm(FlaskForm):
 
     alamut_institution = StringField("Alamut Institution ID", validators=[validators.Optional()])
 
-    check_show_all_vars = BooleanField("Preselect 'Show also variants only present in unaffected'")
+    check_show_all_vars = BooleanField("Preselect 'Include variants only present in unaffected'")
+
+    soft_filters = NonValidatingSelectMultipleField(
+        "Default soft filters", validators=[validators.Optional()]
+    )
 
     clinvar_key = StringField("API key", widget=PasswordInput(hide_value=False))
 
diff --git a/scout/server/blueprints/institutes/templates/overview/institute_settings.html b/scout/server/blueprints/institutes/templates/overview/institute_settings.html
index 981d4439c..ccf7c1755 100644
--- a/scout/server/blueprints/institutes/templates/overview/institute_settings.html
+++ b/scout/server/blueprints/institutes/templates/overview/institute_settings.html
@@ -104,6 +104,13 @@
       placeholder: "Add Sanger email",
     });
 
+    $('#soft_filters').select2({
+      tags: true,
+      theme: 'bootstrap-5',
+      tokenSeparators: [','],
+      placeholder: "germline_risk",
+    });
+
     $('#clinvar_tags').select2({
       tags: true,
       theme: 'bootstrap-5',
diff --git a/scout/server/blueprints/institutes/templates/overview/utils.html b/scout/server/blueprints/institutes/templates/overview/utils.html
index a4762723f..c189772c4 100644
--- a/scout/server/blueprints/institutes/templates/overview/utils.html
+++ b/scout/server/blueprints/institutes/templates/overview/utils.html
@@ -285,7 +285,7 @@
             </div>
             <!-- End of cohorts settings -->
 
-            <!-- Variants and panels searching -->
+             <!-- Variants and panels searching -->
             <div class="row mt-5 d-flex align-items-center">
             <fieldset>
               <legend>Variants and gene panels searching</legend>
@@ -349,6 +349,25 @@
               </div>
               <!-- End of loqusdb settings -->
 
+              <!-- Custom soft filters for variants -->
+              <div class="row mt-5 d-flex align-items-center">
+                <fieldset>
+                  <legend>Variants custom soft filters</legend>
+                  <div class="row">
+                    <div class="col-sm-6 col-lg-4">
+                      {{form.soft_filters.label(class="control-label", data_bs_toggle="tooltip", data_bs_placement="top", title="Values to filter variant documents with by default. For example germline_risk or in_normal.")}}
+                      <select class="select2" id="soft_filters" name="soft_filters" multiple="true" style="width:100%;">
+                        {% if institute.soft_filters %}
+                          {% for filter in institute.soft_filters %}
+                            <option value="{{filter}}" selected>{{filter}}</option>
+                          {% endfor %}
+                        {% endif %}
+                      </select>
+                    </div>
+                  </div>
+              </div>
+              <!-- End of custom soft filters for variants -->
+
               <!-- Alamut settings -->
               <div class="row mt-5 d-flex align-items-center">
                 <fieldset><legend>Alamut Plus<a class="ms-2 text-decoration-none" href="https://extranet.interactive-biosoftware.com/alamut-visual-plus_API.html" target="_blank" rel="noopener">*</a></legend>
diff --git a/scout/server/blueprints/variants/controllers.py b/scout/server/blueprints/variants/controllers.py
index e42575e04..645c765f6 100644
--- a/scout/server/blueprints/variants/controllers.py
+++ b/scout/server/blueprints/variants/controllers.py
@@ -110,6 +110,12 @@ def populate_chrom_choices(form, case_obj):
     form.chrom.choices = [(chrom, chrom) for chrom in chromosomes]
 
 
+def populate_institute_soft_filters(form, institute_obj):
+    """Populate the hidden field 'institute_soft_filters' with a string containing all institute's soft filters."""
+    if institute_obj.get("soft_filters"):
+        form.institute_soft_filters.data = ",".join(institute_obj["soft_filters"])
+
+
 def variants(
     store,
     institute_obj,
diff --git a/scout/server/blueprints/variants/forms.py b/scout/server/blueprints/variants/forms.py
index 79491f019..494250510 100644
--- a/scout/server/blueprints/variants/forms.py
+++ b/scout/server/blueprints/variants/forms.py
@@ -168,7 +168,9 @@ class VariantFiltersForm(FlaskForm):
     filter_variants = SubmitField(label="Filter variants")
     export = SubmitField(label="Filter and export")
 
-    show_unaffected = BooleanField("Show also variants present only in unaffected", default=False)
+    show_unaffected = BooleanField("Include variants present only in unaffected", default=True)
+    show_soft_filtered = BooleanField(f"Include soft-filtered variants", default=False)
+    institute_soft_filters = HiddenField()
 
 
 class FiltersForm(VariantFiltersForm):
@@ -202,7 +204,6 @@ class CancerFiltersForm(VariantFiltersForm):
     local_obs_cancer_germline_old = IntegerField(
         "Local germline obs. (archive)", validators=[validators.Optional()]
     )
-
     # polymorphic constant base for clinical filter
     clinical_filter_base = CLINICAL_FILTER_BASE_CANCER
 
@@ -311,7 +312,7 @@ class OutlierFiltersForm(FlaskForm):
 
     clinical_filter_base = CLINICAL_FILTER_BASE_OUTLIER
 
-    show_unaffected = BooleanField("Show also variants present only in unaffected", default=False)
+    show_unaffected = BooleanField("Include variants present only in unaffected", default=False)
 
     sort_by = NonValidatingSelectField(
         choices=[
diff --git a/scout/server/blueprints/variants/templates/variants/utils.html b/scout/server/blueprints/variants/templates/variants/utils.html
index 2553d7b7f..ebdd2a879 100644
--- a/scout/server/blueprints/variants/templates/variants/utils.html
+++ b/scout/server/blueprints/variants/templates/variants/utils.html
@@ -36,12 +36,18 @@
       the_form.submit();
     }}
 
-    var show_unaffected =document.getElementById('show_unaffected');
+    var show_unaffected = document.getElementById('show_unaffected');
     if (show_unaffected) {
       show_unaffected.onchange = function() {
       the_form.submit();
     }}
 
+    var show_soft_filtered = document.getElementById('show_soft_filtered');
+    if (show_soft_filtered) {
+      show_soft_filtered.onchange = function() {
+      the_form.submit();
+    }}
+
     function resetPage(){
       document.getElementById('page').value = "1";
     }
@@ -102,6 +108,18 @@
         {{ form.hide_dismissed(class="form-check-input") }}
         {{ form.hide_dismissed.label(class="form-check-label ms-2") }}
       </div>
+      {% if institute.soft_filters %} <!-- Available only for institutes with soft filters in settings -->
+        <div class="form-check d-flex justify-content-start">
+          {{ form.show_soft_filtered(class="form-check-input") }}
+          {{ form.show_soft_filtered.label(
+              class="form-check-label ms-2",
+              data_bs_toggle="tooltip",
+              title="Filters are defined by an admin in the institute settings. Current filters are: " ~
+                form.institute_soft_filters.data|safe
+          ) }}
+          {{ form.institute_soft_filters() }}
+        </div>
+      {% endif %}
       <div class="form-check d-flex justify-content-start">
         {% if institute.check_show_all_vars %}
           <input type="checkbox" class="form-check-input" name="show_unaffected" id="show_unaffected" checked disabled>
diff --git a/scout/server/blueprints/variants/views.py b/scout/server/blueprints/variants/views.py
index c8d05dc90..2709259dc 100644
--- a/scout/server/blueprints/variants/views.py
+++ b/scout/server/blueprints/variants/views.py
@@ -100,6 +100,9 @@ def variants(institute_id, case_name):
     # Populate chromosome select choices
     controllers.populate_chrom_choices(form, case_obj)
 
+    # Populate custom soft filters
+    controllers.populate_institute_soft_filters(form=form, institute_obj=institute_obj)
+
     # populate available panel choices
     form.gene_panels.choices = controllers.gene_panel_choices(store, institute_obj, case_obj)
 
@@ -210,6 +213,9 @@ def str_variants(institute_id, case_name):
     # Populate chromosome select choices
     controllers.populate_chrom_choices(form, case_obj)
 
+    # Populate custom soft filters
+    controllers.populate_institute_soft_filters(form=form, institute_obj=institute_obj)
+
     # populate available panel choices
     form.gene_panels.choices = controllers.gene_panel_choices(store, institute_obj, case_obj)
 
@@ -295,6 +301,9 @@ def sv_variants(institute_id, case_name):
     # Populate chromosome select choices
     controllers.populate_chrom_choices(form, case_obj)
 
+    # Populate custom soft filters
+    controllers.populate_institute_soft_filters(form=form, institute_obj=institute_obj)
+
     genome_build = "38" if "38" in str(case_obj.get("genome_build", "37")) else "37"
     cytobands = store.cytoband_by_chrom(genome_build)
 
@@ -385,6 +394,9 @@ def mei_variants(institute_id, case_name):
     # Populate chromosome select choices
     controllers.populate_chrom_choices(form, case_obj)
 
+    # Populate custom soft filters
+    controllers.populate_institute_soft_filters(form=form, institute_obj=institute_obj)
+
     # populate available panel choices
     form.gene_panels.choices = controllers.gene_panel_choices(store, institute_obj, case_obj)
 
@@ -495,6 +507,9 @@ def cancer_variants(institute_id, case_name):
     # Populate chromosome select choices
     controllers.populate_chrom_choices(form, case_obj)
 
+    # Populate custom soft filters
+    controllers.populate_institute_soft_filters(form=form, institute_obj=institute_obj)
+
     form.gene_panels.choices = controllers.gene_panel_choices(store, institute_obj, case_obj)
 
     genome_build = "38" if "38" in str(case_obj.get("genome_build", "37")) else "37"
@@ -575,6 +590,9 @@ def cancer_sv_variants(institute_id, case_name):
     # Populate chromosome select choices
     controllers.populate_chrom_choices(form, case_obj)
 
+    # Populate custom soft filters
+    controllers.populate_institute_soft_filters(form=form, institute_obj=institute_obj)
+
     genome_build = "38" if "38" in str(case_obj.get("genome_build", "37")) else "37"
     cytobands = store.cytoband_by_chrom(genome_build)
 
@@ -659,6 +677,9 @@ def fusion_variants(institute_id, case_name):
     # Populate chromosome select choices
     controllers.populate_chrom_choices(form, case_obj)
 
+    # Populate custom soft filters
+    controllers.populate_institute_soft_filters(form=form, institute_obj=institute_obj)
+
     genome_build = "38" if "38" in str(case_obj.get("genome_build", "37")) else "37"
     cytobands = store.cytoband_by_chrom(genome_build)
 


Test patch:
diff --git a/tests/adapter/mongo/test_query.py b/tests/adapter/mongo/test_query.py
index af2247459..4f252b4f7 100644
--- a/tests/adapter/mongo/test_query.py
+++ b/tests/adapter/mongo/test_query.py
@@ -105,7 +105,7 @@ def test_gene_symbols_query(adapter, case_obj):
 
 
 def test_gene_panel_query(adapter, case_obj):
-    """Test variants query using a gene panel cointaining a certain gene"""
+    """Test variants query using a gene panel containing a certain gene"""
 
     # GIVEN a database containing a minimal gene panel
     test_gene = "POT1"
@@ -131,6 +131,24 @@ def test_gene_panel_query(adapter, case_obj):
     }
 
 
+def test_soft_filters_query(adapter, case_obj):
+    """Test variants query by providing a form with soft filters data."""
+
+    # GIVEN some soft filters saved at the institute level:
+    institute_soft_filters = "germline_risk,in_normal"
+    show_soft_filtered = False
+
+    # WHEN user query contains this data:
+    query = {
+        "institute_soft_filters": institute_soft_filters,
+        "show_soft_filtered": show_soft_filtered,
+    }
+    mongo_query = adapter.build_query(case_obj["_id"], query=query)
+
+    # THEN the MongoDB query should contain soft filters:
+    assert mongo_query["filters"] == {"$nin": institute_soft_filters.split(",")}
+
+
 def test_genotype_query_heterozygous(adapter, case_obj):
     """Test variants query using a 'genotypes' field in variants filter to filter for heterozygous variants"""
 
diff --git a/tests/server/blueprints/institutes/test_institute_views.py b/tests/server/blueprints/institutes/test_institute_views.py
index 664ec53bd..65762c2ae 100644
--- a/tests/server/blueprints/institutes/test_institute_views.py
+++ b/tests/server/blueprints/institutes/test_institute_views.py
@@ -139,6 +139,7 @@ def test_institute_settings(app, user_obj, institute_obj):
             "alamut_key": "test_alamut_key",
             "clinvar_key": "test_clinvar_key",
             "clinvar_emails": ["john@doe.com"],
+            "soft_filters": ["in_normal"],
         }
 
         # via POST request
@@ -163,6 +164,7 @@ def test_institute_settings(app, user_obj, institute_obj):
         assert updated_institute["alamut_key"] == form_data["alamut_key"]
         assert updated_institute["clinvar_key"] == form_data["clinvar_key"]
         assert updated_institute["clinvar_submitters"] == form_data["clinvar_emails"]
+        assert updated_institute["soft_filters"] == ["in_normal"]
 
 
 def test_cases_export_samples(app, institute_obj):