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
18 changes: 13 additions & 5 deletions docs/guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -1351,6 +1351,13 @@ five corresponding command arrays for operator inspection. It does not run
authorize broad downloads. The summary `handoff_checklist` keeps bounded
`datasets` execution and final genome acceptance as separate approval/review
steps.
When `prepare --write` succeeds, stdout also includes
`recommended_execution_validation_request_target`,
`recommended_execution_validation_request`, and
`recommended_execution_validation_next_command` for the matching
validation-only `download-smoke execute` handoff. That recommended command does
not include `--execute`; it only validates the pinned command manifest and
writes an isolated execution audit.

Before running any bounded datasets command, validate the command manifest and
write an isolated execution audit:
Expand Down Expand Up @@ -1412,11 +1419,12 @@ When `prepare --write` succeeds, `recommended_inspection_request_target`,
point to the matching local `download-smoke inspect` handoff for the written
bounded plan; controllers can pass the request to `commands render` instead of
parsing command text. The compatibility `recommended_inspection_command` argv
list remains available for operator inspection; choose a fresh isolated
inspection `--outdir` before running it. By default, that handoff includes
`--quality-profile fragmentation`, which blocks visibly fragmented multi-record
FASTA signals and WGS/scaffold/contig FASTA header keywords during the later
local inspection. Use
list remains available for operator inspection. The default handoff writes to
the deterministic sibling `inspection/` directory; copy the command and change
`--outdir` only when a different isolated inspection directory is needed. By
default, that handoff includes `--quality-profile fragmentation`, which blocks
visibly fragmented multi-record FASTA signals and WGS/scaffold/contig FASTA
header keywords during the later local inspection. Use
`--inspection-quality-profile none` when the follow-up inspection should remain
descriptive-only unless explicit gate flags are provided. Optional prepare
flags such as `--inspection-min-fasta-n50-bases <bases>`,
Expand Down
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 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_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`, `recommended_execution_validation_request_target`, `recommended_execution_validation_request`, `recommended_execution_validation_next_command`, `recommended_execution_validation_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_execution_validation_*` fields are empty until `prepare --write` has produced an isolated command manifest, then point to validation-only `download-smoke execute` without `--execute`; that handoff validates the pinned command manifest and does not download. 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` or `recommended_execution_validation_request` to `commands render`; the `recommended_*_command` fields remain compatibility argv lists 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
46 changes: 46 additions & 0 deletions tests/test_cli_download_smoke.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ def test_download_smoke_prepare_write_outputs_isolated_pair(capsys, tmp_path):
(outdir / "bounded_download_smoke_summary.json").read_text(encoding="utf-8")
)
inspection_outdir = outdir / "inspection"
execution_outdir = outdir / "execution"
assert payload["writes_outputs"] is True
assert payload["output_files"] == {
"bounded_download_smoke_plan": str(
Expand Down Expand Up @@ -337,6 +338,36 @@ def test_download_smoke_prepare_write_outputs_isolated_pair(capsys, tmp_path):
assert payload["bounded_download_smoke_summary"][
"recommended_inspection_request"
] == summary["recommended_inspection_request"]
assert summary["recommended_execution_validation_request_target"] == (
"download-smoke execute"
)
assert summary["recommended_execution_validation_request"] == {
"command": "download-smoke",
"subcommand": "execute",
"commands_manifest": str(outdir / "bounded_download_smoke_commands.tsv"),
"limit": 1,
"write": True,
"outdir": str(execution_outdir),
}
assert summary["recommended_execution_validation_next_command"] == (
"typetreeflow download-smoke execute --commands-manifest "
f"{outdir / 'bounded_download_smoke_commands.tsv'} "
f"--limit 1 --write --outdir {execution_outdir}"
)
assert summary["recommended_execution_validation_command"] == [
"typetreeflow",
"download-smoke",
"execute",
"--commands-manifest",
str(outdir / "bounded_download_smoke_commands.tsv"),
"--limit",
"1",
"--write",
"--outdir",
str(execution_outdir),
]
assert "--execute" not in summary["recommended_execution_validation_command"]
assert not execution_outdir.exists()
assert (
main(
[
Expand All @@ -350,6 +381,21 @@ def test_download_smoke_prepare_write_outputs_isolated_pair(capsys, tmp_path):
)
rendered = json.loads(capsys.readouterr().out)
assert rendered["target_argv"] == summary["recommended_inspection_command"][1:]
assert (
main(
[
"commands",
"render",
"--request-json",
json.dumps(summary["recommended_execution_validation_request"]),
]
)
== 0
)
rendered = json.loads(capsys.readouterr().out)
assert rendered["target_argv"] == (
summary["recommended_execution_validation_command"][1:]
)
checklist = {item["id"]: item for item in summary["handoff_checklist"]}
assert checklist["prepare_bounded_download_smoke_input"]["status"] == "written"
assert checklist["run_bounded_datasets_download"]["requires_explicit_approval"]
Expand Down
42 changes: 42 additions & 0 deletions typetreeflow/download_smoke_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,10 @@ def run_download_smoke_command(
return 2

if args.action == "prepare" and args.write:
execution_validation_request = _recommended_execution_validation_request(
Path(args.outdir) / OUTPUT_COMMANDS_NAME,
limit=int(result["summary"].get("selected_row_count", args.limit)), # type: ignore[union-attr]
)
inspection_request = _recommended_inspection_request(
Path(args.outdir) / OUTPUT_PLAN_NAME,
min_fasta_n50_bases=args.inspection_min_fasta_n50_bases,
Expand Down Expand Up @@ -261,6 +265,18 @@ def run_download_smoke_command(
result["summary"]["recommended_inspection_command"] = ( # type: ignore[index]
_recommended_inspection_command_from_request(inspection_request)
)
result["summary"]["recommended_execution_validation_request_target"] = ( # type: ignore[index]
EXECUTE_COMMAND
)
result["summary"]["recommended_execution_validation_request"] = ( # type: ignore[index]
execution_validation_request
)
result["summary"]["recommended_execution_validation_next_command"] = ( # type: ignore[index]
_recommended_next_command(execution_validation_request)
)
result["summary"]["recommended_execution_validation_command"] = ( # type: ignore[index]
_recommended_command_from_request(execution_validation_request)
)
if args.action == "inspect":
summary = result["summary"] # type: ignore[index]
if args.write and int(summary.get("selected_row_count", 0)) > 0:
Expand Down Expand Up @@ -520,6 +536,10 @@ def prepare_bounded_download_smoke_input(
"recommended_inspection_request": {},
"recommended_inspection_next_command": "",
"recommended_inspection_command": [],
"recommended_execution_validation_request_target": "",
"recommended_execution_validation_request": {},
"recommended_execution_validation_next_command": "",
"recommended_execution_validation_command": [],
"handoff_checklist": _prepare_handoff_checklist(
writes_outputs=False,
ready=not blockers,
Expand Down Expand Up @@ -633,6 +653,22 @@ def _recommended_inspection_request(
return request


def _recommended_execution_validation_request(
commands_manifest_path: str | Path,
*,
limit: int,
) -> dict[str, object]:
commands_path = Path(commands_manifest_path)
return {
"command": "download-smoke",
"subcommand": "execute",
"commands_manifest": str(commands_path),
"limit": limit,
"write": True,
"outdir": str(commands_path.parent / "execution"),
}


def _recommended_next_command(request: dict[str, object]) -> str:
if not request:
return ""
Expand All @@ -648,6 +684,12 @@ def _recommended_next_command(request: dict[str, object]) -> str:

def _recommended_inspection_command_from_request(
request: dict[str, object],
) -> list[str]:
return _recommended_command_from_request(request)


def _recommended_command_from_request(
request: dict[str, object],
) -> list[str]:
if not request:
return []
Expand Down
Loading