diff --git a/AGENTS.md b/AGENTS.md index 8686b2f..bcbcdc5 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -105,9 +105,10 @@ The release strategy is evidence before expansion: v0.3: evidence pack + assembly gate + provenance checksums v0.4: compare mode for many FASTA files v0.5: submission readiness gate -v0.6: transcriptome profile -v0.7: protein profile -v0.8: reference-panel profile +v0.6: workflow-compatible exit contract +v0.7: transcriptome profile +v0.8: protein profile +v0.9: reference-panel profile later: MCP/tool-agent interface and optional local summaries ``` @@ -123,20 +124,20 @@ Default product boundaries: Recommended next big release: ```text -v0.5 should make submission readiness concrete before adding broad new biological profiles. +v0.6 should simplify workflow integration before adding broad new biological profiles. ``` The next planned feature direction is: ```text -Submission Readiness Gate: --gate submission with --submission-target generic|ncbi. +Workflow-Compatible Exit Contract: successful reports exit 0; report fields carry QC status. ``` -This should stay FASTA-level and database-free. It should check identifier -safety, duplicate first-token IDs, unsafe characters, long identifiers, gap-like -N runs, high ambiguity, and tiny-record advisories. It must not claim repository -acceptance, biological completeness, annotation correctness, or contamination -confirmation. +This should keep JSON and TSV as the source of truth. Successful report +generation should exit `0`, including WARN and FAIL reports. Argument parsing +errors should exit `2`; configuration, input-access, and runtime errors should +exit `3`. Existing v0.5 workflow integrations should keep compatibility handling +until v0.6 packages and containers are published. ## Collaboration Preference diff --git a/Cargo.lock b/Cargo.lock index fda743e..e718225 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -360,7 +360,7 @@ dependencies = [ [[package]] name = "fastaguard" -version = "0.5.0" +version = "0.6.0" dependencies = [ "anyhow", "assert_cmd", diff --git a/Cargo.toml b/Cargo.toml index b738db6..8a54f06 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "fastaguard" -version = "0.5.0" +version = "0.6.0" edition = "2021" license = "MIT" description = "FASTA preflight QC for assembly pipelines" diff --git a/README.md b/README.md index 7b14e13..bf8fd98 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ downstream tool. | Channel | Status | | --- | --- | -| Source/package metadata | `v0.5.0` is the latest tagged source release | +| Source/package metadata | This branch prepares `v0.6.0`; `v0.5.0` remains the latest tag | | GitHub release | v0.5 GitHub release binaries are built from the `v0.5.0` tag | | Bioconda | `v0.5.0` is live for Linux and macOS x86_64/ARM64 | | BioContainers | `v0.5.0` is live as a pinned workflow image | @@ -123,6 +123,7 @@ fastaguard --version The `--gate pipeline` examples below require FastaGuard `v0.3.0` or newer. The `fastaguard compare` example requires FastaGuard `v0.4.0` or newer. The `--gate submission` example requires FastaGuard `v0.5.0` or newer. +The conventional exit contract below starts with FastaGuard `v0.6.0`. Run the assembly preflight check: @@ -142,10 +143,10 @@ fastaguard sample.fa --profile assembly --gate pipeline ``` The `pipeline` gate is the v0.3 assembly preset for workflow stop/go decisions. -It fails on duplicate IDs, invalid characters, invalid FASTA structure, and -high-N content. GC and length outliers remain advisory by default because they -are routing signals, not proof of contamination or misassembly. To make an -advisory finding block a pipeline, add it explicitly with `--fail-on`. +It marks duplicate IDs, invalid characters, invalid FASTA structure, and high-N +content as blocking findings. GC and length outliers remain advisory by default +because they are routing signals, not proof of contamination or misassembly. To +mark an advisory finding as blocking, add it explicitly with `--fail-on`. v0.4 compare starter example: @@ -197,15 +198,21 @@ Published BioContainers provides the v0.5 image for workflow engines: docker pull quay.io/biocontainers/fastaguard:0.5.0--hfa8f182_0 ``` -Exit codes: +Starting with FastaGuard v0.6.0, exit codes are: ```text -0 = pass -1 = warnings above configured threshold -2 = hard QC failure -3 = invalid input / tool error +0 = command completed and requested outputs were written +2 = argument parsing error +3 = configuration, input-access, or runtime error ``` +QC PASS/WARN/FAIL decisions are recorded in the machine-readable outputs, +especially `verdict.status`, `gate.status`, and `gate.blocking_findings`. +Workflow engines should route on those fields instead of interpreting QC +findings from the process exit code. Single-file TSV reports include +`input_path`, `verdict`, and `gate_status`; compare TSV reports retain one row +per input with its path and status fields. + ## Product Thesis FASTA files are everywhere, but FASTA QC is fragmented across ad hoc scripts, `seqkit stats`, assembly QC tools, completeness tools, contamination workflows, and pipeline-specific checks. Each is useful, but none is the simple default first command for: @@ -261,7 +268,7 @@ v0.2 expands the assembly preflight layer with: v0.3 adds the assembly gate contract: -- `--gate pipeline` for default workflow blocking behavior +- `--gate pipeline` for the default workflow gate policy - `gate.blocking_findings` for machine stop/go decisions - checksum provenance with `provenance.input_sha256` - explicit advisory findings for evidence that should route follow-up QC rather @@ -285,6 +292,15 @@ v0.5 adds the submission-readiness gate: - boundaries that keep FastaGuard upstream of official validators, NCBI FCS, annotation validation, QUAST, BUSCO, BlobToolKit, and CheckM +v0.6 makes report generation workflow-compatible: + +- successful report generation exits `0` for PASS, WARN, and FAIL reports +- argument parsing errors exit `2`; configuration, input-access, and runtime + errors exit `3` +- single-file TSV reports include `input_path` for downstream routing +- workflows enforce QC policy from stable report fields instead of process + status + ## Positioning FastaGuard should recommend deeper tools when they are appropriate: @@ -324,6 +340,7 @@ FastaGuard catches FASTA-level assembly problems before expensive assembly QC. - [v0.5 submission readiness evidence](docs/evidence/fastaguard-v0.5-submission-readiness.md) - [v0.5 public evidence workflow](docs/evidence/fastaguard-v0.5-public-evidence.md) - [Packaging](docs/packaging.md) +- [v0.6.0 release notes](docs/releases/v0.6.0.md) - [v0.5.0 release notes](docs/releases/v0.5.0.md) - [v0.4.0 release notes](docs/releases/v0.4.0.md) - [v0.3.0 release notes](docs/releases/v0.3.0.md) diff --git a/docs/mvp-spec.md b/docs/mvp-spec.md index aaf285d..9c8ddc9 100644 --- a/docs/mvp-spec.md +++ b/docs/mvp-spec.md @@ -150,13 +150,19 @@ Default WARN conditions: ## Exit Codes +Starting with FastaGuard v0.6.0: + ```text -0 = pass -1 = warnings above configured threshold -2 = hard QC failure -3 = invalid input / tool error +0 = command completed and requested outputs were written +2 = argument parsing error +3 = configuration, input-access, or runtime error ``` +QC PASS/WARN/FAIL decisions are report fields, not process-failure signals. +Pipelines should read `verdict.status`, `gate.status`, and +`gate.blocking_findings` from JSON/TSV outputs. Single-file TSV reports include +`input_path`, `verdict`, and `gate_status` for downstream routing. + ## Success Criteria The first release is successful if: @@ -164,7 +170,7 @@ The first release is successful if: - it validates huge FASTA files without loading full sequences into memory - it produces useful HTML, JSON, TSV, and MultiQC-compatible outputs - it catches invalid FASTA structure, duplicate IDs, invalid characters, and high-N content -- it has deterministic, documented exit codes +- it has deterministic, documented status fields and tool-error exit codes - it can be added to a Nextflow or Snakemake pipeline in under 5 minutes ## Implementation Status @@ -174,5 +180,5 @@ The v0.1 assembly MVP is implemented as a Rust CLI with: - streaming FASTA parsing for plain and gzipped files - assembly metrics - explainable findings -- deterministic verdict exit codes +- deterministic verdict status fields - JSON, TSV, HTML, and MultiQC-compatible outputs diff --git a/docs/output-contract.md b/docs/output-contract.md index 72f9efc..5a2d11b 100644 --- a/docs/output-contract.md +++ b/docs/output-contract.md @@ -4,7 +4,7 @@ FastaGuard should be pipeline-native from the first release. -The output contract is as important as the HTML report. Pipeline authors need stable field names, deterministic behavior, documented exit codes, and versioned schemas. +The output contract is as important as the HTML report. Pipeline authors need stable field names, deterministic behavior, documented tool-error exit codes, and versioned schemas. ## Artifacts @@ -29,6 +29,23 @@ fastaguard_compare_mqc.json v0.5 adds submission-readiness gate fields to the same JSON, TSV, HTML, MultiQC, and compare artifacts. JSON remains the source of truth. +v0.6 separates process execution from QC status. Successful report generation +returns exit code `0` for PASS, WARN, and FAIL reports. + +## Process Exit Contract + +Starting with FastaGuard v0.6.0: + +```text +0 = command completed and requested outputs were written +2 = argument parsing error +3 = configuration, input-access, or runtime error +``` + +Workflow engines should apply stop/go policy from `gate.status`, +`gate.blocking_findings`, or `verdict.status`. Process status only indicates +whether FastaGuard completed the requested command and reports. + ## JSON Contract Example v0.3 shape: @@ -416,7 +433,8 @@ Recommended first rows: ```text metric value -schema_version 0.3.0 +schema_version 0.5.0 +input_path sample.fa profile assembly verdict FAIL gate_mode pipeline diff --git a/docs/packaging.md b/docs/packaging.md index aafaea4..7d0a0c8 100644 --- a/docs/packaging.md +++ b/docs/packaging.md @@ -135,7 +135,7 @@ Keep future releases compatible with Bioconda expectations: - keep a single static-ish CLI binary target - keep deterministic tests and tiny fixtures - avoid runtime databases for early releases -- maintain stable exit codes +- keep process exit codes reserved for CLI/tool execution errors - maintain a versioned JSON Schema Bioconda recipe guidance checked for this setup: diff --git a/docs/releases/v0.6.0.md b/docs/releases/v0.6.0.md new file mode 100644 index 0000000..41c1066 --- /dev/null +++ b/docs/releases/v0.6.0.md @@ -0,0 +1,31 @@ +# FastaGuard v0.6.0 + +## Workflow-Compatible Exit Contract + +FastaGuard now separates command execution from FASTA quality decisions. +Successful report generation exits with code `0`, including reports whose +verdict or gate status is `WARN` or `FAIL`. Argument parsing errors exit with +code `2`, while configuration, input-access, and runtime errors exit with code +`3`. + +QC decisions remain explicit in the report contract: + +- `verdict.status` records the overall PASS/WARN/FAIL result. +- `gate.status` records the selected gate result. +- `gate.blocking_findings` lists findings that should stop downstream work. +- single-file TSV reports include `input_path`, `verdict`, and `gate_status`. +- compare TSV reports retain one row per input with its path and status fields. + +This keeps JSON and TSV reports available to Nextflow, Snakemake, nf-core, and +other workflow engines. Pipelines can publish the evidence first and apply +their own stop/go policy downstream. + +## Migration + +Workflows that previously interpreted process exit codes `1` and `2` as WARN +and FAIL should instead read `gate.status` or `verdict.status` from JSON or TSV. +The repository includes `examples/workflows/check_fastaguard_gate.py` for +workflows that need a separate enforcement step after reports are collected. + +The JSON schema and finding catalog remain at version `0.5.0` because their +structures and finding semantics are unchanged in this release. diff --git a/docs/roadmap.md b/docs/roadmap.md index 361a3d9..4209fee 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -27,7 +27,7 @@ Capabilities: - GC-vs-length plot data and HTML plot - PASS / WARN / FAIL verdict - JSON, TSV, HTML, and MultiQC-compatible outputs -- deterministic exit codes +- deterministic report status fields ## v0.2: Assembly Trust + Pipeline Adoption @@ -118,7 +118,25 @@ Development scope: - FastaGuard does not replace NCBI, ENA, DDBJ official validators or guarantee repository acceptance -## v0.6: Transcriptome Profile +## v0.6: Workflow-Compatible Exit Contract + +Goal: + +```text +Separate command execution from FASTA quality decisions in workflow engines. +``` + +Development scope: + +- return exit code `0` whenever requested reports are written successfully, + including WARN and FAIL reports +- reserve exit code `2` for argument parsing errors +- reserve exit code `3` for configuration, input-access, and runtime errors +- keep PASS/WARN/FAIL decisions in stable JSON and TSV report fields +- include `input_path` in single-file TSV reports for downstream routing +- document migration from legacy QC-derived process exit codes + +## v0.7: Transcriptome Profile Potential additions: @@ -128,7 +146,7 @@ Potential additions: - extreme GC outliers - isoform-heavy warning heuristics -## v0.7: Protein Profile +## v0.8: Protein Profile Potential additions: @@ -138,7 +156,7 @@ Potential additions: - low-complexity regions - suspicious nucleotide-looking proteins -## v0.8: Reference Panel Profile +## v0.9: Reference Panel Profile Potential additions: diff --git a/docs/tool-landscape.md b/docs/tool-landscape.md index 255d828..d98305f 100644 --- a/docs/tool-landscape.md +++ b/docs/tool-landscape.md @@ -56,7 +56,7 @@ Without FastaGuard, users typically combine several partial checks: - run QUAST for assembly metrics - run BUSCO for biological completeness - run BlobToolKit or taxonomy tooling for contamination exploration -- rely on pipeline-specific assumptions for exit codes and report parsing +- rely on pipeline-specific assumptions for report parsing and stop/go policy That works, but it is fragmented. The missing layer is a default, explainable, machine-readable FASTA preflight contract. diff --git a/docs/use-cases.md b/docs/use-cases.md index c8c3722..f77b4e2 100644 --- a/docs/use-cases.md +++ b/docs/use-cases.md @@ -56,11 +56,12 @@ spend time on bad input. ### Pipeline Gate For Workflow Engines FastaGuard gives Nextflow, Snakemake, nf-core, Galaxy, and institutional -pipelines a simple PASS/WARN/FAIL decision with deterministic exit codes and -structured evidence. +pipelines a simple PASS/WARN/FAIL decision with structured evidence in JSON, +TSV, HTML, and MultiQC-compatible outputs. Pipelines can stop early on hard FASTA failures, continue with warnings, or -route samples to follow-up tools based on machine-readable findings. +route samples to follow-up tools based on machine-readable fields such as +`gate.status` and `gate.blocking_findings`. ### Batch Triage With Compare Mode diff --git a/docs/vision-plan.md b/docs/vision-plan.md index 0ae8b51..bed45ec 100644 --- a/docs/vision-plan.md +++ b/docs/vision-plan.md @@ -26,7 +26,7 @@ The release strategy is evidence before expansion. FastaGuard should not rush into many biological profiles until the assembly preflight contract is trusted. The product should earn adoption in this order: -1. **Trust:** reproducible evidence, stable schemas, clear exit codes, installable packages. +1. **Trust:** reproducible evidence, stable schemas, clear status fields, installable packages. 2. **Integration:** Bioconda, BioContainers, MultiQC, Nextflow, Snakemake, Galaxy. 3. **Scale:** compare mode for many FASTA files and batch pipeline reports. 4. **Readiness depth:** submission-oriented preflight checks before official validators. @@ -109,7 +109,25 @@ The v0.5 contract should make workflow routing explicit through `gate.mode`, `readiness.categories[id=submission]` record, while still pointing users to official validators for final repository-specific checks. -### v0.6: Transcriptome Profile +### v0.6: Workflow-Compatible Exit Contract + +Goal: + +```text +Let workflows collect complete QC reports before applying their own stop/go policy. +``` + +Successful report generation should exit with code `0` for PASS, WARN, and FAIL +reports. Argument parsing errors should use code `2`; configuration, +input-access, and runtime errors should use code `3`. JSON and TSV remain the +source of truth for `verdict.status`, `gate.status`, and blocking findings. + +Single-file TSV reports should include `input_path` alongside status fields so +workflow engines can route samples without scraping logs or HTML. Existing +workflow examples pinned to v0.5 should retain compatibility handling until a +v0.6 package and container are published. + +### v0.7: Transcriptome Profile Goal: @@ -129,7 +147,7 @@ FastaGuard should not claim transcriptome biological completeness. It should route users to transcriptome-specific completeness and annotation tools when needed. -### v0.7: Protein Profile +### v0.8: Protein Profile Goal: @@ -148,7 +166,7 @@ Initial protein checks: Protein mode should be strict about alphabet validity and careful about biology: it should flag preflight problems, not infer functional correctness. -### v0.8: Reference-Panel Profile +### v0.9: Reference-Panel Profile Goal: @@ -219,7 +237,7 @@ Required adoption qualities: - generated BioContainers image - stable JSON schema - deterministic outputs -- clear exit codes +- clear tool-error exit codes - MultiQC compatibility - Nextflow, nf-core, Snakemake, and Galaxy examples - small public evidence pack @@ -239,12 +257,13 @@ Recommended sequence: v0.3: evidence pack + assembly gate + provenance checksums v0.4: compare mode for many FASTA files v0.5: submission readiness gate -v0.6: transcriptome profile -v0.7: protein profile -v0.8: reference-panel profile +v0.6: workflow-compatible exit contract +v0.7: transcriptome profile +v0.8: protein profile +v0.9: reference-panel profile later: MCP/tool-agent interface and optional local summaries ``` This path gives FastaGuard the best chance to become a default tool: prove the -assembly gate first, scale to batches, make submission readiness concrete, then -expand profiles. +assembly gate first, scale to batches, make submission readiness concrete, +simplify workflow integration, then expand profiles. diff --git a/docs/workflow-readiness.md b/docs/workflow-readiness.md index b466007..fbe9976 100644 --- a/docs/workflow-readiness.md +++ b/docs/workflow-readiness.md @@ -32,6 +32,12 @@ External upstream-style validation was run on 2026-07-03 in dedicated checkouts: PASS, WARN, FAIL, and invalid FASTA fixtures plus captured `exit_code` outputs. +The v0.6 source contract removes QC-derived process failures: successfully +written PASS, WARN, and FAIL reports all return exit code `0`. The pinned v0.5 +starters keep their compatibility capture until v0.6 packages and containers +are published. After publication, upstream wrappers can remove that workaround +and route directly from JSON or TSV status fields. + ## Safe Order 1. Run local repository tests first. @@ -53,11 +59,11 @@ official submission validators. The default workflow pattern is: collect FASTA-level evidence -> apply stop/go policy -> route downstream tools ``` -For local fail-fast runs, `--gate pipeline` and `--gate submission` write JSON, -TSV, HTML, and MultiQC-compatible evidence before returning a blocking exit -code. Some workflow engines remove failed-job outputs by default, so production -integrations should use a collect-then-gate pattern when evidence preservation -matters. The important contract fields are: +With the published v0.5 runtime, `--gate pipeline` and `--gate submission` write +JSON, TSV, HTML, and MultiQC-compatible evidence before returning a QC-derived +exit code. The pinned local starters capture that code so the evidence remains +available, then leave stop/go enforcement to a downstream gate step. The +important contract fields are: - `verdict.status` - `gate.mode` diff --git a/examples/nextflow/main.nf b/examples/nextflow/main.nf index efad50d..f98f526 100644 --- a/examples/nextflow/main.nf +++ b/examples/nextflow/main.nf @@ -14,8 +14,8 @@ process FASTAGUARD { script: """ - # Fail-fast starter example: FastaGuard WARN exits 1 and FAIL exits 2. - # Depending on engine behavior, evidence may remain only in the work directory. + # FastaGuard writes PASS/WARN/FAIL decisions to JSON/TSV/HTML reports. + # Route downstream workflow steps by reading gate.status from JSON. fastaguard ${fasta} \ --profile assembly \ --gate pipeline \ @@ -32,6 +32,6 @@ workflow { // Compare mode starter pattern for v0.4 cohort triage: // fastaguard compare assemblies/*.fa --profile assembly --gate pipeline -// This is local fail-fast starter guidance, not an upstream nf-core submission yet. -// FastaGuard WARN exits 1 and FAIL exits 2; collect-then-gate wrappers can preserve -// evidence in publish directories before applying workflow stop/go logic. +// This is local starter guidance, not an upstream nf-core submission yet. +// FastaGuard returns success when reports are written; collect-then-gate wrappers +// can apply workflow stop/go logic from gate.status. diff --git a/examples/nf-core/README.md b/examples/nf-core/README.md index ac58df2..329a50b 100644 --- a/examples/nf-core/README.md +++ b/examples/nf-core/README.md @@ -26,6 +26,7 @@ Emitted outputs: - `json` - `tsv` - `mqc` +- `exit_code` - `versions` The module assumes `fastaguard` is available on `PATH` when run without a @@ -47,13 +48,12 @@ The command block is written for the v0.3 assembly gate and runs: fastaguard sample.fa --profile assembly --gate pipeline ``` -That gate contract blocks downstream workflow steps on duplicate IDs, invalid -characters, invalid FASTA structure, and high-N content. Gate failures intentionally exit with code `2` after writing reports, so downstream workflow steps stop while the JSON/HTML evidence remains available. - -This is a local fail-fast starter example: FastaGuard WARN exits 1 and FAIL exits 2. -Depending on workflow engine behavior, naive fail-fast runs may leave evidence -only in the work directory. A production wrapper can use a collect-then-gate -pattern to publish JSON/HTML/TSV/MultiQC evidence before applying stop/go logic. +That gate contract marks duplicate IDs, invalid characters, invalid FASTA +structure, and high-N content as blocking findings. The published v0.5.0 +runtime returns `1` for WARN and `2` for FAIL. This module captures that legacy +status so JSON, HTML, TSV, and MultiQC evidence can be published; a downstream +gate step should then enforce stop/go policy from `gate.status` or the captured +exit code. Runtime errors with status `3` still fail the process. For v0.4 cohort triage, compare mode is a starter pattern: @@ -75,9 +75,9 @@ Pipeline authors should route on: - `gate.blocking_findings` - `readiness.categories[id=submission]` -This is local fail-fast starter guidance only. It is not yet an upstream nf-core -module submission, and the Snakemake example is not yet an official wrapper -submission. +This is local collect-then-gate starter guidance only. It is not yet an +upstream nf-core module submission, and the Snakemake example is not yet an +official wrapper submission. Example include: diff --git a/examples/reports/README.md b/examples/reports/README.md index 2344658..8b28554 100644 --- a/examples/reports/README.md +++ b/examples/reports/README.md @@ -1,6 +1,6 @@ # Example Reports -These tiny examples show the current v0.5 output contract without requiring large datasets. +These tiny examples show the current v0.6 output contract without requiring large datasets. ## Assembly Pass @@ -41,4 +41,6 @@ cargo run -- testdata/problem_assembly.fa \ --multiqc examples/reports/assembly_fail/fastaguard_mqc.json ``` -The command exits with code `2` because this example contains critical FASTA-level blockers. Inspect the JSON `gate` object and readiness categories to separate blocking findings from advisory findings. +The command exits with code `0` after writing the FAIL report. Inspect the JSON +`gate` object and readiness categories to separate blocking findings from +advisory findings. diff --git a/examples/reports/assembly_fail/fastaguard.json b/examples/reports/assembly_fail/fastaguard.json index bc738c8..ba08540 100644 --- a/examples/reports/assembly_fail/fastaguard.json +++ b/examples/reports/assembly_fail/fastaguard.json @@ -2,7 +2,7 @@ "schema_version": "0.5.0", "tool": { "name": "FastaGuard", - "version": "0.5.0" + "version": "0.6.0" }, "input": { "path": "testdata/problem_assembly.fa", diff --git a/examples/reports/assembly_fail/fastaguard.tsv b/examples/reports/assembly_fail/fastaguard.tsv index 59d824c..6f9540a 100644 --- a/examples/reports/assembly_fail/fastaguard.tsv +++ b/examples/reports/assembly_fail/fastaguard.tsv @@ -1,5 +1,6 @@ metric value schema_version 0.5.0 +input_path testdata/problem_assembly.fa profile assembly verdict FAIL gate_mode none diff --git a/examples/reports/assembly_fail/fastaguard_report.html b/examples/reports/assembly_fail/fastaguard_report.html index 5e08b79..1e66cf3 100644 --- a/examples/reports/assembly_fail/fastaguard_report.html +++ b/examples/reports/assembly_fail/fastaguard_report.html @@ -579,7 +579,7 @@