fix(seedgo): Debug_Print detector regex matched print( inside string literals - strip string content before matching (+regression test); flatten depth-5 nesting in cli_ux_check. The auditor was the last branch under 100 - fleet now genuinely 17/17 (FPLAN-0333)

This commit is contained in:
AIOSAI
2026-07-17 20:17:41 -07:00
parent d4b265ad45
commit f6d31285ea
4 changed files with 30 additions and 15 deletions
+5
View File
@@ -53,6 +53,11 @@ and README to the house pattern: 17/17 branches at 100%.
- **Fleet-100 sweep**: 15 branches gained Quick Start READMEs and/or
Usage/Examples help sections — each owner fixed their own front against the
new gate.
- **Debug_Print detector hardened**: the regex-based checker matched `print(`
inside string literals (flagging cli_ux_check's own error messages — the
auditor was the last branch under 100%). String content is now stripped
before matching, with a regression test; plus a depth-5 nesting refactor in
the same file.
**v2.7.2** — everything merged since v2.7.1, headlined by the compass decision
engine v2: curation with supersedes links + write-time conflict advisories
@@ -214,20 +214,10 @@ def _find_function(tree: ast.Module, name: str) -> Optional[ast.FunctionDef]:
def _collect_string_constants(func_node: ast.FunctionDef) -> List[str]:
"""
Extract all string constants from a function body, including strings
inside f-strings (ast.JoinedStr -> ast.Constant).
"""
strings: List[str] = []
for node in ast.walk(func_node):
if isinstance(node, ast.Constant) and isinstance(node.value, str):
strings.append(node.value)
elif isinstance(node, ast.JoinedStr):
# f-string: extract string parts
for part in node.values:
if isinstance(part, ast.Constant) and isinstance(part.value, str):
strings.append(part.value)
return strings
"""Extract all string constants from a function body, including f-string parts."""
return [
node.value for node in ast.walk(func_node) if isinstance(node, ast.Constant) and isinstance(node.value, str)
]
# ---------------------------------------------------------------------------
@@ -34,6 +34,9 @@ _DOCTEST_RE = re.compile(r"^\s*(\.\.\.|>>>)\s")
# Test file name patterns
_TEST_FILE_RE = re.compile(r"^(test_.+|.+_test|conftest)\.py$")
# String literals — strip content before regex to avoid false positives on print( inside strings
_STRING_LITERAL_RE = re.compile(r'""".*?"""|\'\'\'.*?\'\'\'|"(?:[^"\\]|\\.)*"|\'(?:[^\'\\]|\\.)*\'')
def _is_in_main_block(lines: list[str], lineno: int) -> bool:
"""
@@ -108,8 +111,9 @@ def _scan_file(file_path: Path) -> tuple[list[int], str | None]:
if _DOCTEST_RE.match(line):
continue
# Strip inline comments before checking for print(
# Strip inline comments and string literal contents before checking
code_part = line.split("#")[0]
code_part = _STRING_LITERAL_RE.sub('""', code_part)
if not _PRINT_RE.search(code_part):
continue
@@ -329,6 +329,22 @@ def test_debug_print_check_bypass_respected(tmp_path):
assert result["score"] == 100, f"Bypass should yield 100: {result}"
def test_debug_print_string_literal_not_flagged(tmp_path):
"""print() mentioned inside string literals must not trigger false positives."""
f = tmp_path / "messages.py"
f.write_text(
'"""Module with print() in docstring."""\n\n'
"def check():\n"
' msg = "use console.print() not bare print()"\n'
" return msg\n",
encoding="utf-8",
)
from aipass.seedgo.apps.handlers.aipass_standards.debug_print_check import check_module
result = check_module(str(f))
assert result["score"] == 100, f"print() inside strings should not flag: {result}"
# ===========================================================================
# 6. deep_nesting_check
# ===========================================================================