{
  "schema": "https://ai-atoms.com/schemas/hook-v1.json",
  "type": "hook",
  "id": "hook/no-commented-code",
  "version": "1.0.0",
  "name": "No Commented-Out Code",
  "description": "Fires on PostToolUse for Edit and Write tools. Scans the written file content for commented-out code blocks — lines that appear to be executable code hidden behind a comment marker rather than explanatory prose. Emits a DEAD-CODE-VIOLATION warning when detected. Non-blocking.",
  "event": "PostToolUse",
  "language": "python",
  "trigger": {
    "type": "tool-name",
    "pattern": "Edit|Write"
  },
  "blocking": false,
  "side_effects": [
    "emits DEAD-CODE-VIOLATION sentinel lines to stderr",
    "reports file path and approximate line numbers of violations"
  ],
  "authored_by": "convergent-systems-key",
  "tags": [
    "code-quality",
    "dead-code",
    "governance",
    "claude-code"
  ],
  "lifecycle": "stable",
  "platforms": [
    "linux",
    "macos",
    "windows"
  ],
  "platform_notes": "Pure Python, no git dependency. Reads file path from the PostToolUse payload. Cross-platform via 'ai hooks run'.",
  "script": "#!/usr/bin/env python3\n\"\"\"hooks/no-commented-code.py — detect commented-out executable code in written files.\n\nFires on PostToolUse for Edit and Write. Reads the just-written file and\nscans for commented-out code: lines that look like executable statements\nhidden behind a comment marker rather than explanatory prose.\n\nLanguage detection is extension-based. Supported languages:\n  # comments: Python, Ruby, Shell, YAML, TOML, R\n  // comments: JS, TS, Go, Rust, Java, Kotlin, Swift, C, C++, C#, PHP\n  -- comments: SQL, Lua, Haskell\n  ; comments: Lisp, Clojure\n  <!-- -->: HTML, XML, SVG\n\nHeuristics for 'this looks like code, not a comment':\n  - Contains a function/method call: word followed by '(' or '::'\n  - Contains an assignment: '=', ':='\n  - Contains a control-flow keyword at the line start after the marker:\n    'if', 'else', 'for', 'while', 'return', 'def', 'function', 'class',\n    'import', 'from', 'require', 'use', 'let', 'var', 'const'\n  - Ends with '{', '}', ';' (structural code tokens)\n  - Starts with a decorator: '@' followed by word characters\n\nExcludes:\n  - Doc-comment blocks (lines starting with ///, //!, /*!, ////, #!)\n  - Lines that are clearly prose: no code tokens, purely natural language\n  - Shebangs (#!)\n  - Single-word commented lines ('# TODO', '# type: ignore', etc.)\n\nNon-blocking: emits DEAD-CODE-VIOLATION to stderr.\n\nSelf-check:\n  --self-check  exits 0 always (no external deps).\n\"\"\"\nfrom __future__ import annotations\n\nimport json\nimport re\nimport sys\nfrom pathlib import Path\n\nsys.path.insert(0, str(Path(__file__).resolve().parent))\nimport _lib  # noqa: E402\n\n\n# ---------------------------------------------------------------------------\n# Language → comment marker mapping\n# ---------------------------------------------------------------------------\n\n_HASH_EXTS = {\n    \".py\", \".rb\", \".sh\", \".bash\", \".zsh\", \".fish\",\n    \".yml\", \".yaml\", \".toml\", \".r\", \".R\",\n}\n_SLASH_EXTS = {\n    \".js\", \".jsx\", \".ts\", \".tsx\", \".mjs\", \".cjs\",\n    \".go\", \".rs\", \".java\", \".kt\", \".kts\",\n    \".swift\", \".c\", \".h\", \".cpp\", \".cc\", \".cxx\", \".hpp\",\n    \".cs\", \".php\",\n}\n_DASH_EXTS = {\".sql\", \".lua\", \".hs\", \".lhs\"}\n_SEMI_EXTS = {\".lisp\", \".clj\", \".cljs\", \".el\", \".scm\"}\n_HTML_EXTS = {\".html\", \".htm\", \".xml\", \".svg\"}\n\n\ndef _comment_prefix(path: Path) -> str | None:\n    ext = path.suffix.lower()\n    if ext in _HASH_EXTS:\n        return \"#\"\n    if ext in _SLASH_EXTS:\n        return \"//\"\n    if ext in _DASH_EXTS:\n        return \"--\"\n    if ext in _SEMI_EXTS:\n        return \";\"\n    return None  # HTML handled separately; unsupported → skip\n\n\n# ---------------------------------------------------------------------------\n# Detection regexes\n# ---------------------------------------------------------------------------\n\n# A call: word chars followed by '(' or '::' (bare ':' excluded — matches English prose like 'TODO:')\n_CALL_RE = re.compile(r\"\\w+\\s*(?:\\(|::)\")\n# An assignment\n_ASSIGN_RE = re.compile(r\"(?<!=)=(?!=)|:=\")\n# Control-flow keywords at the start of the content after the marker\n_KEYWORD_RE = re.compile(\n    r\"^(?:if|else(?:if)?|elif|for|while|do|switch|match|return|yield|\"\n    r\"def|function|class|struct|enum|interface|impl|trait|\"\n    r\"import|from|require|use|include|\"\n    r\"let|var|const|val|mut|pub|private|protected|static|\"\n    r\"try|catch|finally|raise|throw|async|await)\\b\"\n)\n# Structural code tokens\n_STRUCTURAL_RE = re.compile(r\"[{}];?\\s*$|;\\s*$\")\n# Decorator\n_DECORATOR_RE = re.compile(r\"^@\\w+\")\n# Doc-comment prefixes to skip\n_DOC_RE = re.compile(r\"^(?:///!?|//!|/\\*!|#{4,}|#!)\")\n# Single identifier line (e.g. '# TODO', '# type: ignore', '# noqa: E501')\n# Uses \\w+ (not \\S+) so that structural tokens like '}' and calls like 'fn(x)' are not excluded early.\n_SINGLE_TOKEN_RE = re.compile(r\"^\\w+(?:\\s*:\\s*\\w+(?:\\.\\w+)*)?\\s*$\")\n\n\ndef _looks_like_code(content: str) -> bool:\n    \"\"\"Return True if the stripped content after the comment marker looks\n    like executable code rather than prose.\"\"\"\n    s = content.strip()\n    if not s:\n        return False\n    if len(s) < 2 and s not in \"{}[];\":\n        return False\n    if _SINGLE_TOKEN_RE.match(s):\n        return False\n    if _KEYWORD_RE.match(s):\n        return True\n    if _CALL_RE.search(s):\n        return True\n    if _ASSIGN_RE.search(s):\n        return True\n    if _STRUCTURAL_RE.search(s):\n        return True\n    if _DECORATOR_RE.match(s):\n        return True\n    return False\n\n\ndef scan_file(path: Path, text: str) -> list[int]:\n    \"\"\"Return list of 1-based line numbers containing commented-out code.\"\"\"\n    prefix = _comment_prefix(path)\n    if prefix is None:\n        return []\n\n    violations: list[int] = []\n    # Build a regex that matches the comment marker, optional whitespace,\n    # then captures the rest. Handles leading whitespace (indented code).\n    marker_re = re.compile(\n        r\"^\\s*\" + re.escape(prefix) + r\"(?!\" + re.escape(prefix[0]) + r\")\\s*(.*)$\"\n    )\n\n    for lineno, line in enumerate(text.splitlines(), start=1):\n        m = marker_re.match(line)\n        if not m:\n            continue\n        content = m.group(1)\n        # Skip doc-comment prefixes\n        full_comment = prefix + content\n        if _DOC_RE.match(full_comment.lstrip()):\n            continue\n        if _looks_like_code(content):\n            violations.append(lineno)\n    return violations\n\n\ndef main() -> None:\n    if \"--self-check\" in sys.argv:\n        _lib.log(\"self-check OK\")\n        sys.exit(0)\n\n    raw = sys.stdin.read()\n    if not raw.strip():\n        sys.exit(0)\n\n    try:\n        payload = json.loads(raw)\n    except json.JSONDecodeError:\n        sys.exit(0)\n\n    # PostToolUse: tool_response contains the result; tool_input has the path.\n    tool_input = (\n        payload.get(\"tool_input\")\n        or payload.get(\"input\")\n        or {}\n    ) if isinstance(payload, dict) else {}\n\n    file_path_str = (\n        tool_input.get(\"file_path\")\n        or tool_input.get(\"path\")\n        or \"\"\n    )\n    if not file_path_str:\n        sys.exit(0)\n\n    path = Path(file_path_str)\n    if not path.is_file():\n        sys.exit(0)\n\n    try:\n        text = path.read_text(encoding=\"utf-8\", errors=\"replace\")\n    except OSError:\n        sys.exit(0)\n\n    violation_lines = scan_file(path, text)\n    if violation_lines:\n        lines_str = \", \".join(str(n) for n in violation_lines[:10])\n        if len(violation_lines) > 10:\n            lines_str += f\" (+{len(violation_lines) - 10} more)\"\n        msg = (\n            f\"DEAD-CODE-VIOLATION: {path} has commented-out code \"\n            f\"at line(s) {lines_str}\"\n        )\n        _lib.log(msg)\n\n\nif __name__ == \"__main__\":\n    main()\n",
  "depends_on": [
    "hook/lib"
  ],
  "category": "governance"
}