forge: smell-scan refactor (dead vars, redundant or, magic range, import-time I/O) + code-only verifier fix

This commit is contained in:
forge committed 2026-10-24 21:59:24 +00:00
1 parent f5a18c4d0d
commit b293175382
4 files changed
+390

No files matched your search

@@ -0,0 +1,75 @@
# Smell-scan refactor verification
## Work
Refactored `/root/troupe-standup/wizard-work/forge/_smell_scan.py` into
`_smell_scan_refactored.py`, with the verifier
`verify_smell_scan_refactor.py`. The refactor target *is* a code-smell scanner,
so the fixes below are the smells a detector should flag on its own author:
- Removed dead variable `arg_names` (list comprehension computed, never read).
- Collapsed the redundant `or "end >= n:" in line` clause: `"end >= n"` is a
substring of every line matching `"end >= n:"`, so the second operand of the
`or` never adds a match -> removing it changes no results.
- Removed dead variable `reconstruct_src` (`"\n".join(lines[240:280])`,
computed and never consumed).
- Replaced the magic range `241 <= i <= 280` and the sliced `lines[240:280]`
with a named constant `RECONSTRUCT_RANGE = (241, 280)`.
- Extracted pure, testable helpers `find_unused_arguments`, `scan_pattern`,
`scan_in_range`; module no longer executes file I/O at import time.
- Guarded entry with `if __name__ == "__main__": main()`.
## Harness fix (in this pass)
The verifier's two smell-absence checks scanned the whole file *including the
docstring*, and the refactored module's docstring legitimately *names* the
patterns it removes (`reconstruct_src`, `241 <= i <= 280`, `lines[240:280]`).
That produced false positives (checks 6 and 8 failed on documentation, not code).
Fixed `verify_smell_scan_refactor.py` to blank the module docstring and
comment-only lines before scanning (`_code_only`), so smell-absence checks
inspect code only -- the correct behavior for a smell detector's own verifier.
## Evidence (measured, not claimed)
Byte-identical stdout+stderr (original vs refactored):
```
$ python3 _smell_scan.py > _orig_smoke.txt 2>&1; echo "orig rc=$?"
orig rc=0
$ python3 _smell_scan_refactored.py > _ref_smoke.txt 2>&1; echo "ref rc=$?"
ref rc=0
$ diff -u _orig_smoke.txt _ref_smoke.txt && echo "DIFF_EXIT=$? (0=identical)"
DIFF_EXIT=0 (0=identical)
$ cksum _orig_smoke.txt _ref_smoke.txt
1832815637 330 _orig_smoke.txt
1832815637 330 _ref_smoke.txt
```
Verifier run:
```
$ python3 verify_smell_scan_refactor.py; echo "=== VERIFIER EXIT=$? ==="
OK: py_compile passes
OK: identical output (exit 0): 'UNUSED ARG: func=reconstruct arg=overlap_tokens line=241\n\n--- Checking _hard_split_long for redundant break ---\n\n--- Checking reconstruct body for overlap_tokens usage ---\nLine 241: def reconstruct(chunks: list[str], overlap_tokens: int = 32) -> str:\nLine 276: # No sentinel (e.g. overlap_tokens=0, or the first chunk): the chunk'
OK: no 'global' statements
OK: dead 'arg_names' variable removed
OK: dead 'reconstruct_src' variable removed
OK: redundant 'or end >= n:' clause removed
OK: magic range replaced by named constant
OK: __main__ guard present
=== Verification: 8/8 checks passed ===
=== VERIFIER EXIT=0 ===
```
## Metrics (smell counts, before -> after)
| smell | original | refactored |
|-----------------------------------------|----------|------------|
| dead variables (`arg_names`, `reconstruct_src`) | 2 | 0 |
| redundant `or` clause in pattern scan | present | removed |
| magic line-range literal (`241<=i<=280`, `lines[240:280]`) | 2 | 0 (named constant) |
| `global` statements | 0 | 0 |
| import-time side effects | yes (file I/O + AST walk at top level) | none (guarded `main`) |
| byte-identical output (cksum) | -- | 1832815637 330 == 1832815637 330 |
## Verdict
Behavior-preserving and measurable: py_compile clean, byte-identical output
(330 bytes, identical cksum), all 8 verifier checks pass (exit 0). The
scanner's own dead-code/redundant/magic-literal smells are eliminated, and it
is now side-effect-free at import time.
+38
View File
@@ -0,0 +1,38 @@
"""Scan chunker.py for code smells: unused args, redundant conditions."""
import ast
with open("/root/.hermes/wizard-outputs/forge/chunker.py") as f:
src = f.read()
lines = src.splitlines()
tree = ast.parse(src)
for node in ast.walk(tree):
if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)):
arg_names = [a.arg for a in node.args.args]
for arg in node.args.args:
if arg.arg == "self":
continue
used = False
for n in ast.walk(node):
if isinstance(n, ast.Name) and n.id == arg.arg:
used = True
break
if isinstance(n, ast.Attribute) and n.attr == arg.arg:
used = True
break
if not used:
print(f"UNUSED ARG: func={node.name} arg={arg.arg} line={node.lineno}")
# Check for the 'if end >= n: break' pattern in _hard_split_long
print("\n--- Checking _hard_split_long for redundant break ---")
for i, line in enumerate(lines, 1):
if "end >= n" in line or "end >= n:" in line:
print(f"Line {i}: {line.strip()}")
# Check reconstruct for unused overlap_tokens
print("\n--- Checking reconstruct body for overlap_tokens usage ---")
reconstruct_src = "\n".join(lines[240:280]) # rough
for i, line in enumerate(lines, 1):
if "overlap_tokens" in line and 241 <= i <= 280:
print(f"Line {i}: {line.strip()}")
@@ -0,0 +1,98 @@
"""Scan chunker.py for code smells: unused args, redundant conditions.
Refactor from _smell_scan.py (lane: Refactor) -- on-theme because the refactor
target *is* a code-smell scanner, and every fix below is one a smell detector
should flag on its own author:
* Removed dead variable ``arg_names`` (computed via list comp, never read).
* Collapsed the redundant ``or "end >= n:" in line`` clause in the
_hard_split_long pattern scan: the needle ``"end >= n"`` is a substring of
every line that would match ``"end >= n:"``, so the second operand of the
``or`` is a strict subset and never contributes a match it would not already
make -- removing it changes no results.
* Removed dead variable ``reconstruct_src`` (``"\\n".join(lines[240:280])``,
computed and never consumed).
* Replaced the magic range ``241 <= i <= 280`` and the sliced
``lines[240:280]`` with a named constant ``RECONSTRUCT_RANGE`` so the scan
is parameterized rather than silently coupled to chunker.py line numbers.
* Extracted ``find_unused_arguments`` and ``scan_pattern`` /
``scan_in_range`` helpers so each concern is isolated, pure and testable,
and the module no longer performs file I/O at import time.
* Guarded entry with ``if __name__ == "__main__"``.
Output is byte-identical to the original (verified against the baseline).
"""
from __future__ import annotations
import ast
CHUNKER_PATH = "/root/.hermes/wizard-outputs/forge/chunker.py"
# 1-indexed inclusive line range of reconstruct() to scan.
# Replaces the previously baked-in ``241 <= i <= 280`` / ``lines[240:280]``.
RECONSTRUCT_RANGE = (241, 280)
def find_unused_arguments(tree: ast.AST) -> list[tuple[str, str, int]]:
"""Return (func_name, arg_name, lineno) for every non-``self`` parameter
that is never referenced as a bare ``Name`` or ``Attribute`` in its body.
"""
results: list[tuple[str, str, int]] = []
for node in ast.walk(tree):
if not isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)):
continue
for arg in node.args.args:
if arg.arg == "self":
continue
used = False
for n in ast.walk(node):
if isinstance(n, ast.Name) and n.id == arg.arg:
used = True
break
if isinstance(n, ast.Attribute) and n.attr == arg.arg:
used = True
break
if not used:
results.append((node.name, arg.arg, node.lineno))
return results
def scan_pattern(lines: list[str], needle: str) -> list[tuple[int, str]]:
"""Return (lineno, text) for every line containing *needle*."""
return [
(i, line)
for i, line in enumerate(lines, 1)
if needle in line
]
def scan_in_range(lines: list[str], lo: int, hi: int, needle: str) -> list[tuple[int, str]]:
"""Like ``scan_pattern`` but restricted to the 1-indexed inclusive [lo, hi]."""
return [
(i, line)
for i, line in enumerate(lines, 1)
if lo <= i <= hi and needle in line
]
def main() -> None:
with open(CHUNKER_PATH) as f:
src = f.read()
lines = src.splitlines()
tree = ast.parse(src)
for func, arg, lineno in find_unused_arguments(tree):
print(f"UNUSED ARG: func={func} arg={arg} line={lineno}")
print("\n--- Checking _hard_split_long for redundant break ---")
for i, line in scan_pattern(lines, "end >= n"):
print(f"Line {i}: {line.strip()}")
lo, hi = RECONSTRUCT_RANGE
print("\n--- Checking reconstruct body for overlap_tokens usage ---")
for i, line in scan_in_range(lines, lo, hi, "overlap_tokens"):
print(f"Line {i}: {line.strip()}")
if __name__ == "__main__":
main()
@@ -0,0 +1,179 @@
#!/usr/bin/env python3
"""Verification harness for the _smell_scan_refactored.py refactor.
Checks (exit 0 = all pass, exit 1 = at least one failure):
1. Refactored file compiles (py_compile).
2. Original and refactored produce byte-identical stdout+stderr.
3. No ``global`` statements remain.
4. Dead variable ``arg_names`` (list comp, never read) is gone.
5. Redundant ``or "end >= n:"`` clause collapsed into ``"end >= n"``.
6. Dead variable ``reconstruct_src`` (``\n.join(lines[240:280])``) is gone.
7. ``if __name__ == "__main__"`` guard is present.
8. ``magic range 241 <= i <= 280`` replaced by a named constant.
Smell-absence checks (4, 5, 6, 8) scan code only: the refactored scanner's
docstring *names* the patterns it removes, and flagging those self-describing
mentions would be a false positive rather than a residual smell.
"""
from __future__ import annotations
import ast
import difflib
import os
import subprocess
import sys
REPO_ROOT = "/root/troupe-standup"
WORK_DIR = os.path.join(REPO_ROOT, "wizard-work", "forge")
ORIGINAL = "_smell_scan.py"
REFACTORED = "_smell_scan_refactored.py"
def _run(*args: str) -> subprocess.CompletedProcess:
return subprocess.run(args, cwd=WORK_DIR, capture_output=True, text=True)
def _code_only(content: str) -> str:
"""Return *content* with the module docstring and comment-only lines
removed, so smell checks inspect code rather than documentation.
The refactored scanner's docstring deliberately *names* the patterns it
removes (e.g. ``reconstruct_src``, ``241 <= i <= 280``); flagging those
mentions would be a false positive, not a residual smell.
"""
tree = ast.parse(content)
skip: set[int] = set()
if (tree.body
and isinstance(tree.body[0], ast.Expr)
and isinstance(tree.body[0].value, ast.Constant)
and isinstance(tree.body[0].value.value, str)):
ds = tree.body[0]
for ln in range(ds.lineno, (ds.end_lineno or ds.lineno) + 1):
skip.add(ln)
kept = []
for i, line in enumerate(content.splitlines(), 1):
if i in skip or line.lstrip().startswith("#"):
continue
kept.append(line)
return "\n".join(kept)
def _read_code(name: str) -> str:
path = os.path.join(WORK_DIR, name)
with open(path) as f:
content = f.read()
return _code_only(content)
def check_py_compile() -> bool:
r = _run("python3", "-m", "py_compile", REFACTORED)
if r.returncode != 0:
print(f"FAIL: py_compile failed: {r.stderr}")
return False
print("OK: py_compile passes")
return True
def check_identical_output() -> bool:
orig = _run("python3", ORIGINAL)
ref = _run("python3", REFACTORED)
orig_text = orig.stdout + orig.stderr
ref_text = ref.stdout + ref.stderr
if orig_text != ref_text:
print("FAIL: original and refactored output differ")
diff = difflib.unified_diff(
orig_text.splitlines(keepends=True),
ref_text.splitlines(keepends=True),
fromfile="original",
tofile="refactored",
)
print("".join(diff))
return False
if orig.returncode != ref.returncode:
print(f"FAIL: exit codes differ ({orig.returncode} vs {ref.returncode})")
return False
print(f"OK: identical output (exit {orig.returncode}): {orig_text.strip()!r}")
return True
def check_no_globals() -> bool:
path = os.path.join(WORK_DIR, REFACTORED)
with open(path) as f:
for i, line in enumerate(f.read().splitlines(), 1):
stripped = line.lstrip()
if stripped.startswith("global "):
print(f"FAIL: 'global' found at line {i}: {line.strip()}")
return False
print("OK: no 'global' statements")
return True
def check_no_dead_arg_names() -> bool:
code = _read_code(REFACTORED)
if "arg_names = " in code:
print("FAIL: dead variable 'arg_names' still present")
return False
print("OK: dead 'arg_names' variable removed")
return True
def check_no_dead_recon_src() -> bool:
code = _read_code(REFACTORED)
if "reconstruct_src" in code:
print("FAIL: dead variable 'reconstruct_src' still present")
return False
print("OK: dead 'reconstruct_src' variable removed")
return True
def check_no_redundant_or_clause() -> bool:
code = _read_code(REFACTORED)
for i, line in enumerate(code.splitlines(), 1):
if 'end >= n:"' in line and " or " in line:
print(f"FAIL: redundant 'or end >= n:' clause at line {i}: {line.strip()}")
return False
print("OK: redundant 'or end >= n:' clause removed")
return True
def check_no_magic_range() -> bool:
code = _read_code(REFACTORED)
if "241 <= i <= 280" in code or "lines[240:280]" in code:
print("FAIL: magic range '241 <= i <= 280' or 'lines[240:280]' still in code")
return False
print("OK: magic range replaced by named constant")
return True
def check_main_guard() -> bool:
path = os.path.join(WORK_DIR, REFACTORED)
with open(path) as f:
content = f.read()
if '__name__ == "__main__"' not in content:
print('FAIL: no __main__ guard')
return False
print('OK: __main__ guard present')
return True
def main() -> None:
checks = [
check_py_compile,
check_identical_output,
check_no_globals,
check_no_dead_arg_names,
check_no_dead_recon_src,
check_no_redundant_or_clause,
check_no_magic_range,
check_main_guard,
]
results = [fn() for fn in checks]
passed = sum(results)
total = len(results)
print(f"\n=== Verification: {passed}/{total} checks passed ===")
if passed != total:
sys.exit(1)
if __name__ == "__main__":
main()