fix(seedgo): skip *(disabled) files in audits like .archive/ dirs (td-103)
Disabled files (AIPass convention: rename name(disabled).py instead of delete) are intentionally-parked inert code, but seedgo audited them as live source — ai_mail's dashboard_sync(disabled).py dragged it to 99%, blocking green CI. - Add is_disabled_file() + DISABLED_FILE_MARKER to skip_dirs.py (single source of truth alongside SOURCE_SKIP_DIRS) - Apply in branch_audit, dead_code, unused_function, test_quality checkers + test_map function_scanner + checklist directory mode - New test in test_coverage_audit.py Verified: ai_mail 99->100%, seedgo self-audit 100%, 1060 seedgo tests pass, @cli/@flow unchanged at 100%. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
a231c7d26e
commit
95a2d1a254
@@ -24,7 +24,7 @@ from pathlib import Path
|
||||
from aipass.prax import logger
|
||||
from aipass.seedgo.apps.handlers.json import json_handler
|
||||
from aipass.seedgo.apps.handlers.bypass.utils import is_bypassed
|
||||
from aipass.seedgo.apps.handlers.aipass_standards.skip_dirs import SOURCE_SKIP_DIRS
|
||||
from aipass.seedgo.apps.handlers.aipass_standards.skip_dirs import SOURCE_SKIP_DIRS, is_disabled_file
|
||||
|
||||
AUDIT_SCOPE = "branch_level"
|
||||
|
||||
@@ -43,8 +43,8 @@ _SKIP_DIRS = SOURCE_SKIP_DIRS | {"tests", "json_templates"}
|
||||
|
||||
|
||||
def _should_skip(path: Path) -> bool:
|
||||
"""Check whether any parent directory component is in the skip set."""
|
||||
return any(part in _SKIP_DIRS for part in path.parts)
|
||||
"""Check whether any parent directory component is in the skip set or file is disabled."""
|
||||
return any(part in _SKIP_DIRS for part in path.parts) or is_disabled_file(path.name)
|
||||
|
||||
|
||||
def _collect_scannable_files(apps_dir: Path) -> list[Path]:
|
||||
|
||||
@@ -14,6 +14,14 @@ products, not committed source — scanning them causes local-vs-CI
|
||||
audit divergence (FPLAN-0261).
|
||||
"""
|
||||
|
||||
DISABLED_FILE_MARKER = "(disabled)"
|
||||
|
||||
|
||||
def is_disabled_file(name: str) -> bool:
|
||||
"""Return True if filename contains the (disabled) convention marker."""
|
||||
return DISABLED_FILE_MARKER in name
|
||||
|
||||
|
||||
SOURCE_SKIP_DIRS: frozenset[str] = frozenset(
|
||||
{
|
||||
# Build / cache
|
||||
|
||||
@@ -29,7 +29,7 @@ from pathlib import Path
|
||||
from aipass.prax import logger
|
||||
from aipass.seedgo.apps.handlers.json import json_handler
|
||||
from aipass.seedgo.apps.handlers.bypass.utils import is_bypassed
|
||||
from aipass.seedgo.apps.handlers.aipass_standards.skip_dirs import SOURCE_SKIP_DIRS
|
||||
from aipass.seedgo.apps.handlers.aipass_standards.skip_dirs import SOURCE_SKIP_DIRS, is_disabled_file
|
||||
|
||||
AUDIT_SCOPE = "branch_level"
|
||||
|
||||
@@ -175,6 +175,11 @@ def _should_skip_dir(name: str) -> bool:
|
||||
return name in SKIP_DIRS or name.startswith(".")
|
||||
|
||||
|
||||
def _should_skip_file(name: str) -> bool:
|
||||
"""Check if a file should be skipped (disabled convention)."""
|
||||
return is_disabled_file(name)
|
||||
|
||||
|
||||
def _find_test_files_broad(branch_path: Path) -> list[Path]:
|
||||
"""Find all test files for module coverage analysis.
|
||||
|
||||
@@ -201,7 +206,7 @@ def _find_test_files_broad(branch_path: Path) -> list[Path]:
|
||||
for py_file in sorted(branch_path.rglob("*.py")):
|
||||
if any(_should_skip_dir(part) for part in py_file.relative_to(branch_path).parts):
|
||||
continue
|
||||
if py_file.name in ("__init__.py", "conftest.py"):
|
||||
if py_file.name in ("__init__.py", "conftest.py") or _should_skip_file(py_file.name):
|
||||
continue
|
||||
if py_file.name.startswith("test_") or py_file.name.endswith("_test.py"):
|
||||
resolved = py_file.resolve()
|
||||
@@ -245,7 +250,12 @@ def _collect_testable_modules(branch_path: Path) -> set[str]:
|
||||
modules_dir = apps_dir / "modules"
|
||||
if modules_dir.is_dir():
|
||||
for item in sorted(modules_dir.iterdir()):
|
||||
if item.is_file() and item.suffix == ".py" and item.name != "__init__.py":
|
||||
if (
|
||||
item.is_file()
|
||||
and item.suffix == ".py"
|
||||
and item.name != "__init__.py"
|
||||
and not _should_skip_file(item.name)
|
||||
):
|
||||
modules.add(item.stem)
|
||||
|
||||
handlers_dir = apps_dir / "handlers"
|
||||
@@ -254,10 +264,19 @@ def _collect_testable_modules(branch_path: Path) -> set[str]:
|
||||
if _should_skip_dir(item.name):
|
||||
continue
|
||||
if item.is_dir() and item.name != "__pycache__":
|
||||
has_py = any(f.suffix == ".py" and f.name != "__init__.py" for f in item.iterdir() if f.is_file())
|
||||
has_py = any(
|
||||
f.suffix == ".py" and f.name != "__init__.py" and not _should_skip_file(f.name)
|
||||
for f in item.iterdir()
|
||||
if f.is_file()
|
||||
)
|
||||
if has_py:
|
||||
modules.add(item.name)
|
||||
elif item.is_file() and item.suffix == ".py" and item.name != "__init__.py":
|
||||
elif (
|
||||
item.is_file()
|
||||
and item.suffix == ".py"
|
||||
and item.name != "__init__.py"
|
||||
and not _should_skip_file(item.name)
|
||||
):
|
||||
modules.add(item.stem)
|
||||
|
||||
return modules
|
||||
|
||||
@@ -32,7 +32,7 @@ from pathlib import Path
|
||||
from aipass.prax import logger
|
||||
from aipass.seedgo.apps.handlers.json import json_handler
|
||||
from aipass.seedgo.apps.handlers.bypass.utils import is_bypassed
|
||||
from aipass.seedgo.apps.handlers.aipass_standards.skip_dirs import SOURCE_SKIP_DIRS
|
||||
from aipass.seedgo.apps.handlers.aipass_standards.skip_dirs import SOURCE_SKIP_DIRS, is_disabled_file
|
||||
|
||||
AUDIT_SCOPE = "branch_level"
|
||||
|
||||
@@ -61,8 +61,8 @@ _MAIN_BLOCK_RE = re.compile(
|
||||
|
||||
|
||||
def _should_skip(path: Path) -> bool:
|
||||
"""Return True if any path component is in the skip set."""
|
||||
return any(part in SKIP_DIRS for part in path.parts)
|
||||
"""Return True if any path component is in the skip set or file is disabled."""
|
||||
return any(part in SKIP_DIRS for part in path.parts) or is_disabled_file(path.name)
|
||||
|
||||
|
||||
def _collect_python_files(branch_path: Path) -> list[Path]:
|
||||
|
||||
@@ -12,6 +12,7 @@ from pathlib import Path
|
||||
from typing import Any, Dict, List
|
||||
from aipass.prax import logger
|
||||
from aipass.seedgo.apps.handlers.bypass import ignore_handler
|
||||
from aipass.seedgo.apps.handlers.aipass_standards.skip_dirs import is_disabled_file
|
||||
from aipass.seedgo.apps.handlers.json import json_handler
|
||||
from aipass.seedgo.apps.handlers.test_map.function_scanner import scan_branch
|
||||
|
||||
@@ -50,7 +51,7 @@ def _collect_py_files(branch_path: Path) -> List[Dict[str, str]]:
|
||||
return [
|
||||
{"file": str(f), "name": f.name}
|
||||
for f in apps_dir.rglob("*.py")
|
||||
if f.name != "__init__.py" and not any(p in str(f).lower() for p in ign)
|
||||
if f.name != "__init__.py" and not is_disabled_file(f.name) and not any(p in str(f).lower() for p in ign)
|
||||
]
|
||||
|
||||
|
||||
|
||||
@@ -112,6 +112,8 @@ def _should_skip_file(py_file: Path) -> bool:
|
||||
"""Check if file should be skipped based on naming/path rules."""
|
||||
if py_file.name.startswith("_"):
|
||||
return True
|
||||
if "(disabled)" in py_file.name:
|
||||
return True
|
||||
return any(part.startswith(".") for part in py_file.parts)
|
||||
|
||||
|
||||
|
||||
@@ -312,7 +312,7 @@ def handle_command(command: str, args: List[str]) -> bool:
|
||||
# Directory mode — run checklist on all .py files in directory
|
||||
if resolved.is_dir():
|
||||
py_files = sorted(resolved.glob("*.py"))
|
||||
py_files = [f for f in py_files if not f.name.startswith("_")]
|
||||
py_files = [f for f in py_files if not f.name.startswith("_") and "(disabled)" not in f.name]
|
||||
if not py_files:
|
||||
error("No .py files found in directory", suggestion=f"Directory: {resolved}")
|
||||
return True
|
||||
@@ -390,7 +390,8 @@ def print_help() -> None:
|
||||
console.print("[yellow]USAGE:[/yellow]")
|
||||
console.print(" [green]drone @seedgo checklist <file>[/green] [dim]# Check single file[/dim]")
|
||||
console.print(
|
||||
" [green]drone @seedgo checklist <directory>[/green] [dim]# Check all .py files in directory[/dim]"
|
||||
" [green]drone @seedgo checklist <directory>[/green]"
|
||||
" [dim]# Check all .py files in directory[/dim]"
|
||||
)
|
||||
console.print(
|
||||
" [green]drone @seedgo checklist --pack <pack> <file>[/green] [dim]# Check with specific pack[/dim]"
|
||||
|
||||
@@ -1103,6 +1103,21 @@ class TestCollectPyFiles:
|
||||
assert "module.py" in names
|
||||
assert "xskip_bad.py" not in names
|
||||
|
||||
def test_excludes_disabled_files(self, tmp_path):
|
||||
"""Files with (disabled) in the name are excluded from collection."""
|
||||
from aipass.seedgo.apps.handlers.audit.branch_audit import (
|
||||
_collect_py_files,
|
||||
)
|
||||
|
||||
apps_dir = tmp_path / "apps"
|
||||
apps_dir.mkdir()
|
||||
(apps_dir / "module.py").write_text("pass", encoding="utf-8")
|
||||
(apps_dir / "dashboard_sync(disabled).py").write_text("pass", encoding="utf-8")
|
||||
result = _collect_py_files(tmp_path)
|
||||
names = [f["name"] for f in result]
|
||||
assert "module.py" in names
|
||||
assert "dashboard_sync(disabled).py" not in names
|
||||
|
||||
|
||||
class TestExtractBranchLevelViolations:
|
||||
"""Tests for _extract_branch_level_violations."""
|
||||
|
||||
Reference in New Issue
Block a user