From ed98ed6568c5a7b89740fad47ec0452f87eca065 Mon Sep 17 00:00:00 2001 From: rookiestar28 Date: Sat, 11 Jul 2026 06:33:08 +0800 Subject: [PATCH] chore(quality): enforce incremental static analysis --- .github/workflows/ci.yml | 4 + .github/workflows/pre-commit.yml | 4 + .pre-commit-config.yaml | 10 + pyproject.toml | 18 +- requirements-quality.txt | 4 + scripts/run_full_tests_linux.sh | 9 + scripts/run_full_tests_windows.ps1 | 15 + scripts/verify_static_analysis_policy.py | 604 ++ tests/static_analysis_policy.json | 10777 ++++++++++++++++++++ tests/test_r217_static_analysis_policy.py | 521 + 10 files changed, 11963 insertions(+), 3 deletions(-) create mode 100644 requirements-quality.txt create mode 100644 scripts/verify_static_analysis_policy.py create mode 100644 tests/static_analysis_policy.json create mode 100644 tests/test_r217_static_analysis_policy.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 24c1803..1a611a2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -106,10 +106,14 @@ jobs: # CRITICAL: Python 3.10 coverage reads pyproject.toml only when the # TOML extra is present; do not downgrade this back to plain coverage. python -m pip install -r requirements.txt + python -m pip install -r requirements-quality.txt python -m pip install numpy pillow aiohttp "coverage[toml]" - name: R120 preflight run: | python scripts/preflight_check.py --strict + - name: Static-analysis policy + run: | + python scripts/verify_static_analysis_policy.py - name: Run MAE hard-guarantee suites env: MOLTBOT_STATE_DIR: ${{ github.workspace }}/moltbot_state/_ci_mae diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index aad43ac..12208ef 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -31,6 +31,10 @@ jobs: # Install black/isort explicitly so CI doesn't fail due to missing tools # if a hook is configured to run via system python. pip install pre-commit black==24.1.1 isort==5.13.2 + pip install -r requirements-quality.txt + + - name: Verify static-analysis policy directly + run: python scripts/verify_static_analysis_policy.py - name: Run all pre-commit hooks run: pre-commit run --all-files --show-diff-on-failure diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 60f9de6..0cd48cd 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -41,6 +41,16 @@ repos: language: python pass_filenames: false always_run: true + - id: static-analysis-policy + name: incremental Ruff/Mypy static-analysis policy + # Keep isolated pins aligned with requirements-quality.txt and policy JSON. + entry: python -B scripts/verify_static_analysis_policy.py + language: python + additional_dependencies: + - ruff==0.15.20 + - mypy==2.2.0 + pass_filenames: false + always_run: true # Secret detection - repo: https://github.com/Yelp/detect-secrets diff --git a/pyproject.toml b/pyproject.toml index e3fbb1f..ec8fcad 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -71,9 +71,12 @@ target-version = ["py310"] [tool.mypy] python_version = "3.10" warn_return_any = true -warn_unused_configs = true +warn_unused_configs = false disallow_untyped_defs = false # Start lenient, can tighten later disallow_any_unimported = false +explicit_package_bases = true +no_site_packages = true +ignore_missing_imports = true no_implicit_optional = true warn_redundant_casts = true warn_unused_ignores = true @@ -81,8 +84,17 @@ warn_no_return = true check_untyped_defs = true strict_equality = true -# Paths to check -files = ["*.py", "tests/**/*.py"] +# Production paths governed by tests/static_analysis_policy.json. +files = [ + "__init__.py", + "config.py", + "api", + "connector", + "models", + "nodes", + "services", + "scripts", +] # Ignore missing imports for ComfyUI and external packages [[tool.mypy.overrides]] diff --git a/requirements-quality.txt b/requirements-quality.txt new file mode 100644 index 0000000..218d6f5 --- /dev/null +++ b/requirements-quality.txt @@ -0,0 +1,4 @@ +# Development/test-only static-analysis toolchain. +# Keep exact pins aligned with tests/static_analysis_policy.json. +ruff==0.15.20 +mypy==2.2.0 diff --git a/scripts/run_full_tests_linux.sh b/scripts/run_full_tests_linux.sh index b95eda8..563ca81 100644 --- a/scripts/run_full_tests_linux.sh +++ b/scripts/run_full_tests_linux.sh @@ -123,6 +123,12 @@ if ! "$VENV_PY" -c "import cryptography" >/dev/null 2>&1; then echo "[tests] Installing cryptography into project venv ($VENV_DIR) ..." pip_install_or_fail "required for S57 secrets-at-rest encryption tests" cryptography fi + +if ! "$VENV_PY" -c "import json, sys; from importlib.metadata import version; p=json.load(open('tests/static_analysis_policy.json', encoding='utf-8')); sys.exit(0 if all(version(name)==cfg['version'] for name,cfg in p['tools'].items()) else 1)" >/dev/null 2>&1; then + echo "[tests] Installing pinned Ruff/Mypy into project venv ($VENV_DIR) ..." + pip_install_or_fail "required for static-analysis policy" -r requirements-quality.txt +fi + if ! "$VENV_PY" -c "import defusedxml" >/dev/null 2>&1; then # IMPORTANT: keep local full-test bootstrap aligned with requirements.txt. echo "[tests] Installing defusedxml into project venv ($VENV_DIR) ..." @@ -194,6 +200,9 @@ echo "[tests] 0/11 supply-chain hardening check" ensure_npm_deps +echo "[tests] 0.5/11 static analysis policy" +"$VENV_PY" scripts/verify_static_analysis_policy.py + echo "[tests] 0/9 R120 dependency preflight" "$VENV_PY" scripts/preflight_check.py --strict diff --git a/scripts/run_full_tests_windows.ps1 b/scripts/run_full_tests_windows.ps1 index 10da4b6..36a0161 100644 --- a/scripts/run_full_tests_windows.ps1 +++ b/scripts/run_full_tests_windows.ps1 @@ -195,6 +195,16 @@ if (-not $hasCoverageTomlSupport) { Invoke-Checked "pip install coverage[toml]" { & $venvPython -m pip install "coverage[toml]" } } +$qualityToolsReady = $true +& $venvPython -c "import json, sys; from importlib.metadata import version; p=json.load(open('tests/static_analysis_policy.json', encoding='utf-8')); sys.exit(0 if all(version(name)==cfg['version'] for name,cfg in p['tools'].items()) else 1)" | Out-Null +if ($LASTEXITCODE -ne 0) { + $qualityToolsReady = $false +} +if (-not $qualityToolsReady) { + Write-Host "[tests] Installing pinned Ruff/Mypy into project venv ..." + Invoke-Checked "pip install quality tools" { & $venvPython -m pip install -r requirements-quality.txt } +} + # Ensure Node >= 18 $nodeMajor = [int]((& node -p "process.versions.node.split('.')[0]").Trim()) if ($nodeMajor -lt 18) { @@ -267,6 +277,11 @@ Invoke-Checked "supply-chain hardening check" { } Ensure-NpmDeps +Write-Host "[tests] 0.5/11 static analysis policy" +Invoke-Checked "static analysis policy" { + & $venvPython scripts/verify_static_analysis_policy.py +} + Write-Host "[tests] 0/8 R120 dependency preflight" Invoke-Checked "preflight_check" { & $venvPython scripts\preflight_check.py --strict } diff --git a/scripts/verify_static_analysis_policy.py b/scripts/verify_static_analysis_policy.py new file mode 100644 index 0000000..22d597c --- /dev/null +++ b/scripts/verify_static_analysis_policy.py @@ -0,0 +1,604 @@ +"""Incremental Ruff/Mypy debt-ratchet verifier. + +The policy owns source paths and normalized diagnostic counts. Line numbers are +intentionally excluded so harmless edits do not churn the baseline; count changes +still fail and require an explicit reviewed baseline refresh. +""" + +from __future__ import annotations + +import argparse +import json +import re +import subprocess +import sys +from collections import Counter +from collections.abc import Callable, Iterable, Mapping +from copy import deepcopy +from dataclasses import dataclass +from datetime import date +from pathlib import Path +from typing import Any, Protocol + + +@dataclass(frozen=True, order=True) +class Diagnostic: + tool: str + path: str + code: str + message: str + + +class _ProcessResult(Protocol): + returncode: int + stdout: str + stderr: str + + +class ToolExecutionError(RuntimeError): + """Raised with content-free context when a quality tool cannot run.""" + + +def _normalize_message(message: Any, repo_root: Path | None = None) -> str: + normalized = " ".join(str(message or "").split()) + if repo_root is not None: + variants = { + str(repo_root.resolve()), + str(repo_root.resolve()).replace("\\", "/"), + } + for variant in sorted(variants, key=len, reverse=True): + if variant: + normalized = normalized.replace(variant, "") + return normalized + + +def _is_safe_relative_path(value: Any) -> bool: + if not isinstance(value, str) or not value.strip(): + return False + candidate = Path(value) + return not candidate.is_absolute() and ".." not in candidate.parts + + +def _repo_relative_path(path_value: Any, repo_root: Path) -> str: + path = Path(str(path_value)) + if not path.is_absolute(): + path = repo_root / path + try: + relative = path.resolve().relative_to(repo_root.resolve()) + except ValueError as exc: + raise ValueError(f"diagnostic path is outside repository: {path_value}") from exc + return relative.as_posix() + + +def _path_within(path: str, root: str) -> bool: + path_obj = Path(path) + root_obj = Path(root) + return path_obj == root_obj or root_obj in path_obj.parents + + +def _excluded_path_values(policy: Mapping[str, Any]) -> tuple[str, ...]: + entries = policy.get("excluded_paths", []) + if not isinstance(entries, list): + return () + return tuple( + str(entry.get("path", "")) + for entry in entries + if isinstance(entry, dict) and entry.get("path") + ) + + +def discover_owned_python_files( + repo_root: Path, policy: Mapping[str, Any] +) -> tuple[str, ...]: + excluded = _excluded_path_values(policy) + discovered: set[str] = set() + for root_value in policy.get("production_roots", []): + root_path = repo_root / str(root_value) + candidates: Iterable[Path] + if root_path.is_file(): + candidates = (root_path,) if root_path.suffix == ".py" else () + elif root_path.is_dir(): + candidates = root_path.rglob("*.py") + else: + continue + for candidate in candidates: + relative = _repo_relative_path(candidate, repo_root) + if any(_path_within(relative, excluded_path) for excluded_path in excluded): + continue + discovered.add(relative) + return tuple(sorted(discovered)) + + +def _baseline_counter(policy: Mapping[str, Any]) -> Counter[Diagnostic]: + baseline: Counter[Diagnostic] = Counter() + entries = policy.get("baseline", []) + if not isinstance(entries, list): + return baseline + for entry in entries: + if not isinstance(entry, dict): + continue + diagnostic = Diagnostic( + tool=str(entry.get("tool", "")), + path=str(entry.get("path", "")), + code=str(entry.get("code", "")), + message=_normalize_message(entry.get("message", "")), + ) + count = entry.get("count", 0) + if isinstance(count, int) and count > 0: + baseline[diagnostic] += count + return baseline + + +def validate_policy(repo_root: Path, policy: Mapping[str, Any]) -> list[str]: + failures: list[str] = [] + if policy.get("schema_version") != 1: + failures.append("schema_version must be 1") + + review = policy.get("review") + if not isinstance(review, dict): + failures.append("review must be an object") + else: + owner = review.get("owner") + if not isinstance(owner, str) or not owner.strip(): + failures.append("review.owner must be a non-empty string") + parsed_dates: dict[str, date] = {} + for key in ("reviewed_at", "next_review_by"): + try: + parsed_dates[key] = date.fromisoformat(str(review.get(key, ""))) + except ValueError: + failures.append(f"review.{key} must be an ISO date") + if ( + len(parsed_dates) == 2 + and parsed_dates["next_review_by"] < parsed_dates["reviewed_at"] + ): + failures.append("review.next_review_by must not precede reviewed_at") + + tools = policy.get("tools") + if not isinstance(tools, dict) or set(tools) != {"ruff", "mypy"}: + failures.append("tools must contain exactly ruff and mypy") + tools = {} + for tool_name in ("ruff", "mypy"): + config = tools.get(tool_name) + if ( + not isinstance(config, dict) + or not isinstance(config.get("version"), str) + or not config["version"].strip() + ): + failures.append(f"tools.{tool_name}.version must be a non-empty string") + + roots = policy.get("production_roots") + if not isinstance(roots, list) or not roots: + failures.append("production_roots must be a non-empty list") + roots = [] + seen_roots: set[str] = set() + valid_roots: list[str] = [] + for index, value in enumerate(roots): + if not _is_safe_relative_path(value): + failures.append(f"production_roots[{index}] is unsafe: {value!r}") + continue + value = str(value) + if value in seen_roots: + failures.append(f"duplicate production root: {value}") + continue + seen_roots.add(value) + valid_roots.append(value) + if not (repo_root / value).exists(): + failures.append(f"production root is missing: {value}") + + excluded_entries = policy.get("excluded_paths") + if not isinstance(excluded_entries, list): + failures.append("excluded_paths must be a list") + excluded_entries = [] + seen_excluded: set[str] = set() + for index, entry in enumerate(excluded_entries): + if not isinstance(entry, dict): + failures.append(f"excluded_paths[{index}] must be an object") + continue + value = entry.get("path") + reason = entry.get("reason") + if not _is_safe_relative_path(value): + failures.append(f"excluded_paths[{index}] is unsafe: {value!r}") + continue + value = str(value) + if value in seen_excluded: + failures.append(f"duplicate excluded path: {value}") + seen_excluded.add(value) + if not isinstance(reason, str) or not reason.strip(): + failures.append(f"excluded path {value} is missing a reason") + if not any(_path_within(value, root) for root in valid_roots): + failures.append(f"excluded path is outside owned roots: {value}") + if not (repo_root / value).exists(): + failures.append(f"excluded path is missing: {value}") + + owned_files = set(discover_owned_python_files(repo_root, policy)) + strict_paths = policy.get("strict_paths") + if not isinstance(strict_paths, list): + failures.append("strict_paths must be a list") + strict_paths = [] + seen_strict: set[str] = set() + for index, value in enumerate(strict_paths): + if not _is_safe_relative_path(value): + failures.append(f"strict_paths[{index}] is unsafe: {value!r}") + continue + value = str(value) + if value in seen_strict: + failures.append(f"duplicate strict path: {value}") + seen_strict.add(value) + if not any(_path_within(path, value) for path in owned_files): + failures.append(f"strict path has no owned Python files: {value}") + + baseline_entries = policy.get("baseline") + if not isinstance(baseline_entries, list): + failures.append("baseline must be a list") + baseline_entries = [] + seen_diagnostics: set[Diagnostic] = set() + for index, entry in enumerate(baseline_entries): + if not isinstance(entry, dict): + failures.append(f"baseline[{index}] must be an object") + continue + diagnostic = Diagnostic( + tool=str(entry.get("tool", "")), + path=str(entry.get("path", "")), + code=str(entry.get("code", "")), + message=_normalize_message(entry.get("message", "")), + ) + if diagnostic.tool not in {"ruff", "mypy"}: + failures.append(f"baseline[{index}] has unknown tool {diagnostic.tool!r}") + if diagnostic.path not in owned_files: + failures.append( + f"baseline[{index}] path is not an owned Python file: {diagnostic.path}" + ) + if not diagnostic.code or not diagnostic.message: + failures.append(f"baseline[{index}] code/message must be non-empty") + count = entry.get("count") + if not isinstance(count, int) or isinstance(count, bool) or count < 1: + failures.append(f"baseline[{index}] count must be a positive integer") + if diagnostic in seen_diagnostics: + failures.append(f"duplicate baseline diagnostic: {diagnostic}") + seen_diagnostics.add(diagnostic) + + if baseline_entries != serialize_baseline(_baseline_counter(policy)): + failures.append("baseline must use canonical sorted serialization") + + return failures + + +def validate_tool_versions( + policy: Mapping[str, Any], detected_versions: Mapping[str, str] +) -> list[str]: + failures: list[str] = [] + tools = policy.get("tools", {}) + for tool_name in ("ruff", "mypy"): + config = tools.get(tool_name, {}) if isinstance(tools, dict) else {} + expected = config.get("version") if isinstance(config, dict) else None + found = detected_versions.get(tool_name, "missing") + if expected != found: + failures.append( + f"{tool_name} version drift: expected {expected}, found {found}" + ) + return failures + + +def validate_requirement_pins( + policy: Mapping[str, Any], requirement_lines: Iterable[str] +) -> list[str]: + requirements: dict[str, str] = {} + for raw_line in requirement_lines: + line = raw_line.split("#", 1)[0].strip() + if not line: + continue + match = re.match(r"^(ruff|mypy)(?:\[.*\])?(.*)$", line, re.IGNORECASE) + if match: + requirements[match.group(1).lower()] = ( + match.group(1).lower() + match.group(2).strip() + ) + + failures: list[str] = [] + tools = policy.get("tools", {}) + for tool_name in sorted(("ruff", "mypy")): + config = tools.get(tool_name, {}) if isinstance(tools, dict) else {} + version = config.get("version") if isinstance(config, dict) else None + expected = f"{tool_name}=={version}" + found = requirements.get(tool_name, "missing") + if found != expected: + failures.append( + f"{tool_name} requirement drift: expected {expected}, found {found}" + ) + return failures + + +def _run_command( + runner: Callable[..., _ProcessResult], command: list[str], repo_root: Path +) -> _ProcessResult: + return runner( + command, + cwd=repo_root, + capture_output=True, + text=True, + encoding="utf-8", + errors="replace", + check=False, + shell=False, + ) + + +def _parse_tool_version(tool_name: str, output: str) -> str: + match = re.search( + rf"\b{re.escape(tool_name)}\s+([0-9]+(?:\.[0-9]+)+)", output + ) + if not match: + raise ToolExecutionError(f"{tool_name} version output was not recognized") + return match.group(1) + + +def run_static_analysis( + repo_root: Path, + policy: Mapping[str, Any], + *, + runner: Callable[..., _ProcessResult] = subprocess.run, +) -> tuple[dict[str, str], Counter[Diagnostic]]: + owned_files = list(discover_owned_python_files(repo_root, policy)) + versions: dict[str, str] = {} + + for tool_name in ("ruff", "mypy"): + command = [sys.executable, "-m", tool_name, "--version"] + result = _run_command(runner, command, repo_root) + if result.returncode != 0: + raise ToolExecutionError( + f"{tool_name} version check failed with exit code {result.returncode}" + ) + versions[tool_name] = _parse_tool_version(tool_name, result.stdout) + + commands = ( + ( + "ruff", + [ + sys.executable, + "-m", + "ruff", + "check", + "--output-format", + "json", + "--no-cache", + *owned_files, + ], + ), + ( + "mypy", + [ + sys.executable, + "-m", + "mypy", + "--output", + "json", + "--no-incremental", + "--explicit-package-bases", + "--no-warn-unused-configs", + "--no-error-summary", + "--no-site-packages", + "--ignore-missing-imports", + *owned_files, + ], + ), + ) + + diagnostics: Counter[Diagnostic] = Counter() + for tool_name, command in commands: + result = _run_command(runner, command, repo_root) + if result.returncode not in {0, 1}: + # SECURITY: stderr may contain private host paths or source content. + # Keep the public/loggable failure content-free and deterministic. + raise ToolExecutionError( + f"{tool_name} execution failed with exit code {result.returncode}" + ) + if tool_name == "ruff": + diagnostics.update(parse_ruff_output(result.stdout, repo_root)) + else: + diagnostics.update(parse_mypy_output(result.stdout, repo_root)) + return versions, diagnostics + + +def compare_diagnostics( + policy: Mapping[str, Any], current: Counter[Diagnostic] +) -> list[str]: + failures: list[str] = [] + baseline = _baseline_counter(policy) + strict_paths = tuple(str(value) for value in policy.get("strict_paths", [])) + + for diagnostic, count in sorted(current.items()): + if any(_path_within(diagnostic.path, path) for path in strict_paths): + failures.append( + "strict path diagnostic: " + f"{diagnostic.tool}:{diagnostic.path}:{diagnostic.code} x{count}" + ) + + for diagnostic in sorted(set(baseline) | set(current)): + expected = baseline.get(diagnostic, 0) + found = current.get(diagnostic, 0) + label = ( + f"{diagnostic.tool}:{diagnostic.path}:{diagnostic.code}:" + f"{diagnostic.message}" + ) + if found > expected: + failures.append(f"new debt: {label} expected {expected}, found {found}") + elif found < expected: + failures.append( + f"stale baseline: {label} expected {expected}, found {found}" + ) + return failures + + +def _diagnostic_from_payload( + *, tool: str, payload: Mapping[str, Any], path_key: str, repo_root: Path +) -> Diagnostic: + return Diagnostic( + tool=tool, + path=_repo_relative_path(payload.get(path_key, ""), repo_root), + code=str(payload.get("code") or "unknown"), + message=_normalize_message(payload.get("message", ""), repo_root), + ) + + +def parse_ruff_output(raw: str, repo_root: Path) -> Counter[Diagnostic]: + payload = json.loads(raw or "[]") + if not isinstance(payload, list): + raise ValueError("Ruff JSON output must be a list") + diagnostics: Counter[Diagnostic] = Counter() + for entry in payload: + if not isinstance(entry, dict): + raise ValueError("Ruff JSON diagnostic must be an object") + diagnostics[ + _diagnostic_from_payload( + tool="ruff", payload=entry, path_key="filename", repo_root=repo_root + ) + ] += 1 + return diagnostics + + +def parse_mypy_output(raw: str, repo_root: Path) -> Counter[Diagnostic]: + stripped = raw.strip() + if not stripped: + return Counter() + if stripped.startswith("["): + payloads = json.loads(stripped) + else: + payloads = [json.loads(line) for line in stripped.splitlines() if line.strip()] + if not isinstance(payloads, list): + raise ValueError("Mypy JSON output must be a list or JSON lines") + diagnostics: Counter[Diagnostic] = Counter() + for entry in payloads: + if not isinstance(entry, dict): + raise ValueError("Mypy JSON diagnostic must be an object") + if entry.get("severity", "error") != "error": + continue + diagnostics[ + _diagnostic_from_payload( + tool="mypy", payload=entry, path_key="file", repo_root=repo_root + ) + ] += 1 + return diagnostics + + +def serialize_baseline(diagnostics: Counter[Diagnostic]) -> list[dict[str, Any]]: + return [ + { + "tool": diagnostic.tool, + "path": diagnostic.path, + "code": diagnostic.code, + "message": diagnostic.message, + "count": count, + } + for diagnostic, count in sorted(diagnostics.items()) + if count > 0 + ] + + +def with_updated_baseline( + policy: Mapping[str, Any], diagnostics: Counter[Diagnostic] +) -> dict[str, Any]: + updated = deepcopy(dict(policy)) + updated["baseline"] = serialize_baseline(diagnostics) + return updated + + +def evaluate_policy( + repo_root: Path, + policy: Mapping[str, Any], + *, + requirement_lines: Iterable[str], + runner: Callable[..., _ProcessResult] = subprocess.run, +) -> tuple[list[str], Counter[Diagnostic]]: + failures = validate_policy(repo_root, policy) + if failures: + return failures, Counter() + failures.extend(validate_requirement_pins(policy, requirement_lines)) + + versions, diagnostics = run_static_analysis(repo_root, policy, runner=runner) + failures.extend(validate_tool_versions(policy, versions)) + failures.extend(compare_diagnostics(policy, diagnostics)) + return failures, diagnostics + + +def _write_policy(path: Path, policy: Mapping[str, Any]) -> None: + path.write_text( + json.dumps(policy, indent=2, ensure_ascii=False) + "\n", encoding="utf-8" + ) + + +def main(argv: list[str] | None = None) -> int: + parser = argparse.ArgumentParser( + description="Verify the incremental Ruff/Mypy static-analysis debt policy." + ) + parser.add_argument("--repo-root", default=".") + parser.add_argument("--policy", default="tests/static_analysis_policy.json") + parser.add_argument("--requirements", default="requirements-quality.txt") + parser.add_argument( + "--write-baseline", + action="store_true", + help="Explicitly replace the accepted diagnostic baseline after review.", + ) + args = parser.parse_args(argv) + + repo_root = Path(args.repo_root).resolve() + policy_path = repo_root / args.policy + requirements_path = repo_root / args.requirements + try: + policy = json.loads(policy_path.read_text(encoding="utf-8")) + requirement_lines = requirements_path.read_text(encoding="utf-8").splitlines() + structural_failures = validate_policy(repo_root, policy) + structural_failures.extend( + validate_requirement_pins(policy, requirement_lines) + ) + if structural_failures: + for failure in structural_failures: + print(f"STATIC-ANALYSIS-FAIL: {failure}") + return 1 + + versions, diagnostics = run_static_analysis(repo_root, policy) + failures = validate_tool_versions(policy, versions) + if args.write_baseline: + strict_policy = with_updated_baseline(policy, diagnostics) + strict_failures = [ + failure + for failure in compare_diagnostics(strict_policy, diagnostics) + if failure.startswith("strict path diagnostic:") + ] + if strict_failures: + for failure in strict_failures: + print(f"STATIC-ANALYSIS-FAIL: {failure}") + return 1 + if failures: + for failure in failures: + print(f"STATIC-ANALYSIS-FAIL: {failure}") + return 1 + _write_policy(policy_path, strict_policy) + print( + "STATIC-ANALYSIS-BASELINE-WRITTEN: " + f"{len(diagnostics)} fingerprints, {sum(diagnostics.values())} findings" + ) + return 0 + + failures.extend(compare_diagnostics(policy, diagnostics)) + if failures: + for failure in failures: + print(f"STATIC-ANALYSIS-FAIL: {failure}") + return 1 + print( + "STATIC-ANALYSIS-PASS: " + f"{len(diagnostics)} fingerprints, {sum(diagnostics.values())} governed findings" + ) + return 0 + except (OSError, ValueError, json.JSONDecodeError) as exc: + print(f"STATIC-ANALYSIS-FAIL: invalid policy or tool output ({type(exc).__name__})") + return 1 + except ToolExecutionError as exc: + print(f"STATIC-ANALYSIS-FAIL: {exc}") + print( + "STATIC-ANALYSIS-REMEDIATION: use the project-local Python to install " + "requirements-quality.txt" + ) + return 1 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/tests/static_analysis_policy.json b/tests/static_analysis_policy.json new file mode 100644 index 0000000..29845ad --- /dev/null +++ b/tests/static_analysis_policy.json @@ -0,0 +1,10777 @@ +{ + "schema_version": 1, + "review": { + "owner": "maintainers", + "reviewed_at": "2026-07-11", + "next_review_by": "2026-10-11" + }, + "tools": { + "ruff": { + "version": "0.15.20" + }, + "mypy": { + "version": "2.2.0" + } + }, + "production_roots": [ + "__init__.py", + "config.py", + "api", + "connector", + "models", + "nodes", + "services", + "scripts" + ], + "excluded_paths": [], + "strict_paths": [ + "scripts/verify_static_analysis_policy.py" + ], + "baseline": [ + { + "tool": "mypy", + "path": "api/approvals.py", + "code": "name-defined", + "message": "Name \"web.Application\" is not defined", + "count": 1 + }, + { + "tool": "mypy", + "path": "api/approvals.py", + "code": "name-defined", + "message": "Name \"web.Request\" is not defined", + "count": 6 + }, + { + "tool": "mypy", + "path": "api/approvals.py", + "code": "name-defined", + "message": "Name \"web.Response\" is not defined", + "count": 4 + }, + { + "tool": "mypy", + "path": "api/approvals.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 4 + }, + { + "tool": "mypy", + "path": "api/assist.py", + "code": "name-defined", + "message": "Name \"web.Request\" is not defined", + "count": 4 + }, + { + "tool": "mypy", + "path": "api/assist.py", + "code": "name-defined", + "message": "Name \"web.Response\" is not defined", + "count": 4 + }, + { + "tool": "mypy", + "path": "api/assist.py", + "code": "name-defined", + "message": "Name \"web.StreamResponse\" is not defined", + "count": 2 + }, + { + "tool": "mypy", + "path": "api/assist.py", + "code": "no-any-return", + "message": "Returning Any from function declared to return \"dict[str, Any]\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "api/bridge.py", + "code": "no-any-return", + "message": "Returning Any from function declared to return \"str\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "api/bridge.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 4 + }, + { + "tool": "mypy", + "path": "api/capabilities.py", + "code": "name-defined", + "message": "Name \"web.Request\" is not defined", + "count": 1 + }, + { + "tool": "mypy", + "path": "api/capabilities.py", + "code": "name-defined", + "message": "Name \"web.Response\" is not defined", + "count": 1 + }, + { + "tool": "mypy", + "path": "api/checkpoints_handler.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 6 + }, + { + "tool": "mypy", + "path": "api/config.py", + "code": "no-redef", + "message": "Name \"redact_text\" already defined (possibly by an import)", + "count": 1 + }, + { + "tool": "mypy", + "path": "api/config.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 7 + }, + { + "tool": "mypy", + "path": "api/connector_contracts.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 7 + }, + { + "tool": "mypy", + "path": "api/events.py", + "code": "assignment", + "message": "Incompatible types in assignment (expression has type \"dict[Never, Never]\", variable has type \"MappingProxyType[str, Parameter]\")", + "count": 1 + }, + { + "tool": "mypy", + "path": "api/events.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 8 + }, + { + "tool": "mypy", + "path": "api/model_manager.py", + "code": "name-defined", + "message": "Name \"web.Request\" is not defined", + "count": 8 + }, + { + "tool": "mypy", + "path": "api/model_manager.py", + "code": "name-defined", + "message": "Name \"web.Response\" is not defined", + "count": 9 + }, + { + "tool": "mypy", + "path": "api/model_manager.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 6 + }, + { + "tool": "mypy", + "path": "api/packs.py", + "code": "assignment", + "message": "Incompatible types in assignment (expression has type \"None\", variable has type \"type[CleanupFileResponse]\")", + "count": 1 + }, + { + "tool": "mypy", + "path": "api/packs.py", + "code": "misc", + "message": "Cannot assign to a type", + "count": 1 + }, + { + "tool": "mypy", + "path": "api/packs.py", + "code": "no-any-return", + "message": "Returning Any from function declared to return \"bool\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "api/pnginfo.py", + "code": "name-defined", + "message": "Name \"web.Request\" is not defined", + "count": 2 + }, + { + "tool": "mypy", + "path": "api/pnginfo.py", + "code": "name-defined", + "message": "Name \"web.Response\" is not defined", + "count": 3 + }, + { + "tool": "mypy", + "path": "api/pnginfo.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 6 + }, + { + "tool": "mypy", + "path": "api/preflight_handler.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 7 + }, + { + "tool": "mypy", + "path": "api/presets.py", + "code": "name-defined", + "message": "Name \"web.Application\" is not defined", + "count": 1 + }, + { + "tool": "mypy", + "path": "api/presets.py", + "code": "name-defined", + "message": "Name \"web.Request\" is not defined", + "count": 5 + }, + { + "tool": "mypy", + "path": "api/presets.py", + "code": "name-defined", + "message": "Name \"web.Response\" is not defined", + "count": 5 + }, + { + "tool": "mypy", + "path": "api/presets.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 1 + }, + { + "tool": "mypy", + "path": "api/remote_admin.py", + "code": "name-defined", + "message": "Name \"web.Request\" is not defined", + "count": 1 + }, + { + "tool": "mypy", + "path": "api/remote_admin.py", + "code": "name-defined", + "message": "Name \"web.Response\" is not defined", + "count": 1 + }, + { + "tool": "mypy", + "path": "api/remote_admin.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 2 + }, + { + "tool": "mypy", + "path": "api/rewrite_recipes.py", + "code": "name-defined", + "message": "Name \"web.Request\" is not defined", + "count": 8 + }, + { + "tool": "mypy", + "path": "api/rewrite_recipes.py", + "code": "name-defined", + "message": "Name \"web.Response\" is not defined", + "count": 9 + }, + { + "tool": "mypy", + "path": "api/rewrite_recipes.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 5 + }, + { + "tool": "mypy", + "path": "api/routes.py", + "code": "misc", + "message": "\"None\" not callable", + "count": 13 + }, + { + "tool": "mypy", + "path": "api/routes.py", + "code": "misc", + "message": "Exception type must be derived from BaseException (or be a tuple of exception classes)", + "count": 4 + }, + { + "tool": "mypy", + "path": "api/routes.py", + "code": "operator", + "message": "Unsupported operand types for - (\"float\" and \"None\")", + "count": 1 + }, + { + "tool": "mypy", + "path": "api/routes.py", + "code": "operator", + "message": "Unsupported right operand type for in (\"Any | None\")", + "count": 1 + }, + { + "tool": "mypy", + "path": "api/routes.py", + "code": "union-attr", + "message": "Item \"None\" of \"Any | None\" has no attribute \"get\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "api/routes.py", + "code": "union-attr", + "message": "Item \"None\" of \"Any | None\" has no attribute \"get_snapshot\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "api/routes.py", + "code": "union-attr", + "message": "Item \"None\" of \"Any | None\" has no attribute \"update\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "api/routes.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 33 + }, + { + "tool": "mypy", + "path": "api/routes.py", + "code": "var-annotated", + "message": "Need type annotation for \"truncated\" (hint: \"truncated: list[] = ...\")", + "count": 1 + }, + { + "tool": "mypy", + "path": "api/schedules.py", + "code": "name-defined", + "message": "Name \"web.Application\" is not defined", + "count": 1 + }, + { + "tool": "mypy", + "path": "api/schedules.py", + "code": "name-defined", + "message": "Name \"web.Request\" is not defined", + "count": 10 + }, + { + "tool": "mypy", + "path": "api/schedules.py", + "code": "name-defined", + "message": "Name \"web.Response\" is not defined", + "count": 10 + }, + { + "tool": "mypy", + "path": "api/schedules.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 8 + }, + { + "tool": "mypy", + "path": "api/secrets.py", + "code": "name-defined", + "message": "Name \"web.Request\" is not defined", + "count": 6 + }, + { + "tool": "mypy", + "path": "api/secrets.py", + "code": "name-defined", + "message": "Name \"web.Response\" is not defined", + "count": 6 + }, + { + "tool": "mypy", + "path": "api/secrets.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 13 + }, + { + "tool": "mypy", + "path": "api/security_doctor.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 4 + }, + { + "tool": "mypy", + "path": "api/templates.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 9 + }, + { + "tool": "mypy", + "path": "api/tools.py", + "code": "name-defined", + "message": "Name \"web.Request\" is not defined", + "count": 2 + }, + { + "tool": "mypy", + "path": "api/tools.py", + "code": "name-defined", + "message": "Name \"web.Response\" is not defined", + "count": 2 + }, + { + "tool": "mypy", + "path": "api/tools.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 1 + }, + { + "tool": "mypy", + "path": "api/triggers.py", + "code": "name-defined", + "message": "Name \"web.Application\" is not defined", + "count": 1 + }, + { + "tool": "mypy", + "path": "api/triggers.py", + "code": "name-defined", + "message": "Name \"web.Request\" is not defined", + "count": 2 + }, + { + "tool": "mypy", + "path": "api/triggers.py", + "code": "name-defined", + "message": "Name \"web.Response\" is not defined", + "count": 3 + }, + { + "tool": "mypy", + "path": "api/triggers.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 8 + }, + { + "tool": "mypy", + "path": "api/webhook.py", + "code": "name-defined", + "message": "Name \"web.Request\" is not defined", + "count": 1 + }, + { + "tool": "mypy", + "path": "api/webhook.py", + "code": "name-defined", + "message": "Name \"web.Response\" is not defined", + "count": 1 + }, + { + "tool": "mypy", + "path": "api/webhook.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 1 + }, + { + "tool": "mypy", + "path": "api/webhook_submit.py", + "code": "name-defined", + "message": "Name \"web.Request\" is not defined", + "count": 1 + }, + { + "tool": "mypy", + "path": "api/webhook_submit.py", + "code": "name-defined", + "message": "Name \"web.Response\" is not defined", + "count": 2 + }, + { + "tool": "mypy", + "path": "api/webhook_submit.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 13 + }, + { + "tool": "mypy", + "path": "api/webhook_validate.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 8 + }, + { + "tool": "mypy", + "path": "config.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 6 + }, + { + "tool": "mypy", + "path": "connector/__main__.py", + "code": "assignment", + "message": "Incompatible types in assignment (expression has type \"DiscordGateway\", target has type \"TelegramPolling\")", + "count": 1 + }, + { + "tool": "mypy", + "path": "connector/__main__.py", + "code": "assignment", + "message": "Incompatible types in assignment (expression has type \"FeishuWebhookServer\", target has type \"TelegramPolling\")", + "count": 1 + }, + { + "tool": "mypy", + "path": "connector/__main__.py", + "code": "assignment", + "message": "Incompatible types in assignment (expression has type \"KakaoWebhookServer\", target has type \"TelegramPolling\")", + "count": 1 + }, + { + "tool": "mypy", + "path": "connector/__main__.py", + "code": "assignment", + "message": "Incompatible types in assignment (expression has type \"LINEWebhookServer\", target has type \"TelegramPolling\")", + "count": 1 + }, + { + "tool": "mypy", + "path": "connector/__main__.py", + "code": "assignment", + "message": "Incompatible types in assignment (expression has type \"SlackSocketModeClient\", target has type \"TelegramPolling\")", + "count": 1 + }, + { + "tool": "mypy", + "path": "connector/__main__.py", + "code": "assignment", + "message": "Incompatible types in assignment (expression has type \"SlackWebhookServer\", variable has type \"SlackSocketModeClient | None\")", + "count": 1 + }, + { + "tool": "mypy", + "path": "connector/__main__.py", + "code": "assignment", + "message": "Incompatible types in assignment (expression has type \"WeChatWebhookServer\", target has type \"TelegramPolling\")", + "count": 1 + }, + { + "tool": "mypy", + "path": "connector/__main__.py", + "code": "assignment", + "message": "Incompatible types in assignment (expression has type \"WhatsAppWebhookServer\", target has type \"TelegramPolling\")", + "count": 1 + }, + { + "tool": "mypy", + "path": "connector/__main__.py", + "code": "var-annotated", + "message": "Need type annotation for \"platforms\" (hint: \"platforms: dict[, ] = ...\")", + "count": 1 + }, + { + "tool": "mypy", + "path": "connector/channels/kakaotalk.py", + "code": "index", + "message": "Unsupported target for indexed assignment (\"Collection[str]\")", + "count": 1 + }, + { + "tool": "mypy", + "path": "connector/llm_client.py", + "code": "assignment", + "message": "Incompatible types in assignment (expression has type \"float\", variable has type \"int\")", + "count": 1 + }, + { + "tool": "mypy", + "path": "connector/llm_client.py", + "code": "no-any-return", + "message": "Returning Any from function declared to return \"bool\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "connector/llm_client.py", + "code": "no-any-return", + "message": "Returning Any from function declared to return \"dict[Any, Any]\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "connector/llm_client.py", + "code": "no-any-return", + "message": "Returning Any from function declared to return \"str\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "connector/openclaw_client.py", + "code": "assignment", + "message": "Incompatible default for parameter \"json_data\" (default has type \"None\", parameter has type \"dict[Any, Any]\")", + "count": 1 + }, + { + "tool": "mypy", + "path": "connector/openclaw_client.py", + "code": "no-any-return", + "message": "Returning Any from function declared to return \"bytes | None\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "connector/openclaw_client.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 1 + }, + { + "tool": "mypy", + "path": "connector/platforms/discord_gateway.py", + "code": "arg-type", + "message": "Argument 1 to \"_send_response\" of \"DiscordGateway\" has incompatible type \"Any | None\"; expected \"str\"", + "count": 2 + }, + { + "tool": "mypy", + "path": "connector/platforms/discord_gateway.py", + "code": "attr-defined", + "message": "\"None\" has no attribute \"post\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "connector/platforms/discord_gateway.py", + "code": "attr-defined", + "message": "\"None\" has no attribute \"send_json\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "connector/platforms/discord_gateway.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 1 + }, + { + "tool": "mypy", + "path": "connector/platforms/feishu_installation_manager.py", + "code": "arg-type", + "message": "Argument 1 to \"_secrets_for_installation\" of \"FeishuInstallationManager\" has incompatible type \"ConnectorInstallation | None\"; expected \"ConnectorInstallation\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "connector/platforms/feishu_installation_manager.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 4 + }, + { + "tool": "mypy", + "path": "connector/platforms/feishu_long_connection.py", + "code": "arg-type", + "message": "Argument 1 to \"create_task\" has incompatible type \"Awaitable[Any]\"; expected \"Generator[Any, None, Any] | Coroutine[Any, Any, Any]\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "connector/platforms/feishu_long_connection.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 2 + }, + { + "tool": "mypy", + "path": "connector/platforms/feishu_webhook.py", + "code": "attr-defined", + "message": "\"None\" has no attribute \"router\"", + "count": 2 + }, + { + "tool": "mypy", + "path": "connector/platforms/feishu_webhook.py", + "code": "attr-defined", + "message": "\"None\" has no attribute \"setup\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "connector/platforms/feishu_webhook.py", + "code": "attr-defined", + "message": "\"None\" has no attribute \"start\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "connector/platforms/feishu_webhook.py", + "code": "index", + "message": "Value of type \"Any | None\" is not indexable", + "count": 1 + }, + { + "tool": "mypy", + "path": "connector/platforms/feishu_webhook.py", + "code": "name-defined", + "message": "Name \"InstallationResolution\" is not defined", + "count": 1 + }, + { + "tool": "mypy", + "path": "connector/platforms/feishu_webhook.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 4 + }, + { + "tool": "mypy", + "path": "connector/platforms/kakao_webhook.py", + "code": "attr-defined", + "message": "\"None\" has no attribute \"router\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "connector/platforms/kakao_webhook.py", + "code": "attr-defined", + "message": "\"None\" has no attribute \"setup\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "connector/platforms/kakao_webhook.py", + "code": "attr-defined", + "message": "\"None\" has no attribute \"start\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "connector/platforms/line_webhook.py", + "code": "arg-type", + "message": "Argument 1 to \"_reply_message\" of \"LINEWebhookServer\" has incompatible type \"Any | None\"; expected \"str\"", + "count": 2 + }, + { + "tool": "mypy", + "path": "connector/platforms/line_webhook.py", + "code": "attr-defined", + "message": "\"None\" has no attribute \"post\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "connector/platforms/line_webhook.py", + "code": "attr-defined", + "message": "\"None\" has no attribute \"router\"", + "count": 2 + }, + { + "tool": "mypy", + "path": "connector/platforms/line_webhook.py", + "code": "attr-defined", + "message": "\"None\" has no attribute \"setup\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "connector/platforms/line_webhook.py", + "code": "attr-defined", + "message": "\"None\" has no attribute \"start\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "connector/platforms/line_webhook.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 2 + }, + { + "tool": "mypy", + "path": "connector/platforms/slack_installation_manager.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 5 + }, + { + "tool": "mypy", + "path": "connector/platforms/slack_socket_mode.py", + "code": "no-any-return", + "message": "Returning Any from function declared to return \"str | None\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "connector/platforms/slack_webhook.py", + "code": "arg-type", + "message": "Argument 1 to \"_is_admin\" of \"CommandRouter\" has incompatible type \"CommandRequest\"; expected \"str\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "connector/platforms/slack_webhook.py", + "code": "attr-defined", + "message": "\"None\" has no attribute \"router\"", + "count": 4 + }, + { + "tool": "mypy", + "path": "connector/platforms/slack_webhook.py", + "code": "attr-defined", + "message": "\"None\" has no attribute \"setup\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "connector/platforms/slack_webhook.py", + "code": "attr-defined", + "message": "\"None\" has no attribute \"start\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "connector/platforms/telegram_polling.py", + "code": "arg-type", + "message": "Argument \"path\" to \"ConnectorState\" has incompatible type \"str | None\"; expected \"str\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "connector/platforms/telegram_polling.py", + "code": "attr-defined", + "message": "\"None\" has no attribute \"get\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "connector/platforms/telegram_polling.py", + "code": "attr-defined", + "message": "\"None\" has no attribute \"post\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "connector/platforms/telegram_polling.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 1 + }, + { + "tool": "mypy", + "path": "connector/platforms/wechat_webhook.py", + "code": "attr-defined", + "message": "\"None\" has no attribute \"router\"", + "count": 2 + }, + { + "tool": "mypy", + "path": "connector/platforms/wechat_webhook.py", + "code": "attr-defined", + "message": "\"None\" has no attribute \"setup\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "connector/platforms/wechat_webhook.py", + "code": "attr-defined", + "message": "\"None\" has no attribute \"start\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "connector/platforms/wechat_webhook.py", + "code": "no-any-return", + "message": "Returning Any from function declared to return \"bytes\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "connector/platforms/wechat_webhook.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 2 + }, + { + "tool": "mypy", + "path": "connector/platforms/whatsapp_webhook.py", + "code": "attr-defined", + "message": "\"None\" has no attribute \"router\"", + "count": 3 + }, + { + "tool": "mypy", + "path": "connector/platforms/whatsapp_webhook.py", + "code": "attr-defined", + "message": "\"None\" has no attribute \"setup\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "connector/platforms/whatsapp_webhook.py", + "code": "attr-defined", + "message": "\"None\" has no attribute \"start\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "connector/platforms/whatsapp_webhook.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 2 + }, + { + "tool": "mypy", + "path": "connector/results_poller.py", + "code": "misc", + "message": "Cannot infer type of lambda", + "count": 2 + }, + { + "tool": "mypy", + "path": "connector/results_poller.py", + "code": "var-annotated", + "message": "Need type annotation for \"active_approval_polls\" (hint: \"active_approval_polls: dict[, ] = ...\")", + "count": 1 + }, + { + "tool": "mypy", + "path": "connector/results_poller.py", + "code": "var-annotated", + "message": "Need type annotation for \"active_polls\" (hint: \"active_polls: dict[, ] = ...\")", + "count": 1 + }, + { + "tool": "mypy", + "path": "connector/results_poller.py", + "code": "var-annotated", + "message": "Need type annotation for \"approval_queue\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "connector/results_poller.py", + "code": "var-annotated", + "message": "Need type annotation for \"queue\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "connector/router.py", + "code": "arg-type", + "message": "Argument \"path\" to \"ConnectorState\" has incompatible type \"str | None\"; expected \"str\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "connector/router.py", + "code": "assignment", + "message": "Incompatible default for parameter \"poller\" (default has type \"None\", parameter has type \"ResultsPoller\")", + "count": 1 + }, + { + "tool": "mypy", + "path": "connector/router.py", + "code": "no-any-return", + "message": "Returning Any from function declared to return \"dict[str, Any]\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "connector/router.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 1 + }, + { + "tool": "mypy", + "path": "connector/state.py", + "code": "assignment", + "message": "Incompatible default for parameter \"path\" (default has type \"None\", parameter has type \"str\")", + "count": 1 + }, + { + "tool": "mypy", + "path": "connector/state.py", + "code": "no-any-return", + "message": "Returning Any from function declared to return \"int\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "connector/transport_contract.py", + "code": "no-any-return", + "message": "Returning Any from function declared to return \"int\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "models/schemas.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 1 + }, + { + "tool": "mypy", + "path": "scripts/openclaw_smoke_import.py", + "code": "arg-type", + "message": "Argument 1 to \"__import__\" has incompatible type \"str | None\"; expected \"str\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "scripts/openclaw_smoke_import.py", + "code": "arg-type", + "message": "Argument 1 to \"join\" of \"str\" has incompatible type \"list[str | None]\"; expected \"Iterable[str]\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "scripts/openclaw_smoke_import.py", + "code": "var-annotated", + "message": "Need type annotation for \"results\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "scripts/quality_governance_common.py", + "code": "no-any-return", + "message": "Returning Any from function declared to return \"dict[str, Any] | None\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "scripts/report_coverage_governance.py", + "code": "attr-defined", + "message": "\"object\" has no attribute \"items\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "scripts/report_coverage_governance.py", + "code": "index", + "message": "Value of type \"object\" is not indexable", + "count": 3 + }, + { + "tool": "mypy", + "path": "scripts/run_adversarial_gate.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 1 + }, + { + "tool": "mypy", + "path": "scripts/run_mutation_test.py", + "code": "attr-defined", + "message": "\"object\" has no attribute \"append\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "scripts/run_mutation_test.py", + "code": "func-returns-value", + "message": "\"setattr\" does not return a value (it only ever returns None)", + "count": 2 + }, + { + "tool": "mypy", + "path": "scripts/run_mutation_test.py", + "code": "operator", + "message": "Unsupported left operand type for / (\"object\")", + "count": 1 + }, + { + "tool": "mypy", + "path": "scripts/run_mutation_test.py", + "code": "operator", + "message": "Unsupported operand types for + (\"object\" and \"int\")", + "count": 3 + }, + { + "tool": "mypy", + "path": "scripts/run_mutation_test.py", + "code": "operator", + "message": "Unsupported operand types for < (\"int\" and \"object\")", + "count": 1 + }, + { + "tool": "mypy", + "path": "scripts/verify_exception_boundary_policy.py", + "code": "arg-type", + "message": "Argument 1 to \"visit_FunctionDef\" of \"_BroadCatchVisitor\" has incompatible type \"AsyncFunctionDef\"; expected \"FunctionDef\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "scripts/verify_exception_boundary_policy.py", + "code": "no-any-return", + "message": "Returning Any from function declared to return \"dict[str, Any]\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/access_control.py", + "code": "misc", + "message": "All conditional function variants must have identical signatures", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/access_control.py", + "code": "no-redef", + "message": "Name \"AuthTier\" already defined (possibly by an import)", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/aiohttp_compat.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/approvals/storage.py", + "code": "var-annotated", + "message": "Need type annotation for \"to_remove\" (hint: \"to_remove: list[] = ...\")", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/audit.py", + "code": "assignment", + "message": "Incompatible types in assignment (expression has type \"None\", variable has type \"Callable[[], str]\")", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/audit.py", + "code": "assignment", + "message": "Incompatible types in assignment (expression has type \"dict[str, Any]\", target has type \"str\")", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/audit.py", + "code": "no-any-return", + "message": "Returning Any from function declared to return \"str\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/audit.py", + "code": "truthy-function", + "message": "Function \"get_state_dir\" could always be true in boolean context", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/audit.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/bridge_token_lifecycle.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 2 + }, + { + "tool": "mypy", + "path": "services/capabilities.py", + "code": "assignment", + "message": "Incompatible types in assignment (expression has type \"dict[Any, Any]\", target has type \"list[str] | str\")", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/capabilities.py", + "code": "assignment", + "message": "Incompatible types in assignment (expression has type \"dict[str, bool]\", target has type \"list[str] | str\")", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/capabilities.py", + "code": "dict-item", + "message": "Dict entry 2 has incompatible type \"str\": \"str\"; expected \"str\": \"bool\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/capabilities.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/chatops/network_errors.py", + "code": "assignment", + "message": "Incompatible types in assignment (expression has type \"BaseException\", variable has type \"Exception\")", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/chatops/retry.py", + "code": "assignment", + "message": "Incompatible types in assignment (expression has type \"Random | Module\", variable has type \"Random | None\")", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/chatops/retry.py", + "code": "no-any-return", + "message": "Returning Any from function declared to return \"float\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/chatops/retry.py", + "code": "union-attr", + "message": "Item \"None\" of \"Random | None\" has no attribute \"uniform\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/comfyui_history.py", + "code": "no-any-return", + "message": "Returning Any from function declared to return \"dict[str, Any] | None\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/connector_callback_contract.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 4 + }, + { + "tool": "mypy", + "path": "services/connector_extraction_contract.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/connector_installation_registry.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 4 + }, + { + "tool": "mypy", + "path": "services/constrained_transforms.py", + "code": "return-value", + "message": "Incompatible return value type (got \"TransformExecutor | None\", expected \"TransformExecutor\")", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/constrained_transforms.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/crypto_lifecycle_drills.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 5 + }, + { + "tool": "mypy", + "path": "services/csrf_protection.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 2 + }, + { + "tool": "mypy", + "path": "services/deployment_profile.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/idempotency_store.py", + "code": "assignment", + "message": "Incompatible types in assignment (expression has type \"None\", variable has type \"DurableBackend\")", + "count": 2 + }, + { + "tool": "mypy", + "path": "services/idempotency_store.py", + "code": "attr-defined", + "message": "\"IdempotencyStore\" has no attribute \"_store\"", + "count": 16 + }, + { + "tool": "mypy", + "path": "services/idempotency_store.py", + "code": "attr-defined", + "message": "\"IdempotencyStore\" has no attribute \"_store_lock\"", + "count": 6 + }, + { + "tool": "mypy", + "path": "services/idempotency_store.py", + "code": "has-type", + "message": "Cannot determine type of \"_last_cleanup\"", + "count": 2 + }, + { + "tool": "mypy", + "path": "services/idempotency_store.py", + "code": "misc", + "message": "Type cannot be declared in assignment to non-self attribute", + "count": 2 + }, + { + "tool": "mypy", + "path": "services/idempotency_store.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/image_utils.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 4 + }, + { + "tool": "mypy", + "path": "services/integrity.py", + "code": "no-any-return", + "message": "Returning Any from function declared to return \"dict[str, Any]\"", + "count": 2 + }, + { + "tool": "mypy", + "path": "services/jobs_read_model.py", + "code": "no-any-return", + "message": "Returning Any from function declared to return \"Callable[..., Any]\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/legacy_compat.py", + "code": "assignment", + "message": "Incompatible types in assignment (expression has type \"None\", variable has type \"Metrics\")", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/llm_client.py", + "code": "arg-type", + "message": "Argument \"api_key\" to \"make_request\" has incompatible type \"str | None\"; expected \"str\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/llm_client.py", + "code": "arg-type", + "message": "Argument \"base_url\" to \"make_request\" has incompatible type \"str | Any | None\"; expected \"str\"", + "count": 2 + }, + { + "tool": "mypy", + "path": "services/llm_client.py", + "code": "arg-type", + "message": "Argument \"base_url\" to \"make_request_stream\" has incompatible type \"str | Any | None\"; expected \"str\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/llm_client.py", + "code": "assignment", + "message": "Incompatible types in assignment (expression has type \"Any | None\", variable has type \"str\")", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/llm_client.py", + "code": "assignment", + "message": "Incompatible types in assignment (expression has type \"None\", variable has type \"str\")", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/llm_client.py", + "code": "assignment", + "message": "Incompatible types in assignment (expression has type \"float | int\", variable has type \"int\")", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/llm_client.py", + "code": "no-any-return", + "message": "Returning Any from function declared to return \"dict[str, Any]\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/llm_client.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/llm_model_list.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/metrics.py", + "code": "attr-defined", + "message": "\"Metrics\" has no attribute \"_counter_lock\"", + "count": 4 + }, + { + "tool": "mypy", + "path": "services/metrics.py", + "code": "attr-defined", + "message": "\"Metrics\" has no attribute \"_counters\"", + "count": 6 + }, + { + "tool": "mypy", + "path": "services/metrics.py", + "code": "no-any-return", + "message": "Returning Any from function declared to return \"dict[str, int]\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/model_manager.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/model_manager_tasks.py", + "code": "no-any-return", + "message": "Returning Any from function declared to return \"dict[str, Any]\"", + "count": 3 + }, + { + "tool": "mypy", + "path": "services/model_manager_transfer.py", + "code": "no-any-return", + "message": "Returning Any from function declared to return \"dict[str, Any]\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/model_manager_transfer.py", + "code": "no-any-return", + "message": "Returning Any from function declared to return \"str\"", + "count": 2 + }, + { + "tool": "mypy", + "path": "services/operator_guidance.py", + "code": "assignment", + "message": "Incompatible types in assignment (expression has type \"dict[str, str]\", target has type \"int | str\")", + "count": 2 + }, + { + "tool": "mypy", + "path": "services/packs/pack_manifest.py", + "code": "arg-type", + "message": "Argument \"key\" to \"sort\" of \"list\" has incompatible type \"Callable[[dict[str, object]], object]\"; expected \"Callable[[dict[str, object]], SupportsDunderLT[Any] | SupportsDunderGT[Any]]\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/packs/pack_manifest.py", + "code": "return-value", + "message": "Incompatible return value type (got \"object\", expected \"SupportsDunderLT[Any] | SupportsDunderGT[Any]\")", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/parameter_lab.py", + "code": "arg-type", + "message": "Argument 1 to \"generate\" of \"ComparePlanner\" has incompatible type \"Any | None\"; expected \"str\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/parameter_lab.py", + "code": "arg-type", + "message": "Argument 1 to \"generate\" of \"SweepPlanner\" has incompatible type \"Any | None\"; expected \"str\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/parameter_lab.py", + "code": "no-any-return", + "message": "Returning Any from function declared to return \"dict[str, Any] | None\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/parameter_lab.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 3 + }, + { + "tool": "mypy", + "path": "services/planner.py", + "code": "arg-type", + "message": "Argument 1 to \"validate_planner_output\" has incompatible type \"dict[str, Any] | None\"; expected \"dict[str, Any]\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/planner.py", + "code": "index", + "message": "Value of type \"dict[str, Any] | None\" is not indexable", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/planner.py", + "code": "union-attr", + "message": "Item \"None\" of \"dict[str, Any] | None\" has no attribute \"get\"", + "count": 2 + }, + { + "tool": "mypy", + "path": "services/planner_registry.py", + "code": "misc", + "message": "Need more than 3 values to unpack (4 expected)", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/planner_registry.py", + "code": "return-value", + "message": "Incompatible return value type (got \"tuple[dict[str, Any], str, str, None]\", expected \"tuple[dict[str, Any], str, str | None]\")", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/planner_registry.py", + "code": "return-value", + "message": "Incompatible return value type (got \"tuple[dict[str, Any], str, str, str | None]\", expected \"tuple[dict[str, Any], str, str | None]\")", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/planner_registry.py", + "code": "return-value", + "message": "Incompatible return value type (got \"tuple[dict[str, Any], str, str, str]\", expected \"tuple[dict[str, Any], str, str | None]\")", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/planner_registry.py", + "code": "union-attr", + "message": "Item \"None\" of \"Any | None\" has no attribute \"strip\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/plugins/contract.py", + "code": "no-any-return", + "message": "Returning Any from function declared to return \"str\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/plugins/manager.py", + "code": "no-any-return", + "message": "Returning Any from function declared to return \"T\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/pnginfo.py", + "code": "no-any-return", + "message": "Returning Any from function declared to return \"str\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/pnginfo.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 3 + }, + { + "tool": "mypy", + "path": "services/preflight.py", + "code": "arg-type", + "message": "Argument 1 to \"len\" has incompatible type \"object\"; expected \"Sized\"", + "count": 4 + }, + { + "tool": "mypy", + "path": "services/preflight.py", + "code": "attr-defined", + "message": "\"object\" has no attribute \"__iter__\"; maybe \"__dir__\" or \"__str__\"? (not iterable)", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/preflight.py", + "code": "attr-defined", + "message": "\"object\" has no attribute \"append\"", + "count": 8 + }, + { + "tool": "mypy", + "path": "services/preflight.py", + "code": "index", + "message": "Unsupported target for indexed assignment (\"object\")", + "count": 4 + }, + { + "tool": "mypy", + "path": "services/preflight.py", + "code": "index", + "message": "Value of type \"object\" is not indexable", + "count": 4 + }, + { + "tool": "mypy", + "path": "services/preflight.py", + "code": "name-defined", + "message": "Name \"OperatorBanner\" is not defined", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/preflight.py", + "code": "no-any-return", + "message": "Returning Any from function declared to return \"dict[str, Any]\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/preflight.py", + "code": "no-any-return", + "message": "Returning Any from function declared to return \"dict[str, list[str]]\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/preflight.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 4 + }, + { + "tool": "mypy", + "path": "services/preflight.py", + "code": "var-annotated", + "message": "Need type annotation for \"_CACHE\" (hint: \"_CACHE: dict[, ] = ...\")", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/preflight.py", + "code": "var-annotated", + "message": "Need type annotation for \"banners\" (hint: \"banners: list[] = ...\")", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/presets/models.py", + "code": "assignment", + "message": "Incompatible default for parameter \"tags\" (default has type \"None\", parameter has type \"list[str]\")", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/providers/keys.py", + "code": "arg-type", + "message": "Argument 1 to \"mask_api_key\" has incompatible type \"str | None\"; expected \"str\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/queue_submit.py", + "code": "no-any-return", + "message": "Returning Any from function declared to return \"dict[str, Any]\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/queue_submit.py", + "code": "no-redef", + "message": "Name \"APIError\" already defined (possibly by an import)", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/queue_submit.py", + "code": "no-redef", + "message": "Name \"ErrorCode\" already defined (possibly by an import)", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/queue_submit.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 3 + }, + { + "tool": "mypy", + "path": "services/rate_limit.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 2 + }, + { + "tool": "mypy", + "path": "services/refiner.py", + "code": "arg-type", + "message": "Argument 1 to \"validate_refiner_output\" has incompatible type \"dict[str, Any] | None\"; expected \"dict[str, Any]\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/refiner.py", + "code": "union-attr", + "message": "Item \"None\" of \"dict[str, Any] | None\" has no attribute \"get\"", + "count": 4 + }, + { + "tool": "mypy", + "path": "services/registry_quarantine.py", + "code": "assignment", + "message": "Incompatible types in assignment (expression has type \"None\", variable has type \"type[PackArchive]\")", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/registry_quarantine.py", + "code": "assignment", + "message": "Incompatible types in assignment (expression has type \"None\", variable has type \"type[PackError]\")", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/registry_quarantine.py", + "code": "misc", + "message": "Cannot assign to a type", + "count": 2 + }, + { + "tool": "mypy", + "path": "services/registry_quarantine.py", + "code": "truthy-function", + "message": "Function \"PackArchive\" could always be true in boolean context", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/registry_quarantine.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 4 + }, + { + "tool": "mypy", + "path": "services/registry_quarantine.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore[assignment, misc]\" comment", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/request_ip.py", + "code": "no-any-return", + "message": "Returning Any from function declared to return \"str\"", + "count": 2 + }, + { + "tool": "mypy", + "path": "services/request_ip.py", + "code": "return-value", + "message": "Incompatible return value type (got \"list[IPv4Network | IPv6Network]\", expected \"list[IPv4Network]\")", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/retry_partition.py", + "code": "no-any-return", + "message": "Returning Any from function declared to return \"float\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/retry_partition.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/rewrite_recipes.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/route_bootstrap.py", + "code": "misc", + "message": "Assignment to variable \"exc\" outside except: block", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/runtime_config.py", + "code": "attr-defined", + "message": "\"Callable[[str], str | None]\" has no attribute \"_warned_legacy\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/runtime_config.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 8 + }, + { + "tool": "mypy", + "path": "services/runtime_config_policy.py", + "code": "assignment", + "message": "Incompatible types in assignment (expression has type \"int\", target has type \"bool\")", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/runtime_config_policy.py", + "code": "assignment", + "message": "Incompatible types in assignment (expression has type \"object\", target has type \"bool\")", + "count": 2 + }, + { + "tool": "mypy", + "path": "services/runtime_config_policy.py", + "code": "assignment", + "message": "Incompatible types in assignment (expression has type \"str\", target has type \"bool\")", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/runtime_config_policy.py", + "code": "no-redef", + "message": "Name \"SSRFError\" already defined (possibly by an import)", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/runtime_config_policy.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 8 + }, + { + "tool": "mypy", + "path": "services/runtime_config_store.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 3 + }, + { + "tool": "mypy", + "path": "services/runtime_guardrails.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/runtime_lifecycle.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 4 + }, + { + "tool": "mypy", + "path": "services/safe_io.py", + "code": "arg-type", + "message": "Argument 1 to \"is_private_ip\" has incompatible type \"str | int\"; expected \"str\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/safe_io.py", + "code": "attr-defined", + "message": "\"Exception\" has no attribute \"read\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/safe_io.py", + "code": "attr-defined", + "message": "\"PinnedHTTPConnection\" has no attribute \"source_address\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/safe_io.py", + "code": "attr-defined", + "message": "\"PinnedHTTPSConnection\" has no attribute \"_context\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/safe_io.py", + "code": "attr-defined", + "message": "\"PinnedHTTPSConnection\" has no attribute \"source_address\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/safe_io.py", + "code": "attr-defined", + "message": "\"PinnedHTTPSHandler\" has no attribute \"_check_hostname\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/safe_io.py", + "code": "attr-defined", + "message": "\"PinnedHTTPSHandler\" has no attribute \"_context\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/safe_io.py", + "code": "no-any-return", + "message": "Returning Any from function declared to return \"bytes\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/safe_io.py", + "code": "no-any-return", + "message": "Returning Any from function declared to return \"dict[Any, Any]\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/safe_io.py", + "code": "return-value", + "message": "Incompatible return value type (got \"tuple[str, str, int, list[str | int]]\", expected \"tuple[str, str, int, list[str]]\")", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/safe_io.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/scheduler/runner.py", + "code": "arg-type", + "message": "Argument 1 to \"is_cron_due\" has incompatible type \"str | None\"; expected \"str\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/scheduler/runner.py", + "code": "arg-type", + "message": "Argument 1 to \"is_interval_due\" has incompatible type \"int | None\"; expected \"int\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/scheduler/runner.py", + "code": "no-any-return", + "message": "Returning Any from function declared to return \"bool\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/schema_sanitizer.py", + "code": "assignment", + "message": "Incompatible types in assignment (expression has type \"bool\", target has type \"str\")", + "count": 2 + }, + { + "tool": "mypy", + "path": "services/schema_sanitizer.py", + "code": "assignment", + "message": "Incompatible types in assignment (expression has type \"dict[Any, dict[str, Any]]\", target has type \"str\")", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/schema_sanitizer.py", + "code": "assignment", + "message": "Incompatible types in assignment (expression has type \"dict[str, Any]\", target has type \"str\")", + "count": 3 + }, + { + "tool": "mypy", + "path": "services/schema_sanitizer.py", + "code": "assignment", + "message": "Incompatible types in assignment (expression has type \"dict[str, str]\", target has type \"str\")", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/schema_sanitizer.py", + "code": "assignment", + "message": "Incompatible types in assignment (expression has type \"list[Any]\", target has type \"str\")", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/schema_sanitizer.py", + "code": "assignment", + "message": "Incompatible types in assignment (expression has type \"list[dict[str, Any]]\", target has type \"str\")", + "count": 2 + }, + { + "tool": "mypy", + "path": "services/schema_sanitizer.py", + "code": "assignment", + "message": "Incompatible types in assignment (expression has type \"list[str]\", target has type \"str\")", + "count": 2 + }, + { + "tool": "mypy", + "path": "services/schema_sanitizer.py", + "code": "index", + "message": "Invalid index type \"str\" for \"str\"; expected type \"SupportsIndex | slice[SupportsIndex | None, SupportsIndex | None, SupportsIndex | None]\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/schema_sanitizer.py", + "code": "index", + "message": "Unsupported target for indexed assignment (\"str\")", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/secret_providers.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 4 + }, + { + "tool": "mypy", + "path": "services/secret_store.py", + "code": "no-redef", + "message": "Name \"get_state_dir\" already defined (possibly by an import)", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/secret_store.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/secrets_encryption.py", + "code": "no-any-return", + "message": "Returning Any from function declared to return \"bytes\"", + "count": 3 + }, + { + "tool": "mypy", + "path": "services/secrets_encryption.py", + "code": "no-any-return", + "message": "Returning Any from function declared to return \"dict[str, str]\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/secrets_encryption.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 4 + }, + { + "tool": "mypy", + "path": "services/secrets_encryption.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore[assignment, misc]\" comment", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/security_doctor_connector_checks.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/security_doctor_endpoint_checks.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 2 + }, + { + "tool": "mypy", + "path": "services/security_doctor_runner.py", + "code": "assignment", + "message": "Incompatible types in assignment (expression has type \"SecurityCheckResult\", variable has type \"Callable[[SecurityReport], None]\")", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/security_doctor_runner.py", + "code": "attr-defined", + "message": "\"Callable[[SecurityReport], None]\" has no attribute \"message\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/security_doctor_runner.py", + "code": "attr-defined", + "message": "\"Callable[[SecurityReport], None]\" has no attribute \"name\"", + "count": 2 + }, + { + "tool": "mypy", + "path": "services/security_doctor_runner.py", + "code": "attr-defined", + "message": "\"Callable[[SecurityReport], None]\" has no attribute \"severity\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/security_doctor_runtime_checks.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 5 + }, + { + "tool": "mypy", + "path": "services/security_gate.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 2 + }, + { + "tool": "mypy", + "path": "services/settings_schema.py", + "code": "assignment", + "message": "Incompatible types in assignment (expression has type \"float\", variable has type \"int\")", + "count": 3 + }, + { + "tool": "mypy", + "path": "services/sidecar/auth.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 4 + }, + { + "tool": "mypy", + "path": "services/sidecar/bridge_client.py", + "code": "assignment", + "message": "Incompatible default for parameter \"details\" (default has type \"None\", parameter has type \"dict[Any, Any]\")", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/sidecar/bridge_client.py", + "code": "index", + "message": "Value of type \"object\" is not indexable", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/sidecar/bridge_client.py", + "code": "no-any-return", + "message": "Returning Any from function declared to return \"bool\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/sidecar/bridge_client.py", + "code": "no-any-return", + "message": "Returning Any from function declared to return \"list[Any]\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/sidecar/bridge_client.py", + "code": "union-attr", + "message": "Item \"None\" of \"Any | None\" has no attribute \"get\"", + "count": 2 + }, + { + "tool": "mypy", + "path": "services/sidecar/bridge_client.py", + "code": "union-attr", + "message": "Item \"None\" of \"Any | None\" has no attribute \"post\"", + "count": 3 + }, + { + "tool": "mypy", + "path": "services/sidecar/runtime.py", + "code": "arg-type", + "message": "Argument 1 to \"submit_job\" of \"OpenClawClient\" has incompatible type \"Any | None\"; expected \"str\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/sidecar/runtime.py", + "code": "arg-type", + "message": "Argument 1 to \"submit_result\" of \"BridgeClient\" has incompatible type \"Any | None\"; expected \"str\"", + "count": 4 + }, + { + "tool": "mypy", + "path": "services/sidecar/runtime.py", + "code": "attr-defined", + "message": "\"OpenClawClient\" has no attribute \"stop\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/surface_guard.py", + "code": "name-defined", + "message": "Name \"web.Request\" is not defined", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/surface_guard.py", + "code": "name-defined", + "message": "Name \"web.Response\" is not defined", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/surface_guard.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/templates.py", + "code": "assignment", + "message": "Incompatible types in assignment (expression has type \"TemplateService\", variable has type \"None\")", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/templates.py", + "code": "no-any-return", + "message": "Returning Any from function declared to return \"dict[str, Any]\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/templates.py", + "code": "return-value", + "message": "Incompatible return value type (got \"None\", expected \"TemplateService\")", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/threat_intel_gate.py", + "code": "no-any-return", + "message": "Returning Any from function declared to return \"ScanResult\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/tool_runner.py", + "code": "arg-type", + "message": "Argument 1 to \"exists\" has incompatible type \"str | None\"; expected \"int | str | bytes | PathLike[str] | PathLike[bytes]\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/tool_runner.py", + "code": "arg-type", + "message": "Argument 1 to \"open\" has incompatible type \"str | None\"; expected \"int | str | bytes | PathLike[str] | PathLike[bytes]\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/tool_runner.py", + "code": "assignment", + "message": "Incompatible types in assignment (expression has type \"None\", variable has type \"Callable[[], str]\")", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/tool_runner.py", + "code": "truthy-function", + "message": "Function \"get_state_dir\" could always be true in boolean context", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/tool_runner.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 3 + }, + { + "tool": "mypy", + "path": "services/transform_worker.py", + "code": "assignment", + "message": "Incompatible types in assignment (expression has type \"def _deny_network(*args: Any, **kwargs: Any) -> Any\", variable has type \"type[socket]\")", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/transform_worker.py", + "code": "misc", + "message": "Cannot assign to a type", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/webhook_auth.py", + "code": "assignment", + "message": "Incompatible import of \"IdempotencyStore\" (imported name has type \"type[IdempotencyStore]\", local name has type \"object\")", + "count": 2 + }, + { + "tool": "mypy", + "path": "services/workflow_portability.py", + "code": "arg-type", + "message": "Argument 1 to \"add\" of \"set\" has incompatible type \"tuple[str | None, str]\"; expected \"tuple[str, str]\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/workflow_portability.py", + "code": "arg-type", + "message": "Argument 1 to \"get\" of \"dict\" has incompatible type \"str | None\"; expected \"str\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/workflow_portability.py", + "code": "arg-type", + "message": "Argument 1 to \"int\" has incompatible type \"Any | None\"; expected \"str | Buffer | SupportsInt | SupportsIndex | SupportsTrunc\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/workflow_portability.py", + "code": "arg-type", + "message": "Argument 1 to \"walk\" has incompatible type \"Any | list[Any] | None\"; expected \"list[Any]\"", + "count": 1 + }, + { + "tool": "mypy", + "path": "services/workflow_portability.py", + "code": "unused-ignore", + "message": "Unused \"type: ignore\" comment", + "count": 1 + }, + { + "tool": "ruff", + "path": "__init__.py", + "code": "N999", + "message": "Invalid module name: 'ComfyUI-OpenClaw'", + "count": 1 + }, + { + "tool": "ruff", + "path": "api/__init__.py", + "code": "N999", + "message": "Invalid module name: 'ComfyUI-OpenClaw'", + "count": 1 + }, + { + "tool": "ruff", + "path": "api/approvals.py", + "code": "F401", + "message": "`typing.Callable` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "api/approvals.py", + "code": "SIM105", + "message": "Use `contextlib.suppress(RuntimeError)` instead of `try`-`except`-`pass`", + "count": 2 + }, + { + "tool": "ruff", + "path": "api/approvals.py", + "code": "UP035", + "message": "Import from `collections.abc` instead: `Callable`", + "count": 1 + }, + { + "tool": "ruff", + "path": "api/approvals.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 1 + }, + { + "tool": "ruff", + "path": "api/assist.py", + "code": "F841", + "message": "Local variable `e` is assigned to but never used", + "count": 3 + }, + { + "tool": "ruff", + "path": "api/assist.py", + "code": "RUF059", + "message": "Unpacked variable `err_msg` is never used", + "count": 1 + }, + { + "tool": "ruff", + "path": "api/assist.py", + "code": "SIM105", + "message": "Use `contextlib.suppress(RuntimeError)` instead of `try`-`except`-`pass`", + "count": 1 + }, + { + "tool": "ruff", + "path": "api/assist.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 7 + }, + { + "tool": "ruff", + "path": "api/assist.py", + "code": "UP012", + "message": "Unnecessary UTF-8 `encoding` argument to `encode`", + "count": 1 + }, + { + "tool": "ruff", + "path": "api/assist.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "api/assist.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 7 + }, + { + "tool": "ruff", + "path": "api/bridge.py", + "code": "F401", + "message": "`asyncio` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "api/bridge.py", + "code": "RUF059", + "message": "Unpacked variable `device_id` is never used", + "count": 1 + }, + { + "tool": "ruff", + "path": "api/bridge.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "api/bridge.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "api/bridge.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 7 + }, + { + "tool": "ruff", + "path": "api/checkpoints_handler.py", + "code": "F401", + "message": "`json` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "api/checkpoints_handler.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "api/checkpoints_handler.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "api/config.py", + "code": "F401", + "message": "`services.provider_errors.ProviderHTTPError` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "api/config.py", + "code": "RUF010", + "message": "Use explicit conversion flag", + "count": 1 + }, + { + "tool": "ruff", + "path": "api/connector_contracts.py", + "code": "I001", + "message": "Import block is un-sorted or un-formatted", + "count": 1 + }, + { + "tool": "ruff", + "path": "api/connector_contracts.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 1 + }, + { + "tool": "ruff", + "path": "api/errors.py", + "code": "F401", + "message": "`json` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "api/errors.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 3 + }, + { + "tool": "ruff", + "path": "api/errors.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "api/errors.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 2 + }, + { + "tool": "ruff", + "path": "api/events.py", + "code": "F401", + "message": "`json` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "api/events.py", + "code": "F401", + "message": "`typing.Dict` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "api/events.py", + "code": "F841", + "message": "Local variable `store` is assigned to but never used", + "count": 1 + }, + { + "tool": "ruff", + "path": "api/events.py", + "code": "SIM105", + "message": "Use `contextlib.suppress(ValueError)` instead of `try`-`except`-`pass`", + "count": 1 + }, + { + "tool": "ruff", + "path": "api/events.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "api/model_manager.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "api/model_manager.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "api/model_manager.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 3 + }, + { + "tool": "ruff", + "path": "api/packs.py", + "code": "F401", + "message": "`shutil` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "api/packs.py", + "code": "F841", + "message": "Local variable `filename` is assigned to but never used", + "count": 1 + }, + { + "tool": "ruff", + "path": "api/packs.py", + "code": "SIM105", + "message": "Use `contextlib.suppress(Exception)` instead of `try`-`except`-`pass`", + "count": 1 + }, + { + "tool": "ruff", + "path": "api/packs.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 1 + }, + { + "tool": "ruff", + "path": "api/pnginfo.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 1 + }, + { + "tool": "ruff", + "path": "api/preflight_handler.py", + "code": "C414", + "message": "Unnecessary `list()` call within `sorted()`", + "count": 1 + }, + { + "tool": "ruff", + "path": "api/preflight_handler.py", + "code": "F401", + "message": "`typing.Any` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "api/preflight_handler.py", + "code": "F401", + "message": "`typing.Dict` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "api/preflight_handler.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "api/presets.py", + "code": "F401", + "message": "`typing.Optional` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "api/presets.py", + "code": "RUF010", + "message": "Use explicit conversion flag", + "count": 2 + }, + { + "tool": "ruff", + "path": "api/presets.py", + "code": "SIM105", + "message": "Use `contextlib.suppress(RuntimeError)` instead of `try`-`except`-`pass`", + "count": 2 + }, + { + "tool": "ruff", + "path": "api/rewrite_recipes.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 2 + }, + { + "tool": "ruff", + "path": "api/rewrite_recipes.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "api/route_registrars.py", + "code": "UP035", + "message": "Import from `collections.abc` instead: `Iterable`", + "count": 1 + }, + { + "tool": "ruff", + "path": "api/routes.py", + "code": "F401", + "message": "`json` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "api/routes.py", + "code": "F401", + "message": "`services.access_control.is_loopback` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "api/routes.py", + "code": "F401", + "message": "`sys` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "api/routes.py", + "code": "N806", + "message": "Variable `MAX_BYTES` in function should be lowercase", + "count": 1 + }, + { + "tool": "ruff", + "path": "api/routes.py", + "code": "SIM105", + "message": "Use `contextlib.suppress(ValueError)` instead of `try`-`except`-`pass`", + "count": 1 + }, + { + "tool": "ruff", + "path": "api/routes.py", + "code": "SIM114", + "message": "Combine `if` branches using logical `or` operator", + "count": 1 + }, + { + "tool": "ruff", + "path": "api/schedules.py", + "code": "F401", + "message": "`typing.Optional` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "api/schedules.py", + "code": "SIM105", + "message": "Use `contextlib.suppress(RuntimeError)` instead of `try`-`except`-`pass`", + "count": 2 + }, + { + "tool": "ruff", + "path": "api/secrets.py", + "code": "I001", + "message": "Import block is un-sorted or un-formatted", + "count": 1 + }, + { + "tool": "ruff", + "path": "api/secrets.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 3 + }, + { + "tool": "ruff", + "path": "api/triggers.py", + "code": "SIM105", + "message": "Use `contextlib.suppress(RuntimeError)` instead of `try`-`except`-`pass`", + "count": 2 + }, + { + "tool": "ruff", + "path": "api/triggers.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 2 + }, + { + "tool": "ruff", + "path": "api/webhook.py", + "code": "F401", + "message": "`logging` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "api/webhook.py", + "code": "F541", + "message": "f-string without any placeholders", + "count": 1 + }, + { + "tool": "ruff", + "path": "api/webhook.py", + "code": "F841", + "message": "Local variable `e` is assigned to but never used", + "count": 1 + }, + { + "tool": "ruff", + "path": "api/webhook_submit.py", + "code": "SIM105", + "message": "Use `contextlib.suppress(Exception)` instead of `try`-`except`-`pass`", + "count": 1 + }, + { + "tool": "ruff", + "path": "api/webhook_validate.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 2 + }, + { + "tool": "ruff", + "path": "api/webhook_validate.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 2 + }, + { + "tool": "ruff", + "path": "api/webhook_validate.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "api/webhook_validate.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "config.py", + "code": "UP015", + "message": "Unnecessary mode argument", + "count": 1 + }, + { + "tool": "ruff", + "path": "config.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 6 + }, + { + "tool": "ruff", + "path": "connector/__init__.py", + "code": "N999", + "message": "Invalid module name: 'ComfyUI-OpenClaw'", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/__main__.py", + "code": "N999", + "message": "Invalid module name: 'ComfyUI-OpenClaw'", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/__main__.py", + "code": "SIM105", + "message": "Use `contextlib.suppress(KeyboardInterrupt)` instead of `try`-`except`-`pass`", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/channels/__init__.py", + "code": "N999", + "message": "Invalid module name: 'ComfyUI-OpenClaw'", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/channels/kakaotalk.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 2 + }, + { + "tool": "ruff", + "path": "connector/channels/kakaotalk.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 2 + }, + { + "tool": "ruff", + "path": "connector/channels/kakaotalk.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/channels/kakaotalk.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/channels/kakaotalk.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 3 + }, + { + "tool": "ruff", + "path": "connector/command_firewall.py", + "code": "RUF010", + "message": "Use explicit conversion flag", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/command_firewall.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 2 + }, + { + "tool": "ruff", + "path": "connector/command_firewall.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/command_firewall.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/command_firewall.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/config.py", + "code": "F401", + "message": "`sys` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/config.py", + "code": "SIM102", + "message": "Use a single `if` statement instead of nested `if` statements", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/config.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 2 + }, + { + "tool": "ruff", + "path": "connector/config.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 15 + }, + { + "tool": "ruff", + "path": "connector/config.py", + "code": "UP006", + "message": "Use `set` instead of `Set` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/config.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/config.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/config.py", + "code": "UP035", + "message": "`typing.Set` is deprecated, use `set` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/config.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 32 + }, + { + "tool": "ruff", + "path": "connector/contract.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 3 + }, + { + "tool": "ruff", + "path": "connector/contract.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 2 + }, + { + "tool": "ruff", + "path": "connector/contract.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/contract.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/contract.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 3 + }, + { + "tool": "ruff", + "path": "connector/llm_client.py", + "code": "F401", + "message": "`typing.Optional` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/llm_client.py", + "code": "SIM102", + "message": "Use a single `if` statement instead of nested `if` statements", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/llm_client.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/llm_client.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/llm_client.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/llm_client.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/media_store.py", + "code": "UP006", + "message": "Use `tuple` instead of `Tuple` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/media_store.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/media_store.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 4 + }, + { + "tool": "ruff", + "path": "connector/openclaw_client.py", + "code": "E722", + "message": "Do not use bare `except`", + "count": 2 + }, + { + "tool": "ruff", + "path": "connector/openclaw_client.py", + "code": "F401", + "message": "`json` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/openclaw_client.py", + "code": "F541", + "message": "f-string without any placeholders", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/openclaw_client.py", + "code": "RUF013", + "message": "PEP 484 prohibits implicit `Optional`", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/openclaw_client.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 2 + }, + { + "tool": "ruff", + "path": "connector/platforms/__init__.py", + "code": "N999", + "message": "Invalid module name: 'ComfyUI-OpenClaw'", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/platforms/discord_gateway.py", + "code": "E722", + "message": "Do not use bare `except`", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/platforms/discord_gateway.py", + "code": "F401", + "message": "`aiohttp` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/platforms/discord_gateway.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 3 + }, + { + "tool": "ruff", + "path": "connector/platforms/feishu_installation_manager.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 8 + }, + { + "tool": "ruff", + "path": "connector/platforms/feishu_installation_manager.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 3 + }, + { + "tool": "ruff", + "path": "connector/platforms/feishu_installation_manager.py", + "code": "UP006", + "message": "Use `tuple` instead of `Tuple` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/platforms/feishu_installation_manager.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/platforms/feishu_installation_manager.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/platforms/feishu_installation_manager.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/platforms/feishu_installation_manager.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 7 + }, + { + "tool": "ruff", + "path": "connector/platforms/feishu_long_connection.py", + "code": "SIM105", + "message": "Use `contextlib.suppress(asyncio.CancelledError)` instead of `try`-`except`-`pass`", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/platforms/feishu_long_connection.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 2 + }, + { + "tool": "ruff", + "path": "connector/platforms/feishu_webhook.py", + "code": "F401", + "message": "`asyncio` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/platforms/feishu_webhook.py", + "code": "F821", + "message": "Undefined name `InstallationResolution`", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/platforms/feishu_webhook.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 34 + }, + { + "tool": "ruff", + "path": "connector/platforms/feishu_webhook.py", + "code": "UP006", + "message": "Use `tuple` instead of `Tuple` for type annotation", + "count": 4 + }, + { + "tool": "ruff", + "path": "connector/platforms/feishu_webhook.py", + "code": "UP012", + "message": "Unnecessary UTF-8 `encoding` argument to `encode`", + "count": 6 + }, + { + "tool": "ruff", + "path": "connector/platforms/feishu_webhook.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/platforms/feishu_webhook.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/platforms/feishu_webhook.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 12 + }, + { + "tool": "ruff", + "path": "connector/platforms/kakao_webhook.py", + "code": "F401", + "message": "`..contract.CommandResponse` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/platforms/kakao_webhook.py", + "code": "F841", + "message": "Local variable `files` is assigned to but never used", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/platforms/kakao_webhook.py", + "code": "F841", + "message": "Local variable `image_url` is assigned to but never used", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/platforms/kakao_webhook.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 2 + }, + { + "tool": "ruff", + "path": "connector/platforms/line_webhook.py", + "code": "F401", + "message": "`..contract.CommandResponse` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/platforms/line_webhook.py", + "code": "RUF059", + "message": "Unpacked variable `aiohttp` is never used", + "count": 2 + }, + { + "tool": "ruff", + "path": "connector/platforms/line_webhook.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 4 + }, + { + "tool": "ruff", + "path": "connector/platforms/slack_installation_manager.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 12 + }, + { + "tool": "ruff", + "path": "connector/platforms/slack_installation_manager.py", + "code": "UP006", + "message": "Use `tuple` instead of `Tuple` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/platforms/slack_installation_manager.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/platforms/slack_installation_manager.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/platforms/slack_installation_manager.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 6 + }, + { + "tool": "ruff", + "path": "connector/platforms/slack_socket_mode.py", + "code": "SIM105", + "message": "Use `contextlib.suppress(asyncio.CancelledError)` instead of `try`-`except`-`pass`", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/platforms/slack_socket_mode.py", + "code": "SIM117", + "message": "Use a single `with` statement with multiple contexts instead of nested `with` statements", + "count": 2 + }, + { + "tool": "ruff", + "path": "connector/platforms/slack_socket_mode.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 2 + }, + { + "tool": "ruff", + "path": "connector/platforms/slack_webhook.py", + "code": "F401", + "message": "`..contract.CommandResponse` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/platforms/slack_webhook.py", + "code": "SIM102", + "message": "Use a single `if` statement instead of nested `if` statements", + "count": 2 + }, + { + "tool": "ruff", + "path": "connector/platforms/slack_webhook.py", + "code": "SIM117", + "message": "Use a single `with` statement with multiple contexts instead of nested `with` statements", + "count": 3 + }, + { + "tool": "ruff", + "path": "connector/platforms/slack_webhook.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 18 + }, + { + "tool": "ruff", + "path": "connector/platforms/slack_webhook.py", + "code": "UP006", + "message": "Use `tuple` instead of `Tuple` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/platforms/slack_webhook.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/platforms/slack_webhook.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/platforms/slack_webhook.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 11 + }, + { + "tool": "ruff", + "path": "connector/platforms/telegram_polling.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 7 + }, + { + "tool": "ruff", + "path": "connector/platforms/wechat_webhook.py", + "code": "F401", + "message": "`..contract.CommandResponse` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/platforms/wechat_webhook.py", + "code": "F401", + "message": "`json` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/platforms/wechat_webhook.py", + "code": "N818", + "message": "Exception name `XMLBudgetExceeded` should be named with an Error suffix", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/platforms/wechat_webhook.py", + "code": "RUF006", + "message": "Store a reference to the return value of `asyncio.create_task`", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/platforms/wechat_webhook.py", + "code": "SIM102", + "message": "Use a single `if` statement instead of nested `if` statements", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/platforms/wechat_webhook.py", + "code": "SIM108", + "message": "Use ternary operator `clean_ver = ver_str[6:] if ver_str.lower().startswith(\"expat_\") else ver_str` instead of `if`-`else`-block", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/platforms/wechat_webhook.py", + "code": "SIM113", + "message": "Use `enumerate()` for index variable `field_count` in `for` loop", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/platforms/wechat_webhook.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 7 + }, + { + "tool": "ruff", + "path": "connector/platforms/whatsapp_webhook.py", + "code": "F401", + "message": "`..contract.CommandResponse` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/platforms/whatsapp_webhook.py", + "code": "F841", + "message": "Local variable `phone_number_id` is assigned to but never used", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/platforms/whatsapp_webhook.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 4 + }, + { + "tool": "ruff", + "path": "connector/rate_limiter.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 2 + }, + { + "tool": "ruff", + "path": "connector/rate_limiter.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/reply_visibility.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 3 + }, + { + "tool": "ruff", + "path": "connector/reply_visibility.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/reply_visibility.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 2 + }, + { + "tool": "ruff", + "path": "connector/results_poller.py", + "code": "B007", + "message": "Loop control variable `node_id` not used within loop body", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/results_poller.py", + "code": "RUF006", + "message": "Store a reference to the return value of `asyncio.create_task`", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/results_poller.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 7 + }, + { + "tool": "ruff", + "path": "connector/results_poller.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/results_poller.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 6 + }, + { + "tool": "ruff", + "path": "connector/router.py", + "code": "E731", + "message": "Do not assign a `lambda` expression, use a `def`", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/router.py", + "code": "F841", + "message": "Local variable `requires_admin` is assigned to but never used", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/router.py", + "code": "RUF010", + "message": "Use explicit conversion flag", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/router.py", + "code": "SIM102", + "message": "Use a single `if` statement instead of nested `if` statements", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/router.py", + "code": "SIM103", + "message": "Return the condition `channel_id in self.config.discord_allowed_channels` directly", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/router.py", + "code": "SIM103", + "message": "Return the condition `channel_id in self.config.feishu_allowed_chats` directly", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/router.py", + "code": "SIM103", + "message": "Return the condition `channel_id in self.config.line_allowed_groups` directly", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/router.py", + "code": "SIM103", + "message": "Return the condition `channel_id in self.config.slack_allowed_channels` directly", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/router.py", + "code": "SIM103", + "message": "Return the condition `sender_id in self.config.kakao_allowed_users` directly", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/router.py", + "code": "SIM103", + "message": "Return the condition `sender_id in self.config.wechat_allowed_users` directly", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/router.py", + "code": "SIM103", + "message": "Return the condition `sender_id in self.config.whatsapp_allowed_users` directly", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/router.py", + "code": "SIM103", + "message": "Return the condition directly", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/router.py", + "code": "SIM108", + "message": "Use ternary operator `canonical_cmd = aliases[0] if isinstance(aliases, tuple) else aliases` instead of `if`-`else`-block", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/router.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 8 + }, + { + "tool": "ruff", + "path": "connector/router.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 17 + }, + { + "tool": "ruff", + "path": "connector/router.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/router.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/router.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 2 + }, + { + "tool": "ruff", + "path": "connector/security_profile.py", + "code": "F401", + "message": "`.transport_contract.CallbackError` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/security_profile.py", + "code": "F401", + "message": "`.transport_contract.CallbackRecord` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/security_profile.py", + "code": "F401", + "message": "`.transport_contract.TokenError` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/security_profile.py", + "code": "F401", + "message": "`.transport_contract.TokenResult` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/security_profile.py", + "code": "F401", + "message": "`.transport_contract.TokenSource` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/security_profile.py", + "code": "F401", + "message": "`typing.Set` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/security_profile.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 8 + }, + { + "tool": "ruff", + "path": "connector/security_profile.py", + "code": "UP006", + "message": "Use `frozenset` instead of `FrozenSet` for type annotation", + "count": 2 + }, + { + "tool": "ruff", + "path": "connector/security_profile.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/security_profile.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/security_profile.py", + "code": "UP035", + "message": "`typing.FrozenSet` is deprecated, use `frozenset` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/security_profile.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/security_profile.py", + "code": "UP035", + "message": "`typing.Set` is deprecated, use `set` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/security_profile.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 14 + }, + { + "tool": "ruff", + "path": "connector/semantic_guard.py", + "code": "RUF012", + "message": "Mutable default value for class attribute", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/semantic_guard.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 3 + }, + { + "tool": "ruff", + "path": "connector/semantic_guard.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 2 + }, + { + "tool": "ruff", + "path": "connector/semantic_guard.py", + "code": "UP006", + "message": "Use `tuple` instead of `Tuple` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/semantic_guard.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/semantic_guard.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/semantic_guard.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/state.py", + "code": "F401", + "message": "`typing.List` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/state.py", + "code": "RUF013", + "message": "PEP 484 prohibits implicit `Optional`", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/state.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/state.py", + "code": "UP006", + "message": "Use `set` instead of `Set` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/state.py", + "code": "UP015", + "message": "Unnecessary mode argument", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/state.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/state.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/state.py", + "code": "UP035", + "message": "`typing.Set` is deprecated, use `set` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/transport_contract.py", + "code": "F541", + "message": "f-string without any placeholders", + "count": 2 + }, + { + "tool": "ruff", + "path": "connector/transport_contract.py", + "code": "SIM102", + "message": "Use a single `if` statement instead of nested `if` statements", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/transport_contract.py", + "code": "SIM103", + "message": "Return the negated condition directly", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/transport_contract.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 20 + }, + { + "tool": "ruff", + "path": "connector/transport_contract.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 5 + }, + { + "tool": "ruff", + "path": "connector/transport_contract.py", + "code": "UP035", + "message": "Import from `collections.abc` instead: `Sequence`", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/transport_contract.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/transport_contract.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "connector/transport_contract.py", + "code": "UP037", + "message": "Remove quotes from type annotation", + "count": 2 + }, + { + "tool": "ruff", + "path": "connector/transport_contract.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 20 + }, + { + "tool": "ruff", + "path": "models/__init__.py", + "code": "N999", + "message": "Invalid module name: 'ComfyUI-OpenClaw'", + "count": 1 + }, + { + "tool": "ruff", + "path": "models/schemas.py", + "code": "F401", + "message": "`services.request_contracts.MAX_BODY_SIZE` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "models/schemas.py", + "code": "F401", + "message": "`typing.List` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "models/schemas.py", + "code": "F401", + "message": "`typing.Union` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "models/schemas.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 10 + }, + { + "tool": "ruff", + "path": "models/schemas.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "models/schemas.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "models/schemas.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 6 + }, + { + "tool": "ruff", + "path": "nodes/__init__.py", + "code": "N999", + "message": "Invalid module name: 'ComfyUI-OpenClaw'", + "count": 1 + }, + { + "tool": "ruff", + "path": "nodes/batch_variants.py", + "code": "F401", + "message": "`typing.Any` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "nodes/batch_variants.py", + "code": "F401", + "message": "`typing.Dict` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "nodes/batch_variants.py", + "code": "N802", + "message": "Function name `INPUT_TYPES` should be lowercase", + "count": 1 + }, + { + "tool": "ruff", + "path": "nodes/batch_variants.py", + "code": "RUF046", + "message": "Value being cast to `int` is already an integer", + "count": 2 + }, + { + "tool": "ruff", + "path": "nodes/batch_variants.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 3 + }, + { + "tool": "ruff", + "path": "nodes/batch_variants.py", + "code": "UP006", + "message": "Use `tuple` instead of `Tuple` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "nodes/batch_variants.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "nodes/batch_variants.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "nodes/batch_variants.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "nodes/image_to_prompt.py", + "code": "N802", + "message": "Function name `INPUT_TYPES` should be lowercase", + "count": 1 + }, + { + "tool": "ruff", + "path": "nodes/image_to_prompt.py", + "code": "UP006", + "message": "Use `tuple` instead of `Tuple` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "nodes/image_to_prompt.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "nodes/portability_contract.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 4 + }, + { + "tool": "ruff", + "path": "nodes/portability_contract.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "nodes/prompt_planner.py", + "code": "N802", + "message": "Function name `INPUT_TYPES` should be lowercase", + "count": 1 + }, + { + "tool": "ruff", + "path": "nodes/prompt_planner.py", + "code": "UP006", + "message": "Use `tuple` instead of `Tuple` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "nodes/prompt_planner.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "nodes/prompt_refiner.py", + "code": "N802", + "message": "Function name `INPUT_TYPES` should be lowercase", + "count": 1 + }, + { + "tool": "ruff", + "path": "nodes/prompt_refiner.py", + "code": "RUF010", + "message": "Use explicit conversion flag", + "count": 1 + }, + { + "tool": "ruff", + "path": "nodes/prompt_refiner.py", + "code": "UP006", + "message": "Use `tuple` instead of `Tuple` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "nodes/prompt_refiner.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/check_deployment_profile.py", + "code": "E402", + "message": "Module level import not at top of file", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/check_openapi_sync.py", + "code": "UP022", + "message": "Prefer `capture_output` over sending `stdout` and `stderr` to `PIPE`", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/check_openapi_sync.py", + "code": "UP035", + "message": "Import from `collections.abc` instead: `Callable`, `Iterable`", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/check_supply_chain_hardening.py", + "code": "F401", + "message": "`sys` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/check_supply_chain_hardening.py", + "code": "SIM102", + "message": "Use a single `if` statement instead of nested `if` statements", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/check_supply_chain_hardening.py", + "code": "UP035", + "message": "Import from `collections.abc` instead: `Iterable`", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/devtools/debug_s35_import.py", + "code": "E402", + "message": "Module level import not at top of file", + "count": 2 + }, + { + "tool": "ruff", + "path": "scripts/devtools/verify_s30_doctor.py", + "code": "E402", + "message": "Module level import not at top of file", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/generate_provenance.py", + "code": "F401", + "message": "`typing.Dict` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/generate_provenance.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/lint_implementation_record.py", + "code": "F401", + "message": "`typing.Iterable` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/lint_implementation_record.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 7 + }, + { + "tool": "ruff", + "path": "scripts/lint_implementation_record.py", + "code": "UP006", + "message": "Use `tuple` instead of `Tuple` for type annotation", + "count": 2 + }, + { + "tool": "ruff", + "path": "scripts/lint_implementation_record.py", + "code": "UP035", + "message": "Import from `collections.abc` instead: `Iterable`, `Sequence`", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/lint_implementation_record.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/lint_implementation_record.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/openclaw_smoke_import.py", + "code": "F541", + "message": "f-string without any placeholders", + "count": 8 + }, + { + "tool": "ruff", + "path": "scripts/operator_doctor.py", + "code": "E402", + "message": "Module level import not at top of file", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/precommit_block_sensitive_files.py", + "code": "UP022", + "message": "Prefer `capture_output` over sending `stdout` and `stderr` to `PIPE`", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/quality_governance_common.py", + "code": "B905", + "message": "`zip()` without an explicit `strict=` parameter", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/quality_governance_common.py", + "code": "RUF007", + "message": "Prefer `itertools.pairwise()` over `zip()` when iterating over successive pairs", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/quality_governance_common.py", + "code": "UP035", + "message": "Import from `collections.abc` instead: `Iterable`", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/registry_publish_guard.py", + "code": "F401", + "message": "`sys` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/run_adversarial_gate.py", + "code": "F401", + "message": "`test_r111_fuzz_harness._deterministic_getaddrinfo` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/run_adversarial_gate.py", + "code": "F401", + "message": "`unittest.mock.patch` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/run_adversarial_gate.py", + "code": "SIM105", + "message": "Use `contextlib.suppress(PathTraversalError, ValueError)` instead of `try`-`except`-`pass`", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/run_adversarial_gate.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 9 + }, + { + "tool": "ruff", + "path": "scripts/run_adversarial_gate.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 16 + }, + { + "tool": "ruff", + "path": "scripts/run_adversarial_gate.py", + "code": "UP006", + "message": "Use `set` instead of `Set` for type annotation", + "count": 4 + }, + { + "tool": "ruff", + "path": "scripts/run_adversarial_gate.py", + "code": "UP006", + "message": "Use `tuple` instead of `Tuple` for type annotation", + "count": 5 + }, + { + "tool": "ruff", + "path": "scripts/run_adversarial_gate.py", + "code": "UP015", + "message": "Unnecessary mode argument", + "count": 2 + }, + { + "tool": "ruff", + "path": "scripts/run_adversarial_gate.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/run_adversarial_gate.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/run_adversarial_gate.py", + "code": "UP035", + "message": "`typing.Set` is deprecated, use `set` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/run_adversarial_gate.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/run_adversarial_gate.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 10 + }, + { + "tool": "ruff", + "path": "scripts/run_mutation_test.py", + "code": "F401", + "message": "`typing.Any` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/run_mutation_test.py", + "code": "F401", + "message": "`typing.Dict` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/run_mutation_test.py", + "code": "F401", + "message": "`typing.List` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/run_mutation_test.py", + "code": "F401", + "message": "`typing.Optional` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/run_mutation_test.py", + "code": "F401", + "message": "`typing.Tuple` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/run_mutation_test.py", + "code": "F401", + "message": "`typing.Union` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/run_mutation_test.py", + "code": "SIM105", + "message": "Use `contextlib.suppress(OSError)` instead of `try`-`except`-`pass`", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/run_mutation_test.py", + "code": "UP015", + "message": "Unnecessary mode argument", + "count": 2 + }, + { + "tool": "ruff", + "path": "scripts/run_mutation_test.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/run_mutation_test.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/run_mutation_test.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/run_unittests.py", + "code": "B007", + "message": "Loop control variable `test` not used within loop body", + "count": 2 + }, + { + "tool": "ruff", + "path": "scripts/run_unittests.py", + "code": "F401", + "message": "`os` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/run_unittests.py", + "code": "SIM108", + "message": "Use ternary operator `test_id = test_case.id() if hasattr(test_case, \"id\") else str(test_case)` instead of `if`-`else`-block", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/run_unittests.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/run_unittests.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 9 + }, + { + "tool": "ruff", + "path": "scripts/run_unittests.py", + "code": "UP006", + "message": "Use `tuple` instead of `Tuple` for type annotation", + "count": 4 + }, + { + "tool": "ruff", + "path": "scripts/run_unittests.py", + "code": "UP035", + "message": "Import from `collections.abc` instead: `Iterable`", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/run_unittests.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/run_unittests.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/run_unittests.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/start_sidecar.py", + "code": "SIM105", + "message": "Use `contextlib.suppress(KeyboardInterrupt)` instead of `try`-`except`-`pass`", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/sync_split.py", + "code": "C416", + "message": "Unnecessary dict comprehension (rewrite using `dict()`)", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/sync_split.py", + "code": "I001", + "message": "Import block is un-sorted or un-formatted", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/sync_split.py", + "code": "UP035", + "message": "Import from `collections.abc` instead: `Iterable`", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/verify_exception_boundary_policy.py", + "code": "UP035", + "message": "Import from `collections.abc` instead: `Iterable`", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/verify_provenance.py", + "code": "UP015", + "message": "Unnecessary mode argument", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/verify_quality_governance.py", + "code": "F401", + "message": "`sys` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/verify_quality_governance.py", + "code": "SIM102", + "message": "Use a single `if` statement instead of nested `if` statements", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/verify_quality_governance.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 3 + }, + { + "tool": "ruff", + "path": "scripts/verify_quality_governance.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/verify_quality_governance.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 4 + }, + { + "tool": "ruff", + "path": "scripts/verify_test_debt_governance.py", + "code": "F401", + "message": "`typing.Iterable` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/verify_test_debt_governance.py", + "code": "F401", + "message": "`typing.Optional` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/verify_test_debt_governance.py", + "code": "SIM118", + "message": "Use `key in dict` instead of `key in dict.keys()`", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/verify_test_debt_governance.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/verify_test_debt_governance.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 9 + }, + { + "tool": "ruff", + "path": "scripts/verify_test_debt_governance.py", + "code": "UP006", + "message": "Use `tuple` instead of `Tuple` for type annotation", + "count": 2 + }, + { + "tool": "ruff", + "path": "scripts/verify_test_debt_governance.py", + "code": "UP035", + "message": "Import from `collections.abc` instead: `Iterable`", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/verify_test_debt_governance.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/verify_test_debt_governance.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "scripts/verify_test_debt_governance.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/__init__.py", + "code": "N999", + "message": "Invalid module name: 'ComfyUI-OpenClaw'", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/access_control.py", + "code": "RUF012", + "message": "Mutable default value for class attribute", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/access_control.py", + "code": "SIM102", + "message": "Use a single `if` statement instead of nested `if` statements", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/access_control.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/access_control.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/access_control.py", + "code": "UP006", + "message": "Use `set` instead of `Set` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/access_control.py", + "code": "UP006", + "message": "Use `tuple` instead of `Tuple` for type annotation", + "count": 5 + }, + { + "tool": "ruff", + "path": "services/access_control.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/access_control.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/access_control.py", + "code": "UP035", + "message": "`typing.Set` is deprecated, use `set` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/access_control.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/access_control.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 7 + }, + { + "tool": "ruff", + "path": "services/approvals/__init__.py", + "code": "N999", + "message": "Invalid module name: 'ComfyUI-OpenClaw'", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/approvals/__init__.py", + "code": "RUF022", + "message": "`__all__` is not sorted", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/approvals/models.py", + "code": "SIM102", + "message": "Use a single `if` statement instead of nested `if` statements", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/approvals/models.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 5 + }, + { + "tool": "ruff", + "path": "services/approvals/models.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/approvals/models.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 10 + }, + { + "tool": "ruff", + "path": "services/approvals/service.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 3 + }, + { + "tool": "ruff", + "path": "services/approvals/service.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/approvals/service.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/approvals/service.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/approvals/service.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 20 + }, + { + "tool": "ruff", + "path": "services/approvals/storage.py", + "code": "E402", + "message": "Module level import not at top of file", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/approvals/storage.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 4 + }, + { + "tool": "ruff", + "path": "services/approvals/storage.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/approvals/storage.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/approvals/storage.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/approvals/storage.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 7 + }, + { + "tool": "ruff", + "path": "services/async_utils.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/async_utils.py", + "code": "UP035", + "message": "Import from `collections.abc` instead: `Callable`, `Iterable`", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/async_utils.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/audit.py", + "code": "SIM105", + "message": "Use `contextlib.suppress(Exception)` instead of `try`-`except`-`pass`", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/audit.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 11 + }, + { + "tool": "ruff", + "path": "services/audit.py", + "code": "UP006", + "message": "Use `tuple` instead of `Tuple` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/audit.py", + "code": "UP012", + "message": "Unnecessary UTF-8 `encoding` argument to `encode`", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/audit.py", + "code": "UP015", + "message": "Unnecessary mode argument", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/audit.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/audit.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/audit.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 14 + }, + { + "tool": "ruff", + "path": "services/audit_events.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/audit_events.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/audit_events.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 6 + }, + { + "tool": "ruff", + "path": "services/audit_pipeline.py", + "code": "SIM105", + "message": "Use `contextlib.suppress(Exception)` instead of `try`-`except`-`pass`", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/audit_pipeline.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 6 + }, + { + "tool": "ruff", + "path": "services/audit_pipeline.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 5 + }, + { + "tool": "ruff", + "path": "services/audit_pipeline.py", + "code": "UP015", + "message": "Unnecessary mode argument", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/audit_pipeline.py", + "code": "UP035", + "message": "Import from `collections.abc` instead: `Callable`", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/audit_pipeline.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/audit_pipeline.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/audit_pipeline.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 4 + }, + { + "tool": "ruff", + "path": "services/automation_composer.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 16 + }, + { + "tool": "ruff", + "path": "services/automation_composer.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/automation_composer.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/automation_composer.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/automation_composer.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 11 + }, + { + "tool": "ruff", + "path": "services/bridge_handshake.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/bridge_handshake.py", + "code": "UP006", + "message": "Use `tuple` instead of `Tuple` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/bridge_handshake.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/bridge_handshake.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/bridge_token_lifecycle.py", + "code": "SIM114", + "message": "Combine `if` branches using logical `or` operator", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/bridge_token_lifecycle.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/bridge_token_lifecycle.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 5 + }, + { + "tool": "ruff", + "path": "services/bridge_token_lifecycle.py", + "code": "UP006", + "message": "Use `tuple` instead of `Tuple` for type annotation", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/bridge_token_lifecycle.py", + "code": "UP015", + "message": "Unnecessary mode argument", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/bridge_token_lifecycle.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/bridge_token_lifecycle.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/bridge_token_lifecycle.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/bridge_token_lifecycle.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 12 + }, + { + "tool": "ruff", + "path": "services/cache/__init__.py", + "code": "N999", + "message": "Invalid module name: 'ComfyUI-OpenClaw'", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/cache/ttl_cache.py", + "code": "F401", + "message": "`typing.Any` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/cache/ttl_cache.py", + "code": "F401", + "message": "`typing.Dict` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/cache/ttl_cache.py", + "code": "UP006", + "message": "Use `tuple` instead of `Tuple` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/cache/ttl_cache.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/cache/ttl_cache.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/cache/ttl_cache.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/callback_delivery.py", + "code": "F401", + "message": "`.retry_partition.RetryDecision` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/callback_delivery.py", + "code": "RUF006", + "message": "Store a reference to the return value of `asyncio.create_task`", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/callback_delivery.py", + "code": "SIM105", + "message": "Use `contextlib.suppress(Exception)` instead of `try`-`except`-`pass`", + "count": 3 + }, + { + "tool": "ruff", + "path": "services/callback_delivery.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/callback_delivery.py", + "code": "UP006", + "message": "Use `set` instead of `Set` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/callback_delivery.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/callback_delivery.py", + "code": "UP035", + "message": "`typing.Set` is deprecated, use `set` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/callback_delivery.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/capabilities.py", + "code": "F401", + "message": "`os` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/chatops/__init__.py", + "code": "N999", + "message": "Invalid module name: 'ComfyUI-OpenClaw'", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/chatops/__init__.py", + "code": "RUF022", + "message": "`__all__` is not sorted", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/chatops/network_errors.py", + "code": "UP006", + "message": "Use `tuple` instead of `Tuple` for type annotation", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/chatops/network_errors.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/chatops/network_errors.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 3 + }, + { + "tool": "ruff", + "path": "services/chatops/retry.py", + "code": "UP035", + "message": "Import from `collections.abc` instead: `Awaitable`, `Callable`", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/chatops/retry.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 5 + }, + { + "tool": "ruff", + "path": "services/chatops/session_scope.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 3 + }, + { + "tool": "ruff", + "path": "services/chatops/targets.py", + "code": "F401", + "message": "`dataclasses.dataclass` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/chatops/targets.py", + "code": "F401", + "message": "`typing.Tuple` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/chatops/targets.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/chatops/targets.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/chatops/transport_contract.py", + "code": "F401", + "message": "`hashlib` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/chatops/transport_contract.py", + "code": "F401", + "message": "`typing.Protocol` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/chatops/transport_contract.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 7 + }, + { + "tool": "ruff", + "path": "services/chatops/transport_contract.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 3 + }, + { + "tool": "ruff", + "path": "services/chatops/transport_contract.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/chatops/transport_contract.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/chatops/transport_contract.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 6 + }, + { + "tool": "ruff", + "path": "services/chatops/webhook_adapter.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 3 + }, + { + "tool": "ruff", + "path": "services/chatops/webhook_adapter.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/chatops/webhook_adapter.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/checkpoints.py", + "code": "E402", + "message": "Module level import not at top of file", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/checkpoints.py", + "code": "F401", + "message": "`shutil` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/checkpoints.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 4 + }, + { + "tool": "ruff", + "path": "services/checkpoints.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/checkpoints.py", + "code": "UP006", + "message": "Use `tuple` instead of `Tuple` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/checkpoints.py", + "code": "UP024", + "message": "Replace aliased errors with `OSError`", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/checkpoints.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/checkpoints.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/checkpoints.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/checkpoints.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/comfyui_history.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 14 + }, + { + "tool": "ruff", + "path": "services/comfyui_history.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/comfyui_history.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/comfyui_history.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/comfyui_history.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 6 + }, + { + "tool": "ruff", + "path": "services/compatibility_matrix_governance.py", + "code": "C420", + "message": "Unnecessary dict comprehension for iterable; use `dict.fromkeys` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/compatibility_matrix_governance.py", + "code": "RUF005", + "message": "Consider `[*lines[:idx + 1], \"\\n\", block, *lines[idx + 1:]]` instead of concatenation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/compatibility_matrix_governance.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 20 + }, + { + "tool": "ruff", + "path": "services/compatibility_matrix_governance.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 6 + }, + { + "tool": "ruff", + "path": "services/compatibility_matrix_governance.py", + "code": "UP006", + "message": "Use `tuple` instead of `Tuple` for type annotation", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/compatibility_matrix_governance.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/compatibility_matrix_governance.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/compatibility_matrix_governance.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/compatibility_matrix_governance.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 21 + }, + { + "tool": "ruff", + "path": "services/config_layers.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 9 + }, + { + "tool": "ruff", + "path": "services/config_layers.py", + "code": "UP006", + "message": "Use `tuple` instead of `Tuple` for type annotation", + "count": 3 + }, + { + "tool": "ruff", + "path": "services/config_layers.py", + "code": "UP035", + "message": "Import from `collections.abc` instead: `Callable`, `Iterable`, `Mapping`", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/config_layers.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/config_layers.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/config_layers.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 10 + }, + { + "tool": "ruff", + "path": "services/connector_allowlist_posture.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 3 + }, + { + "tool": "ruff", + "path": "services/connector_allowlist_posture.py", + "code": "UP035", + "message": "Import from `collections.abc` instead: `Mapping`", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/connector_allowlist_posture.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/connector_allowlist_posture.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/connector_callback_contract.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 7 + }, + { + "tool": "ruff", + "path": "services/connector_callback_contract.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/connector_callback_contract.py", + "code": "UP037", + "message": "Remove quotes from type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/connector_callback_contract.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 9 + }, + { + "tool": "ruff", + "path": "services/connector_extraction_contract.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/connector_extraction_contract.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/connector_installation_registry.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 21 + }, + { + "tool": "ruff", + "path": "services/connector_installation_registry.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 3 + }, + { + "tool": "ruff", + "path": "services/connector_installation_registry.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/connector_installation_registry.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/connector_installation_registry.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 20 + }, + { + "tool": "ruff", + "path": "services/connector_replay_lifecycle.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 6 + }, + { + "tool": "ruff", + "path": "services/connector_replay_lifecycle.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/connector_replay_lifecycle.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 13 + }, + { + "tool": "ruff", + "path": "services/constrained_transforms.py", + "code": "F401", + "message": "`os` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/constrained_transforms.py", + "code": "N818", + "message": "Exception name `TransformExecutorUnavailable` should be named with an Error suffix", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/constrained_transforms.py", + "code": "RUF022", + "message": "`__all__` is not sorted", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/constrained_transforms.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 4 + }, + { + "tool": "ruff", + "path": "services/constrained_transforms.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 3 + }, + { + "tool": "ruff", + "path": "services/constrained_transforms.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/constrained_transforms.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/constrained_transforms.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/control_plane.py", + "code": "F401", + "message": "`.deployment_profile.evaluate_deployment_profile` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/control_plane.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/control_plane.py", + "code": "UP006", + "message": "Use `frozenset` instead of `FrozenSet` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/control_plane.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 3 + }, + { + "tool": "ruff", + "path": "services/control_plane.py", + "code": "UP006", + "message": "Use `tuple` instead of `Tuple` for type annotation", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/control_plane.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/control_plane.py", + "code": "UP035", + "message": "`typing.FrozenSet` is deprecated, use `frozenset` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/control_plane.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/control_plane.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/control_plane.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/control_plane_adapter.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 4 + }, + { + "tool": "ruff", + "path": "services/control_plane_adapter.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/control_plane_adapter.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/crypto_lifecycle_drills.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 13 + }, + { + "tool": "ruff", + "path": "services/crypto_lifecycle_drills.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 9 + }, + { + "tool": "ruff", + "path": "services/crypto_lifecycle_drills.py", + "code": "UP035", + "message": "Import from `collections.abc` instead: `Iterable`", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/crypto_lifecycle_drills.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/crypto_lifecycle_drills.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/crypto_lifecycle_drills.py", + "code": "UP037", + "message": "Remove quotes from type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/crypto_lifecycle_drills.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 5 + }, + { + "tool": "ruff", + "path": "services/csrf_protection.py", + "code": "E402", + "message": "Module level import not at top of file", + "count": 4 + }, + { + "tool": "ruff", + "path": "services/csrf_protection.py", + "code": "F841", + "message": "Local variable `origin_base` is assigned to but never used", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/csrf_protection.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/delivery/__init__.py", + "code": "N999", + "message": "Invalid module name: 'ComfyUI-OpenClaw'", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/delivery/__init__.py", + "code": "RUF022", + "message": "`__all__` is not sorted", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/delivery/http_callback.py", + "code": "C401", + "message": "Unnecessary generator (rewrite as a set comprehension)", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/delivery/http_callback.py", + "code": "F401", + "message": "`asyncio` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/delivery/http_callback.py", + "code": "UP006", + "message": "Use `set` instead of `Set` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/delivery/http_callback.py", + "code": "UP035", + "message": "`typing.Set` is deprecated, use `set` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/delivery/http_callback.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/delivery/router.py", + "code": "F401", + "message": "`typing.Any` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/delivery/router.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/delivery/router.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/delivery/router.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/deployment_profile.py", + "code": "F401", + "message": "`typing.Dict` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/deployment_profile.py", + "code": "UP035", + "message": "Import from `collections.abc` instead: `Iterable`, `Mapping`", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/deployment_profile.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/deployment_profile.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 5 + }, + { + "tool": "ruff", + "path": "services/diagnostics_flags.py", + "code": "F401", + "message": "`.redaction.redact_text` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/diagnostics_flags.py", + "code": "UP006", + "message": "Use `set` instead of `Set` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/diagnostics_flags.py", + "code": "UP035", + "message": "`typing.Set` is deprecated, use `set` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/endpoint_manifest.py", + "code": "B010", + "message": "Do not call `setattr` with a constant attribute value. It is not any safer than normal property access.", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/endpoint_manifest.py", + "code": "E402", + "message": "Module level import not at top of file", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/endpoint_manifest.py", + "code": "F401", + "message": "`typing.Set` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/endpoint_manifest.py", + "code": "SIM102", + "message": "Use a single `if` statement instead of nested `if` statements", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/endpoint_manifest.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 3 + }, + { + "tool": "ruff", + "path": "services/endpoint_manifest.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 6 + }, + { + "tool": "ruff", + "path": "services/endpoint_manifest.py", + "code": "UP006", + "message": "Use `tuple` instead of `Tuple` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/endpoint_manifest.py", + "code": "UP035", + "message": "Import from `collections.abc` instead: `Callable`", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/endpoint_manifest.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/endpoint_manifest.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/endpoint_manifest.py", + "code": "UP035", + "message": "`typing.Set` is deprecated, use `set` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/endpoint_manifest.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/endpoint_manifest.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 6 + }, + { + "tool": "ruff", + "path": "services/execution_budgets.py", + "code": "F841", + "message": "Local variable `global_acquired` is assigned to but never used", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/execution_budgets.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 5 + }, + { + "tool": "ruff", + "path": "services/execution_budgets.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/execution_budgets.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 6 + }, + { + "tool": "ruff", + "path": "services/failover.py", + "code": "F401", + "message": "`pathlib.Path` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/failover.py", + "code": "F401", + "message": "`typing.Any` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/failover.py", + "code": "SIM103", + "message": "Return the condition `category == ErrorCategory.UNKNOWN` directly", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/failover.py", + "code": "SIM103", + "message": "Return the condition directly", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/failover.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 4 + }, + { + "tool": "ruff", + "path": "services/failover.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 3 + }, + { + "tool": "ruff", + "path": "services/failover.py", + "code": "UP006", + "message": "Use `tuple` instead of `Tuple` for type annotation", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/failover.py", + "code": "UP015", + "message": "Unnecessary mode argument", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/failover.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/failover.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/failover.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/failover.py", + "code": "UP037", + "message": "Remove quotes from type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/failover.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 26 + }, + { + "tool": "ruff", + "path": "services/idempotency_store.py", + "code": "SIM102", + "message": "Use a single `if` statement instead of nested `if` statements", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/idempotency_store.py", + "code": "SIM105", + "message": "Use `contextlib.suppress(Exception)` instead of `try`-`except`-`pass`", + "count": 3 + }, + { + "tool": "ruff", + "path": "services/idempotency_store.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 4 + }, + { + "tool": "ruff", + "path": "services/idempotency_store.py", + "code": "UP006", + "message": "Use `tuple` instead of `Tuple` for type annotation", + "count": 3 + }, + { + "tool": "ruff", + "path": "services/idempotency_store.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/idempotency_store.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/idempotency_store.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 10 + }, + { + "tool": "ruff", + "path": "services/import_fallback.py", + "code": "UP006", + "message": "Use `tuple` instead of `Tuple` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/import_fallback.py", + "code": "UP035", + "message": "Import from `collections.abc` instead: `Iterable`", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/import_fallback.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/integrity.py", + "code": "F401", + "message": "`shutil` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/integrity.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 4 + }, + { + "tool": "ruff", + "path": "services/integrity.py", + "code": "UP007", + "message": "Use `X | Y` for type annotations", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/integrity.py", + "code": "UP015", + "message": "Unnecessary mode argument", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/integrity.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/integrity.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/job_events.py", + "code": "F401", + "message": "`dataclasses.asdict` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/job_events.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 5 + }, + { + "tool": "ruff", + "path": "services/job_events.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 3 + }, + { + "tool": "ruff", + "path": "services/job_events.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/job_events.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/job_events.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 6 + }, + { + "tool": "ruff", + "path": "services/jobs_read_model.py", + "code": "N818", + "message": "Exception name `JobsBackendUnavailable` should be named with an Error suffix", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/jobs_read_model.py", + "code": "N818", + "message": "Exception name `JobsHostContractUnsupported` should be named with an Error suffix", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/jobs_security.py", + "code": "UP035", + "message": "Import from `collections.abc` instead: `Iterator`", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/legacy_compat.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/legacy_compat.py", + "code": "UP006", + "message": "Use `tuple` instead of `Tuple` for type annotation", + "count": 4 + }, + { + "tool": "ruff", + "path": "services/legacy_compat.py", + "code": "UP035", + "message": "Import from `collections.abc` instead: `Mapping`", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/legacy_compat.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/legacy_compat.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/legacy_compat.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 3 + }, + { + "tool": "ruff", + "path": "services/llm_client.py", + "code": "E402", + "message": "Module level import not at top of file", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/llm_client.py", + "code": "F401", + "message": "`.providers.catalog.DEFAULT_MODEL_BY_PROVIDER` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/llm_client.py", + "code": "F401", + "message": "`asyncio` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/llm_client.py", + "code": "F401", + "message": "`concurrent.futures` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/llm_client.py", + "code": "N806", + "message": "Variable `ErrorCategory` in function should be lowercase", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/llm_client.py", + "code": "N806", + "message": "Variable `SAFE_BOUNDS` in function should be lowercase", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/llm_client.py", + "code": "RUF012", + "message": "Mutable default value for class attribute", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/llm_client.py", + "code": "SIM102", + "message": "Use a single `if` statement instead of nested `if` statements", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/llm_client.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 13 + }, + { + "tool": "ruff", + "path": "services/llm_client.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 9 + }, + { + "tool": "ruff", + "path": "services/llm_client.py", + "code": "UP006", + "message": "Use `tuple` instead of `Tuple` for type annotation", + "count": 5 + }, + { + "tool": "ruff", + "path": "services/llm_client.py", + "code": "UP035", + "message": "Import from `collections.abc` instead: `Callable`", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/llm_client.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/llm_client.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/llm_client.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/llm_client.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 36 + }, + { + "tool": "ruff", + "path": "services/llm_model_list.py", + "code": "RUF059", + "message": "Unpacked variable `models` is never used", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/llm_output.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 5 + }, + { + "tool": "ruff", + "path": "services/llm_output.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/llm_output.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 3 + }, + { + "tool": "ruff", + "path": "services/log_tail.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/log_tail.py", + "code": "UP015", + "message": "Unnecessary mode argument", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/log_tail.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/management_query.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 8 + }, + { + "tool": "ruff", + "path": "services/management_query.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 4 + }, + { + "tool": "ruff", + "path": "services/management_query.py", + "code": "UP035", + "message": "Import from `collections.abc` instead: `Callable`, `Iterable`", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/management_query.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/management_query.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/management_query.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 3 + }, + { + "tool": "ruff", + "path": "services/metrics.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/metrics.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/model_manager.py", + "code": "N818", + "message": "Exception name `DownloadCancelled` should be named with an Error suffix", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/model_manager.py", + "code": "SIM105", + "message": "Use `contextlib.suppress(OSError)` instead of `try`-`except`-`pass`", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/model_manager.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 24 + }, + { + "tool": "ruff", + "path": "services/model_manager.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 5 + }, + { + "tool": "ruff", + "path": "services/model_manager.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/model_manager.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/model_manager.py", + "code": "UP037", + "message": "Remove quotes from type annotation", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/model_manager.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 22 + }, + { + "tool": "ruff", + "path": "services/model_manager_catalog.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 6 + }, + { + "tool": "ruff", + "path": "services/model_manager_catalog.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 4 + }, + { + "tool": "ruff", + "path": "services/model_manager_catalog.py", + "code": "UP035", + "message": "Import from `collections.abc` instead: `Callable`", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/model_manager_catalog.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/model_manager_catalog.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/model_manager_catalog.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 5 + }, + { + "tool": "ruff", + "path": "services/model_manager_tasks.py", + "code": "SIM103", + "message": "Return the negated condition directly", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/model_manager_tasks.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 7 + }, + { + "tool": "ruff", + "path": "services/model_manager_tasks.py", + "code": "UP035", + "message": "Import from `collections.abc` instead: `Callable`", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/model_manager_tasks.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/model_manager_tasks.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 5 + }, + { + "tool": "ruff", + "path": "services/model_manager_transfer.py", + "code": "SIM105", + "message": "Use `contextlib.suppress(Exception)` instead of `try`-`except`-`pass`", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/model_manager_transfer.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 6 + }, + { + "tool": "ruff", + "path": "services/model_manager_transfer.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/model_manager_transfer.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/model_manager_transfer.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/model_manager_transfer.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 8 + }, + { + "tool": "ruff", + "path": "services/modules.py", + "code": "F401", + "message": "`typing.Dict` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/modules.py", + "code": "RUF012", + "message": "Mutable default value for class attribute", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/modules.py", + "code": "UP006", + "message": "Use `set` instead of `Set` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/modules.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/modules.py", + "code": "UP035", + "message": "`typing.Set` is deprecated, use `set` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/observability/backpressure.py", + "code": "F401", + "message": "`typing.Optional` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/observability/backpressure.py", + "code": "UP006", + "message": "Use `collections.deque` instead of `Deque` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/observability/backpressure.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/observability/backpressure.py", + "code": "UP035", + "message": "`typing.Deque` is deprecated, use `collections.deque` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/observability/backpressure.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/openapi_generation.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 4 + }, + { + "tool": "ruff", + "path": "services/openapi_generation.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 6 + }, + { + "tool": "ruff", + "path": "services/openapi_generation.py", + "code": "UP035", + "message": "Import from `collections.abc` instead: `Iterable`", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/openapi_generation.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/openapi_generation.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/openapi_generation.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 6 + }, + { + "tool": "ruff", + "path": "services/operator_doctor.py", + "code": "F401", + "message": "`.permission_posture.evaluate_startup_permissions` imported but unused; consider using `importlib.util.find_spec` to test for availability", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/operator_doctor.py", + "code": "F541", + "message": "f-string without any placeholders", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/operator_doctor.py", + "code": "F841", + "message": "Local variable `long_path` is assigned to but never used", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/operator_doctor.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 8 + }, + { + "tool": "ruff", + "path": "services/operator_doctor.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 6 + }, + { + "tool": "ruff", + "path": "services/operator_doctor.py", + "code": "UP034", + "message": "Avoid extraneous parentheses", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/operator_doctor.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/operator_doctor.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/operator_doctor.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/operator_guidance.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 3 + }, + { + "tool": "ruff", + "path": "services/operator_guidance.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/operator_guidance.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/package_hygiene.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/package_hygiene.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/packs/pack_archive.py", + "code": "F401", + "message": "`typing.Optional` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/packs/pack_archive.py", + "code": "N806", + "message": "Variable `DANGEROUS_PATTERNS` in function should be lowercase", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/packs/pack_archive.py", + "code": "RUF003", + "message": "Comment contains ambiguous `.` (FULLWIDTH FULL STOP). Did you mean `.` (FULL STOP)?", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/packs/pack_archive.py", + "code": "UP015", + "message": "Unnecessary mode argument", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/packs/pack_manifest.py", + "code": "F401", + "message": "`typing.Tuple` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/packs/pack_manifest.py", + "code": "RUF010", + "message": "Use explicit conversion flag", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/packs/pack_manifest.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/packs/pack_manifest.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/packs/pack_manifest.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/packs/pack_manifest.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/packs/pack_manifest.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/packs/pack_registry.py", + "code": "F401", + "message": "`typing.Dict` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/packs/pack_registry.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/packs/pack_registry.py", + "code": "UP015", + "message": "Unnecessary mode argument", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/packs/pack_registry.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/packs/pack_registry.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/packs/pack_registry.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/packs/pack_types.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/packs/pack_types.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/packs/pack_types.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/parameter_lab.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 8 + }, + { + "tool": "ruff", + "path": "services/parameter_lab.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 15 + }, + { + "tool": "ruff", + "path": "services/parameter_lab.py", + "code": "UP015", + "message": "Unnecessary mode argument", + "count": 3 + }, + { + "tool": "ruff", + "path": "services/parameter_lab.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/parameter_lab.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/parameter_lab.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 4 + }, + { + "tool": "ruff", + "path": "services/paths.py", + "code": "SIM105", + "message": "Use `contextlib.suppress(OSError)` instead of `try`-`except`-`pass`", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/permission_posture.py", + "code": "F401", + "message": "`typing.Dict` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/permission_posture.py", + "code": "F401", + "message": "`typing.Optional` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/permission_posture.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/permission_posture.py", + "code": "UP006", + "message": "Use `tuple` instead of `Tuple` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/permission_posture.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/permission_posture.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/permission_posture.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/planner.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/planner.py", + "code": "UP006", + "message": "Use `tuple` instead of `Tuple` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/planner.py", + "code": "UP035", + "message": "Import from `collections.abc` instead: `Callable`", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/planner.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/planner.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/planner.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/planner_registry.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 9 + }, + { + "tool": "ruff", + "path": "services/planner_registry.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/planner_registry.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 11 + }, + { + "tool": "ruff", + "path": "services/plugins/__init__.py", + "code": "N999", + "message": "Invalid module name: 'ComfyUI-OpenClaw'", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/plugins/__init__.py", + "code": "RUF022", + "message": "`__all__` is not sorted", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/plugins/async_bridge.py", + "code": "F401", + "message": "`typing.Callable` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/plugins/async_bridge.py", + "code": "F841", + "message": "Local variable `loop` is assigned to but never used", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/plugins/async_bridge.py", + "code": "UP035", + "message": "Import from `collections.abc` instead: `Callable`", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/plugins/builtin/__init__.py", + "code": "N999", + "message": "Invalid module name: 'ComfyUI-OpenClaw'", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/plugins/builtin/audit_log.py", + "code": "F401", + "message": "`..contract.Plugin` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/plugins/builtin/model_alias.py", + "code": "F401", + "message": "`..contract.Plugin` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/plugins/builtin/model_alias.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/plugins/builtin/params_clamp.py", + "code": "F401", + "message": "`..contract.Plugin` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/plugins/builtin/params_clamp.py", + "code": "F401", + "message": "`typing.Optional` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/plugins/builtin/params_clamp.py", + "code": "RUF012", + "message": "Mutable default value for class attribute", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/plugins/builtin/params_clamp.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/plugins/builtin/params_clamp.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/plugins/contract.py", + "code": "F401", + "message": "`typing.Generic` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/plugins/contract.py", + "code": "F401", + "message": "`typing.List` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/plugins/contract.py", + "code": "F401", + "message": "`typing.Union` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/plugins/contract.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/plugins/contract.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/plugins/contract.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/plugins/contract.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/plugins/manager.py", + "code": "F401", + "message": "`.contract.HookType` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/plugins/manager.py", + "code": "F401", + "message": "`inspect` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/plugins/manager.py", + "code": "F401", + "message": "`typing.Any` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/plugins/manager.py", + "code": "F401", + "message": "`typing.Optional` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/plugins/manager.py", + "code": "F401", + "message": "`typing.Tuple` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/plugins/manager.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 3 + }, + { + "tool": "ruff", + "path": "services/plugins/manager.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/plugins/manager.py", + "code": "UP035", + "message": "Import from `collections.abc` instead: `Callable`", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/plugins/manager.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/plugins/manager.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/plugins/manager.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/policy_posture.py", + "code": "F401", + "message": "`cryptography.hazmat.primitives.serialization` imported but unused; consider using `importlib.util.find_spec` to test for availability", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/policy_posture.py", + "code": "F401", + "message": "`os` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/policy_posture.py", + "code": "F401", + "message": "`time` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/policy_posture.py", + "code": "F401", + "message": "`typing.Union` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/policy_posture.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 11 + }, + { + "tool": "ruff", + "path": "services/policy_posture.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/policy_posture.py", + "code": "UP015", + "message": "Unnecessary mode argument", + "count": 3 + }, + { + "tool": "ruff", + "path": "services/policy_posture.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/policy_posture.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/policy_posture.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/preflight.py", + "code": "B007", + "message": "Loop control variable `key` not used within loop body", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/preflight.py", + "code": "F401", + "message": "`typing.Set` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/preflight.py", + "code": "F401", + "message": "`typing.Tuple` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/preflight.py", + "code": "F821", + "message": "Undefined name `OperatorBanner`", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/preflight.py", + "code": "SIM118", + "message": "Use `key in dict` instead of `key in dict.keys()`", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/preflight.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 19 + }, + { + "tool": "ruff", + "path": "services/preflight.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 10 + }, + { + "tool": "ruff", + "path": "services/preflight.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/preflight.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/preflight.py", + "code": "UP035", + "message": "`typing.Set` is deprecated, use `set` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/preflight.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/presets/__init__.py", + "code": "N999", + "message": "Invalid module name: 'ComfyUI-OpenClaw'", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/presets/models.py", + "code": "F401", + "message": "`json` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/presets/models.py", + "code": "F401", + "message": "`typing.Optional` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/presets/models.py", + "code": "RUF013", + "message": "PEP 484 prohibits implicit `Optional`", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/presets/models.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 4 + }, + { + "tool": "ruff", + "path": "services/presets/models.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/presets/models.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/presets/models.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/presets/storage.py", + "code": "F401", + "message": "`typing.Dict` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/presets/storage.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/presets/storage.py", + "code": "UP015", + "message": "Unnecessary mode argument", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/presets/storage.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/presets/storage.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/presets/storage.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 11 + }, + { + "tool": "ruff", + "path": "services/product_boundary.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/product_boundary.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/provider_errors.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 3 + }, + { + "tool": "ruff", + "path": "services/provider_errors.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/provider_errors.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 4 + }, + { + "tool": "ruff", + "path": "services/providers/__init__.py", + "code": "N999", + "message": "Invalid module name: 'ComfyUI-OpenClaw'", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/providers/__init__.py", + "code": "RUF022", + "message": "`__all__` is not sorted", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/providers/anthropic.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 6 + }, + { + "tool": "ruff", + "path": "services/providers/anthropic.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/providers/anthropic.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/providers/anthropic.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/providers/anthropic.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 6 + }, + { + "tool": "ruff", + "path": "services/providers/catalog.py", + "code": "F401", + "message": "`dataclasses.field` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/providers/catalog.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 6 + }, + { + "tool": "ruff", + "path": "services/providers/catalog.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 4 + }, + { + "tool": "ruff", + "path": "services/providers/catalog.py", + "code": "UP006", + "message": "Use `tuple` instead of `Tuple` for type annotation", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/providers/catalog.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/providers/catalog.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/providers/catalog.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/providers/catalog.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/providers/keys.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 3 + }, + { + "tool": "ruff", + "path": "services/providers/openai_compat.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 11 + }, + { + "tool": "ruff", + "path": "services/providers/openai_compat.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 7 + }, + { + "tool": "ruff", + "path": "services/providers/openai_compat.py", + "code": "UP035", + "message": "Import from `collections.abc` instead: `Callable`", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/providers/openai_compat.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/providers/openai_compat.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/providers/openai_compat.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 15 + }, + { + "tool": "ruff", + "path": "services/queue_submit.py", + "code": "E402", + "message": "Module level import not at top of file", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/queue_submit.py", + "code": "E722", + "message": "Do not use bare `except`", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/queue_submit.py", + "code": "F401", + "message": "`api.errors.create_error_response` imported but unused; consider using `importlib.util.find_spec` to test for availability", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/queue_submit.py", + "code": "RUF010", + "message": "Use explicit conversion flag", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/queue_submit.py", + "code": "SIM117", + "message": "Use a single `with` statement with multiple contexts instead of nested `with` statements", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/queue_submit.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 5 + }, + { + "tool": "ruff", + "path": "services/queue_submit.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/queue_submit.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 6 + }, + { + "tool": "ruff", + "path": "services/rate_limit.py", + "code": "B009", + "message": "Do not call `getattr` with a constant attribute value. It is not any safer than normal property access.", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/rate_limit.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 8 + }, + { + "tool": "ruff", + "path": "services/rate_limit.py", + "code": "UP006", + "message": "Use `tuple` instead of `Tuple` for type annotation", + "count": 5 + }, + { + "tool": "ruff", + "path": "services/rate_limit.py", + "code": "UP035", + "message": "Import from `collections.abc` instead: `Mapping`", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/rate_limit.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/rate_limit.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/rate_limit.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 11 + }, + { + "tool": "ruff", + "path": "services/reasoning_redaction.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 6 + }, + { + "tool": "ruff", + "path": "services/reasoning_redaction.py", + "code": "UP035", + "message": "Import from `collections.abc` instead: `Iterable`", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/reasoning_redaction.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/redaction.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 3 + }, + { + "tool": "ruff", + "path": "services/redaction.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 3 + }, + { + "tool": "ruff", + "path": "services/redaction.py", + "code": "UP006", + "message": "Use `set` instead of `Set` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/redaction.py", + "code": "UP006", + "message": "Use `tuple` instead of `Tuple` for type annotation", + "count": 4 + }, + { + "tool": "ruff", + "path": "services/redaction.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/redaction.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/redaction.py", + "code": "UP035", + "message": "`typing.Set` is deprecated, use `set` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/redaction.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/redaction.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 3 + }, + { + "tool": "ruff", + "path": "services/refiner.py", + "code": "SIM118", + "message": "Use `key in dict` instead of `key in dict.keys()`", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/refiner.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/refiner.py", + "code": "UP006", + "message": "Use `tuple` instead of `Tuple` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/refiner.py", + "code": "UP035", + "message": "Import from `collections.abc` instead: `Callable`", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/refiner.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/refiner.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/refiner.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/registry.py", + "code": "F401", + "message": "`typing.Type` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/registry.py", + "code": "RUF012", + "message": "Mutable default value for class attribute", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/registry.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/registry.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/registry.py", + "code": "UP035", + "message": "`typing.Type` is deprecated, use `type` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/registry.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/registry_quarantine.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 9 + }, + { + "tool": "ruff", + "path": "services/registry_quarantine.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 4 + }, + { + "tool": "ruff", + "path": "services/registry_quarantine.py", + "code": "UP006", + "message": "Use `tuple` instead of `Tuple` for type annotation", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/registry_quarantine.py", + "code": "UP015", + "message": "Unnecessary mode argument", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/registry_quarantine.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/registry_quarantine.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/registry_quarantine.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/registry_quarantine.py", + "code": "UP037", + "message": "Remove quotes from type annotation", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/registry_quarantine.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 6 + }, + { + "tool": "ruff", + "path": "services/request_contracts.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 6 + }, + { + "tool": "ruff", + "path": "services/request_contracts.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/request_ip.py", + "code": "F401", + "message": "`typing.Optional` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/request_ip.py", + "code": "F841", + "message": "Local variable `candidate` is assigned to but never used", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/request_ip.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/request_ip.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/retry_after.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 4 + }, + { + "tool": "ruff", + "path": "services/retry_after.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/retry_after.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 5 + }, + { + "tool": "ruff", + "path": "services/retry_partition.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 5 + }, + { + "tool": "ruff", + "path": "services/retry_partition.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/retry_partition.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/retry_partition.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/retry_partition.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/rewrite_recipes.py", + "code": "SIM118", + "message": "Use `key in dict` instead of `key in dict.keys()`", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/rewrite_recipes.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 25 + }, + { + "tool": "ruff", + "path": "services/rewrite_recipes.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 16 + }, + { + "tool": "ruff", + "path": "services/rewrite_recipes.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/rewrite_recipes.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/rewrite_recipes.py", + "code": "UP037", + "message": "Remove quotes from type annotation", + "count": 4 + }, + { + "tool": "ruff", + "path": "services/rewrite_recipes.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 15 + }, + { + "tool": "ruff", + "path": "services/route_bootstrap.py", + "code": "N806", + "message": "Variable `BridgeHandlers` in function should be lowercase", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/route_bootstrap.py", + "code": "N806", + "message": "Variable `PromptServer` in function should be lowercase", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/runtime_config.py", + "code": "F401", + "message": "`services.runtime_config_policy.get_apply_semantics` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/runtime_config.py", + "code": "F401", + "message": "`services.runtime_config_policy.get_llm_egress_controls` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/runtime_config.py", + "code": "F401", + "message": "`services.runtime_config_policy.get_scheduler_config` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/runtime_config.py", + "code": "F401", + "message": "`services.runtime_config_policy.is_config_write_enabled` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/runtime_config.py", + "code": "F401", + "message": "`services.runtime_config_policy.is_loopback_client` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/runtime_config.py", + "code": "F401", + "message": "`services.runtime_config_policy.validate_admin_token` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/runtime_config.py", + "code": "I001", + "message": "Import block is un-sorted or un-formatted", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/runtime_config.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 12 + }, + { + "tool": "ruff", + "path": "services/runtime_config.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/runtime_config.py", + "code": "UP006", + "message": "Use `tuple` instead of `Tuple` for type annotation", + "count": 4 + }, + { + "tool": "ruff", + "path": "services/runtime_config.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/runtime_config.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/runtime_config.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/runtime_config.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 8 + }, + { + "tool": "ruff", + "path": "services/runtime_config_policy.py", + "code": "E731", + "message": "Do not assign a `lambda` expression, use a `def`", + "count": 5 + }, + { + "tool": "ruff", + "path": "services/runtime_config_policy.py", + "code": "F401", + "message": "`services.config_layers.SOURCE_PERSISTED` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/runtime_config_policy.py", + "code": "F401", + "message": "`services.config_layers.SOURCE_RUNTIME_OVERRIDE` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/runtime_config_policy.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 6 + }, + { + "tool": "ruff", + "path": "services/runtime_config_policy.py", + "code": "UP006", + "message": "Use `tuple` instead of `Tuple` for type annotation", + "count": 3 + }, + { + "tool": "ruff", + "path": "services/runtime_config_policy.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/runtime_config_policy.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/runtime_config_policy.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/runtime_config_projection.py", + "code": "UP035", + "message": "Import from `collections.abc` instead: `Callable`", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/runtime_config_store.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 4 + }, + { + "tool": "ruff", + "path": "services/runtime_config_store.py", + "code": "UP015", + "message": "Unnecessary mode argument", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/runtime_config_store.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/runtime_config_store.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/runtime_dependency_hygiene.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 4 + }, + { + "tool": "ruff", + "path": "services/runtime_dependency_hygiene.py", + "code": "UP007", + "message": "Use `X | Y` for type annotations", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/runtime_dependency_hygiene.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/runtime_dependency_hygiene.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/runtime_guardrails.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 8 + }, + { + "tool": "ruff", + "path": "services/runtime_guardrails.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 3 + }, + { + "tool": "ruff", + "path": "services/runtime_guardrails.py", + "code": "UP006", + "message": "Use `tuple` instead of `Tuple` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/runtime_guardrails.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/runtime_guardrails.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/runtime_guardrails.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/runtime_lifecycle.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 4 + }, + { + "tool": "ruff", + "path": "services/runtime_lifecycle.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/runtime_lifecycle.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/runtime_lifecycle.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/safe_io.py", + "code": "N806", + "message": "Variable `PACK_VERSION` in function should be lowercase", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/safe_io.py", + "code": "SIM105", + "message": "Use `contextlib.suppress(Exception)` instead of `try`-`except`-`pass`", + "count": 5 + }, + { + "tool": "ruff", + "path": "services/safe_io.py", + "code": "SIM105", + "message": "Use `contextlib.suppress(OSError)` instead of `try`-`except`-`pass`", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/safe_io.py", + "code": "SIM105", + "message": "Use `contextlib.suppress(UnicodeError, UnicodeDecodeError)` instead of `try`-`except`-`pass`", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/safe_io.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/safe_io.py", + "code": "UP006", + "message": "Use `frozenset` instead of `FrozenSet` for type annotation", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/safe_io.py", + "code": "UP006", + "message": "Use `set` instead of `Set` for type annotation", + "count": 9 + }, + { + "tool": "ruff", + "path": "services/safe_io.py", + "code": "UP006", + "message": "Use `tuple` instead of `Tuple` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/safe_io.py", + "code": "UP035", + "message": "Import from `collections.abc` instead: `Callable`", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/safe_io.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/safe_io.py", + "code": "UP035", + "message": "`typing.FrozenSet` is deprecated, use `frozenset` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/safe_io.py", + "code": "UP035", + "message": "`typing.Set` is deprecated, use `set` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/safe_io.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/safe_io.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 28 + }, + { + "tool": "ruff", + "path": "services/scheduler/__init__.py", + "code": "N999", + "message": "Invalid module name: 'ComfyUI-OpenClaw'", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/scheduler/delivery_contract.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 5 + }, + { + "tool": "ruff", + "path": "services/scheduler/delivery_contract.py", + "code": "UP035", + "message": "Import from `collections.abc` instead: `Iterable`", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/scheduler/delivery_contract.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/scheduler/delivery_contract.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 4 + }, + { + "tool": "ruff", + "path": "services/scheduler/history.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 3 + }, + { + "tool": "ruff", + "path": "services/scheduler/history.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/scheduler/history.py", + "code": "UP015", + "message": "Unnecessary mode argument", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/scheduler/history.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/scheduler/history.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/scheduler/history.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 10 + }, + { + "tool": "ruff", + "path": "services/scheduler/models.py", + "code": "F401", + "message": "`typing.List` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/scheduler/models.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 4 + }, + { + "tool": "ruff", + "path": "services/scheduler/models.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/scheduler/models.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/scheduler/models.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 6 + }, + { + "tool": "ruff", + "path": "services/scheduler/runner.py", + "code": "F401", + "message": "`asyncio` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/scheduler/runner.py", + "code": "F401", + "message": "`time` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/scheduler/runner.py", + "code": "UP035", + "message": "Import from `collections.abc` instead: `Awaitable`, `Callable`", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/scheduler/runner.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 8 + }, + { + "tool": "ruff", + "path": "services/scheduler/storage.py", + "code": "F401", + "message": "`pathlib.Path` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/scheduler/storage.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 3 + }, + { + "tool": "ruff", + "path": "services/scheduler/storage.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/scheduler/storage.py", + "code": "UP015", + "message": "Unnecessary mode argument", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/scheduler/storage.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/scheduler/storage.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/scheduler/storage.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/schema_sanitizer.py", + "code": "F401", + "message": "`typing.Optional` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/schema_sanitizer.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 6 + }, + { + "tool": "ruff", + "path": "services/schema_sanitizer.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 3 + }, + { + "tool": "ruff", + "path": "services/schema_sanitizer.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/schema_sanitizer.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/secret_providers.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 12 + }, + { + "tool": "ruff", + "path": "services/secret_store.py", + "code": "SIM118", + "message": "Use `key in dict` instead of `key in dict.keys()`", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/secret_store.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 3 + }, + { + "tool": "ruff", + "path": "services/secret_store.py", + "code": "UP015", + "message": "Unnecessary mode argument", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/secret_store.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/secret_store.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 11 + }, + { + "tool": "ruff", + "path": "services/secrets_encryption.py", + "code": "F401", + "message": "`dataclasses.field` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/secrets_encryption.py", + "code": "F401", + "message": "`typing.Any` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/secrets_encryption.py", + "code": "F401", + "message": "`typing.List` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/secrets_encryption.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 4 + }, + { + "tool": "ruff", + "path": "services/secrets_encryption.py", + "code": "UP006", + "message": "Use `tuple` instead of `Tuple` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/secrets_encryption.py", + "code": "UP015", + "message": "Unnecessary mode argument", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/secrets_encryption.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/secrets_encryption.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/secrets_encryption.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/secrets_encryption.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/security_advisories.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 6 + }, + { + "tool": "ruff", + "path": "services/security_advisories.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 3 + }, + { + "tool": "ruff", + "path": "services/security_advisories.py", + "code": "UP006", + "message": "Use `tuple` instead of `Tuple` for type annotation", + "count": 4 + }, + { + "tool": "ruff", + "path": "services/security_advisories.py", + "code": "UP035", + "message": "Import from `collections.abc` instead: `Iterable`", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/security_advisories.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/security_advisories.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/security_advisories.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/security_advisories.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/security_doctor.py", + "code": "RUF022", + "message": "`__all__` is not sorted", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/security_doctor_checks.py", + "code": "RUF022", + "message": "`__all__` is not sorted", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/security_doctor_endpoint_checks.py", + "code": "RUF022", + "message": "`__all__` is not sorted", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/security_doctor_endpoint_checks.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/security_doctor_endpoint_checks.py", + "code": "UP015", + "message": "Unnecessary mode argument", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/security_doctor_endpoint_checks.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/security_doctor_report.py", + "code": "RUF001", + "message": "String contains ambiguous `ℹ` (INFORMATION SOURCE). Did you mean `i` (LATIN SMALL LETTER I)?", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/security_doctor_report.py", + "code": "RUF022", + "message": "`__all__` is not sorted", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/security_doctor_report.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 13 + }, + { + "tool": "ruff", + "path": "services/security_doctor_report.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 9 + }, + { + "tool": "ruff", + "path": "services/security_doctor_report.py", + "code": "UP006", + "message": "Use `tuple` instead of `Tuple` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/security_doctor_report.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/security_doctor_report.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/security_doctor_report.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/security_doctor_runner.py", + "code": "RUF022", + "message": "`__all__` is not sorted", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/security_doctor_runtime_checks.py", + "code": "F401", + "message": "`.integrity.load_verified` imported but unused; consider using `importlib.util.find_spec` to test for availability", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/security_doctor_runtime_checks.py", + "code": "RUF022", + "message": "`__all__` is not sorted", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/security_gate.py", + "code": "SIM102", + "message": "Use a single `if` statement instead of nested `if` statements", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/security_gate.py", + "code": "SIM103", + "message": "Return the condition directly", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/security_gate.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/security_gate.py", + "code": "UP006", + "message": "Use `tuple` instead of `Tuple` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/security_gate.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/security_gate.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/security_invariants.py", + "code": "F401", + "message": "`typing.List` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/security_invariants.py", + "code": "F401", + "message": "`typing.Optional` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/security_invariants.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/security_invariants.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/security_invariants.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/security_telemetry.py", + "code": "F401", + "message": "`dataclasses.field` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/security_telemetry.py", + "code": "F401", + "message": "`typing.List` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/security_telemetry.py", + "code": "UP006", + "message": "Use `collections.deque` instead of `Deque` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/security_telemetry.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 3 + }, + { + "tool": "ruff", + "path": "services/security_telemetry.py", + "code": "UP035", + "message": "`typing.Deque` is deprecated, use `collections.deque` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/security_telemetry.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/security_telemetry.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/security_telemetry.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/settings_schema.py", + "code": "F401", + "message": "`dataclasses.field` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/settings_schema.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 5 + }, + { + "tool": "ruff", + "path": "services/settings_schema.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 4 + }, + { + "tool": "ruff", + "path": "services/settings_schema.py", + "code": "UP006", + "message": "Use `tuple` instead of `Tuple` for type annotation", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/settings_schema.py", + "code": "UP007", + "message": "Use `X | Y` for type annotations", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/settings_schema.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/settings_schema.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/settings_schema.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/settings_schema.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 5 + }, + { + "tool": "ruff", + "path": "services/sidecar/__init__.py", + "code": "N999", + "message": "Invalid module name: 'ComfyUI-OpenClaw'", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/sidecar/__init__.py", + "code": "RUF022", + "message": "`__all__` is not sorted", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/sidecar/auth.py", + "code": "C401", + "message": "Unnecessary generator (rewrite as a set comprehension)", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/sidecar/auth.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/sidecar/auth.py", + "code": "UP006", + "message": "Use `set` instead of `Set` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/sidecar/auth.py", + "code": "UP006", + "message": "Use `tuple` instead of `Tuple` for type annotation", + "count": 3 + }, + { + "tool": "ruff", + "path": "services/sidecar/auth.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/sidecar/auth.py", + "code": "UP035", + "message": "`typing.Set` is deprecated, use `set` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/sidecar/auth.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/sidecar/auth.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 8 + }, + { + "tool": "ruff", + "path": "services/sidecar/bridge_client.py", + "code": "F401", + "message": "`typing.List` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/sidecar/bridge_client.py", + "code": "F841", + "message": "Local variable `resp` is assigned to but never used", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/sidecar/bridge_client.py", + "code": "RUF013", + "message": "PEP 484 prohibits implicit `Optional`", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/sidecar/bridge_client.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/sidecar/bridge_client.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/sidecar/bridge_client.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/sidecar/bridge_client.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/sidecar/bridge_contract.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/sidecar/bridge_contract.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/sidecar/bridge_contract.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/sidecar/bridge_contract.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/sidecar/bridge_contract.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 7 + }, + { + "tool": "ruff", + "path": "services/sidecar/runtime.py", + "code": "F401", + "message": "`json` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/sidecar/runtime.py", + "code": "SIM105", + "message": "Use `contextlib.suppress(KeyboardInterrupt)` instead of `try`-`except`-`pass`", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/sidecar/runtime.py", + "code": "SIM105", + "message": "Use `contextlib.suppress(NotImplementedError)` instead of `try`-`except`-`pass`", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/sidecar_secret_refs.py", + "code": "UP035", + "message": "Import from `collections.abc` instead: `Mapping`", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/startup_lifecycle.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 5 + }, + { + "tool": "ruff", + "path": "services/startup_lifecycle.py", + "code": "UP035", + "message": "Import from `collections.abc` instead: `Callable`, `Iterable`", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/startup_lifecycle.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/startup_lifecycle.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 5 + }, + { + "tool": "ruff", + "path": "services/startup_profile_gate.py", + "code": "F401", + "message": "`dataclasses.asdict` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/startup_profile_gate.py", + "code": "F401", + "message": "`typing.Tuple` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/startup_profile_gate.py", + "code": "RUF100", + "message": "Unused `noqa` directive (non-enabled: `PLW0603`)", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/startup_profile_gate.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/startup_profile_gate.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/startup_profile_gate.py", + "code": "UP035", + "message": "Import from `collections.abc` instead: `Mapping`", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/startup_profile_gate.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/startup_profile_gate.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/startup_profile_gate.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/startup_profile_gate.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 5 + }, + { + "tool": "ruff", + "path": "services/state_dir.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/structured_logging.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 3 + }, + { + "tool": "ruff", + "path": "services/structured_logging.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/structured_logging.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/surface_guard.py", + "code": "C416", + "message": "Unnecessary dict comprehension (rewrite using `dict()`)", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/templates.py", + "code": "C414", + "message": "Unnecessary `list()` call within `sorted()`", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/templates.py", + "code": "F401", + "message": "`copy` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/templates.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 6 + }, + { + "tool": "ruff", + "path": "services/templates.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 4 + }, + { + "tool": "ruff", + "path": "services/templates.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/templates.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/templates.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 3 + }, + { + "tool": "ruff", + "path": "services/tenant_context.py", + "code": "B009", + "message": "Do not call `getattr` with a constant attribute value. It is not any safer than normal property access.", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/tenant_context.py", + "code": "UP035", + "message": "Import from `collections.abc` instead: `Mapping`", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/tenant_context.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 6 + }, + { + "tool": "ruff", + "path": "services/threat_intel_gate.py", + "code": "F401", + "message": "`typing.Any` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/threat_intel_gate.py", + "code": "F401", + "message": "`typing.Dict` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/threat_intel_gate.py", + "code": "F401", + "message": "`typing.Optional` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/threat_intel_gate.py", + "code": "F541", + "message": "f-string without any placeholders", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/threat_intel_gate.py", + "code": "SIM103", + "message": "Return the condition `self._policy != ThreatPolicy.STRICT` directly", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/threat_intel_gate.py", + "code": "UP006", + "message": "Use `tuple` instead of `Tuple` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/threat_intel_gate.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/threat_intel_gate.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/threat_intel_provider.py", + "code": "F401", + "message": "`typing.Any` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/threat_intel_provider.py", + "code": "F401", + "message": "`typing.Optional` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/threat_intel_provider.py", + "code": "SIM102", + "message": "Use a single `if` statement instead of nested `if` statements", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/tool_calling.py", + "code": "RUF019", + "message": "Unnecessary key check before dictionary access", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/tool_calling.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 21 + }, + { + "tool": "ruff", + "path": "services/tool_calling.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/tool_calling.py", + "code": "UP006", + "message": "Use `tuple` instead of `Tuple` for type annotation", + "count": 7 + }, + { + "tool": "ruff", + "path": "services/tool_calling.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/tool_calling.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/tool_calling.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/tool_calling.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 15 + }, + { + "tool": "ruff", + "path": "services/tool_runner.py", + "code": "F401", + "message": "`shlex` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/tool_runner.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 6 + }, + { + "tool": "ruff", + "path": "services/tool_runner.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 11 + }, + { + "tool": "ruff", + "path": "services/tool_runner.py", + "code": "UP006", + "message": "Use `tuple` instead of `Tuple` for type annotation", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/tool_runner.py", + "code": "UP015", + "message": "Unnecessary mode argument", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/tool_runner.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/tool_runner.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/tool_runner.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/tool_runner.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 7 + }, + { + "tool": "ruff", + "path": "services/trace.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 3 + }, + { + "tool": "ruff", + "path": "services/trace_store.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 3 + }, + { + "tool": "ruff", + "path": "services/trace_store.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/trace_store.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/trace_store.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/trace_store.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/transform_common.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 6 + }, + { + "tool": "ruff", + "path": "services/transform_common.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/transform_common.py", + "code": "UP006", + "message": "Use `set` instead of `Set` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/transform_common.py", + "code": "UP015", + "message": "Unnecessary mode argument", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/transform_common.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/transform_common.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/transform_common.py", + "code": "UP035", + "message": "`typing.Set` is deprecated, use `set` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/transform_common.py", + "code": "UP037", + "message": "Remove quotes from type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/transform_common.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 4 + }, + { + "tool": "ruff", + "path": "services/transform_runner.py", + "code": "RUF010", + "message": "Use explicit conversion flag", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/transform_runner.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/transform_runner.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/transform_runner.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/transform_worker.py", + "code": "B009", + "message": "Do not call `getattr` with a constant attribute value. It is not any safer than normal property access.", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/transform_worker.py", + "code": "F401", + "message": "`typing.Any` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/transform_worker.py", + "code": "F401", + "message": "`typing.Dict` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/transform_worker.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/webhook_auth.py", + "code": "N806", + "message": "Variable `IdempotencyStore` in function should be lowercase", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/webhook_auth.py", + "code": "RUF059", + "message": "Unpacked variable `error` is never used", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/webhook_auth.py", + "code": "SIM105", + "message": "Use `contextlib.suppress(ImportError)` instead of `try`-`except`-`pass`", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/webhook_auth.py", + "code": "UP006", + "message": "Use `tuple` instead of `Tuple` for type annotation", + "count": 3 + }, + { + "tool": "ruff", + "path": "services/webhook_auth.py", + "code": "UP035", + "message": "Import from `collections.abc` instead: `Mapping`", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/webhook_auth.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/webhook_auth.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 4 + }, + { + "tool": "ruff", + "path": "services/webhook_mapping.py", + "code": "F401", + "message": "`os` imported but unused", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/webhook_mapping.py", + "code": "SIM102", + "message": "Use a single `if` statement instead of nested `if` statements", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/webhook_mapping.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 11 + }, + { + "tool": "ruff", + "path": "services/webhook_mapping.py", + "code": "UP006", + "message": "Use `frozenset` instead of `FrozenSet` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/webhook_mapping.py", + "code": "UP006", + "message": "Use `list` instead of `List` for type annotation", + "count": 6 + }, + { + "tool": "ruff", + "path": "services/webhook_mapping.py", + "code": "UP006", + "message": "Use `set` instead of `Set` for type annotation", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/webhook_mapping.py", + "code": "UP006", + "message": "Use `tuple` instead of `Tuple` for type annotation", + "count": 3 + }, + { + "tool": "ruff", + "path": "services/webhook_mapping.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/webhook_mapping.py", + "code": "UP035", + "message": "`typing.FrozenSet` is deprecated, use `frozenset` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/webhook_mapping.py", + "code": "UP035", + "message": "`typing.List` is deprecated, use `list` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/webhook_mapping.py", + "code": "UP035", + "message": "`typing.Set` is deprecated, use `set` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/webhook_mapping.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/webhook_mapping.py", + "code": "UP037", + "message": "Remove quotes from type annotation", + "count": 2 + }, + { + "tool": "ruff", + "path": "services/webhook_mapping.py", + "code": "UP045", + "message": "Use `X | None` for type annotations", + "count": 4 + }, + { + "tool": "ruff", + "path": "services/workflow_portability.py", + "code": "UP006", + "message": "Use `dict` instead of `Dict` for type annotation", + "count": 17 + }, + { + "tool": "ruff", + "path": "services/workflow_portability.py", + "code": "UP006", + "message": "Use `tuple` instead of `Tuple` for type annotation", + "count": 4 + }, + { + "tool": "ruff", + "path": "services/workflow_portability.py", + "code": "UP035", + "message": "Import from `collections.abc` instead: `Iterable`", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/workflow_portability.py", + "code": "UP035", + "message": "`typing.Dict` is deprecated, use `dict` instead", + "count": 1 + }, + { + "tool": "ruff", + "path": "services/workflow_portability.py", + "code": "UP035", + "message": "`typing.Tuple` is deprecated, use `tuple` instead", + "count": 1 + } + ] +} diff --git a/tests/test_r217_static_analysis_policy.py b/tests/test_r217_static_analysis_policy.py new file mode 100644 index 0000000..a339445 --- /dev/null +++ b/tests/test_r217_static_analysis_policy.py @@ -0,0 +1,521 @@ +import json +import sys +import tempfile +import unittest +from collections import Counter +from pathlib import Path +from types import SimpleNamespace + +from scripts import verify_static_analysis_policy as policy_module + + +class TestStaticAnalysisPolicy(unittest.TestCase): + def _policy(self) -> dict: + return { + "schema_version": 1, + "review": { + "owner": "maintainers", + "reviewed_at": "2026-07-11", + "next_review_by": "2026-10-11", + }, + "tools": { + "ruff": {"version": "0.15.20"}, + "mypy": {"version": "2.2.0"}, + }, + "production_roots": ["config.py", "pkg"], + "excluded_paths": [ + { + "path": "pkg/generated.py", + "reason": "generated fixture excluded from source ownership", + } + ], + "strict_paths": ["pkg/clean.py"], + "baseline": [ + { + "tool": "ruff", + "path": "pkg/owned.py", + "code": "F401", + "message": "unused import", + "count": 1, + } + ], + } + + def _create_repo(self, root: Path) -> None: + (root / "config.py").write_text("VALUE = 1\n", encoding="utf-8") + (root / "pkg" / "nested").mkdir(parents=True) + (root / "pkg" / "owned.py").write_text("import os\n", encoding="utf-8") + (root / "pkg" / "clean.py").write_text("VALUE: int = 1\n", encoding="utf-8") + (root / "pkg" / "generated.py").write_text("generated = True\n", encoding="utf-8") + (root / "pkg" / "nested" / "child.py").write_text( + "CHILD = True\n", encoding="utf-8" + ) + + def test_policy_validation_rejects_missing_and_unsafe_paths(self): + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + self._create_repo(root) + policy = self._policy() + policy["production_roots"].extend(["missing", "../outside"]) + policy["strict_paths"].append("pkg/missing.py") + policy["excluded_paths"].append( + {"path": "reference/untrusted.py", "reason": "not inside an owned root"} + ) + + failures = policy_module.validate_policy(root, policy) + + self.assertTrue(any("missing" in failure for failure in failures)) + self.assertTrue(any("unsafe" in failure for failure in failures)) + self.assertTrue(any("strict path" in failure for failure in failures)) + self.assertTrue(any("excluded path" in failure for failure in failures)) + + def test_owned_file_discovery_is_recursive_and_excludes_only_declared_paths(self): + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + self._create_repo(root) + + files = policy_module.discover_owned_python_files(root, self._policy()) + + self.assertEqual( + files, + ( + "config.py", + "pkg/clean.py", + "pkg/nested/child.py", + "pkg/owned.py", + ), + ) + + def test_exact_baseline_passes(self): + policy = self._policy() + current = Counter( + { + policy_module.Diagnostic( + tool="ruff", + path="pkg/owned.py", + code="F401", + message="unused import", + ): 1 + } + ) + + self.assertEqual(policy_module.compare_diagnostics(policy, current), []) + + def test_new_and_resolved_debt_both_fail_the_ratchet(self): + policy = self._policy() + key = policy_module.Diagnostic( + tool="ruff", + path="pkg/owned.py", + code="F401", + message="unused import", + ) + + increased = policy_module.compare_diagnostics(policy, Counter({key: 2})) + resolved = policy_module.compare_diagnostics(policy, Counter()) + + self.assertTrue(any("new debt" in failure for failure in increased)) + self.assertTrue(any("stale baseline" in failure for failure in resolved)) + + def test_strict_path_rejects_even_baselined_diagnostic(self): + policy = self._policy() + policy["baseline"].append( + { + "tool": "mypy", + "path": "pkg/clean.py", + "code": "assignment", + "message": "incompatible assignment", + "count": 1, + } + ) + current = Counter( + { + policy_module.Diagnostic( + tool="ruff", + path="pkg/owned.py", + code="F401", + message="unused import", + ): 1, + policy_module.Diagnostic( + tool="mypy", + path="pkg/clean.py", + code="assignment", + message="incompatible assignment", + ): 1, + } + ) + + failures = policy_module.compare_diagnostics(policy, current) + + self.assertTrue(any("strict path" in failure for failure in failures)) + + def test_tool_version_drift_is_rejected(self): + failures = policy_module.validate_tool_versions( + self._policy(), {"ruff": "0.15.19", "mypy": "2.2.0"} + ) + + self.assertEqual( + failures, + ["ruff version drift: expected 0.15.20, found 0.15.19"], + ) + + def test_policy_validation_rejects_noncanonical_baseline_order(self): + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + self._create_repo(root) + policy = self._policy() + policy["baseline"] = [ + { + "tool": "ruff", + "path": "pkg/owned.py", + "code": "F401", + "message": "unused import", + "count": 1, + }, + { + "tool": "mypy", + "path": "pkg/owned.py", + "code": "assignment", + "message": "bad assignment", + "count": 1, + }, + ] + + failures = policy_module.validate_policy(root, policy) + + self.assertIn("baseline must use canonical sorted serialization", failures) + + def test_ruff_json_is_normalized_to_repo_relative_diagnostics(self): + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + source = root / "pkg" / "owned.py" + raw = json.dumps( + [ + { + "filename": str(source), + "code": "F401", + "message": " unused import ", + "location": {"row": 1, "column": 1}, + } + ] + ) + + result = policy_module.parse_ruff_output(raw, root) + + self.assertEqual( + result, + Counter( + { + policy_module.Diagnostic( + tool="ruff", + path="pkg/owned.py", + code="F401", + message="unused import", + ): 1 + } + ), + ) + + def test_mypy_json_lines_are_normalized_without_line_numbers(self): + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + source = root / "pkg" / "owned.py" + raw = json.dumps( + { + "file": str(source), + "line": 4, + "column": 2, + "message": " Name is not defined ", + "hint": None, + "code": "name-defined", + "severity": "error", + } + ) + + result = policy_module.parse_mypy_output(raw, root) + + self.assertEqual( + result, + Counter( + { + policy_module.Diagnostic( + tool="mypy", + path="pkg/owned.py", + code="name-defined", + message="Name is not defined", + ): 1 + } + ), + ) + + def test_serialized_baseline_is_deterministic_and_sorted(self): + diagnostics = Counter( + { + policy_module.Diagnostic("ruff", "z.py", "F401", "unused"): 2, + policy_module.Diagnostic("mypy", "a.py", "assignment", "bad"): 1, + } + ) + + self.assertEqual( + policy_module.serialize_baseline(diagnostics), + [ + { + "tool": "mypy", + "path": "a.py", + "code": "assignment", + "message": "bad", + "count": 1, + }, + { + "tool": "ruff", + "path": "z.py", + "code": "F401", + "message": "unused", + "count": 2, + }, + ], + ) + + def test_quality_requirement_pins_must_match_policy(self): + policy = self._policy() + + self.assertEqual( + policy_module.validate_requirement_pins( + policy, ["ruff==0.15.20", "mypy==2.2.0"] + ), + [], + ) + self.assertEqual( + policy_module.validate_requirement_pins( + policy, ["ruff>=0.15.20", "mypy==2.1.0"] + ), + [ + "mypy requirement drift: expected mypy==2.2.0, found mypy==2.1.0", + "ruff requirement drift: expected ruff==0.15.20, found ruff>=0.15.20", + ], + ) + + def test_tool_runner_uses_current_interpreter_and_combines_diagnostics(self): + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + self._create_repo(root) + commands: list[tuple[str, ...]] = [] + + def runner(command, **kwargs): + self.assertEqual(kwargs["cwd"], root) + self.assertFalse(kwargs.get("shell", False)) + commands.append(tuple(command)) + if command[-1] == "--version": + name = command[2] + output = ( + "ruff 0.15.20\n" + if name == "ruff" + else "mypy 2.2.0 (compiled: yes)\n" + ) + return SimpleNamespace(returncode=0, stdout=output, stderr="") + if command[2] == "ruff": + return SimpleNamespace( + returncode=1, + stdout=json.dumps( + [ + { + "filename": str(root / "pkg" / "owned.py"), + "code": "F401", + "message": "unused import", + } + ] + ), + stderr="", + ) + return SimpleNamespace( + returncode=1, + stdout=json.dumps( + { + "file": str(root / "pkg" / "nested" / "child.py"), + "line": 1, + "column": 1, + "message": "missing annotation", + "code": "no-untyped-def", + "severity": "error", + } + ), + stderr="", + ) + + versions, diagnostics = policy_module.run_static_analysis( + root, self._policy(), runner=runner + ) + + self.assertEqual(versions, {"ruff": "0.15.20", "mypy": "2.2.0"}) + self.assertEqual(sum(diagnostics.values()), 2) + self.assertEqual(len(commands), 4) + for command in commands: + self.assertEqual(command[:2], (sys.executable, "-m")) + self.assertIn(command[2], {"ruff", "mypy"}) + ruff_command = next(command for command in commands if "check" in command) + mypy_command = next(command for command in commands if "--output" in command) + self.assertIn("--no-cache", ruff_command) + self.assertIn("json", ruff_command) + self.assertIn("--no-incremental", mypy_command) + self.assertIn("--explicit-package-bases", mypy_command) + self.assertIn("--no-warn-unused-configs", mypy_command) + self.assertIn("--no-error-summary", mypy_command) + self.assertIn("--no-site-packages", mypy_command) + self.assertIn("--ignore-missing-imports", mypy_command) + self.assertIn("json", mypy_command) + + def test_tool_runner_rejects_abnormal_tool_failure_without_echoing_stderr(self): + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + self._create_repo(root) + + def runner(command, **_kwargs): + if command[-1] == "--version": + name = command[2] + return SimpleNamespace( + returncode=0, + stdout=f"{name} 0.15.20\n" + if name == "ruff" + else "mypy 2.2.0\n", + stderr="", + ) + return SimpleNamespace( + returncode=2, + stdout="", + stderr="private C:\\Users\\name\\secret tool failure", + ) + + with self.assertRaises(policy_module.ToolExecutionError) as ctx: + policy_module.run_static_analysis(root, self._policy(), runner=runner) + + self.assertEqual(str(ctx.exception), "ruff execution failed with exit code 2") + self.assertNotIn("private", str(ctx.exception)) + + def test_updated_policy_baseline_does_not_mutate_input(self): + policy = self._policy() + diagnostics = Counter( + {policy_module.Diagnostic("mypy", "pkg/owned.py", "assignment", "bad"): 1} + ) + + updated = policy_module.with_updated_baseline(policy, diagnostics) + + self.assertNotEqual(updated["baseline"], policy["baseline"]) + self.assertEqual(policy["baseline"][0]["tool"], "ruff") + self.assertEqual(updated["baseline"][0]["tool"], "mypy") + + def test_evaluate_policy_reports_requirement_and_installed_version_drift(self): + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + self._create_repo(root) + policy = self._policy() + policy["baseline"] = [] + + def runner(command, **_kwargs): + if command[-1] == "--version": + return SimpleNamespace( + returncode=0, + stdout=( + "ruff 0.15.19\n" + if command[2] == "ruff" + else "mypy 2.2.0\n" + ), + stderr="", + ) + return SimpleNamespace( + returncode=0, + stdout="[]" if command[2] == "ruff" else "", + stderr="", + ) + + failures, diagnostics = policy_module.evaluate_policy( + root, + policy, + requirement_lines=["ruff>=0.15.20", "mypy==2.2.0"], + runner=runner, + ) + + self.assertEqual(diagnostics, Counter()) + self.assertIn( + "ruff requirement drift: expected ruff==0.15.20, found ruff>=0.15.20", + failures, + ) + self.assertIn( + "ruff version drift: expected 0.15.20, found 0.15.19", failures + ) + + +class TestRepositoryStaticAnalysisPolicy(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.repo_root = Path(__file__).resolve().parents[1] + cls.policy_path = cls.repo_root / "tests" / "static_analysis_policy.json" + cls.requirements_path = cls.repo_root / "requirements-quality.txt" + + def test_repository_policy_and_quality_pins_are_valid(self): + policy = json.loads(self.policy_path.read_text(encoding="utf-8")) + requirement_lines = self.requirements_path.read_text(encoding="utf-8").splitlines() + + self.assertEqual(policy_module.validate_policy(self.repo_root, policy), []) + self.assertEqual( + policy_module.validate_requirement_pins(policy, requirement_lines), [] + ) + self.assertEqual( + policy["production_roots"], + [ + "__init__.py", + "config.py", + "api", + "connector", + "models", + "nodes", + "services", + "scripts", + ], + ) + self.assertGreater(len(policy_module.discover_owned_python_files(self.repo_root, policy)), 200) + self.assertGreaterEqual(len(policy["strict_paths"]), 1) + + def test_repository_execution_surfaces_use_shared_verifier(self): + expected = "scripts/verify_static_analysis_policy.py" + surfaces = { + ".pre-commit-config.yaml": self.repo_root / ".pre-commit-config.yaml", + "windows full gate": self.repo_root / "scripts" / "run_full_tests_windows.ps1", + "linux full gate": self.repo_root / "scripts" / "run_full_tests_linux.sh", + "pre-commit CI": self.repo_root / ".github" / "workflows" / "pre-commit.yml", + "unit CI": self.repo_root / ".github" / "workflows" / "ci.yml", + } + for label, path in surfaces.items(): + with self.subTest(surface=label): + content = path.read_text(encoding="utf-8") + self.assertIn(expected, content) + self.assertIn("requirements-quality.txt", content) + + def test_precommit_hook_has_an_isolated_pinned_tool_environment(self): + content = (self.repo_root / ".pre-commit-config.yaml").read_text( + encoding="utf-8" + ) + hook = content.split("- id: static-analysis-policy", 1)[1].split( + "# Secret detection", 1 + )[0] + + self.assertIn("language: python", hook) + self.assertIn("ruff==0.15.20", hook) + self.assertIn("mypy==2.2.0", hook) + + def test_quality_tools_are_not_runtime_requirements(self): + runtime_requirements = (self.repo_root / "requirements.txt").read_text( + encoding="utf-8" + ) + project_config = (self.repo_root / "pyproject.toml").read_text(encoding="utf-8") + + self.assertNotIn("ruff", runtime_requirements.lower()) + self.assertNotIn("mypy", runtime_requirements.lower()) + dependencies_block = project_config.split("[project.urls]", 1)[0] + self.assertNotIn("ruff", dependencies_block.lower()) + self.assertNotIn("mypy", dependencies_block.lower()) + self.assertIn("explicit_package_bases = true", project_config) + self.assertIn("no_site_packages = true", project_config) + self.assertIn("ignore_missing_imports = true", project_config) + + +if __name__ == "__main__": + unittest.main()