feat(system): feat(seedgo): add handler_import standard #34 + ruff format enforcement in ruff_check v1.2.0

Co-Authored-By: @devpulse <devpulse@aipass>
This commit is contained in:
AIOSAI
2026-04-26 00:28:09 -07:00
co-authored by @devpulse
parent 2d306d4f4f
commit b03f8b57ed
6 changed files with 691 additions and 34 deletions
@@ -0,0 +1,119 @@
# Handler Import Standard
**Status:** Active v1
**Date:** 2026-04-26
---
## Core Rule: Every apps/__init__.py Must Import Handlers
Every AIPass branch with an `apps/` package must include `from . import handlers` in its `apps/__init__.py`. Without this explicit import, Python 3.10's `mock.patch` cannot resolve handler subpackages through the attribute chain.
---
## Why This Matters
**The problem:** `mock.patch("aipass.branch.apps.handlers.some_module")` traverses the dotted path using `getattr`. In Python 3.10, if `handlers` was never explicitly imported in `apps/__init__.py`, the `getattr(apps, "handlers")` call raises `AttributeError` -- even though the `handlers/` directory exists on disk with its own `__init__.py`.
**What goes wrong without the import:**
1. **Tests silently break** -- `mock.patch` targeting handler submodules raises `AttributeError` instead of patching.
2. **CI false greens** -- if the test catches the exception or skips, violations slip through undetected.
3. **3.10 vs 3.11 divergence** -- Python 3.11+ is more lenient about lazy subpackage resolution. Code that works on 3.11 breaks on 3.10, which AIPass CI uses.
**What the import does:**
```python
from . import handlers
```
This single line forces Python to import and register the `handlers` subpackage on the `apps` namespace at import time. After that, `getattr(apps, "handlers")` succeeds and `mock.patch` can walk the full dotted path.
---
## What the Checker Validates
The handler_import standard checks **one thing**: does `apps/__init__.py` contain the string `from . import handlers`?
- **Scope:** `AUDIT_SCOPE = "branch_level"` -- one check per branch
- **Pass:** The string `from . import handlers` is found in the file content -- score 100
- **Fail:** The string is missing or the file does not exist -- score 0
---
## Examples
**Good -- explicit handler import present:**
```python
# apps/__init__.py
from . import handlers
from . import modules
```
**Good -- import with trailing comment:**
```python
# apps/__init__.py
from . import handlers # required for mock.patch resolution
```
**Bad -- empty init:**
```python
# apps/__init__.py
```
**Bad -- modules imported but not handlers:**
```python
# apps/__init__.py
from . import modules
```
---
## Scoring
| Condition | Score |
|-----------|-------|
| `from . import handlers` found in apps/__init__.py | 100 |
| Import missing from apps/__init__.py | 0 |
| apps/__init__.py not found | 0 |
| apps/__init__.py not readable | 0 |
| Bypassed via `.seedgo/bypass.json` | 100 |
Binary pass/fail -- there is no partial credit. Either the import is there or it is not.
---
## How to Fix
Add the import line to `apps/__init__.py`. That is it.
**Before:**
```python
# apps/__init__.py
from . import modules
```
**After:**
```python
# apps/__init__.py
from . import handlers
from . import modules
```
---
## Bypass
If a branch genuinely does not have a `handlers/` subpackage (rare edge case), add a bypass rule in `.seedgo/bypass.json`:
```json
{
"standard": "handler_import",
"file": "apps/__init__.py"
}
```
---
## Summary
1. **Every apps/__init__.py needs `from . import handlers`** -- required for mock.patch resolution on Python 3.10
2. **One check per branch** -- scope is `branch_level`
3. **Binary scoring** -- 100 (import present) or 0 (import missing)
4. **Fix is one line** -- add `from . import handlers` to apps/__init__.py
@@ -0,0 +1,183 @@
# =================== AIPass ====================
# Name: handler_import_check.py
# Description: Handler Import Standards Checker
# Version: 1.0.0
# Created: 2026-04-26
# Modified: 2026-04-26
# =============================================
"""
Handler Import Standards Checker
Validates that every branch's apps/__init__.py contains
``from . import handlers`` to ensure Python 3.10 mock.patch
can resolve handler subpackages correctly.
Score: 100 (import present) or 0 (missing / file absent).
"""
from pathlib import Path
from aipass.prax import logger
from aipass.seedgo.apps.handlers.json import json_handler
AUDIT_SCOPE = "branch_level"
# =============================================
# BYPASS HELPER
# =============================================
def is_bypassed(
file_path: str,
standard: str,
line: int | None = None,
bypass_rules: list | None = None,
) -> bool:
"""Check if a violation should be bypassed."""
if not bypass_rules:
return False
for rule in bypass_rules:
if rule.get("standard") and rule.get("standard") != standard:
continue
rule_file = rule.get("file", "")
if rule_file and rule_file not in file_path:
continue
rule_lines = rule.get("lines", [])
if rule_lines and line is not None and line not in rule_lines:
continue
return True
return False
# =============================================
# BRANCH-LEVEL CHECK (audit pipeline entry)
# =============================================
def check_branch(branch_path: str, bypass_rules: list | None = None) -> dict:
"""
Check that a branch's apps/__init__.py contains ``from . import handlers``.
Args:
branch_path: Path to branch root (e.g., src/aipass/seedgo)
bypass_rules: Optional list of bypass rules to skip certain checks
Returns:
dict: {
'passed': bool,
'score': int,
'checks': [{'name': str, 'passed': bool, 'message': str}],
'standard': 'HANDLER_IMPORT'
}
"""
bp = Path(branch_path)
# Check if entire standard is bypassed
if is_bypassed(branch_path, "handler_import", bypass_rules=bypass_rules):
result = {
"passed": True,
"checks": [
{
"name": "Bypassed",
"passed": True,
"message": "Standard bypassed via .seedgo/bypass.json",
}
],
"score": 100,
"standard": "HANDLER_IMPORT",
}
json_handler.log_operation(
"check_completed",
{"branch": branch_path, "score": 100, "standard": "handler_import"},
)
return result
init_file = bp / "apps" / "__init__.py"
if not init_file.exists():
message = "apps/__init__.py not found"
logger.info("handler_import check: %s in %s", message, branch_path)
result = {
"passed": False,
"checks": [
{
"name": "Handler import present",
"passed": False,
"message": message,
}
],
"score": 0,
"standard": "HANDLER_IMPORT",
}
json_handler.log_operation(
"check_completed",
{"branch": branch_path, "score": 0, "standard": "handler_import"},
)
return result
# Read the file and check for the import line
try:
content = init_file.read_text(encoding="utf-8")
except OSError as exc:
logger.info("handler_import check: cannot read %s: %s", init_file, exc)
result = {
"passed": False,
"checks": [
{
"name": "Handler import present",
"passed": False,
"message": f"Cannot read apps/__init__.py: {exc}",
}
],
"score": 0,
"standard": "HANDLER_IMPORT",
}
json_handler.log_operation(
"check_completed",
{"branch": branch_path, "score": 0, "standard": "handler_import"},
)
return result
if "from . import handlers" in content:
result = {
"passed": True,
"checks": [
{
"name": "Handler import present",
"passed": True,
"message": ("apps/__init__.py contains 'from . import handlers'"),
}
],
"score": 100,
"standard": "HANDLER_IMPORT",
}
else:
result = {
"passed": False,
"checks": [
{
"name": "Handler import present",
"passed": False,
"message": (
"apps/__init__.py is missing 'from . import handlers'"
" -- Python 3.10 mock.patch cannot resolve handler"
" subpackages without an explicit import in the"
" parent __init__.py"
),
}
],
"score": 0,
"standard": "HANDLER_IMPORT",
}
json_handler.log_operation(
"check_completed",
{
"branch": branch_path,
"score": result["score"],
"standard": "handler_import",
},
)
return result
@@ -0,0 +1,90 @@
# =================== AIPass ====================
# Name: handler_import_content.py
# Description: Handler Import Standards Content Handler
# Version: 1.0.0
# Created: 2026-04-26
# Modified: 2026-04-26
# =============================================
"""
Handler Import Standards Content Handler
Provides formatted handler import standards content.
Module orchestrates, handler implements.
"""
from aipass.seedgo.apps.handlers.json import json_handler
def get_handler_import_standards() -> str:
"""Return formatted handler import standards content with Rich markup.
Returns:
str: Formatted standards text with Rich styling
"""
lines = [
"[bold red]HANDLER IMPORT STANDARD[/bold red]",
"",
"[bold cyan]CORE RULE:[/bold cyan] Every apps/__init__.py must contain 'from . import handlers'",
"",
"[yellow]RULE:[/yellow] Python 3.10 mock.patch resolution requires explicit subpackage imports in __init__.py.",
" Without 'from . import handlers', mock.patch() targeting handler"
" submodules fails with AttributeError at test time.",
"",
"─" * 70,
"",
"[bold cyan]WHY THIS MATTERS:[/bold cyan]",
"",
" [red]✗[/red] mock.patch('aipass.branch.apps.handlers.some_handler') fails silently",
" [red]✗[/red] Python 3.10 getattr resolution needs the subpackage pre-imported",
" [red]✗[/red] Tests pass on 3.11+ but break on 3.10 without the explicit import",
" [red]✗[/red] CI uses 3.10 -- broken patches mean false green tests",
"",
"─" * 70,
"",
"[bold cyan]WHAT IS CHECKED:[/bold cyan]",
"",
" [yellow]Scope:[/yellow] branch_level -- one check per branch",
" [yellow]Check:[/yellow] Does apps/__init__.py contain 'from . import handlers'?",
" [yellow]Pass:[/yellow] Import found → [green]score 100[/green]",
" [yellow]Fail:[/yellow] Import missing → [red]score 0[/red]",
"",
"─" * 70,
"",
"[bold cyan]EXAMPLES:[/bold cyan]",
"",
"[bold]Good (explicit handler import):[/bold]",
" [green]✓[/green] [dim]from . import handlers[/dim]",
" [green]✓[/green] [dim]from . import modules[/dim]",
" [green]✓[/green] [dim]from . import handlers # noqa[/dim]",
"",
"[bold]Bad (missing handler import):[/bold]",
" [red]✗[/red] [dim]# empty __init__.py[/dim]",
" [red]✗[/red] [dim]from . import modules # but no handlers[/dim]",
"",
"─" * 70,
"",
"[bold cyan]HOW TO FIX:[/bold cyan]",
"",
" Add this line to apps/__init__.py:",
"",
" [bold]from . import handlers[/bold]",
"",
" That's it. One line. The import ensures Python registers the",
" handlers subpackage on the apps namespace so mock.patch can",
" resolve it via getattr chain.",
"",
"─" * 70,
"",
"[bold cyan]SCORING:[/bold cyan]",
" [green]100[/green] - 'from . import handlers' found in apps/__init__.py",
" [red] 0[/red] - Import missing from apps/__init__.py",
" [red] 0[/red] - apps/__init__.py not found",
" [green]100[/green] - Bypassed via .seedgo/bypass.json",
"",
"[bold cyan]REFERENCE:[/bold cyan]",
" [dim]See: seedgo standards pack (handler_import)[/dim]",
]
json_handler.log_operation("standard_content_queried", {"standard": "handler_import"})
return "\n".join(lines)
@@ -1,13 +1,15 @@
# =================== AIPass ====================
# Name: ruff_check.py
# Description: Ruff Linter Standards Checker Handler
# Version: 1.1.0
# Description: Ruff Linter & Formatter Standards Checker Handler
# Version: 1.2.0
# Created: 2026-04-16
# Modified: 2026-04-20
# Modified: 2026-04-26
# =============================================
"""
Ruff Linter Standards Checker Handler
Ruff Linter & Formatter Standards Checker Handler
Runs both ``ruff check`` (lint) and ``ruff format --check`` (formatting).
Two modes:
- check_branch(): runs ruff across entire apps/ tree (used by audit pipeline,
@@ -186,32 +188,60 @@ def check_module(module_path: str, bypass_rules: list | None = None) -> Dict:
active = [v for v in violations if not _is_ruff_bypassed(v, ruff_bypass)]
count = len(active)
if count == 0:
json_handler.log_operation(
"check_completed",
{"file": module_path, "score": 100, "standard": "ruff_check"},
)
return {
"passed": True,
"checks": [{"name": "Ruff check", "passed": True, "message": "No ruff violations found"}],
"score": 100,
"standard": "RUFF_CHECK",
}
checks: list[dict] = []
passed = True
top = active[:5]
msgs = [f"{v.get('code', '?')} L{v.get('location', {}).get('row', '?')}: {v.get('message', '?')[:80]}" for v in top]
suffix = f" (and {count - 5} more)" if count > 5 else ""
detail = f"{count} violation(s) — " + "; ".join(msgs) + suffix
if count == 0:
checks.append({"name": "Ruff lint", "passed": True, "message": "No ruff violations found"})
else:
top = active[:5]
msgs = [
f"{v.get('code', '?')} L{v.get('location', {}).get('row', '?')}: {v.get('message', '?')[:80]}" for v in top
]
suffix = f" (and {count - 5} more)" if count > 5 else ""
detail = f"{count} violation(s) — " + "; ".join(msgs) + suffix
checks.append({"name": "Ruff lint", "passed": False, "message": detail})
passed = False
# --- ruff format --check ---
needs_format = False
try:
fmt_proc = subprocess.run(
["ruff", "format", "--check", str(fp)],
capture_output=True,
text=True,
timeout=15,
)
if fmt_proc.returncode != 0:
needs_format = True
except subprocess.TimeoutExpired:
logger.warning("ruff format --check timed out on %s", module_path)
except Exception as exc:
logger.warning("ruff format --check failed on %s: %s", module_path, exc)
if needs_format:
checks.append({"name": "Ruff format", "passed": False, "message": f"{fp.name} needs ruff format"})
passed = False
else:
checks.append({"name": "Ruff format", "passed": True, "message": "File is formatted"})
score = 100 if passed else 0
json_handler.log_operation(
"check_completed",
{"file": module_path, "score": 0, "standard": "ruff_check", "violations": count},
{
"file": module_path,
"score": score,
"standard": "ruff_check",
"violations": count,
"needs_format": needs_format,
},
)
return {
"passed": False,
"checks": [{"name": "Ruff check", "passed": False, "message": detail}],
"score": 0,
"passed": passed,
"checks": checks,
"score": score,
"standard": "RUFF_CHECK",
}
@@ -320,9 +350,10 @@ def check_branch(branch_path: str, bypass_rules: list | None = None) -> Dict:
count = len(active)
score = _score_from_count(count)
checks: list[dict] = []
if count == 0:
message = "No ruff violations found"
check_passed = True
checks.append({"name": "Ruff lint", "passed": True, "message": "No ruff violations found"})
else:
top = active[:5]
codes = ", ".join(
@@ -331,16 +362,55 @@ def check_branch(branch_path: str, bypass_rules: list | None = None) -> Dict:
)
suffix = f" (and {count - 5} more)" if count > 5 else ""
message = f"{count} violation(s) — {codes}{suffix}"
check_passed = False
checks.append({"name": "Ruff lint", "passed": False, "message": message})
# --- ruff format --check (advisory) ---
fmt_files: list[str] = []
try:
fmt_proc = subprocess.run(
["ruff", "format", "--check", str(scan_target)],
capture_output=True,
text=True,
timeout=60,
)
if fmt_proc.returncode != 0 and fmt_proc.stdout.strip():
fmt_files = [line.strip() for line in fmt_proc.stdout.strip().splitlines() if line.strip()]
except subprocess.TimeoutExpired:
logger.warning("ruff format --check timed out on branch %s", branch_path)
except Exception as exc:
logger.warning("ruff format --check failed on branch %s: %s", branch_path, exc)
fmt_count = len(fmt_files)
if fmt_count == 0:
checks.append({"name": "Ruff format", "passed": True, "message": "All files formatted"})
else:
names = ", ".join(Path(f).name for f in fmt_files[:5])
fmt_suffix = f" (and {fmt_count - 5} more)" if fmt_count > 5 else ""
checks.append(
{
"name": "Ruff format",
"passed": False,
"message": f"{fmt_count} file(s) need formatting — {names}{fmt_suffix}",
}
)
# Penalise score: subtract 2 points per unformatted file, floor at 25
score = max(25, score - fmt_count * 2)
json_handler.log_operation(
"check_completed",
{"branch": branch_path, "score": score, "standard": "ruff_check", "violations": count, "advisory": True},
{
"branch": branch_path,
"score": score,
"standard": "ruff_check",
"violations": count,
"format_violations": fmt_count,
"advisory": True,
},
)
return {
"passed": True, # Advisory: never blocks the audit
"checks": [{"name": "Ruff check", "passed": check_passed, "message": message}],
"checks": checks,
"score": score,
"standard": "RUFF_CHECK",
"advisory": True,
@@ -45,6 +45,19 @@ def _ruff_proc(violations: list, returncode: int = 1) -> MagicMock:
return proc
def _fmt_proc(unformatted_files: list[str] | None = None) -> MagicMock:
"""Build a fake subprocess.CompletedProcess for ruff format --check."""
proc = MagicMock()
if unformatted_files:
proc.stdout = "\n".join(unformatted_files) + "\n"
proc.returncode = 1
else:
proc.stdout = ""
proc.returncode = 0
proc.stderr = ""
return proc
def _make_violation(filename: str, code: str = "F401", row: int = 1) -> dict:
return {
"filename": filename,
@@ -139,11 +152,14 @@ class TestCheckBranch:
"""Branch with zero ruff violations scores 100."""
branch = _make_branch(tmp_path)
clean_proc = _ruff_proc([], returncode=0)
fmt_clean = _fmt_proc()
with patch(
"aipass.seedgo.apps.handlers.aipass_standards.ruff_check.shutil.which", return_value="/usr/bin/ruff"
"aipass.seedgo.apps.handlers.aipass_standards.ruff_check.shutil.which",
return_value="/usr/bin/ruff",
):
with patch(
"aipass.seedgo.apps.handlers.aipass_standards.ruff_check.subprocess.run", return_value=clean_proc
"aipass.seedgo.apps.handlers.aipass_standards.ruff_check.subprocess.run",
side_effect=[clean_proc, fmt_clean],
):
result = check_branch(str(branch))
assert result["score"] == 100
@@ -156,10 +172,15 @@ class TestCheckBranch:
branch = _make_branch(tmp_path)
violations = [_make_violation(str(branch / "apps" / "modules" / "x.py"), "F401", i) for i in range(10)]
proc = _ruff_proc(violations, returncode=1)
fmt_clean = _fmt_proc()
with patch(
"aipass.seedgo.apps.handlers.aipass_standards.ruff_check.shutil.which", return_value="/usr/bin/ruff"
"aipass.seedgo.apps.handlers.aipass_standards.ruff_check.shutil.which",
return_value="/usr/bin/ruff",
):
with patch("aipass.seedgo.apps.handlers.aipass_standards.ruff_check.subprocess.run", return_value=proc):
with patch(
"aipass.seedgo.apps.handlers.aipass_standards.ruff_check.subprocess.run",
side_effect=[proc, fmt_clean],
):
result = check_branch(str(branch))
assert result["score"] == 85 # 10 violations → 6–20 band
assert result["passed"] is True # advisory: always True
@@ -192,14 +213,19 @@ class TestCheckBranch:
_make_violation(v_path, "E501", 10),
]
proc = _ruff_proc(violations, returncode=1)
fmt_clean = _fmt_proc()
# Bypass the F401
bypass_file = branch / ".seedgo" / "ruff_bypass.json"
bypass_file.parent.mkdir(parents=True, exist_ok=True)
bypass_file.write_text(json.dumps([{"file": "thing.py", "code": "F401"}]))
with patch(
"aipass.seedgo.apps.handlers.aipass_standards.ruff_check.shutil.which", return_value="/usr/bin/ruff"
"aipass.seedgo.apps.handlers.aipass_standards.ruff_check.shutil.which",
return_value="/usr/bin/ruff",
):
with patch("aipass.seedgo.apps.handlers.aipass_standards.ruff_check.subprocess.run", return_value=proc):
with patch(
"aipass.seedgo.apps.handlers.aipass_standards.ruff_check.subprocess.run",
side_effect=[proc, fmt_clean],
):
result = check_branch(str(branch))
# Only 1 active violation (E501), score should be 95
assert result["score"] == 95
@@ -0,0 +1,169 @@
"""Tests for handler_import_check."""
# =================== META ====================
# Name: test_handler_import.py
# Description: Unit tests for handler_import_check checker handler
# Version: 1.0.0
# Created: 2026-04-26
# Modified: 2026-04-26
# =============================================
import sys
from pathlib import Path
from unittest.mock import MagicMock
import pytest
# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------
def _write_file(path: Path, content: str) -> None:
"""Write content to a file, creating parent dirs as needed."""
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(content, encoding="utf-8")
# ---------------------------------------------------------------------------
# Fixtures
# ---------------------------------------------------------------------------
@pytest.fixture(autouse=True)
def _mock_infrastructure(monkeypatch):
"""Mock heavy infrastructure imports for the handler_import checker."""
mock_logger = MagicMock()
mock_json_handler = MagicMock()
mock_json_handler.log_operation = MagicMock(return_value=True)
# -- prax ---------------------------------------------------------------
prax_mod = MagicMock()
prax_mod.logger = mock_logger
monkeypatch.setitem(sys.modules, "aipass.prax", prax_mod)
# -- seedgo json handler ------------------------------------------------
json_pkg = MagicMock()
json_pkg.json_handler = mock_json_handler
monkeypatch.setitem(sys.modules, "aipass.seedgo.apps.handlers.json", json_pkg)
json_mod = MagicMock()
json_mod.log_operation = mock_json_handler.log_operation
monkeypatch.setitem(
sys.modules,
"aipass.seedgo.apps.handlers.json.json_handler",
json_mod,
)
# -- bypass handler -----------------------------------------------------
bypass_pkg = MagicMock()
bypass_ignore = MagicMock()
bypass_ignore.get_template_ignore_patterns = MagicMock(return_value=[])
bypass_pkg.ignore_handler = bypass_ignore
monkeypatch.setitem(sys.modules, "aipass.seedgo.apps.handlers.bypass", bypass_pkg)
monkeypatch.setitem(
sys.modules,
"aipass.seedgo.apps.handlers.bypass.ignore_handler",
bypass_ignore,
)
# Force re-import so checker picks up fresh mocks
monkeypatch.delitem(
sys.modules,
"aipass.seedgo.apps.handlers.aipass_standards.handler_import_check",
raising=False,
)
monkeypatch.delitem(
sys.modules,
"aipass.seedgo.apps.handlers.aipass_standards.handler_import_content",
raising=False,
)
# ===========================================================================
# handler_import_check tests
# ===========================================================================
class TestHandlerImportCheck:
"""Tests for the handler_import_check checker."""
def test_branch_with_handler_import_passes(self, tmp_path: Path) -> None:
"""apps/__init__.py containing 'from . import handlers' scores 100."""
_write_file(
tmp_path / "apps" / "__init__.py",
"from . import handlers\n",
)
from aipass.seedgo.apps.handlers.aipass_standards.handler_import_check import (
check_branch,
)
result = check_branch(str(tmp_path))
assert result["passed"] is True
assert result["score"] == 100
assert result["standard"] == "HANDLER_IMPORT"
def test_branch_missing_handler_import_fails(self, tmp_path: Path) -> None:
"""apps/__init__.py without the handler import scores 0."""
_write_file(
tmp_path / "apps" / "__init__.py",
"from . import modules\n",
)
from aipass.seedgo.apps.handlers.aipass_standards.handler_import_check import (
check_branch,
)
result = check_branch(str(tmp_path))
assert result["passed"] is False
assert result["score"] == 0
assert result["standard"] == "HANDLER_IMPORT"
failed = [c for c in result["checks"] if not c["passed"]]
assert len(failed) == 1
assert "missing" in failed[0]["message"]
def test_branch_no_apps_init_fails(self, tmp_path: Path) -> None:
"""Branch with no apps/__init__.py at all scores 0."""
# Create apps/ directory but no __init__.py
(tmp_path / "apps").mkdir(parents=True)
from aipass.seedgo.apps.handlers.aipass_standards.handler_import_check import (
check_branch,
)
result = check_branch(str(tmp_path))
assert result["passed"] is False
assert result["score"] == 0
assert "not found" in result["checks"][0]["message"]
def test_branch_bypassed(self, tmp_path: Path) -> None:
"""Bypass rule matches produce score 100."""
# No apps/ at all -- bypass should still pass
from aipass.seedgo.apps.handlers.aipass_standards.handler_import_check import (
check_branch,
)
bypass = [{"standard": "handler_import"}]
result = check_branch(str(tmp_path), bypass_rules=bypass)
assert result["passed"] is True
assert result["score"] == 100
def test_branch_no_apps_dir(self, tmp_path: Path) -> None:
"""Branch with no apps/ directory at all scores 0."""
from aipass.seedgo.apps.handlers.aipass_standards.handler_import_check import (
check_branch,
)
result = check_branch(str(tmp_path))
assert result["passed"] is False
assert result["score"] == 0
assert "not found" in result["checks"][0]["message"]
def test_content_returns_string(self) -> None:
"""handler_import_content.get_handler_import_standards() returns non-empty string."""
from aipass.seedgo.apps.handlers.aipass_standards.handler_import_content import (
get_handler_import_standards,
)
content = get_handler_import_standards()
assert isinstance(content, str)
assert len(content) > 0
assert "HANDLER IMPORT" in content