← Files NGS Analysis WorkbenchARCHIVED FILE

tests/test_readiness.py

33.7 KB · Sep 30, 2026 · 23:20 UTC

↓ Download file

from __future__ import annotations

import json
import sys
import tempfile
import unittest
from datetime import UTC, datetime, timedelta
from pathlib import Path
from unittest import mock

PLUGIN_ROOT = Path(__file__).resolve().parents[1]
MCP_ROOT = PLUGIN_ROOT / "mcp"
if str(MCP_ROOT) not in sys.path:
    sys.path.insert(0, str(MCP_ROOT))

from daemon_test_case import DaemonTestCase  # noqa: E402
from ngs_workbench_daemon import remote_probe  # noqa: E402
from ngs_workbench_mcp import readiness_service  # noqa: E402
from ngs_workbench_mcp.compute_targets import ComputeTargetRef  # noqa: E402
from ngs_workbench_mcp.readiness import evaluate  # noqa: E402
from ngs_workbench_mcp.readiness.models import (  # noqa: E402
    RequirementSet,
    RuntimeRequirement,
)
from ngs_workbench_mcp.runtime import local as local_runtime  # noqa: E402
from ngs_workbench_mcp.runtime.models import (  # noqa: E402
    ControllerRuntimeCandidate,
    DockerRuntime,
    ManagedEnvironmentRuntime,
    RuntimeCommand,
    RuntimeCommandProbe,
    RuntimeEnvironmentSnapshot,
    RuntimePlatform,
)
from ngs_workbench_mcp.workflows import nextflow as nfcore  # noqa: E402
from ngs_workbench_mcp.workflows import snakemake  # noqa: E402


def _snapshot(
    workspace: Path,
    *commands: RuntimeCommand,
    controller_candidates: list[ControllerRuntimeCandidate] | None = None,
) -> RuntimeEnvironmentSnapshot:
    observed_at = datetime(2026, 8, 6, tzinfo=UTC)
    return RuntimeEnvironmentSnapshot(
        snapshot_id="runtime-0123456789abcdef0123456789abcdef",
        target=ComputeTargetRef(
            target_id="local",
            provider="ngs-analysis-workbench",
        ),
        observed_at=observed_at,
        expires_at=observed_at + timedelta(minutes=5),
        host=RuntimePlatform(os="darwin", arch="arm64"),
        commands=list(commands),
        docker=DockerRuntime(path=None, daemon_reachable=False),
        controller_candidates=controller_candidates or [],
    )


def _controller_requirement(controller: str = "snakemake") -> RequirementSet:
    return RequirementSet(
        binding="snakemake",
        pipeline="fastq_qc",
        requirements=[
            RuntimeRequirement(
                id=controller,
                layer="workflow_controller",
                capability="command",
                value=controller,
                source="request.binding",
            )
        ],
    )


class RemoteRuntimeTests(DaemonTestCase):
    def test_remote_managed_controller_is_available_without_host_path_activation(self) -> None:
        target = self._configure_ssh_target()
        environment = "/home/lab/.local/share/micromamba/envs/fastq-qc"
        observed = {
            "target_id": "lab",
            "config_hash": target["config_hash"],
            "host": {"hostname": "lab-node", "os": "linux", "arch": "x86_64"},
            "workspace": {
                "path": "/shared/ngs",
                "exists": True,
                "readable": True,
                "writable": True,
            },
            "commands": [
                {"executable": "snakemake", "path": None, "state": "missing"},
                {"executable": "fastqc", "path": None, "state": "missing"},
                {"executable": "multiqc", "path": None, "state": "missing"},
            ],
            "managed_environments": {
                "environments_scanned": 1,
                "environments": [
                    {
                        "name": "fastq-qc",
                        "path": environment,
                        "active": False,
                        "discovered_by": ["micromamba"],
                        "managers": [{"name": "micromamba", "path": "/usr/bin/micromamba"}],
                        "commands": [
                            {
                                "name": name,
                                "path": f"{environment}/bin/{name}",
                                "state": "ready",
                            }
                            for name in ("snakemake", "fastqc", "multiqc")
                        ],
                    }
                ],
            },
            "docker": {"path": None, "daemon_reachable": False},
            "scheduler": None,
        }
        original_request = local_runtime.daemon_client.request

        def inspect_request(path: str, payload: dict, **options: object) -> dict:
            if path == "/targets/inspect":
                return observed
            return original_request(path, payload, **options)

        with mock.patch.object(local_runtime.daemon_client, "request", side_effect=inspect_request):
            snapshot = local_runtime.inspect_runtime_environment(target_id="lab")

        candidate = snapshot.controller_candidates[0]
        self.assertEqual(candidate.controller, "snakemake")
        self.assertEqual(candidate.source, "managed_environment")
        self.assertEqual(candidate.executable_path, f"{environment}/bin/snakemake")
        self.assertTrue(candidate.recommended)
        self.assertEqual(
            candidate.launch_argv_prefix,
            ["/usr/bin/micromamba", "run", "--prefix", environment, "snakemake"],
        )
        requirements = _controller_requirement()
        requirements.requirements.extend(
            RuntimeRequirement(
                id=name,
                layer="task_software",
                capability="command",
                value=name,
                source="workflow.runtime",
            )
            for name in ("fastqc", "multiqc")
        )
        readiness = evaluate(requirements, snapshot)
        self.assertEqual(readiness.status, "ready")
        software = {command.name: command for command in readiness.commands}
        self.assertEqual(software["fastqc"].path, f"{environment}/bin/fastqc")
        self.assertEqual(software["multiqc"].path, f"{environment}/bin/multiqc")

        isolated = snapshot.model_copy(deep=True)
        isolated.commands = [
            command.model_copy(update={"path": "/usr/bin/fastqc", "state": "ready"})
            if command.name == "fastqc"
            else command
            for command in isolated.commands
        ]
        isolated.managed_environments.environments[0].commands = [
            command
            for command in isolated.managed_environments.environments[0].commands
            if command.name != "fastqc"
        ]
        unavailable = evaluate(requirements, isolated)

        self.assertEqual(unavailable.status, "blocked")
        self.assertIsNone(
            next(command for command in unavailable.commands if command.name == "fastqc").path
        )

    def test_remote_managed_environment_inspection_returns_before_its_deadline(self) -> None:
        managers = [
            {"executable": name, "path": f"/usr/bin/{name}", "state": "ready"}
            for name in ("conda", "mamba", "micromamba")
        ]
        with (
            mock.patch.object(remote_probe.time, "monotonic", side_effect=[98.0, 100.0]),
            mock.patch.object(
                remote_probe.subprocess,
                "run",
                return_value=mock.Mock(returncode=0, stdout='{"envs": []}'),
            ) as inspect,
        ):
            observed = remote_probe._managed_environments(managers, [], deadline=100.0)

        inspect.assert_called_once()
        self.assertTrue(observed["warnings"])
        snapshot = _snapshot(
            self.workspace,
            RuntimeCommand(name="snakemake", path=None, state="missing"),
        ).model_copy(update={"managed_environments": ManagedEnvironmentRuntime(**observed)})
        self.assertEqual(evaluate(_controller_requirement(), snapshot).status, "unknown")

    def test_workbench_uses_remote_host_facts_without_resolving_remote_paths_locally(self) -> None:
        target = self._configure_ssh_target()
        observed = {
            "target_id": "lab",
            "config_hash": target["config_hash"],
            "host": {"hostname": "lab-node", "os": "linux", "arch": "aarch64"},
            "workspace": {
                "path": "/shared/ngs",
                "exists": False,
                "readable": False,
                "writable": False,
            },
            "commands": [
                {
                    "executable": "snakemake",
                    "path": "/home/lab/bin/snakemake",
                    "state": "ready",
                    "version": "8.0.0",
                },
                {"executable": "sbatch", "path": None, "state": "missing"},
            ],
            "docker": {
                "path": None,
                "daemon_reachable": False,
                "message": "Docker CLI is missing",
            },
            "scheduler": {
                "kind": "slurm",
                "control_plane": "missing",
                "worker_readiness": "unknown",
                "shared_filesystem": "unknown",
            },
        }
        original_request = local_runtime.daemon_client.request

        def inspect_request(path: str, payload: dict, **options: object) -> dict:
            if path == "/targets/inspect":
                return observed
            return original_request(path, payload, **options)

        with (
            mock.patch.object(local_runtime.daemon_client, "request", side_effect=inspect_request),
            mock.patch.object(local_runtime, "_new_snapshot") as inspect_local,
        ):
            snapshot = local_runtime.inspect_runtime_environment(target_id="lab")
        inspect_local.assert_not_called()
        self.assertEqual((snapshot.host.os, snapshot.host.arch), ("linux", "arm64"))
        self.assertEqual(snapshot.target.target_id, "lab")
        self.assertEqual(
            snapshot.controller_candidates[0].executable_path, "/home/lab/bin/snakemake"
        )
        self.assertIn("Slurm worker", " ".join(snapshot.warnings))
        reused = local_runtime.resolve_runtime_environment(snapshot.snapshot_id, target_id="lab")
        self.assertEqual(reused.snapshot_id, snapshot.snapshot_id)

        observed["commands"].append(
            {"executable": "squeue", "path": "/usr/bin/squeue", "state": "ready"}
        )
        observed["scheduler"]["control_plane"] = "unavailable"
        with mock.patch.object(local_runtime.daemon_client, "request", side_effect=inspect_request):
            unavailable = local_runtime.resolve_runtime_environment(
                target_id="lab",
                command_probes=[
                    RuntimeCommandProbe(name="slurm-queue", executable="squeue", mode="version")
                ],
            )
        queue = next(command for command in unavailable.commands if command.name == "slurm-queue")
        self.assertEqual(queue.state, "broken")

        changed = self._configure_ssh_target(partition="gpu")
        observed["config_hash"] = changed["config_hash"]
        observed["host"]["arch"] = "x86_64"
        with mock.patch.object(local_runtime.daemon_client, "request", side_effect=inspect_request):
            updated = local_runtime.resolve_runtime_environment(
                snapshot.snapshot_id,
                target_id="lab",
            )
        self.assertEqual(updated.host.arch, "amd64")
        self.assertNotEqual(updated.snapshot_id, snapshot.snapshot_id)


class NfcoreRequirementTests(unittest.TestCase):
    def test_standard_docker_profile_resolves_binding_requirements_without_probing(self) -> None:
        result = nfcore.resolve_runtime_requirements(
            "rnaseq",
            "test,docker",
            workflow="nf-core/rnaseq",
            revision="3.26.0",
        )

        self.assertEqual(result.blockers, [])
        self.assertEqual(result.unknowns, [])
        self.assertEqual(
            [(item.id, item.layer, item.source) for item in result.requirements],
            [
                ("nextflow", "workflow_controller", "request.binding"),
                ("docker-command", "task_environment", "request.profile"),
                ("docker-daemon", "task_environment", "request.profile"),
            ],
        )

    def test_custom_profile_preserves_unresolved_task_environment(self) -> None:
        result = nfcore.resolve_runtime_requirements("rnaseq", "mylab")

        self.assertEqual(result.blockers, [])
        self.assertIn("task software environment is unresolved", result.unknowns[0])


class SnakemakeRequirementTests(unittest.TestCase):
    def test_snakemake_workflow_requires_the_snakemake_controller(self) -> None:
        config = PLUGIN_ROOT / "workflows" / "fastq_qc" / "config" / "config.json"

        result = snakemake.resolve_runtime_requirements("example", config)

        self.assertEqual(result.blockers, [])
        self.assertEqual(result.unknowns, [])
        self.assertEqual([item.id for item in result.requirements], ["snakemake"])


class RuntimeEnvironmentDiscoveryTests(unittest.TestCase):
    def test_discovers_controllers_in_inactive_conda_env_without_executing_them(self) -> None:
        with tempfile.TemporaryDirectory() as temporary:
            root = Path(temporary)
            conda_environment = root / "envs" / "workflow"
            bin_dir = conda_environment / "bin"
            metadata_dir = conda_environment / "conda-meta"
            bin_dir.mkdir(parents=True)
            metadata_dir.mkdir()

            execution_marker = root / "snakemake-was-executed"
            snakemake_executable = bin_dir / "snakemake"
            snakemake_executable.write_text(
                f"#!/bin/sh\nprintf ran > {execution_marker}\n",
                encoding="utf-8",
            )
            snakemake_executable.chmod(0o755)
            nextflow_marker = root / "nextflow-was-executed"
            nextflow_executable = bin_dir / "nextflow"
            nextflow_executable.write_text(
                f"#!/bin/sh\nprintf ran > {nextflow_marker}\n",
                encoding="utf-8",
            )
            nextflow_executable.chmod(0o755)
            (metadata_dir / "snakemake-minimal-9.24.0-0.json").write_text(
                json.dumps(
                    {
                        "name": "snakemake-minimal",
                        "version": "9.24.0",
                        "build": "pyhdfd78af_0",
                        "channel": "bioconda",
                        "subdir": "noarch",
                    }
                ),
                encoding="utf-8",
            )
            (metadata_dir / "nextflow-26.04.6-0.json").write_text(
                json.dumps(
                    {
                        "name": "nextflow",
                        "version": "26.04.6",
                        "build": "h2a3209d_0",
                        "channel": "bioconda",
                        "subdir": "noarch",
                    }
                ),
                encoding="utf-8",
            )
            (metadata_dir / "python-3.13.5-0.json").write_text(
                json.dumps(
                    {
                        "name": "python",
                        "version": "3.13.5",
                        "build": "h81fe080_0_cpython",
                        "channel": "conda-forge",
                        "subdir": "osx-arm64",
                    }
                ),
                encoding="utf-8",
            )

            manager = root / "conda"
            manager.write_text(
                f"#!{sys.executable}\n"
                "import json\n"
                f"print(json.dumps({{'envs': [{str(conda_environment)!r}]}}))\n",
                encoding="utf-8",
            )
            manager.chmod(0o755)
            commands = [RuntimeCommand(name="conda", path=str(manager), state="ready")]

            with mock.patch.dict(
                local_runtime.os.environ,
                {"CONDA_PREFIX": "", "CONDA_DEFAULT_ENV": ""},
            ):
                result = local_runtime._discover_managed_environment_runtime(
                    commands,
                    RuntimePlatform(os="darwin", arch="arm64"),
                )
            self.assertFalse(execution_marker.exists())
            self.assertFalse(nextflow_marker.exists())

        self.assertEqual(result.environments_scanned, 1)
        self.assertFalse(result.truncated)
        self.assertEqual(len(result.environments), 1)
        environment = result.environments[0]
        self.assertFalse(environment.active)
        self.assertEqual(environment.discovered_by, ["conda"])
        self.assertEqual(environment.platform, RuntimePlatform(os="darwin", arch="arm64"))
        self.assertEqual(environment.platform_subdirs, ["noarch", "osx-arm64"])
        self.assertEqual(
            [(package.name, package.subdir) for package in environment.packages],
            [
                ("nextflow", "noarch"),
                ("python", "osx-arm64"),
                ("snakemake-minimal", "noarch"),
            ],
        )
        self.assertTrue(environment.platform_matches_host)
        snakemake = next(command for command in environment.commands if command.name == "snakemake")
        self.assertEqual(snakemake.state, "ready")
        self.assertEqual(snakemake.path, str(snakemake_executable.resolve()))
        self.assertEqual(snakemake.version, "9.24.0")
        nextflow = next(command for command in environment.commands if command.name == "nextflow")
        self.assertEqual(nextflow.state, "ready")
        self.assertEqual(nextflow.path, str(nextflow_executable.resolve()))
        self.assertEqual(nextflow.version, "26.04.6")

        candidates = local_runtime._controller_candidates(
            commands,
            result,
            RuntimePlatform(os="darwin", arch="arm64"),
        )
        snakemake_candidate = next(
            candidate for candidate in candidates if candidate.controller == "snakemake"
        )
        self.assertTrue(snakemake_candidate.recommended)
        self.assertEqual(snakemake_candidate.source, "managed_environment")
        self.assertEqual(snakemake_candidate.manager, "conda")
        self.assertEqual(
            snakemake_candidate.launch_argv_prefix,
            [
                str(manager),
                "run",
                "--prefix",
                str(conda_environment.resolve()),
                "snakemake",
            ],
        )

    def test_discovers_locked_pixi_project_and_binds_non_mutating_launch(self) -> None:
        with tempfile.TemporaryDirectory() as temporary:
            root = Path(temporary)
            workspace = root / "workspace"
            environment_path = workspace / ".pixi" / "envs" / "default"
            bin_dir = environment_path / "bin"
            metadata_dir = environment_path / "conda-meta"
            bin_dir.mkdir(parents=True)
            metadata_dir.mkdir()
            (workspace / "pixi.toml").write_text(
                "[workspace]\nchannels = ['conda-forge', 'bioconda']\n"
                "platforms = ['osx-arm64']\n\n"
                "[dependencies]\nsnakemake-minimal = '==9.24.0'\n",
                encoding="utf-8",
            )
            (workspace / "pixi.lock").write_text("version: 6\n", encoding="utf-8")
            execution_marker = root / "snakemake-was-executed"
            snakemake_executable = bin_dir / "snakemake"
            snakemake_executable.write_text(
                f"#!/bin/sh\nprintf ran > {execution_marker}\n",
                encoding="utf-8",
            )
            snakemake_executable.chmod(0o755)
            (metadata_dir / "snakemake-minimal-9.24.0-0.json").write_text(
                json.dumps(
                    {
                        "name": "snakemake-minimal",
                        "version": "9.24.0",
                        "channel": "bioconda",
                        "subdir": "noarch",
                    }
                ),
                encoding="utf-8",
            )
            (metadata_dir / "python-3.13.5-0.json").write_text(
                json.dumps(
                    {
                        "name": "python",
                        "version": "3.13.5",
                        "channel": "conda-forge",
                        "subdir": "osx-arm64",
                    }
                ),
                encoding="utf-8",
            )
            pixi = root / "pixi"
            pixi.write_text("#!/bin/sh\nexit 99\n", encoding="utf-8")
            pixi.chmod(0o755)
            commands = [RuntimeCommand(name="pixi", path=str(pixi), state="ready")]
            host = RuntimePlatform(os="darwin", arch="arm64")

            with mock.patch.dict(
                local_runtime.os.environ,
                {
                    "PIXI_HOME": str(root / "pixi-home"),
                    "CONDA_PREFIX": "",
                    "CONDA_DEFAULT_ENV": "",
                },
            ):
                environments = local_runtime._discover_managed_environment_runtime(
                    commands,
                    host,
                    workspace,
                )
                candidates = local_runtime._controller_candidates(
                    commands,
                    environments,
                    host,
                )

            self.assertFalse(execution_marker.exists())

        self.assertEqual(len(environments.environments), 1)
        environment = environments.environments[0]
        self.assertEqual(environment.discovered_by, ["pixi"])
        self.assertEqual(environment.lockfile_path, str((workspace / "pixi.lock").resolve()))
        self.assertEqual(environment.declared_channels, ["conda-forge", "bioconda"])
        candidate = next(item for item in candidates if item.controller == "snakemake")
        self.assertTrue(candidate.recommended)
        self.assertEqual(candidate.manager, "pixi")
        self.assertEqual(candidate.lockfile_path, environment.lockfile_path)
        self.assertEqual(
            candidate.launch_argv_prefix,
            [
                str(pixi),
                "run",
                "--as-is",
                "--manifest-path",
                str((workspace / "pixi.toml").resolve()),
                "--environment",
                "default",
                "--executable",
                "snakemake",
            ],
        )

    def test_marks_foreign_conda_platform_without_executing_controller(self) -> None:
        with tempfile.TemporaryDirectory() as temporary:
            environment_path = Path(temporary)
            (environment_path / "bin").mkdir()
            metadata_dir = environment_path / "conda-meta"
            metadata_dir.mkdir()
            execution_marker = environment_path / "controller-was-executed"
            controller = environment_path / "bin" / "nextflow"
            controller.write_text(
                f"#!/bin/sh\nprintf ran > {execution_marker}\n",
                encoding="utf-8",
            )
            controller.chmod(0o755)
            (metadata_dir / "nextflow-26.04.6-0.json").write_text(
                json.dumps({"name": "nextflow", "version": "26.04.6", "subdir": "noarch"}),
                encoding="utf-8",
            )
            (metadata_dir / "openjdk-21.0.7-0.json").write_text(
                json.dumps({"name": "openjdk", "version": "21.0.7", "subdir": "linux-64"}),
                encoding="utf-8",
            )

            environment, warnings = local_runtime._managed_environment(
                environment_path,
                active=False,
                discovered_by={"conda"},
                host=RuntimePlatform(os="darwin", arch="arm64"),
            )
            self.assertFalse(execution_marker.exists())

        self.assertEqual(warnings, [])
        self.assertEqual(environment.platform, RuntimePlatform(os="linux", arch="amd64"))
        self.assertFalse(environment.platform_matches_host)
        self.assertEqual(
            [(package.name, package.subdir) for package in environment.packages],
            [("nextflow", "noarch"), ("openjdk", "linux-64")],
        )

    def test_keeps_noarch_only_conda_platform_unknown(self) -> None:
        platform_result, warning = local_runtime._conda_platform(["noarch"])

        self.assertIsNone(platform_result)
        self.assertIsNone(warning)


class ReadinessEvaluationTests(unittest.TestCase):
    def test_truncated_environment_discovery_keeps_controller_availability_unknown(self) -> None:
        requirements = _controller_requirement()
        requirements.requirements.append(
            RuntimeRequirement(
                id="fastqc",
                layer="task_software",
                capability="command",
                value="fastqc",
                source="workflow contract",
            )
        )
        snapshot = _snapshot(
            Path("/workspace"),
            RuntimeCommand(name="snakemake", path=None, state="missing"),
            RuntimeCommand(name="fastqc", path=None, state="missing"),
        ).model_copy(update={"managed_environments": ManagedEnvironmentRuntime(truncated=True)})

        result = evaluate(requirements, snapshot)

        self.assertEqual(result.status, "unknown")
        self.assertEqual(result.blockers, [])
        self.assertIsNone(result.selected_controller)

    def test_managed_controller_is_selected_instead_of_host_path(self) -> None:
        workspace = Path("/workspace")
        managed = ControllerRuntimeCandidate(
            candidate_id=f"controller-{'1' * 32}",
            controller="snakemake",
            source="managed_environment",
            manager="mamba",
            executable_path="/env/bin/snakemake",
            environment_path="/env",
            platform=RuntimePlatform(os="darwin", arch="arm64"),
            platform_matches_host=True,
            launch_argv_prefix=[
                "/opt/mamba",
                "run",
                "--prefix",
                "/env",
                "snakemake",
            ],
            recommended=True,
            recommendation_reason="managed environment",
        )
        host_path = ControllerRuntimeCandidate(
            candidate_id=f"controller-{'2' * 32}",
            controller="snakemake",
            source="host_path",
            executable_path="/usr/local/bin/snakemake",
            platform=RuntimePlatform(os="darwin", arch="arm64"),
            platform_matches_host=True,
            active=True,
            launch_argv_prefix=["/usr/local/bin/snakemake"],
            recommended=False,
            recommendation_reason="explicit fallback only",
        )

        result = evaluate(
            _controller_requirement(),
            _snapshot(
                workspace,
                RuntimeCommand(
                    name="snakemake",
                    path="/usr/local/bin/snakemake",
                    state="ready",
                ),
                controller_candidates=[host_path, managed],
            ),
        )

        self.assertEqual(result.status, "ready")
        self.assertEqual(result.selected_controller, managed)
        self.assertTrue(any("no observed lockfile" in warning for warning in result.warnings))

    def test_host_path_requires_explicit_candidate_selection(self) -> None:
        workspace = Path("/workspace")
        host_path = ControllerRuntimeCandidate(
            candidate_id=f"controller-{'3' * 32}",
            controller="snakemake",
            source="host_path",
            executable_path="/usr/local/bin/snakemake",
            platform=RuntimePlatform(os="darwin", arch="arm64"),
            platform_matches_host=True,
            active=True,
            launch_argv_prefix=["/usr/local/bin/snakemake"],
            recommended=False,
            recommendation_reason="explicit fallback only",
        )
        snapshot = _snapshot(
            workspace,
            RuntimeCommand(
                name="snakemake",
                path="/usr/local/bin/snakemake",
                state="ready",
            ),
            controller_candidates=[host_path],
        )

        unresolved = evaluate(_controller_requirement(), snapshot)
        selected = evaluate(
            _controller_requirement(),
            snapshot,
            controller_candidate_id=host_path.candidate_id,
        )

        self.assertEqual(unresolved.status, "unknown")
        self.assertIn("obtain user confirmation", unresolved.unknowns[0])
        self.assertEqual(selected.status, "ready")
        self.assertEqual(selected.selected_controller, host_path)
        self.assertTrue(any("not reproducibly bound" in warning for warning in selected.warnings))

    def test_multiple_managed_environments_require_an_exact_choice(self) -> None:
        workspace = Path("/workspace")
        candidates = [
            ControllerRuntimeCandidate(
                candidate_id=f"controller-{digit * 32}",
                controller="snakemake",
                source="managed_environment",
                manager=manager,
                executable_path=f"/{manager}/bin/snakemake",
                environment_path=f"/{manager}",
                platform=RuntimePlatform(os="darwin", arch="arm64"),
                platform_matches_host=True,
                launch_argv_prefix=[f"/opt/{manager}", "run", "snakemake"],
                recommended=True,
                recommendation_reason="managed environment",
            )
            for digit, manager in (("4", "conda"), ("5", "pixi"))
        ]

        result = evaluate(
            _controller_requirement(),
            _snapshot(workspace, controller_candidates=candidates),
        )

        self.assertEqual(result.status, "unknown")
        self.assertIn("multiple recommended", result.unknowns[0])
        self.assertTrue(
            all(candidate.candidate_id in result.unknowns[0] for candidate in candidates)
        )

    def test_presence_probe_does_not_execute_request_sourced_lookalike_binary(self) -> None:
        with tempfile.TemporaryDirectory() as temporary:
            executable = Path(temporary) / "docker"
            executable.write_text("not executed", encoding="utf-8")
            executable.chmod(0o755)
            probe = RuntimeCommandProbe(
                name="fastqc",
                executable=str(executable),
                mode="presence",
            )
            with mock.patch.object(local_runtime.subprocess, "run") as run:
                result = local_runtime._probe_command(probe)

        self.assertEqual(result.state, "ready")
        self.assertEqual(result.path, str(executable))
        run.assert_not_called()

    def test_known_missing_executable_is_blocked(self) -> None:
        workspace = Path("/workspace")
        requirements = RequirementSet(
            binding="snakemake",
            pipeline="fastq_qc",
            requirements=[
                RuntimeRequirement(
                    id="fastqc",
                    layer="task_software",
                    capability="command",
                    value="fastqc",
                    source="workflow contract",
                )
            ],
        )
        result = evaluate(
            requirements,
            _snapshot(workspace, RuntimeCommand(name="fastqc", path=None, state="missing")),
        )

        self.assertEqual(result.status, "blocked")
        self.assertEqual(result.unknowns, [])
        self.assertEqual(result.blockers, ["required executable is not available: fastqc"])

    def test_absent_observation_is_unknown_instead_of_guessed(self) -> None:
        workspace = Path("/workspace")
        requirements = RequirementSet(
            binding="snakemake",
            pipeline="fastq_qc",
            requirements=[
                RuntimeRequirement(
                    id="fastqc",
                    layer="task_software",
                    capability="command",
                    value="fastqc",
                    source="workflow contract",
                )
            ],
        )
        result = evaluate(requirements, _snapshot(workspace))

        self.assertEqual(result.status, "unknown")
        self.assertEqual(result.blockers, [])
        self.assertEqual(result.unknowns, ["runtime did not observe required executable: fastqc"])

    def test_orchestration_observes_a_real_requested_executable(self) -> None:
        requirements = RequirementSet(
            binding="snakemake",
            pipeline="test",
            requirements=[
                RuntimeRequirement(
                    id="current-python",
                    layer="task_software",
                    capability="command",
                    value=sys.executable,
                    source="test request",
                )
            ],
        )
        result = readiness_service.assess(requirements)

        observation = next(
            command for command in result.commands if command.name == "current-python"
        )
        self.assertEqual(result.status, "ready")
        self.assertEqual(result.target.target_id, "local")
        self.assertEqual(observation.state, "ready")
        self.assertEqual(observation.path, sys.executable)

    def test_slurm_control_plane_is_required_but_worker_uncertainty_is_not_blocking(self) -> None:
        workspace = Path("/workspace")
        requirements = RequirementSet(binding="nextflow", pipeline="fastq_qc", requirements=[])
        snapshot = _snapshot(
            workspace,
            RuntimeCommand(name="slurm-submit", path="/usr/bin/sbatch", state="ready"),
            RuntimeCommand(name="slurm-queue", path="/usr/bin/squeue", state="ready"),
        )
        snapshot.warnings.append("Slurm worker runtime and shared filesystem remain unknown")
        with (
            mock.patch.object(
                readiness_service,
                "resolve_compute_target",
                return_value=mock.Mock(executor="slurm"),
            ),
            mock.patch.object(
                readiness_service.runtime,
                "resolve_runtime_environment",
                return_value=snapshot,
            ),
        ):
            result = readiness_service.assess(requirements, target_id="cluster")
        self.assertEqual(result.status, "ready")
        self.assertEqual(result.unknowns, [])
        self.assertTrue(any("worker" in warning for warning in result.warnings))
        self.assertEqual(
            [requirement.id for requirement in result.requirements],
            ["slurm-submit", "slurm-queue"],
        )


if __name__ == "__main__":
    unittest.main()

SHA-256: 2a0221d0214141e6891a0f013a55c34f93fd6dd63bc23c386d4a85c480c23a7e