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
2 changes: 1 addition & 1 deletion docs/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -1554,7 +1554,7 @@ Recommended layout:
- `cache/ncbi/download_plan.tsv`: `record_id`, `normalized_id`, `assembly_accession`, `expected_genome_path`, `datasets_zip_path`, `download_dir`, `status`, `notes`
- `bounded_download_smoke_plan.tsv`: isolated subset of `cache/ncbi/download_plan.tsv` for a separately authorized bounded NCBI download smoke. Fields are the `cache/ncbi/download_plan.tsv` fields plus `assembly_level`, `refseq_category`, and `quality_tier`; every row has `status=planned`. `download-smoke inspect` also accepts older bounded smoke plans whose field order matches only `cache/ncbi/download_plan.tsv`.
- `bounded_download_smoke_commands.tsv`: complete command handoff manifest written by `download-smoke prepare --write`, with one row per bounded plan row. Fields are `record_id`, `assembly_accession`, `assembly_level`, `refseq_category`, `quality_tier`, `datasets_zip_path`, and `command_json`; `command_json` is a compact JSON array for the bounded `datasets download genome accession ... --include genome --filename ...` command. This file is for operator or AI-controller inspection only; it does not run `datasets`, authorize downloads, contact providers, mutate manifests, or create strict deliverables.
- `bounded_download_smoke_summary.json`: read-only JSON summary for `download-smoke prepare`. Stable fields include `schema_version`, `command`, `source_download_plan_path`, `limit`, `requested_quality_tier`, `resolved_quality_tier`, `quality_tier`, `selected_row_count`, `selected_high_quality_row_count`, `selected_quality_tier_counts`, `selected_assembly_level_counts`, `selected_refseq_category_counts`, `selected_accession_quality_preview`, `selected_accession_quality_preview_truncated`, `selected_datasets_command_preview`, `selected_datasets_command_preview_truncated`, `selected_datasets_command_preview_only`, `inspection_min_fasta_n50_bases`, `inspection_max_fasta_record_count`, `inspection_max_fasta_ambiguous_bases`, `inspection_min_fasta_total_bases`, `inspection_min_fasta_longest_record_bases`, `inspection_quality_profile`, `inspection_block_fragmented_fasta`, `inspection_block_fasta_header_keywords`, `recommended_inspection_request_target`, `recommended_inspection_request`, `recommended_inspection_next_command`, `recommended_inspection_command`, `handoff_checklist`, `source_planned_row_count`, `source_high_quality_planned_row_count`, `source_draft_or_fragmented_planned_row_count`, `source_unknown_assembly_level_planned_row_count`, `source_refseq_category_counts`, `source_total_rows`, `ready`, `blockers`, `execution_boundary`, `safe_for_unattended_download`, `downloads_triggered`, `providers_contacted`, `network_access`, `external_tools`, `manifest_mutated`, and `strict_scientific_deliverable`. `selected_high_quality_row_count`, `selected_quality_tier_counts`, and `selected_refseq_category_counts` count only selected rows; source-level high-quality and RefSeq-category availability are reported separately. `selected_accession_quality_preview` includes selected accessions, normalized assembly levels, normalized RefSeq category labels, and quality tiers. `selected_datasets_command_preview` lists at most five bounded `datasets download genome accession ... --include genome --filename ...` command arrays for operator inspection; it is a preview only and does not run `datasets`. `handoff_checklist` marks bounded datasets execution and final genome acceptance as separate approval/review steps. The `recommended_inspection_*` fields are empty until `prepare --write` has produced an isolated bounded plan, then point to `download-smoke inspect` with that plan path and an operator-chosen isolated inspection output directory. Controllers can pass `recommended_inspection_request` to `commands render`; `recommended_inspection_command` remains a compatibility argv list for operator inspection. The default `inspection_quality_profile=fragmentation` carries `--quality-profile fragmentation` into that recommended handoff, enabling local blockers for fragmented FASTA signals and WGS/scaffold/contig header keywords during the later inspection; `--inspection-quality-profile none` leaves those profile gates disabled unless explicit gate flags are supplied. The `inspection_*` fields only carry optional local inspection quality gates into that recommended handoff; prepare does not inspect ZIPs, run downloads, contact providers, or decide final genome usability. `quality_tier` is the resolved effective tier. `--quality-tier recommended` is the default and resolves the readiness recommendation to `high`, `all`, or `none`; `--quality-tier high` selects only planned Complete Genome or Chromosome rows; Scaffold and Contig remain valid planned rows when `all` is selected explicitly or when `recommended` falls back to `all`.
- `bounded_download_smoke_summary.json`: read-only JSON summary for `download-smoke prepare`. Stable fields include `schema_version`, `command`, `source_download_plan_path`, `limit`, `requested_quality_tier`, `resolved_quality_tier`, `quality_tier`, `selected_row_count`, `selected_high_quality_row_count`, `selected_quality_tier_counts`, `selected_assembly_level_counts`, `selected_refseq_category_counts`, `selected_accession_quality_preview`, `selected_accession_quality_preview_truncated`, `selected_datasets_command_preview`, `selected_datasets_command_preview_truncated`, `selected_datasets_command_preview_only`, `inspection_min_fasta_n50_bases`, `inspection_max_fasta_record_count`, `inspection_max_fasta_ambiguous_bases`, `inspection_min_fasta_total_bases`, `inspection_min_fasta_longest_record_bases`, `inspection_quality_profile`, `inspection_block_fragmented_fasta`, `inspection_block_fasta_header_keywords`, `recommended_inspection_request_target`, `recommended_inspection_request`, `recommended_inspection_next_command`, `recommended_inspection_command`, `handoff_checklist`, `source_planned_row_count`, `source_high_quality_planned_row_count`, `source_draft_or_fragmented_planned_row_count`, `source_unknown_assembly_level_planned_row_count`, `source_refseq_category_counts`, `source_total_rows`, `ready`, `blockers`, `execution_boundary`, `safe_for_unattended_download`, `downloads_triggered`, `providers_contacted`, `network_access`, `external_tools`, `manifest_mutated`, and `strict_scientific_deliverable`. `selected_high_quality_row_count`, `selected_quality_tier_counts`, and `selected_refseq_category_counts` count only selected rows; source-level high-quality and RefSeq-category availability are reported separately. `selected_accession_quality_preview` includes selected accessions, normalized assembly levels, normalized RefSeq category labels, and quality tiers. `selected_datasets_command_preview` lists at most five bounded `datasets download genome accession ... --include genome --filename ...` command arrays for operator inspection; it is a preview only and does not run `datasets`. `handoff_checklist` marks bounded datasets execution and final genome acceptance as separate approval/review steps. The `recommended_inspection_*` fields are empty until `prepare --write` has produced an isolated bounded plan, then point to `download-smoke inspect` with that plan path and the deterministic sibling `inspection/` output directory. Controllers can pass `recommended_inspection_request` to `commands render`; `recommended_inspection_command` remains a compatibility argv list for operator inspection. The default `inspection_quality_profile=fragmentation` carries `--quality-profile fragmentation` into that recommended handoff, enabling local blockers for fragmented FASTA signals and WGS/scaffold/contig header keywords during the later inspection; `--inspection-quality-profile none` leaves those profile gates disabled unless explicit gate flags are supplied. The `inspection_*` fields only carry optional local inspection quality gates into that recommended handoff; prepare does not inspect ZIPs, run downloads, contact providers, or decide final genome usability. `quality_tier` is the resolved effective tier. `--quality-tier recommended` is the default and resolves the readiness recommendation to `high`, `all`, or `none`; `--quality-tier high` selects only planned Complete Genome or Chromosome rows; Scaffold and Contig remain valid planned rows when `all` is selected explicitly or when `recommended` falls back to `all`.
- `bounded_download_smoke_execution.tsv`: bounded execution audit rows for `download-smoke execute`. Fields are `record_id`, `assembly_accession`, `assembly_level`, `refseq_category`, `quality_tier`, `datasets_zip_path`, `command_json`, `command_valid`, `executed`, `returncode`, `status`, and `notes`. A row is executed only when `command_json` exactly matches the bounded datasets command contract and `--execute` is supplied; otherwise the command is validation-only. Execution success means a ZIP is ready for `download-smoke inspect`, not that a genome is final-use accepted.
- `bounded_download_smoke_execution_summary.json`: read-only JSON summary for `download-smoke execute`. Stable fields include `schema_version`, `command`, `source_commands_manifest_path`, `limit`, `selected_row_count`, `command_valid_count`, `command_invalid_count`, `execute_requested`, `executed_command_count`, `datasets_zip_ready_for_inspection_count`, `status_counts`, `ready`, `blockers`, `execution_boundary`, `safe_for_unattended_download`, `recommended_inspection_request_target`, `recommended_inspection_request`, `recommended_inspection_request_blockers`, `recommended_inspection_next_command`, `recommended_inspection_command`, `downloads_triggered`, `providers_contacted`, `network_access`, `external_tools`, `manifest_mutated`, `strict_scientific_deliverable`, and legacy `recommended_next_command`. When execution audit outputs are written and the sibling `bounded_download_smoke_plan.tsv` is present, the structured `recommended_inspection_*` fields point to the matching local `download-smoke inspect` handoff. If the sibling plan is absent, the request fields stay empty and `recommended_inspection_request_blockers` includes `bounded_download_smoke_plan_missing`. Dry-run validation leaves `downloads_triggered=0`, `network_access=false`, and `external_tools=false`. Explicit execution may set those fields when commands run, but it still writes only isolated audit outputs and requires later ZIP/FASTA inspection before any bounded-smoke quality decision.
`--download-smoke-execution-dir <dir>` is an explicit read-only report/package surface for these two files. Report-only mode may show `## Bounded Download Smoke Execution`; `package-results --include reports` and `--include all` may copy validated members under `download_smoke/` with `evidence_policy=download_smoke_execution_audit` and `strict_scientific_deliverable=false`. Missing input is omitted; partial or malformed input copies only valid members and emits a compact warning. Failed-handoff packages exclude the execution files.
Expand Down
30 changes: 18 additions & 12 deletions tests/test_cli_download_smoke.py
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,7 @@ def test_download_smoke_prepare_write_outputs_isolated_pair(capsys, tmp_path):
summary = json.loads(
(outdir / "bounded_download_smoke_summary.json").read_text(encoding="utf-8")
)
inspection_outdir = outdir / "inspection"
assert payload["writes_outputs"] is True
assert payload["output_files"] == {
"bounded_download_smoke_plan": str(
Expand Down Expand Up @@ -309,13 +310,13 @@ def test_download_smoke_prepare_write_outputs_isolated_pair(capsys, tmp_path):
"download_plan": str(outdir / "bounded_download_smoke_plan.tsv"),
"quality_profile": "fragmentation",
"write": True,
"outdir": "<isolated-bounded-download-smoke-inspection-dir>",
"outdir": str(inspection_outdir),
}
assert summary["recommended_inspection_next_command"] == (
"typetreeflow download-smoke inspect --download-plan "
f"{outdir / 'bounded_download_smoke_plan.tsv'} "
"--quality-profile fragmentation --write --outdir "
"<isolated-bounded-download-smoke-inspection-dir>"
f"{inspection_outdir}"
)
assert summary["recommended_inspection_command"] == [
"typetreeflow",
Expand All @@ -327,8 +328,9 @@ def test_download_smoke_prepare_write_outputs_isolated_pair(capsys, tmp_path):
"fragmentation",
"--write",
"--outdir",
"<isolated-bounded-download-smoke-inspection-dir>",
str(inspection_outdir),
]
assert not inspection_outdir.exists()
assert payload["bounded_download_smoke_summary"][
"recommended_inspection_command"
] == summary["recommended_inspection_command"]
Expand Down Expand Up @@ -422,21 +424,22 @@ def test_download_smoke_execute_dry_run_validates_command_manifest(
assert summary["executed_command_count"] == 0
assert summary["status_counts"] == {"execution_planned": 1}
assert summary["ready"] is True
inspection_outdir = commands.parent / "inspection"
assert summary["recommended_inspection_request_target"] == "download-smoke inspect"
assert summary["recommended_inspection_request"] == {
"command": "download-smoke",
"subcommand": "inspect",
"download_plan": str(commands.parent / "bounded_download_smoke_plan.tsv"),
"write": True,
"outdir": "<isolated-bounded-download-smoke-inspection-dir>",
"outdir": str(inspection_outdir),
"quality_profile": "fragmentation",
}
assert summary["recommended_inspection_request_blockers"] == []
assert summary["recommended_inspection_next_command"] == (
"typetreeflow download-smoke inspect --download-plan "
f"{commands.parent / 'bounded_download_smoke_plan.tsv'} "
"--quality-profile fragmentation --write --outdir "
"<isolated-bounded-download-smoke-inspection-dir>"
f"{inspection_outdir}"
)
assert summary["recommended_inspection_command"] == [
"typetreeflow",
Expand All @@ -448,7 +451,7 @@ def test_download_smoke_execute_dry_run_validates_command_manifest(
"fragmentation",
"--write",
"--outdir",
"<isolated-bounded-download-smoke-inspection-dir>",
str(inspection_outdir),
]
assert (
main(
Expand Down Expand Up @@ -705,6 +708,7 @@ def test_download_smoke_prepare_write_carries_inspection_quality_gates(
summary = json.loads(
(outdir / "bounded_download_smoke_summary.json").read_text(encoding="utf-8")
)
inspection_outdir = outdir / "inspection"
assert summary["inspection_min_fasta_n50_bases"] == 50000
assert summary["inspection_max_fasta_record_count"] == 10
assert summary["inspection_max_fasta_ambiguous_bases"] == 100
Expand Down Expand Up @@ -735,7 +739,7 @@ def test_download_smoke_prepare_write_carries_inspection_quality_gates(
"--block-fasta-header-keywords",
"--write",
"--outdir",
"<isolated-bounded-download-smoke-inspection-dir>",
str(inspection_outdir),
]
assert summary["recommended_inspection_request"] == {
"command": "download-smoke",
Expand All @@ -750,7 +754,7 @@ def test_download_smoke_prepare_write_carries_inspection_quality_gates(
"block_fragmented_fasta": True,
"block_fasta_header_keywords": True,
"write": True,
"outdir": "<isolated-bounded-download-smoke-inspection-dir>",
"outdir": str(inspection_outdir),
}
assert payload["bounded_download_smoke_summary"][
"recommended_inspection_command"
Expand Down Expand Up @@ -786,6 +790,7 @@ def test_download_smoke_prepare_write_can_disable_inspection_quality_profile(
summary = json.loads(
(outdir / "bounded_download_smoke_summary.json").read_text(encoding="utf-8")
)
inspection_outdir = outdir / "inspection"
assert summary["inspection_quality_profile"] == "none"
assert summary["inspection_block_fragmented_fasta"] is False
assert summary["inspection_block_fasta_header_keywords"] is False
Expand All @@ -794,7 +799,7 @@ def test_download_smoke_prepare_write_can_disable_inspection_quality_profile(
"subcommand": "inspect",
"download_plan": str(outdir / "bounded_download_smoke_plan.tsv"),
"write": True,
"outdir": "<isolated-bounded-download-smoke-inspection-dir>",
"outdir": str(inspection_outdir),
}
assert "--quality-profile" not in summary["recommended_inspection_command"]
assert payload["bounded_download_smoke_summary"][
Expand Down Expand Up @@ -1405,18 +1410,19 @@ def test_download_smoke_inspect_passes_when_selected_zip_contains_genome(
assert summary["recommended_quality_gate_request_target"] == (
"download-smoke inspect"
)
inspection_outdir = plan.parent / "inspection"
assert summary["recommended_quality_gate_request"] == {
"command": "download-smoke",
"subcommand": "inspect",
"download_plan": str(plan),
"quality_profile": "fragmentation",
"write": True,
"outdir": "<isolated-bounded-download-smoke-inspection-dir>",
"outdir": str(inspection_outdir),
}
assert summary["recommended_quality_gate_next_command"] == (
"typetreeflow download-smoke inspect --download-plan "
f"{plan} --quality-profile fragmentation --write --outdir "
"<isolated-bounded-download-smoke-inspection-dir>"
f"{inspection_outdir}"
)
assert summary["recommended_quality_gate_command"] == [
"typetreeflow",
Expand All @@ -1428,7 +1434,7 @@ def test_download_smoke_inspect_passes_when_selected_zip_contains_genome(
"fragmentation",
"--write",
"--outdir",
"<isolated-bounded-download-smoke-inspection-dir>",
str(inspection_outdir),
]
assert (
main(
Expand Down
11 changes: 7 additions & 4 deletions typetreeflow/download_smoke_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -606,12 +606,13 @@ def _recommended_inspection_request(
block_fragmented_fasta: bool = False,
block_fasta_header_keywords: bool = False,
) -> dict[str, object]:
inspection_outdir = Path(bounded_plan_path).parent / "inspection"
request: dict[str, object] = {
"command": "download-smoke",
"subcommand": "inspect",
"download_plan": str(bounded_plan_path),
"write": True,
"outdir": "<isolated-bounded-download-smoke-inspection-dir>",
"outdir": str(inspection_outdir),
}
if min_fasta_n50_bases > 0:
request["min_fasta_n50_bases"] = min_fasta_n50_bases
Expand Down Expand Up @@ -721,7 +722,7 @@ def _recommended_inspection_command(
[
"--write",
"--outdir",
"<isolated-bounded-download-smoke-inspection-dir>",
str(Path(bounded_plan_path).parent / "inspection"),
]
)
return command
Expand Down Expand Up @@ -1260,6 +1261,8 @@ def execute_bounded_download_smoke_commands(
succeeded_count = sum(
1 for row in results if row["status"] == "datasets_zip_ready_for_inspection"
)
bounded_plan_path = manifest_path.parent / OUTPUT_PLAN_NAME
inspection_outdir = manifest_path.parent / "inspection"
summary = {
"schema_version": EXECUTION_SCHEMA_VERSION,
"command": EXECUTE_COMMAND,
Expand Down Expand Up @@ -1291,12 +1294,12 @@ def execute_bounded_download_smoke_commands(
"download-smoke",
"inspect",
"--download-plan",
"<bounded_download_smoke_plan.tsv>",
str(bounded_plan_path),
"--quality-profile",
"fragmentation",
"--write",
"--outdir",
"<isolated-bounded-download-smoke-inspection-dir>",
str(inspection_outdir),
],
"summary": (
"Bounded datasets command manifest is valid."
Expand Down
Loading