Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# CHANGELOG

We use this CHANGELOG to document breaking changes, new features, bug fixes, and config value changes that may affect both the usage of the workflows and the outputs of the workflows.

## 2026

* 11 August 2026: Phylogenetic workflow configuration is now validated against a strict schema. The workflow will error if your configuration has extraneous entries that were previously ignored.
226 changes: 226 additions & 0 deletions config.schema.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
$schema: "https://json-schema.org/draft/2020-12/schema"
title: RSV Phylogenetic Workflow Configuration
description: >-
This is the schema for the Nextstrain rsv phylogenetic workflow's
configuration file.

$defs:
per_subtype_map: &per_subtype_map
type: object
additionalProperties: false
propertyNames:
title: Subtype
description: Subtype ('a' or 'b')

per_build_map: &per_build_map
type: object
additionalProperties: false
propertyNames:
title: Build name
description: Build name ('genome', 'G', 'F', or 'F-antibody-escape')

per_resolution_map: &per_resolution_map
type: object
additionalProperties: false
propertyNames:
title: Resolution name
description: Resolution name ('all-time', '6y', or '3y')

input_item:
type: object
additionalProperties: false
required:
- name
anyOf:
- required: [metadata]
- required: [sequences]
properties:
name:
type: string
metadata:
type: string
sequences:
type: string

type: object
additionalProperties: false
properties:
conda_environment:
type: string
Comment on lines +48 to +49

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.

non-blocking

Just noticed this conda_environment param isn't used in the workflow at all. I wish there was a way for us to validate the schema against the workflow to flag things like this.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Yeah, schema can get out of sync with actual usage. There are ways to programmatically find and track every usage of the config variable and compare that against the schema, but the complexity doesn't seem worthwhile.

I'll leave it as-is in this PR.

genesforglycosylation:
type: array
items:
type: string
builds_to_run:
type: array
items:
type: string
resolutions_to_run:
type: array
items:
type: string
subtypes:
type: array
items:
type: string
inputs:
type: array
items:
$ref: "#/$defs/input_item"
additional_inputs:
type: array
items:
$ref: "#/$defs/input_item"
exclude:
type: string
description:
type: string
strain_id_field:
type: string
display_strain_field:
type: string
filter:
type: object
additionalProperties: false
properties:
group_by:
type: string
min_coverage:
<<: *per_build_map
patternProperties:
"^.*$":
type: number
min_length:
<<: *per_build_map
patternProperties:
"^.*$":
type: integer
resolutions:
<<: *per_resolution_map
patternProperties:
"^.*$":
type: object
additionalProperties: false
properties:
min_date:
type: string
background_min_date:
type: string
subsample_max_sequences:
<<: *per_build_map
patternProperties:
"^.*$":
type: integer
exclude_where:
type: object
additionalProperties: false
properties:
recent:
type: array
items:
type: string
background:
type: array
items:
type: string
missing_data_threshold:
type: integer
files:
type: object
additionalProperties: false
properties:
auspice_config:
type: string
auspice_config_additional_colorings:
type: string
auspice_config_f_antibody_escape:
type: string
auspice_config_non-genome_builds:
type: string
refine:
type: object
additionalProperties: false
properties:
coalescent:
type: string
date_inference:
type: string
clock_filter_iqd:
type: number
divergence_units:
type: string
ancestral:
type: object
additionalProperties: false
properties:
inference:
type: string
cds:
<<: *per_build_map
patternProperties:
"^.*$":
type: string
traits:
type: object
additionalProperties: false
properties:
columns:
type: [string, array]
items:
type: string
frequencies:
type: object
additionalProperties: false
properties:
resolutions:
<<: *per_resolution_map
patternProperties:
"^.*$":
type: object
additionalProperties: false
properties:
min_date:
type: string
nextclade_attributes:
<<: *per_subtype_map
patternProperties:
"^.*$":
type: object
additionalProperties: false
properties:
name:
type: string
reference_name:
type: string
accession:
type: string
f_dms_data:
type: string
f_dms_antibodies:
type: array
items:
type: string
dms_only_positive_escape:
type: boolean
enrich_antibody_escape:
<<: *per_build_map
patternProperties:
"^.*$":
type: object
additionalProperties: false
properties:
nseqs_per_antibody_scoretype:
type: integer
group_by:
type: array
items:
type: string
max_identical_f_prot_muts:
type: integer
max_identical_max_escape_mut:
type: integer
custom_rules:
type: array
description: Custom Snakemake rule files to include. If used, this will disable config schema validation.
items:
type: string
4 changes: 2 additions & 2 deletions config/configfile.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ filter:
F-antibody-escape: 1200
resolutions:
all-time:
min_date: 1975-01-01
min_date: "1975-01-01"

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.

Date values in the default config file are explicitly quoted to avoid
being parsed into Python as date objects by Snakemake's YAML parser.

OH! That's good to know.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

It hasn't mattered so far because the date objects get translated back to the same YYYY-MM-DD strings in augur filter --min-date {params.min_date}.

In augur subsample, we explicitly parse date-like values into Python as strings.

6y:
min_date: 6Y
background_min_date: 12Y
Expand Down Expand Up @@ -91,7 +91,7 @@ traits:
frequencies:
resolutions:
all-time:
min_date: 1975-01-01
min_date: "1975-01-01"
6y:
min_date: 6Y
3y:
Expand Down
40 changes: 39 additions & 1 deletion workflow/snakemake_rules/config.smk
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,42 @@ OUTPUTS:

results/run_config.yaml
"""
write_config("results/run_config.yaml")
import sys
from augur.validate import load_json_schema_locally, validate_json, ValidateError
from pathlib import Path

def main():
dump_and_validate(
"results/run_config.yaml",
Path(workflow.basedir) / "config.schema.yaml"
)


# TODO: move this to nextstrain/shared
# Copied from measles with some cleanups
# <https://github.com/nextstrain/measles/blob/60634e2f/phylogenetic/rules/config.smk#L36-L57>
def dump_and_validate(dump_path, schema_path):
"""
Write Snakemake's 'config' variable to a file, then validate it against the
schema. Do both in the same function so that the validation output can
easily reference the path of the dumped config for inspection.
"""
global config

write_config(dump_path)

if "custom_rules" in config:
print("WARNING: Skipping config schema validation because custom rules are defined.", file=sys.stderr)
return

try:
validator = load_json_schema_locally(schema_path)
validate_json(config, validator, dump_path)
except ValidateError as e:
raise InvalidConfigError(str(e)) from e

try:
main()
except InvalidConfigError as e:
print(f"ERROR: {e}", file=sys.stderr)
exit(1)
Loading