Skip to content

PR: Backbone subsampling — stable sequence set across reruns - #9

Merged
filiperomero2 merged 5 commits into
mainfrom
feat/major_code_review
Jun 10, 2026
Merged

PR: Backbone subsampling — stable sequence set across reruns#9
filiperomero2 merged 5 commits into
mainfrom
feat/major_code_review

Conversation

@filiperomero2

Copy link
Copy Markdown
Contributor

Summary

Adds opt-in --backbone-from <prev_workdir> flag to flexpipe-run so a surveillance rerun can anchor itself to a previous build's subsampled strain list. The new subsample becomes the union of (stable backbone strains) + (freshly-selected new sequences), making results comparable across months-apart runs without re-subsampling from scratch.

Motivation

Without this, each run independently re-subsamples from the full available pool. Even older, previously-selected sequences can drop in or out of the tree between runs — conflating biological signal with sampling noise. For a lab running scheduled surveillance (e.g. RSV every 6 months), this makes "what's new since last time?" hard to answer reliably.

Mechanism

augur subsample is driven entirely by a YAML config. A sample set with only an include: path force-keeps every listed strain regardless of group_by / sequences_per_group caps. We exploit this:

  1. _materialize_backbone() in run.py reads the strain column from <prev_workdir>/results/subsampled/metadata.tsv and writes it to <workdir>/config/backbone_strains.txt
  2. cfg.subsampling.backbone_strains is set to that path before write_snakemake_config_overrides is called, so it propagates into the single resolved Snakemake configfile
  3. The ingest Snakefile resolve_subsample_config rule passes it to flexpipe.config.resolve_subsample_config(), which injects samples.__backbone__: {include: <path>} into the resolved subsample YAML
  4. augur subsample force-keeps the backbone strains on top of the normal subsample

Usage

# Initial build (e.g. June 2024)
flexpipe-run --config builds/rsv-a-brazil/config.yaml \
             --workdir /data/rsv-A --run-date 2024-06-01

# 2 years later — backbone anchors the 2024 selection
flexpipe-run --config builds/rsv-a-brazil/config.yaml \
             --workdir /data/rsv-B --run-date 2026-06-01 \
             --backbone-from /data/rsv-A

Edge cases

Scenario Behaviour
--backbone-from omitted Complete no-op — identical to current behaviour
Previous workdir missing or metadata absent Warning logged, run proceeds without backbone
Empty backbone (header-only metadata) Warning logged, run proceeds without backbone
--backbone-from == current workdir Hard error, exit 2
Backbone strain withdrawn from source Silently skipped by augur subsample (acceptable)
Backbone strain dropped by upstream QC / clade_filter Cannot be force-kept — backbone retention is best-effort, bounded by the quality contract

Key design decisions

  • Explicit CLI flag, not auto-detection — backbone is an operational decision per run, not a stable property of the build definition. Auto-detecting from the workdir risks silently anchoring to stale state on an ordinary rerun.
  • No QC bypassinclude applies within augur subsample, which runs after augur filter and clade_filter. Strains that newly fail QC are correctly excluded even if they were in the previous backbone.
  • Runtime-only fieldSubsamplingConfig.backbone_strains is never authored in builds/*/config.yaml (would bake a machine-specific absolute path into version control).
  • Provenancebackbone_from path and backbone_strain_count are recorded in manifest.json.

Files changed

  • flexpipe/paths.pyWorkdirPaths.backbone_strains property (config/backbone_strains.txt)
  • flexpipe/config.pySubsamplingConfig.backbone_strains: str | None; resolve_subsample_config() extended with backbone_strains param
  • flexpipe/run.py_materialize_backbone() helper; --backbone-from CLI arg; threading through run_pipeline_run_pipeline_locked; manifest provenance
  • ingest/Snakefileresolve_subsample_config rule reads _sub.get("backbone_strains") and passes it through
  • CLAUDE.md — usage example, semantics, and limitations documented

Tests

  • 13 new unit tests covering _materialize_backbone (happy path, missing dir, empty metadata, self-reference, end-to-end run_pipeline propagation), resolve_subsample_config backbone injection, and config schema propagation to resolved YAML
  • 1 new integration dry-run test confirming the ingest DAG plans cleanly when backbone_strains is set
  • All 563 tests pass; 78.8% coverage (threshold 60%); ruff + black + mypy clean

filiperomero2 and others added 5 commits June 10, 2026 14:20
Adds WorkdirPaths.backbone_strains property (config/backbone_strains.txt)
and SubsamplingConfig.backbone_strains field (None by default). The field
propagates automatically to the resolved Snakemake config via model_dump().
No behaviour change — feature is completely off when the field is None.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…onfig

When backbone_strains (a path to a one-strain-per-line include-list) is
provided, a synthetic samples.__backbone__ entry is added to the resolved
subsample config so augur subsample force-keeps the listed strains
regardless of group caps. Defaults to None — no-op for existing callers.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds _materialize_backbone() helper that extracts the previous run's
subsampled strain list, writes it to config/backbone_strains.txt, and
sets cfg.subsampling.backbone_strains before write_snakemake_config_overrides
so the resolved config already carries the path.

Guards: self-reference (exit 2), missing previous run (warning + no-op),
empty backbone (warning + no-op). Manifest records backbone_from path and
strain count for provenance. CLI gains --backbone-from PREV_WORKDIR flag.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
resolve_subsample_config rule now reads _sub.get("backbone_strains") from
the resolved config and passes it to resolve_subsample_config() so the
__backbone__ synthetic sample set is injected before augur subsample runs.

Adds integration test confirming the DAG plans cleanly when
backbone_strains is set in the resolved config.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…rnals

Adds --backbone-from usage example to CLAUDE.md Running the Full Pipeline
section (with RSV 2-year-gap example), documents key limitations
(best-effort QC, runtime-only, self-reference guard), and documents the
implementation path (backbone_strains.txt → SubsamplingConfig →
resolve_subsample_config → __backbone__ sample set).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@filiperomero2
filiperomero2 merged commit 20ef2a7 into main Jun 10, 2026
4 checks passed
@filiperomero2
filiperomero2 deleted the feat/major_code_review branch June 17, 2026 13:16
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